From f2c54df2b02ea310c92a06ed58ab72b34f97d317 Mon Sep 17 00:00:00 2001 From: vfedosevich Date: Thu, 15 Jan 2015 04:03:02 -0800 Subject: [PATCH] webdav protal office 365 fix --- .../Config/Entities/OfficeOnlineCollection.cs | 10 +- .../WebConfigSections/OfficeOnlineElement.cs | 8 ++ .../Entities/Owa/CheckFileInfo.cs | 124 ++++++++++++++++++ .../ConnectToWebDavServerException.cs | 2 +- .../Exceptions/ResourceNotFoundException.cs | 2 +- .../WebsitePanel.WebDav.Core/IFolder.cs | 11 +- .../Interfaces/Managers}/IWebDavManager.cs | 6 +- .../Interfaces/Owa/IWopiServer.cs | 12 ++ .../Security/IAuthenticationService.cs | 3 + .../Managers}/WebDavManager.cs | 81 ++++++++---- .../Owa/WopiServer.cs | 58 ++++++++ .../FormsAuthenticationService.cs | 37 +++++- .../Authentication/Principals/WspPrincipal.cs | 4 +- .../WebsitePanel.WebDav.Core.csproj | 15 +++ .../WebsitePanel.WebDav.Core/packages.config | 1 + .../App_Start/RouteConfig.cs | 18 ++- .../Controllers/AccountController.cs | 6 +- .../Controllers/FileSystemController.cs | 22 +++- .../Controllers/OwaController.cs | 53 ++++++++ .../DependencyInjection/PortalDependencies.cs | 4 + .../Providers/WebDavManagerProvider.cs | 2 +- .../FileOperations/FileOpenerManager.cs | 2 +- .../WebsitePanel.WebDavPortal/Global.asax.cs | 19 ++- .../UI/Routes/OwaRouteNames.cs | 8 ++ .../Views/FileSystem/ShowContent.cshtml | 3 +- .../WebsitePanel.WebDavPortal/Web.config | 25 ++-- .../WebsitePanel.WebDavPortal.csproj | 10 +- 27 files changed, 466 insertions(+), 80 deletions(-) create mode 100644 WebsitePanel/Sources/WebsitePanel.WebDav.Core/Entities/Owa/CheckFileInfo.cs rename WebsitePanel/Sources/{WebsitePanel.WebDavPortal => WebsitePanel.WebDav.Core}/Exceptions/ConnectToWebDavServerException.cs (89%) rename WebsitePanel/Sources/{WebsitePanel.WebDavPortal => WebsitePanel.WebDav.Core}/Exceptions/ResourceNotFoundException.cs (88%) rename WebsitePanel/Sources/{WebsitePanel.WebDavPortal/Models => WebsitePanel.WebDav.Core/Interfaces/Managers}/IWebDavManager.cs (64%) create mode 100644 WebsitePanel/Sources/WebsitePanel.WebDav.Core/Interfaces/Owa/IWopiServer.cs rename WebsitePanel/Sources/{WebsitePanel.WebDavPortal/Models => WebsitePanel.WebDav.Core/Managers}/WebDavManager.cs (68%) create mode 100644 WebsitePanel/Sources/WebsitePanel.WebDav.Core/Owa/WopiServer.cs create mode 100644 WebsitePanel/Sources/WebsitePanel.WebDavPortal/Controllers/OwaController.cs create mode 100644 WebsitePanel/Sources/WebsitePanel.WebDavPortal/UI/Routes/OwaRouteNames.cs diff --git a/WebsitePanel/Sources/WebsitePanel.WebDav.Core/Config/Entities/OfficeOnlineCollection.cs b/WebsitePanel/Sources/WebsitePanel.WebDav.Core/Config/Entities/OfficeOnlineCollection.cs index a28114b5..4ecb0c7f 100644 --- a/WebsitePanel/Sources/WebsitePanel.WebDav.Core/Config/Entities/OfficeOnlineCollection.cs +++ b/WebsitePanel/Sources/WebsitePanel.WebDav.Core/Config/Entities/OfficeOnlineCollection.cs @@ -5,21 +5,21 @@ using WebsitePanel.WebDavPortal.WebConfigSections; namespace WebsitePanel.WebDav.Core.Config.Entities { - public class OfficeOnlineCollection : AbstractConfigCollection, IReadOnlyCollection + public class OfficeOnlineCollection : AbstractConfigCollection, IReadOnlyCollection { - private readonly IList _officeExtensions; + private readonly IList _officeExtensions; public OfficeOnlineCollection() { IsEnabled = ConfigSection.OfficeOnline.IsEnabled; Url = ConfigSection.OfficeOnline.Url; - _officeExtensions = ConfigSection.OfficeOnline.Cast().Select(x => x.Extension).ToList(); + _officeExtensions = ConfigSection.OfficeOnline.Cast().ToList(); } public bool IsEnabled { get; private set; } public string Url { get; private set; } - public IEnumerator GetEnumerator() + public IEnumerator GetEnumerator() { return _officeExtensions.GetEnumerator(); } @@ -36,7 +36,7 @@ namespace WebsitePanel.WebDav.Core.Config.Entities public bool Contains(string extension) { - return _officeExtensions.Contains(extension); + return _officeExtensions.Any(x=>x.Extension == extension); } } } \ No newline at end of file diff --git a/WebsitePanel/Sources/WebsitePanel.WebDav.Core/Config/WebConfigSections/OfficeOnlineElement.cs b/WebsitePanel/Sources/WebsitePanel.WebDav.Core/Config/WebConfigSections/OfficeOnlineElement.cs index a6c25031..1f836eb3 100644 --- a/WebsitePanel/Sources/WebsitePanel.WebDav.Core/Config/WebConfigSections/OfficeOnlineElement.cs +++ b/WebsitePanel/Sources/WebsitePanel.WebDav.Core/Config/WebConfigSections/OfficeOnlineElement.cs @@ -5,6 +5,7 @@ namespace WebsitePanel.WebDavPortal.WebConfigSections public class OfficeOnlineElement : ConfigurationElement { private const string ExtensionKey = "extension"; + private const string OwaOpenerKey = "owaOpener"; [ConfigurationProperty(ExtensionKey, IsKey = true, IsRequired = true)] public string Extension @@ -12,5 +13,12 @@ namespace WebsitePanel.WebDavPortal.WebConfigSections get { return this[ExtensionKey].ToString(); } set { this[ExtensionKey] = value; } } + + [ConfigurationProperty(OwaOpenerKey, IsKey = true, IsRequired = true)] + public string OwaOpener + { + get { return this[OwaOpenerKey].ToString(); } + set { this[OwaOpenerKey] = value; } + } } } \ No newline at end of file diff --git a/WebsitePanel/Sources/WebsitePanel.WebDav.Core/Entities/Owa/CheckFileInfo.cs b/WebsitePanel/Sources/WebsitePanel.WebDav.Core/Entities/Owa/CheckFileInfo.cs new file mode 100644 index 00000000..e4283ac9 --- /dev/null +++ b/WebsitePanel/Sources/WebsitePanel.WebDav.Core/Entities/Owa/CheckFileInfo.cs @@ -0,0 +1,124 @@ +using System.Runtime.Serialization; + +namespace WebsitePanel.WebDav.Core.Entities.Owa +{ + [DataContract] + public class CheckFileInfo + { + [DataMember] + public string BaseFileName { get; set; } + [DataMember] + public string OwnerId { get; set; } + [DataMember] + public long Size { get; set; } + [DataMember] + public string Version { get; set; } + + //[DataMember] + //public string SHA256 { get; set; } + //[DataMember] + //public bool AllowExternalMarketplace { get; set; } + //[DataMember] + //public string BreadcrumbBrandName { get; set; } + //[DataMember] + //public string BreadcrumbBrandUrl { get; set; } + //[DataMember] + //public string BreadcrumbDocName { get; set; } + //[DataMember] + //public string BreadcrumbDocUrl { get; set; } + //[DataMember] + //public string BreadcrumbFolderName { get; set; } + //[DataMember] + //public string BreadcrumbFolderUrl { get; set; } + //[DataMember] + //public string ClientUrl { get; set; } + //[DataMember] + //public bool CloseButtonClosesWindow { get; set; } + //[DataMember] + //public string CloseUrl { get; set; } + //[DataMember] + //public bool DisableBrowserCachingOfUserContent { get; set; } + //[DataMember] + //public bool DisablePrint { get; set; } + //[DataMember] + //public bool DisableTranslation { get; set; } + //[DataMember] + //public string DownloadUrl { get; set; } + //[DataMember] + //public string FileSharingUrl { get; set; } + //[DataMember] + //public string FileUrl { get; set; } + //[DataMember] + //public string HostAuthenticationId { get; set; } + //[DataMember] + //public string HostEditUrl { get; set; } + //[DataMember] + //public string HostEmbeddedEditUrl { get; set; } + //[DataMember] + //public string HostEmbeddedViewUrl { get; set; } + //[DataMember] + //public string HostName { get; set; } + //[DataMember] + //public string HostNotes { get; set; } + //[DataMember] + //public string HostRestUrl { get; set; } + //[DataMember] + //public string HostViewUrl { get; set; } + //[DataMember] + //public string IrmPolicyDescription { get; set; } + //[DataMember] + //public string IrmPolicyTitle { get; set; } + + //[DataMember] + //public string PresenceProvider { get; set; } + //[DataMember] + //public string PresenceUserId { get; set; } + //[DataMember] + //public string PrivacyUrl { get; set; } + //[DataMember] + //public bool ProtectInClient { get; set; } + //[DataMember] + //public bool ReadOnly { get; set; } + //[DataMember] + //public bool RestrictedWebViewOnly { get; set; } + + //[DataMember] + //public string SignoutUrl { get; set; } + + //[DataMember] + //public bool SupportsCoauth { get; set; } + //[DataMember] + //public bool SupportsCobalt { get; set; } + //[DataMember] + //public bool SupportsFolders { get; set; } + //[DataMember] + //public bool SupportsLocks { get; set; } + //[DataMember] + //public bool SupportsScenarioLinks { get; set; } + //[DataMember] + //public bool SupportsSecureStore { get; set; } + //[DataMember] + //public bool SupportsUpdate { get; set; } + //[DataMember] + //public string TenantId { get; set; } + //[DataMember] + //public string TermsOfUseUrl { get; set; } + //[DataMember] + //public string TimeZone { get; set; } + //[DataMember] + //public bool UserCanAttend { get; set; } + //[DataMember] + //public bool UserCanNotWriteRelative { get; set; } + //[DataMember] + //public bool UserCanPresent { get; set; } + //[DataMember] + //public bool UserCanWrite { get; set; } + //[DataMember] + //public string UserFriendlyName { get; set; } + //[DataMember] + //public string UserId { get; set; } + + //[DataMember] + //public bool WebEditingDisabled { get; set; } + } +} \ No newline at end of file diff --git a/WebsitePanel/Sources/WebsitePanel.WebDavPortal/Exceptions/ConnectToWebDavServerException.cs b/WebsitePanel/Sources/WebsitePanel.WebDav.Core/Exceptions/ConnectToWebDavServerException.cs similarity index 89% rename from WebsitePanel/Sources/WebsitePanel.WebDavPortal/Exceptions/ConnectToWebDavServerException.cs rename to WebsitePanel/Sources/WebsitePanel.WebDav.Core/Exceptions/ConnectToWebDavServerException.cs index 00cc4047..b0c58dd3 100644 --- a/WebsitePanel/Sources/WebsitePanel.WebDavPortal/Exceptions/ConnectToWebDavServerException.cs +++ b/WebsitePanel/Sources/WebsitePanel.WebDav.Core/Exceptions/ConnectToWebDavServerException.cs @@ -1,7 +1,7 @@ using System; using System.Runtime.Serialization; -namespace WebsitePanel.WebDavPortal.Exceptions +namespace WebsitePanel.WebDav.Core.Exceptions { [Serializable] public class ConnectToWebDavServerException : Exception diff --git a/WebsitePanel/Sources/WebsitePanel.WebDavPortal/Exceptions/ResourceNotFoundException.cs b/WebsitePanel/Sources/WebsitePanel.WebDav.Core/Exceptions/ResourceNotFoundException.cs similarity index 88% rename from WebsitePanel/Sources/WebsitePanel.WebDavPortal/Exceptions/ResourceNotFoundException.cs rename to WebsitePanel/Sources/WebsitePanel.WebDav.Core/Exceptions/ResourceNotFoundException.cs index fd6aca0d..46d6f1c0 100644 --- a/WebsitePanel/Sources/WebsitePanel.WebDavPortal/Exceptions/ResourceNotFoundException.cs +++ b/WebsitePanel/Sources/WebsitePanel.WebDav.Core/Exceptions/ResourceNotFoundException.cs @@ -1,7 +1,7 @@ using System; using System.Runtime.Serialization; -namespace WebsitePanel.WebDavPortal.Exceptions +namespace WebsitePanel.WebDav.Core.Exceptions { [Serializable] public class ResourceNotFoundException : Exception diff --git a/WebsitePanel/Sources/WebsitePanel.WebDav.Core/IFolder.cs b/WebsitePanel/Sources/WebsitePanel.WebDav.Core/IFolder.cs index 9b14cf8a..eb1e1f99 100644 --- a/WebsitePanel/Sources/WebsitePanel.WebDav.Core/IFolder.cs +++ b/WebsitePanel/Sources/WebsitePanel.WebDav.Core/IFolder.cs @@ -1,4 +1,5 @@ using System; +using System.DirectoryServices.AccountManagement; using System.IO; using System.Linq; using System.Net; @@ -6,6 +7,7 @@ using System.Net.Security; using System.Text; using System.Text.RegularExpressions; using System.Xml; +using WebsitePanel.WebDav.Core.Config; using WebsitePanel.WebDav.Core.Exceptions; namespace WebsitePanel.WebDav.Core @@ -18,6 +20,7 @@ namespace WebsitePanel.WebDav.Core IFolder CreateFolder(string name); IHierarchyItem[] GetChildren(); IResource GetResource(string name); + Uri Path { get; } } public class WebDavFolder : WebDavHierarchyItem, IFolder @@ -25,6 +28,8 @@ namespace WebsitePanel.WebDav.Core private IHierarchyItem[] _children = new IHierarchyItem[0]; private Uri _path; + public Uri Path { get { return _path; } } + /// /// The constructor /// @@ -155,7 +160,7 @@ namespace WebsitePanel.WebDav.Core /// public void Open() { - var request = (HttpWebRequest) WebRequest.Create(_path); + var request = (HttpWebRequest)WebRequest.Create(_path); request.PreAuthenticate = true; request.Method = "PROPFIND"; request.ContentType = "application/xml"; @@ -163,10 +168,10 @@ namespace WebsitePanel.WebDav.Core //TODO Disable SSL ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(delegate { return true; }); - var credentials = (NetworkCredential) _credentials; + var credentials = (NetworkCredential)_credentials; if (credentials != null && credentials.UserName != null) { - request.Credentials = credentials; + //request.Credentials = credentials; string auth = "Basic " + Convert.ToBase64String( Encoding.Default.GetBytes(credentials.UserName + ":" + credentials.Password)); diff --git a/WebsitePanel/Sources/WebsitePanel.WebDavPortal/Models/IWebDavManager.cs b/WebsitePanel/Sources/WebsitePanel.WebDav.Core/Interfaces/Managers/IWebDavManager.cs similarity index 64% rename from WebsitePanel/Sources/WebsitePanel.WebDavPortal/Models/IWebDavManager.cs rename to WebsitePanel/Sources/WebsitePanel.WebDav.Core/Interfaces/Managers/IWebDavManager.cs index f50fc984..f3900c88 100644 --- a/WebsitePanel/Sources/WebsitePanel.WebDavPortal/Models/IWebDavManager.cs +++ b/WebsitePanel/Sources/WebsitePanel.WebDav.Core/Interfaces/Managers/IWebDavManager.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; using WebsitePanel.WebDav.Core.Client; -namespace WebsitePanel.WebDavPortal.Models +namespace WebsitePanel.WebDav.Core.Interfaces.Managers { public interface IWebDavManager { @@ -10,6 +10,10 @@ namespace WebsitePanel.WebDavPortal.Models IEnumerable GetChildren(); bool IsFile(string fileName); byte[] GetFileBytes(string fileName); + IResource GetResource( string fileName); string GetFileUrl(string fileName); + + string CreateFileId(string path); + string FilePathFromId(string id); } } \ No newline at end of file diff --git a/WebsitePanel/Sources/WebsitePanel.WebDav.Core/Interfaces/Owa/IWopiServer.cs b/WebsitePanel/Sources/WebsitePanel.WebDav.Core/Interfaces/Owa/IWopiServer.cs new file mode 100644 index 00000000..6f35d7ff --- /dev/null +++ b/WebsitePanel/Sources/WebsitePanel.WebDav.Core/Interfaces/Owa/IWopiServer.cs @@ -0,0 +1,12 @@ +using System.Web.Mvc; +using WebsitePanel.WebDav.Core.Client; +using WebsitePanel.WebDav.Core.Entities.Owa; + +namespace WebsitePanel.WebDav.Core.Interfaces.Owa +{ + public interface IWopiServer + { + CheckFileInfo GetCheckFileInfo(string path); + FileResult GetFile(string path); + } +} \ No newline at end of file diff --git a/WebsitePanel/Sources/WebsitePanel.WebDav.Core/Interfaces/Security/IAuthenticationService.cs b/WebsitePanel/Sources/WebsitePanel.WebDav.Core/Interfaces/Security/IAuthenticationService.cs index 6bd042a4..771774f8 100644 --- a/WebsitePanel/Sources/WebsitePanel.WebDav.Core/Interfaces/Security/IAuthenticationService.cs +++ b/WebsitePanel/Sources/WebsitePanel.WebDav.Core/Interfaces/Security/IAuthenticationService.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using System.Web.Security; using WebsitePanel.WebDav.Core.Security.Authentication.Principals; namespace WebsitePanel.WebDav.Core.Interfaces.Security @@ -10,7 +11,9 @@ 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(); } } diff --git a/WebsitePanel/Sources/WebsitePanel.WebDavPortal/Models/WebDavManager.cs b/WebsitePanel/Sources/WebsitePanel.WebDav.Core/Managers/WebDavManager.cs similarity index 68% rename from WebsitePanel/Sources/WebsitePanel.WebDavPortal/Models/WebDavManager.cs rename to WebsitePanel/Sources/WebsitePanel.WebDav.Core/Managers/WebDavManager.cs index 0ab50f03..05a7d69f 100644 --- a/WebsitePanel/Sources/WebsitePanel.WebDavPortal/Models/WebDavManager.cs +++ b/WebsitePanel/Sources/WebsitePanel.WebDav.Core/Managers/WebDavManager.cs @@ -3,20 +3,16 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; -using System.Text.RegularExpressions; -using WebsitePanel.WebDav.Core; +using log4net; +using WebsitePanel.Providers.OS; using WebsitePanel.WebDav.Core.Client; using WebsitePanel.WebDav.Core.Config; +using WebsitePanel.WebDav.Core.Exceptions; +using WebsitePanel.WebDav.Core.Interfaces.Managers; using WebsitePanel.WebDav.Core.Security.Cryptography; using WebsitePanel.WebDav.Core.Wsp.Framework; -using WebsitePanel.WebDavPortal.Exceptions; -using WebsitePanel.Providers.OS; -using Ninject; -using WebsitePanel.WebDavPortal.DependencyInjection; -using System.Web.Mvc; -using log4net; -namespace WebsitePanel.WebDavPortal.Models +namespace WebsitePanel.WebDav.Core.Managers { public class WebDavManager : IWebDavManager { @@ -25,15 +21,15 @@ namespace WebsitePanel.WebDavPortal.Models private readonly ILog Log; - private IList _rootFolders; - private int _itemId; private IFolder _currentFolder; - private string _webDavRootPath; private bool _isRoot = true; + private Lazy> _rootFolders; + private Lazy _webDavRootPath; + public string RootPath { - get { return _webDavRootPath; } + get { return _webDavRootPath.Value; } } public WebDavManager(ICryptography cryptography) @@ -41,20 +37,21 @@ namespace WebsitePanel.WebDavPortal.Models _cryptography = cryptography; Log = LogManager.GetLogger(this.GetType()); - var credential = new NetworkCredential(WspContext.User.Login, _cryptography.Decrypt(WspContext.User.EncryptedPassword), WebDavAppConfigManager.Instance.UserDomain); - _webDavSession = new WebDavSession(); - _webDavSession.Credentials = credential; - _itemId = WspContext.User.ItemId; - _rootFolders = ConnectToWebDavServer(); - - if (_rootFolders.Any()) + _rootFolders = new Lazy>(ConnectToWebDavServer); + _webDavRootPath = new Lazy(() => { - var folder = _rootFolders.First(); - var uri = new Uri(folder.Url); - _webDavRootPath = uri.Scheme + "://" + uri.Host + uri.Segments[0] + uri.Segments[1]; - } + if (_rootFolders.Value.Any()) + { + var folder = _rootFolders.Value.First(); + var uri = new Uri(folder.Url); + return uri.Scheme + "://" + uri.Host + uri.Segments[0] + uri.Segments[1]; + } + + return string.Empty; + }); + } public void OpenFolder(string pathPart) @@ -64,8 +61,12 @@ namespace WebsitePanel.WebDavPortal.Models _isRoot = true; return; } + _isRoot = false; - _currentFolder = _webDavSession.OpenFolder(_webDavRootPath + pathPart); + + _webDavSession.Credentials = new NetworkCredential(WspContext.User.Login, _cryptography.Decrypt(WspContext.User.EncryptedPassword), WebDavAppConfigManager.Instance.UserDomain); + + _currentFolder = _webDavSession.OpenFolder(_webDavRootPath.Value + pathPart); } public IEnumerable GetChildren() @@ -74,7 +75,7 @@ namespace WebsitePanel.WebDavPortal.Models if (_isRoot) { - children = _rootFolders.Select(x => new WebDavHierarchyItem {Href = new Uri(x.Url), ItemType = ItemType.Folder}).ToArray(); + children = _rootFolders.Value.Select(x => new WebDavHierarchyItem {Href = new Uri(x.Url), ItemType = ItemType.Folder}).ToArray(); } else { @@ -119,6 +120,19 @@ namespace WebsitePanel.WebDavPortal.Models } } + public IResource GetResource(string fileName) + { + try + { + IResource resource = _currentFolder.GetResource(fileName); + return resource; + } + catch (InvalidOperationException exception) + { + throw new ResourceNotFoundException("Resource not found", exception); + } + } + public string GetFileUrl(string fileName) { try @@ -139,9 +153,9 @@ namespace WebsitePanel.WebDavPortal.Models var userGroups = WSP.Services.Organizations.GetSecurityGroupsByMember(user.ItemId, user.AccountId); - foreach (var folder in WSP.Services.EnterpriseStorage.GetEnterpriseFolders(_itemId)) + foreach (var folder in WSP.Services.EnterpriseStorage.GetEnterpriseFolders(WspContext.User.ItemId)) { - var permissions = WSP.Services.EnterpriseStorage.GetEnterpriseFolderPermissions(_itemId, folder.Name); + var permissions = WSP.Services.EnterpriseStorage.GetEnterpriseFolderPermissions(WspContext.User.ItemId, folder.Name); foreach (var permission in permissions) { @@ -168,5 +182,16 @@ namespace WebsitePanel.WebDavPortal.Models return ms.ToArray(); } } + + + public string CreateFileId(string path) + { + return _cryptography.Encrypt(path).Replace("/", "AAAAA"); + } + + public string FilePathFromId(string id) + { + return _cryptography.Decrypt(id.Replace("AAAAA", "/")); + } } } \ No newline at end of file diff --git a/WebsitePanel/Sources/WebsitePanel.WebDav.Core/Owa/WopiServer.cs b/WebsitePanel/Sources/WebsitePanel.WebDav.Core/Owa/WopiServer.cs new file mode 100644 index 00000000..7f646f02 --- /dev/null +++ b/WebsitePanel/Sources/WebsitePanel.WebDav.Core/Owa/WopiServer.cs @@ -0,0 +1,58 @@ +using System; +using System.IO; +using System.Linq; +using System.Net.Mime; +using System.Runtime.Serialization.Json; +using System.Text; +using System.Web.Mvc; +using WebsitePanel.WebDav.Core.Client; +using WebsitePanel.WebDav.Core.Entities.Owa; +using WebsitePanel.WebDav.Core.Interfaces.Managers; +using WebsitePanel.WebDav.Core.Interfaces.Owa; + +namespace WebsitePanel.WebDav.Core.Owa +{ + public class WopiServer : IWopiServer + { + private readonly IWebDavManager _webDavManager; + + public WopiServer(IWebDavManager webDavManager) + { + _webDavManager = webDavManager; + } + + public CheckFileInfo GetCheckFileInfo(string path) + { + string fileName = path.Split('/').Last(); + int index = path.LastIndexOf(fileName, StringComparison.InvariantCultureIgnoreCase); + string folder = path.Remove(index - 1, fileName.Length + 1); + + _webDavManager.OpenFolder(folder); + + var resource = _webDavManager.GetResource(fileName); + + var cFileInfo = new CheckFileInfo + { + BaseFileName = resource.DisplayName, + OwnerId = @"4257508bfe174aa28b461536d8b6b648", + Size = resource.ContentLength, + Version = @"%22%7B59CCD75F%2D0687%2D4F86%2DBBCF%2D059126640640%7D%2C1%22" + }; + + return cFileInfo; + } + + public FileResult GetFile(string path) + { + string fileName = path.Split('/').Last(); + int index = path.LastIndexOf(fileName, StringComparison.InvariantCultureIgnoreCase); + string folder = path.Remove(index - 1, fileName.Length + 1); + + _webDavManager.OpenFolder(folder); + + var fileBytes = _webDavManager.GetFileBytes(fileName); + + return new FileContentResult(fileBytes, MediaTypeNames.Application.Octet); + } + } +} \ No newline at end of file diff --git a/WebsitePanel/Sources/WebsitePanel.WebDav.Core/Security/Authentication/FormsAuthenticationService.cs b/WebsitePanel/Sources/WebsitePanel.WebDav.Core/Security/Authentication/FormsAuthenticationService.cs index b33ae4ac..bf1cdec0 100644 --- a/WebsitePanel/Sources/WebsitePanel.WebDav.Core/Security/Authentication/FormsAuthenticationService.cs +++ b/WebsitePanel/Sources/WebsitePanel.WebDav.Core/Security/Authentication/FormsAuthenticationService.cs @@ -1,5 +1,6 @@ using System; using System.DirectoryServices.AccountManagement; +using System.Threading; using System.Web; using System.Web.Script.Serialization; using System.Web.Security; @@ -29,8 +30,10 @@ namespace WebsitePanel.WebDav.Core.Security.Authentication return null; } - var principal = new WspPrincipal(login); + //var user = UserPrincipal.FindByIdentity(_principalContext, IdentityType.UserPrincipalName, login); + var principal = new WspPrincipal(login); + var exchangeAccount = WSP.Services.ExchangeServer.GetAccountByAccountNameWithoutItemId(login); var organization = WSP.Services.Organizations.GetOrganization(exchangeAccount.ItemId); @@ -40,13 +43,34 @@ namespace WebsitePanel.WebDav.Core.Security.Authentication principal.DisplayName = exchangeAccount.DisplayName; principal.EncryptedPassword = _cryptography.Encrypt(password); - CreateAuthenticationTicket(principal); + if (HttpContext.Current != null) + { + HttpContext.Current.User = principal; + } - HttpContext.Current.User = principal; + Thread.CurrentPrincipal = principal; 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(); @@ -67,6 +91,13 @@ 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(); diff --git a/WebsitePanel/Sources/WebsitePanel.WebDav.Core/Security/Authentication/Principals/WspPrincipal.cs b/WebsitePanel/Sources/WebsitePanel.WebDav.Core/Security/Authentication/Principals/WspPrincipal.cs index 15401a14..e289b687 100644 --- a/WebsitePanel/Sources/WebsitePanel.WebDav.Core/Security/Authentication/Principals/WspPrincipal.cs +++ b/WebsitePanel/Sources/WebsitePanel.WebDav.Core/Security/Authentication/Principals/WspPrincipal.cs @@ -28,8 +28,8 @@ namespace WebsitePanel.WebDav.Core.Security.Authentication.Principals public IIdentity Identity { get; private set; } public WspPrincipal(string username) - { - Identity = new GenericIdentity(username); + { + Identity = new GenericIdentity(username);//new WindowsIdentity(username, "WindowsAuthentication"); Login = username; } diff --git a/WebsitePanel/Sources/WebsitePanel.WebDav.Core/WebsitePanel.WebDav.Core.csproj b/WebsitePanel/Sources/WebsitePanel.WebDav.Core/WebsitePanel.WebDav.Core.csproj index cdd7e02b..9823dce5 100644 --- a/WebsitePanel/Sources/WebsitePanel.WebDav.Core/WebsitePanel.WebDav.Core.csproj +++ b/WebsitePanel/Sources/WebsitePanel.WebDav.Core/WebsitePanel.WebDav.Core.csproj @@ -32,6 +32,9 @@ 4 + + ..\packages\log4net.2.0.0\lib\net40-full\log4net.dll + True ..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll @@ -45,6 +48,7 @@ + C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.5\System.Web.dll @@ -79,6 +83,10 @@ + + False + ..\..\..\..\Scheduler Domains\WebsitePanel\Bin\WebsitePanel.EnterpriseServer.Base.dll + ..\WebsitePanel.WebPortal\Bin\WebsitePanel.EnterpriseServer.Client.dll @@ -108,6 +116,9 @@ + + + @@ -115,11 +126,14 @@ + + + @@ -132,6 +146,7 @@ + diff --git a/WebsitePanel/Sources/WebsitePanel.WebDav.Core/packages.config b/WebsitePanel/Sources/WebsitePanel.WebDav.Core/packages.config index 2b0a9f5f..ad6a1af2 100644 --- a/WebsitePanel/Sources/WebsitePanel.WebDav.Core/packages.config +++ b/WebsitePanel/Sources/WebsitePanel.WebDav.Core/packages.config @@ -1,5 +1,6 @@  + diff --git a/WebsitePanel/Sources/WebsitePanel.WebDavPortal/App_Start/RouteConfig.cs b/WebsitePanel/Sources/WebsitePanel.WebDavPortal/App_Start/RouteConfig.cs index d8b9682d..0b86bcc2 100644 --- a/WebsitePanel/Sources/WebsitePanel.WebDavPortal/App_Start/RouteConfig.cs +++ b/WebsitePanel/Sources/WebsitePanel.WebDavPortal/App_Start/RouteConfig.cs @@ -26,12 +26,28 @@ namespace WebsitePanel.WebDavPortal #endregion + #region Owa + + routes.MapRoute( + name: OwaRouteNames.GetFile, + url: "owa/wopi*/files/{encodedPath}/contents", + defaults: new { controller = "Owa", action = "GetFile" } + ); + + routes.MapRoute( + name: OwaRouteNames.CheckFileInfo, + url: "owa/wopi*/files/{encodedPath}", + defaults: new { controller = "Owa", action = "CheckFileInfo" } + ); + + #endregion + routes.MapRoute( name: "Office365DocumentRoute", url: "office365/{org}/{*pathPart}", defaults: new { controller = "FileSystem", action = "ShowOfficeDocument", pathPart = UrlParameter.Optional } ); - + routes.MapRoute( name: FileSystemRouteNames.FilePath, url: "{org}/{*pathPart}", diff --git a/WebsitePanel/Sources/WebsitePanel.WebDavPortal/Controllers/AccountController.cs b/WebsitePanel/Sources/WebsitePanel.WebDavPortal/Controllers/AccountController.cs index f3b3e1b2..b63ff4dd 100644 --- a/WebsitePanel/Sources/WebsitePanel.WebDavPortal/Controllers/AccountController.cs +++ b/WebsitePanel/Sources/WebsitePanel.WebDavPortal/Controllers/AccountController.cs @@ -3,8 +3,8 @@ using System.Net; using System.Web.Mvc; using System.Web.Routing; using WebsitePanel.WebDav.Core.Config; +using WebsitePanel.WebDav.Core.Security.Authentication; using WebsitePanel.WebDav.Core.Security.Cryptography; -using WebsitePanel.WebDavPortal.Exceptions; using WebsitePanel.WebDavPortal.Models; using WebsitePanel.WebDavPortal.UI.Routes; using WebsitePanel.WebDav.Core.Interfaces.Security; @@ -39,11 +39,13 @@ namespace WebsitePanel.WebDavPortal.Controllers public ActionResult Login(AccountModel model) { var user = _authenticationService.LogIn(model.Login, model.Password); - + ViewBag.LdapIsAuthentication = user.Identity.IsAuthenticated; if (user.Identity.IsAuthenticated) { + _authenticationService.CreateAuthenticationTicket(user); + Session[WebDavAppConfigManager.Instance.SessionKeys.WebDavManager] = null; return RedirectToRoute(FileSystemRouteNames.FilePath, new { org = WspContext.User.OrganizationId }); diff --git a/WebsitePanel/Sources/WebsitePanel.WebDavPortal/Controllers/FileSystemController.cs b/WebsitePanel/Sources/WebsitePanel.WebDavPortal/Controllers/FileSystemController.cs index 80966704..f2411e82 100644 --- a/WebsitePanel/Sources/WebsitePanel.WebDavPortal/Controllers/FileSystemController.cs +++ b/WebsitePanel/Sources/WebsitePanel.WebDavPortal/Controllers/FileSystemController.cs @@ -1,17 +1,23 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Net.Mime; using System.Web; using System.Web.Mvc; +using System.Web.Routing; using WebsitePanel.WebDav.Core; using WebsitePanel.WebDav.Core.Client; using WebsitePanel.WebDav.Core.Config; using WebsitePanel.WebDav.Core.Exceptions; +using WebsitePanel.WebDav.Core.Interfaces.Managers; +using WebsitePanel.WebDav.Core.Interfaces.Security; +using WebsitePanel.WebDav.Core.Security.Cryptography; using WebsitePanel.WebDavPortal.CustomAttributes; using WebsitePanel.WebDavPortal.Extensions; using WebsitePanel.WebDavPortal.Models; using System.Net; +using WebsitePanel.WebDavPortal.UI.Routes; namespace WebsitePanel.WebDavPortal.Controllers @@ -20,11 +26,15 @@ namespace WebsitePanel.WebDavPortal.Controllers [LdapAuthorization] public class FileSystemController : Controller { + private readonly ICryptography _cryptography; private readonly IWebDavManager _webdavManager; + private readonly IAuthenticationService _authenticationService; - public FileSystemController(IWebDavManager webdavManager) + public FileSystemController(ICryptography cryptography, IWebDavManager webdavManager, IAuthenticationService authenticationService) { + _cryptography = cryptography; _webdavManager = webdavManager; + _authenticationService = authenticationService; } [HttpGet] @@ -58,8 +68,14 @@ namespace WebsitePanel.WebDavPortal.Controllers public ActionResult ShowOfficeDocument(string org, string pathPart = "") { + var owaOpener = WebDavAppConfigManager.Instance.OfficeOnline.Single(x => x.Extension == Path.GetExtension(pathPart)); + string fileUrl = _webdavManager.RootPath.TrimEnd('/') + "/" + pathPart.TrimStart('/'); - var uri = new Uri(WebDavAppConfigManager.Instance.OfficeOnline.Url).AddParameter("src", fileUrl).ToString(); + string accessToken = _authenticationService.CreateAccessToken(WspContext.User); + + string wopiSrc = Server.UrlDecode(Url.RouteUrl(OwaRouteNames.CheckFileInfo, new { encodedPath = _webdavManager.CreateFileId(pathPart) }, 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)); return View(new OfficeOnlineModel(uri, new Uri(fileUrl).Segments.Last())); } @@ -80,7 +96,7 @@ namespace WebsitePanel.WebDavPortal.Controllers return PartialView("_ResourseCollectionPartial", result); } - return new HttpStatusCodeResult(HttpStatusCode.NoContent); ; + return new HttpStatusCodeResult(HttpStatusCode.NoContent); } } } \ No newline at end of file diff --git a/WebsitePanel/Sources/WebsitePanel.WebDavPortal/Controllers/OwaController.cs b/WebsitePanel/Sources/WebsitePanel.WebDavPortal/Controllers/OwaController.cs new file mode 100644 index 00000000..5f6ba9ca --- /dev/null +++ b/WebsitePanel/Sources/WebsitePanel.WebDavPortal/Controllers/OwaController.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using System.Web.Mvc; +using WebsitePanel.WebDav.Core.Interfaces.Managers; +using WebsitePanel.WebDav.Core.Interfaces.Owa; +using WebsitePanel.WebDav.Core.Interfaces.Security; +using WebsitePanel.WebDav.Core.Security.Cryptography; + +namespace WebsitePanel.WebDavPortal.Controllers +{ + [AllowAnonymous] + public class OwaController : Controller + { + private readonly IWopiServer _wopiServer; + private readonly IWebDavManager _webDavManager; + private readonly IAuthenticationService _authenticationService; + + public OwaController(IWopiServer wopiServer, IWebDavManager webDavManager, IAuthenticationService authenticationService) + { + _wopiServer = wopiServer; + _webDavManager = webDavManager; + _authenticationService = authenticationService; + } + + public JsonResult CheckFileInfo( string encodedPath) + { + var path = _webDavManager.FilePathFromId(encodedPath); + + var fileInfo = _wopiServer.GetCheckFileInfo(path); + + return Json(fileInfo, JsonRequestBehavior.AllowGet); + } + + public FileResult GetFile(string encodedPath) + { + var path = _webDavManager.FilePathFromId(encodedPath); + + return _wopiServer.GetFile(path); + } + + protected override void OnActionExecuting(ActionExecutingContext filterContext) + { + base.OnActionExecuting(filterContext); + + if (!string.IsNullOrEmpty(Request["access_token"])) + { + _authenticationService.LogIn(Request["access_token"]); + } + } + } +} \ No newline at end of file diff --git a/WebsitePanel/Sources/WebsitePanel.WebDavPortal/DependencyInjection/PortalDependencies.cs b/WebsitePanel/Sources/WebsitePanel.WebDavPortal/DependencyInjection/PortalDependencies.cs index f13ae411..c6031ca0 100644 --- a/WebsitePanel/Sources/WebsitePanel.WebDavPortal/DependencyInjection/PortalDependencies.cs +++ b/WebsitePanel/Sources/WebsitePanel.WebDavPortal/DependencyInjection/PortalDependencies.cs @@ -4,7 +4,10 @@ using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.SessionState; +using WebsitePanel.WebDav.Core.Interfaces.Managers; +using WebsitePanel.WebDav.Core.Interfaces.Owa; using WebsitePanel.WebDav.Core.Interfaces.Security; +using WebsitePanel.WebDav.Core.Owa; using WebsitePanel.WebDav.Core.Security; using WebsitePanel.WebDav.Core.Security.Authentication; using WebsitePanel.WebDav.Core.Security.Cryptography; @@ -21,6 +24,7 @@ namespace WebsitePanel.WebDavPortal.DependencyInjection kernel.Bind().To(); kernel.Bind().To(); kernel.Bind().ToProvider(); + kernel.Bind().To(); } } } \ No newline at end of file diff --git a/WebsitePanel/Sources/WebsitePanel.WebDavPortal/DependencyInjection/Providers/WebDavManagerProvider.cs b/WebsitePanel/Sources/WebsitePanel.WebDavPortal/DependencyInjection/Providers/WebDavManagerProvider.cs index c06a2a89..e731d5fc 100644 --- a/WebsitePanel/Sources/WebsitePanel.WebDavPortal/DependencyInjection/Providers/WebDavManagerProvider.cs +++ b/WebsitePanel/Sources/WebsitePanel.WebDavPortal/DependencyInjection/Providers/WebDavManagerProvider.cs @@ -4,8 +4,8 @@ using Ninject; using Ninject.Activation; using WebsitePanel.WebDav.Core; using WebsitePanel.WebDav.Core.Config; +using WebsitePanel.WebDav.Core.Managers; using WebsitePanel.WebDav.Core.Security.Cryptography; -using WebsitePanel.WebDavPortal.Exceptions; using WebsitePanel.WebDavPortal.Models; namespace WebsitePanel.WebDavPortal.DependencyInjection.Providers diff --git a/WebsitePanel/Sources/WebsitePanel.WebDavPortal/FileOperations/FileOpenerManager.cs b/WebsitePanel/Sources/WebsitePanel.WebDavPortal/FileOperations/FileOpenerManager.cs index b4305109..1310e0ba 100644 --- a/WebsitePanel/Sources/WebsitePanel.WebDavPortal/FileOperations/FileOpenerManager.cs +++ b/WebsitePanel/Sources/WebsitePanel.WebDavPortal/FileOperations/FileOpenerManager.cs @@ -12,7 +12,7 @@ namespace WebsitePanel.WebDavPortal.FileOperations public FileOpenerManager() { if (WebDavAppConfigManager.Instance.OfficeOnline.IsEnabled) - _operationTypes.AddRange(WebDavAppConfigManager.Instance.OfficeOnline.ToDictionary(x => x, y => FileOpenerType.OfficeOnline)); + _operationTypes.AddRange(WebDavAppConfigManager.Instance.OfficeOnline.ToDictionary(x => x.Extension, y => FileOpenerType.OfficeOnline)); } public FileOpenerType this[string fileExtension] diff --git a/WebsitePanel/Sources/WebsitePanel.WebDavPortal/Global.asax.cs b/WebsitePanel/Sources/WebsitePanel.WebDavPortal/Global.asax.cs index 8cf744a3..14649e45 100644 --- a/WebsitePanel/Sources/WebsitePanel.WebDavPortal/Global.asax.cs +++ b/WebsitePanel/Sources/WebsitePanel.WebDavPortal/Global.asax.cs @@ -1,4 +1,5 @@ using System; +using System.Threading; using System.Web; using System.Web.Mvc; using System.Web.Optimization; @@ -6,9 +7,12 @@ using System.Web.Routing; using System.Web.Script.Serialization; using System.Web.Security; using WebsitePanel.WebDav.Core.Config; +using WebsitePanel.WebDav.Core.Interfaces.Security; using WebsitePanel.WebDav.Core.Security.Authentication.Principals; +using WebsitePanel.WebDav.Core.Security.Cryptography; using WebsitePanel.WebDavPortal.Controllers; using WebsitePanel.WebDavPortal.DependencyInjection; +using WebsitePanel.WebDavPortal.HttpHandlers; namespace WebsitePanel.WebDavPortal { @@ -55,8 +59,11 @@ namespace WebsitePanel.WebDavPortal protected void Application_PostAuthenticateRequest(Object sender, EventArgs e) { - HttpCookie authCookie = Request.Cookies[FormsAuthentication.FormsCookieName]; var contextWrapper = new HttpContextWrapper(Context); + HttpCookie authCookie = Request.Cookies[FormsAuthentication.FormsCookieName]; + + var authService = DependencyResolver.Current.GetService(); + var cryptography = DependencyResolver.Current.GetService(); if (authCookie != null) { @@ -66,15 +73,7 @@ namespace WebsitePanel.WebDavPortal var principalSerialized = serializer.Deserialize(authTicket.UserData); - var principal = new WspPrincipal(principalSerialized.Login); - - principal.AccountId = principalSerialized.AccountId; - principal.ItemId = principalSerialized.ItemId; - principal.OrganizationId = principalSerialized.OrganizationId; - principal.DisplayName = principalSerialized.DisplayName; - principal.EncryptedPassword = principalSerialized.EncryptedPassword; - - HttpContext.Current.User = principal; + authService.LogIn(principalSerialized.Login, cryptography.Decrypt(principalSerialized.EncryptedPassword)); if (!contextWrapper.Request.IsAjaxRequest()) { diff --git a/WebsitePanel/Sources/WebsitePanel.WebDavPortal/UI/Routes/OwaRouteNames.cs b/WebsitePanel/Sources/WebsitePanel.WebDavPortal/UI/Routes/OwaRouteNames.cs new file mode 100644 index 00000000..4a263e53 --- /dev/null +++ b/WebsitePanel/Sources/WebsitePanel.WebDavPortal/UI/Routes/OwaRouteNames.cs @@ -0,0 +1,8 @@ +namespace WebsitePanel.WebDavPortal.UI.Routes +{ + public class OwaRouteNames + { + public const string CheckFileInfo = "OwaCheckFileInfoPath"; + public const string GetFile = "OwaGetFilePath"; + } +} \ No newline at end of file diff --git a/WebsitePanel/Sources/WebsitePanel.WebDavPortal/Views/FileSystem/ShowContent.cshtml b/WebsitePanel/Sources/WebsitePanel.WebDavPortal/Views/FileSystem/ShowContent.cshtml index 939f3bba..bc4222bd 100644 --- a/WebsitePanel/Sources/WebsitePanel.WebDavPortal/Views/FileSystem/ShowContent.cshtml +++ b/WebsitePanel/Sources/WebsitePanel.WebDavPortal/Views/FileSystem/ShowContent.cshtml @@ -2,10 +2,11 @@ @using WebsitePanel.WebDav.Core.Client @using Ninject @using WebsitePanel.WebDav.Core.Config +@using WebsitePanel.WebDav.Core.Interfaces.Managers @model WebsitePanel.WebDavPortal.Models.ModelForWebDav @{ - var webDavManager = DependencyResolver.Current.GetService(); + var webDavManager = DependencyResolver.Current.GetService(); ViewBag.Title = WebDavAppConfigManager.Instance.ApplicationName; } @Scripts.Render("~/bundles/jquery") diff --git a/WebsitePanel/Sources/WebsitePanel.WebDavPortal/Web.config b/WebsitePanel/Sources/WebsitePanel.WebDavPortal/Web.config index 25d53401..ba449d53 100644 --- a/WebsitePanel/Sources/WebsitePanel.WebDavPortal/Web.config +++ b/WebsitePanel/Sources/WebsitePanel.WebDavPortal/Web.config @@ -37,7 +37,7 @@ - + @@ -58,13 +58,13 @@ - - - - - - - + + + + + + + + @@ -83,11 +84,8 @@ - - - - + @@ -104,6 +102,9 @@ + + + diff --git a/WebsitePanel/Sources/WebsitePanel.WebDavPortal/WebsitePanel.WebDavPortal.csproj b/WebsitePanel/Sources/WebsitePanel.WebDavPortal/WebsitePanel.WebDavPortal.csproj index bd1bf241..fc89d398 100644 --- a/WebsitePanel/Sources/WebsitePanel.WebDavPortal/WebsitePanel.WebDavPortal.csproj +++ b/WebsitePanel/Sources/WebsitePanel.WebDavPortal/WebsitePanel.WebDavPortal.csproj @@ -144,13 +144,12 @@ + - - @@ -162,13 +161,12 @@ - - + @@ -261,7 +259,9 @@ - + + +