From 93df2edec2c247ef6615496ed75195580f7b71da Mon Sep 17 00:00:00 2001 From: Shannon Date: Fri, 6 Feb 2015 13:47:00 +1100 Subject: [PATCH] Initial install which now uses Identity middleware to perform the back office auth (no longer done in our module). Created custom data secure classes that use the legacy Forms auth logic for backwards compat. This means that the cookie can still be written the old way and still auth the new way if required. Now need to clean a lot of this up. --- .../Security/AuthenticationExtensions.cs | 49 ++++- src/Umbraco.Core/Umbraco.Core.csproj | 6 + src/Umbraco.Core/packages.config | 2 + src/Umbraco.Tests/App.config | 8 + src/Umbraco.Web.UI/App_Code/OwinStartup.cs | 61 ++++++ src/Umbraco.Web.UI/Umbraco.Web.UI.csproj | 2 +- .../Editors/AuthenticationController.cs | 11 ++ .../Security/Identity/AppBuilderExtensions.cs | 8 +- .../FormsAuthenticationSecureDataFormat.cs | 62 ++++++ .../UmbracoBackOfficeAuthenticationHandler.cs | 179 ++++++++++++++++-- ...bracoBackOfficeAuthenticationMiddleware.cs | 17 +- .../UmbracoBackOfficeAuthenticationOptions.cs | 18 -- ...coBackOfficeCookieAuthenticationOptions.cs | 35 ++++ src/Umbraco.Web/Security/WebSecurity.cs | 2 +- src/Umbraco.Web/Umbraco.Web.csproj | 8 +- src/Umbraco.Web/UmbracoModule.cs | 30 +-- src/Umbraco.Web/app.config | 4 + src/Umbraco.Web/packages.config | 2 +- src/umbraco.MacroEngines/app.config | 4 + src/umbraco.businesslogic/packages.config | 2 + .../umbraco.businesslogic.csproj | 6 + src/umbraco.editorControls/app.config | 4 + 22 files changed, 454 insertions(+), 66 deletions(-) create mode 100644 src/Umbraco.Web.UI/App_Code/OwinStartup.cs create mode 100644 src/Umbraco.Web/Security/Identity/FormsAuthenticationSecureDataFormat.cs delete mode 100644 src/Umbraco.Web/Security/Identity/UmbracoBackOfficeAuthenticationOptions.cs create mode 100644 src/Umbraco.Web/Security/Identity/UmbracoBackOfficeCookieAuthenticationOptions.cs diff --git a/src/Umbraco.Core/Security/AuthenticationExtensions.cs b/src/Umbraco.Core/Security/AuthenticationExtensions.cs index 8511d39125..49511697d7 100644 --- a/src/Umbraco.Core/Security/AuthenticationExtensions.cs +++ b/src/Umbraco.Core/Security/AuthenticationExtensions.cs @@ -1,10 +1,15 @@ using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.Linq; using System.Net.Http; using System.Net.Http.Headers; using System.Security.Principal; using System.Threading; using System.Web; using System.Web.Security; +using Microsoft.Owin; using Newtonsoft.Json; using Umbraco.Core.Configuration; @@ -268,6 +273,23 @@ namespace Umbraco.Core.Security return new HttpContextWrapper(http).GetUmbracoAuthTicket(); } + internal static FormsAuthenticationTicket GetUmbracoAuthTicket(this IOwinContext ctx) + { + if (ctx == null) throw new ArgumentNullException("ctx"); + //get the ticket + try + { + return GetAuthTicket(ctx.Request.Cookies.ToDictionary(x => x.Key, x => x.Value), UmbracoConfig.For.UmbracoSettings().Security.AuthCookieName); + } + catch (Exception) + { + //TODO: Do we need to do more here?? need to make sure that the forms cookie is gone, but is that + // taken care of in our custom middleware somehow? + ctx.Authentication.SignOut(); + return null; + } + } + /// /// This clears the forms authentication cookie /// @@ -301,16 +323,18 @@ namespace Umbraco.Core.Security private static FormsAuthenticationTicket GetAuthTicket(this HttpContextBase http, string cookieName) { - if (http == null) throw new ArgumentNullException("http"); - var formsCookie = http.Request.Cookies[cookieName]; - if (formsCookie == null) + var allKeys = new List(); + for (var i = 0; i < http.Request.Cookies.Keys.Count; i++) { - return null; + allKeys.Add(http.Request.Cookies.Keys.Get(i)); } + var asDictionary = allKeys.ToDictionary(key => key, key => http.Request.Cookies[key].Value); + //get the ticket try { - return FormsAuthentication.Decrypt(formsCookie.Value); + + return GetAuthTicket(asDictionary, cookieName); } catch (Exception) { @@ -320,6 +344,21 @@ namespace Umbraco.Core.Security } } + private static FormsAuthenticationTicket GetAuthTicket(IDictionary cookies, string cookieName) + { + if (cookies == null) throw new ArgumentNullException("cookies"); + + if (cookies.ContainsKey(cookieName) == false) return null; + + var formsCookie = cookies[cookieName]; + if (formsCookie == null) + { + return null; + } + //get the ticket + return FormsAuthentication.Decrypt(formsCookie); + } + /// /// Renews the forms authentication ticket & cookie /// diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 7cdb815933..9579bbba59 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -54,6 +54,9 @@ False ..\packages\log4net-mediumtrust.2.0.0\lib\log4net.dll + + ..\packages\Microsoft.Owin.3.0.0\lib\net45\Microsoft.Owin.dll + True ..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll @@ -70,6 +73,9 @@ False ..\packages\Newtonsoft.Json.6.0.4\lib\net45\Newtonsoft.Json.dll + + ..\packages\Owin.1.0\lib\net40\Owin.dll + diff --git a/src/Umbraco.Core/packages.config b/src/Umbraco.Core/packages.config index f3f9b617f7..c13e24ef1a 100644 --- a/src/Umbraco.Core/packages.config +++ b/src/Umbraco.Core/packages.config @@ -10,10 +10,12 @@ + + \ No newline at end of file diff --git a/src/Umbraco.Tests/App.config b/src/Umbraco.Tests/App.config index 3d35ae5c93..86e6a0cbfe 100644 --- a/src/Umbraco.Tests/App.config +++ b/src/Umbraco.Tests/App.config @@ -152,6 +152,14 @@ + + + + + + + + diff --git a/src/Umbraco.Web.UI/App_Code/OwinStartup.cs b/src/Umbraco.Web.UI/App_Code/OwinStartup.cs new file mode 100644 index 0000000000..e215fd552c --- /dev/null +++ b/src/Umbraco.Web.UI/App_Code/OwinStartup.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using Microsoft.AspNet.Identity; +using Microsoft.AspNet.Identity.Owin; +using Microsoft.Owin; +using Microsoft.Owin.Security.Cookies; + +using Owin; +using Umbraco.Web.Security.Identity; +using Umbraco.Web.UI; + +[assembly: OwinStartup(typeof(OwinStartup))] + +namespace Umbraco.Web.UI +{ + + /// + /// Summary description for Startup + /// + public class OwinStartup + { + + public void Configuration(IAppBuilder app) + { + ////Single method to configure the Identity user manager for use with Umbraco + //app.ConfigureUserManagerForUmbraco(); + + //// Enable the application to use a cookie to store information for the + //// signed in user and to use a cookie to temporarily store information + //// about a user logging in with a third party login provider + //// Configure the sign in cookie + //app.UseCookieAuthentication(new CookieAuthenticationOptions + //{ + // AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie, + + // Provider = new CookieAuthenticationProvider + // { + // // 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, UmbracoApplicationUser, int>( + // TimeSpan.FromMinutes(30), + // (manager, user) => user.GenerateUserIdentityAsync(manager), + // identity => identity.GetUserId()) + // } + //}); + + //Ensure owin is configured for Umbraco back office authentication - this must + // be configured AFTER the standard UseCookieConfiguration above. + app.UseUmbracoBackAuthentication(); + + app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie); + + } + + + } +} \ No newline at end of file diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj index c2de5441ab..fb07ae1ff4 100644 --- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj +++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj @@ -2579,7 +2579,7 @@ xcopy "$(ProjectDir)"..\packages\SqlServerCE.4.0.0.0\x86\*.* "$(TargetDir)x86\" True 7300 / - http://localhost:7300 + http://localhost:7301 False False diff --git a/src/Umbraco.Web/Editors/AuthenticationController.cs b/src/Umbraco.Web/Editors/AuthenticationController.cs index 00498f7e61..e3f13d46f3 100644 --- a/src/Umbraco.Web/Editors/AuthenticationController.cs +++ b/src/Umbraco.Web/Editors/AuthenticationController.cs @@ -9,6 +9,9 @@ using System.Web.Http; using System.Web.Http.Controllers; using System.Web.Security; using AutoMapper; +using Microsoft.AspNet.Identity; +using Microsoft.Owin; +using Microsoft.Owin.Security; using Umbraco.Core; using Umbraco.Core.Configuration; using Umbraco.Core.Models.Membership; @@ -109,6 +112,14 @@ namespace Umbraco.Web.Editors //TODO: Clean up the int cast! var ticket = UmbracoContext.Security.PerformLogin(user); + //TODO: Normally we'd do something like this for identity, but we're mixing and matching legacy and new here + // so we'll keep the legacy way and move forward with this in our custom handler for now, eventually replacing + // the above legacy logic with the new stuff. + + //OwinContext.Authentication.SignOut(DefaultAuthenticationTypes.ExternalCookie); + //OwinContext.Authentication.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent }, + // await user.GenerateUserIdentityAsync(UserManager)); + var http = this.TryGetHttpContext(); if (http.Success == false) { diff --git a/src/Umbraco.Web/Security/Identity/AppBuilderExtensions.cs b/src/Umbraco.Web/Security/Identity/AppBuilderExtensions.cs index f2ef0a010d..dc68a43152 100644 --- a/src/Umbraco.Web/Security/Identity/AppBuilderExtensions.cs +++ b/src/Umbraco.Web/Security/Identity/AppBuilderExtensions.cs @@ -7,6 +7,7 @@ using Microsoft.Owin.Extensions; using Owin; using Umbraco.Core; using Umbraco.Core.Configuration; +using Umbraco.Core.Logging; namespace Umbraco.Web.Security.Identity { @@ -52,7 +53,12 @@ namespace Umbraco.Web.Security.Identity app.Use(typeof (UmbracoBackOfficeAuthenticationMiddleware), //ctor params - app, new UmbracoBackOfficeAuthenticationOptions(), UmbracoConfig.For.UmbracoSettings().Security); + app, + new UmbracoBackOfficeCookieAuthenticationOptions( + UmbracoConfig.For.UmbracoSettings().Security, + GlobalSettings.TimeOutInMinutes, + GlobalSettings.UseSSL), + LoggerResolver.Current.Logger); app.UseStageMarker(PipelineStage.Authenticate); return app; diff --git a/src/Umbraco.Web/Security/Identity/FormsAuthenticationSecureDataFormat.cs b/src/Umbraco.Web/Security/Identity/FormsAuthenticationSecureDataFormat.cs new file mode 100644 index 0000000000..fac130f0ca --- /dev/null +++ b/src/Umbraco.Web/Security/Identity/FormsAuthenticationSecureDataFormat.cs @@ -0,0 +1,62 @@ +using System; +using System.Web.Security; +using Microsoft.Owin.Security; +using Newtonsoft.Json; +using Umbraco.Core.Security; + +namespace Umbraco.Web.Security.Identity +{ + /// + /// Custom secure format that uses the old FormsAuthentication format + /// + internal class FormsAuthenticationSecureDataFormat : ISecureDataFormat + { + private readonly int _loginTimeoutMinutes; + + public FormsAuthenticationSecureDataFormat(int loginTimeoutMinutes) + { + _loginTimeoutMinutes = loginTimeoutMinutes; + } + + public string Protect(AuthenticationTicket data) + { + //TODO: Where to get the user data? + //var userDataString = JsonConvert.SerializeObject(userdata); + + var ticket = new FormsAuthenticationTicket( + 5, + data.Identity.Name, + data.Properties.IssuedUtc.HasValue ? data.Properties.IssuedUtc.Value.LocalDateTime : DateTime.Now, + data.Properties.ExpiresUtc.HasValue ? data.Properties.ExpiresUtc.Value.LocalDateTime : DateTime.Now.AddMinutes(_loginTimeoutMinutes), + data.Properties.IsPersistent, + "", //User data here!! This will come from the identity + "/" + ); + + return FormsAuthentication.Encrypt(ticket); + } + + public AuthenticationTicket Unprotect(string protectedText) + { + FormsAuthenticationTicket decrypt; + try + { + decrypt = FormsAuthentication.Decrypt(protectedText); + if (decrypt == null) return null; + } + catch (Exception) + { + return null; + } + + var identity = new UmbracoBackOfficeIdentity(decrypt); + + return new AuthenticationTicket(identity, new AuthenticationProperties + { + ExpiresUtc = decrypt.Expiration.ToUniversalTime(), + IssuedUtc = decrypt.IssueDate.ToUniversalTime(), + IsPersistent = decrypt.IsPersistent + }); + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Web/Security/Identity/UmbracoBackOfficeAuthenticationHandler.cs b/src/Umbraco.Web/Security/Identity/UmbracoBackOfficeAuthenticationHandler.cs index 1b0adc604c..3393075c14 100644 --- a/src/Umbraco.Web/Security/Identity/UmbracoBackOfficeAuthenticationHandler.cs +++ b/src/Umbraco.Web/Security/Identity/UmbracoBackOfficeAuthenticationHandler.cs @@ -1,26 +1,35 @@ using System; using System.Reflection; +using System.Security.Principal; +using System.Threading; using System.Threading.Tasks; +using System.Web; using System.Web.Security; using Microsoft.Owin; using Microsoft.Owin.Security; +using Microsoft.Owin.Security.Cookies; using Microsoft.Owin.Security.Infrastructure; +using Newtonsoft.Json; using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.Security; using Umbraco.Core; +using Umbraco.Core.Logging; namespace Umbraco.Web.Security.Identity { /// /// Used to allow normal Umbraco back office authentication to work /// - public class UmbracoBackOfficeAuthenticationHandler : AuthenticationHandler + public class UmbracoBackOfficeAuthenticationHandler : AuthenticationHandler { - private readonly ISecuritySection _securitySection; + private readonly ILogger _logger; + private bool _shouldRenew; + private DateTimeOffset _renewIssuedUtc; + private DateTimeOffset _renewExpiresUtc; - public UmbracoBackOfficeAuthenticationHandler(ISecuritySection securitySection) + public UmbracoBackOfficeAuthenticationHandler(ILogger logger) { - _securitySection = securitySection; + _logger = logger; } /// @@ -33,24 +42,165 @@ namespace Umbraco.Web.Security.Identity /// so that it assigns the new Principal object on the OWIN request: /// http://brockallen.com/2013/10/27/host-authentication-and-web-api-with-owin-and-active-vs-passive-authentication-middleware/ /// - protected override Task AuthenticateCoreAsync() + protected override async Task AuthenticateCoreAsync() { if (ShouldAuthRequest()) { - var authTicket = GetAuthTicket(Request, _securitySection.AuthCookieName); - if (authTicket != null) + var ticket = GetAuthTicket(Request); + + if (ticket == null) { - return Task.FromResult(new AuthenticationTicket(new UmbracoBackOfficeIdentity(authTicket), new AuthenticationProperties())); + _logger.Warn(@"Unprotect ticket failed"); + return null; } + + DateTimeOffset currentUtc = Options.SystemClock.UtcNow; + DateTimeOffset? issuedUtc = ticket.Properties.IssuedUtc; + DateTimeOffset? expiresUtc = ticket.Properties.ExpiresUtc; + + if (expiresUtc != null && expiresUtc.Value < currentUtc) + { + return null; + } + + if (issuedUtc != null && expiresUtc != null && Options.SlidingExpiration) + { + TimeSpan timeElapsed = currentUtc.Subtract(issuedUtc.Value); + TimeSpan timeRemaining = expiresUtc.Value.Subtract(currentUtc); + + if (timeRemaining < timeElapsed) + { + _shouldRenew = true; + _renewIssuedUtc = currentUtc; + TimeSpan timeSpan = expiresUtc.Value.Subtract(issuedUtc.Value); + _renewExpiresUtc = currentUtc.Add(timeSpan); + } + } + + var context = new CookieValidateIdentityContext(Context, ticket, Options); + + await Options.Provider.ValidateIdentity(context); + + return new AuthenticationTicket(context.Identity, context.Properties); } - return Task.FromResult(null); + return await Task.FromResult(null); + } + + protected override async Task ApplyResponseGrantAsync() + { + AuthenticationResponseGrant signin = Helper.LookupSignIn(Options.AuthenticationType); + bool shouldSignin = signin != null; + AuthenticationResponseRevoke signout = Helper.LookupSignOut(Options.AuthenticationType, Options.AuthenticationMode); + bool shouldSignout = signout != null; + + if (shouldSignin || shouldSignout || _shouldRenew) + { + var cookieOptions = new CookieOptions + { + 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 (shouldSignin) + { + var context = new CookieResponseSignInContext( + Context, + Options, + Options.AuthenticationType, + signin.Identity, + signin.Properties); + + DateTimeOffset issuedUtc = Options.SystemClock.UtcNow; + DateTimeOffset expiresUtc = issuedUtc.Add(Options.ExpireTimeSpan); + + context.Properties.IssuedUtc = issuedUtc; + context.Properties.ExpiresUtc = expiresUtc; + + Options.Provider.ResponseSignIn(context); + + if (context.Properties.IsPersistent) + { + cookieOptions.Expires = expiresUtc.ToUniversalTime().DateTime; + } + + var model = new AuthenticationTicket(context.Identity, context.Properties); + string cookieValue = Options.TicketDataFormat.Protect(model); + + Response.Cookies.Append( + Options.CookieName, + cookieValue, + cookieOptions); + } + else if (shouldSignout) + { + Response.Cookies.Delete( + Options.CookieName, + cookieOptions); + } + else if (_shouldRenew) + { + AuthenticationTicket model = await AuthenticateAsync(); + + model.Properties.IssuedUtc = _renewIssuedUtc; + model.Properties.ExpiresUtc = _renewExpiresUtc; + + string cookieValue = Options.TicketDataFormat.Protect(model); + + if (model.Properties.IsPersistent) + { + cookieOptions.Expires = _renewExpiresUtc.ToUniversalTime().DateTime; + } + + Response.Cookies.Append( + Options.CookieName, + cookieValue, + cookieOptions); + } + + //Response.Headers.Set( + // HeaderNameCacheControl, + // HeaderValueNoCache); + + //Response.Headers.Set( + // HeaderNamePragma, + // HeaderValueNoCache); + + //Response.Headers.Set( + // HeaderNameExpires, + // HeaderValueMinusOne); + + bool shouldLoginRedirect = shouldSignin && Options.LoginPath.HasValue && Request.Path == Options.LoginPath; + bool shouldLogoutRedirect = shouldSignout && Options.LogoutPath.HasValue && Request.Path == Options.LogoutPath; + + if ((shouldLoginRedirect || shouldLogoutRedirect) && Response.StatusCode == 200) + { + IReadableStringCollection query = Request.Query; + string redirectUri = query.Get(Options.ReturnUrlParameter); + if (!string.IsNullOrWhiteSpace(redirectUri) + //&& IsHostRelative(redirectUri) + ) + { + var redirectContext = new CookieApplyRedirectContext(Context, Options, redirectUri); + Options.Provider.ApplyRedirect(redirectContext); + } + } + } } private bool ShouldAuthRequest() { var httpContext = Context.HttpContextFromOwinContext(); - + // do not process if client-side request if (httpContext.Request.Url.IsClientSideRequest()) return false; @@ -62,21 +212,20 @@ namespace Umbraco.Web.Security.Identity /// Returns the current FormsAuth ticket in the request /// /// - /// /// - private static FormsAuthenticationTicket GetAuthTicket(IOwinRequest request, string cookieName) + private AuthenticationTicket GetAuthTicket(IOwinRequest request) { if (request == null) throw new ArgumentNullException("request"); - var formsCookie = request.Cookies[cookieName]; - if (formsCookie == null) + var formsCookie = request.Cookies[Options.CookieName]; + if (string.IsNullOrWhiteSpace(formsCookie)) { return null; } //get the ticket try { - return FormsAuthentication.Decrypt(formsCookie); + return Options.TicketDataFormat.Unprotect(formsCookie); } catch (Exception) { diff --git a/src/Umbraco.Web/Security/Identity/UmbracoBackOfficeAuthenticationMiddleware.cs b/src/Umbraco.Web/Security/Identity/UmbracoBackOfficeAuthenticationMiddleware.cs index 1275b72c08..ffdce0fc8d 100644 --- a/src/Umbraco.Web/Security/Identity/UmbracoBackOfficeAuthenticationMiddleware.cs +++ b/src/Umbraco.Web/Security/Identity/UmbracoBackOfficeAuthenticationMiddleware.cs @@ -2,25 +2,30 @@ using Microsoft.Owin.Security.Infrastructure; using Owin; using Umbraco.Core.Configuration.UmbracoSettings; +using Umbraco.Core.Logging; namespace Umbraco.Web.Security.Identity { /// /// Used to enable the normal Umbraco back office authentication to operate /// - public class UmbracoBackOfficeAuthenticationMiddleware : AuthenticationMiddleware + public class UmbracoBackOfficeAuthenticationMiddleware : AuthenticationMiddleware { - private readonly ISecuritySection _securitySection; + private readonly ILogger _logger; - public UmbracoBackOfficeAuthenticationMiddleware(OwinMiddleware next, IAppBuilder app, UmbracoBackOfficeAuthenticationOptions options, ISecuritySection securitySection) + public UmbracoBackOfficeAuthenticationMiddleware( + OwinMiddleware next, + IAppBuilder app, + UmbracoBackOfficeCookieAuthenticationOptions options, + ILogger logger) : base(next, options) { - _securitySection = securitySection; + _logger = logger; } - protected override AuthenticationHandler CreateHandler() + protected override AuthenticationHandler CreateHandler() { - return new UmbracoBackOfficeAuthenticationHandler(_securitySection); + return new UmbracoBackOfficeAuthenticationHandler(_logger); } } } \ No newline at end of file diff --git a/src/Umbraco.Web/Security/Identity/UmbracoBackOfficeAuthenticationOptions.cs b/src/Umbraco.Web/Security/Identity/UmbracoBackOfficeAuthenticationOptions.cs deleted file mode 100644 index c7609a8e83..0000000000 --- a/src/Umbraco.Web/Security/Identity/UmbracoBackOfficeAuthenticationOptions.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Microsoft.Owin.Security; - -namespace Umbraco.Web.Security.Identity -{ - /// - /// Umbraco auth options - really just ensures that it is operating in Active mode - /// - public sealed class UmbracoBackOfficeAuthenticationOptions : AuthenticationOptions - { - public UmbracoBackOfficeAuthenticationOptions() - : base("UmbracoBackOffice") - { - //Must be active, this needs to look at each request to determine if it should execute, - // if set to passive this will not be the case - AuthenticationMode = AuthenticationMode.Active; - } - } -} \ No newline at end of file diff --git a/src/Umbraco.Web/Security/Identity/UmbracoBackOfficeCookieAuthenticationOptions.cs b/src/Umbraco.Web/Security/Identity/UmbracoBackOfficeCookieAuthenticationOptions.cs new file mode 100644 index 0000000000..e23f30b27f --- /dev/null +++ b/src/Umbraco.Web/Security/Identity/UmbracoBackOfficeCookieAuthenticationOptions.cs @@ -0,0 +1,35 @@ +using System.Security.Claims; +using System.Threading.Tasks; +using Microsoft.Owin; +using Microsoft.Owin.Security.Cookies; +using Umbraco.Core.Configuration; +using Umbraco.Core.Configuration.UmbracoSettings; + +namespace Umbraco.Web.Security.Identity +{ + /// + /// Umbraco auth cookie options + /// + public sealed class UmbracoBackOfficeCookieAuthenticationOptions : CookieAuthenticationOptions + { + public UmbracoBackOfficeCookieAuthenticationOptions() + : this(UmbracoConfig.For.UmbracoSettings().Security, GlobalSettings.TimeOutInMinutes, GlobalSettings.UseSSL) + { + } + + public UmbracoBackOfficeCookieAuthenticationOptions(ISecuritySection securitySection, int loginTimeoutMinutes, bool forceSsl) + { + AuthenticationType = "UmbracoBackOffice"; + + TicketDataFormat = new FormsAuthenticationSecureDataFormat(loginTimeoutMinutes); + + CookieDomain = securitySection.AuthCookieDomain; + CookieName = securitySection.AuthCookieName; + CookieHttpOnly = true; + CookieSecure = forceSsl ? CookieSecureOption.Always : CookieSecureOption.SameAsRequest; + CookiePath = "/"; + LoginPath = new PathString("/umbraco/login"); //TODO: ?? + + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Web/Security/WebSecurity.cs b/src/Umbraco.Web/Security/WebSecurity.cs index 0cad922d16..b6ec3680d8 100644 --- a/src/Umbraco.Web/Security/WebSecurity.cs +++ b/src/Umbraco.Web/Security/WebSecurity.cs @@ -91,7 +91,7 @@ namespace Umbraco.Web.Security /// Logs the user in /// /// - /// returns the number of seconds until their session times out + /// returns the Forms Auth ticket created which is used to log them in public virtual FormsAuthenticationTicket PerformLogin(IUser user) { var ticket = _httpContext.CreateUmbracoAuthTicket(new UserData(Guid.NewGuid().ToString("N")) diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 45e0ce5fe2..858561e5e9 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -138,8 +138,9 @@ ..\packages\Microsoft.AspNet.Identity.Owin.2.1.0\lib\net45\Microsoft.AspNet.Identity.Owin.dll - - ..\packages\Microsoft.Owin.2.1.0\lib\net45\Microsoft.Owin.dll + + False + ..\packages\Microsoft.Owin.3.0.0\lib\net45\Microsoft.Owin.dll ..\packages\Microsoft.Owin.Security.2.1.0\lib\net45\Microsoft.Owin.Security.dll @@ -540,10 +541,11 @@ + - + diff --git a/src/Umbraco.Web/UmbracoModule.cs b/src/Umbraco.Web/UmbracoModule.cs index f2d216f2fd..719f7135c4 100644 --- a/src/Umbraco.Web/UmbracoModule.cs +++ b/src/Umbraco.Web/UmbracoModule.cs @@ -180,26 +180,26 @@ namespace Umbraco.Web /// static void AuthenticateRequest(object sender, EventArgs e) { - var app = (HttpApplication)sender; - var http = new HttpContextWrapper(app.Context); + //var app = (HttpApplication)sender; + //var http = new HttpContextWrapper(app.Context); - // do not process if client-side request - if (http.Request.Url.IsClientSideRequest()) - return; + //// do not process if client-side request + //if (http.Request.Url.IsClientSideRequest()) + // return; - var req = new HttpRequestWrapper(app.Request); + //var req = new HttpRequestWrapper(app.Request); - if (ShouldAuthenticateRequest(req, UmbracoContext.Current.OriginalRequestUrl)) - { - //TODO: Here we should have an authentication mechanism, this mechanism should be smart in the way that the ASP.Net 5 pipeline works - // in which each registered handler will attempt to authenticate and if it fails it will just call Next() so the next handler - // executes. If it is successful, it doesn't call next and assigns the current user/principal. - // This might actually all be possible with ASP.Net Identity and how it is setup to work already, need to investigate. + //if (ShouldAuthenticateRequest(req, UmbracoContext.Current.OriginalRequestUrl)) + //{ + // //TODO: Here we should have an authentication mechanism, this mechanism should be smart in the way that the ASP.Net 5 pipeline works + // // in which each registered handler will attempt to authenticate and if it fails it will just call Next() so the next handler + // // executes. If it is successful, it doesn't call next and assigns the current user/principal. + // // This might actually all be possible with ASP.Net Identity and how it is setup to work already, need to investigate. - var ticket = http.GetUmbracoAuthTicket(); + // var ticket = http.GetUmbracoAuthTicket(); - http.AuthenticateCurrentRequest(ticket, ShouldIgnoreTicketRenew(UmbracoContext.Current.OriginalRequestUrl, http) == false); - } + // http.AuthenticateCurrentRequest(ticket, ShouldIgnoreTicketRenew(UmbracoContext.Current.OriginalRequestUrl, http) == false); + //} } diff --git a/src/Umbraco.Web/app.config b/src/Umbraco.Web/app.config index 957569042f..051211ebf7 100644 --- a/src/Umbraco.Web/app.config +++ b/src/Umbraco.Web/app.config @@ -51,6 +51,10 @@ + + + + \ No newline at end of file diff --git a/src/Umbraco.Web/packages.config b/src/Umbraco.Web/packages.config index 3fade0702d..8506c1de5b 100644 --- a/src/Umbraco.Web/packages.config +++ b/src/Umbraco.Web/packages.config @@ -19,7 +19,7 @@ - + diff --git a/src/umbraco.MacroEngines/app.config b/src/umbraco.MacroEngines/app.config index 900c3903d5..a3f8757270 100644 --- a/src/umbraco.MacroEngines/app.config +++ b/src/umbraco.MacroEngines/app.config @@ -26,6 +26,10 @@ + + + + \ No newline at end of file diff --git a/src/umbraco.businesslogic/packages.config b/src/umbraco.businesslogic/packages.config index 59350953ba..8ae1655c0d 100644 --- a/src/umbraco.businesslogic/packages.config +++ b/src/umbraco.businesslogic/packages.config @@ -4,5 +4,7 @@ + + \ No newline at end of file diff --git a/src/umbraco.businesslogic/umbraco.businesslogic.csproj b/src/umbraco.businesslogic/umbraco.businesslogic.csproj index c4c675366f..7accd2ccb5 100644 --- a/src/umbraco.businesslogic/umbraco.businesslogic.csproj +++ b/src/umbraco.businesslogic/umbraco.businesslogic.csproj @@ -113,10 +113,16 @@ ..\packages\AutoMapper.3.0.0\lib\net40\AutoMapper.Net4.dll + + ..\packages\Microsoft.Owin.3.0.0\lib\net45\Microsoft.Owin.dll + True ..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll + + ..\packages\Owin.1.0\lib\net40\Owin.dll + diff --git a/src/umbraco.editorControls/app.config b/src/umbraco.editorControls/app.config index 734aeed7b8..743b7c93ca 100644 --- a/src/umbraco.editorControls/app.config +++ b/src/umbraco.editorControls/app.config @@ -31,6 +31,10 @@ + + + + \ No newline at end of file