U4-7538 GetRemainingTimeoutSeconds is double setting the cookie in 7.4

This commit is contained in:
Shannon
2016-01-05 12:35:06 +01:00
parent 15d06557e9
commit d08f4230c8
4 changed files with 105 additions and 56 deletions

View File

@@ -118,33 +118,45 @@ namespace Umbraco.Web.Security.Identity
{
if (app == null) throw new ArgumentNullException("app");
if (appContext == null) throw new ArgumentNullException("appContext");
var cookieAuthProvider = new BackOfficeCookieAuthenticationProvider
{
// Enables the application to validate the security stamp when the user
// logs in. This is a security feature which is used when you
// change a password or add an external login to your account.
OnValidateIdentity = SecurityStampValidator
.OnValidateIdentity<BackOfficeUserManager, BackOfficeIdentityUser, int>(
TimeSpan.FromMinutes(30),
(manager, user) => user.GenerateUserIdentityAsync(manager),
identity => identity.GetUserId<int>()),
};
var authOptions = new UmbracoBackOfficeCookieAuthOptions(
UmbracoConfig.For.UmbracoSettings().Security,
GlobalSettings.TimeOutInMinutes,
GlobalSettings.UseSSL)
{
Provider = new BackOfficeCookieAuthenticationProvider
{
// Enables the application to validate the security stamp when the user
// logs in. This is a security feature which is used when you
// change a password or add an external login to your account.
OnValidateIdentity = SecurityStampValidator
.OnValidateIdentity<BackOfficeUserManager, BackOfficeIdentityUser, int>(
TimeSpan.FromMinutes(30),
(manager, user) => user.GenerateUserIdentityAsync(manager),
identity => identity.GetUserId<int>()),
}
Provider = cookieAuthProvider
};
app.UseUmbracoBackOfficeCookieAuthentication(authOptions, appContext);
//don't apply if app isnot ready
if (appContext.IsUpgrading || appContext.IsConfigured)
{
var getSecondsOptions = new UmbracoBackOfficeCookieAuthOptions(
//This defines the explicit path read cookies from for this middleware
new[]{string.Format("{0}/backoffice/UmbracoApi/Authentication/GetRemainingTimeoutSeconds", GlobalSettings.Path)},
UmbracoConfig.For.UmbracoSettings().Security,
GlobalSettings.TimeOutInMinutes,
GlobalSettings.UseSSL)
{
Provider = cookieAuthProvider
};
//This is a custom middleware, we need to return the user's remaining logged in seconds
app.Use<GetUserSecondsMiddleWare>(
authOptions,
getSecondsOptions,
UmbracoConfig.For.UmbracoSettings().Security,
app.CreateLogger<GetUserSecondsMiddleWare>());
}

View File

@@ -1,8 +1,11 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using Microsoft.Owin;
using Microsoft.Owin.Infrastructure;
using Umbraco.Core;
using Umbraco.Core.Configuration;
using Umbraco.Core.IO;
namespace Umbraco.Web.Security.Identity
@@ -17,10 +20,19 @@ namespace Umbraco.Web.Security.Identity
internal class BackOfficeCookieManager : ChunkingCookieManager, ICookieManager
{
private readonly IUmbracoContextAccessor _umbracoContextAccessor;
private readonly string[] _explicitPaths;
private readonly string _getRemainingSecondsPath;
public BackOfficeCookieManager(IUmbracoContextAccessor umbracoContextAccessor)
: this(umbracoContextAccessor, null)
{
}
public BackOfficeCookieManager(IUmbracoContextAccessor umbracoContextAccessor, IEnumerable<string> explicitPaths)
{
_umbracoContextAccessor = umbracoContextAccessor;
_explicitPaths = explicitPaths == null ? null : explicitPaths.ToArray();
_getRemainingSecondsPath = string.Format("{0}/backoffice/UmbracoApi/Authentication/GetRemainingTimeoutSeconds", GlobalSettings.Path);
}
/// <summary>
@@ -64,9 +76,18 @@ namespace Umbraco.Web.Security.Identity
var request = ctx.Request;
var httpCtx = ctx.TryGetHttpContext();
//check the explicit paths
if (_explicitPaths != null)
{
return _explicitPaths.Any(x => x.InvariantEquals(request.Uri.AbsolutePath));
}
//check user seconds path
if (request.Uri.AbsolutePath.InvariantEquals(_getRemainingSecondsPath)) return false;
if (//check the explicit flag
(checkForceAuthTokens && ctx.Get<bool?>("umbraco-force-auth") != null)
|| (checkForceAuthTokens && httpCtx.Success && httpCtx.Result.Items["umbraco-force-auth"] != null)
|| (checkForceAuthTokens && httpCtx.Success && httpCtx.Result.Items["umbraco-force-auth"] != null)
//check back office
|| request.Uri.IsBackOfficeRequest(HttpRuntime.AppDomainAppVirtualPath)
//check installer

View File

@@ -24,7 +24,6 @@ namespace Umbraco.Web.Security.Identity
private readonly UmbracoBackOfficeCookieAuthOptions _authOptions;
private readonly ISecuritySection _security;
private readonly ILogger _logger;
private const int PersistentLoginSlidingMinutes = 30;
public GetUserSecondsMiddleWare(
OwinMiddleware next,
@@ -44,14 +43,10 @@ namespace Umbraco.Web.Security.Identity
{
var request = context.Request;
var response = context.Response;
var rootPath = context.Request.PathBase.HasValue
? context.Request.PathBase.Value.EnsureStartsWith("/").EnsureEndsWith("/")
: "/";
if (request.Uri.Scheme.InvariantStartsWith("http")
&& request.Uri.AbsolutePath.InvariantEquals(
string.Format("{0}{1}/backoffice/UmbracoApi/Authentication/GetRemainingTimeoutSeconds", rootPath, GlobalSettings.UmbracoMvcArea)))
string.Format("{0}/backoffice/UmbracoApi/Authentication/GetRemainingTimeoutSeconds", GlobalSettings.Path)))
{
var cookie = _authOptions.CookieManager.GetRequestCookie(context, _security.AuthCookieName);
if (cookie.IsNullOrWhiteSpace() == false)
@@ -88,7 +83,8 @@ namespace Umbraco.Web.Security.Identity
if (timeRemaining < timeElapsed)
{
ticket.Properties.IssuedUtc = currentUtc;
ticket.Properties.ExpiresUtc = currentUtc.AddMinutes(PersistentLoginSlidingMinutes);
var timeSpan = expiresUtc.Value.Subtract(issuedUtc.Value);
ticket.Properties.ExpiresUtc = currentUtc.Add(timeSpan);
var cookieValue = _authOptions.TicketDataFormat.Protect(ticket);

View File

@@ -21,35 +21,13 @@ namespace Umbraco.Web.Security.Identity
: this(UmbracoConfig.For.UmbracoSettings().Security, GlobalSettings.TimeOutInMinutes, GlobalSettings.UseSSL)
{
}
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,
bool forceSsl,
bool useLegacyFormsAuthDataFormat = true)
public UmbracoBackOfficeCookieAuthOptions(
string[] explicitPaths,
ISecuritySection securitySection,
int loginTimeoutMinutes,
bool forceSsl,
bool useLegacyFormsAuthDataFormat = true)
{
LoginTimeoutMinutes = loginTimeoutMinutes;
AuthenticationType = Constants.Security.BackOfficeAuthenticationType;
@@ -57,9 +35,9 @@ namespace Umbraco.Web.Security.Identity
if (useLegacyFormsAuthDataFormat)
{
//If this is not explicitly set it will fall back to the default automatically
TicketDataFormat = new FormsAuthenticationSecureDataFormat(loginTimeoutMinutes);
TicketDataFormat = new FormsAuthenticationSecureDataFormat(loginTimeoutMinutes);
}
SlidingExpiration = true;
ExpireTimeSpan = TimeSpan.FromMinutes(LoginTimeoutMinutes);
CookieDomain = securitySection.AuthCookieDomain;
@@ -69,7 +47,49 @@ namespace Umbraco.Web.Security.Identity
CookiePath = "/";
//Custom cookie manager so we can filter requests
CookieManager = new BackOfficeCookieManager(new SingletonUmbracoContextAccessor());
}
CookieManager = new BackOfficeCookieManager(new SingletonUmbracoContextAccessor(), explicitPaths);
}
public UmbracoBackOfficeCookieAuthOptions(
ISecuritySection securitySection,
int loginTimeoutMinutes,
bool forceSsl,
bool useLegacyFormsAuthDataFormat = true)
: this(null, securitySection, loginTimeoutMinutes, forceSsl, useLegacyFormsAuthDataFormat)
{
}
/// <summary>
/// Creates the cookie options for saving the auth cookie
/// </summary>
/// <param name="ctx"></param>
/// <param name="ticket"></param>
/// <returns></returns>
public CookieOptions CreateRequestCookieOptions(IOwinContext ctx, AuthenticationTicket ticket)
{
if (ctx == null) throw new ArgumentNullException("ctx");
if (ticket == null) throw new ArgumentNullException("ticket");
var issuedUtc = ticket.Properties.IssuedUtc ?? SystemClock.UtcNow;
var expiresUtc = ticket.Properties.ExpiresUtc ?? issuedUtc.Add(ExpireTimeSpan);
var cookieOptions = new CookieOptions
{
Path = "/",
Domain = this.CookieDomain ?? null,
HttpOnly = true,
Secure = this.CookieSecure == CookieSecureOption.Always
|| (this.CookieSecure == CookieSecureOption.SameAsRequest && ctx.Request.IsSecure),
};
if (ticket.Properties.IsPersistent)
{
cookieOptions.Expires = expiresUtc.ToUniversalTime().DateTime;
}
return cookieOptions;
}
}
}