diff --git a/samples/IdentitySample.Mvc/Models/SampleData.cs b/samples/IdentitySample.Mvc/Models/SampleData.cs index a1c8e624c8..929785a2f5 100644 --- a/samples/IdentitySample.Mvc/Models/SampleData.cs +++ b/samples/IdentitySample.Mvc/Models/SampleData.cs @@ -29,7 +29,7 @@ namespace IdentitySample.Models /// private static async Task CreateAdminUser(IServiceProvider serviceProvider) { - var options = serviceProvider.GetRequiredService>().Options; + var options = serviceProvider.GetRequiredService>().Value; const string adminRole = "Administrator"; var userManager = serviceProvider.GetRequiredService>(); diff --git a/src/Microsoft.AspNet.Identity/BuilderExtensions.cs b/src/Microsoft.AspNet.Identity/BuilderExtensions.cs index 2f5159da32..a37afaafe4 100644 --- a/src/Microsoft.AspNet.Identity/BuilderExtensions.cs +++ b/src/Microsoft.AspNet.Identity/BuilderExtensions.cs @@ -5,6 +5,7 @@ using System; using Microsoft.AspNet.Identity; using Microsoft.Framework.DependencyInjection; +using Microsoft.Framework.OptionsModel; namespace Microsoft.AspNet.Builder { @@ -31,10 +32,11 @@ namespace Microsoft.AspNet.Builder throw new InvalidOperationException(Resources.MustCallAddIdentity); } - app.UseCookieAuthentication(null, IdentityOptions.ExternalCookieAuthenticationScheme); - app.UseCookieAuthentication(null, IdentityOptions.TwoFactorRememberMeCookieAuthenticationScheme); - app.UseCookieAuthentication(null, IdentityOptions.TwoFactorUserIdCookieAuthenticationScheme); - app.UseCookieAuthentication(null, IdentityOptions.ApplicationCookieAuthenticationScheme); + var options = app.ApplicationServices.GetRequiredService>().Value; + app.UseCookieAuthentication(options.Cookies.ExternalCookie); + app.UseCookieAuthentication(options.Cookies.TwoFactorRememberMeCookie); + app.UseCookieAuthentication(options.Cookies.TwoFactorUserIdCookie); + app.UseCookieAuthentication(options.Cookies.ApplicationCookie); return app; } } diff --git a/src/Microsoft.AspNet.Identity/DataProtectionTokenProvider.cs b/src/Microsoft.AspNet.Identity/DataProtectionTokenProvider.cs index 90b7821565..1d5ad76ecb 100644 --- a/src/Microsoft.AspNet.Identity/DataProtectionTokenProvider.cs +++ b/src/Microsoft.AspNet.Identity/DataProtectionTokenProvider.cs @@ -28,7 +28,7 @@ namespace Microsoft.AspNet.Identity { throw new ArgumentNullException(nameof(dataProtectionProvider)); } - Options = options?.Options ?? new DataProtectionTokenProviderOptions(); + Options = options?.Value ?? new DataProtectionTokenProviderOptions(); // Use the Name as the purpose which should usually be distinct from others Protector = dataProtectionProvider.CreateProtector(Name ?? "DataProtectorTokenProvider"); } diff --git a/src/Microsoft.AspNet.Identity/EmailTokenProvider.cs b/src/Microsoft.AspNet.Identity/EmailTokenProvider.cs index 31d91de53a..6ab61a2a25 100644 --- a/src/Microsoft.AspNet.Identity/EmailTokenProvider.cs +++ b/src/Microsoft.AspNet.Identity/EmailTokenProvider.cs @@ -1,23 +1,7 @@ -using System; using System.Threading.Tasks; -using Microsoft.Framework.OptionsModel; namespace Microsoft.AspNet.Identity { - /// - /// Options for the class. - /// - public class EmailTokenProviderOptions - { - /// - /// Gets or sets the unique name used for an instance of . - /// - /// - /// The unique name used for an instance of . - /// - public string Name { get; set; } = "Email"; - } - /// /// TokenProvider that generates tokens from the user's security stamp and notifies a user via email. /// @@ -25,36 +9,6 @@ namespace Microsoft.AspNet.Identity public class EmailTokenProvider : TotpSecurityStampBasedTokenProvider where TUser : class { - /// - /// Initializes a new instance of the class. - /// - /// The configured . - /// The unique name for this instance of . - public EmailTokenProvider(IOptions options, string name = "") - { - if (options == null) - { - throw new ArgumentNullException(nameof(options)); - } - Options = options.GetNamedOptions(name); - } - - /// - /// Gets the options for this instance of . - /// - /// - /// The options for this instance of . - /// - public EmailTokenProviderOptions Options { get; private set; } - - /// - /// Gets the unique name for this instance of . - /// - /// - /// The unique name for this instance of . - /// - public override string Name { get { return Options.Name; } } - /// /// Checks if a two factor authentication token can be generated for the specified . /// diff --git a/src/Microsoft.AspNet.Identity/IUserTokenProvider.cs b/src/Microsoft.AspNet.Identity/IUserTokenProvider.cs index ce9ee317be..96d9b5fec4 100644 --- a/src/Microsoft.AspNet.Identity/IUserTokenProvider.cs +++ b/src/Microsoft.AspNet.Identity/IUserTokenProvider.cs @@ -11,12 +11,6 @@ namespace Microsoft.AspNet.Identity /// The type encapsulating a user. public interface IUserTokenProvider where TUser : class { - /// - /// Gets the name of the token provider. - /// - /// The name of the token provider. - string Name { get; } - /// /// Generates a token for the specified and , as an asynchronous operation. /// diff --git a/src/Microsoft.AspNet.Identity/IdentityBuilder.cs b/src/Microsoft.AspNet.Identity/IdentityBuilder.cs index 09d6d2b81b..c1dbafd5f6 100644 --- a/src/Microsoft.AspNet.Identity/IdentityBuilder.cs +++ b/src/Microsoft.AspNet.Identity/IdentityBuilder.cs @@ -121,20 +121,31 @@ namespace Microsoft.AspNet.Identity /// Adds a token provider. /// /// The type of the token provider to add. + /// The name of the provider to add. /// The . - public virtual IdentityBuilder AddTokenProvider() where TProvider : class + public virtual IdentityBuilder AddTokenProvider(string providerName) where TProvider : class { - return AddTokenProvider(typeof(TProvider)); + return AddTokenProvider(providerName, typeof(TProvider)); } /// /// Adds a token provider for the . /// + /// The name of the provider to add. /// The type of the to add. /// The . - public virtual IdentityBuilder AddTokenProvider(Type provider) + public virtual IdentityBuilder AddTokenProvider(string providerName, Type provider) { - return AddScoped(typeof(IUserTokenProvider<>).MakeGenericType(UserType), provider); + if (!typeof(IUserTokenProvider<>).MakeGenericType(UserType).GetTypeInfo().IsAssignableFrom(provider.GetTypeInfo())) + { + throw new InvalidOperationException(Resources.FormatInvalidManagerType(provider.Name, "IUserTokenProvider", UserType.Name)); + } + Services.Configure(options => + { + options.Tokens.ProviderMap[providerName] = new TokenProviderDescriptor(provider); + }); + Services.AddTransient(provider); + return this; } /// @@ -143,14 +154,12 @@ namespace Microsoft.AspNet.Identity /// The . public virtual IdentityBuilder AddDefaultTokenProviders() { - Services.Configure(options => - { - options.Name = Resources.DefaultTokenProvider; - }); - - return AddTokenProvider(typeof(DataProtectorTokenProvider<>).MakeGenericType(UserType)) - .AddTokenProvider(typeof(PhoneNumberTokenProvider<>).MakeGenericType(UserType)) - .AddTokenProvider(typeof(EmailTokenProvider<>).MakeGenericType(UserType)); + var dataProtectionProviderType = typeof(DataProtectorTokenProvider<>).MakeGenericType(UserType); + var phoneNumberProviderType = typeof(PhoneNumberTokenProvider<>).MakeGenericType(UserType); + var emailTokenProviderType = typeof(EmailTokenProvider<>).MakeGenericType(UserType); + return AddTokenProvider(TokenOptions.DefaultProvider, dataProtectionProviderType) + .AddTokenProvider(TokenOptions.DefaultEmailProvider, emailTokenProviderType) + .AddTokenProvider(TokenOptions.DefaultPhoneProvider, phoneNumberProviderType); } /// diff --git a/src/Microsoft.AspNet.Identity/IdentityCookieOptions.cs b/src/Microsoft.AspNet.Identity/IdentityCookieOptions.cs new file mode 100644 index 0000000000..f435203ecb --- /dev/null +++ b/src/Microsoft.AspNet.Identity/IdentityCookieOptions.cs @@ -0,0 +1,86 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using Microsoft.AspNet.Authentication.Cookies; +using Microsoft.AspNet.Http; + +namespace Microsoft.AspNet.Identity +{ + /// + /// Represents all the options you can use to configure the cookies middleware uesd by the identity system. + /// + public class IdentityCookieOptions + { + public IdentityCookieOptions() + { + // Configure all of the cookie middlewares + ApplicationCookie = new CookieAuthenticationOptions + { + AuthenticationScheme = ApplicationCookieAuthenticationScheme, + AutomaticAuthentication = true, + LoginPath = new PathString("/Account/Login"), + Notifications = new CookieAuthenticationNotifications + { + OnValidatePrincipal = SecurityStampValidator.ValidatePrincipalAsync + } + }; + + ExternalCookie = new CookieAuthenticationOptions + { + AuthenticationScheme = ExternalCookieAuthenticationScheme, + CookieName = ExternalCookieAuthenticationScheme, + ExpireTimeSpan = TimeSpan.FromMinutes(5) + }; + + TwoFactorRememberMeCookie = new CookieAuthenticationOptions + { + AuthenticationScheme = TwoFactorRememberMeCookieAuthenticationScheme, + CookieName = TwoFactorRememberMeCookieAuthenticationScheme + }; + + TwoFactorUserIdCookie = new CookieAuthenticationOptions + { + AuthenticationScheme = TwoFactorUserIdCookieAuthenticationScheme, + CookieName = TwoFactorUserIdCookieAuthenticationScheme, + ExpireTimeSpan = TimeSpan.FromMinutes(5) + }; + + } + + public CookieAuthenticationOptions ApplicationCookie { get; set; } + public CookieAuthenticationOptions ExternalCookie { get; set; } + public CookieAuthenticationOptions TwoFactorRememberMeCookie { get; set; } + public CookieAuthenticationOptions TwoFactorUserIdCookie { get; set; } + + /// + /// Gets or sets the scheme used to identify application authentication cookies. + /// + /// The scheme used to identify application authentication cookies. + public string ApplicationCookieAuthenticationScheme { get; set; } = ApplicationCookieAuthenticationType; + + /// + /// Gets or sets the scheme used to identify external authentication cookies. + /// + /// The scheme used to identify external authentication cookies. + public string ExternalCookieAuthenticationScheme { get; set; } = typeof(IdentityCookieOptions).Namespace + ".External.AuthType"; + + /// + /// Gets or sets the scheme used to identify Two Factor authentication cookies for round tripping user identities. + /// + /// The scheme used to identify user identity 2fa authentication cookies. + public string TwoFactorUserIdCookieAuthenticationScheme { get; set; } = typeof(IdentityCookieOptions).Namespace + ".TwoFactorUserId.AuthType"; + + /// + /// Gets or sets the scheme used to identify Two Factor authentication cookies for saving the Remember Me state. + /// + /// The scheme used to identify remember me application authentication cookies. + public string TwoFactorRememberMeCookieAuthenticationScheme { get; set; } = typeof(IdentityCookieOptions).Namespace + ".TwoFactorRemeberMe.AuthType"; + + /// + /// Gets or sets the authentication type used when constructing an from an application cookie. + /// + /// The authentication type used when constructing an from an application cookie. + public static string ApplicationCookieAuthenticationType { get; set; } = typeof(IdentityCookieOptions).Namespace + ".Application.AuthType"; + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNet.Identity/IdentityOptions.cs b/src/Microsoft.AspNet.Identity/IdentityOptions.cs index 932d4e6b1c..24f716c42a 100644 --- a/src/Microsoft.AspNet.Identity/IdentityOptions.cs +++ b/src/Microsoft.AspNet.Identity/IdentityOptions.cs @@ -6,7 +6,7 @@ using System; namespace Microsoft.AspNet.Identity { /// - /// Represents all the options you can used to configure the identity system. + /// Represents all the options you can use to configure the identity system. /// public class IdentityOptions { @@ -50,6 +50,22 @@ namespace Microsoft.AspNet.Identity /// public SignInOptions SignIn { get; set; } = new SignInOptions(); + /// + /// Gets or sets the for the identity system. + /// + /// + /// The for the identity system. + /// + public IdentityCookieOptions Cookies { get; set; } = new IdentityCookieOptions(); + + /// + /// Gets or sets the for the identity system. + /// + /// + /// The for the identity system. + /// + public TokenOptions Tokens { get; set; } = new TokenOptions(); + /// /// Gets or sets the after which security stamps are re-validated. /// @@ -57,78 +73,5 @@ namespace Microsoft.AspNet.Identity /// The after which security stamps are re-validated. /// public TimeSpan SecurityStampValidationInterval { get; set; } = TimeSpan.FromMinutes(30); - - /// - /// Gets or sets the used to generate tokens used in account confirmation emails. - /// - /// - /// The used to generate tokens used in account confirmation emails. - /// - public string EmailConfirmationTokenProvider { get; set; } = Resources.DefaultTokenProvider; - - /// - /// Gets or sets the used to generate tokens used in password reset emails. - /// - /// - /// The used to generate tokens used in password reset emails. - /// - public string PasswordResetTokenProvider { get; set; } = Resources.DefaultTokenProvider; - - /// - /// Gets or sets the used to generate tokens used in email change confirmation emails. - /// - /// - /// The used to generate tokens used in email change confirmation emails. - /// - public string ChangeEmailTokenProvider { get; set; } = Resources.DefaultTokenProvider; - - /// - /// Gets or sets the scheme used to identify application authentication cookies. - /// - /// The scheme used to identify application authentication cookies. - public static string ApplicationCookieAuthenticationScheme { get; set; } = typeof(IdentityOptions).Namespace + ".Application"; - - /// - /// Gets or sets the scheme used to identify external authentication cookies. - /// - /// The scheme used to identify external authentication cookies. - public static string ExternalCookieAuthenticationScheme { get; set; } = typeof(IdentityOptions).Namespace + ".External"; - - /// - /// Gets or sets the scheme used to identify Two Factor authentication cookies for round tripping user identities. - /// - /// The scheme used to identify user identity 2fa authentication cookies. - public static string TwoFactorUserIdCookieAuthenticationScheme { get; set; } = typeof(IdentityOptions).Namespace + ".TwoFactorUserId"; - - /// - /// Gets or sets the scheme used to identify Two Factor authentication cookies for saving the Remember Me state. - /// - /// The scheme used to identify remember me application authentication cookies. - public static string TwoFactorRememberMeCookieAuthenticationScheme { get; set; } = typeof(IdentityOptions).Namespace + ".TwoFactorRememberMe"; - - - /// - /// Gets or sets the authentication type used when constructing an from an application cookie. - /// - /// The authentication type used when constructing an from an application cookie. - public static string ApplicationCookieAuthenticationType { get; set; } = typeof(IdentityOptions).Namespace + ".Application.AuthType"; - - /// - /// Gets or sets the authentication type used when constructing an from an external identity cookie. - /// - /// The authentication type used when constructing an from an external identity cookie. - public static string ExternalCookieAuthenticationType { get; set; } = typeof(IdentityOptions).Namespace + ".External.AuthType"; - - /// - /// Gets or sets the authentication type used when constructing an from an two factor authentication cookie. - /// - /// The authentication type used when constructing an from an two factor authentication cookie. - public static string TwoFactorUserIdCookieAuthenticationType { get; set; } = typeof(IdentityOptions).Namespace + ".TwoFactorUserId.AuthType"; - - /// - /// Gets or sets the authentication type used when constructing an from an two factor remember me authentication cookie. - /// - /// The authentication type used when constructing an from an two factor remember me authentication cookie. - public static string TwoFactorRememberMeCookieAuthenticationType { get; set; } = typeof(IdentityOptions).Namespace + ".TwoFactorRemeberMe.AuthType"; } } \ No newline at end of file diff --git a/src/Microsoft.AspNet.Identity/IdentityServiceCollectionExtensions.cs b/src/Microsoft.AspNet.Identity/IdentityServiceCollectionExtensions.cs index 303144b717..1762e5c11e 100644 --- a/src/Microsoft.AspNet.Identity/IdentityServiceCollectionExtensions.cs +++ b/src/Microsoft.AspNet.Identity/IdentityServiceCollectionExtensions.cs @@ -2,10 +2,8 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using Microsoft.AspNet.Http; -using Microsoft.AspNet.Identity; using Microsoft.AspNet.Authentication; -using Microsoft.AspNet.Authentication.Cookies; +using Microsoft.AspNet.Identity; using Microsoft.Framework.Configuration; using Microsoft.Framework.DependencyInjection.Extensions; @@ -16,39 +14,6 @@ namespace Microsoft.Framework.DependencyInjection /// public static class IdentityServiceCollectionExtensions { - /// - /// Configures a set of for the application - /// - /// The services available in the application. - /// An action to configure the . - /// The instance this method extends. - public static IServiceCollection ConfigureIdentity(this IServiceCollection services, Action setupAction) - { - return services.Configure(setupAction); - } - - /// - /// Configures a set of for the application - /// - /// The services available in the application. - /// The configuration for the . - /// The instance this method extends. - public static IServiceCollection ConfigureIdentity(this IServiceCollection services, IConfiguration config) - { - return services.Configure(config); - } - - /// - /// Configures a set of for the application - /// - /// The services available in the application. - /// An action to configure the . - /// The instance this method extends. - public static IServiceCollection ConfigureIdentityApplicationCookie(this IServiceCollection services, Action setupAction) - { - return services.ConfigureCookieAuthentication(setupAction, IdentityOptions.ApplicationCookieAuthenticationScheme); - } - /// /// Adds the default identity system configuration for the specified User and Role types. /// @@ -99,43 +64,14 @@ namespace Microsoft.Framework.DependencyInjection if (setupAction != null) { - services.ConfigureIdentity(setupAction); + services.Configure(setupAction); } services.Configure(options => { - options.SignInScheme = IdentityOptions.ExternalCookieAuthenticationScheme; + // This is the Default value for ExternalCookieAuthenticationScheme + options.SignInScheme = new IdentityCookieOptions().ExternalCookieAuthenticationScheme; }); - // Configure all of the cookie middlewares - services.ConfigureIdentityApplicationCookie(options => - { - options.AuthenticationScheme = IdentityOptions.ApplicationCookieAuthenticationScheme; - options.AutomaticAuthentication = true; - options.LoginPath = new PathString("/Account/Login"); - options.Notifications = new CookieAuthenticationNotifications - { - OnValidatePrincipal = SecurityStampValidator.ValidatePrincipalAsync - }; - }); - - services.ConfigureCookieAuthentication(options => - { - options.AuthenticationScheme = IdentityOptions.ExternalCookieAuthenticationScheme; - options.CookieName = IdentityOptions.ExternalCookieAuthenticationScheme; - options.ExpireTimeSpan = TimeSpan.FromMinutes(5); - }, IdentityOptions.ExternalCookieAuthenticationScheme); - services.ConfigureCookieAuthentication(options => - { - options.AuthenticationScheme = IdentityOptions.TwoFactorRememberMeCookieAuthenticationScheme; - options.CookieName = IdentityOptions.TwoFactorRememberMeCookieAuthenticationScheme; - }, IdentityOptions.TwoFactorRememberMeCookieAuthenticationScheme); - services.ConfigureCookieAuthentication(options => - { - options.AuthenticationScheme = IdentityOptions.TwoFactorUserIdCookieAuthenticationScheme; - options.CookieName = IdentityOptions.TwoFactorUserIdCookieAuthenticationScheme; - options.ExpireTimeSpan = TimeSpan.FromMinutes(5); - }, IdentityOptions.TwoFactorUserIdCookieAuthenticationScheme); - return new IdentityBuilder(typeof(TUser), typeof(TRole), services); } } diff --git a/src/Microsoft.AspNet.Identity/PasswordHasher.cs b/src/Microsoft.AspNet.Identity/PasswordHasher.cs index 31397802d9..cd53f24bb5 100644 --- a/src/Microsoft.AspNet.Identity/PasswordHasher.cs +++ b/src/Microsoft.AspNet.Identity/PasswordHasher.cs @@ -40,7 +40,7 @@ namespace Microsoft.AspNet.Identity /// The options for this instance. public PasswordHasher(IOptions optionsAccessor = null) { - var options = optionsAccessor?.Options ?? new PasswordHasherOptions(); + var options = optionsAccessor?.Value ?? new PasswordHasherOptions(); _compatibilityMode = options.CompatibilityMode; switch (_compatibilityMode) diff --git a/src/Microsoft.AspNet.Identity/PhoneNumberTokenProvider.cs b/src/Microsoft.AspNet.Identity/PhoneNumberTokenProvider.cs index f90b3a02f3..20436faa54 100644 --- a/src/Microsoft.AspNet.Identity/PhoneNumberTokenProvider.cs +++ b/src/Microsoft.AspNet.Identity/PhoneNumberTokenProvider.cs @@ -1,23 +1,8 @@ using System; using System.Threading.Tasks; -using Microsoft.Framework.OptionsModel; namespace Microsoft.AspNet.Identity { - /// - /// Encapsulations options for a . - /// - public class PhoneNumberTokenProviderOptions - { - /// - /// Gets or sets the name for the . - /// - /// - /// The name for the . - /// - public string Name { get; set; } = "Phone"; - } - /// /// Represents a token provider that generates tokens from a user's security stamp and /// sends them to the user via their phone number. @@ -26,31 +11,6 @@ namespace Microsoft.AspNet.Identity public class PhoneNumberTokenProvider : TotpSecurityStampBasedTokenProvider where TUser : class { - /// - /// Creates a new instance of with the specified . - /// - /// The options to use for the created instance of a . - public PhoneNumberTokenProvider(IOptions options) - { - if (options == null || options.Options == null) - { - throw new ArgumentNullException(nameof(options)); - } - Options = options.Options; - } - - /// - /// Gets the options for this instance of . - /// - /// The options for this instance of . - public PhoneNumberTokenProviderOptions Options { get; private set; } - - /// - /// Gets the name for this instance of . - /// - /// The name for this instance of . - public override string Name { get { return Options.Name; } } - /// /// Returns a flag indicating whether the token provider can generate a token suitable for two factor authentication token for /// the specified . diff --git a/src/Microsoft.AspNet.Identity/PrincipalExtensions.cs b/src/Microsoft.AspNet.Identity/PrincipalExtensions.cs index 73ab8d1537..cf6eb29667 100644 --- a/src/Microsoft.AspNet.Identity/PrincipalExtensions.cs +++ b/src/Microsoft.AspNet.Identity/PrincipalExtensions.cs @@ -53,7 +53,7 @@ namespace System.Security.Claims throw new ArgumentNullException(nameof(principal)); } return principal?.Identities != null && - principal.Identities.Any(i => i.AuthenticationType == IdentityOptions.ApplicationCookieAuthenticationType); + principal.Identities.Any(i => i.AuthenticationType == IdentityCookieOptions.ApplicationCookieAuthenticationType); } /// diff --git a/src/Microsoft.AspNet.Identity/Properties/Resources.Designer.cs b/src/Microsoft.AspNet.Identity/Properties/Resources.Designer.cs index 55c081d61c..094c0fe0f8 100644 --- a/src/Microsoft.AspNet.Identity/Properties/Resources.Designer.cs +++ b/src/Microsoft.AspNet.Identity/Properties/Resources.Designer.cs @@ -42,22 +42,6 @@ namespace Microsoft.AspNet.Identity return GetString("DefaultError"); } - /// - /// Default Token Provider - /// - internal static string DefaultTokenProvider - { - get { return GetString("DefaultTokenProvider"); } - } - - /// - /// Default Token Provider - /// - internal static string FormatDefaultTokenProvider() - { - return GetString("DefaultTokenProvider"); - } - /// /// Email '{0}' is already taken. /// @@ -123,7 +107,7 @@ namespace Microsoft.AspNet.Identity } /// - /// Type {0} must be derived from {1}<{2}>. + /// Type {0} must derive from {1}<{2}>. /// internal static string InvalidManagerType { @@ -131,7 +115,7 @@ namespace Microsoft.AspNet.Identity } /// - /// Type {0} must be derived from {1}<{2}>. + /// Type {0} must derive from {1}<{2}>. /// internal static string FormatInvalidManagerType(object p0, object p1, object p2) { diff --git a/src/Microsoft.AspNet.Identity/Resources.resx b/src/Microsoft.AspNet.Identity/Resources.resx index 87dbde9344..feda1883d2 100644 --- a/src/Microsoft.AspNet.Identity/Resources.resx +++ b/src/Microsoft.AspNet.Identity/Resources.resx @@ -125,10 +125,6 @@ An unknown failure has occured. Default identity result error message - - Default Token Provider - Name of the default token provider - Email '{0}' is already taken. Error for duplicate emails diff --git a/src/Microsoft.AspNet.Identity/SecurityStampValidator.cs b/src/Microsoft.AspNet.Identity/SecurityStampValidator.cs index ba9b6d7ca7..5ec5dca3fc 100644 --- a/src/Microsoft.AspNet.Identity/SecurityStampValidator.cs +++ b/src/Microsoft.AspNet.Identity/SecurityStampValidator.cs @@ -74,7 +74,7 @@ namespace Microsoft.AspNet.Identity { var timeElapsed = currentUtc.Subtract(issuedUtc.Value); var accessor = context.HttpContext.RequestServices.GetRequiredService>(); - validate = timeElapsed > accessor.Options.SecurityStampValidationInterval; + validate = timeElapsed > accessor.Value.SecurityStampValidationInterval; } if (validate) { diff --git a/src/Microsoft.AspNet.Identity/SignInManager.cs b/src/Microsoft.AspNet.Identity/SignInManager.cs index 2f9bee50b7..addbea4195 100644 --- a/src/Microsoft.AspNet.Identity/SignInManager.cs +++ b/src/Microsoft.AspNet.Identity/SignInManager.cs @@ -54,7 +54,7 @@ namespace Microsoft.AspNet.Identity UserManager = userManager; Context = contextAccessor.HttpContext; ClaimsFactory = claimsFactory; - Options = optionsAccessor?.Options ?? new IdentityOptions(); + Options = optionsAccessor?.Value ?? new IdentityOptions(); Logger = logger; } @@ -109,7 +109,7 @@ namespace Microsoft.AspNet.Identity /// The task object representing the asynchronous operation. public virtual async Task RefreshSignInAsync(TUser user) { - var auth = new AuthenticateContext(IdentityOptions.ApplicationCookieAuthenticationScheme); + var auth = new AuthenticateContext(Options.Cookies.ApplicationCookieAuthenticationScheme); await Context.Authentication.AuthenticateAsync(auth); var authenticationMethod = auth.Principal?.FindFirstValue(ClaimTypes.AuthenticationMethod); await SignInAsync(user, new AuthenticationProperties(auth.Properties), authenticationMethod); @@ -142,7 +142,7 @@ namespace Microsoft.AspNet.Identity { userPrincipal.Identities.First().AddClaim(new Claim(ClaimTypes.AuthenticationMethod, authenticationMethod)); } - await Context.Authentication.SignInAsync(IdentityOptions.ApplicationCookieAuthenticationScheme, + await Context.Authentication.SignInAsync(Options.Cookies.ApplicationCookieAuthenticationScheme, userPrincipal, authenticationProperties ?? new AuthenticationProperties()); } @@ -152,9 +152,9 @@ namespace Microsoft.AspNet.Identity /// public virtual async Task SignOutAsync() { - await Context.Authentication.SignOutAsync(IdentityOptions.ApplicationCookieAuthenticationScheme); - await Context.Authentication.SignOutAsync(IdentityOptions.ExternalCookieAuthenticationScheme); - await Context.Authentication.SignOutAsync(IdentityOptions.TwoFactorUserIdCookieAuthenticationScheme); + await Context.Authentication.SignOutAsync(Options.Cookies.ApplicationCookieAuthenticationScheme); + await Context.Authentication.SignOutAsync(Options.Cookies.ExternalCookieAuthenticationScheme); + await Context.Authentication.SignOutAsync(Options.Cookies.TwoFactorUserIdCookieAuthenticationScheme); } /// @@ -260,7 +260,7 @@ namespace Microsoft.AspNet.Identity public virtual async Task IsTwoFactorClientRememberedAsync(TUser user) { var userId = await UserManager.GetUserIdAsync(user); - var result = await Context.Authentication.AuthenticateAsync(IdentityOptions.TwoFactorRememberMeCookieAuthenticationScheme); + var result = await Context.Authentication.AuthenticateAsync(Options.Cookies.TwoFactorRememberMeCookieAuthenticationScheme); return (result != null && result.FindFirstValue(ClaimTypes.Name) == userId); } @@ -273,9 +273,9 @@ namespace Microsoft.AspNet.Identity public virtual async Task RememberTwoFactorClientAsync(TUser user) { var userId = await UserManager.GetUserIdAsync(user); - var rememberBrowserIdentity = new ClaimsIdentity(IdentityOptions.TwoFactorRememberMeCookieAuthenticationType); + var rememberBrowserIdentity = new ClaimsIdentity(Options.Cookies.TwoFactorRememberMeCookieAuthenticationScheme); rememberBrowserIdentity.AddClaim(new Claim(ClaimTypes.Name, userId)); - await Context.Authentication.SignInAsync(IdentityOptions.TwoFactorRememberMeCookieAuthenticationScheme, + await Context.Authentication.SignInAsync(Options.Cookies.TwoFactorRememberMeCookieAuthenticationScheme, new ClaimsPrincipal(rememberBrowserIdentity), new AuthenticationProperties { IsPersistent = true }); } @@ -286,7 +286,7 @@ namespace Microsoft.AspNet.Identity /// The task object representing the asynchronous operation. public virtual Task ForgetTwoFactorClientAsync() { - return Context.Authentication.SignOutAsync(IdentityOptions.TwoFactorRememberMeCookieAuthenticationScheme); + return Context.Authentication.SignOutAsync(Options.Cookies.TwoFactorRememberMeCookieAuthenticationScheme); } /// @@ -325,7 +325,7 @@ namespace Microsoft.AspNet.Identity // Cleanup external cookie if (twoFactorInfo.LoginProvider != null) { - await Context.Authentication.SignOutAsync(IdentityOptions.ExternalCookieAuthenticationScheme); + await Context.Authentication.SignOutAsync(Options.Cookies.ExternalCookieAuthenticationScheme); } if (rememberClient) { @@ -397,7 +397,7 @@ namespace Microsoft.AspNet.Identity /// for the sign-in attempt. public virtual async Task GetExternalLoginInfoAsync(string expectedXsrf = null) { - var auth = new AuthenticateContext(IdentityOptions.ExternalCookieAuthenticationScheme); + var auth = new AuthenticateContext(Options.Cookies.ExternalCookieAuthenticationScheme); await Context.Authentication.AuthenticateAsync(auth); if (auth.Principal == null || auth.Properties == null || !auth.Properties.ContainsKey(LoginProviderKey)) { @@ -451,9 +451,9 @@ namespace Microsoft.AspNet.Identity /// The user whose is logging in via 2fa. /// The 2fa provider. /// A containing the user 2fa information. - internal static ClaimsPrincipal StoreTwoFactorInfo(string userId, string loginProvider) + internal ClaimsPrincipal StoreTwoFactorInfo(string userId, string loginProvider) { - var identity = new ClaimsIdentity(IdentityOptions.TwoFactorUserIdCookieAuthenticationType); + var identity = new ClaimsIdentity(Options.Cookies.TwoFactorUserIdCookieAuthenticationScheme); identity.AddClaim(new Claim(ClaimTypes.Name, userId)); if (loginProvider != null) { @@ -462,13 +462,13 @@ namespace Microsoft.AspNet.Identity return new ClaimsPrincipal(identity); } - private static ClaimsIdentity CreateIdentity(TwoFactorAuthenticationInfo info) + private ClaimsIdentity CreateIdentity(TwoFactorAuthenticationInfo info) { if (info == null) { return null; } - var identity = new ClaimsIdentity(IdentityOptions.TwoFactorUserIdCookieAuthenticationType); + var identity = new ClaimsIdentity(Options.Cookies.TwoFactorUserIdCookieAuthenticationScheme); identity.AddClaim(new Claim(ClaimTypes.Name, info.UserId)); if (info.LoginProvider != null) { @@ -488,14 +488,14 @@ namespace Microsoft.AspNet.Identity { // Store the userId for use after two factor check var userId = await UserManager.GetUserIdAsync(user); - await Context.Authentication.SignInAsync(IdentityOptions.TwoFactorUserIdCookieAuthenticationScheme, StoreTwoFactorInfo(userId, loginProvider)); + await Context.Authentication.SignInAsync(Options.Cookies.TwoFactorUserIdCookieAuthenticationScheme, StoreTwoFactorInfo(userId, loginProvider)); return SignInResult.TwoFactorRequired; } } // Cleanup external cookie if (loginProvider != null) { - await Context.Authentication.SignOutAsync(IdentityOptions.ExternalCookieAuthenticationScheme); + await Context.Authentication.SignOutAsync(Options.Cookies.ExternalCookieAuthenticationScheme); } await SignInAsync(user, isPersistent, loginProvider); return SignInResult.Success; @@ -503,7 +503,7 @@ namespace Microsoft.AspNet.Identity private async Task RetrieveTwoFactorInfoAsync() { - var result = await Context.Authentication.AuthenticateAsync(IdentityOptions.TwoFactorUserIdCookieAuthenticationScheme); + var result = await Context.Authentication.AuthenticateAsync(Options.Cookies.TwoFactorUserIdCookieAuthenticationScheme); if (result != null) { return new TwoFactorAuthenticationInfo diff --git a/src/Microsoft.AspNet.Identity/TokenOptions.cs b/src/Microsoft.AspNet.Identity/TokenOptions.cs new file mode 100644 index 0000000000..4b0c94b9a9 --- /dev/null +++ b/src/Microsoft.AspNet.Identity/TokenOptions.cs @@ -0,0 +1,44 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; + +namespace Microsoft.AspNet.Identity +{ + public class TokenOptions + { + public static readonly string DefaultProvider = "Default"; + public static readonly string DefaultEmailProvider = "Email"; + public static readonly string DefaultPhoneProvider = "Phone"; + + /// + /// Will be used to construct UserTokenProviders with the key used as the providerName. + /// + public Dictionary ProviderMap { get; set; } = new Dictionary(); + + /// + /// Gets or sets the used to generate tokens used in account confirmation emails. + /// + /// + /// The used to generate tokens used in account confirmation emails. + /// + public string EmailConfirmationTokenProvider { get; set; } = DefaultProvider; + + /// + /// Gets or sets the used to generate tokens used in password reset emails. + /// + /// + /// The used to generate tokens used in password reset emails. + /// + public string PasswordResetTokenProvider { get; set; } = DefaultProvider; + + /// + /// Gets or sets the used to generate tokens used in email change confirmation emails. + /// + /// + /// The used to generate tokens used in email change confirmation emails. + /// + public string ChangeEmailTokenProvider { get; set; } = DefaultProvider; + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNet.Identity/TokenProviderDescriptor.cs b/src/Microsoft.AspNet.Identity/TokenProviderDescriptor.cs new file mode 100644 index 0000000000..881b0d4c53 --- /dev/null +++ b/src/Microsoft.AspNet.Identity/TokenProviderDescriptor.cs @@ -0,0 +1,17 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; + +namespace Microsoft.AspNet.Identity +{ + public class TokenProviderDescriptor + { + public TokenProviderDescriptor(Type type) + { + ProviderType = type; + } + + public Type ProviderType { get; } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNet.Identity/TotpSecurityStampBasedTokenProvider.cs b/src/Microsoft.AspNet.Identity/TotpSecurityStampBasedTokenProvider.cs index d77872a449..4c7b5ea3f7 100644 --- a/src/Microsoft.AspNet.Identity/TotpSecurityStampBasedTokenProvider.cs +++ b/src/Microsoft.AspNet.Identity/TotpSecurityStampBasedTokenProvider.cs @@ -12,12 +12,6 @@ namespace Microsoft.AspNet.Identity public abstract class TotpSecurityStampBasedTokenProvider : IUserTokenProvider where TUser : class { - /// - /// Gets the name of the token provider. - /// - /// The name of the token provider. - public abstract string Name { get; } - /// /// Generates a token for the specified and , as an asynchronous operation. /// diff --git a/src/Microsoft.AspNet.Identity/UserClaimsPrincipalFactory.cs b/src/Microsoft.AspNet.Identity/UserClaimsPrincipalFactory.cs index 9f6f3a5a77..5430a94c83 100644 --- a/src/Microsoft.AspNet.Identity/UserClaimsPrincipalFactory.cs +++ b/src/Microsoft.AspNet.Identity/UserClaimsPrincipalFactory.cs @@ -38,13 +38,13 @@ namespace Microsoft.AspNet.Identity { throw new ArgumentNullException(nameof(roleManager)); } - if (optionsAccessor == null || optionsAccessor.Options == null) + if (optionsAccessor == null || optionsAccessor.Value == null) { throw new ArgumentNullException(nameof(optionsAccessor)); } UserManager = userManager; RoleManager = roleManager; - Options = optionsAccessor.Options; + Options = optionsAccessor.Value; } /// @@ -85,7 +85,7 @@ namespace Microsoft.AspNet.Identity } var userId = await UserManager.GetUserIdAsync(user); var userName = await UserManager.GetUserNameAsync(user); - var id = new ClaimsIdentity(IdentityOptions.ApplicationCookieAuthenticationType, + var id = new ClaimsIdentity(Options.Cookies.TwoFactorRememberMeCookieAuthenticationScheme, Options.ClaimsIdentity.UserNameClaimType, Options.ClaimsIdentity.RoleClaimType); id.AddClaim(new Claim(Options.ClaimsIdentity.UserIdClaimType, userId)); diff --git a/src/Microsoft.AspNet.Identity/UserManager.cs b/src/Microsoft.AspNet.Identity/UserManager.cs index a8fcbe9a70..fae4cc5edf 100644 --- a/src/Microsoft.AspNet.Identity/UserManager.cs +++ b/src/Microsoft.AspNet.Identity/UserManager.cs @@ -12,6 +12,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.AspNet.Hosting; using Microsoft.AspNet.Http; +using Microsoft.Framework.DependencyInjection; using Microsoft.Framework.Logging; using Microsoft.Framework.OptionsModel; @@ -51,7 +52,7 @@ namespace Microsoft.AspNet.Identity IEnumerable> passwordValidators, ILookupNormalizer keyNormalizer, IdentityErrorDescriber errors, - IEnumerable> tokenProviders, + IServiceProvider services, ILogger> logger, IHttpContextAccessor contextAccessor) { @@ -60,7 +61,7 @@ namespace Microsoft.AspNet.Identity throw new ArgumentNullException(nameof(store)); } Store = store; - Options = optionsAccessor?.Options ?? new IdentityOptions(); + Options = optionsAccessor?.Value ?? new IdentityOptions(); _context = contextAccessor?.HttpContext; PasswordHasher = passwordHasher; KeyNormalizer = keyNormalizer; @@ -82,11 +83,15 @@ namespace Microsoft.AspNet.Identity } } - if (tokenProviders != null) + if (services != null) { - foreach (var tokenProvider in tokenProviders) + foreach (var providerName in Options.Tokens.ProviderMap.Keys) { - RegisterTokenProvider(tokenProvider); + var provider = services.GetRequiredService(Options.Tokens.ProviderMap[providerName].ProviderType) as IUserTokenProvider; + if (provider != null) + { + RegisterTokenProvider(providerName, provider); + } } } } @@ -715,7 +720,7 @@ namespace Microsoft.AspNet.Identity public virtual Task GeneratePasswordResetTokenAsync(TUser user) { ThrowIfDisposed(); - return GenerateUserTokenAsync(user, Options.PasswordResetTokenProvider, "ResetPassword"); + return GenerateUserTokenAsync(user, Options.Tokens.PasswordResetTokenProvider, "ResetPassword"); } /// @@ -738,7 +743,7 @@ namespace Microsoft.AspNet.Identity } // Make sure the token is valid and the stamp matches - if (!await VerifyUserTokenAsync(user, Options.PasswordResetTokenProvider, "ResetPassword", token)) + if (!await VerifyUserTokenAsync(user, Options.Tokens.PasswordResetTokenProvider, "ResetPassword", token)) { return IdentityResult.Failed(ErrorDescriber.InvalidToken()); } @@ -1260,7 +1265,7 @@ namespace Microsoft.AspNet.Identity public virtual Task GenerateEmailConfirmationTokenAsync(TUser user) { ThrowIfDisposed(); - return GenerateUserTokenAsync(user, Options.EmailConfirmationTokenProvider, "EmailConfirmation"); + return GenerateUserTokenAsync(user, Options.Tokens.EmailConfirmationTokenProvider, "EmailConfirmation"); } /// @@ -1281,7 +1286,7 @@ namespace Microsoft.AspNet.Identity throw new ArgumentNullException("user"); } - if (!await VerifyUserTokenAsync(user, Options.EmailConfirmationTokenProvider, "EmailConfirmation", token)) + if (!await VerifyUserTokenAsync(user, Options.Tokens.EmailConfirmationTokenProvider, "EmailConfirmation", token)) { return IdentityResult.Failed(ErrorDescriber.InvalidToken()); } @@ -1319,7 +1324,7 @@ namespace Microsoft.AspNet.Identity public virtual Task GenerateChangeEmailTokenAsync(TUser user, string newEmail) { ThrowIfDisposed(); - return GenerateUserTokenAsync(user, Options.ChangeEmailTokenProvider, GetChangeEmailPurpose(newEmail)); + return GenerateUserTokenAsync(user, Options.Tokens.ChangeEmailTokenProvider, GetChangeEmailPurpose(newEmail)); } /// @@ -1341,7 +1346,7 @@ namespace Microsoft.AspNet.Identity } // Make sure the token is valid and the stamp matches - if (!await VerifyUserTokenAsync(user, Options.ChangeEmailTokenProvider, GetChangeEmailPurpose(newEmail), token)) + if (!await VerifyUserTokenAsync(user, Options.Tokens.ChangeEmailTokenProvider, GetChangeEmailPurpose(newEmail), token)) { return IdentityResult.Failed(ErrorDescriber.InvalidToken()); } @@ -1556,15 +1561,16 @@ namespace Microsoft.AspNet.Identity /// /// Registers a token provider. /// + /// The name of the provider to register. /// The provider to register. - public virtual void RegisterTokenProvider(IUserTokenProvider provider) + public virtual void RegisterTokenProvider(string providerName, IUserTokenProvider provider) { ThrowIfDisposed(); if (provider == null) { throw new ArgumentNullException("provider"); } - _tokenProviders[provider.Name] = provider; + _tokenProviders[providerName] = provider; } /// diff --git a/src/Microsoft.AspNet.Identity/UserOptions.cs b/src/Microsoft.AspNet.Identity/UserOptions.cs index 8be8db924f..df1ea2aeaa 100644 --- a/src/Microsoft.AspNet.Identity/UserOptions.cs +++ b/src/Microsoft.AspNet.Identity/UserOptions.cs @@ -1,8 +1,6 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -using System; - namespace Microsoft.AspNet.Identity { /// diff --git a/test/Microsoft.AspNet.Identity.EntityFramework.InMemory.Test/Microsoft.AspNet.Identity.EntityFramework.InMemory.Test.xproj b/test/Microsoft.AspNet.Identity.EntityFramework.InMemory.Test/Microsoft.AspNet.Identity.EntityFramework.InMemory.Test.xproj index 3914283809..e469aa1435 100644 --- a/test/Microsoft.AspNet.Identity.EntityFramework.InMemory.Test/Microsoft.AspNet.Identity.EntityFramework.InMemory.Test.xproj +++ b/test/Microsoft.AspNet.Identity.EntityFramework.InMemory.Test/Microsoft.AspNet.Identity.EntityFramework.InMemory.Test.xproj @@ -13,5 +13,8 @@ 2.0 + + + \ No newline at end of file diff --git a/test/Microsoft.AspNet.Identity.InMemory.Test/FunctionalTest.cs b/test/Microsoft.AspNet.Identity.InMemory.Test/FunctionalTest.cs index 58ab902a35..2ab22326c3 100644 --- a/test/Microsoft.AspNet.Identity.InMemory.Test/FunctionalTest.cs +++ b/test/Microsoft.AspNet.Identity.InMemory.Test/FunctionalTest.cs @@ -37,7 +37,7 @@ namespace Microsoft.AspNet.Identity.InMemory public async Task CanChangePasswordOptions() { var clock = new TestClock(); - var server = CreateServer(services => services.ConfigureIdentity(options => + var server = CreateServer(services => services.Configure(options => { options.Password.RequireUppercase = false; options.Password.RequireNonLetterOrDigit = false; @@ -53,11 +53,11 @@ namespace Microsoft.AspNet.Identity.InMemory public async Task CanCreateMeLoginAndCookieStopsWorkingAfterExpiration() { var clock = new TestClock(); - var server = CreateServer(services => services.ConfigureIdentityApplicationCookie(appCookieOptions => + var server = CreateServer(services => services.Configure(options => { - appCookieOptions.SystemClock = clock; - appCookieOptions.ExpireTimeSpan = TimeSpan.FromMinutes(10); - appCookieOptions.SlidingExpiration = false; + options.Cookies.ApplicationCookie.SystemClock = clock; + options.Cookies.ApplicationCookie.ExpireTimeSpan = TimeSpan.FromMinutes(10); + options.Cookies.ApplicationCookie.SlidingExpiration = false; })); var transaction1 = await SendAsync(server, "http://example.com/createMe"); @@ -92,9 +92,9 @@ namespace Microsoft.AspNet.Identity.InMemory public async Task CanCreateMeLoginAndSecurityStampExtendsExpiration(bool rememberMe) { var clock = new TestClock(); - var server = CreateServer(services => services.ConfigureIdentityApplicationCookie(appCookieOptions => + var server = CreateServer(services => services.Configure(options => { - appCookieOptions.SystemClock = clock; + options.Cookies.ApplicationCookie.SystemClock = clock; })); var transaction1 = await SendAsync(server, "http://example.com/createMe"); @@ -148,7 +148,7 @@ namespace Microsoft.AspNet.Identity.InMemory transaction2.Response.StatusCode.ShouldBe(HttpStatusCode.OK); string setCookie = transaction2.SetCookie; - setCookie.ShouldContain(IdentityOptions.TwoFactorRememberMeCookieAuthenticationScheme + "="); + setCookie.ShouldContain(new IdentityCookieOptions().TwoFactorRememberMeCookieAuthenticationScheme + "="); setCookie.ShouldContain("; expires="); var transaction3 = await SendAsync(server, "http://example.com/isTwoFactorRememebered", transaction2.CookieNameValue); diff --git a/test/Microsoft.AspNet.Identity.InMemory.Test/HttpSignInTest.cs b/test/Microsoft.AspNet.Identity.InMemory.Test/HttpSignInTest.cs index 94844ebc93..433998ae6d 100644 --- a/test/Microsoft.AspNet.Identity.InMemory.Test/HttpSignInTest.cs +++ b/test/Microsoft.AspNet.Identity.InMemory.Test/HttpSignInTest.cs @@ -30,7 +30,7 @@ namespace Microsoft.AspNet.Identity.InMemory.Test var context = new Mock(); var auth = new Mock(); context.Setup(c => c.Authentication).Returns(auth.Object).Verifiable(); - auth.Setup(a => a.SignInAsync(IdentityOptions.ApplicationCookieAuthenticationScheme, + auth.Setup(a => a.SignInAsync(new IdentityCookieOptions().ApplicationCookieAuthenticationScheme, It.IsAny(), It.IsAny())).Returns(Task.FromResult(0)).Verifiable(); // REVIEW: is persistant mocking broken diff --git a/test/Microsoft.AspNet.Identity.InMemory.Test/Microsoft.AspNet.Identity.InMemory.Test.xproj b/test/Microsoft.AspNet.Identity.InMemory.Test/Microsoft.AspNet.Identity.InMemory.Test.xproj index 2d1b8e9294..7b09944843 100644 --- a/test/Microsoft.AspNet.Identity.InMemory.Test/Microsoft.AspNet.Identity.InMemory.Test.xproj +++ b/test/Microsoft.AspNet.Identity.InMemory.Test/Microsoft.AspNet.Identity.InMemory.Test.xproj @@ -13,5 +13,8 @@ 2.0 + + + \ No newline at end of file diff --git a/test/Microsoft.AspNet.Identity.Test/IdentityBuilderTest.cs b/test/Microsoft.AspNet.Identity.Test/IdentityBuilderTest.cs index 7724233c86..29394fc696 100644 --- a/test/Microsoft.AspNet.Identity.Test/IdentityBuilderTest.cs +++ b/test/Microsoft.AspNet.Identity.Test/IdentityBuilderTest.cs @@ -7,6 +7,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using Microsoft.Framework.DependencyInjection; +using Microsoft.Framework.OptionsModel; using Xunit; namespace Microsoft.AspNet.Identity.Test @@ -105,10 +106,30 @@ namespace Microsoft.AspNet.Identity.Test services.AddIdentity().AddDefaultTokenProviders(); var provider = services.BuildServiceProvider(); - var tokenProviders = provider.GetRequiredService>>(); + var tokenProviders = provider.GetRequiredService>().Value.Tokens.ProviderMap.Values; Assert.Equal(3, tokenProviders.Count()); } + [Fact] + public void AddManagerWithWrongTypesThrows() + { + var services = new ServiceCollection(); + var builder = services.AddIdentity(); + Assert.Throws(() => builder.AddUserManager>()); + Assert.Throws(() => builder.AddRoleManager>()); + Assert.Throws(() => builder.AddUserManager()); + Assert.Throws(() => builder.AddRoleManager()); + } + + [Fact] + public void AddTokenProviderWithWrongTypesThrows() + { + var services = new ServiceCollection(); + var builder = services.AddIdentity(); + Assert.Throws(() => builder.AddTokenProvider("whatevs")); + Assert.Throws(() => builder.AddTokenProvider("whatevs", typeof(object))); + } + private class MyUberThingy : IUserValidator, IPasswordValidator, IRoleValidator, IUserStore, IRoleStore { public Task CreateAsync(TestRole role, CancellationToken cancellationToken = default(CancellationToken)) diff --git a/test/Microsoft.AspNet.Identity.Test/IdentityOptionsTest.cs b/test/Microsoft.AspNet.Identity.Test/IdentityOptionsTest.cs index e9c38c4485..daf49ae475 100644 --- a/test/Microsoft.AspNet.Identity.Test/IdentityOptionsTest.cs +++ b/test/Microsoft.AspNet.Identity.Test/IdentityOptionsTest.cs @@ -66,10 +66,10 @@ namespace Microsoft.AspNet.Identity.Test var services = new ServiceCollection(); services.AddIdentity(); - services.ConfigureIdentity(config.GetSection("identity")); + services.Configure(config.GetSection("identity")); var accessor = services.BuildServiceProvider().GetRequiredService>(); Assert.NotNull(accessor); - var options = accessor.Options; + var options = accessor.Value; Assert.Equal(roleClaimType, options.ClaimsIdentity.RoleClaimType); Assert.Equal(useridClaimType, options.ClaimsIdentity.UserIdClaimType); Assert.Equal(usernameClaimType, options.ClaimsIdentity.UserNameClaimType); @@ -96,11 +96,11 @@ namespace Microsoft.AspNet.Identity.Test var builder = new ConfigurationBuilder(new MemoryConfigurationSource(dic)); var config = builder.Build(); var services = new ServiceCollection(); - services.ConfigureIdentity(config.GetSection("identity")); + services.Configure(config.GetSection("identity")); services.AddIdentity(o => { o.User.RequireUniqueEmail = false; o.Lockout.MaxFailedAccessAttempts++; }); var accessor = services.BuildServiceProvider().GetRequiredService>(); Assert.NotNull(accessor); - var options = accessor.Options; + var options = accessor.Value; Assert.False(options.User.RequireUniqueEmail); Assert.Equal(1001, options.Lockout.MaxFailedAccessAttempts); } @@ -124,7 +124,7 @@ namespace Microsoft.AspNet.Identity.Test Assert.IsType(typeof(PasswordsNegativeLengthSetup), setup); var optionsGetter = serviceProvider.GetRequiredService>(); Assert.NotNull(optionsGetter); - var myOptions = optionsGetter.Options; + var myOptions = optionsGetter.Value; Assert.True(myOptions.Password.RequireLowercase); Assert.True(myOptions.Password.RequireDigit); Assert.True(myOptions.Password.RequireNonLetterOrDigit); @@ -135,16 +135,14 @@ namespace Microsoft.AspNet.Identity.Test [Fact] public void CanSetupIdentityOptions() { - var services = new ServiceCollection() - .AddOptions() - .ConfigureIdentity(options => options.User.RequireUniqueEmail = true); - services.AddIdentity(); + var services = new ServiceCollection(); + services.AddIdentity(options => options.User.RequireUniqueEmail = true); var serviceProvider = services.BuildServiceProvider(); var optionsGetter = serviceProvider.GetRequiredService>(); Assert.NotNull(optionsGetter); - var myOptions = optionsGetter.Options; + var myOptions = optionsGetter.Value; Assert.True(myOptions.User.RequireUniqueEmail); } } diff --git a/test/Microsoft.AspNet.Identity.Test/PasswordHasherTest.cs b/test/Microsoft.AspNet.Identity.Test/PasswordHasherTest.cs index 76ccbcb7a5..4753491c31 100644 --- a/test/Microsoft.AspNet.Identity.Test/PasswordHasherTest.cs +++ b/test/Microsoft.AspNet.Identity.Test/PasswordHasherTest.cs @@ -164,14 +164,14 @@ namespace Microsoft.AspNet.Identity.Test var options = new PasswordHasherOptionsAccessor(); if (compatMode != null) { - options.Options.CompatibilityMode = (PasswordHasherCompatibilityMode)compatMode; + options.Value.CompatibilityMode = (PasswordHasherCompatibilityMode)compatMode; } if (iterCount != null) { - options.Options.IterationCount = (int)iterCount; + options.Value.IterationCount = (int)iterCount; } - Assert.NotNull(options.Options.Rng); // should have a default value - options.Options.Rng = new SequentialRandomNumberGenerator(); + Assert.NotNull(options.Value.Rng); // should have a default value + options.Value.Rng = new SequentialRandomNumberGenerator(); return options; } } diff --git a/test/Microsoft.AspNet.Identity.Test/PrincipalExtensionsTest.cs b/test/Microsoft.AspNet.Identity.Test/PrincipalExtensionsTest.cs index baaa81b765..528308b26b 100644 --- a/test/Microsoft.AspNet.Identity.Test/PrincipalExtensionsTest.cs +++ b/test/Microsoft.AspNet.Identity.Test/PrincipalExtensionsTest.cs @@ -51,7 +51,7 @@ namespace Microsoft.AspNet.Identity.Test private static ClaimsPrincipal CreateAppIdentity(string authType = null) { - authType = authType ?? IdentityOptions.ApplicationCookieAuthenticationType; + authType = authType ?? new IdentityCookieOptions().ApplicationCookieAuthenticationScheme; return new ClaimsPrincipal(new ClaimsIdentity( new[] { diff --git a/test/Microsoft.AspNet.Identity.Test/SecurityStampValidatorTest.cs b/test/Microsoft.AspNet.Identity.Test/SecurityStampValidatorTest.cs index 9c4636d230..84469e8dcf 100644 --- a/test/Microsoft.AspNet.Identity.Test/SecurityStampValidatorTest.cs +++ b/test/Microsoft.AspNet.Identity.Test/SecurityStampValidatorTest.cs @@ -21,10 +21,11 @@ namespace Microsoft.AspNet.Identity.Test [Fact] public async Task OnValidatePrincipalThrowsWithEmptyServiceCollection() { + var scheme = new IdentityOptions().Cookies.ApplicationCookieAuthenticationScheme; var httpContext = new Mock(); httpContext.Setup(c => c.RequestServices).Returns(new ServiceCollection().BuildServiceProvider()); - var id = new ClaimsPrincipal(new ClaimsIdentity(IdentityOptions.ApplicationCookieAuthenticationScheme)); - var ticket = new AuthenticationTicket(id, new AuthenticationProperties { IssuedUtc = DateTimeOffset.UtcNow }, IdentityOptions.ApplicationCookieAuthenticationScheme); + var id = new ClaimsPrincipal(new ClaimsIdentity(scheme)); + var ticket = new AuthenticationTicket(id, new AuthenticationProperties { IssuedUtc = DateTimeOffset.UtcNow }, scheme); var context = new CookieValidatePrincipalContext(httpContext.Object, ticket, new CookieAuthenticationOptions()); var ex = await Assert.ThrowsAsync(() => SecurityStampValidator.ValidatePrincipalAsync(context)); Assert.True(ex.Message.Contains("No service for type 'Microsoft.Framework.OptionsModel.IOptions")); @@ -40,11 +41,11 @@ namespace Microsoft.AspNet.Identity.Test var claimsManager = new Mock>(); var identityOptions = new IdentityOptions { SecurityStampValidationInterval = TimeSpan.Zero }; var options = new Mock>(); - options.Setup(a => a.Options).Returns(identityOptions); + options.Setup(a => a.Value).Returns(identityOptions); var httpContext = new Mock(); var contextAccessor = new Mock(); contextAccessor.Setup(a => a.HttpContext).Returns(httpContext.Object); - var id = new ClaimsIdentity(IdentityOptions.ApplicationCookieAuthenticationScheme); + var id = new ClaimsIdentity(identityOptions.Cookies.ApplicationCookieAuthenticationScheme); id.AddClaim(new Claim(ClaimTypes.NameIdentifier, user.Id)); var principal = new ClaimsPrincipal(id); @@ -61,7 +62,7 @@ namespace Microsoft.AspNet.Identity.Test var ticket = new AuthenticationTicket(principal, properties, - IdentityOptions.ApplicationCookieAuthenticationScheme); + identityOptions.Cookies.ApplicationCookieAuthenticationScheme); var context = new CookieValidatePrincipalContext(httpContext.Object, ticket, new CookieAuthenticationOptions()); Assert.NotNull(context.Properties); Assert.NotNull(context.Options); @@ -80,7 +81,7 @@ namespace Microsoft.AspNet.Identity.Test var claimsManager = new Mock>(); var identityOptions = new IdentityOptions { SecurityStampValidationInterval = TimeSpan.Zero }; var options = new Mock>(); - options.Setup(a => a.Options).Returns(identityOptions); + options.Setup(a => a.Value).Returns(identityOptions); var httpContext = new Mock(); var contextAccessor = new Mock(); contextAccessor.Setup(a => a.HttpContext).Returns(httpContext.Object); @@ -92,12 +93,12 @@ 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(IdentityOptions.ApplicationCookieAuthenticationScheme); + var id = new ClaimsIdentity(identityOptions.Cookies.ApplicationCookieAuthenticationScheme); id.AddClaim(new Claim(ClaimTypes.NameIdentifier, user.Id)); var ticket = new AuthenticationTicket(new ClaimsPrincipal(id), new AuthenticationProperties { IssuedUtc = DateTimeOffset.UtcNow }, - IdentityOptions.ApplicationCookieAuthenticationScheme); + identityOptions.Cookies.ApplicationCookieAuthenticationScheme); var context = new CookieValidatePrincipalContext(httpContext.Object, ticket, new CookieAuthenticationOptions()); Assert.NotNull(context.Properties); Assert.NotNull(context.Options); @@ -116,7 +117,7 @@ namespace Microsoft.AspNet.Identity.Test var claimsManager = new Mock>(); var identityOptions = new IdentityOptions { SecurityStampValidationInterval = TimeSpan.Zero }; var options = new Mock>(); - options.Setup(a => a.Options).Returns(identityOptions); + options.Setup(a => a.Value).Returns(identityOptions); var contextAccessor = new Mock(); contextAccessor.Setup(a => a.HttpContext).Returns(httpContext.Object); var signInManager = new Mock>(userManager.Object, @@ -127,12 +128,12 @@ 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(IdentityOptions.ApplicationCookieAuthenticationScheme); + var id = new ClaimsIdentity(identityOptions.Cookies.ApplicationCookieAuthenticationScheme); id.AddClaim(new Claim(ClaimTypes.NameIdentifier, user.Id)); var ticket = new AuthenticationTicket(new ClaimsPrincipal(id), new AuthenticationProperties(), - IdentityOptions.ApplicationCookieAuthenticationScheme); + identityOptions.Cookies.ApplicationCookieAuthenticationScheme); var context = new CookieValidatePrincipalContext(httpContext.Object, ticket, new CookieAuthenticationOptions()); Assert.NotNull(context.Properties); Assert.NotNull(context.Options); @@ -151,7 +152,7 @@ namespace Microsoft.AspNet.Identity.Test var claimsManager = new Mock>(); var identityOptions = new IdentityOptions { SecurityStampValidationInterval = TimeSpan.FromDays(1) }; var options = new Mock>(); - options.Setup(a => a.Options).Returns(identityOptions); + options.Setup(a => a.Value).Returns(identityOptions); var contextAccessor = new Mock(); contextAccessor.Setup(a => a.HttpContext).Returns(httpContext.Object); var signInManager = new Mock>(userManager.Object, @@ -163,12 +164,12 @@ 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(IdentityOptions.ApplicationCookieAuthenticationScheme); + var id = new ClaimsIdentity(identityOptions.Cookies.ApplicationCookieAuthenticationScheme); id.AddClaim(new Claim(ClaimTypes.NameIdentifier, user.Id)); var ticket = new AuthenticationTicket(new ClaimsPrincipal(id), new AuthenticationProperties { IssuedUtc = DateTimeOffset.UtcNow }, - IdentityOptions.ApplicationCookieAuthenticationScheme); + identityOptions.Cookies.ApplicationCookieAuthenticationScheme); var context = new CookieValidatePrincipalContext(httpContext.Object, ticket, new CookieAuthenticationOptions()); Assert.NotNull(context.Properties); Assert.NotNull(context.Options); diff --git a/test/Microsoft.AspNet.Identity.Test/SignInManagerTest.cs b/test/Microsoft.AspNet.Identity.Test/SignInManagerTest.cs index 9d98643de6..4f05a65170 100644 --- a/test/Microsoft.AspNet.Identity.Test/SignInManagerTest.cs +++ b/test/Microsoft.AspNet.Identity.Test/SignInManagerTest.cs @@ -122,7 +122,7 @@ namespace Microsoft.AspNet.Identity.Test var roleManager = MockHelpers.MockRoleManager(); var identityOptions = new IdentityOptions(); var options = new Mock>(); - options.Setup(a => a.Options).Returns(identityOptions); + options.Setup(a => a.Value).Returns(identityOptions); var claimsFactory = new UserClaimsPrincipalFactory(manager.Object, roleManager.Object, options.Object); var logStore = new StringBuilder(); var logger = MockHelpers.MockILogger>(logStore); @@ -155,7 +155,7 @@ namespace Microsoft.AspNet.Identity.Test var roleManager = MockHelpers.MockRoleManager(); identityOptions = identityOptions ?? new IdentityOptions(); var options = new Mock>(); - options.Setup(a => a.Options).Returns(identityOptions); + options.Setup(a => a.Value).Returns(identityOptions); var claimsFactory = new UserClaimsPrincipalFactory(manager, roleManager.Object, options.Object); var sm = new SignInManager(manager, contextAccessor.Object, claimsFactory, options.Object, null); sm.Logger = MockHelpers.MockILogger>(logStore ?? new StringBuilder()).Object; @@ -268,11 +268,11 @@ namespace Microsoft.AspNet.Identity.Test manager.Setup(m => m.ResetAccessFailedCountAsync(user)).ReturnsAsync(IdentityResult.Success).Verifiable(); } var context = new Mock(); + var helper = SetupSignInManager(manager.Object, context.Object); var auth = new Mock(); - auth.Setup(a => a.SignInAsync(IdentityOptions.TwoFactorUserIdCookieAuthenticationScheme, + auth.Setup(a => a.SignInAsync(helper.Options.Cookies.TwoFactorUserIdCookieAuthenticationScheme, It.Is(id => id.FindFirstValue(ClaimTypes.Name) == user.Id))).Returns(Task.FromResult(0)).Verifiable(); context.Setup(c => c.Authentication).Returns(auth.Object).Verifiable(); - var helper = SetupSignInManager(manager.Object, context.Object); // Act var result = await helper.PasswordSignInAsync(user.UserName, "password", false, false); @@ -340,7 +340,7 @@ namespace Microsoft.AspNet.Identity.Test } // REVIEW: auth changes we lost the ability to mock is persistent //var properties = new AuthenticationProperties { IsPersistent = isPersistent }; - auth.Setup(a => a.AuthenticateAsync(It.Is(c => c.AuthenticationScheme == IdentityOptions.ApplicationCookieAuthenticationScheme))) + auth.Setup(a => a.AuthenticateAsync(It.Is(c => c.AuthenticationScheme == IdentityCookieOptions.ApplicationCookieAuthenticationType))) .Returns(Task.FromResult(0)).Verifiable(); var manager = SetupUserManager(user); @@ -398,17 +398,18 @@ namespace Microsoft.AspNet.Identity.Test var auth = new Mock(); var twoFactorInfo = new SignInManager.TwoFactorAuthenticationInfo { UserId = user.Id }; var loginProvider = "loginprovider"; - var id = SignInManager.StoreTwoFactorInfo(user.Id, externalLogin ? loginProvider : null); + var helper = SetupSignInManager(manager.Object, context.Object); + var id = helper.StoreTwoFactorInfo(user.Id, externalLogin ? loginProvider : null); if (externalLogin) { auth.Setup(a => a.SignInAsync( - IdentityOptions.ApplicationCookieAuthenticationScheme, + helper.Options.Cookies.ApplicationCookieAuthenticationScheme, It.Is(i => i.FindFirstValue(ClaimTypes.AuthenticationMethod) == loginProvider && i.FindFirstValue(ClaimTypes.NameIdentifier) == user.Id), It.IsAny())).Returns(Task.FromResult(0)).Verifiable(); // REVIEW: restore ability to test is persistent //It.Is(v => v.IsPersistent == isPersistent))).Verifiable(); - auth.Setup(a => a.SignOutAsync(IdentityOptions.ExternalCookieAuthenticationScheme)).Returns(Task.FromResult(0)).Verifiable(); + auth.Setup(a => a.SignOutAsync(helper.Options.Cookies.ExternalCookieAuthenticationScheme)).Returns(Task.FromResult(0)).Verifiable(); } else { @@ -417,15 +418,14 @@ namespace Microsoft.AspNet.Identity.Test if (rememberClient) { auth.Setup(a => a.SignInAsync( - IdentityOptions.TwoFactorRememberMeCookieAuthenticationScheme, + helper.Options.Cookies.TwoFactorRememberMeCookieAuthenticationScheme, It.Is(i => i.FindFirstValue(ClaimTypes.Name) == user.Id - && i.Identities.First().AuthenticationType == IdentityOptions.TwoFactorRememberMeCookieAuthenticationType), + && i.Identities.First().AuthenticationType == helper.Options.Cookies.TwoFactorRememberMeCookieAuthenticationScheme), It.IsAny())).Returns(Task.FromResult(0)).Verifiable(); //It.Is(v => v.IsPersistent == true))).Returns(Task.FromResult(0)).Verifiable(); } - auth.Setup(a => a.AuthenticateAsync(IdentityOptions.TwoFactorUserIdCookieAuthenticationScheme)).ReturnsAsync(id).Verifiable(); + auth.Setup(a => a.AuthenticateAsync(helper.Options.Cookies.TwoFactorUserIdCookieAuthenticationScheme)).ReturnsAsync(id).Verifiable(); context.Setup(c => c.Authentication).Returns(auth.Object).Verifiable(); - var helper = SetupSignInManager(manager.Object, context.Object); // Act var result = await helper.TwoFactorSignInAsync(provider, code, isPersistent, rememberClient); @@ -447,9 +447,9 @@ namespace Microsoft.AspNet.Identity.Test var auth = new Mock(); context.Setup(c => c.Authentication).Returns(auth.Object).Verifiable(); auth.Setup(a => a.SignInAsync( - IdentityOptions.TwoFactorRememberMeCookieAuthenticationScheme, + manager.Object.Options.Cookies.TwoFactorRememberMeCookieAuthenticationScheme, It.Is(i => i.FindFirstValue(ClaimTypes.Name) == user.Id - && i.Identities.First().AuthenticationType == IdentityOptions.TwoFactorRememberMeCookieAuthenticationType), + && i.Identities.First().AuthenticationType == manager.Object.Options.Cookies.TwoFactorRememberMeCookieAuthenticationScheme), It.Is(v => v.IsPersistent == true))).Returns(Task.FromResult(0)).Verifiable(); var helper = SetupSignInManager(manager.Object, context.Object); @@ -483,9 +483,9 @@ namespace Microsoft.AspNet.Identity.Test var auth = new Mock(); context.Setup(c => c.Authentication).Returns(auth.Object).Verifiable(); SetupSignIn(auth); - var id = new ClaimsIdentity(IdentityOptions.TwoFactorRememberMeCookieAuthenticationType); + var id = new ClaimsIdentity(manager.Object.Options.Cookies.TwoFactorRememberMeCookieAuthenticationScheme); id.AddClaim(new Claim(ClaimTypes.Name, user.Id)); - auth.Setup(a => a.AuthenticateAsync(IdentityOptions.TwoFactorRememberMeCookieAuthenticationScheme)).ReturnsAsync(new ClaimsPrincipal(id)).Verifiable(); + auth.Setup(a => a.AuthenticateAsync(manager.Object.Options.Cookies.TwoFactorRememberMeCookieAuthenticationScheme)).ReturnsAsync(new ClaimsPrincipal(id)).Verifiable(); var helper = SetupSignInManager(manager.Object, context.Object); // Act @@ -509,9 +509,9 @@ namespace Microsoft.AspNet.Identity.Test var auth = new Mock(); context.Setup(c => c.Authentication).Returns(auth.Object).Verifiable(); auth.Setup(a => a.SignOutAsync(authenticationScheme)).Returns(Task.FromResult(0)).Verifiable(); - auth.Setup(a => a.SignOutAsync(IdentityOptions.TwoFactorUserIdCookieAuthenticationScheme)).Returns(Task.FromResult(0)).Verifiable(); - auth.Setup(a => a.SignOutAsync(IdentityOptions.ExternalCookieAuthenticationScheme)).Returns(Task.FromResult(0)).Verifiable(); - IdentityOptions.ApplicationCookieAuthenticationScheme = authenticationScheme; + auth.Setup(a => a.SignOutAsync(manager.Object.Options.Cookies.TwoFactorUserIdCookieAuthenticationScheme)).Returns(Task.FromResult(0)).Verifiable(); + auth.Setup(a => a.SignOutAsync(manager.Object.Options.Cookies.ExternalCookieAuthenticationScheme)).Returns(Task.FromResult(0)).Verifiable(); + IdentityCookieOptions.ApplicationCookieAuthenticationType = authenticationScheme; var helper = SetupSignInManager(manager.Object, context.Object); // Act @@ -631,7 +631,7 @@ namespace Microsoft.AspNet.Identity.Test private static void SetupSignIn(Mock auth, string userId = null, bool? isPersistent = null, string loginProvider = null) { - auth.Setup(a => a.SignInAsync(IdentityOptions.ApplicationCookieAuthenticationScheme, + auth.Setup(a => a.SignInAsync(IdentityCookieOptions.ApplicationCookieAuthenticationType, It.Is(id => (userId == null || id.FindFirstValue(ClaimTypes.NameIdentifier) == userId) && (loginProvider == null || id.FindFirstValue(ClaimTypes.AuthenticationMethod) == loginProvider)), diff --git a/test/Microsoft.AspNet.Identity.Test/UserClaimsPrincipalFactoryTest.cs b/test/Microsoft.AspNet.Identity.Test/UserClaimsPrincipalFactoryTest.cs index 7632c8a76a..4581c4d27f 100644 --- a/test/Microsoft.AspNet.Identity.Test/UserClaimsPrincipalFactoryTest.cs +++ b/test/Microsoft.AspNet.Identity.Test/UserClaimsPrincipalFactoryTest.cs @@ -22,7 +22,7 @@ namespace Microsoft.AspNet.Identity.Test Assert.Throws("optionsAccessor", () => new UserClaimsPrincipalFactory(userManager, roleManager, options.Object)); var identityOptions = new IdentityOptions(); - options.Setup(a => a.Options).Returns(identityOptions); + options.Setup(a => a.Value).Returns(identityOptions); var factory = new UserClaimsPrincipalFactory(userManager, roleManager, options.Object); await Assert.ThrowsAsync("user", async () => await factory.CreateAsync(null)); @@ -72,7 +72,7 @@ namespace Microsoft.AspNet.Identity.Test var options = new Mock>(); var identityOptions = new IdentityOptions(); - options.Setup(a => a.Options).Returns(identityOptions); + options.Setup(a => a.Value).Returns(identityOptions); var factory = new UserClaimsPrincipalFactory(userManager.Object, roleManager.Object, options.Object); // Act @@ -83,7 +83,7 @@ namespace Microsoft.AspNet.Identity.Test var manager = userManager.Object; Assert.NotNull(identity); Assert.Equal(1, principal.Identities.Count()); - Assert.Equal(IdentityOptions.ApplicationCookieAuthenticationType, identity.AuthenticationType); + Assert.Equal(identityOptions.Cookies.TwoFactorRememberMeCookieAuthenticationScheme, identity.AuthenticationType); var claims = identity.Claims.ToList(); Assert.NotNull(claims); Assert.True( diff --git a/test/Microsoft.AspNet.Identity.Test/UserManagerTest.cs b/test/Microsoft.AspNet.Identity.Test/UserManagerTest.cs index 977c39664f..07bddee229 100644 --- a/test/Microsoft.AspNet.Identity.Test/UserManagerTest.cs +++ b/test/Microsoft.AspNet.Identity.Test/UserManagerTest.cs @@ -48,17 +48,6 @@ namespace Microsoft.AspNet.Identity.Test provider.GetRequiredService()); } - [Fact] - public void AddManagerWithWrongTypesThrows() - { - var services = new ServiceCollection(); - var builder = services.AddIdentity(); - Assert.Throws(() => builder.AddUserManager>()); - Assert.Throws(() => builder.AddRoleManager>()); - Assert.Throws(() => builder.AddUserManager()); - Assert.Throws(() => builder.AddRoleManager()); - } - public class CustomUserManager : UserManager { public CustomUserManager() : base(new Mock>().Object, null, null, null, null, null, null, null, null, null) @@ -714,7 +703,7 @@ namespace Microsoft.AspNet.Identity.Test await Assert.ThrowsAsync("providerKey", async () => await manager.RemoveLoginAsync(null, "", null)); await Assert.ThrowsAsync("email", async () => await manager.FindByEmailAsync(null)); - Assert.Throws("provider", () => manager.RegisterTokenProvider(null)); + Assert.Throws("provider", () => manager.RegisterTokenProvider("whatever", null)); await Assert.ThrowsAsync("roles", async () => await manager.AddToRolesAsync(new TestUser(), null)); await Assert.ThrowsAsync("roles", async () => await manager.RemoveFromRolesAsync(new TestUser(), null)); } @@ -723,7 +712,7 @@ namespace Microsoft.AspNet.Identity.Test public async Task MethodsFailWithUnknownUserTest() { var manager = MockHelpers.TestUserManager(new EmptyStore()); - manager.RegisterTokenProvider(new NoOpTokenProvider()); + manager.RegisterTokenProvider("whatever", new NoOpTokenProvider()); await Assert.ThrowsAsync("user", async () => await manager.GetUserNameAsync(null)); await Assert.ThrowsAsync("user", diff --git a/test/Shared/MockHelpers.cs b/test/Shared/MockHelpers.cs index bf2a025992..7957304205 100644 --- a/test/Shared/MockHelpers.cs +++ b/test/Shared/MockHelpers.cs @@ -3,14 +3,11 @@ using System; using System.Collections.Generic; -using System.Threading; using System.Threading.Tasks; using System.Text; using Microsoft.Framework.Logging; using Moq; using Microsoft.Framework.OptionsModel; -using System.Linq; -using Microsoft.AspNet.Hosting; namespace Microsoft.AspNet.Identity.Test { @@ -70,7 +67,7 @@ namespace Microsoft.AspNet.Identity.Test var options = new Mock>(); var idOptions = new IdentityOptions(); idOptions.Lockout.AllowedForNewUsers = false; - options.Setup(o => o.Options).Returns(idOptions); + options.Setup(o => o.Value).Returns(idOptions); var userValidators = new List>(); var validator = new Mock>(); userValidators.Add(validator.Object); @@ -78,7 +75,7 @@ namespace Microsoft.AspNet.Identity.Test pwdValidators.Add(new PasswordValidator()); var userManager = new UserManager(store, options.Object, new PasswordHasher(), userValidators, pwdValidators, new UpperInvariantLookupNormalizer(), - new IdentityErrorDescriber(), Enumerable.Empty>(), + new IdentityErrorDescriber(), null, new Mock>>().Object, null); validator.Setup(v => v.ValidateAsync(userManager, It.IsAny())) diff --git a/test/Shared/PasswordHasherOptionsAccessor.cs b/test/Shared/PasswordHasherOptionsAccessor.cs index 1e8cc844a7..10a1e74cc2 100644 --- a/test/Shared/PasswordHasherOptionsAccessor.cs +++ b/test/Shared/PasswordHasherOptionsAccessor.cs @@ -8,11 +8,6 @@ namespace Microsoft.AspNet.Identity.Test { internal class PasswordHasherOptionsAccessor : IOptions { - public PasswordHasherOptions Options { get; } = new PasswordHasherOptions(); - - public PasswordHasherOptions GetNamedOptions(string name) - { - throw new NotImplementedException(); - } + public PasswordHasherOptions Value { get; } = new PasswordHasherOptions(); } } \ No newline at end of file diff --git a/test/Shared/UserManagerTestBase.cs b/test/Shared/UserManagerTestBase.cs index 98750065cc..9ab9c26ab7 100644 --- a/test/Shared/UserManagerTestBase.cs +++ b/test/Shared/UserManagerTestBase.cs @@ -32,23 +32,22 @@ namespace Microsoft.AspNet.Identity.Test protected virtual void SetupIdentityServices(IServiceCollection services, object context = null) { services.AddSingleton(); - services.AddIdentity().AddDefaultTokenProviders(); - AddUserStore(services, context); - AddRoleStore(services, context); - services.AddLogging(); - services.AddInstance>>(new TestLogger>()); - services.AddInstance>>(new TestLogger>()); - services.ConfigureIdentity(options => + services.AddIdentity(options => { options.Password.RequireDigit = false; options.Password.RequireLowercase = false; options.Password.RequireNonLetterOrDigit = false; options.Password.RequireUppercase = false; options.User.AllowedUserNameCharacters = null; - }); + }).AddDefaultTokenProviders(); + AddUserStore(services, context); + AddRoleStore(services, context); + services.AddLogging(); + services.AddInstance>>(new TestLogger>()); + services.AddInstance>>(new TestLogger>()); } - protected virtual UserManager CreateManager(object context = null, IServiceCollection services = null) + protected virtual UserManager CreateManager(object context = null, IServiceCollection services = null, Action configureServices = null) { if (services == null) { @@ -59,6 +58,10 @@ namespace Microsoft.AspNet.Identity.Test context = CreateTestContext(); } SetupIdentityServices(services, context); + if (configureServices != null) + { + configureServices(services); + } return services.BuildServiceProvider().GetService>(); } @@ -648,8 +651,6 @@ namespace Microsoft.AspNet.Identity.Test private class StaticTokenProvider : IUserTokenProvider { - public string Name { get; } = "Static"; - public async Task GenerateAsync(string purpose, UserManager manager, TUser user) { return MakeToken(purpose, await manager.GetUserIdAsync(user)); @@ -680,8 +681,8 @@ namespace Microsoft.AspNet.Identity.Test public async Task CanResetPasswordWithStaticTokenProvider() { var manager = CreateManager(); - manager.RegisterTokenProvider(new StaticTokenProvider()); - manager.Options.PasswordResetTokenProvider = "Static"; + manager.RegisterTokenProvider("Static", new StaticTokenProvider()); + manager.Options.Tokens.PasswordResetTokenProvider = "Static"; var user = CreateTestUser(); const string password = "password"; const string newPassword = "newpassword"; @@ -701,8 +702,8 @@ namespace Microsoft.AspNet.Identity.Test public async Task PasswordValidatorCanBlockResetPasswordWithStaticTokenProvider() { var manager = CreateManager(); - manager.RegisterTokenProvider(new StaticTokenProvider()); - manager.Options.PasswordResetTokenProvider = "Static"; + manager.RegisterTokenProvider("Static", new StaticTokenProvider()); + manager.Options.Tokens.PasswordResetTokenProvider = "Static"; var user = CreateTestUser(); const string password = "password"; const string newPassword = "newpassword"; @@ -723,8 +724,8 @@ namespace Microsoft.AspNet.Identity.Test public async Task ResetPasswordWithStaticTokenProviderFailsWithWrongToken() { var manager = CreateManager(); - manager.RegisterTokenProvider(new StaticTokenProvider()); - manager.Options.PasswordResetTokenProvider = "Static"; + manager.RegisterTokenProvider("Static", new StaticTokenProvider()); + manager.Options.Tokens.PasswordResetTokenProvider = "Static"; var user = CreateTestUser(); const string password = "password"; const string newPassword = "newpassword"; @@ -741,7 +742,7 @@ namespace Microsoft.AspNet.Identity.Test public async Task CanGenerateAndVerifyUserTokenWithStaticTokenProvider() { var manager = CreateManager(); - manager.RegisterTokenProvider(new StaticTokenProvider()); + manager.RegisterTokenProvider("Static", new StaticTokenProvider()); var user = CreateTestUser(); var user2 = CreateTestUser(); IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); @@ -765,8 +766,8 @@ namespace Microsoft.AspNet.Identity.Test public async Task CanConfirmEmailWithStaticToken() { var manager = CreateManager(); - manager.RegisterTokenProvider(new StaticTokenProvider()); - manager.Options.EmailConfirmationTokenProvider = "Static"; + manager.RegisterTokenProvider("Static", new StaticTokenProvider()); + manager.Options.Tokens.EmailConfirmationTokenProvider = "Static"; var user = CreateTestUser(); Assert.False(await manager.IsEmailConfirmedAsync(user)); IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); @@ -783,8 +784,8 @@ namespace Microsoft.AspNet.Identity.Test public async Task ConfirmEmailWithStaticTokenFailsWithWrongToken() { var manager = CreateManager(); - manager.RegisterTokenProvider(new StaticTokenProvider()); - manager.Options.EmailConfirmationTokenProvider = "Static"; + manager.RegisterTokenProvider("Static", new StaticTokenProvider()); + manager.Options.Tokens.EmailConfirmationTokenProvider = "Static"; var user = CreateTestUser(); Assert.False(await manager.IsEmailConfirmedAsync(user)); IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); @@ -1449,6 +1450,27 @@ namespace Microsoft.AspNet.Identity.Test Assert.NotEqual(stamp, await manager.GetSecurityStampAsync(user)); } + [Fact] + public async Task CanChangeEmailWithDifferentTokenProvider() + { + var manager = CreateManager(context: null, services: null, + configureServices: s => s.Configure( + o => o.Tokens.ProviderMap["NewProvider2"] = new TokenProviderDescriptor(typeof(EmailTokenProvider)))); + manager.Options.Tokens.ChangeEmailTokenProvider = "NewProvider2"; + var user = CreateTestUser("foouser"); + IdentityResultAssert.IsSuccess(await manager.CreateAsync(user)); + var email = await manager.GetUserNameAsync(user) + "@diddly.bop"; + IdentityResultAssert.IsSuccess(await manager.SetEmailAsync(user, email)); + Assert.False(await manager.IsEmailConfirmedAsync(user)); + var stamp = await manager.GetSecurityStampAsync(user); + var newEmail = await manager.GetUserNameAsync(user) + "@en.vec"; + var token1 = await manager.GenerateChangeEmailTokenAsync(user, newEmail); + IdentityResultAssert.IsSuccess(await manager.ChangeEmailAsync(user, newEmail, token1)); + Assert.True(await manager.IsEmailConfirmedAsync(user)); + Assert.Equal(await manager.GetEmailAsync(user), newEmail); + Assert.NotEqual(stamp, await manager.GetSecurityStampAsync(user)); + } + [Fact] public async Task ChangeEmailFailsWithWrongToken() {