diff --git a/Identity.sln b/Identity.sln index 0f887fcf61..7b0232a0d1 100644 --- a/Identity.sln +++ b/Identity.sln @@ -28,6 +28,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution global.json = global.json EndProjectSection EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNet.Hosting", "..\Hosting\src\Microsoft.AspNet.Hosting\Microsoft.AspNet.Hosting.kproj", "{3944F036-7E75-47E8-AA52-C4B89A64EC3A}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -108,6 +110,16 @@ Global {E1BFA023-CFFD-49CE-8466-1C28DD2EC1F6}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {E1BFA023-CFFD-49CE-8466-1C28DD2EC1F6}.Release|Mixed Platforms.Build.0 = Release|Any CPU {E1BFA023-CFFD-49CE-8466-1C28DD2EC1F6}.Release|x86.ActiveCfg = Release|Any CPU + {3944F036-7E75-47E8-AA52-C4B89A64EC3A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3944F036-7E75-47E8-AA52-C4B89A64EC3A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3944F036-7E75-47E8-AA52-C4B89A64EC3A}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {3944F036-7E75-47E8-AA52-C4B89A64EC3A}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {3944F036-7E75-47E8-AA52-C4B89A64EC3A}.Debug|x86.ActiveCfg = Debug|Any CPU + {3944F036-7E75-47E8-AA52-C4B89A64EC3A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3944F036-7E75-47E8-AA52-C4B89A64EC3A}.Release|Any CPU.Build.0 = Release|Any CPU + {3944F036-7E75-47E8-AA52-C4B89A64EC3A}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {3944F036-7E75-47E8-AA52-C4B89A64EC3A}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {3944F036-7E75-47E8-AA52-C4B89A64EC3A}.Release|x86.ActiveCfg = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/samples/IdentitySample.Mvc/Controllers/AccountController.cs b/samples/IdentitySample.Mvc/Controllers/AccountController.cs index 5e29092042..5cde68b216 100644 --- a/samples/IdentitySample.Mvc/Controllers/AccountController.cs +++ b/samples/IdentitySample.Mvc/Controllers/AccountController.cs @@ -22,7 +22,6 @@ namespace IdentitySample.Models public SignInManager SignInManager { get; private set; } - // // GET: /Account/Login [HttpGet] @@ -30,7 +29,7 @@ namespace IdentitySample.Models public IActionResult Login(string returnUrl = null) { ViewBag.ReturnUrl = returnUrl; - ViewBag.LoginProviders = Context.GetExternalAuthenticationTypes().ToList(); + ViewBag.LoginProviders = SignInManager.GetExternalAuthenticationTypes().ToList(); return View(); } @@ -118,7 +117,7 @@ namespace IdentitySample.Models { // Request a redirect to the external login provider var redirectUrl = Url.Action("ExternalLoginCallback", "Account", new { ReturnUrl = returnUrl }); - var properties = Context.ConfigureExternalAuthenticationProperties(provider, redirectUrl); + var properties = SignInManager.ConfigureExternalAuthenticationProperties(provider, redirectUrl); return new ChallengeResult(provider, properties); } @@ -128,7 +127,7 @@ namespace IdentitySample.Models [AllowAnonymous] public async Task ExternalLoginCallback(string returnUrl = null) { - var info = await Context.GetExternalLoginInfo(); + var info = await SignInManager.GetExternalLoginInfoAsync(); if (info == null) { return RedirectToAction("Login"); @@ -171,7 +170,7 @@ namespace IdentitySample.Models if (ModelState.IsValid) { // Get the information about the user from the external login provider - var info = await Context.GetExternalLoginInfo(); + var info = await SignInManager.GetExternalLoginInfoAsync(); if (info == null) { return View("ExternalLoginFailure"); diff --git a/samples/IdentitySample.Mvc/Controllers/ManageController.cs b/samples/IdentitySample.Mvc/Controllers/ManageController.cs index f7c801903f..c824cedf76 100644 --- a/samples/IdentitySample.Mvc/Controllers/ManageController.cs +++ b/samples/IdentitySample.Mvc/Controllers/ManageController.cs @@ -302,7 +302,7 @@ namespace IdentitySample return View("Error"); } var userLogins = await UserManager.GetLoginsAsync(user); - var otherLogins = Context.GetExternalAuthenticationTypes().Where(auth => userLogins.All(ul => auth.AuthenticationType != ul.LoginProvider)).ToList(); + var otherLogins = SignInManager.GetExternalAuthenticationTypes().Where(auth => userLogins.All(ul => auth.AuthenticationType != ul.LoginProvider)).ToList(); ViewBag.ShowRemoveButton = user.PasswordHash != null || userLogins.Count > 1; return View(new ManageLoginsViewModel { @@ -319,7 +319,7 @@ namespace IdentitySample { // Request a redirect to the external login provider to link a login for the current user var redirectUrl = Url.Action("LinkLoginCallback", "Manage"); - var properties = Context.ConfigureExternalAuthenticationProperties(provider, redirectUrl, User.Identity.GetUserId()); + var properties = SignInManager.ConfigureExternalAuthenticationProperties(provider, redirectUrl, User.Identity.GetUserId()); return new ChallengeResult(provider, properties); } @@ -333,7 +333,7 @@ namespace IdentitySample { return View("Error"); } - var info = await Context.GetExternalLoginInfo(User.Identity.GetUserId()); + var info = await SignInManager.GetExternalLoginInfoAsync(User.Identity.GetUserId()); if (info == null) { return RedirectToAction("ManageLogins", new { Message = ManageMessageId.Error }); diff --git a/samples/IdentitySample.Mvc/Startup.cs b/samples/IdentitySample.Mvc/Startup.cs index eb6228948b..be5140aa17 100644 --- a/samples/IdentitySample.Mvc/Startup.cs +++ b/samples/IdentitySample.Mvc/Startup.cs @@ -1,79 +1,15 @@ -using System; +using IdentitySample.Models; using Microsoft.AspNet.Builder; using Microsoft.AspNet.Diagnostics; using Microsoft.AspNet.Identity; using Microsoft.AspNet.Routing; -using Microsoft.AspNet.Security.Facebook; -using Microsoft.AspNet.Security.Google; -using Microsoft.AspNet.Security.Twitter; using Microsoft.Data.Entity; using Microsoft.Framework.ConfigurationModel; using Microsoft.Framework.DependencyInjection; -using Microsoft.Framework.DependencyInjection.Fallback; -using Microsoft.Framework.OptionsModel; -using IdentitySample.Models; +using System; namespace IdentitySamples { - public static class UseExt - { - - /** - * TODO: Middleware constructors need to take IOptionsAccessor - - * Move options setup into a different method? - - * Cookie options need to be different, named service/option instances? i.e. Singleton Named Options - - SetupNamedOption("ApplicationCookie", options => { }) - UseCookieAuthentication("ApplicationCookie") - SetupNamedOption("ExternalCookie", options => { }) - UseCookieAuthentication("ApplicationCookie") - - // Overloads which use default/no name - SetupOption(options => { }) - UseGoogleAuthentication() - - */ - - public static IApplicationBuilder UseGoogleAuthentication(this IApplicationBuilder builder) - { - return builder.UseMiddleware(); - //return builder.UseGoogleAuthentication(b => - // b.ApplicationServices.GetService>().Options); - } - - - - public static IApplicationBuilder UseGoogleAuthentication(this IApplicationBuilder builder, Func func) - { - return builder.UseGoogleAuthentication(func(builder)); - } - - public static IApplicationBuilder UseFacebookAuthentication(this IApplicationBuilder builder) - { - // This should go inside of the middleware delegate - return builder.UseFacebookAuthentication(b => - b.ApplicationServices.GetService>().Options); - } - - public static IApplicationBuilder UseFacebookAuthentication(this IApplicationBuilder builder, Func func) - { - return builder.UseFacebookAuthentication(func(builder)); - } - - public static IApplicationBuilder UseTwitterAuthentication(this IApplicationBuilder builder) - { - return builder.UseTwitterAuthentication(b => - b.ApplicationServices.GetService>().Options); - } - - public static IApplicationBuilder UseTwitterAuthentication(this IApplicationBuilder builder, Func func) - { - return builder.UseTwitterAuthentication(func(builder)); - } - } - public partial class Startup { public Startup() @@ -89,102 +25,63 @@ namespace IdentitySamples public IConfiguration Configuration { get; private set; } + public void ConfigureServices(IServiceCollection services) + { + services.AddEntityFramework().AddSqlServer(); + services.AddScoped(); + services.ConfigureOptions(options => + { + options.DefaultAdminUserName = Configuration.Get("DefaultAdminUsername"); + options.DefaultAdminPassword = Configuration.Get("DefaultAdminPassword"); + options.UseSqlServer(Configuration.Get("Data:IdentityConnection:ConnectionString")); + }); + + services.AddDefaultIdentity(Configuration, options => + { + options.Password.RequireDigit = false; + options.Password.RequireLowercase = false; + options.Password.RequireUppercase = false; + options.Password.RequireNonLetterOrDigit = false; + options.SecurityStampValidationInterval = TimeSpan.FromMinutes(20); + }); + + services.ConfigureFacebookAuthentication(options => + { + options.AppId = "901611409868059"; + options.AppSecret = "4aa3c530297b1dcebc8860334b39668b"; + }); + services.ConfigureGoogleAuthentication(options => + { + options.ClientId = "514485782433-fr3ml6sq0imvhi8a7qir0nb46oumtgn9.apps.googleusercontent.com"; + options.ClientSecret = "V2nDD9SkFbvLTqAUBWBBxYAL"; + }); + services.ConfigureTwitterAuthentication(options => + { + options.ConsumerKey = "BSdJJ0CrDuvEhpkchnukXZBUv"; + options.ConsumerSecret = "xKUNuKhsRdHD03eLn67xhPAyE1wFFEndFo1X2UJaK2m1jdAxf4"; + }); + services.AddMvc(); + } + public void Configure(IApplicationBuilder app) { - app.UseServices(services => - { - // Add EF services to the services container - services.AddEntityFramework() - .AddSqlServer(); - - // Configure DbContext - services.SetupOptions(options => + app.UseErrorPage(ErrorPageOptions.ShowAll) + .UseServices() + .UseStaticFiles() + .UseIdentity() + .UseFacebookAuthentication() + .UseGoogleAuthentication() + .UseTwitterAuthentication() + .UseMvc(routes => { - options.DefaultAdminUserName = Configuration.Get("DefaultAdminUsername"); - options.DefaultAdminPassword = Configuration.Get("DefaultAdminPassword"); - options.UseSqlServer(Configuration.Get("Data:IdentityConnection:ConnectionString")); + routes.MapRoute( + name: "default", + template: "{controller}/{action}/{id?}", + defaults: new { controller = "Home", action = "Index" }); }); - // Add Identity services to the services container - services.AddDefaultIdentity(Configuration); - - // move this into add identity along with the - //service.SetupOptions(options => options.SignInAsAuthenticationType = "External") - - services.SetupOptions(options => - { - options.Password.RequireDigit = false; - options.Password.RequireLowercase = false; - options.Password.RequireUppercase = false; - options.Password.RequireNonLetterOrDigit = false; - options.SecurityStampValidationInterval = TimeSpan.Zero; - }); - services.SetupOptions(options => - { - options.ClientId = "514485782433-fr3ml6sq0imvhi8a7qir0nb46oumtgn9.apps.googleusercontent.com"; - options.ClientSecret = "V2nDD9SkFbvLTqAUBWBBxYAL"; - }); - services.AddInstance(new GoogleAuthenticationOptions - { - ClientId = "514485782433-fr3ml6sq0imvhi8a7qir0nb46oumtgn9.apps.googleusercontent.com", - ClientSecret = "V2nDD9SkFbvLTqAUBWBBxYAL" - }); - services.SetupOptions(options => - { - options.AppId = "901611409868059"; - options.AppSecret = "4aa3c530297b1dcebc8860334b39668b"; - }); - - services.SetupOptions(options => - { - options.AppId = "901611409868059"; - options.AppSecret = "4aa3c530297b1dcebc8860334b39668b"; - }); - - services.SetupOptions(options => - { - options.ConsumerKey = "BSdJJ0CrDuvEhpkchnukXZBUv"; - options.ConsumerSecret = "xKUNuKhsRdHD03eLn67xhPAyE1wFFEndFo1X2UJaK2m1jdAxf4"; - }); - - // Add MVC services to the services container - services.AddMvc(); - }); - - /* Error page middleware displays a nice formatted HTML page for any unhandled exceptions in the request pipeline. - * Note: ErrorPageOptions.ShowAll to be used only at development time. Not recommended for production. - */ - app.UseErrorPage(ErrorPageOptions.ShowAll); - - // Add static files to the request pipeline - app.UseStaticFiles(); - - // Setup identity cookie middleware - // Add cookie-based authentication to the request pipeline - app.UseIdentity(); - - app.UseGoogleAuthentication(); - app.UseFacebookAuthentication(); - app.UseTwitterAuthentication(); - - // Add MVC to the request pipeline - app.UseMvc(routes => - { - routes.MapRoute( - name: "default", - template: "{controller}/{action}/{id?}", - defaults: new { controller = "Home", action = "Index" }); - }); - - //Populates the Admin user and role + //Populates the Admin user and role SampleData.InitializeIdentityDatabaseAsync(app.ApplicationServices).Wait(); } - - // TODO: Move services here - public IServiceProvider ConfigureServices(ServiceCollection services) - { - return services.BuildServiceProvider(); - } - } } \ No newline at end of file diff --git a/src/Microsoft.AspNet.Identity.SqlServer/IdentityEntityFrameworkServiceCollectionExtensions.cs b/src/Microsoft.AspNet.Identity.SqlServer/IdentityEntityFrameworkServiceCollectionExtensions.cs index a75a3ca796..6b2b1d5beb 100644 --- a/src/Microsoft.AspNet.Identity.SqlServer/IdentityEntityFrameworkServiceCollectionExtensions.cs +++ b/src/Microsoft.AspNet.Identity.SqlServer/IdentityEntityFrameworkServiceCollectionExtensions.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using Microsoft.AspNet.Builder; using Microsoft.AspNet.Identity; using Microsoft.AspNet.Identity.SqlServer; using Microsoft.Data.Entity; @@ -11,6 +12,7 @@ namespace Microsoft.Framework.DependencyInjection { public static class IdentityEntityFrameworkServiceCollectionExtensions { + // MOVE to builder extension public static IdentityBuilder AddIdentitySqlServer(this IServiceCollection services) { return services.AddIdentitySqlServer(); @@ -22,54 +24,42 @@ namespace Microsoft.Framework.DependencyInjection return services.AddIdentitySqlServer(); } - public static IdentityBuilder AddDefaultIdentity(this IServiceCollection services, IConfiguration config) + public static IdentityBuilder AddDefaultIdentity(this IServiceCollection services, IConfiguration config = null, + Action configureOptions = null) where TUser : IdentityUser, new() where TRole : IdentityRole, new() where TContext : DbContext { - return services.AddDefaultIdentity(config) + return services.AddDefaultIdentity(config, configureOptions) .AddEntityFramework(); } - - public static IdentityBuilder AddIdentitySqlServer(this IServiceCollection services) + public static IdentityBuilder AddIdentitySqlServer(this IServiceCollection services, Action configureOptions = null) where TUser : IdentityUser, new() where TContext : DbContext { - return services.AddIdentitySqlServer(); + return services.AddIdentitySqlServer(null, configureOptions); } - public static IdentityBuilder AddSqlServer(this IServiceCollection services) + public static IdentityBuilder AddIdentitySqlServer(this IServiceCollection services, IConfiguration config = null, Action configureOptions = null) where TUser : IdentityUser, new() where TRole : IdentityRole, new() where TContext : DbContext { - var builder = services.AddIdentity(); + var builder = services.AddIdentity(config, configureOptions); services.AddScoped, UserStore>(); services.AddScoped, RoleStore>(); services.AddScoped(); return builder; } - public static IdentityBuilder AddIdentitySqlServer(this IServiceCollection services) - where TUser : IdentityUser, new() - where TRole : IdentityRole, new() - where TContext : DbContext - { - var builder = services.AddIdentity(); - services.AddScoped, UserStore>(); - services.AddScoped, RoleStore>(); - services.AddScoped(); - return builder; - } - - public static IdentityBuilder AddIdentitySqlServer(this IServiceCollection services) + public static IdentityBuilder AddIdentitySqlServer(this IServiceCollection services, IConfiguration config = null, Action configureOptions = null) where TUser : IdentityUser, new() where TRole : IdentityRole, new() where TContext : DbContext where TKey : IEquatable { - var builder = services.AddIdentity(); + var builder = services.AddIdentity(config, configureOptions); services.AddScoped, UserStore>(); services.AddScoped, RoleStore>(); services.AddScoped(); diff --git a/src/Microsoft.AspNet.Identity/BuilderExtensions.cs b/src/Microsoft.AspNet.Identity/BuilderExtensions.cs index 86b95d2a99..d3ca0cb72e 100644 --- a/src/Microsoft.AspNet.Identity/BuilderExtensions.cs +++ b/src/Microsoft.AspNet.Identity/BuilderExtensions.cs @@ -5,6 +5,8 @@ using System; using Microsoft.AspNet.Identity; using Microsoft.Framework.OptionsModel; using Microsoft.Framework.DependencyInjection; +using Microsoft.AspNet.Security.Cookies; +using Microsoft.Framework.ConfigurationModel; namespace Microsoft.AspNet.Builder { @@ -19,12 +21,11 @@ namespace Microsoft.AspNet.Builder { throw new ArgumentNullException("app"); } - var options = app.ApplicationServices.GetService>().Options; - app.SetDefaultSignInAsAuthenticationType(options.DefaultSignInAsAuthenticationType); - app.UseCookieAuthentication(options.ExternalCookie); - app.UseCookieAuthentication(options.ApplicationCookie); - app.UseCookieAuthentication(options.TwoFactorRememberMeCookie); - app.UseCookieAuthentication(options.TwoFactorUserIdCookie); + app.UseCookieAuthentication(null, IdentityOptions.ExternalCookieAuthenticationType); + app.UseCookieAuthentication(null, IdentityOptions.ApplicationCookieAuthenticationType); + app.UseCookieAuthentication(null, IdentityOptions.TwoFactorRememberMeCookieAuthenticationType); + app.UseCookieAuthentication(null, IdentityOptions.TwoFactorUserIdCookieAuthenticationType); + app.UseCookieAuthentication(null, IdentityOptions.ApplicationCookieAuthenticationType); return app; } } diff --git a/src/Microsoft.AspNet.Identity/ClaimsIdentityFactory.cs b/src/Microsoft.AspNet.Identity/ClaimsIdentityFactory.cs index a458b464b8..13b0d6b473 100644 --- a/src/Microsoft.AspNet.Identity/ClaimsIdentityFactory.cs +++ b/src/Microsoft.AspNet.Identity/ClaimsIdentityFactory.cs @@ -58,7 +58,7 @@ namespace Microsoft.AspNet.Identity } var userId = await UserManager.GetUserIdAsync(user, cancellationToken); var userName = await UserManager.GetUserNameAsync(user, cancellationToken); - var id = new ClaimsIdentity(Options.ApplicationCookie.AuthenticationType, Options.ClaimsIdentity.UserNameClaimType, + var id = new ClaimsIdentity(IdentityOptions.ApplicationCookieAuthenticationType, Options.ClaimsIdentity.UserNameClaimType, Options.ClaimsIdentity.RoleClaimType); id.AddClaim(new Claim(Options.ClaimsIdentity.UserIdClaimType, userId)); id.AddClaim(new Claim(Options.ClaimsIdentity.UserNameClaimType, userName, ClaimValueTypes.String)); diff --git a/src/Microsoft.AspNet.Identity/ClaimsIdentityOptions.cs b/src/Microsoft.AspNet.Identity/ClaimsIdentityOptions.cs index dce5fb4240..9b8dd3c24f 100644 --- a/src/Microsoft.AspNet.Identity/ClaimsIdentityOptions.cs +++ b/src/Microsoft.AspNet.Identity/ClaimsIdentityOptions.cs @@ -8,10 +8,6 @@ namespace Microsoft.AspNet.Identity public class ClaimsIdentityOptions { public static readonly string DefaultSecurityStampClaimType = "AspNet.Identity.SecurityStamp"; - public static readonly string DefaultAuthenticationType = typeof(ClaimsIdentityOptions).Namespace + ".Application"; - public static readonly string DefaultExternalLoginAuthenticationType = typeof(ClaimsIdentityOptions).Namespace + ".ExternalLogin"; - public static readonly string DefaultTwoFactorRememberMeAuthenticationType = typeof(ClaimsIdentityOptions).Namespace + ".TwoFactorRememberMe"; - public static readonly string DefaultTwoFactorUserIdAuthenticationType = typeof(ClaimsIdentityOptions).Namespace + ".TwoFactorUserId"; /// /// Claim type used for role claims diff --git a/src/Microsoft.AspNet.Identity/HttpContextExtensions.cs b/src/Microsoft.AspNet.Identity/HttpContextExtensions.cs deleted file mode 100644 index b05b5fa1cb..0000000000 --- a/src/Microsoft.AspNet.Identity/HttpContextExtensions.cs +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System.Collections.Generic; -using System.Security.Claims; -using System.Threading.Tasks; -using Microsoft.AspNet.Identity; -using Microsoft.AspNet.Http.Security; -using System.Linq; -using System; -using System.Security.Principal; - -namespace Microsoft.AspNet.Http -{ - public static class HttpContextExtensions - { - private const string LoginProviderKey = "LoginProvider"; - private const string XsrfKey = "XsrfId"; - - public static IEnumerable GetExternalAuthenticationTypes(this HttpContext context) - { - if (context == null) - { - throw new ArgumentNullException(nameof(context)); - } - return context.GetAuthenticationTypes().Where(d => !string.IsNullOrEmpty(d.Caption)); - } - - public static async Task GetExternalLoginInfo(this HttpContext context, string expectedXsrf = null) - { - if (context == null) - { - throw new ArgumentNullException(nameof(context)); - } - // REVIEW: should we consider taking the external authentication type as an argument? - var auth = await context.AuthenticateAsync(ClaimsIdentityOptions.DefaultExternalLoginAuthenticationType); - if (auth == null || auth.Identity == null || auth.Properties.Dictionary == null || !auth.Properties.Dictionary.ContainsKey(LoginProviderKey)) - { - return null; - } - - if (expectedXsrf != null) - { - if (!auth.Properties.Dictionary.ContainsKey(XsrfKey)) - { - return null; - } - var userId = auth.Properties.Dictionary[XsrfKey] as string; - if (userId != expectedXsrf) - { - return null; - } - } - - var providerKey = auth.Identity.FindFirstValue(ClaimTypes.NameIdentifier); - var provider = auth.Properties.Dictionary[LoginProviderKey] as string; - if (providerKey == null || provider == null) - { - return null; - } - return new ExternalLoginInfo(auth.Identity, provider, providerKey, auth.Description.Caption); - } - - public static AuthenticationProperties ConfigureExternalAuthenticationProperties(this HttpContext context, string provider, string redirectUrl, string userId = null) - { - var properties = new AuthenticationProperties { RedirectUri = redirectUrl }; - properties.Dictionary[LoginProviderKey] = provider; - if (userId != null) - { - properties.Dictionary[XsrfKey] = userId; - } - return properties; - } - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNet.Identity/IdentityBuilder.cs b/src/Microsoft.AspNet.Identity/IdentityBuilder.cs index 0719c05dd5..7445fca909 100644 --- a/src/Microsoft.AspNet.Identity/IdentityBuilder.cs +++ b/src/Microsoft.AspNet.Identity/IdentityBuilder.cs @@ -16,8 +16,6 @@ namespace Microsoft.AspNet.Identity Services = services; } - // Rename to Add - public IdentityBuilder AddInstance(T obj) { Services.AddInstance(obj); @@ -49,17 +47,12 @@ namespace Microsoft.AspNet.Identity return AddInstance(tokenProvider); } - public IdentityBuilder SetupOptions(Action action, int order) + public IdentityBuilder ConfigureIdentity(Action action, int order = 0) { - Services.AddSetup(new OptionsSetup(action) { Order = order }); + Services.AddOptionsAction(new OptionsAction(action) { Order = order }); return this; } - public IdentityBuilder SetupOptions(Action action) - { - return SetupOptions(action, 0); - } - public IdentityBuilder AddUserManager() where TManager : UserManager { Services.AddScoped(); diff --git a/src/Microsoft.AspNet.Identity/IdentityOptions.cs b/src/Microsoft.AspNet.Identity/IdentityOptions.cs index c5cbc525f6..0705a4dbd5 100644 --- a/src/Microsoft.AspNet.Identity/IdentityOptions.cs +++ b/src/Microsoft.AspNet.Identity/IdentityOptions.cs @@ -29,47 +29,9 @@ namespace Microsoft.AspNet.Identity public string PasswordResetTokenProvider { get; set; } = Resources.DefaultTokenProvider; - //public string ApplicationCookieAuthenticationType { get; set; } - //public string ExternalCookieAuthenticationType { get; set; } - //public string TwoFactorCookieAuthenticationType { get; set; } - //public string TwoFactorFactorCookieAuthenticationType { get; set; } - - public CookieAuthenticationOptions ApplicationCookie { get; set; } = new CookieAuthenticationOptions - { - AuthenticationType = ClaimsIdentityOptions.DefaultAuthenticationType, - //CookieName = ".AspNet.Identity." + ClaimsIdentityOptions.DefaultAuthenticationType, - LoginPath = new PathString("/Account/Login"), - Notifications = new CookieAuthenticationNotifications - { - OnValidateIdentity = SecurityStampValidator.ValidateIdentityAsync - } - }; - - // Move to setups for named per cookie option - - public string DefaultSignInAsAuthenticationType { get; set; } = ClaimsIdentityOptions.DefaultExternalLoginAuthenticationType; - - public CookieAuthenticationOptions ExternalCookie { get; set; } = new CookieAuthenticationOptions - { - AuthenticationType = ClaimsIdentityOptions.DefaultExternalLoginAuthenticationType, - AuthenticationMode = AuthenticationMode.Passive, - CookieName = ClaimsIdentityOptions.DefaultExternalLoginAuthenticationType, - ExpireTimeSpan = TimeSpan.FromMinutes(5), - }; - - public CookieAuthenticationOptions TwoFactorRememberMeCookie { get; set; } = new CookieAuthenticationOptions - { - AuthenticationType = ClaimsIdentityOptions.DefaultTwoFactorRememberMeAuthenticationType, - AuthenticationMode = AuthenticationMode.Passive, - CookieName = ClaimsIdentityOptions.DefaultTwoFactorRememberMeAuthenticationType - }; - - public CookieAuthenticationOptions TwoFactorUserIdCookie { get; set; } = new CookieAuthenticationOptions - { - AuthenticationType = ClaimsIdentityOptions.DefaultTwoFactorUserIdAuthenticationType, - AuthenticationMode = AuthenticationMode.Passive, - CookieName = ClaimsIdentityOptions.DefaultTwoFactorUserIdAuthenticationType, - ExpireTimeSpan = TimeSpan.FromMinutes(5), - }; + public static string ApplicationCookieAuthenticationType { get; set; } = typeof(IdentityOptions).Namespace + ".Application"; + public static string ExternalCookieAuthenticationType { get; set; } = typeof(IdentityOptions).Namespace + ".External"; + public static string TwoFactorUserIdCookieAuthenticationType { get; set; } = typeof(IdentityOptions).Namespace + ".TwoFactorUserId"; + public static string TwoFactorRememberMeCookieAuthenticationType { get; set; } = typeof(IdentityOptions).Namespace + ".TwoFactorRemeberMe"; } } \ No newline at end of file diff --git a/src/Microsoft.AspNet.Identity/IdentityServiceCollectionExtensions.cs b/src/Microsoft.AspNet.Identity/IdentityServiceCollectionExtensions.cs index 41784b2955..7aaceee581 100644 --- a/src/Microsoft.AspNet.Identity/IdentityServiceCollectionExtensions.cs +++ b/src/Microsoft.AspNet.Identity/IdentityServiceCollectionExtensions.cs @@ -5,16 +5,23 @@ using System; using Microsoft.AspNet.Identity; using Microsoft.Framework.ConfigurationModel; using Microsoft.AspNet.Security.DataProtection; +using Microsoft.AspNet.Security.Cookies; +using Microsoft.AspNet.Http; +using Microsoft.AspNet.Security; namespace Microsoft.Framework.DependencyInjection { public static class IdentityServiceCollectionExtensions { - public static IdentityBuilder AddIdentity(this IServiceCollection services, - IConfiguration identityConfig) + public static IServiceCollection ConfigureIdentity(this IServiceCollection services, Action configure) { - services.SetupOptions(identityConfig); - return services.AddIdentity(); + return services.ConfigureOptions(configure); + } + + public static IdentityBuilder AddIdentity(this IServiceCollection services, + IConfiguration identityConfig = null, Action configureOptions = null) + { + return services.AddIdentity(identityConfig, configureOptions); } public static IdentityBuilder AddIdentity(this IServiceCollection services) @@ -23,28 +30,73 @@ namespace Microsoft.Framework.DependencyInjection } public static IdentityBuilder AddIdentity(this IServiceCollection services, - IConfiguration identityConfig = null) + IConfiguration identityConfig = null, Action configureOptions = null) where TUser : class where TRole : class { if (identityConfig != null) { - services.SetupOptions(identityConfig); + services.ConfigureOptions(identityConfig); } + if (configureOptions != null) + { + services.ConfigureIdentity(configureOptions); + } + services.Add(IdentityServices.GetDefaultServices(identityConfig)); services.AddScoped>(); services.AddScoped>(); services.AddScoped>(); services.AddScoped>(); services.AddScoped, ClaimsIdentityFactory>(); + + services.ConfigureOptions(options => + { + options.SignInAsAuthenticationType = IdentityOptions.ExternalCookieAuthenticationType; + }); + + services.ConfigureOptions(options => + { + options.AuthenticationType = IdentityOptions.ApplicationCookieAuthenticationType; + //CookieName = ".AspNet.Identity." + ClaimsIdentityOptions.DefaultAuthenticationType, + options.LoginPath = new PathString("/Account/Login"); + options.Notifications = new CookieAuthenticationNotifications + { + OnValidateIdentity = SecurityStampValidator.ValidateIdentityAsync + }; + }, IdentityOptions.ApplicationCookieAuthenticationType); + + services.ConfigureOptions(options => + { + options.AuthenticationType = IdentityOptions.ExternalCookieAuthenticationType; + options.AuthenticationMode = AuthenticationMode.Passive; + options.CookieName = IdentityOptions.ExternalCookieAuthenticationType; + options.ExpireTimeSpan = TimeSpan.FromMinutes(5); + }, IdentityOptions.ExternalCookieAuthenticationType); + + services.ConfigureOptions(options => + { + options.AuthenticationType = IdentityOptions.TwoFactorRememberMeCookieAuthenticationType; + options.AuthenticationMode = AuthenticationMode.Passive; + options.CookieName = IdentityOptions.TwoFactorRememberMeCookieAuthenticationType; + }, IdentityOptions.TwoFactorRememberMeCookieAuthenticationType); + + services.ConfigureOptions(options => + { + options.AuthenticationType = IdentityOptions.TwoFactorUserIdCookieAuthenticationType; + options.AuthenticationMode = AuthenticationMode.Passive; + options.CookieName = IdentityOptions.TwoFactorUserIdCookieAuthenticationType; + options.ExpireTimeSpan = TimeSpan.FromMinutes(5); + }, IdentityOptions.TwoFactorUserIdCookieAuthenticationType); + return new IdentityBuilder(services); } - public static IdentityBuilder AddDefaultIdentity(this IServiceCollection services, IConfiguration config = null) + public static IdentityBuilder AddDefaultIdentity(this IServiceCollection services, IConfiguration config = null, Action configureOptions = null) where TUser : class where TRole : class { - return services.AddIdentity(config) + return services.AddIdentity(config, configureOptions) .AddTokenProvider(new DataProtectorTokenProvider( new DataProtectionTokenProviderOptions { diff --git a/src/Microsoft.AspNet.Identity/SignInManager.cs b/src/Microsoft.AspNet.Identity/SignInManager.cs index 21f655a0f9..e2eab6b672 100644 --- a/src/Microsoft.AspNet.Identity/SignInManager.cs +++ b/src/Microsoft.AspNet.Identity/SignInManager.cs @@ -10,6 +10,8 @@ using Microsoft.AspNet.Http; using Microsoft.AspNet.Http.Security; using Microsoft.Framework.DependencyInjection; using Microsoft.Framework.OptionsModel; +using System.Collections.Generic; +using System.Linq; namespace Microsoft.AspNet.Identity { @@ -74,8 +76,6 @@ namespace Microsoft.AspNet.Identity CancellationToken cancellationToken = default(CancellationToken)) { var userIdentity = await CreateUserIdentityAsync(user); - // Should always clear any external login cookies when signing in for real - Context.Response.SignOut(Options.ExternalCookie.AuthenticationType); if (authenticationMethod != null) { userIdentity.AddClaim(new Claim(ClaimTypes.AuthenticationMethod, authenticationMethod)); @@ -86,7 +86,7 @@ namespace Microsoft.AspNet.Identity // TODO: Should this be async? public virtual void SignOut() { - Context.Response.SignOut(Options.ApplicationCookie.AuthenticationType); + Context.Response.SignOut(IdentityOptions.ApplicationCookieAuthenticationType); } private async Task IsLockedOut(TUser user, CancellationToken token) @@ -151,7 +151,7 @@ namespace Microsoft.AspNet.Identity { return null; } - var identity = new ClaimsIdentity(ClaimsIdentityOptions.DefaultTwoFactorUserIdAuthenticationType); + var identity = new ClaimsIdentity(IdentityOptions.TwoFactorUserIdCookieAuthenticationType); identity.AddClaim(new Claim(ClaimTypes.Name, info.UserId)); if (info.LoginProvider != null) { @@ -185,7 +185,7 @@ namespace Microsoft.AspNet.Identity { var userId = await UserManager.GetUserIdAsync(user, cancellationToken); var result = - await Context.AuthenticateAsync(Options.TwoFactorRememberMeCookie.AuthenticationType); + await Context.AuthenticateAsync(IdentityOptions.TwoFactorRememberMeCookieAuthenticationType); return (result != null && result.Identity != null && result.Identity.Name == userId); } @@ -193,14 +193,14 @@ namespace Microsoft.AspNet.Identity CancellationToken cancellationToken = default(CancellationToken)) { var userId = await UserManager.GetUserIdAsync(user, cancellationToken); - var rememberBrowserIdentity = new ClaimsIdentity(ClaimsIdentityOptions.DefaultTwoFactorRememberMeAuthenticationType); + var rememberBrowserIdentity = new ClaimsIdentity(IdentityOptions.TwoFactorRememberMeCookieAuthenticationType); rememberBrowserIdentity.AddClaim(new Claim(ClaimTypes.Name, userId)); Context.Response.SignIn(new AuthenticationProperties { IsPersistent = true }, rememberBrowserIdentity); } public virtual Task ForgetTwoFactorClientAsync() { - Context.Response.SignOut(Options.TwoFactorRememberMeCookie.AuthenticationType); + Context.Response.SignOut(IdentityOptions.TwoFactorRememberMeCookieAuthenticationType); return Task.FromResult(0); } @@ -225,6 +225,11 @@ namespace Microsoft.AspNet.Identity { // When token is verified correctly, clear the access failed count used for lockout await UserManager.ResetAccessFailedCountAsync(user, cancellationToken); + // Cleanup external cookie + if (twoFactorInfo.LoginProvider != null) + { + Context.Response.SignOut(IdentityOptions.ExternalCookieAuthenticationType); + } await SignInAsync(user, isPersistent, twoFactorInfo.LoginProvider, cancellationToken); if (rememberClient) { @@ -254,7 +259,7 @@ namespace Microsoft.AspNet.Identity return await UserManager.FindByIdAsync(info.UserId, cancellationToken); } - public async Task ExternalLoginSignInAsync(string loginProvider, string providerKey, bool isPersistent, + public virtual async Task ExternalLoginSignInAsync(string loginProvider, string providerKey, bool isPersistent, CancellationToken cancellationToken = default(CancellationToken)) { var user = await UserManager.FindByLoginAsync(loginProvider, providerKey, cancellationToken); @@ -269,6 +274,56 @@ namespace Microsoft.AspNet.Identity return await SignInOrTwoFactorAsync(user, isPersistent, cancellationToken, loginProvider); } + private const string LoginProviderKey = "LoginProvider"; + private const string XsrfKey = "XsrfId"; + + public virtual IEnumerable GetExternalAuthenticationTypes() + { + return Context.GetAuthenticationTypes().Where(d => !string.IsNullOrEmpty(d.Caption)); + } + + public virtual async Task GetExternalLoginInfoAsync(string expectedXsrf = null, + CancellationToken cancellationToken = default(CancellationToken)) + { + var auth = await Context.AuthenticateAsync(IdentityOptions.ExternalCookieAuthenticationType); + if (auth == null || auth.Identity == null || auth.Properties.Dictionary == null || !auth.Properties.Dictionary.ContainsKey(LoginProviderKey)) + { + return null; + } + + if (expectedXsrf != null) + { + if (!auth.Properties.Dictionary.ContainsKey(XsrfKey)) + { + return null; + } + var userId = auth.Properties.Dictionary[XsrfKey] as string; + if (userId != expectedXsrf) + { + return null; + } + } + + var providerKey = auth.Identity.FindFirstValue(ClaimTypes.NameIdentifier); + var provider = auth.Properties.Dictionary[LoginProviderKey] as string; + if (providerKey == null || provider == null) + { + return null; + } + return new ExternalLoginInfo(auth.Identity, provider, providerKey, auth.Description.Caption); + } + + public AuthenticationProperties ConfigureExternalAuthenticationProperties(string provider, string redirectUrl, string userId = null) + { + var properties = new AuthenticationProperties { RedirectUri = redirectUrl }; + properties.Dictionary[LoginProviderKey] = provider; + if (userId != null) + { + properties.Dictionary[XsrfKey] = userId; + } + return properties; + } + private async Task SignInOrTwoFactorAsync(TUser user, bool isPersistent, CancellationToken cancellationToken, string loginProvider = null) { @@ -284,13 +339,18 @@ namespace Microsoft.AspNet.Identity return SignInStatus.RequiresVerification; } } + // Cleanup external cookie + if (loginProvider != null) + { + Context.Response.SignOut(IdentityOptions.ExternalCookieAuthenticationType); + } await SignInAsync(user, isPersistent, loginProvider, cancellationToken); return SignInStatus.Success; } private async Task RetrieveTwoFactorInfoAsync(CancellationToken cancellationToken) { - var result = await Context.AuthenticateAsync(ClaimsIdentityOptions.DefaultTwoFactorUserIdAuthenticationType); + var result = await Context.AuthenticateAsync(IdentityOptions.TwoFactorUserIdCookieAuthenticationType); if (result != null && result.Identity != null) { return new TwoFactorAuthenticationInfo @@ -304,7 +364,7 @@ namespace Microsoft.AspNet.Identity internal static ClaimsIdentity StoreTwoFactorInfo(string userId, string loginProvider) { - var identity = new ClaimsIdentity(ClaimsIdentityOptions.DefaultTwoFactorUserIdAuthenticationType); + var identity = new ClaimsIdentity(IdentityOptions.TwoFactorUserIdCookieAuthenticationType); identity.AddClaim(new Claim(ClaimTypes.Name, userId)); if (loginProvider != null) { diff --git a/test/Microsoft.AspNet.Identity.InMemory.Test/HttpSignInTest.cs b/test/Microsoft.AspNet.Identity.InMemory.Test/HttpSignInTest.cs index 0e18d83eed..613da6d648 100644 --- a/test/Microsoft.AspNet.Identity.InMemory.Test/HttpSignInTest.cs +++ b/test/Microsoft.AspNet.Identity.InMemory.Test/HttpSignInTest.cs @@ -19,17 +19,20 @@ namespace Microsoft.AspNet.Identity.InMemory.Test public class HttpSignInTest { -#if ASPNET50 [Theory] [InlineData(true)] [InlineData(false)] public async Task VerifyAccountControllerSignIn(bool isPersistent) { var app = new ApplicationBuilder(new ServiceCollection().BuildServiceProvider()); - app.UseCookieAuthentication(new CookieAuthenticationOptions - { - AuthenticationType = ClaimsIdentityOptions.DefaultAuthenticationType - }); + //app.UseServices(services => + //{ + // services.SetupOptions(options => + // { + // options.AuthenticationType = IdentityOptions.ApplicationCookieAuthenticationType; + // }); + //}); + app.UseCookieAuthentication(); var context = new Mock(); var response = new Mock(); @@ -61,6 +64,5 @@ namespace Microsoft.AspNet.Identity.InMemory.Test response.VerifyAll(); contextAccessor.VerifyAll(); } -#endif } } diff --git a/test/Microsoft.AspNet.Identity.InMemory.Test/InMemoryStoreTest.cs b/test/Microsoft.AspNet.Identity.InMemory.Test/InMemoryStoreTest.cs index d72a7cc5ff..7759c4f5d5 100644 --- a/test/Microsoft.AspNet.Identity.InMemory.Test/InMemoryStoreTest.cs +++ b/test/Microsoft.AspNet.Identity.InMemory.Test/InMemoryStoreTest.cs @@ -21,7 +21,7 @@ namespace Microsoft.AspNet.Identity.InMemory.Test var services = new ServiceCollection(); services.Add(OptionsServices.GetDefaultServices()); services.AddIdentity().AddInMemory(); - services.SetupOptions(options => + services.ConfigureIdentity(options => { options.Password.RequireDigit = false; options.Password.RequireLowercase = false; diff --git a/test/Microsoft.AspNet.Identity.SqlServer.InMemory.Test/InMemoryEFUserStoreTest.cs b/test/Microsoft.AspNet.Identity.SqlServer.InMemory.Test/InMemoryEFUserStoreTest.cs index ef93470e05..cd7d1f1ce5 100644 --- a/test/Microsoft.AspNet.Identity.SqlServer.InMemory.Test/InMemoryEFUserStoreTest.cs +++ b/test/Microsoft.AspNet.Identity.SqlServer.InMemory.Test/InMemoryEFUserStoreTest.cs @@ -25,7 +25,7 @@ namespace Microsoft.AspNet.Identity.SqlServer.InMemory.Test services.Add(OptionsServices.GetDefaultServices()); services.AddEntityFramework().AddInMemoryStore(); services.AddIdentityInMemory((InMemoryContext)context); - services.SetupOptions(options => + services.ConfigureIdentity(options => { options.Password.RequireDigit = false; options.Password.RequireLowercase = false; diff --git a/test/Microsoft.AspNet.Identity.SqlServer.Test/CustomPocoTest.cs b/test/Microsoft.AspNet.Identity.SqlServer.Test/CustomPocoTest.cs index 4109876bd1..1072cbcc04 100644 --- a/test/Microsoft.AspNet.Identity.SqlServer.Test/CustomPocoTest.cs +++ b/test/Microsoft.AspNet.Identity.SqlServer.Test/CustomPocoTest.cs @@ -52,7 +52,7 @@ namespace Microsoft.AspNet.Identity.SqlServer.Test services.Add(OptionsServices.GetDefaultServices()); services.AddInstance(new NullLoggerFactory()); services.AddEntityFramework().AddSqlServer(); - services.SetupOptions(options => options.UseSqlServer(ConnectionString)); + services.ConfigureOptions(options => options.UseSqlServer(ConnectionString)); var serviceProvider = services.BuildServiceProvider(); return new CustomDbContext(serviceProvider); } diff --git a/test/Microsoft.AspNet.Identity.SqlServer.Test/DefaultPocoTest.cs b/test/Microsoft.AspNet.Identity.SqlServer.Test/DefaultPocoTest.cs index 37a439534b..363d5660d7 100644 --- a/test/Microsoft.AspNet.Identity.SqlServer.Test/DefaultPocoTest.cs +++ b/test/Microsoft.AspNet.Identity.SqlServer.Test/DefaultPocoTest.cs @@ -25,7 +25,7 @@ namespace Microsoft.AspNet.Identity.SqlServer.Test services.Add(OptionsServices.GetDefaultServices()); services.AddInstance(new NullLoggerFactory()); services.AddEntityFramework().AddSqlServer(); - services.SetupOptions(options => options.UseSqlServer(ConnectionString)); + services.ConfigureOptions(options => options.UseSqlServer(ConnectionString)); var serviceProvider = services.BuildServiceProvider(); var db = new IdentityDbContext(serviceProvider, serviceProvider.GetService>().Options); @@ -59,7 +59,7 @@ namespace Microsoft.AspNet.Identity.SqlServer.Test { services.AddEntityFramework().AddSqlServer(); services.AddIdentitySqlServer(); - services.SetupOptions(options => + services.ConfigureOptions(options => options.UseSqlServer(ConnectionString)); // todo: constructor resolution doesn't work well with IdentityDbContext since it has 4 constructors services.AddInstance(context); diff --git a/test/Microsoft.AspNet.Identity.SqlServer.Test/SqlStoreTestBase.cs b/test/Microsoft.AspNet.Identity.SqlServer.Test/SqlStoreTestBase.cs index f6d6d76bb1..d3d2c5cffb 100644 --- a/test/Microsoft.AspNet.Identity.SqlServer.Test/SqlStoreTestBase.cs +++ b/test/Microsoft.AspNet.Identity.SqlServer.Test/SqlStoreTestBase.cs @@ -50,7 +50,7 @@ namespace Microsoft.AspNet.Identity.SqlServer.Test services.AddEntityFramework().AddSqlServer(); services.Add(OptionsServices.GetDefaultServices()); services.AddInstance(new NullLoggerFactory()); - services.SetupOptions(options => + services.ConfigureOptions(options => options.UseSqlServer(ConnectionString)); var serviceProvider = services.BuildServiceProvider(); var db = new ApplicationDbContext(serviceProvider, @@ -64,8 +64,7 @@ namespace Microsoft.AspNet.Identity.SqlServer.Test services.AddEntityFramework().AddSqlServer(); services.Add(OptionsServices.GetDefaultServices()); services.AddInstance(new NullLoggerFactory()); - services.SetupOptions(options => - options.UseSqlServer(ConnectionString)); + services.ConfigureOptions(options => options.UseSqlServer(ConnectionString)); var serviceProvider = services.BuildServiceProvider(); var db = new ApplicationDbContext(serviceProvider, serviceProvider.GetService>()); @@ -118,7 +117,7 @@ namespace Microsoft.AspNet.Identity.SqlServer.Test services.AddInstance(new NullLoggerFactory()); services.AddEntityFramework().AddSqlServer(); services.AddIdentitySqlServer(); - services.SetupOptions(options => + services.ConfigureOptions(options => options.UseSqlServer(ConnectionString)); }); @@ -145,7 +144,8 @@ namespace Microsoft.AspNet.Identity.SqlServer.Test { services.AddInstance(new NullLoggerFactory()); services.AddEntityFramework().AddSqlServer(); - services.AddIdentitySqlServer().SetupOptions(options => + services.AddIdentitySqlServer(); + services.ConfigureIdentity(options => { options.Password.RequiredLength = 1; options.Password.RequireLowercase = false; @@ -154,7 +154,7 @@ namespace Microsoft.AspNet.Identity.SqlServer.Test options.Password.RequireDigit = false; options.User.UserNameValidationRegex = null; }); - services.SetupOptions(options => + services.ConfigureOptions(options => options.UseSqlServer(ConnectionString)); }); diff --git a/test/Microsoft.AspNet.Identity.SqlServer.Test/UserStoreTest.cs b/test/Microsoft.AspNet.Identity.SqlServer.Test/UserStoreTest.cs index 4617950091..77fa6bfdad 100644 --- a/test/Microsoft.AspNet.Identity.SqlServer.Test/UserStoreTest.cs +++ b/test/Microsoft.AspNet.Identity.SqlServer.Test/UserStoreTest.cs @@ -49,7 +49,7 @@ namespace Microsoft.AspNet.Identity.SqlServer.Test services.AddInstance(new NullLoggerFactory()); services.AddEntityFramework().AddSqlServer(); services.Add(OptionsServices.GetDefaultServices()); - services.SetupOptions(options => + services.ConfigureOptions(options => options.UseSqlServer(ConnectionString)); var serviceProvider = services.BuildServiceProvider(); var db = new ApplicationDbContext(serviceProvider, @@ -67,8 +67,8 @@ namespace Microsoft.AspNet.Identity.SqlServer.Test { services.AddInstance(new NullLoggerFactory()); services.AddEntityFramework().AddSqlServer(); - services.AddIdentitySqlServer(); - services.SetupOptions(options => + services.AddDefaultIdentity(); + services.ConfigureOptions(options => options.UseSqlServer(ConnectionString)); }); @@ -95,7 +95,7 @@ namespace Microsoft.AspNet.Identity.SqlServer.Test { services.AddInstance(new NullLoggerFactory()); services.AddEntityFramework().AddSqlServer(); - services.AddIdentitySqlServer().SetupOptions(options => + services.AddIdentitySqlServer(options => { options.Password.RequiredLength = 1; options.Password.RequireLowercase = false; @@ -103,7 +103,7 @@ namespace Microsoft.AspNet.Identity.SqlServer.Test options.Password.RequireUppercase = false; options.Password.RequireDigit = false; }); - services.SetupOptions(options => + services.ConfigureOptions(options => options.UseSqlServer(ConnectionString)); }); diff --git a/test/Microsoft.AspNet.Identity.Test/ClaimsIdentityFactoryTest.cs b/test/Microsoft.AspNet.Identity.Test/ClaimsIdentityFactoryTest.cs index aa2c333e38..ed4ceabc61 100644 --- a/test/Microsoft.AspNet.Identity.Test/ClaimsIdentityFactoryTest.cs +++ b/test/Microsoft.AspNet.Identity.Test/ClaimsIdentityFactoryTest.cs @@ -82,8 +82,7 @@ namespace Microsoft.AspNet.Identity.Test // Assert var manager = userManager.Object; Assert.NotNull(identity); - Assert.Equal(ClaimsIdentityOptions.DefaultAuthenticationType, identity.AuthenticationType); - Assert.Equal(identityOptions.ApplicationCookie.AuthenticationType, identity.AuthenticationType); + Assert.Equal(IdentityOptions.ApplicationCookieAuthenticationType, identity.AuthenticationType); var claims = identity.Claims.ToList(); Assert.NotNull(claims); Assert.True( diff --git a/test/Microsoft.AspNet.Identity.Test/IdentityOptionsTest.cs b/test/Microsoft.AspNet.Identity.Test/IdentityOptionsTest.cs index 2b7fb5030f..9bbbca15fc 100644 --- a/test/Microsoft.AspNet.Identity.Test/IdentityOptionsTest.cs +++ b/test/Microsoft.AspNet.Identity.Test/IdentityOptionsTest.cs @@ -84,14 +84,30 @@ namespace Microsoft.AspNet.Identity.Test Assert.Equal(1000, options.Lockout.MaxFailedAccessAttempts); } - public class PasswordsNegativeLengthSetup : IOptionsSetup + [Fact] + public void IdentityOptionsActionOverridesConfig() { - public int Order { get { return 0; } } - public string Name { get; set; } - public void Setup(IdentityOptions options) + var dic = new Dictionary { - options.Password.RequiredLength = -1; - } + {"identity:user:requireUniqueEmail", "true"}, + {"identity:lockout:MaxFailedAccessAttempts", "1000"} + }; + var config = new Configuration { new MemoryConfigurationSource(dic) }; + var services = new ServiceCollection { OptionsServices.GetDefaultServices() }; + services.AddIdentity(config.GetSubKey("identity"), + o => { o.User.RequireUniqueEmail = false; o.Lockout.MaxFailedAccessAttempts++; }); + var accessor = services.BuildServiceProvider().GetService>(); + Assert.NotNull(accessor); + var options = accessor.Options; + Assert.False(options.User.RequireUniqueEmail); + Assert.Equal(1001, options.Lockout.MaxFailedAccessAttempts); + } + + public class PasswordsNegativeLengthSetup : OptionsAction + { + public PasswordsNegativeLengthSetup() + : base(options => options.Password.RequiredLength = -1) + { } } [Fact] @@ -101,15 +117,13 @@ namespace Microsoft.AspNet.Identity.Test builder.UseServices(services => { services.AddIdentity(); - services.AddSetup(); + services.AddOptionsAction(); }); - var setup = builder.ApplicationServices.GetService>(); + var setup = builder.ApplicationServices.GetService>(); Assert.IsType(typeof(PasswordsNegativeLengthSetup), setup); var optionsGetter = builder.ApplicationServices.GetService>(); Assert.NotNull(optionsGetter); - setup.Setup(optionsGetter.Options); - var myOptions = optionsGetter.Options; Assert.True(myOptions.Password.RequireLowercase); Assert.True(myOptions.Password.RequireDigit); @@ -124,7 +138,7 @@ namespace Microsoft.AspNet.Identity.Test var app = new ApplicationBuilder(new ServiceCollection().BuildServiceProvider()); app.UseServices(services => { - services.AddIdentity().SetupOptions(options => options.User.RequireUniqueEmail = true); + services.AddIdentity().ConfigureIdentity(options => options.User.RequireUniqueEmail = true); }); var optionsGetter = app.ApplicationServices.GetService>(); diff --git a/test/Microsoft.AspNet.Identity.Test/SecurityStampValidatorTest.cs b/test/Microsoft.AspNet.Identity.Test/SecurityStampValidatorTest.cs index fccacb0c3a..ac56c76e9f 100644 --- a/test/Microsoft.AspNet.Identity.Test/SecurityStampValidatorTest.cs +++ b/test/Microsoft.AspNet.Identity.Test/SecurityStampValidatorTest.cs @@ -24,7 +24,7 @@ namespace Microsoft.AspNet.Identity.Test { var httpContext = new Mock(); httpContext.Setup(c => c.RequestServices).Returns(new ServiceCollection().BuildServiceProvider()); - var id = new ClaimsIdentity(ClaimsIdentityOptions.DefaultAuthenticationType); + var id = new ClaimsIdentity(IdentityOptions.ApplicationCookieAuthenticationType); var ticket = new AuthenticationTicket(id, new AuthenticationProperties { IssuedUtc = DateTimeOffset.UtcNow }); var context = new CookieValidateIdentityContext(httpContext.Object, ticket, new CookieAuthenticationOptions()); await Assert.ThrowsAsync(() => SecurityStampValidator.ValidateIdentityAsync(context)); @@ -53,7 +53,7 @@ namespace Microsoft.AspNet.Identity.Test services.AddInstance(signInManager.Object); services.AddInstance(new SecurityStampValidator()); httpContext.Setup(c => c.RequestServices).Returns(services.BuildServiceProvider()); - var id = new ClaimsIdentity(ClaimsIdentityOptions.DefaultAuthenticationType); + var id = new ClaimsIdentity(IdentityOptions.ApplicationCookieAuthenticationType); id.AddClaim(new Claim(ClaimTypes.NameIdentifier, user.Id)); var ticket = new AuthenticationTicket(id, new AuthenticationProperties { IssuedUtc = DateTimeOffset.UtcNow, IsPersistent = isPersistent }); @@ -87,7 +87,7 @@ namespace Microsoft.AspNet.Identity.Test services.AddInstance(signInManager.Object); services.AddInstance(new SecurityStampValidator()); httpContext.Setup(c => c.RequestServices).Returns(services.BuildServiceProvider()); - var id = new ClaimsIdentity(ClaimsIdentityOptions.DefaultAuthenticationType); + var id = new ClaimsIdentity(IdentityOptions.ApplicationCookieAuthenticationType); id.AddClaim(new Claim(ClaimTypes.NameIdentifier, user.Id)); var ticket = new AuthenticationTicket(id, new AuthenticationProperties { IssuedUtc = DateTimeOffset.UtcNow }); @@ -121,7 +121,7 @@ namespace Microsoft.AspNet.Identity.Test services.AddInstance(signInManager.Object); services.AddInstance(new SecurityStampValidator()); httpContext.Setup(c => c.RequestServices).Returns(services.BuildServiceProvider()); - var id = new ClaimsIdentity(ClaimsIdentityOptions.DefaultAuthenticationType); + var id = new ClaimsIdentity(IdentityOptions.ApplicationCookieAuthenticationType); id.AddClaim(new Claim(ClaimTypes.NameIdentifier, user.Id)); var ticket = new AuthenticationTicket(id, new AuthenticationProperties()); @@ -156,7 +156,7 @@ namespace Microsoft.AspNet.Identity.Test services.AddInstance(signInManager.Object); services.AddInstance(new SecurityStampValidator()); httpContext.Setup(c => c.RequestServices).Returns(services.BuildServiceProvider()); - var id = new ClaimsIdentity(ClaimsIdentityOptions.DefaultAuthenticationType); + var id = new ClaimsIdentity(IdentityOptions.ApplicationCookieAuthenticationType); id.AddClaim(new Claim(ClaimTypes.NameIdentifier, user.Id)); var ticket = new AuthenticationTicket(id, new AuthenticationProperties { IssuedUtc = DateTimeOffset.UtcNow }); diff --git a/test/Microsoft.AspNet.Identity.Test/SignInManagerTest.cs b/test/Microsoft.AspNet.Identity.Test/SignInManagerTest.cs index 17275cae00..798235da57 100644 --- a/test/Microsoft.AspNet.Identity.Test/SignInManagerTest.cs +++ b/test/Microsoft.AspNet.Identity.Test/SignInManagerTest.cs @@ -280,7 +280,7 @@ namespace Microsoft.AspNet.Identity.Test contextAccessor.Setup(a => a.Value).Returns(context.Object); var roleManager = MockHelpers.MockRoleManager(); var identityOptions = new IdentityOptions(); - response.Setup(r => r.SignOut(identityOptions.ExternalCookie.AuthenticationType)).Verifiable(); + response.Setup(r => r.SignOut(IdentityOptions.ExternalCookieAuthenticationType)).Verifiable(); var options = new Mock>(); options.Setup(a => a.Options).Returns(identityOptions); var claimsFactory = new Mock>(manager.Object, roleManager.Object, options.Object); @@ -351,6 +351,7 @@ namespace Microsoft.AspNet.Identity.Test It.Is(v => v.IsPersistent == isPersistent), It.Is(i => i.FindFirstValue(ClaimTypes.NameIdentifier) == user.Id && i.FindFirstValue(ClaimTypes.AuthenticationMethod) == loginProvider))).Verifiable(); + response.Setup(r => r.SignOut(IdentityOptions.ExternalCookieAuthenticationType)).Verifiable(); } else { @@ -363,11 +364,10 @@ namespace Microsoft.AspNet.Identity.Test response.Setup(r => r.SignIn( It.Is(v => v.IsPersistent == true), It.Is(i => i.FindFirstValue(ClaimTypes.Name) == user.Id - && i.AuthenticationType == ClaimsIdentityOptions.DefaultTwoFactorRememberMeAuthenticationType))).Verifiable(); + && i.AuthenticationType == IdentityOptions.TwoFactorRememberMeCookieAuthenticationType))).Verifiable(); } - response.Setup(r => r.SignOut(identityOptions.ExternalCookie.AuthenticationType)).Verifiable(); context.Setup(c => c.Response).Returns(response.Object).Verifiable(); - context.Setup(c => c.AuthenticateAsync(ClaimsIdentityOptions.DefaultTwoFactorUserIdAuthenticationType)).ReturnsAsync(authResult).Verifiable(); + context.Setup(c => c.AuthenticateAsync(IdentityOptions.TwoFactorUserIdCookieAuthenticationType)).ReturnsAsync(authResult).Verifiable(); contextAccessor.Setup(a => a.Value).Returns(context.Object); var helper = new SignInManager(manager.Object, contextAccessor.Object, claimsFactory, options.Object); @@ -402,7 +402,7 @@ namespace Microsoft.AspNet.Identity.Test response.Setup(r => r.SignIn( It.Is(v => v.IsPersistent == true), It.Is(i => i.FindFirstValue(ClaimTypes.Name) == user.Id - && i.AuthenticationType == ClaimsIdentityOptions.DefaultTwoFactorRememberMeAuthenticationType))).Verifiable(); + && i.AuthenticationType == IdentityOptions.TwoFactorRememberMeCookieAuthenticationType))).Verifiable(); contextAccessor.Setup(a => a.Value).Returns(context.Object).Verifiable(); options.Setup(a => a.Options).Returns(identityOptions).Verifiable(); @@ -440,20 +440,19 @@ namespace Microsoft.AspNet.Identity.Test var context = new Mock(); var response = new Mock(); context.Setup(c => c.Response).Returns(response.Object).Verifiable(); - response.Setup(r => r.SignIn(It.Is(v => v.IsPersistent == isPersistent), It.Is(i => i.AuthenticationType == ClaimsIdentityOptions.DefaultAuthenticationType))).Verifiable(); - var id = new ClaimsIdentity(ClaimsIdentityOptions.DefaultTwoFactorRememberMeAuthenticationType); + response.Setup(r => r.SignIn(It.Is(v => v.IsPersistent == isPersistent), It.Is(i => i.AuthenticationType == IdentityOptions.ApplicationCookieAuthenticationType))).Verifiable(); + var id = new ClaimsIdentity(IdentityOptions.TwoFactorRememberMeCookieAuthenticationType); id.AddClaim(new Claim(ClaimTypes.Name, user.Id)); var authResult = new AuthenticationResult(id, new AuthenticationProperties(), new AuthenticationDescription()); - context.Setup(c => c.AuthenticateAsync(ClaimsIdentityOptions.DefaultTwoFactorRememberMeAuthenticationType)).ReturnsAsync(authResult).Verifiable(); + context.Setup(c => c.AuthenticateAsync(IdentityOptions.TwoFactorRememberMeCookieAuthenticationType)).ReturnsAsync(authResult).Verifiable(); var contextAccessor = new Mock>(); contextAccessor.Setup(a => a.Value).Returns(context.Object); var roleManager = MockHelpers.MockRoleManager(); var identityOptions = new IdentityOptions(); - response.Setup(r => r.SignOut(identityOptions.ExternalCookie.AuthenticationType)).Verifiable(); var options = new Mock>(); options.Setup(a => a.Options).Returns(identityOptions); var claimsFactory = new Mock>(manager.Object, roleManager.Object, options.Object); - claimsFactory.Setup(m => m.CreateAsync(user, CancellationToken.None)).ReturnsAsync(new ClaimsIdentity(identityOptions.ApplicationCookie.AuthenticationType)).Verifiable(); + claimsFactory.Setup(m => m.CreateAsync(user, CancellationToken.None)).ReturnsAsync(new ClaimsIdentity(IdentityOptions.ApplicationCookieAuthenticationType)).Verifiable(); var helper = new SignInManager(manager.Object, contextAccessor.Object, claimsFactory.Object, options.Object); // Act @@ -485,7 +484,7 @@ namespace Microsoft.AspNet.Identity.Test var identityOptions = new IdentityOptions(); var options = new Mock>(); options.Setup(a => a.Options).Returns(identityOptions); - identityOptions.ApplicationCookie.AuthenticationType = authenticationType; + IdentityOptions.ApplicationCookieAuthenticationType = authenticationType; var claimsFactory = new Mock>(manager.Object, roleManager.Object, options.Object); var helper = new SignInManager(manager.Object, contextAccessor.Object, claimsFactory.Object, options.Object); diff --git a/test/Shared/MockHelpers.cs b/test/Shared/MockHelpers.cs index 89825915c3..3601bbad0e 100644 --- a/test/Shared/MockHelpers.cs +++ b/test/Shared/MockHelpers.cs @@ -8,6 +8,7 @@ using Microsoft.Framework.DependencyInjection.Fallback; using Microsoft.Framework.OptionsModel; using Moq; using System; +using System.Collections.Generic; namespace Microsoft.AspNet.Identity.Test { @@ -18,7 +19,7 @@ namespace Microsoft.AspNet.Identity.Test var services = new ServiceCollection(); services.Add(OptionsServices.GetDefaultServices()); services.AddIdentity().AddUserStore(store); - services.SetupOptions(options => + services.ConfigureIdentity(options => { options.Password.RequireDigit = false; options.Password.RequireLowercase = false; @@ -40,7 +41,7 @@ namespace Microsoft.AspNet.Identity.Test new UserValidator(), new PasswordValidator(), new UpperInvariantUserNameNormalizer(), - null); + new List>()); } public static Mock> MockRoleManager() where TRole : class