From 6efd14eff32d548915fd288f7b31ad514ec30b54 Mon Sep 17 00:00:00 2001 From: Shannon Date: Thu, 26 Mar 2015 17:43:22 +1100 Subject: [PATCH] Updates the startup auth code extension methods to better support extensibility so people could override the default user store or manager in order to implement some interfaces that we currently don't. --- .../Models/Identity/BackOfficeIdentityUser.cs | 2 +- .../Models/Identity/IdentityUser.cs | 23 +++--- .../Security/BackOfficeUserManager.cs | 82 ++++++++++--------- .../Editors/BackOfficeController.cs | 6 ++ .../Security/Identity/AppBuilderExtensions.cs | 32 ++++++++ 5 files changed, 97 insertions(+), 48 deletions(-) diff --git a/src/Umbraco.Core/Models/Identity/BackOfficeIdentityUser.cs b/src/Umbraco.Core/Models/Identity/BackOfficeIdentityUser.cs index 31c56ba013..1523cf9040 100644 --- a/src/Umbraco.Core/Models/Identity/BackOfficeIdentityUser.cs +++ b/src/Umbraco.Core/Models/Identity/BackOfficeIdentityUser.cs @@ -12,7 +12,7 @@ namespace Umbraco.Core.Models.Identity public class BackOfficeIdentityUser : IdentityUser, IdentityUserClaim> { - public async Task GenerateUserIdentityAsync(BackOfficeUserManager manager) + public virtual async Task GenerateUserIdentityAsync(BackOfficeUserManager manager) { // NOTE the authenticationType must match the umbraco one // defined in CookieAuthenticationOptions.AuthenticationType diff --git a/src/Umbraco.Core/Models/Identity/IdentityUser.cs b/src/Umbraco.Core/Models/Identity/IdentityUser.cs index 09306bb1f0..cba4fc514a 100644 --- a/src/Umbraco.Core/Models/Identity/IdentityUser.cs +++ b/src/Umbraco.Core/Models/Identity/IdentityUser.cs @@ -18,6 +18,18 @@ namespace Umbraco.Core.Models.Identity where TRole : IdentityUserRole where TClaim : IdentityUserClaim { + + /// + /// Constructor + /// + /// + public IdentityUser() + { + this.Claims = new List(); + this.Roles = new List(); + this.Logins = new List(); + } + /// /// Email /// @@ -108,15 +120,6 @@ namespace Umbraco.Core.Models.Identity /// public virtual string UserName { get; set; } - /// - /// Constructor - /// - /// - public IdentityUser() - { - this.Claims = new List(); - this.Roles = new List(); - this.Logins = new List(); - } + } } \ No newline at end of file diff --git a/src/Umbraco.Core/Security/BackOfficeUserManager.cs b/src/Umbraco.Core/Security/BackOfficeUserManager.cs index b410f34107..def46b7556 100644 --- a/src/Umbraco.Core/Security/BackOfficeUserManager.cs +++ b/src/Umbraco.Core/Security/BackOfficeUserManager.cs @@ -13,47 +13,14 @@ using Umbraco.Core.Services; namespace Umbraco.Core.Security { /// - /// Back office user manager + /// Default back office user manager /// - public class BackOfficeUserManager : UserManager + public class BackOfficeUserManager : BackOfficeUserManager { public BackOfficeUserManager(IUserStore store) : base(store) { } - - #region What we support do not currently - - //NOTE: Not sure if we really want/need to ever support this - public override bool SupportsUserClaim - { - get { return false; } - } - - //TODO: Support this - public override bool SupportsQueryableUsers - { - get { return false; } - } - - //TODO: Support this - public override bool SupportsUserLockout - { - get { return false; } - } - - //TODO: Support this - public override bool SupportsUserTwoFactor - { - get { return false; } - } - - //TODO: Support this - public override bool SupportsUserPhoneNumber - { - get { return false; } - } - #endregion /// /// Creates a BackOfficeUserManager instance with all default options and the default BackOfficeUserManager @@ -155,10 +122,51 @@ namespace Umbraco.Core.Security return manager; } + } - protected override void Dispose(bool disposing) + /// + /// Generic Back office user manager + /// + public class BackOfficeUserManager : UserManager + where T : BackOfficeIdentityUser + { + public BackOfficeUserManager(IUserStore store) + : base(store) { - base.Dispose(disposing); } + + #region What we support do not currently + + //NOTE: Not sure if we really want/need to ever support this + public override bool SupportsUserClaim + { + get { return false; } + } + + //TODO: Support this + public override bool SupportsQueryableUsers + { + get { return false; } + } + + //TODO: Support this + public override bool SupportsUserLockout + { + get { return false; } + } + + //TODO: Support this + public override bool SupportsUserTwoFactor + { + get { return false; } + } + + //TODO: Support this + public override bool SupportsUserPhoneNumber + { + get { return false; } + } + #endregion + } } diff --git a/src/Umbraco.Web/Editors/BackOfficeController.cs b/src/Umbraco.Web/Editors/BackOfficeController.cs index 3a6f91eb2c..40ca7d428a 100644 --- a/src/Umbraco.Web/Editors/BackOfficeController.cs +++ b/src/Umbraco.Web/Editors/BackOfficeController.cs @@ -472,6 +472,12 @@ namespace Umbraco.Web.Editors var user = await UserManager.FindAsync(loginInfo.Login); if (user != null) { + //TODO: It might be worth keeping some of the claims associated with the ExternalLoginInfo, in which case we + // wouldn't necessarily sign the user in here with the standard login, instead we'd update the + // UseUmbracoBackOfficeExternalCookieAuthentication extension method to have the correct provider and claims factory, + // ticket format, etc.. to create our back office user including the claims assigned and in this method we'd just ensure + // that the ticket is created and stored and that the user is logged in. + //sign in await SignInAsync(user, isPersistent: false); } diff --git a/src/Umbraco.Web/Security/Identity/AppBuilderExtensions.cs b/src/Umbraco.Web/Security/Identity/AppBuilderExtensions.cs index bd8e47b6b3..c1cff6a5aa 100644 --- a/src/Umbraco.Web/Security/Identity/AppBuilderExtensions.cs +++ b/src/Umbraco.Web/Security/Identity/AppBuilderExtensions.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Threading.Tasks; using System.Web; using Microsoft.AspNet.Identity; using Microsoft.AspNet.Identity.Owin; @@ -31,6 +32,9 @@ namespace Umbraco.Web.Security.Identity ApplicationContext appContext, MembershipProviderBase userMembershipProvider) { + if (appContext == null) throw new ArgumentNullException("appContext"); + if (userMembershipProvider == null) throw new ArgumentNullException("userMembershipProvider"); + //Don't proceed if the app is not ready if (appContext.IsConfigured == false || appContext.DatabaseContext == null @@ -57,6 +61,10 @@ namespace Umbraco.Web.Security.Identity MembershipProviderBase userMembershipProvider, BackOfficeUserStore customUserStore) { + if (appContext == null) throw new ArgumentNullException("appContext"); + if (userMembershipProvider == null) throw new ArgumentNullException("userMembershipProvider"); + if (customUserStore == null) throw new ArgumentNullException("customUserStore"); + //Don't proceed if the app is not ready if (appContext.IsConfigured == false || appContext.DatabaseContext == null @@ -70,6 +78,30 @@ namespace Umbraco.Web.Security.Identity userMembershipProvider)); } + /// + /// Configure a custom BackOfficeUserManager for Umbraco + /// + /// + /// + /// + public static void ConfigureUserManagerForUmbracoBackOffice(this IAppBuilder app, + ApplicationContext appContext, + Func, IOwinContext, TManager> userManager) + where TManager : BackOfficeUserManager + where TUser : BackOfficeIdentityUser + { + if (appContext == null) throw new ArgumentNullException("appContext"); + if (userManager == null) throw new ArgumentNullException("userManager"); + + //Don't proceed if the app is not ready + if (appContext.IsConfigured == false + || appContext.DatabaseContext == null + || appContext.DatabaseContext.IsDatabaseConfigured == false) return; + + //Configure Umbraco user manager to be created per request + app.CreatePerOwinContext(userManager); + } + /// /// Ensures that the UmbracoBackOfficeAuthenticationMiddleware is assigned to the pipeline ///