From ad697db42bd458ca6fd4cae278ba1a7da688586a Mon Sep 17 00:00:00 2001 From: Shannon Date: Wed, 31 Jul 2013 11:10:33 +1000 Subject: [PATCH 1/5] Fixes an issue with WebSecurity logout --- src/Umbraco.Web/Security/WebSecurity.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web/Security/WebSecurity.cs b/src/Umbraco.Web/Security/WebSecurity.cs index 972644ff49..08f5b0b67a 100644 --- a/src/Umbraco.Web/Security/WebSecurity.cs +++ b/src/Umbraco.Web/Security/WebSecurity.cs @@ -128,7 +128,7 @@ namespace Umbraco.Web.Security SqlHelper.CreateParameter("@contextId", retVal)); UmbracoUserContextId = retVal.ToString(); - LogHelper.Info(typeof(WebSecurity), "User Id: {0} logged in", () => userId); + LogHelper.Info("User Id: {0} logged in", () => userId); } @@ -147,8 +147,11 @@ namespace Umbraco.Web.Security } catch (Exception ex) { - LogHelper.Error(typeof(WebSecurity), string.Format("Login with contextId {0} didn't exist in the database", UmbracoUserContextId), ex); + LogHelper.Error(string.Format("Login with contextId {0} didn't exist in the database", UmbracoUserContextId), ex); } + + //this clears the cookie + UmbracoUserContextId = ""; } public void RenewLoginTimeout() From e2eeafcbfcb12934f825b24d7bf5aba0d6f7cfa3 Mon Sep 17 00:00:00 2001 From: Shannon Date: Wed, 31 Jul 2013 16:45:11 +1000 Subject: [PATCH 2/5] Fixes: U4-2232 UmbracoAuthorizeAttribute breaks Relfection methods - ensures that no singleton instances are passed into attributes since they only ever get created once, meaning we're left with a stale version in the attribute. --- .../UmbracoInstallAuthorizeAttribute.cs | 30 +++++++++++++------ .../Mvc/MemberAuthorizeAttribute.cs | 14 ++++++--- .../Mvc/UmbracoAuthorizeAttribute.cs | 27 ++++++++++++----- .../WebApi/MemberAuthorizeAttribute.cs | 18 +++++++---- .../WebApi/UmbracoAuthorizeAttribute.cs | 21 ++++++++++--- 5 files changed, 80 insertions(+), 30 deletions(-) diff --git a/src/Umbraco.Web/Install/UmbracoInstallAuthorizeAttribute.cs b/src/Umbraco.Web/Install/UmbracoInstallAuthorizeAttribute.cs index 994703bfd3..3aafa86de3 100644 --- a/src/Umbraco.Web/Install/UmbracoInstallAuthorizeAttribute.cs +++ b/src/Umbraco.Web/Install/UmbracoInstallAuthorizeAttribute.cs @@ -13,9 +13,23 @@ namespace Umbraco.Web.Install /// internal class UmbracoInstallAuthorizeAttribute : AuthorizeAttribute { - private readonly ApplicationContext _applicationContext; + private readonly ApplicationContext _applicationContext; private readonly UmbracoContext _umbracoContext; + private ApplicationContext GetApplicationContext() + { + return _applicationContext ?? ApplicationContext.Current; + } + + private UmbracoContext GetUmbracoContext() + { + return _umbracoContext ?? UmbracoContext.Current; + } + + /// + /// THIS SHOULD BE ONLY USED FOR UNIT TESTS + /// + /// public UmbracoInstallAuthorizeAttribute(UmbracoContext umbracoContext) { if (umbracoContext == null) throw new ArgumentNullException("umbracoContext"); @@ -23,11 +37,9 @@ namespace Umbraco.Web.Install _applicationContext = _umbracoContext.Application; } - public UmbracoInstallAuthorizeAttribute() - : this(UmbracoContext.Current) - { - - } + public UmbracoInstallAuthorizeAttribute() + { + } /// /// Ensures that the user must be logged in or that the application is not configured just yet. @@ -41,13 +53,13 @@ namespace Umbraco.Web.Install try { //if its not configured then we can continue - if (!_applicationContext.IsConfigured) + if (!GetApplicationContext().IsConfigured) { return true; } - + var umbCtx = GetUmbracoContext(); //otherwise we need to ensure that a user is logged in - var isLoggedIn = _umbracoContext.Security.ValidateUserContextId(_umbracoContext.Security.UmbracoUserContextId); + var isLoggedIn = umbCtx.Security.ValidateUserContextId(umbCtx.Security.UmbracoUserContextId); if (isLoggedIn) { return true; diff --git a/src/Umbraco.Web/Mvc/MemberAuthorizeAttribute.cs b/src/Umbraco.Web/Mvc/MemberAuthorizeAttribute.cs index bdcbd275ba..dd9720cdcf 100644 --- a/src/Umbraco.Web/Mvc/MemberAuthorizeAttribute.cs +++ b/src/Umbraco.Web/Mvc/MemberAuthorizeAttribute.cs @@ -18,18 +18,24 @@ namespace Umbraco.Web.Mvc public sealed class MemberAuthorizeAttribute : AuthorizeAttribute { - private readonly ApplicationContext _applicationContext; private readonly UmbracoContext _umbracoContext; + private UmbracoContext GetUmbracoContext() + { + return _umbracoContext ?? UmbracoContext.Current; + } + + /// + /// THIS SHOULD BE ONLY USED FOR UNIT TESTS + /// + /// public MemberAuthorizeAttribute(UmbracoContext umbracoContext) { if (umbracoContext == null) throw new ArgumentNullException("umbracoContext"); _umbracoContext = umbracoContext; - _applicationContext = _umbracoContext.Application; } public MemberAuthorizeAttribute() - : this(UmbracoContext.Current) { } @@ -76,7 +82,7 @@ namespace Umbraco.Web.Mvc } } - return _umbracoContext.Security.IsMemberAuthorized(AllowAll, + return GetUmbracoContext().Security.IsMemberAuthorized(AllowAll, AllowType.Split(','), AllowGroup.Split(','), members); diff --git a/src/Umbraco.Web/Mvc/UmbracoAuthorizeAttribute.cs b/src/Umbraco.Web/Mvc/UmbracoAuthorizeAttribute.cs index 19615706d6..ff7056838b 100644 --- a/src/Umbraco.Web/Mvc/UmbracoAuthorizeAttribute.cs +++ b/src/Umbraco.Web/Mvc/UmbracoAuthorizeAttribute.cs @@ -15,6 +15,20 @@ namespace Umbraco.Web.Mvc private readonly ApplicationContext _applicationContext; private readonly UmbracoContext _umbracoContext; + private ApplicationContext GetApplicationContext() + { + return _applicationContext ?? ApplicationContext.Current; + } + + private UmbracoContext GetUmbracoContext() + { + return _umbracoContext ?? UmbracoContext.Current; + } + + /// + /// THIS SHOULD BE ONLY USED FOR UNIT TESTS + /// + /// public UmbracoAuthorizeAttribute(UmbracoContext umbracoContext) { if (umbracoContext == null) throw new ArgumentNullException("umbracoContext"); @@ -22,11 +36,9 @@ namespace Umbraco.Web.Mvc _applicationContext = _umbracoContext.Application; } - public UmbracoAuthorizeAttribute() - : this(UmbracoContext.Current) - { - - } + public UmbracoAuthorizeAttribute() + { + } /// /// Ensures that the user must be in the Administrator or the Install role @@ -40,9 +52,10 @@ namespace Umbraco.Web.Mvc try { //we need to that the app is configured and that a user is logged in - if (!_applicationContext.IsConfigured) + if (!GetApplicationContext().IsConfigured) return false; - var isLoggedIn = _umbracoContext.Security.ValidateUserContextId(_umbracoContext.Security.UmbracoUserContextId); + var umbCtx = GetUmbracoContext(); + var isLoggedIn = umbCtx.Security.ValidateUserContextId(umbCtx.Security.UmbracoUserContextId); return isLoggedIn; } catch (Exception) diff --git a/src/Umbraco.Web/WebApi/MemberAuthorizeAttribute.cs b/src/Umbraco.Web/WebApi/MemberAuthorizeAttribute.cs index bb15fe7c47..0fc04a6206 100644 --- a/src/Umbraco.Web/WebApi/MemberAuthorizeAttribute.cs +++ b/src/Umbraco.Web/WebApi/MemberAuthorizeAttribute.cs @@ -16,21 +16,27 @@ namespace Umbraco.Web.WebApi public sealed class MemberAuthorizeAttribute : AuthorizeAttribute { - private readonly ApplicationContext _applicationContext; private readonly UmbracoContext _umbracoContext; + private UmbracoContext GetUmbracoContext() + { + return _umbracoContext ?? UmbracoContext.Current; + } + + /// + /// THIS SHOULD BE ONLY USED FOR UNIT TESTS + /// + /// public MemberAuthorizeAttribute(UmbracoContext umbracoContext) { if (umbracoContext == null) throw new ArgumentNullException("umbracoContext"); _umbracoContext = umbracoContext; - _applicationContext = _umbracoContext.Application; } public MemberAuthorizeAttribute() - : this(UmbracoContext.Current) - { + { - } + } /// /// Flag for whether to allow all site visitors or just authenticated members @@ -74,7 +80,7 @@ namespace Umbraco.Web.WebApi } } - return _umbracoContext.Security.IsMemberAuthorized(AllowAll, + return GetUmbracoContext().Security.IsMemberAuthorized(AllowAll, AllowType.Split(','), AllowGroup.Split(','), members); diff --git a/src/Umbraco.Web/WebApi/UmbracoAuthorizeAttribute.cs b/src/Umbraco.Web/WebApi/UmbracoAuthorizeAttribute.cs index dc83b043df..7fee8c34e4 100644 --- a/src/Umbraco.Web/WebApi/UmbracoAuthorizeAttribute.cs +++ b/src/Umbraco.Web/WebApi/UmbracoAuthorizeAttribute.cs @@ -13,6 +13,20 @@ namespace Umbraco.Web.WebApi private readonly ApplicationContext _applicationContext; private readonly UmbracoContext _umbracoContext; + private ApplicationContext GetApplicationContext() + { + return _applicationContext ?? ApplicationContext.Current; + } + + private UmbracoContext GetUmbracoContext() + { + return _umbracoContext ?? UmbracoContext.Current; + } + + /// + /// THIS SHOULD BE ONLY USED FOR UNIT TESTS + /// + /// public UmbracoAuthorizeAttribute(UmbracoContext umbracoContext) { if (umbracoContext == null) throw new ArgumentNullException("umbracoContext"); @@ -21,9 +35,7 @@ namespace Umbraco.Web.WebApi } public UmbracoAuthorizeAttribute() - : this(UmbracoContext.Current) { - } protected override bool IsAuthorized(System.Web.Http.Controllers.HttpActionContext actionContext) @@ -31,9 +43,10 @@ namespace Umbraco.Web.WebApi try { //we need to that the app is configured and that a user is logged in - if (!_applicationContext.IsConfigured) + if (!GetApplicationContext().IsConfigured) return false; - var isLoggedIn = _umbracoContext.Security.ValidateUserContextId(_umbracoContext.Security.UmbracoUserContextId); + var umbCtx = GetUmbracoContext(); + var isLoggedIn = umbCtx.Security.ValidateUserContextId(umbCtx.Security.UmbracoUserContextId); return isLoggedIn; } catch (Exception) From b48f0f52e0a866b50c9e614376ecf9b104570c4f Mon Sep 17 00:00:00 2001 From: Shannon Date: Wed, 31 Jul 2013 17:08:10 +1000 Subject: [PATCH 3/5] updates uri extensions + tests Conflicts: src/Umbraco.Core/UriExtensions.cs --- src/Umbraco.Core/UriExtensions.cs | 159 +++++++++++------- src/Umbraco.Tests/UriExtensionsTests.cs | 32 ++++ .../ServerRegistrationEventHandler.cs | 7 +- 3 files changed, 129 insertions(+), 69 deletions(-) diff --git a/src/Umbraco.Core/UriExtensions.cs b/src/Umbraco.Core/UriExtensions.cs index 45088aa1bf..53ca85e0a8 100644 --- a/src/Umbraco.Core/UriExtensions.cs +++ b/src/Umbraco.Core/UriExtensions.cs @@ -2,6 +2,7 @@ using System; using System.IO; using System.Linq; using System.Text; +using Umbraco.Core.IO; namespace Umbraco.Core { @@ -10,6 +11,38 @@ namespace Umbraco.Core /// public static class UriExtensions { + /// + /// Checks if the current uri is a back office request + /// + /// + /// + internal static bool IsBackOfficeRequest(this Uri url) + { + var authority = url.GetLeftPart(UriPartial.Authority); + var afterAuthority = url.GetLeftPart(UriPartial.Query) + .TrimStart(authority) + .TrimStart("/"); + + //check if this is in the umbraco back office + return afterAuthority.InvariantStartsWith(GlobalSettings.Path.TrimStart("/")); + } + + /// + /// Checks if the current uri is an install request + /// + /// + /// + internal static bool IsInstallerRequest(this Uri url) + { + var authority = url.GetLeftPart(UriPartial.Authority); + var afterAuthority = url.GetLeftPart(UriPartial.Query) + .TrimStart(authority) + .TrimStart("/"); + + //check if this is in the umbraco back office + return afterAuthority.InvariantStartsWith(IOHelper.ResolveUrl("~/install").TrimStart("/")); + } + /// /// This is a performance tweak to check if this is a .css, .js or .ico, .jpg, .jpeg, .png, .gif file request since /// .Net will pass these requests through to the module when in integrated mode. @@ -19,7 +52,7 @@ namespace Umbraco.Core /// internal static bool IsClientSideRequest(this Uri url) { - var toIgnore = new[] { ".js", ".css", ".ico", ".png", ".jpg", ".jpeg", ".gif" }; + var toIgnore = new[] { ".js", ".css", ".ico", ".png", ".jpg", ".jpeg", ".gif", ".html", ".svg" }; return toIgnore.Any(x => Path.GetExtension(url.LocalPath).InvariantEquals(x)); } @@ -31,14 +64,14 @@ namespace Umbraco.Core /// The rewritten uri. /// Everything else remains unchanged, except for the fragment which is removed. public static Uri Rewrite(this Uri uri, string path) - { + { if (!path.StartsWith("/")) throw new ArgumentException("Path must start with a slash.", "path"); - return uri.IsAbsoluteUri - ? new Uri(uri.GetLeftPart(UriPartial.Authority) + path + uri.Query) + return uri.IsAbsoluteUri + ? new Uri(uri.GetLeftPart(UriPartial.Authority) + path + uri.Query) : new Uri(path + uri.GetSafeQuery(), UriKind.Relative); - } + } /// /// Rewrites the path and query of a uri. @@ -49,18 +82,18 @@ namespace Umbraco.Core /// The rewritten uri. /// Everything else remains unchanged, except for the fragment which is removed. public static Uri Rewrite(this Uri uri, string path, string query) - { + { if (!path.StartsWith("/")) throw new ArgumentException("Path must start with a slash.", "path"); if (query.Length > 0 && !query.StartsWith("?")) throw new ArgumentException("Query must start with a question mark.", "query"); if (query == "?") query = ""; - - return uri.IsAbsoluteUri - ? new Uri(uri.GetLeftPart(UriPartial.Authority) + path + query) + + return uri.IsAbsoluteUri + ? new Uri(uri.GetLeftPart(UriPartial.Authority) + path + query) : new Uri(path + query, UriKind.Relative); - } + } /// /// Gets the absolute path of the uri, even if the uri is relative. @@ -68,10 +101,10 @@ namespace Umbraco.Core /// The uri. /// The absolute path of the uri. /// Default uri.AbsolutePath does not support relative uris. - public static string GetSafeAbsolutePath(this Uri uri) - { - if (uri.IsAbsoluteUri) - return uri.AbsolutePath; + public static string GetSafeAbsolutePath(this Uri uri) + { + if (uri.IsAbsoluteUri) + return uri.AbsolutePath; // cannot get .AbsolutePath on relative uri (InvalidOperation) var s = uri.OriginalString; @@ -80,7 +113,7 @@ namespace Umbraco.Core var pos = posq > 0 ? posq : (posf > 0 ? posf : 0); var path = pos > 0 ? s.Substring(0, pos) : s; return path; - } + } /// /// Gets the decoded, absolute path of the uri. @@ -89,9 +122,9 @@ namespace Umbraco.Core /// The absolute path of the uri. /// Only for absolute uris. public static string GetAbsolutePathDecoded(this Uri uri) - { - return System.Web.HttpUtility.UrlDecode(uri.AbsolutePath); - } + { + return System.Web.HttpUtility.UrlDecode(uri.AbsolutePath); + } /// /// Gets the decoded, absolute path of the uri, even if the uri is relative. @@ -100,32 +133,32 @@ namespace Umbraco.Core /// The absolute path of the uri. /// Default uri.AbsolutePath does not support relative uris. public static string GetSafeAbsolutePathDecoded(this Uri uri) - { - return System.Web.HttpUtility.UrlDecode(uri.GetSafeAbsolutePath()); - } + { + return System.Web.HttpUtility.UrlDecode(uri.GetSafeAbsolutePath()); + } - /// - /// Rewrites the path of the uri so it ends with a slash. - /// - /// The uri. - /// The rewritten uri. - /// Everything else remains unchanged. + /// + /// Rewrites the path of the uri so it ends with a slash. + /// + /// The uri. + /// The rewritten uri. + /// Everything else remains unchanged. public static Uri EndPathWithSlash(this Uri uri) - { - var path = uri.GetSafeAbsolutePath(); - if (uri.IsAbsoluteUri) - { - if (path != "/" && !path.EndsWith("/")) - uri = new Uri(uri.GetLeftPart(UriPartial.Authority) + path + "/" + uri.Query); - return uri; - } - else - { - if (path != "/" && !path.EndsWith("/")) - uri = new Uri(path + "/" + uri.Query, UriKind.Relative); - } - return uri; - } + { + var path = uri.GetSafeAbsolutePath(); + if (uri.IsAbsoluteUri) + { + if (path != "/" && !path.EndsWith("/")) + uri = new Uri(uri.GetLeftPart(UriPartial.Authority) + path + "/" + uri.Query); + return uri; + } + else + { + if (path != "/" && !path.EndsWith("/")) + uri = new Uri(path + "/" + uri.Query, UriKind.Relative); + } + return uri; + } /// /// Rewrites the path of the uri so it does not end with a slash. @@ -134,20 +167,20 @@ namespace Umbraco.Core /// The rewritten uri. /// Everything else remains unchanged. public static Uri TrimPathEndSlash(this Uri uri) - { - var path = uri.GetSafeAbsolutePath(); - if (uri.IsAbsoluteUri) - { - if (path != "/") - uri = new Uri(uri.GetLeftPart(UriPartial.Authority) + path.TrimEnd('/') + uri.Query); - } - else - { - if (path != "/") - uri = new Uri(path.TrimEnd('/') + uri.Query, UriKind.Relative); - } - return uri; - } + { + var path = uri.GetSafeAbsolutePath(); + if (uri.IsAbsoluteUri) + { + if (path != "/") + uri = new Uri(uri.GetLeftPart(UriPartial.Authority) + path.TrimEnd('/') + uri.Query); + } + else + { + if (path != "/") + uri = new Uri(path.TrimEnd('/') + uri.Query, UriKind.Relative); + } + return uri; + } /// /// Transforms a relative uri into an absolute uri. @@ -155,13 +188,13 @@ namespace Umbraco.Core /// The relative uri. /// The base absolute uri. /// The absolute uri. - public static Uri MakeAbsolute(this Uri uri, Uri baseUri) - { - if (uri.IsAbsoluteUri) - throw new ArgumentException("Uri is already absolute.", "uri"); + public static Uri MakeAbsolute(this Uri uri, Uri baseUri) + { + if (uri.IsAbsoluteUri) + throw new ArgumentException("Uri is already absolute.", "uri"); - return new Uri(baseUri.GetLeftPart(UriPartial.Authority) + uri.GetSafeAbsolutePath() + uri.GetSafeQuery()); - } + return new Uri(baseUri.GetLeftPart(UriPartial.Authority) + uri.GetSafeAbsolutePath() + uri.GetSafeQuery()); + } static string GetSafeQuery(this Uri uri) { @@ -176,5 +209,5 @@ namespace Umbraco.Core return query; } - } + } } \ No newline at end of file diff --git a/src/Umbraco.Tests/UriExtensionsTests.cs b/src/Umbraco.Tests/UriExtensionsTests.cs index 8389e5d727..61ed49d65d 100644 --- a/src/Umbraco.Tests/UriExtensionsTests.cs +++ b/src/Umbraco.Tests/UriExtensionsTests.cs @@ -10,6 +10,38 @@ namespace Umbraco.Tests [TestFixture] public class UriExtensionsTests { + [TestCase("http://www.domain.com/umbraco", true)] + [TestCase("http://www.domain.com/Umbraco/", true)] + [TestCase("http://www.domain.com/umbraco/default.aspx", true)] + [TestCase("http://www.domain.com/umbraco/test/test", true)] + [TestCase("http://www.domain.com/Umbraco/test/test.aspx", true)] + [TestCase("http://www.domain.com/umbraco/test/test.js", true)] + [TestCase("http://www.domain.com/umbrac", false)] + [TestCase("http://www.domain.com/test", false)] + [TestCase("http://www.domain.com/test/umbraco", false)] + [TestCase("http://www.domain.com/test/umbraco.aspx", false)] + public void Is_Back_Office_Request(string input, bool expected) + { + var source = new Uri(input); + Assert.AreEqual(expected, source.IsBackOfficeRequest()); + } + + [TestCase("http://www.domain.com/install", true)] + [TestCase("http://www.domain.com/Install/", true)] + [TestCase("http://www.domain.com/install/default.aspx", true)] + [TestCase("http://www.domain.com/install/test/test", true)] + [TestCase("http://www.domain.com/Install/test/test.aspx", true)] + [TestCase("http://www.domain.com/install/test/test.js", true)] + [TestCase("http://www.domain.com/instal", false)] + [TestCase("http://www.domain.com/umbraco", false)] + [TestCase("http://www.domain.com/umbraco/umbraco", false)] + [TestCase("http://www.domain.com/test/umbraco.aspx", false)] + public void Is_Installer_Request(string input, bool expected) + { + var source = new Uri(input); + Assert.AreEqual(expected, source.IsInstallerRequest()); + } + [TestCase("http://www.domain.com/foo/bar", "/", "http://www.domain.com/")] [TestCase("http://www.domain.com/foo/bar#hop", "/", "http://www.domain.com/")] [TestCase("http://www.domain.com/foo/bar?q=2#hop", "/", "http://www.domain.com/?q=2")] diff --git a/src/Umbraco.Web/Strategies/ServerRegistrationEventHandler.cs b/src/Umbraco.Web/Strategies/ServerRegistrationEventHandler.cs index bef5f2c4cd..79edd8192e 100644 --- a/src/Umbraco.Web/Strategies/ServerRegistrationEventHandler.cs +++ b/src/Umbraco.Web/Strategies/ServerRegistrationEventHandler.cs @@ -77,13 +77,8 @@ namespace Umbraco.Web.Strategies //if it is not a document request, we'll check if it is a back end request if (e.Outcome == EnsureRoutableOutcome.NotDocumentRequest) { - var authority = e.HttpContext.Request.Url.GetLeftPart(UriPartial.Authority); - var afterAuthority = e.HttpContext.Request.Url.GetLeftPart(UriPartial.Query) - .TrimStart(authority) - .TrimStart("/"); - //check if this is in the umbraco back office - if (afterAuthority.InvariantStartsWith(GlobalSettings.Path.TrimStart("/"))) + if (e.HttpContext.Request.Url.IsBackOfficeRequest()) { //yup it's a back office request! using (var lck = new UpgradeableReadLock(Locker)) From cbda86fe921f6a32d41a313e71b6a9b8f4b0ef0d Mon Sep 17 00:00:00 2001 From: Shannon Date: Wed, 31 Jul 2013 17:24:36 +1000 Subject: [PATCH 4/5] Fixes build error, streamlines all calls to validate a user for base controllers. --- src/Umbraco.Core/UriExtensions.cs | 1 + .../Mvc/UmbracoAuthorizedController.cs | 47 ++-------------- .../WebApi/UmbracoApiController.cs | 24 +++++++++ .../WebApi/UmbracoAuthorizedApiController.cs | 54 ++++--------------- 4 files changed, 41 insertions(+), 85 deletions(-) diff --git a/src/Umbraco.Core/UriExtensions.cs b/src/Umbraco.Core/UriExtensions.cs index 53ca85e0a8..e5de22456b 100644 --- a/src/Umbraco.Core/UriExtensions.cs +++ b/src/Umbraco.Core/UriExtensions.cs @@ -2,6 +2,7 @@ using System; using System.IO; using System.Linq; using System.Text; +using Umbraco.Core.Configuration; using Umbraco.Core.IO; namespace Umbraco.Core diff --git a/src/Umbraco.Web/Mvc/UmbracoAuthorizedController.cs b/src/Umbraco.Web/Mvc/UmbracoAuthorizedController.cs index ae62f7acee..0f99a6c6c7 100644 --- a/src/Umbraco.Web/Mvc/UmbracoAuthorizedController.cs +++ b/src/Umbraco.Web/Mvc/UmbracoAuthorizedController.cs @@ -20,20 +20,8 @@ namespace Umbraco.Web.Mvc [UmbracoAuthorize] public abstract class UmbracoAuthorizedController : UmbracoController { - - private User _user; private bool _userisValidated = false; - /// - /// The current user ID - /// - private int _uid = 0; - - /// - /// The page timeout in seconds. - /// - private long _timeout = 0; - /// /// Returns the currently logged in Umbraco User /// @@ -41,40 +29,15 @@ namespace Umbraco.Web.Mvc { get { - if (!_userisValidated) ValidateUser(); - return _user; - } - } - - private void ValidateUser() - { - if ((UmbracoContext.Security.UmbracoUserContextId != "")) - { - _uid = UmbracoContext.Security.GetUserId(UmbracoContext.Security.UmbracoUserContextId); - _timeout = UmbracoContext.Security.GetTimeout(UmbracoContext.Security.UmbracoUserContextId); - - if (_timeout > DateTime.Now.Ticks) + //throw exceptions if not valid (true) + if (!_userisValidated) { - _user = global::umbraco.BusinessLogic.User.GetUser(_uid); - - // Check for console access - if (_user.Disabled || (_user.NoConsole && GlobalSettings.RequestIsInUmbracoApplication(HttpContext) && !GlobalSettings.RequestIsLiveEditRedirector(HttpContext))) - { - throw new ArgumentException("You have no priviledges to the umbraco console. Please contact your administrator"); - } + Security.ValidateCurrentUser(HttpContext, true); _userisValidated = true; - UmbracoContext.Security.UpdateLogin(_timeout); } - else - { - throw new ArgumentException("User has timed out!!"); - } - } - else - { - throw new InvalidOperationException("The user has no umbraco contextid - try logging in"); - } + return Security.CurrentUser; + } } } diff --git a/src/Umbraco.Web/WebApi/UmbracoApiController.cs b/src/Umbraco.Web/WebApi/UmbracoApiController.cs index acbf82f161..b8ba3f9a7b 100644 --- a/src/Umbraco.Web/WebApi/UmbracoApiController.cs +++ b/src/Umbraco.Web/WebApi/UmbracoApiController.cs @@ -1,4 +1,5 @@ using System; +using System.Web; using System.Web.Http; using Umbraco.Core; using Umbraco.Core.Services; @@ -22,6 +23,29 @@ namespace Umbraco.Web.WebApi Umbraco = new UmbracoHelper(umbracoContext); } + /// + /// Tries to retreive the current HttpContext if one exists. + /// + /// + protected Attempt TryGetHttpContext() + { + object context; + if (Request.Properties.TryGetValue("MS_HttpContext", out context)) + { + var httpContext = context as HttpContextBase; + if (httpContext != null) + { + return new Attempt(true, httpContext); + } + } + if (HttpContext.Current != null) + { + return new Attempt(true, new HttpContextWrapper(HttpContext.Current)); + } + + return Attempt.False; + } + /// /// Returns the current ApplicationContext /// diff --git a/src/Umbraco.Web/WebApi/UmbracoAuthorizedApiController.cs b/src/Umbraco.Web/WebApi/UmbracoAuthorizedApiController.cs index 9101e3ac66..d0ede6fcda 100644 --- a/src/Umbraco.Web/WebApi/UmbracoAuthorizedApiController.cs +++ b/src/Umbraco.Web/WebApi/UmbracoAuthorizedApiController.cs @@ -19,20 +19,9 @@ namespace Umbraco.Web.WebApi : base(umbracoContext) { } - - private User _user; + private bool _userisValidated = false; - - /// - /// The current user ID - /// - private int _uid = 0; - - /// - /// The page timeout in seconds. - /// - private long _timeout = 0; - + /// /// Returns the currently logged in Umbraco User /// @@ -40,40 +29,19 @@ namespace Umbraco.Web.WebApi { get { - if (!_userisValidated) ValidateUser(); - return _user; - } - } - - private void ValidateUser() - { - if ((UmbracoContext.Security.UmbracoUserContextId != "")) - { - _uid = UmbracoContext.Security.GetUserId(UmbracoContext.Security.UmbracoUserContextId); - _timeout = UmbracoContext.Security.GetTimeout(UmbracoContext.Security.UmbracoUserContextId); - - if (_timeout > DateTime.Now.Ticks) + //throw exceptions if not valid (true) + if (!_userisValidated) { - _user = global::umbraco.BusinessLogic.User.GetUser(_uid); - - // Check for console access - if (_user.Disabled || (_user.NoConsole && GlobalSettings.RequestIsInUmbracoApplication(HttpContext.Current) && !GlobalSettings.RequestIsLiveEditRedirector(HttpContext.Current))) - { - throw new ArgumentException("You have no priviledges to the umbraco console. Please contact your administrator"); - } + var ctx = TryGetHttpContext(); + if (ctx.Success == false) + throw new InvalidOperationException("To get a current user, this method must occur in a web request"); + Security.ValidateCurrentUser(ctx.Result, true); _userisValidated = true; - UmbracoContext.Security.UpdateLogin(_timeout); } - else - { - throw new ArgumentException("User has timed out!!"); - } - } - else - { - throw new InvalidOperationException("The user has no umbraco contextid - try logging in"); - } + return Security.CurrentUser; + } } + } } \ No newline at end of file From 9bc3fdd5559dccdebf68d6a155b9e48e1be1875f Mon Sep 17 00:00:00 2001 From: Shannon Date: Wed, 31 Jul 2013 17:34:42 +1000 Subject: [PATCH 5/5] Makes UmbracoContext disposable and fixes the module's DisposeHttpContextItems to actual perform the disposal of each item. --- src/Umbraco.Web/UmbracoContext.cs | 16 ++++++-- src/Umbraco.Web/UmbracoModule.cs | 62 ++++++++++++++++--------------- 2 files changed, 45 insertions(+), 33 deletions(-) diff --git a/src/Umbraco.Web/UmbracoContext.cs b/src/Umbraco.Web/UmbracoContext.cs index 471e7403ad..abec9e4076 100644 --- a/src/Umbraco.Web/UmbracoContext.cs +++ b/src/Umbraco.Web/UmbracoContext.cs @@ -24,7 +24,7 @@ namespace Umbraco.Web /// /// Class that encapsulates Umbraco information of a specific HTTP request /// - public class UmbracoContext + public class UmbracoContext : DisposableObject { private const string HttpContextItemName = "Umbraco.Web.UmbracoContext"; private static readonly object Locker = new object(); @@ -361,7 +361,17 @@ namespace Umbraco.Web return null; } } - - + + protected override void DisposeResources() + { + Security.DisposeIfDisposable(); + Security = null; + _previewContent = null; + _umbracoContext = null; + //ensure not to dispose this! + Application = null; + ContentCache = null; + MediaCache = null; + } } } \ No newline at end of file diff --git a/src/Umbraco.Web/UmbracoModule.cs b/src/Umbraco.Web/UmbracoModule.cs index c93b99d180..604e61e55f 100644 --- a/src/Umbraco.Web/UmbracoModule.cs +++ b/src/Umbraco.Web/UmbracoModule.cs @@ -1,4 +1,5 @@ using System; +using System.Collections; using System.IO; using System.Linq; using System.Web; @@ -166,23 +167,6 @@ namespace Umbraco.Web return end; } - /// - /// Checks if the xml cache file needs to be updated/persisted - /// - /// - /// - /// TODO: This needs an overhaul, see the error report created here: - /// https://docs.google.com/document/d/1neGE3q3grB4lVJfgID1keWY2v9JYqf-pw75sxUUJiyo/edit - /// - void PersistXmlCache(HttpContextBase httpContext) - { - if (content.Instance.IsXmlQueuedForPersistenceToFile) - { - content.Instance.RemoveXmlFilePersistenceQueue(); - content.Instance.PersistXmlToFile(); - } - } - #endregion #region Route helper methods @@ -350,7 +334,7 @@ namespace Umbraco.Web /// /// /// - private void RewriteToUmbracoHandler(HttpContextBase context, PublishedContentRequest pcr) + private static void RewriteToUmbracoHandler(HttpContextBase context, PublishedContentRequest pcr) { // NOTE: we do not want to use TransferRequest even though many docs say it is better with IIS7, turns out this is // not what we need. The purpose of TransferRequest is to ensure that .net processes all of the rules for the newly @@ -402,6 +386,36 @@ namespace Umbraco.Web } } + /// + /// Checks if the xml cache file needs to be updated/persisted + /// + /// + /// + /// TODO: This needs an overhaul, see the error report created here: + /// https://docs.google.com/document/d/1neGE3q3grB4lVJfgID1keWY2v9JYqf-pw75sxUUJiyo/edit + /// + static void PersistXmlCache(HttpContextBase httpContext) + { + if (content.Instance.IsXmlQueuedForPersistenceToFile) + { + content.Instance.RemoveXmlFilePersistenceQueue(); + content.Instance.PersistXmlToFile(); + } + } + + /// + /// Any object that is in the HttpContext.Items collection that is IDisposable will get disposed on the end of the request + /// + /// + private static void DisposeHttpContextItems(HttpContext http) + { + foreach (DictionaryEntry i in http.Items) + { + i.Value.DisposeIfDisposable(); + i.Key.DisposeIfDisposable(); + } + } + #region IHttpModule /// @@ -469,18 +483,6 @@ namespace Umbraco.Web #endregion - /// - /// Any object that is in the HttpContext.Items collection that is IDisposable will get disposed on the end of the request - /// - /// - private static void DisposeHttpContextItems(HttpContext http) - { - foreach(var i in http.Items) - { - i.DisposeIfDisposable(); - } - } - #region Events internal static event EventHandler RouteAttempt; private void OnRouteAttempt(RoutableAttemptEventArgs args)