diff --git a/src/Umbraco.Core/Security/AuthenticationExtensions.cs b/src/Umbraco.Core/Security/AuthenticationExtensions.cs index 01b7639cdc..6fd1b1fcd9 100644 --- a/src/Umbraco.Core/Security/AuthenticationExtensions.cs +++ b/src/Umbraco.Core/Security/AuthenticationExtensions.cs @@ -38,19 +38,17 @@ namespace Umbraco.Core.Security /// Renews the Umbraco authentication ticket /// /// - /// /// - public static bool RenewUmbracoAuthTicket(this HttpContextBase http, int timeoutInMinutes = 60) + public static bool RenewUmbracoAuthTicket(this HttpContextBase http) { return RenewAuthTicket(http, UmbracoConfig.For.UmbracoSettings().Security.AuthCookieName, - UmbracoConfig.For.UmbracoSettings().Security.AuthCookieDomain, - timeoutInMinutes); + UmbracoConfig.For.UmbracoSettings().Security.AuthCookieDomain); } - internal static bool RenewUmbracoAuthTicket(this HttpContext http, int timeoutInMinutes = 60) + internal static bool RenewUmbracoAuthTicket(this HttpContext http) { - return new HttpContextWrapper(http).RenewUmbracoAuthTicket(timeoutInMinutes); + return new HttpContextWrapper(http).RenewUmbracoAuthTicket(); } /// @@ -65,6 +63,7 @@ namespace Umbraco.Core.Security http, userdata.Username, userDataString, + //use the configuration timeout - this is the same timeout that will be used when renewing the ticket. GlobalSettings.TimeOutInMinutes, //Umbraco has always persisted it's original cookie for 1 day so we'll keep it that way 1440, @@ -78,6 +77,23 @@ namespace Umbraco.Core.Security new HttpContextWrapper(http).CreateUmbracoAuthTicket(userdata); } + /// + /// returns the number of seconds the user has until their auth session times out + /// + /// + /// + public static double GetRemainingAuthSeconds(this HttpContextBase http) + { + var ticket = http.GetUmbracoAuthTicket(); + if (ticket == null) + { + return 0; + } + var utcExpired = ticket.Expiration.ToUniversalTime(); + var secondsRemaining = utcExpired.Subtract(DateTime.UtcNow).TotalSeconds; + return secondsRemaining; + } + /// /// Gets the umbraco auth ticket /// @@ -143,9 +159,8 @@ namespace Umbraco.Core.Security /// /// /// - /// - /// - private static bool RenewAuthTicket(this HttpContextBase http, string cookieName, string cookieDomain, int minutesPersisted) + /// true if there was a ticket to renew otherwise false if there was no ticket + private static bool RenewAuthTicket(this HttpContextBase http, string cookieName, string cookieDomain) { //get the ticket var ticket = GetAuthTicket(http, cookieName); diff --git a/src/Umbraco.Core/UriExtensions.cs b/src/Umbraco.Core/UriExtensions.cs index b935dce488..a3ce4d0c0f 100644 --- a/src/Umbraco.Core/UriExtensions.cs +++ b/src/Umbraco.Core/UriExtensions.cs @@ -1,6 +1,9 @@ using System; using System.IO; using System.Linq; +using System.Web; +using System.Web.Mvc; +using System.Web.Routing; using Umbraco.Core.Configuration; using Umbraco.Core.IO; diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/auth.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/auth.resource.js index 604ba4b582..381682c932 100644 --- a/src/Umbraco.Web.UI.Client/src/common/resources/auth.resource.js +++ b/src/Umbraco.Web.UI.Client/src/common/resources/auth.resource.js @@ -55,6 +55,17 @@ function authResource($q, $http, umbRequestHelper, angularHelper) { "IsAuthenticated")), 'Server call failed for checking authentication'); }, + + /** Gets the user's remaining seconds before their login times out */ + getRemainingTimeoutSeconds: function () { + + return umbRequestHelper.resourcePromise( + $http.get( + umbRequestHelper.getApiUrl( + "authenticationApiBaseUrl", + "GetRemainingTimeoutSeconds")), + 'Server call failed for checking remaining seconds'); + } }; } diff --git a/src/Umbraco.Web.UI.Client/src/common/security/interceptor.js b/src/Umbraco.Web.UI.Client/src/common/security/interceptor.js index e995765d29..205088cdfe 100644 --- a/src/Umbraco.Web.UI.Client/src/common/security/interceptor.js +++ b/src/Umbraco.Web.UI.Client/src/common/security/interceptor.js @@ -1,45 +1,63 @@ angular.module('umbraco.security.interceptor', ['umbraco.security.retryQueue']) + // This http interceptor listens for authentication successes and failures + .factory('securityInterceptor', ['$injector', 'securityRetryQueue', 'notificationsService', function ($injector, queue, notifications) { + return function(promise) { -// This http interceptor listens for authentication failures -.factory('securityInterceptor', ['$injector', 'securityRetryQueue', 'notificationsService', function ($injector, queue, notifications) { - return function (promise) { - // Intercept failed requests - return promise.then(null, function (originalResponse) { - - //A 401 means that the user is not logged in - if (originalResponse.status === 401) { + return promise.then( + function(originalResponse) { + // Intercept successful requests + + //Here we'll check if our custom header is in the response which indicates how many seconds the user's session has before it + //expires. Then we'll update the user in the user service accordingly. + var headers = originalResponse.headers(); + if (headers["x-umb-user-seconds"]) { + var asNumber = parseFloat(headers["x-umb-user-seconds"]); + if (!isNaN(asNumber)) { + // We must use $injector to get the $http service to prevent circular dependency + var userService = $injector.get('userService'); + userService.setUserTimeout(asNumber); + } + } + + return promise; + }, function(originalResponse) { + // Intercept failed requests - // The request bounced because it was not authorized - add a new request to the retry queue - promise = queue.pushRetryFn('unauthorized-server', function retryRequest() { - // We must use $injector to get the $http service to prevent circular dependency - return $injector.get('$http')(originalResponse.config); + //A 401 means that the user is not logged in + if (originalResponse.status === 401) { + + // The request bounced because it was not authorized - add a new request to the retry queue + promise = queue.pushRetryFn('unauthorized-server', function retryRequest() { + // We must use $injector to get the $http service to prevent circular dependency + return $injector.get('$http')(originalResponse.config); + }); + } + else if (originalResponse.status === 403) { + //if the status was a 403 it means the user didn't have permission to do what the request was trying to do. + //How do we deal with this now, need to tell the user somehow that they don't have permission to do the thing that was + //requested. We can either deal with this globally here, or we can deal with it globally for individual requests on the umbRequestHelper, + // or completely custom for services calling resources. + + //http://issues.umbraco.org/issue/U4-2749 + + //It was decided to just put these messages into the normal status messages. + + var msg = "Unauthorized access to URL:
" + originalResponse.config.url.split('?')[0] + ""; + if (originalResponse.config.data) { + msg += "
with data:
" + angular.toJson(originalResponse.config.data) + "
Contact your administrator for information."; + } + + notifications.error( + "Authorization error", + msg); + } + + return promise; }); - } - else if (originalResponse.status === 403) { - //if the status was a 403 it means the user didn't have permission to do what the request was trying to do. - //How do we deal with this now, need to tell the user somehow that they don't have permission to do the thing that was - //requested. We can either deal with this globally here, or we can deal with it globally for individual requests on the umbRequestHelper, - // or completely custom for services calling resources. - - //http://issues.umbraco.org/issue/U4-2749 - - //It was decided to just put these messages into the normal status messages. + }; + }]) - var msg = "Unauthorized access to URL:
" + originalResponse.config.url.split('?')[0] + ""; - if (originalResponse.config.data) { - msg += "
with data:
" + angular.toJson(originalResponse.config.data) + "
Contact your administrator for information."; - } - - notifications.error( - "Authorization error", - msg); - } - return promise; - }); - }; -}]) - -// We have to add the interceptor to the queue as a string because the interceptor depends upon service instances that are not available in the config block. -.config(['$httpProvider', function ($httpProvider) { - $httpProvider.responseInterceptors.push('securityInterceptor'); -}]); \ No newline at end of file + // We have to add the interceptor to the queue as a string because the interceptor depends upon service instances that are not available in the config block. + .config(['$httpProvider', function ($httpProvider) { + $httpProvider.responseInterceptors.push('securityInterceptor'); + }]); \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/common/services/user.service.js b/src/Umbraco.Web.UI.Client/src/common/services/user.service.js index 811ed55c18..d70b5fe72e 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/user.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/user.service.js @@ -1,5 +1,5 @@ angular.module('umbraco.services') -.factory('userService', function ($rootScope, $q, $location, $log, securityRetryQueue, authResource, dialogService) { +.factory('userService', function ($rootScope, $q, $location, $log, securityRetryQueue, authResource, dialogService, $timeout) { var currentUser = null; var lastUserId = null; @@ -34,6 +34,31 @@ angular.module('umbraco.services') } } + /** + This methods will set the current user when it is resolved and + will then start the counter to count in-memory how many seconds they have + remaining on the auth session + */ + function setCurrentUser(usr) { + if (!usr.remainingAuthSeconds) { + throw "The user object is invalid, the remainingAuthSeconds is required."; + } + currentUser = usr; + //start the timer + setCurrentUserTimeout(usr); + } + function setCurrentUserTimeout() { + $timeout(function () { + if (currentUser) { + currentUser.remainingAuthSeconds -= 1; + if (currentUser.remainingAuthSeconds > 0) { + //recurse! + setCurrentUserTimeout(); + } + } + }, 1000);//every second + } + // Register a handler for when an item is added to the retry queue securityRetryQueue.onItemAddedCallbacks.push(function (retryItem) { if (securityRetryQueue.hasMore()) { @@ -76,7 +101,7 @@ angular.module('umbraco.services') .then(function (data) { //when it's successful, return the user data - currentUser = data; + setCurrentUser(data); var result = { user: data, authenticated: true, lastUserId: lastUserId }; @@ -119,7 +144,7 @@ angular.module('umbraco.services') $rootScope.$broadcast("authenticated", result); } - currentUser = data; + setCurrentUser(data); currentUser.avatar = 'http://www.gravatar.com/avatar/' + data.emailHash + '?s=40&d=404'; deferred.resolve(currentUser); }); @@ -130,6 +155,12 @@ angular.module('umbraco.services') } return deferred.promise; + }, + + setUserTimeout: function(newTimeout) { + if (currentUser && angular.isNumber(newTimeout)) { + currentUser.remainingAuthSeconds = newTimeout; + } } }; diff --git a/src/Umbraco.Web.UI.Client/src/less/panel.less b/src/Umbraco.Web.UI.Client/src/less/panel.less index 15d66b4ebc..2eeeca65e3 100644 --- a/src/Umbraco.Web.UI.Client/src/less/panel.less +++ b/src/Umbraco.Web.UI.Client/src/less/panel.less @@ -69,7 +69,9 @@ h1.headline{height: 20px; padding: 30px 0 0 20px;} width: 100%; margin: -2px 0 0 0; } - +.umb-panel-header p { + margin:0px 20px; +} .umb-headline-editor-wrapper input { background: none; border: none; diff --git a/src/Umbraco.Web.UI.Client/src/views/common/dialogs/user.html b/src/Umbraco.Web.UI.Client/src/views/common/dialogs/user.html index 86743358fc..41b0fd5306 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/dialogs/user.html +++ b/src/Umbraco.Web.UI.Client/src/views/common/dialogs/user.html @@ -8,6 +8,10 @@

{{user.name}}

+

+ Session expires in {{user.remainingAuthSeconds | number:0}} seconds +

+
diff --git a/src/Umbraco.Web/Editors/AuthenticationController.cs b/src/Umbraco.Web/Editors/AuthenticationController.cs index 5876a6b3d2..18d0462b8f 100644 --- a/src/Umbraco.Web/Editors/AuthenticationController.cs +++ b/src/Umbraco.Web/Editors/AuthenticationController.cs @@ -1,12 +1,15 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Net; using System.Net.Http; using System.Web; using System.Web.Http; using AutoMapper; +using Umbraco.Core; using Umbraco.Web.Models.ContentEditing; using Umbraco.Web.Models.Mapping; using Umbraco.Web.Mvc; +using Umbraco.Core.Security; using Umbraco.Web.Security; using Umbraco.Web.WebApi; using Umbraco.Web.WebApi.Filters; @@ -31,6 +34,25 @@ namespace Umbraco.Web.Editors base.Initialize(controllerContext); controllerContext.Configuration.Formatters.Remove(controllerContext.Configuration.Formatters.XmlFormatter); } + + /// + /// This is a special method that will return the current users' remaining session seconds, the reason + /// it is special is because this route is ignored in the UmbracoModule so that the auth ticket doesn't get + /// updated with a new timeout. + /// + /// + [WebApi.UmbracoAuthorize] + public double GetRemainingTimeoutSeconds() + { + var httpContextAttempt = TryGetHttpContext(); + if (httpContextAttempt.Success) + { + return httpContextAttempt.Result.GetRemainingAuthSeconds(); + } + + //we need an http context + throw new NotSupportedException("An HttpContext is required for this request"); + } /// /// Checks if the current user's cookie is valid and if so returns OK or a 400 (BadRequest) @@ -53,23 +75,23 @@ namespace Umbraco.Web.Editors /// - /// Checks if the current user's cookie is valid and if so returns the user object associated + /// Returns the currently logged in Umbraco user /// /// + [WebApi.UmbracoAuthorize] public UserDetail GetCurrentUser() { - var attempt = UmbracoContext.Security.AuthorizeRequest(); - if (attempt == ValidateRequestAttempt.Success) + var user = Services.UserService.GetUserById(UmbracoContext.Security.GetUserId()); + var result = Mapper.Map(user); + var httpContextAttempt = TryGetHttpContext(); + if (httpContextAttempt.Success) { - var user = Services.UserService.GetUserById(UmbracoContext.Security.GetUserId()); - return Mapper.Map(user); + //set their remaining seconds + result.SecondsUntilTimeout = httpContextAttempt.Result.GetRemainingAuthSeconds(); } - - //return Unauthorized (401) because the user is not authorized right now - throw new HttpResponseException(HttpStatusCode.Unauthorized); + return result; } - /// /// Logs a user in /// @@ -83,7 +105,14 @@ namespace Umbraco.Web.Editors var user = Services.UserService.GetUserByUserName(username); //TODO: Clean up the int cast! UmbracoContext.Security.PerformLogin((int)user.Id); - return Mapper.Map(user); + var result = Mapper.Map(user); + var httpContextAttempt = TryGetHttpContext(); + if (httpContextAttempt.Success) + { + //set their remaining seconds + result.SecondsUntilTimeout = httpContextAttempt.Result.GetRemainingAuthSeconds(); + } + return result; } //return BadRequest (400), we don't want to return a 401 because that get's intercepted diff --git a/src/Umbraco.Web/Models/ContentEditing/UserDetail.cs b/src/Umbraco.Web/Models/ContentEditing/UserDetail.cs index 499bacc902..70bbddfa8a 100644 --- a/src/Umbraco.Web/Models/ContentEditing/UserDetail.cs +++ b/src/Umbraco.Web/Models/ContentEditing/UserDetail.cs @@ -19,5 +19,11 @@ namespace Umbraco.Web.Models.ContentEditing /// [DataMember(Name = "emailHash")] public string EmailHash { get; set; } + + /// + /// Gets/sets the number of seconds for the user's auth ticket to expire + /// + [DataMember(Name = "remainingAuthSeconds")] + public double SecondsUntilTimeout { get; set; } } } \ No newline at end of file diff --git a/src/Umbraco.Web/Models/Mapping/UserModelMapper.cs b/src/Umbraco.Web/Models/Mapping/UserModelMapper.cs index 66c552726b..d72f7b33d9 100644 --- a/src/Umbraco.Web/Models/Mapping/UserModelMapper.cs +++ b/src/Umbraco.Web/Models/Mapping/UserModelMapper.cs @@ -16,6 +16,7 @@ namespace Umbraco.Web.Models.Mapping .ForMember( detail => detail.EmailHash, opt => opt.MapFrom(user => user.Email.ToLowerInvariant().Trim().ToMd5())); + config.CreateMap() .ForMember(detail => detail.UserId, opt => opt.MapFrom(profile => GetIntId(profile.Id))); } diff --git a/src/Umbraco.Web/Security/WebSecurity.cs b/src/Umbraco.Web/Security/WebSecurity.cs index adf1caa1e2..4baf64d553 100644 --- a/src/Umbraco.Web/Security/WebSecurity.cs +++ b/src/Umbraco.Web/Security/WebSecurity.cs @@ -166,7 +166,7 @@ namespace Umbraco.Web.Security public void RenewLoginTimeout() { - _httpContext.RenewUmbracoAuthTicket(UmbracoTimeOutInMinutes); + _httpContext.RenewUmbracoAuthTicket(); } /// @@ -229,7 +229,7 @@ namespace Umbraco.Web.Security internal void UpdateLogin() { - _httpContext.RenewUmbracoAuthTicket(UmbracoTimeOutInMinutes); + _httpContext.RenewUmbracoAuthTicket(); } internal long GetTimeout() diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 44df3f328c..46d36a78b8 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -839,6 +839,7 @@ + diff --git a/src/Umbraco.Web/UmbracoModule.cs b/src/Umbraco.Web/UmbracoModule.cs index 8a33b2449a..00f8c6f5fc 100644 --- a/src/Umbraco.Web/UmbracoModule.cs +++ b/src/Umbraco.Web/UmbracoModule.cs @@ -6,6 +6,7 @@ using System.Linq; using System.Security.Principal; using System.Threading; using System.Web; +using System.Web.Mvc; using System.Web.Routing; using Newtonsoft.Json; using Umbraco.Core; @@ -13,6 +14,7 @@ using Umbraco.Core.Configuration; using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Security; +using Umbraco.Web.Editors; using Umbraco.Web.Routing; using Umbraco.Web.Security; using umbraco; @@ -173,7 +175,9 @@ namespace Umbraco.Web if (ShouldAuthenticateRequest(req, UmbracoContext.Current.OriginalRequestUrl)) { var ticket = http.GetUmbracoAuthTicket(); - if (ticket != null && !ticket.Expired && http.RenewUmbracoAuthTicket()) + //if there was a ticket, it's not expired, its renewable - or it should not be renewed + if (ticket != null && ticket.Expired == false + && (http.RenewUmbracoAuthTicket() || ShouldIgnoreTicketRenew(UmbracoContext.Current.OriginalRequestUrl, http))) { try { @@ -249,6 +253,35 @@ namespace Umbraco.Web return false; } + private static readonly ConcurrentHashSet IgnoreTicketRenewUrls = new ConcurrentHashSet(); + /// + /// Determines if the authentication ticket should be renewed with a new timeout + /// + /// + /// + /// + /// + /// We do not want to renew the ticket when we are checking for the user's remaining timeout. + /// + internal static bool ShouldIgnoreTicketRenew(Uri url, HttpContextBase httpContext) + { + //initialize the ignore ticket urls - we don't need to lock this, it's concurrent and a hashset + // we don't want to have to gen the url each request so this will speed things up a teeny bit. + if (IgnoreTicketRenewUrls.Any() == false) + { + var urlHelper = new UrlHelper(new RequestContext(httpContext, new RouteData())); + var checkSessionUrl = urlHelper.GetUmbracoApiServiceBaseUrl(controller => controller.GetRemainingTimeoutSeconds()); + IgnoreTicketRenewUrls.Add(checkSessionUrl); + } + + if (IgnoreTicketRenewUrls.Any(x => url.AbsolutePath.StartsWith(x))) + { + return true; + } + + return false; + } + /// /// Checks the current request and ensures that it is routable based on the structure of the request and URI /// diff --git a/src/Umbraco.Web/WebApi/Filters/UmbracoUserTimeoutFilterAttribute.cs b/src/Umbraco.Web/WebApi/Filters/UmbracoUserTimeoutFilterAttribute.cs new file mode 100644 index 0000000000..012e2024fb --- /dev/null +++ b/src/Umbraco.Web/WebApi/Filters/UmbracoUserTimeoutFilterAttribute.cs @@ -0,0 +1,30 @@ +using System.Globalization; +using System.Web.Http.Filters; +using Umbraco.Core.Security; + +namespace Umbraco.Web.WebApi.Filters +{ + /// + /// This will check if the request is authenticated and if there's an auth ticket present we will + /// add a custom header to the response indicating how many seconds are remaining for the current + /// user's session. This allows us to keep track of a user's session effectively in the back office. + /// + public sealed class UmbracoUserTimeoutFilterAttribute : ActionFilterAttribute + { + public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext) + { + base.OnActionExecuted(actionExecutedContext); + + var httpContextAttempt = actionExecutedContext.Request.TryGetHttpContext(); + if (httpContextAttempt.Success) + { + var ticket = httpContextAttempt.Result.GetUmbracoAuthTicket(); + if (ticket != null && ticket.Expired == false) + { + var remainingSeconds = httpContextAttempt.Result.GetRemainingAuthSeconds(); + actionExecutedContext.Response.Headers.Add("X-Umb-User-Seconds", remainingSeconds.ToString(CultureInfo.InvariantCulture)); + } + } + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Web/WebApi/HttpRequestMessageExtensions.cs b/src/Umbraco.Web/WebApi/HttpRequestMessageExtensions.cs index 44cc8793fe..f053d7b790 100644 --- a/src/Umbraco.Web/WebApi/HttpRequestMessageExtensions.cs +++ b/src/Umbraco.Web/WebApi/HttpRequestMessageExtensions.cs @@ -5,14 +5,39 @@ using System.Net; using System.Net.Http; using System.Text; using System.Threading.Tasks; +using System.Web; using System.Web.Http; using System.Web.Http.ModelBinding; +using Umbraco.Core; namespace Umbraco.Web.WebApi { public static class HttpRequestMessageExtensions { + /// + /// Tries to retreive the current HttpContext if one exists. + /// + /// + public static Attempt TryGetHttpContext(this HttpRequestMessage request) + { + object context; + if (request.Properties.TryGetValue("MS_HttpContext", out context)) + { + var httpContext = context as HttpContextBase; + if (httpContext != null) + { + return Attempt.Succeed(httpContext); + } + } + if (HttpContext.Current != null) + { + return Attempt.Succeed(new HttpContextWrapper(HttpContext.Current)); + } + + return Attempt.Fail(); + } + /// /// Create a 403 (Forbidden) response indicating that hte current user doesn't have access to the resource /// requested or the action it needs to take. diff --git a/src/Umbraco.Web/WebApi/UmbracoApiController.cs b/src/Umbraco.Web/WebApi/UmbracoApiController.cs index 189acc24f3..cbe855ec3b 100644 --- a/src/Umbraco.Web/WebApi/UmbracoApiController.cs +++ b/src/Umbraco.Web/WebApi/UmbracoApiController.cs @@ -35,21 +35,7 @@ namespace Umbraco.Web.WebApi /// protected Attempt TryGetHttpContext() { - object context; - if (Request.Properties.TryGetValue("MS_HttpContext", out context)) - { - var httpContext = context as HttpContextBase; - if (httpContext != null) - { - return Attempt.Succeed(httpContext); - } - } - if (HttpContext.Current != null) - { - return Attempt.Succeed(new HttpContextWrapper(HttpContext.Current)); - } - - return Attempt.Fail(); + return Request.TryGetHttpContext(); } /// diff --git a/src/Umbraco.Web/WebApi/UmbracoAuthorizeAttribute.cs b/src/Umbraco.Web/WebApi/UmbracoAuthorizeAttribute.cs index 337892e0ca..4517464553 100644 --- a/src/Umbraco.Web/WebApi/UmbracoAuthorizeAttribute.cs +++ b/src/Umbraco.Web/WebApi/UmbracoAuthorizeAttribute.cs @@ -6,7 +6,7 @@ namespace Umbraco.Web.WebApi { /// /// Ensures authorization is successful for a back office user - /// + /// public sealed class UmbracoAuthorizeAttribute : AuthorizeAttribute { /// diff --git a/src/Umbraco.Web/WebApi/UmbracoAuthorizedApiController.cs b/src/Umbraco.Web/WebApi/UmbracoAuthorizedApiController.cs index c977200cb6..f27b25273b 100644 --- a/src/Umbraco.Web/WebApi/UmbracoAuthorizedApiController.cs +++ b/src/Umbraco.Web/WebApi/UmbracoAuthorizedApiController.cs @@ -8,6 +8,14 @@ using umbraco.BusinessLogic; namespace Umbraco.Web.WebApi { + /// + /// A base controller that ensures all requests are authorized - the user is logged in. + /// + /// + /// This controller will also append a custom header to the response if the user is logged in using forms authentication + /// which indicates the seconds remaining before their timeout expires. + /// + [UmbracoUserTimeoutFilter] [UmbracoAuthorize] public abstract class UmbracoAuthorizedApiController : UmbracoApiController { diff --git a/src/umbraco.businesslogic/BasePages/BasePage.cs b/src/umbraco.businesslogic/BasePages/BasePage.cs index d30d5aa506..a9727fb41c 100644 --- a/src/umbraco.businesslogic/BasePages/BasePage.cs +++ b/src/umbraco.businesslogic/BasePages/BasePage.cs @@ -252,12 +252,12 @@ namespace umbraco.BasePages private void UpdateLogin() { - Context.RenewUmbracoAuthTicket(UmbracoTimeOutInMinutes); + Context.RenewUmbracoAuthTicket(); } public static void RenewLoginTimeout() { - HttpContext.Current.RenewUmbracoAuthTicket(UmbracoTimeOutInMinutes); + HttpContext.Current.RenewUmbracoAuthTicket(); } ///