diff --git a/src/Umbraco.Web/Security/Identity/AppBuilderExtensions.cs b/src/Umbraco.Web/Security/Identity/AppBuilderExtensions.cs
index 946810ffc9..755eafedcb 100644
--- a/src/Umbraco.Web/Security/Identity/AppBuilderExtensions.cs
+++ b/src/Umbraco.Web/Security/Identity/AppBuilderExtensions.cs
@@ -172,7 +172,7 @@ namespace Umbraco.Web.Security.Identity
app.UseStageMarker(PipelineStage.Authenticate);
//Then our custom middlewares
- app.Use(typeof(ForceRenewalCookieAuthenticationMiddleware), app, options);
+ app.Use(typeof(ForceRenewalCookieAuthenticationMiddleware), app, options, new SingletonUmbracoContextAccessor());
app.UseStageMarker(PipelineStage.Authenticate);
app.Use(typeof(FixWindowsAuthMiddlware));
app.UseStageMarker(PipelineStage.Authenticate);
diff --git a/src/Umbraco.Web/Security/Identity/BackOfficeCookieManager.cs b/src/Umbraco.Web/Security/Identity/BackOfficeCookieManager.cs
index 06ce201ef9..c78a918fd9 100644
--- a/src/Umbraco.Web/Security/Identity/BackOfficeCookieManager.cs
+++ b/src/Umbraco.Web/Security/Identity/BackOfficeCookieManager.cs
@@ -50,6 +50,7 @@ namespace Umbraco.Web.Security.Identity
///
///
///
+ ///
///
///
/// We auth the request when:
@@ -58,14 +59,14 @@ namespace Umbraco.Web.Security.Identity
/// * it is a /base request
/// * it is a preview request
///
- internal static bool ShouldAuthenticateRequest(IOwinContext ctx, Uri originalRequestUrl)
+ internal bool ShouldAuthenticateRequest(IOwinContext ctx, Uri originalRequestUrl, bool checkForceAuthTokens = true)
{
var request = ctx.Request;
var httpCtx = ctx.TryGetHttpContext();
if (//check the explicit flag
- ctx.Get("umbraco-force-auth") != null
- || (httpCtx.Success && httpCtx.Result.Items["umbraco-force-auth"] != null)
+ (checkForceAuthTokens && ctx.Get("umbraco-force-auth") != null)
+ || (checkForceAuthTokens && httpCtx.Success && httpCtx.Result.Items["umbraco-force-auth"] != null)
//check back office
|| request.Uri.IsBackOfficeRequest(HttpRuntime.AppDomainAppVirtualPath)
//check installer
diff --git a/src/Umbraco.Web/Security/Identity/ForceRenewalCookieAuthenticationHandler.cs b/src/Umbraco.Web/Security/Identity/ForceRenewalCookieAuthenticationHandler.cs
index 24beb708f7..c7030b2558 100644
--- a/src/Umbraco.Web/Security/Identity/ForceRenewalCookieAuthenticationHandler.cs
+++ b/src/Umbraco.Web/Security/Identity/ForceRenewalCookieAuthenticationHandler.cs
@@ -1,3 +1,5 @@
+using System;
+using Umbraco.Core;
using System.Threading.Tasks;
using Microsoft.Owin;
using Microsoft.Owin.Security;
@@ -11,6 +13,13 @@ namespace Umbraco.Web.Security.Identity
///
internal class ForceRenewalCookieAuthenticationHandler : AuthenticationHandler
{
+ private readonly IUmbracoContextAccessor _umbracoContextAccessor;
+
+ public ForceRenewalCookieAuthenticationHandler(IUmbracoContextAccessor umbracoContextAccessor)
+ {
+ _umbracoContextAccessor = umbracoContextAccessor;
+ }
+
///
/// This handler doesn't actually do any auth so we return null;
///
@@ -45,7 +54,20 @@ namespace Umbraco.Web.Security.Identity
///
protected override Task ApplyResponseGrantAsync()
{
- //Now we need to check if we should force renew this based on a flag in the context
+ if (_umbracoContextAccessor.Value == null || Context.Request.Uri.IsClientSideRequest())
+ {
+ return Task.FromResult(0);
+ }
+
+ //Now we need to check if we should force renew this based on a flag in the context and whether this is a request that is not normally renewed by OWIN...
+ // which means that it is not a normal URL that is authenticated.
+
+ var normalAuthUrl = ((BackOfficeCookieManager) Options.CookieManager)
+ .ShouldAuthenticateRequest(Context, _umbracoContextAccessor.Value.OriginalRequestUrl,
+ //Pass in false, we want to know if this is a normal auth'd page
+ checkForceAuthTokens: false);
+ //This is auth'd normally, so OWIN will naturally take care of the cookie renewal
+ if (normalAuthUrl) return Task.FromResult(0);
var httpCtx = Context.TryGetHttpContext();
//check for the special flag in either the owin or http context
@@ -62,45 +84,39 @@ namespace Umbraco.Web.Security.Identity
if (shouldSignin == false && shouldSignout == false)
{
//get the ticket
- var model = GetTicket();
- if (model != null)
+ var ticket = GetTicket();
+ if (ticket != null)
{
var currentUtc = Options.SystemClock.UtcNow;
- var issuedUtc = model.Properties.IssuedUtc;
- var expiresUtc = model.Properties.ExpiresUtc;
+ var issuedUtc = ticket.Properties.IssuedUtc;
+ var expiresUtc = ticket.Properties.ExpiresUtc;
if (expiresUtc.HasValue && issuedUtc.HasValue)
{
- //renew the date/times
- model.Properties.IssuedUtc = currentUtc;
- var timeSpan = expiresUtc.Value.Subtract(issuedUtc.Value);
- model.Properties.ExpiresUtc = currentUtc.Add(timeSpan);
+ var timeElapsed = currentUtc.Subtract(issuedUtc.Value);
+ var timeRemaining = expiresUtc.Value.Subtract(currentUtc);
- //now save back all the required cookie details
- var cookieValue = Options.TicketDataFormat.Protect(model);
- var cookieOptions = new CookieOptions
+ //if it's time to renew, then do it
+ if (timeRemaining < timeElapsed)
{
- Domain = Options.CookieDomain,
- HttpOnly = Options.CookieHttpOnly,
- Path = Options.CookiePath ?? "/",
- };
- if (Options.CookieSecure == CookieSecureOption.SameAsRequest)
- {
- cookieOptions.Secure = Request.IsSecure;
- }
- else
- {
- cookieOptions.Secure = Options.CookieSecure == CookieSecureOption.Always;
- }
- if (model.Properties.IsPersistent)
- {
- cookieOptions.Expires = model.Properties.ExpiresUtc.Value.ToUniversalTime().DateTime;
- }
- Options.CookieManager.AppendResponseCookie(
- Context,
- Options.CookieName,
- cookieValue,
- cookieOptions);
+ //renew the date/times
+ ticket.Properties.IssuedUtc = currentUtc;
+ var timeSpan = expiresUtc.Value.Subtract(issuedUtc.Value);
+ ticket.Properties.ExpiresUtc = currentUtc.Add(timeSpan);
+
+ //now save back all the required cookie details
+ var cookieValue = Options.TicketDataFormat.Protect(ticket);
+
+ var cookieOptions = ((UmbracoBackOfficeCookieAuthOptions)Options).CreateRequestCookieOptions(Context, ticket);
+
+ Options.CookieManager.AppendResponseCookie(
+ Context,
+ Options.CookieName,
+ cookieValue,
+ cookieOptions);
+ }
+
+
}
}
}
diff --git a/src/Umbraco.Web/Security/Identity/ForceRenewalCookieAuthenticationMiddleware.cs b/src/Umbraco.Web/Security/Identity/ForceRenewalCookieAuthenticationMiddleware.cs
index e159a1c847..77a7a335f0 100644
--- a/src/Umbraco.Web/Security/Identity/ForceRenewalCookieAuthenticationMiddleware.cs
+++ b/src/Umbraco.Web/Security/Identity/ForceRenewalCookieAuthenticationMiddleware.cs
@@ -10,13 +10,20 @@ namespace Umbraco.Web.Security.Identity
///
internal class ForceRenewalCookieAuthenticationMiddleware : CookieAuthenticationMiddleware
{
- public ForceRenewalCookieAuthenticationMiddleware(OwinMiddleware next, IAppBuilder app, CookieAuthenticationOptions options) : base(next, app, options)
+ private readonly IUmbracoContextAccessor _umbracoContextAccessor;
+
+ public ForceRenewalCookieAuthenticationMiddleware(
+ OwinMiddleware next,
+ IAppBuilder app,
+ UmbracoBackOfficeCookieAuthOptions options,
+ IUmbracoContextAccessor umbracoContextAccessor) : base(next, app, options)
{
- }
+ _umbracoContextAccessor = umbracoContextAccessor;
+ }
protected override AuthenticationHandler CreateHandler()
{
- return new ForceRenewalCookieAuthenticationHandler();
+ return new ForceRenewalCookieAuthenticationHandler(_umbracoContextAccessor);
}
}
}
\ No newline at end of file
diff --git a/src/Umbraco.Web/Security/Identity/GetUserSecondsMiddleWare.cs b/src/Umbraco.Web/Security/Identity/GetUserSecondsMiddleWare.cs
index c3ce720fa5..a1f4c67681 100644
--- a/src/Umbraco.Web/Security/Identity/GetUserSecondsMiddleWare.cs
+++ b/src/Umbraco.Web/Security/Identity/GetUserSecondsMiddleWare.cs
@@ -80,15 +80,7 @@ namespace Umbraco.Web.Security.Identity
var cookieValue = _authOptions.TicketDataFormat.Protect(ticket);
- var cookieOptions = new CookieOptions
- {
- Path = "/",
- Domain = _authOptions.CookieDomain ?? null,
- Expires = DateTime.Now.AddMinutes(30),
- HttpOnly = true,
- Secure = _authOptions.CookieSecure == CookieSecureOption.Always
- || (_authOptions.CookieSecure == CookieSecureOption.SameAsRequest && request.Uri.Scheme.InvariantEquals("https")),
- };
+ var cookieOptions = _authOptions.CreateRequestCookieOptions(context, ticket);
_authOptions.CookieManager.AppendResponseCookie(
context,
diff --git a/src/Umbraco.Web/Security/Identity/UmbracoBackOfficeCookieAuthOptions.cs b/src/Umbraco.Web/Security/Identity/UmbracoBackOfficeCookieAuthOptions.cs
index 957cb66b0a..397b438f35 100644
--- a/src/Umbraco.Web/Security/Identity/UmbracoBackOfficeCookieAuthOptions.cs
+++ b/src/Umbraco.Web/Security/Identity/UmbracoBackOfficeCookieAuthOptions.cs
@@ -1,6 +1,8 @@
using System;
using System.Security.Claims;
using System.Threading.Tasks;
+using Microsoft.Owin;
+using Microsoft.Owin.Security;
using Microsoft.Owin.Security.Cookies;
using Umbraco.Core;
using Umbraco.Core.Configuration;
@@ -20,6 +22,29 @@ namespace Umbraco.Web.Security.Identity
{
}
+ public CookieOptions CreateRequestCookieOptions(IOwinContext ctx, AuthenticationTicket ticket)
+ {
+ if (ctx == null) throw new ArgumentNullException("ctx");
+ if (ticket == null) throw new ArgumentNullException("ticket");
+
+ var cookieOptions = new CookieOptions
+ {
+ Path = "/",
+ Domain = this.CookieDomain ?? null,
+ Expires = DateTime.Now.AddMinutes(30),
+ HttpOnly = true,
+ Secure = this.CookieSecure == CookieSecureOption.Always
+ || (this.CookieSecure == CookieSecureOption.SameAsRequest && ctx.Request.IsSecure),
+ };
+
+ if (ticket.Properties.IsPersistent && ticket.Properties.ExpiresUtc.HasValue)
+ {
+ cookieOptions.Expires = ticket.Properties.ExpiresUtc.Value.ToUniversalTime().DateTime;
+ }
+
+ return cookieOptions;
+ }
+
public UmbracoBackOfficeCookieAuthOptions(
ISecuritySection securitySection,
int loginTimeoutMinutes,