webdav portal login + access token fix

This commit is contained in:
vfedosevich 2015-01-16 03:56:59 -08:00
parent 1c3f10a30a
commit 213eaf0077
19 changed files with 1431 additions and 1181 deletions

View file

@ -7566,3 +7566,116 @@ COMMIT TRAN
RETURN
GO
-- WebDAv portal
IF EXISTS (SELECT * FROM SYS.TABLES WHERE name = 'WebDavAccessTokens')
DROP TABLE WebDavAccessTokens
GO
CREATE TABLE WebDavAccessTokens
(
ID INT IDENTITY(1,1) NOT NULL PRIMARY KEY,
FilePath NVARCHAR(MAX) NOT NULL,
AuthData NVARCHAR(MAX) NOT NULL,
AccessToken UNIQUEIDENTIFIER NOT NULL,
ExpirationDate DATETIME NOT NULL,
AccountID INT NOT NULL ,
ItemId INT NOT NULL
)
GO
ALTER TABLE [dbo].[WebDavAccessTokens] WITH CHECK ADD CONSTRAINT [FK_WebDavAccessTokens_UserId] FOREIGN KEY([AccountID])
REFERENCES [dbo].[ExchangeAccounts] ([AccountID])
ON DELETE CASCADE
GO
IF EXISTS (SELECT * FROM SYS.OBJECTS WHERE type = 'P' AND name = 'AddWebDavAccessToken')
DROP PROCEDURE AddWebDavAccessToken
GO
CREATE PROCEDURE [dbo].[AddWebDavAccessToken]
(
@TokenID INT OUTPUT,
@FilePath NVARCHAR(MAX),
@AccessToken UNIQUEIDENTIFIER,
@AuthData NVARCHAR(MAX),
@ExpirationDate DATETIME,
@AccountID INT,
@ItemId INT
)
AS
INSERT INTO WebDavAccessTokens
(
FilePath,
AccessToken,
AuthData,
ExpirationDate,
AccountID ,
ItemId
)
VALUES
(
@FilePath ,
@AccessToken ,
@AuthData,
@ExpirationDate ,
@AccountID,
@ItemId
)
SET @TokenID = SCOPE_IDENTITY()
RETURN
GO
IF EXISTS (SELECT * FROM SYS.OBJECTS WHERE type = 'P' AND name = 'DeleteExpiredWebDavAccessTokens')
DROP PROCEDURE DeleteExpiredWebDavAccessTokens
GO
CREATE PROCEDURE [dbo].[DeleteExpiredWebDavAccessTokens]
AS
DELETE FROM WebDavAccessTokens
WHERE ExpirationDate < getdate()
GO
IF EXISTS (SELECT * FROM SYS.OBJECTS WHERE type = 'P' AND name = 'GetWebDavAccessTokenById')
DROP PROCEDURE GetWebDavAccessTokenById
GO
CREATE PROCEDURE [dbo].[GetWebDavAccessTokenById]
(
@Id int
)
AS
SELECT
ID ,
FilePath ,
AuthData ,
AccessToken,
ExpirationDate,
AccountID,
ItemId
FROM WebDavAccessTokens
Where ID = @Id AND ExpirationDate > getdate()
GO
IF EXISTS (SELECT * FROM SYS.OBJECTS WHERE type = 'P' AND name = 'GetWebDavAccessTokenByAccessToken')
DROP PROCEDURE GetWebDavAccessTokenByAccessToken
GO
CREATE PROCEDURE [dbo].[GetWebDavAccessTokenByAccessToken]
(
@AccessToken UNIQUEIDENTIFIER
)
AS
SELECT
ID ,
FilePath ,
AuthData ,
AccessToken,
ExpirationDate,
AccountID,
ItemId
FROM WebDavAccessTokens
Where AccessToken = @AccessToken AND ExpirationDate > getdate()
GO

View file

@ -0,0 +1,15 @@
using System;
namespace WebsitePanel.EnterpriseServer.Base.HostedSolution
{
public class WebDavAccessToken
{
public int Id { get; set; }
public string FilePath { get; set; }
public string AuthData { get; set; }
public Guid AccessToken { get; set; }
public DateTime ExpirationDate { get; set; }
public int AccountId { get; set; }
public int ItemId { get; set; }
}
}

View file

@ -120,6 +120,7 @@
<Compile Include="HostedSolution\ServiceLevel.cs" />
<Compile Include="HostedSolution\CRMLycenseTypes.cs" />
<Compile Include="HostedSolution\ESPermission.cs" />
<Compile Include="HostedSolution\WebDavAccessToken.cs" />
<Compile Include="Log\LogRecord.cs" />
<Compile Include="Packages\ServiceLevelQuotaValueInfo.cs" />
<Compile Include="Packages\HostingPlanContext.cs" />

View file

@ -4330,6 +4330,57 @@ namespace WebsitePanel.EnterpriseServer
#region Enterprise Storage
public static int AddWebDavAccessToken(Base.HostedSolution.WebDavAccessToken accessToken)
{
SqlParameter prmId = new SqlParameter("@TokenID", SqlDbType.Int);
prmId.Direction = ParameterDirection.Output;
SqlHelper.ExecuteNonQuery(
ConnectionString,
CommandType.StoredProcedure,
"AddWebDavAccessToken",
prmId,
new SqlParameter("@AccessToken", accessToken.AccessToken),
new SqlParameter("@FilePath", accessToken.FilePath),
new SqlParameter("@AuthData", accessToken.AuthData),
new SqlParameter("@ExpirationDate", accessToken.ExpirationDate),
new SqlParameter("@AccountID", accessToken.AccountId),
new SqlParameter("@ItemId", accessToken.ItemId)
);
// read identity
return Convert.ToInt32(prmId.Value);
}
public static void DeleteExpiredWebDavAccessTokens()
{
SqlHelper.ExecuteNonQuery(
ConnectionString,
CommandType.StoredProcedure,
"DeleteExpiredWebDavAccessTokens"
);
}
public static IDataReader GetWebDavAccessTokenById(int id)
{
return SqlHelper.ExecuteReader(
ConnectionString,
CommandType.StoredProcedure,
"GetWebDavAccessTokenById",
new SqlParameter("@Id", id)
);
}
public static IDataReader GetWebDavAccessTokenByAccessToken(Guid accessToken)
{
return SqlHelper.ExecuteReader(
ConnectionString,
CommandType.StoredProcedure,
"GetWebDavAccessTokenByAccessToken",
new SqlParameter("@AccessToken", accessToken)
);
}
public static int AddEntepriseFolder(int itemId, string folderName, int folderQuota, string locationDrive, string homeFolder, string domain)
{
SqlParameter prmId = new SqlParameter("@FolderID", SqlDbType.Int);

View file

@ -152,6 +152,26 @@ namespace WebsitePanel.EnterpriseServer
StartESBackgroundTaskInternal("SET_ENTERPRISE_FOLDER_SETTINGS", itemId, folder, permissions, directoyBrowsingEnabled, quota, quotaType);
}
public static int AddWebDavAccessToken(WebDavAccessToken accessToken)
{
return DataProvider.AddWebDavAccessToken(accessToken);
}
public static void DeleteExpiredWebDavAccessTokens()
{
DataProvider.DeleteExpiredWebDavAccessTokens();
}
public static WebDavAccessToken GetWebDavAccessTokenById(int id)
{
return ObjectUtils.FillObjectFromDataReader<WebDavAccessToken>(DataProvider.GetWebDavAccessTokenById(id));
}
public static WebDavAccessToken GetWebDavAccessTokenByAccessToken(Guid accessToken)
{
return ObjectUtils.FillObjectFromDataReader<WebDavAccessToken>(DataProvider.GetWebDavAccessTokenByAccessToken(accessToken));
}
#region Directory Browsing
public static bool GetDirectoryBrowseEnabled(int itemId, string siteId)

View file

@ -56,6 +56,29 @@ namespace WebsitePanel.EnterpriseServer
[ToolboxItem(false)]
public class esEnterpriseStorage : WebService
{
[WebMethod]
public int AddWebDavAccessToken(WebDavAccessToken accessToken)
{
return EnterpriseStorageController.AddWebDavAccessToken(accessToken);
}
[WebMethod]
public void DeleteExpiredWebDavAccessTokens()
{
EnterpriseStorageController.DeleteExpiredWebDavAccessTokens();
}
[WebMethod]
public WebDavAccessToken GetWebDavAccessTokenById(int id)
{
return EnterpriseStorageController.GetWebDavAccessTokenById(id);
}
[WebMethod]
public WebDavAccessToken GetWebDavAccessTokenByAccessToken(Guid accessToken)
{
return EnterpriseStorageController.GetWebDavAccessTokenByAccessToken(accessToken);
}
[WebMethod]
public bool CheckFileServicesInstallation(int serviceId)

View file

@ -0,0 +1,14 @@
using System;
using WebsitePanel.EnterpriseServer.Base.HostedSolution;
using WebsitePanel.WebDav.Core.Security.Authentication.Principals;
namespace WebsitePanel.WebDav.Core.Interfaces.Managers
{
public interface IAccessTokenManager
{
WebDavAccessToken CreateToken(WspPrincipal principal, string filePath);
WebDavAccessToken GetToken(int id);
WebDavAccessToken GetToken(Guid guid);
void ClearExpiredTokens();
}
}

View file

@ -10,8 +10,5 @@ namespace WebsitePanel.WebDav.Core.Interfaces.Managers
byte[] GetFileBytes(string path);
IResource GetResource(string path);
string GetFileUrl(string path);
string CreateFileId(string path);
string FilePathFromId(string id);
}
}

View file

@ -4,6 +4,7 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web.Security;
using WebsitePanel.EnterpriseServer.Base.HostedSolution;
using WebsitePanel.WebDav.Core.Security.Authentication.Principals;
namespace WebsitePanel.WebDav.Core.Interfaces.Security
@ -11,9 +12,7 @@ namespace WebsitePanel.WebDav.Core.Interfaces.Security
public interface IAuthenticationService
{
WspPrincipal LogIn(string login, string password);
WspPrincipal LogIn(string accessToken);
void CreateAuthenticationTicket(WspPrincipal principal);
string CreateAccessToken(WspPrincipal principal);
void LogOut();
}
}

View file

@ -0,0 +1,42 @@
using System;
using WebsitePanel.EnterpriseServer.Base.HostedSolution;
using WebsitePanel.WebDav.Core.Interfaces.Managers;
using WebsitePanel.WebDav.Core.Security.Authentication.Principals;
using WebsitePanel.WebDav.Core.Wsp.Framework;
namespace WebsitePanel.WebDav.Core.Managers
{
public class AccessTokenManager : IAccessTokenManager
{
public WebDavAccessToken CreateToken(WspPrincipal principal, string filePath)
{
var token = new WebDavAccessToken();
token.AccessToken = Guid.NewGuid();
token.AccountId = principal.AccountId;
token.ItemId = principal.ItemId;
token.AuthData = principal.EncryptedPassword;
token.ExpirationDate = DateTime.Now.AddHours(3);
token.FilePath = filePath;
token.Id = WSP.Services.EnterpriseStorage.AddWebDavAccessToken(token);
return token;
}
public WebDavAccessToken GetToken(int id)
{
return WSP.Services.EnterpriseStorage.GetWebDavAccessTokenById(id);
}
public WebDavAccessToken GetToken(Guid guid)
{
return WSP.Services.EnterpriseStorage.GetWebDavAccessTokenByAccessToken(guid);
}
public void ClearExpiredTokens()
{
WSP.Services.EnterpriseStorage.DeleteExpiredWebDavAccessTokens();
}
}
}

View file

@ -164,16 +164,6 @@ namespace WebsitePanel.WebDav.Core.Managers
return rootFolders;
}
public string CreateFileId(string path)
{
return _cryptography.Encrypt(path).Replace("/", "AAAAA");
}
public string FilePathFromId(string id)
{
return _cryptography.Decrypt(id.Replace("AAAAA", "/"));
}
#region Helpers
private byte[] ReadFully(Stream input)

View file

@ -4,6 +4,7 @@ using System.Threading;
using System.Web;
using System.Web.Script.Serialization;
using System.Web.Security;
using WebsitePanel.EnterpriseServer.Base.HostedSolution;
using WebsitePanel.WebDav.Core.Config;
using WebsitePanel.WebDav.Core.Interfaces.Security;
using WebsitePanel.WebDav.Core.Security.Authentication.Principals;
@ -58,24 +59,6 @@ namespace WebsitePanel.WebDav.Core.Security.Authentication
return principal;
}
public WspPrincipal LogIn(string accessToken)
{
var token = _cryptography.Decrypt(accessToken.Replace("AAAAA", "/"));
var splitResult = token.Split(':');
var login = splitResult[0];
var password = _cryptography.Decrypt(splitResult[1]);
var expiration = DateTime.Parse(splitResult[2]);
if (expiration < DateTime.Today)
{
return null;
}
return LogIn(login, password);
}
public void CreateAuthenticationTicket(WspPrincipal principal)
{
var serializer = new JavaScriptSerializer();
@ -96,13 +79,6 @@ namespace WebsitePanel.WebDav.Core.Security.Authentication
HttpContext.Current.Response.Cookies.Add(cookie);
}
public string CreateAccessToken(WspPrincipal principal)
{
var token = string.Format("{0}:{1}:{2}", principal.Login, principal.EncryptedPassword, DateTime.Now.ToShortDateString());
return _cryptography.Encrypt(token).Replace("/", "AAAAA");
}
public void LogOut()
{
FormsAuthentication.SignOut();

View file

@ -12,7 +12,6 @@ namespace WebsitePanel.WebDav.Core.Security.Authentication.Principals
public int ItemId { get; set; }
public string Login { get; set; }
public string EncryptedPassword { get; set; }
public string DisplayName { get; set; }
@ -27,6 +26,8 @@ namespace WebsitePanel.WebDav.Core.Security.Authentication.Principals
[XmlIgnore, ScriptIgnore]
public IIdentity Identity { get; private set; }
public string EncryptedPassword { get; set; }
public WspPrincipal(string username)
{
Identity = new GenericIdentity(username);//new WindowsIdentity(username, "WindowsAuthentication");

View file

@ -127,6 +127,8 @@
<Compile Include="IFolder.cs" />
<Compile Include="IHierarchyItem.cs" />
<Compile Include="IItemContent.cs" />
<Compile Include="Managers\AccessTokenManager.cs" />
<Compile Include="Interfaces\Managers\IAccessTokenManager.cs" />
<Compile Include="Interfaces\Managers\IWebDavManager.cs" />
<Compile Include="Interfaces\Owa\IWopiServer.cs" />
<Compile Include="Interfaces\Security\IAuthenticationService.cs" />

View file

@ -30,13 +30,13 @@ namespace WebsitePanel.WebDavPortal
routes.MapRoute(
name: OwaRouteNames.GetFile,
url: "owa/wopi*/files/{encodedPath}/contents",
url: "owa/wopi*/files/{accessTokenId}/contents",
defaults: new { controller = "Owa", action = "GetFile" }
);
routes.MapRoute(
name: OwaRouteNames.CheckFileInfo,
url: "owa/wopi*/files/{encodedPath}",
url: "owa/wopi*/files/{accessTokenId}",
defaults: new { controller = "Owa", action = "CheckFileInfo" }
);

View file

@ -29,12 +29,14 @@ namespace WebsitePanel.WebDavPortal.Controllers
private readonly ICryptography _cryptography;
private readonly IWebDavManager _webdavManager;
private readonly IAuthenticationService _authenticationService;
private readonly IAccessTokenManager _tokenManager;
public FileSystemController(ICryptography cryptography, IWebDavManager webdavManager, IAuthenticationService authenticationService)
public FileSystemController(ICryptography cryptography, IWebDavManager webdavManager, IAuthenticationService authenticationService, IAccessTokenManager tokenManager)
{
_cryptography = cryptography;
_webdavManager = webdavManager;
_authenticationService = authenticationService;
_tokenManager = tokenManager;
}
[HttpGet]
@ -73,11 +75,11 @@ namespace WebsitePanel.WebDavPortal.Controllers
var owaOpener = WebDavAppConfigManager.Instance.OfficeOnline.Single(x => x.Extension == Path.GetExtension(pathPart));
string fileUrl = WebDavAppConfigManager.Instance.WebdavRoot+ org + "/" + pathPart.TrimStart('/');
string accessToken = _authenticationService.CreateAccessToken(WspContext.User);
var accessToken = _tokenManager.CreateToken(WspContext.User, pathPart);
string wopiSrc = Server.UrlDecode(Url.RouteUrl(OwaRouteNames.CheckFileInfo, new { encodedPath = _webdavManager.CreateFileId(pathPart) }, Request.Url.Scheme));
string wopiSrc = Server.UrlDecode(Url.RouteUrl(OwaRouteNames.CheckFileInfo, new { accessTokenId = accessToken.Id }, Request.Url.Scheme));
var uri = string.Format("{0}/{1}?WOPISrc={2}&access_token={3}", WebDavAppConfigManager.Instance.OfficeOnline.Url, owaOpener.OwaOpener, Server.UrlEncode(wopiSrc), Server.UrlEncode(accessToken));
var uri = string.Format("{0}/{1}?WOPISrc={2}&access_token={3}", WebDavAppConfigManager.Instance.OfficeOnline.Url, owaOpener.OwaOpener, Server.UrlEncode(wopiSrc), Server.UrlEncode(accessToken.AccessToken.ToString("N")));
return View(new OfficeOnlineModel(uri, new Uri(fileUrl).Segments.Last()));
}

View file

@ -1,12 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Web;
using System.Web.Mvc;
using WebsitePanel.EnterpriseServer.Base.HostedSolution;
using WebsitePanel.WebDav.Core.Interfaces.Managers;
using WebsitePanel.WebDav.Core.Interfaces.Owa;
using WebsitePanel.WebDav.Core.Interfaces.Security;
using WebsitePanel.WebDav.Core.Security.Cryptography;
using WebsitePanel.WebDav.Core.Wsp.Framework;
namespace WebsitePanel.WebDavPortal.Controllers
{
@ -16,28 +19,40 @@ namespace WebsitePanel.WebDavPortal.Controllers
private readonly IWopiServer _wopiServer;
private readonly IWebDavManager _webDavManager;
private readonly IAuthenticationService _authenticationService;
private readonly IAccessTokenManager _tokenManager;
private readonly ICryptography _cryptography;
private WebDavAccessToken _token;
public OwaController(IWopiServer wopiServer, IWebDavManager webDavManager, IAuthenticationService authenticationService)
public OwaController(IWopiServer wopiServer, IWebDavManager webDavManager, IAuthenticationService authenticationService, IAccessTokenManager tokenManager, ICryptography cryptography)
{
_wopiServer = wopiServer;
_webDavManager = webDavManager;
_authenticationService = authenticationService;
_tokenManager = tokenManager;
_cryptography = cryptography;
}
public JsonResult CheckFileInfo( string encodedPath)
public ActionResult CheckFileInfo(int accessTokenId)
{
var path = _webDavManager.FilePathFromId(encodedPath);
if (!CheckAccess(accessTokenId))
{
return new HttpStatusCodeResult(HttpStatusCode.NoContent);
}
var fileInfo = _wopiServer.GetCheckFileInfo(path);
var fileInfo = _wopiServer.GetCheckFileInfo(_token.FilePath);
return Json(fileInfo, JsonRequestBehavior.AllowGet);
}
public FileResult GetFile(string encodedPath)
public ActionResult GetFile(int accessTokenId)
{
var path = _webDavManager.FilePathFromId(encodedPath);
if (!CheckAccess(accessTokenId))
{
return new HttpStatusCodeResult(HttpStatusCode.NoContent);
}
return _wopiServer.GetFile(path);
return _wopiServer.GetFile((_token.FilePath));
}
protected override void OnActionExecuting(ActionExecutingContext filterContext)
@ -46,8 +61,26 @@ namespace WebsitePanel.WebDavPortal.Controllers
if (!string.IsNullOrEmpty(Request["access_token"]))
{
_authenticationService.LogIn(Request["access_token"]);
}
var guid = Guid.Parse((Request["access_token"]));
_tokenManager.ClearExpiredTokens();
_token = _tokenManager.GetToken(guid);
var user = WSP.Services.ExchangeServer.GetAccount(_token.ItemId, _token.AccountId);
_authenticationService.LogIn(user.UserPrincipalName, _cryptography.Decrypt(_token.AuthData));
}
}
private bool CheckAccess(int accessTokenId)
{
if (_token == null || accessTokenId != _token.Id)
{
return false;
}
return true;
}
}
}

View file

@ -25,6 +25,7 @@ namespace WebsitePanel.WebDavPortal.DependencyInjection
kernel.Bind<ICryptography>().To<CryptoUtils>();
kernel.Bind<IAuthenticationService>().To<FormsAuthenticationService>();
kernel.Bind<IWebDavManager>().To<WebDavManager>();
kernel.Bind<IAccessTokenManager>().To<AccessTokenManager>();
kernel.Bind<IWopiServer>().To<WopiServer>();
}
}