From d827b9fff2b2648935d4297c98a986766eb6ee8e Mon Sep 17 00:00:00 2001 From: Hao Kung Date: Tue, 22 Apr 2014 13:31:23 -0700 Subject: [PATCH] More DI-ify identity Follow K patterns for DI - IdentityBuilder - IServiceProvider constructor - Unit tests for Startup usage/new DI builder - Move template default configuration into DefaultServices --- .../project.json | 4 + .../SignInManager.cs | 1 - .../IdentityBuilder.cs | 71 ++++++++++ .../IdentityServiceCollectionExtensions.cs | 27 ++++ .../IdentityServices.cs | 59 ++++++++ .../LockoutPolicy.cs | 27 ++++ src/Microsoft.AspNet.Identity/RoleManager.cs | 27 +++- src/Microsoft.AspNet.Identity/UserManager.cs | 80 +++++++---- src/Microsoft.AspNet.Identity/project.json | 1 + temp/Identity45.sln | 130 ++++++++++++++++++ .../TestIdentityFactory.cs | 7 +- .../UserStoreTest.cs | 109 +++++++++++++-- .../project.json | 5 +- .../InMemoryStoreTest.cs | 68 ++++++--- .../StartupTest.cs | 70 ++++++++++ .../project.json | 8 +- .../IdentityBuilderTest.cs | 90 ++++++++++++ .../RoleManagerTest.cs | 5 +- .../TestServices.cs | 20 --- .../UserManagerTest.cs | 14 +- .../project.json | 2 +- 21 files changed, 727 insertions(+), 98 deletions(-) create mode 100644 src/Microsoft.AspNet.Identity/IdentityBuilder.cs create mode 100644 src/Microsoft.AspNet.Identity/IdentityServiceCollectionExtensions.cs create mode 100644 src/Microsoft.AspNet.Identity/IdentityServices.cs create mode 100644 src/Microsoft.AspNet.Identity/LockoutPolicy.cs create mode 100644 temp/Identity45.sln create mode 100644 test/Microsoft.AspNet.Identity.InMemory.Test/StartupTest.cs create mode 100644 test/Microsoft.AspNet.Identity.Test/IdentityBuilderTest.cs delete mode 100644 test/Microsoft.AspNet.Identity.Test/TestServices.cs diff --git a/src/Microsoft.AspNet.Identity.InMemory/project.json b/src/Microsoft.AspNet.Identity.InMemory/project.json index ea9ce1c10b..6edbc05b35 100644 --- a/src/Microsoft.AspNet.Identity.InMemory/project.json +++ b/src/Microsoft.AspNet.Identity.InMemory/project.json @@ -2,6 +2,10 @@ "version": "0.1-alpha-*", "dependencies": { "Microsoft.AspNet.Identity": "0.1-alpha-*", + "Microsoft.AspNet.Abstractions" : "0.1-alpha-*", + "Microsoft.AspNet.ConfigurationModel" : "0.1-alpha-*", + "Microsoft.AspNet.DependencyInjection" : "0.1-alpha-*", + "Microsoft.AspNet.RequestContainer" : "0.1-alpha-*", "System.Security.Claims": "0.1-alpha-*" }, "configurations": { diff --git a/src/Microsoft.AspNet.Identity.Security/SignInManager.cs b/src/Microsoft.AspNet.Identity.Security/SignInManager.cs index 49c8bb27eb..86da5adf10 100644 --- a/src/Microsoft.AspNet.Identity.Security/SignInManager.cs +++ b/src/Microsoft.AspNet.Identity.Security/SignInManager.cs @@ -17,7 +17,6 @@ namespace Microsoft.AspNet.Identity.Security public UserManager UserManager { get; set; } public HttpContext Context { get; set; } - public virtual async Task CreateUserIdentityAsync(TUser user) { if (UserManager == null) diff --git a/src/Microsoft.AspNet.Identity/IdentityBuilder.cs b/src/Microsoft.AspNet.Identity/IdentityBuilder.cs new file mode 100644 index 0000000000..cdd966e4fe --- /dev/null +++ b/src/Microsoft.AspNet.Identity/IdentityBuilder.cs @@ -0,0 +1,71 @@ +using Microsoft.AspNet.DependencyInjection; +using System; + +namespace Microsoft.AspNet.Identity +{ + public class IdentityBuilder where TUser : class where TRole : class + { + private ServiceCollection Services { get; set; } + + public IdentityBuilder(ServiceCollection services) + { + Services = services; + } + + public IdentityBuilder Use(Func func) + { + Services.AddInstance(func()); + return this; + } + + public IdentityBuilder UseIdentity() + { + Services.Add(IdentityServices.GetDefaultUserServices()); + Services.Add(IdentityServices.GetDefaultRoleServices()); + return this; + } + + public IdentityBuilder UseUserStore(Func> func) + { + return Use(func); + } + + public IdentityBuilder UseRoleStore(Func> func) + { + return Use(func); + } + + public IdentityBuilder UsePasswordValidator(Func func) + { + return Use(func); + } + + public IdentityBuilder UseUserValidator(Func> func) + { + return Use(func); + } + + public IdentityBuilder UseUserManager() where TManager : UserManager + { + Services.AddScoped(); + return this; + } + + public IdentityBuilder UseRoleManager() where TManager : RoleManager + { + Services.AddScoped(); + return this; + } + + //public IdentityBuilder UseTwoFactorProviders(Func>> func) + //{ + // return Use(func); + //} + + public IdentityBuilder UseLockoutPolicy(Func func) + { + return Use(func); + } + + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNet.Identity/IdentityServiceCollectionExtensions.cs b/src/Microsoft.AspNet.Identity/IdentityServiceCollectionExtensions.cs new file mode 100644 index 0000000000..53bc5c4863 --- /dev/null +++ b/src/Microsoft.AspNet.Identity/IdentityServiceCollectionExtensions.cs @@ -0,0 +1,27 @@ +using Microsoft.AspNet.Identity; +using System; + +namespace Microsoft.AspNet.DependencyInjection +{ + public static class IdentityServiceCollectionExtensions + { + public static ServiceCollection AddIdentity(this ServiceCollection services, Action> actionBuilder) + where TUser : class + where TRole : class + { + services.Add(IdentityServices.GetDefaultUserServices()); + services.Add(IdentityServices.GetDefaultRoleServices()); + actionBuilder(new IdentityBuilder(services)); + return services; + } + + public static ServiceCollection AddIdentity(this ServiceCollection services, Action> actionBuilder) + where TUser : class + { + services.Add(IdentityServices.GetDefaultUserServices()); + services.Add(IdentityServices.GetDefaultRoleServices()); + actionBuilder(new IdentityBuilder(services)); + return services; + } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNet.Identity/IdentityServices.cs b/src/Microsoft.AspNet.Identity/IdentityServices.cs new file mode 100644 index 0000000000..a5efe06704 --- /dev/null +++ b/src/Microsoft.AspNet.Identity/IdentityServices.cs @@ -0,0 +1,59 @@ +using Microsoft.AspNet.ConfigurationModel; +using Microsoft.AspNet.DependencyInjection; +using System; +using System.Collections.Generic; + +namespace Microsoft.AspNet.Identity +{ + /// + /// Default services used by UserManager and RoleManager + /// + public class IdentityServices + { + + public static IEnumerable GetDefaultUserServices() where TUser : class + { + return GetDefaultUserServices(new Configuration()); + } + + public static IEnumerable GetDefaultUserServices(IConfiguration configuration) where TUser : class + { + var describe = new ServiceDescriber(configuration); + + // TODO: review defaults for validators should get picked up from config? + yield return describe.Instance>(new UserValidator()); + yield return describe.Instance(new PasswordValidator() + { + RequiredLength = 6, + RequireDigit = true, + RequireLowercase = true, + RequireNonLetterOrDigit = true, + RequireUppercase = true + }); + yield return describe.Instance(new PasswordHasher()); + yield return describe.Instance>(new ClaimsIdentityFactory()); + yield return describe.Instance(new LockoutPolicy + { + UserLockoutEnabledByDefault = false, + DefaultAccountLockoutTimeSpan = TimeSpan.FromMinutes(5), + MaxFailedAccessAttemptsBeforeLockout = 5 + }); + + // TODO: rationalize email/sms/usertoken services + // TODO: configure lockout from config? + } + + public static IEnumerable GetDefaultRoleServices() where TRole : class + { + return GetDefaultRoleServices(new Configuration()); + } + + public static IEnumerable GetDefaultRoleServices(IConfiguration configuration) where TRole : class + { + var describe = new ServiceDescriber(configuration); + + // TODO: review defaults for validators should get picked up from config? + yield return describe.Instance>(new RoleValidator()); + } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNet.Identity/LockoutPolicy.cs b/src/Microsoft.AspNet.Identity/LockoutPolicy.cs new file mode 100644 index 0000000000..27d343aeb8 --- /dev/null +++ b/src/Microsoft.AspNet.Identity/LockoutPolicy.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Microsoft.AspNet.Identity +{ + /// + /// Configuration for lockout + /// + public class LockoutPolicy + { + /// + /// If true, will enable user lockout when users are created + /// + public bool UserLockoutEnabledByDefault { get; set; } + + /// + /// Number of access attempts allowed for a user before lockout (if enabled) + /// + public int MaxFailedAccessAttemptsBeforeLockout { get; set; } + + /// + /// Default amount of time an user is locked out for after MaxFailedAccessAttempsBeforeLockout is reached + /// + public TimeSpan DefaultAccountLockoutTimeSpan { get; set; } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNet.Identity/RoleManager.cs b/src/Microsoft.AspNet.Identity/RoleManager.cs index 7746bcb124..db448ef973 100644 --- a/src/Microsoft.AspNet.Identity/RoleManager.cs +++ b/src/Microsoft.AspNet.Identity/RoleManager.cs @@ -2,6 +2,8 @@ using System; using System.Linq; using System.Threading; using System.Threading.Tasks; +using Microsoft.AspNet.DependencyInjection; +using Microsoft.AspNet.DependencyInjection.Fallback; namespace Microsoft.AspNet.Identity { @@ -13,6 +15,11 @@ namespace Microsoft.AspNet.Identity { private bool _disposed; + public RoleManager(IServiceProvider services) + { + Initialize(services); + } + /// /// Constructor /// @@ -23,8 +30,9 @@ namespace Microsoft.AspNet.Identity { throw new ArgumentNullException("store"); } - Store = store; - RoleValidator = new RoleValidator(); + var services = new ServiceCollection { IdentityServices.GetDefaultRoleServices() }; + services.AddInstance>(store); + Initialize(services.BuildServiceProvider()); } /// @@ -65,6 +73,21 @@ namespace Microsoft.AspNet.Identity } } + public void Initialize(IServiceProvider services) + { + if (services == null) + { + throw new ArgumentNullException("services"); + } + Store = services.GetService>(); + if (Store == null) + { + // TODO: what is the right way to enforce required services + throw new InvalidOperationException(); + } + RoleValidator = services.GetService>(); + } + /// /// Dispose this object /// diff --git a/src/Microsoft.AspNet.Identity/UserManager.cs b/src/Microsoft.AspNet.Identity/UserManager.cs index 4e1e7f3af5..ce9cffbe94 100644 --- a/src/Microsoft.AspNet.Identity/UserManager.cs +++ b/src/Microsoft.AspNet.Identity/UserManager.cs @@ -7,6 +7,7 @@ using System.Text; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNet.DependencyInjection; +using Microsoft.AspNet.DependencyInjection.Fallback; namespace Microsoft.AspNet.Identity { @@ -23,25 +24,18 @@ namespace Microsoft.AspNet.Identity private TimeSpan _defaultLockout = TimeSpan.Zero; private bool _disposed; private IPasswordHasher _passwordHasher; + private LockoutPolicy _lockoutPolicy; + // Needed for mock unit tests public UserManager() { } /// - /// Constructor which takes a service provider to find the default interfaces to hook up + /// Constructor which takes a service provider /// /// public UserManager(IServiceProvider serviceProvider) { - if (serviceProvider == null) - { - throw new ArgumentNullException("serviceProvider"); - } - PasswordHasher = serviceProvider.GetService(); - UserValidator = serviceProvider.GetService>(); - PasswordValidator = serviceProvider.GetService(); - ClaimsIdentityFactory = serviceProvider.GetService>(); - Store = serviceProvider.GetService>(); - // TODO: maybe each optional store as well? Email and SMS services? + Initialize(serviceProvider); } /// @@ -54,10 +48,29 @@ namespace Microsoft.AspNet.Identity { throw new ArgumentNullException("store"); } - Store = store; - UserValidator = new UserValidator(); - PasswordHasher = new PasswordHasher(); - ClaimsIdentityFactory = new ClaimsIdentityFactory(); + var services = new ServiceCollection { IdentityServices.GetDefaultUserServices() }; + services.AddInstance>(store); + Initialize(services.BuildServiceProvider()); + } + + public void Initialize(IServiceProvider serviceProvider) + { + if (serviceProvider == null) + { + throw new ArgumentNullException("serviceProvider"); + } + PasswordHasher = serviceProvider.GetService(); + UserValidator = serviceProvider.GetService>(); + PasswordValidator = serviceProvider.GetService(); + ClaimsIdentityFactory = serviceProvider.GetService>(); + LockoutPolicy = serviceProvider.GetService(); + Store = serviceProvider.GetService>(); + if (Store == null) + { + // TODO: what is the right way to enforce required services + throw new InvalidOperationException(); + } + // TODO: Email/Sms/Token services } /// @@ -132,23 +145,30 @@ namespace Microsoft.AspNet.Identity /// public IUserTokenProvider UserTokenProvider { get; set; } - /// - /// If true, will enable user lockout when users are created - /// - public bool UserLockoutEnabledByDefault { get; set; } + public LockoutPolicy LockoutPolicy { get; set; } - /// - /// Number of access attempts allowed for a user before lockout (if enabled) - /// - public int MaxFailedAccessAttemptsBeforeLockout { get; set; } - - /// - /// Default amount of time an user is locked out for after MaxFailedAccessAttempsBeforeLockout is reached - /// - public TimeSpan DefaultAccountLockoutTimeSpan + private bool UserLockoutEnabledByDefault { - get { return _defaultLockout; } - set { _defaultLockout = value; } + get + { + return LockoutPolicy != null && LockoutPolicy.UserLockoutEnabledByDefault; + } + } + + private int MaxFailedAccessAttemptsBeforeLockout + { + get + { + return LockoutPolicy != null ? LockoutPolicy.MaxFailedAccessAttemptsBeforeLockout : 0; + } + } + + private TimeSpan DefaultAccountLockoutTimeSpan + { + get + { + return LockoutPolicy != null ? LockoutPolicy.DefaultAccountLockoutTimeSpan : TimeSpan.FromMinutes(5); + } } /// diff --git a/src/Microsoft.AspNet.Identity/project.json b/src/Microsoft.AspNet.Identity/project.json index e7215434ee..3158a62019 100644 --- a/src/Microsoft.AspNet.Identity/project.json +++ b/src/Microsoft.AspNet.Identity/project.json @@ -1,6 +1,7 @@ { "version": "0.1-alpha-*", "dependencies": { + "Microsoft.AspNet.ConfigurationModel": "0.1-alpha-*", "Microsoft.AspNet.DependencyInjection" : "0.1-alpha-*", "System.Security.Claims" : "0.1-alpha-*", "Microsoft.AspNet.HttpFeature" : "0.1-alpha-*", diff --git a/temp/Identity45.sln b/temp/Identity45.sln new file mode 100644 index 0000000000..f6601bd62b --- /dev/null +++ b/temp/Identity45.sln @@ -0,0 +1,130 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0.30408.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNet.Identity.net45", "..\src\Microsoft.AspNet.Identity\Microsoft.AspNet.Identity.net45.csproj", "{4D061067-3FE9-442D-81D3-29658DA2FF8F}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{31019886-9CDA-4072-B3D9-E513122CECD0}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNet.Identity.Entity.net45", "..\src\Microsoft.AspNet.Identity.Entity\Microsoft.AspNet.Identity.Entity.net45.csproj", "{1832A433-ABB4-4D87-B7CE-E80E9A3E8CA7}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNet.Identity.InMemory.net45", "..\src\Microsoft.AspNet.Identity.InMemory\Microsoft.AspNet.Identity.InMemory.net45.csproj", "{173CABE9-9FDF-43A0-AF9B-409F8AA2BE56}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNet.Identity.Security.net45", "..\src\Microsoft.AspNet.Identity.Security\Microsoft.AspNet.Identity.Security.net45.csproj", "{720B2280-085C-441D-98CD-B241145A1C12}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{394C0E59-7E24-453E-993C-7B914C62110A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNet.Identity.Test.net45", "..\test\Microsoft.AspNet.Identity.Test\Microsoft.AspNet.Identity.Test.net45.csproj", "{B3A5D740-2C31-4EBC-AADB-356263965C1F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNet.Identity.Security.Test.net45", "..\test\Microsoft.AspNet.Identity.Security.Test\Microsoft.AspNet.Identity.Security.Test.net45.csproj", "{9F67914A-1F35-4068-A21A-F279C4053ADD}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNet.Identity.InMemory.Test.net45", "..\test\Microsoft.AspNet.Identity.InMemory.Test\Microsoft.AspNet.Identity.InMemory.Test.net45.csproj", "{E2154446-8A68-478B-927F-FD05251C8452}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNet.Identity.Entity.Test.net45", "..\test\Microsoft.AspNet.Identity.Entity.Test\Microsoft.AspNet.Identity.Entity.Test.net45.csproj", "{CFCEFA4C-548D-459A-A051-1DBE3F2FF91F}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|Mixed Platforms = Debug|Mixed Platforms + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|Mixed Platforms = Release|Mixed Platforms + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {4D061067-3FE9-442D-81D3-29658DA2FF8F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4D061067-3FE9-442D-81D3-29658DA2FF8F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4D061067-3FE9-442D-81D3-29658DA2FF8F}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {4D061067-3FE9-442D-81D3-29658DA2FF8F}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {4D061067-3FE9-442D-81D3-29658DA2FF8F}.Debug|x86.ActiveCfg = Debug|Any CPU + {4D061067-3FE9-442D-81D3-29658DA2FF8F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4D061067-3FE9-442D-81D3-29658DA2FF8F}.Release|Any CPU.Build.0 = Release|Any CPU + {4D061067-3FE9-442D-81D3-29658DA2FF8F}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {4D061067-3FE9-442D-81D3-29658DA2FF8F}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {4D061067-3FE9-442D-81D3-29658DA2FF8F}.Release|x86.ActiveCfg = Release|Any CPU + {1832A433-ABB4-4D87-B7CE-E80E9A3E8CA7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1832A433-ABB4-4D87-B7CE-E80E9A3E8CA7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1832A433-ABB4-4D87-B7CE-E80E9A3E8CA7}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {1832A433-ABB4-4D87-B7CE-E80E9A3E8CA7}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {1832A433-ABB4-4D87-B7CE-E80E9A3E8CA7}.Debug|x86.ActiveCfg = Debug|Any CPU + {1832A433-ABB4-4D87-B7CE-E80E9A3E8CA7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1832A433-ABB4-4D87-B7CE-E80E9A3E8CA7}.Release|Any CPU.Build.0 = Release|Any CPU + {1832A433-ABB4-4D87-B7CE-E80E9A3E8CA7}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {1832A433-ABB4-4D87-B7CE-E80E9A3E8CA7}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {1832A433-ABB4-4D87-B7CE-E80E9A3E8CA7}.Release|x86.ActiveCfg = Release|Any CPU + {173CABE9-9FDF-43A0-AF9B-409F8AA2BE56}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {173CABE9-9FDF-43A0-AF9B-409F8AA2BE56}.Debug|Any CPU.Build.0 = Debug|Any CPU + {173CABE9-9FDF-43A0-AF9B-409F8AA2BE56}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {173CABE9-9FDF-43A0-AF9B-409F8AA2BE56}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {173CABE9-9FDF-43A0-AF9B-409F8AA2BE56}.Debug|x86.ActiveCfg = Debug|Any CPU + {173CABE9-9FDF-43A0-AF9B-409F8AA2BE56}.Release|Any CPU.ActiveCfg = Release|Any CPU + {173CABE9-9FDF-43A0-AF9B-409F8AA2BE56}.Release|Any CPU.Build.0 = Release|Any CPU + {173CABE9-9FDF-43A0-AF9B-409F8AA2BE56}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {173CABE9-9FDF-43A0-AF9B-409F8AA2BE56}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {173CABE9-9FDF-43A0-AF9B-409F8AA2BE56}.Release|x86.ActiveCfg = Release|Any CPU + {720B2280-085C-441D-98CD-B241145A1C12}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {720B2280-085C-441D-98CD-B241145A1C12}.Debug|Any CPU.Build.0 = Debug|Any CPU + {720B2280-085C-441D-98CD-B241145A1C12}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {720B2280-085C-441D-98CD-B241145A1C12}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {720B2280-085C-441D-98CD-B241145A1C12}.Debug|x86.ActiveCfg = Debug|Any CPU + {720B2280-085C-441D-98CD-B241145A1C12}.Release|Any CPU.ActiveCfg = Release|Any CPU + {720B2280-085C-441D-98CD-B241145A1C12}.Release|Any CPU.Build.0 = Release|Any CPU + {720B2280-085C-441D-98CD-B241145A1C12}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {720B2280-085C-441D-98CD-B241145A1C12}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {720B2280-085C-441D-98CD-B241145A1C12}.Release|x86.ActiveCfg = Release|Any CPU + {B3A5D740-2C31-4EBC-AADB-356263965C1F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B3A5D740-2C31-4EBC-AADB-356263965C1F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B3A5D740-2C31-4EBC-AADB-356263965C1F}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {B3A5D740-2C31-4EBC-AADB-356263965C1F}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {B3A5D740-2C31-4EBC-AADB-356263965C1F}.Debug|x86.ActiveCfg = Debug|Any CPU + {B3A5D740-2C31-4EBC-AADB-356263965C1F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B3A5D740-2C31-4EBC-AADB-356263965C1F}.Release|Any CPU.Build.0 = Release|Any CPU + {B3A5D740-2C31-4EBC-AADB-356263965C1F}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {B3A5D740-2C31-4EBC-AADB-356263965C1F}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {B3A5D740-2C31-4EBC-AADB-356263965C1F}.Release|x86.ActiveCfg = Release|Any CPU + {9F67914A-1F35-4068-A21A-F279C4053ADD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9F67914A-1F35-4068-A21A-F279C4053ADD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9F67914A-1F35-4068-A21A-F279C4053ADD}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {9F67914A-1F35-4068-A21A-F279C4053ADD}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {9F67914A-1F35-4068-A21A-F279C4053ADD}.Debug|x86.ActiveCfg = Debug|Any CPU + {9F67914A-1F35-4068-A21A-F279C4053ADD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9F67914A-1F35-4068-A21A-F279C4053ADD}.Release|Any CPU.Build.0 = Release|Any CPU + {9F67914A-1F35-4068-A21A-F279C4053ADD}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {9F67914A-1F35-4068-A21A-F279C4053ADD}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {9F67914A-1F35-4068-A21A-F279C4053ADD}.Release|x86.ActiveCfg = Release|Any CPU + {E2154446-8A68-478B-927F-FD05251C8452}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E2154446-8A68-478B-927F-FD05251C8452}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E2154446-8A68-478B-927F-FD05251C8452}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {E2154446-8A68-478B-927F-FD05251C8452}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {E2154446-8A68-478B-927F-FD05251C8452}.Debug|x86.ActiveCfg = Debug|Any CPU + {E2154446-8A68-478B-927F-FD05251C8452}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E2154446-8A68-478B-927F-FD05251C8452}.Release|Any CPU.Build.0 = Release|Any CPU + {E2154446-8A68-478B-927F-FD05251C8452}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {E2154446-8A68-478B-927F-FD05251C8452}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {E2154446-8A68-478B-927F-FD05251C8452}.Release|x86.ActiveCfg = Release|Any CPU + {CFCEFA4C-548D-459A-A051-1DBE3F2FF91F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CFCEFA4C-548D-459A-A051-1DBE3F2FF91F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CFCEFA4C-548D-459A-A051-1DBE3F2FF91F}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {CFCEFA4C-548D-459A-A051-1DBE3F2FF91F}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {CFCEFA4C-548D-459A-A051-1DBE3F2FF91F}.Debug|x86.ActiveCfg = Debug|Any CPU + {CFCEFA4C-548D-459A-A051-1DBE3F2FF91F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CFCEFA4C-548D-459A-A051-1DBE3F2FF91F}.Release|Any CPU.Build.0 = Release|Any CPU + {CFCEFA4C-548D-459A-A051-1DBE3F2FF91F}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {CFCEFA4C-548D-459A-A051-1DBE3F2FF91F}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {CFCEFA4C-548D-459A-A051-1DBE3F2FF91F}.Release|x86.ActiveCfg = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {4D061067-3FE9-442D-81D3-29658DA2FF8F} = {31019886-9CDA-4072-B3D9-E513122CECD0} + {1832A433-ABB4-4D87-B7CE-E80E9A3E8CA7} = {31019886-9CDA-4072-B3D9-E513122CECD0} + {173CABE9-9FDF-43A0-AF9B-409F8AA2BE56} = {31019886-9CDA-4072-B3D9-E513122CECD0} + {720B2280-085C-441D-98CD-B241145A1C12} = {31019886-9CDA-4072-B3D9-E513122CECD0} + {B3A5D740-2C31-4EBC-AADB-356263965C1F} = {394C0E59-7E24-453E-993C-7B914C62110A} + {9F67914A-1F35-4068-A21A-F279C4053ADD} = {394C0E59-7E24-453E-993C-7B914C62110A} + {E2154446-8A68-478B-927F-FD05251C8452} = {394C0E59-7E24-453E-993C-7B914C62110A} + {CFCEFA4C-548D-459A-A051-1DBE3F2FF91F} = {394C0E59-7E24-453E-993C-7B914C62110A} + EndGlobalSection +EndGlobal diff --git a/test/Microsoft.AspNet.Identity.Entity.Test/TestIdentityFactory.cs b/test/Microsoft.AspNet.Identity.Entity.Test/TestIdentityFactory.cs index 7d30c54c88..2849cf9806 100644 --- a/test/Microsoft.AspNet.Identity.Entity.Test/TestIdentityFactory.cs +++ b/test/Microsoft.AspNet.Identity.Entity.Test/TestIdentityFactory.cs @@ -81,7 +81,12 @@ namespace Microsoft.AspNet.Identity.Entity.Test public static UserManager CreateManager(EntityContext context) { - return new UserManager(new UserStore(context)); + var manager = new UserManager(new UserStore(context)) + { + UserValidator = new UserValidator(), + PasswordValidator = new PasswordValidator() + }; + return manager; } public static UserManager CreateManager() diff --git a/test/Microsoft.AspNet.Identity.Entity.Test/UserStoreTest.cs b/test/Microsoft.AspNet.Identity.Entity.Test/UserStoreTest.cs index a6f195e9a1..1ef3a2ed02 100644 --- a/test/Microsoft.AspNet.Identity.Entity.Test/UserStoreTest.cs +++ b/test/Microsoft.AspNet.Identity.Entity.Test/UserStoreTest.cs @@ -16,6 +16,58 @@ namespace Microsoft.AspNet.Identity.Entity.Test { public class UserStoreTest { + class ApplicationUserManager : UserManager + { + public ApplicationUserManager(IServiceProvider services) : base(services) { } + } + + [Fact] + public async Task CanUseAddedManagerInstance() + { + var services = new ServiceCollection(); + var store = new UserStore(new IdentityContext()); + services.AddInstance>(new UserManager(store)); + var provider = services.BuildServiceProvider(); + var manager = provider.GetService>(); + Assert.NotNull(manager); + IdentityResultAssert.IsSuccess(await manager.CreateAsync(new EntityUser("hello"))); + } + + [Fact] + public async Task CanUseSingletonManagerInstance() + { + var services = new ServiceCollection(); + var store = new UserStore(new IdentityContext()); + services.AddIdentity(s => + { + s.UseUserStore(() => store); + s.UseUserManager(); + }); + //services.AddSingleton(); + + var provider = services.BuildServiceProvider(); + var manager = provider.GetService(); + Assert.NotNull(manager); + IdentityResultAssert.IsSuccess(await manager.CreateAsync(new EntityUser("hello"))); + } + + //[Fact] + //public async Task CanUseSingletonGenericManagerInstance() + //{ + // var services = new ServiceCollection(); + // var store = new UserStore(new IdentityContext()); + // services.AddIdentity(s => + // { + // s.UseStore(() => store); + // s.UseManager>(); + // }); + + // var provider = services.BuildServiceProvider(); + // var manager = provider.GetService>(); + // Assert.NotNull(manager); + // IdentityResultAssert.IsSuccess(await manager.CreateAsync(new EntityUser("hello"))); + //} + [Fact] public async Task UserStoreMethodsThrowWhenDisposedTest() { @@ -723,8 +775,11 @@ namespace Microsoft.AspNet.Identity.Entity.Test public async Task SingleFailureLockout() { var mgr = TestIdentityFactory.CreateManager(); - mgr.DefaultAccountLockoutTimeSpan = TimeSpan.FromHours(1); - mgr.UserLockoutEnabledByDefault = true; + mgr.LockoutPolicy = new LockoutPolicy + { + DefaultAccountLockoutTimeSpan = TimeSpan.FromHours(1), + UserLockoutEnabledByDefault = true, + }; var user = new EntityUser("fastLockout"); IdentityResultAssert.IsSuccess(await mgr.CreateAsync(user)); Assert.True(await mgr.GetLockoutEnabledAsync(user)); @@ -740,9 +795,12 @@ namespace Microsoft.AspNet.Identity.Entity.Test public async Task TwoFailureLockout() { var mgr = TestIdentityFactory.CreateManager(); - mgr.DefaultAccountLockoutTimeSpan = TimeSpan.FromHours(1); - mgr.UserLockoutEnabledByDefault = true; - mgr.MaxFailedAccessAttemptsBeforeLockout = 2; + mgr.LockoutPolicy = new LockoutPolicy + { + DefaultAccountLockoutTimeSpan = TimeSpan.FromHours(1), + UserLockoutEnabledByDefault = true, + MaxFailedAccessAttemptsBeforeLockout = 2 + }; var user = new EntityUser("twoFailureLockout"); IdentityResultAssert.IsSuccess(await mgr.CreateAsync(user)); Assert.True(await mgr.GetLockoutEnabledAsync(user)); @@ -762,9 +820,12 @@ namespace Microsoft.AspNet.Identity.Entity.Test public async Task ResetAccessCountPreventsLockout() { var mgr = TestIdentityFactory.CreateManager(); - mgr.DefaultAccountLockoutTimeSpan = TimeSpan.FromHours(1); - mgr.UserLockoutEnabledByDefault = true; - mgr.MaxFailedAccessAttemptsBeforeLockout = 2; + mgr.LockoutPolicy = new LockoutPolicy + { + DefaultAccountLockoutTimeSpan = TimeSpan.FromHours(1), + UserLockoutEnabledByDefault = true, + MaxFailedAccessAttemptsBeforeLockout = 2 + }; var user = new EntityUser("resetLockout"); IdentityResultAssert.IsSuccess(await mgr.CreateAsync(user)); Assert.True(await mgr.GetLockoutEnabledAsync(user)); @@ -788,8 +849,11 @@ namespace Microsoft.AspNet.Identity.Entity.Test public async Task CanEnableLockoutManuallyAndLockout() { var mgr = TestIdentityFactory.CreateManager(); - mgr.DefaultAccountLockoutTimeSpan = TimeSpan.FromHours(1); - mgr.MaxFailedAccessAttemptsBeforeLockout = 2; + mgr.LockoutPolicy = new LockoutPolicy + { + DefaultAccountLockoutTimeSpan = TimeSpan.FromHours(1), + MaxFailedAccessAttemptsBeforeLockout = 2 + }; var user = new EntityUser("manualLockout"); IdentityResultAssert.IsSuccess(await mgr.CreateAsync(user)); Assert.False(await mgr.GetLockoutEnabledAsync(user)); @@ -812,7 +876,10 @@ namespace Microsoft.AspNet.Identity.Entity.Test public async Task UserNotLockedOutWithNullDateTimeAndIsSetToNullDate() { var mgr = TestIdentityFactory.CreateManager(); - mgr.UserLockoutEnabledByDefault = true; + mgr.LockoutPolicy = new LockoutPolicy + { + UserLockoutEnabledByDefault = true, + }; var user = new EntityUser("LockoutTest"); IdentityResultAssert.IsSuccess(await mgr.CreateAsync(user)); Assert.True(await mgr.GetLockoutEnabledAsync(user)); @@ -840,7 +907,10 @@ namespace Microsoft.AspNet.Identity.Entity.Test public async Task LockoutEndToUtcNowMinus1SecInUserShouldNotBeLockedOut() { var mgr = TestIdentityFactory.CreateManager(); - mgr.UserLockoutEnabledByDefault = true; + mgr.LockoutPolicy = new LockoutPolicy + { + UserLockoutEnabledByDefault = true, + }; var user = new EntityUser("LockoutUtcNowTest") { LockoutEnd = DateTime.UtcNow.AddSeconds(-1) }; IdentityResultAssert.IsSuccess(await mgr.CreateAsync(user)); Assert.True(await mgr.GetLockoutEnabledAsync(user)); @@ -852,7 +922,10 @@ namespace Microsoft.AspNet.Identity.Entity.Test public async Task LockoutEndToUtcNowSubOneSecondWithManagerShouldNotBeLockedOut() { var mgr = TestIdentityFactory.CreateManager(); - mgr.UserLockoutEnabledByDefault = true; + mgr.LockoutPolicy = new LockoutPolicy + { + UserLockoutEnabledByDefault = true, + }; var user = new EntityUser("LockoutUtcNowTest"); IdentityResultAssert.IsSuccess(await mgr.CreateAsync(user)); Assert.True(await mgr.GetLockoutEnabledAsync(user)); @@ -865,7 +938,10 @@ namespace Microsoft.AspNet.Identity.Entity.Test public async Task LockoutEndToUtcNowPlus5ShouldBeLockedOut() { var mgr = TestIdentityFactory.CreateManager(); - mgr.UserLockoutEnabledByDefault = true; + mgr.LockoutPolicy = new LockoutPolicy + { + UserLockoutEnabledByDefault = true, + }; var user = new EntityUser("LockoutUtcNowTest") { LockoutEnd = DateTime.UtcNow.AddMinutes(5) }; IdentityResultAssert.IsSuccess(await mgr.CreateAsync(user)); Assert.True(await mgr.GetLockoutEnabledAsync(user)); @@ -877,7 +953,10 @@ namespace Microsoft.AspNet.Identity.Entity.Test public async Task UserLockedOutWithDateTimeLocalKindNowPlus30() { var mgr = TestIdentityFactory.CreateManager(); - mgr.UserLockoutEnabledByDefault = true; + mgr.LockoutPolicy = new LockoutPolicy + { + UserLockoutEnabledByDefault = true, + }; var user = new EntityUser("LockoutTest"); IdentityResultAssert.IsSuccess(await mgr.CreateAsync(user)); Assert.True(await mgr.GetLockoutEnabledAsync(user)); diff --git a/test/Microsoft.AspNet.Identity.Entity.Test/project.json b/test/Microsoft.AspNet.Identity.Entity.Test/project.json index d959fe3618..bc65355683 100644 --- a/test/Microsoft.AspNet.Identity.Entity.Test/project.json +++ b/test/Microsoft.AspNet.Identity.Entity.Test/project.json @@ -6,14 +6,15 @@ "Microsoft.AspNet.ConfigurationModel": "0.1-alpha-*", "Microsoft.AspNet.Identity": "", "Microsoft.AspNet.Identity.Entity": "", - "Microsoft.AspNet.DependencyInjection": "0.1-alpha-*", + "Microsoft.AspNet.PipelineCore": "0.1-alpha-*", "Microsoft.AspNet.Logging": "0.1-alpha-*", + "Microsoft.AspNet.RequestContainer": "0.1-alpha-*", "Microsoft.AspNet.Security.DataProtection": "0.1-alpha-*", "Microsoft.AspNet.Testing": "0.1-alpha-*", "Microsoft.Data.Entity": "0.1-alpha-*", "Microsoft.Data.InMemory": "0.1-alpha-*", "Microsoft.Data.Relational": "0.1-alpha-*", - "Microsoft.Data.SqlServer": "0.1-pre-*", + "Remotion.Linq": "1.16-alpha", "System.Security.Claims": "0.1-alpha-*", "Xunit.KRunner": "0.1-alpha-*", "xunit.abstractions": "2.0.0-aspnet-*", diff --git a/test/Microsoft.AspNet.Identity.InMemory.Test/InMemoryStoreTest.cs b/test/Microsoft.AspNet.Identity.InMemory.Test/InMemoryStoreTest.cs index 507923e817..be28e16fd4 100644 --- a/test/Microsoft.AspNet.Identity.InMemory.Test/InMemoryStoreTest.cs +++ b/test/Microsoft.AspNet.Identity.InMemory.Test/InMemoryStoreTest.cs @@ -559,8 +559,11 @@ namespace Microsoft.AspNet.Identity.InMemory.Test public async Task SingleFailureLockout() { var mgr = CreateManager(); - mgr.DefaultAccountLockoutTimeSpan = TimeSpan.FromHours(1); - mgr.UserLockoutEnabledByDefault = true; + mgr.LockoutPolicy = new LockoutPolicy + { + DefaultAccountLockoutTimeSpan = TimeSpan.FromHours(1), + UserLockoutEnabledByDefault = true + }; var user = new IdentityUser("fastLockout"); IdentityResultAssert.IsSuccess(await mgr.CreateAsync(user)); Assert.True(await mgr.GetLockoutEnabledAsync(user)); @@ -576,9 +579,12 @@ namespace Microsoft.AspNet.Identity.InMemory.Test public async Task TwoFailureLockout() { var mgr = CreateManager(); - mgr.DefaultAccountLockoutTimeSpan = TimeSpan.FromHours(1); - mgr.UserLockoutEnabledByDefault = true; - mgr.MaxFailedAccessAttemptsBeforeLockout = 2; + mgr.LockoutPolicy = new LockoutPolicy + { + DefaultAccountLockoutTimeSpan = TimeSpan.FromHours(1), + UserLockoutEnabledByDefault = true, + MaxFailedAccessAttemptsBeforeLockout = 2 + }; var user = new IdentityUser("twoFailureLockout"); IdentityResultAssert.IsSuccess(await mgr.CreateAsync(user)); Assert.True(await mgr.GetLockoutEnabledAsync(user)); @@ -598,9 +604,12 @@ namespace Microsoft.AspNet.Identity.InMemory.Test public async Task ResetAccessCountPreventsLockout() { var mgr = CreateManager(); - mgr.DefaultAccountLockoutTimeSpan = TimeSpan.FromHours(1); - mgr.UserLockoutEnabledByDefault = true; - mgr.MaxFailedAccessAttemptsBeforeLockout = 2; + mgr.LockoutPolicy = new LockoutPolicy + { + DefaultAccountLockoutTimeSpan = TimeSpan.FromHours(1), + UserLockoutEnabledByDefault = true, + MaxFailedAccessAttemptsBeforeLockout = 2 + }; var user = new IdentityUser("resetLockout"); IdentityResultAssert.IsSuccess(await mgr.CreateAsync(user)); Assert.True(await mgr.GetLockoutEnabledAsync(user)); @@ -624,8 +633,11 @@ namespace Microsoft.AspNet.Identity.InMemory.Test public async Task CanEnableLockoutManuallyAndLockout() { var mgr = CreateManager(); - mgr.DefaultAccountLockoutTimeSpan = TimeSpan.FromHours(1); - mgr.MaxFailedAccessAttemptsBeforeLockout = 2; + mgr.LockoutPolicy = new LockoutPolicy + { + DefaultAccountLockoutTimeSpan = TimeSpan.FromHours(1), + MaxFailedAccessAttemptsBeforeLockout = 2 + }; var user = new IdentityUser("manualLockout"); IdentityResultAssert.IsSuccess(await mgr.CreateAsync(user)); Assert.False(await mgr.GetLockoutEnabledAsync(user)); @@ -648,7 +660,10 @@ namespace Microsoft.AspNet.Identity.InMemory.Test public async Task UserNotLockedOutWithNullDateTimeAndIsSetToNullDate() { var mgr = CreateManager(); - mgr.UserLockoutEnabledByDefault = true; + mgr.LockoutPolicy = new LockoutPolicy + { + UserLockoutEnabledByDefault = true, + }; var user = new IdentityUser("LockoutTest"); IdentityResultAssert.IsSuccess(await mgr.CreateAsync(user)); Assert.True(await mgr.GetLockoutEnabledAsync(user)); @@ -676,8 +691,11 @@ namespace Microsoft.AspNet.Identity.InMemory.Test public async Task LockoutEndToUtcNowMinus1SecInUserShouldNotBeLockedOut() { var mgr = CreateManager(); - mgr.UserLockoutEnabledByDefault = true; - var user = new IdentityUser("LockoutUtcNowTest") {LockoutEnd = DateTimeOffset.UtcNow.AddSeconds(-1)}; + mgr.LockoutPolicy = new LockoutPolicy + { + UserLockoutEnabledByDefault = true, + }; + var user = new IdentityUser("LockoutUtcNowTest") { LockoutEnd = DateTimeOffset.UtcNow.AddSeconds(-1) }; IdentityResultAssert.IsSuccess(await mgr.CreateAsync(user)); Assert.True(await mgr.GetLockoutEnabledAsync(user)); Assert.True(user.LockoutEnabled); @@ -688,7 +706,10 @@ namespace Microsoft.AspNet.Identity.InMemory.Test public async Task LockoutEndToUtcNowSubOneSecondWithManagerShouldNotBeLockedOut() { var mgr = CreateManager(); - mgr.UserLockoutEnabledByDefault = true; + mgr.LockoutPolicy = new LockoutPolicy + { + UserLockoutEnabledByDefault = true, + }; var user = new IdentityUser("LockoutUtcNowTest"); IdentityResultAssert.IsSuccess(await mgr.CreateAsync(user)); Assert.True(await mgr.GetLockoutEnabledAsync(user)); @@ -701,8 +722,11 @@ namespace Microsoft.AspNet.Identity.InMemory.Test public async Task LockoutEndToUtcNowPlus5ShouldBeLockedOut() { var mgr = CreateManager(); - mgr.UserLockoutEnabledByDefault = true; - var user = new IdentityUser("LockoutUtcNowTest") {LockoutEnd = DateTimeOffset.UtcNow.AddMinutes(5)}; + mgr.LockoutPolicy = new LockoutPolicy + { + UserLockoutEnabledByDefault = true, + }; + var user = new IdentityUser("LockoutUtcNowTest") { LockoutEnd = DateTimeOffset.UtcNow.AddMinutes(5) }; IdentityResultAssert.IsSuccess(await mgr.CreateAsync(user)); Assert.True(await mgr.GetLockoutEnabledAsync(user)); Assert.True(user.LockoutEnabled); @@ -713,7 +737,10 @@ namespace Microsoft.AspNet.Identity.InMemory.Test public async Task UserLockedOutWithDateTimeLocalKindNowPlus30() { var mgr = CreateManager(); - mgr.UserLockoutEnabledByDefault = true; + mgr.LockoutPolicy = new LockoutPolicy + { + UserLockoutEnabledByDefault = true, + }; var user = new IdentityUser("LockoutTest"); IdentityResultAssert.IsSuccess(await mgr.CreateAsync(user)); Assert.True(await mgr.GetLockoutEnabledAsync(user)); @@ -1431,7 +1458,12 @@ namespace Microsoft.AspNet.Identity.InMemory.Test private static UserManager CreateManager() { - return new UserManager(new InMemoryUserStore()); + var manager = new UserManager(new InMemoryUserStore()) + { + UserValidator = new UserValidator(), + PasswordValidator = new PasswordValidator() + }; + return manager; } private static RoleManager CreateRoleManager() diff --git a/test/Microsoft.AspNet.Identity.InMemory.Test/StartupTest.cs b/test/Microsoft.AspNet.Identity.InMemory.Test/StartupTest.cs new file mode 100644 index 0000000000..0f376115b9 --- /dev/null +++ b/test/Microsoft.AspNet.Identity.InMemory.Test/StartupTest.cs @@ -0,0 +1,70 @@ +using Microsoft.AspNet.Abstractions; +using Microsoft.AspNet.DependencyInjection; +using Microsoft.AspNet.DependencyInjection.Fallback; +using Microsoft.AspNet.PipelineCore; +using System; +using System.Threading.Tasks; +using Xunit; + +namespace Microsoft.AspNet.Identity.InMemory.Test +{ + public class StartupTest + { + + [Fact] + public async Task EnsureStartupUsageWorks() + { + IBuilder builder = new Builder(new ServiceCollection().BuildServiceProvider()); + + builder.UseServices(services => services.AddIdentity(s => + { + s.UseUserStore(() => new InMemoryUserStore()); + s.UseUserManager(); + s.UseRoleStore(() => new InMemoryRoleStore()); + s.UseRoleManager(); + })); + + var userStore = builder.ApplicationServices.GetService>(); + var roleStore = builder.ApplicationServices.GetService>(); + var userManager = builder.ApplicationServices.GetService(); + var roleManager = builder.ApplicationServices.GetService(); + + Assert.NotNull(userStore); + Assert.NotNull(userManager); + Assert.NotNull(roleStore); + Assert.NotNull(roleManager); + + await CreateAdminUser(builder.ApplicationServices); + } + + private static async Task CreateAdminUser(IServiceProvider serviceProvider) + { + const string userName = "admin"; + const string roleName = "Admins"; + const string password = "1qaz@WSX"; + var userManager = serviceProvider.GetService(); + var roleManager = serviceProvider.GetService(); + + var user = new ApplicationUser { UserName = userName }; + IdentityResultAssert.IsSuccess(await userManager.CreateAsync(user, password)); + IdentityResultAssert.IsSuccess(await roleManager.CreateAsync(new IdentityRole { Name = roleName })); + IdentityResultAssert.IsSuccess(await userManager.AddToRoleAsync(user, roleName)); + } + + + public class ApplicationUserManager : UserManager + { + public ApplicationUserManager(IServiceProvider services) : base(services) { } + } + + public class ApplicationRoleManager : RoleManager + { + public ApplicationRoleManager(IServiceProvider services) : base(services) { } + } + + public class ApplicationUser : IdentityUser + { + } + + } +} \ No newline at end of file diff --git a/test/Microsoft.AspNet.Identity.InMemory.Test/project.json b/test/Microsoft.AspNet.Identity.InMemory.Test/project.json index 1c84e17d97..64d5006a6f 100644 --- a/test/Microsoft.AspNet.Identity.InMemory.Test/project.json +++ b/test/Microsoft.AspNet.Identity.InMemory.Test/project.json @@ -1,9 +1,13 @@ { "version": "0.1-alpha-*", "dependencies": { - "Microsoft.AspNet.Identity" : "", - "Microsoft.AspNet.Identity.InMemory" : "", + "Microsoft.AspNet.Abstractions" : "0.1-alpha-*", + "Microsoft.AspNet.ConfigurationModel" : "0.1-alpha-*", "Microsoft.AspNet.DependencyInjection" : "0.1-alpha-*", + "Microsoft.AspNet.Identity" : "0.1-alpha-*", + "Microsoft.AspNet.Identity.InMemory" : "0.1-alpha-*", + "Microsoft.AspNet.PipelineCore" : "0.1-alpha-*", + "Microsoft.AspNet.RequestContainer" : "0.1-alpha-*", "Microsoft.AspNet.Testing" : "0.1-alpha-*", "Xunit.KRunner": "0.1-alpha-*", "xunit.abstractions": "2.0.0-aspnet-*", diff --git a/test/Microsoft.AspNet.Identity.Test/IdentityBuilderTest.cs b/test/Microsoft.AspNet.Identity.Test/IdentityBuilderTest.cs new file mode 100644 index 0000000000..8078553820 --- /dev/null +++ b/test/Microsoft.AspNet.Identity.Test/IdentityBuilderTest.cs @@ -0,0 +1,90 @@ +using System.Security.Claims; +using Microsoft.AspNet.DependencyInjection; +using Microsoft.AspNet.DependencyInjection.Fallback; +using Xunit; + +namespace Microsoft.AspNet.Identity.Test +{ + public class IdentityBuilderTest + { + [Fact] + public void CanSpecifyUserValidatorInstance() + { + var services = new ServiceCollection(); + var validator = new UserValidator(); + services.AddIdentity(b => b.UseUserValidator(() => validator)); + Assert.Equal(validator, services.BuildServiceProvider().GetService>()); + } + + [Fact] + public void CanSpecifyPasswordValidatorInstance() + { + var services = new ServiceCollection(); + var validator = new PasswordValidator(); + services.AddIdentity(b => b.UsePasswordValidator(() => validator)); + Assert.Equal(validator, services.BuildServiceProvider().GetService()); + } + + [Fact] + public void CanSpecifyLockoutPolicyInstance() + { + var services = new ServiceCollection(); + var policy = new LockoutPolicy(); + services.AddIdentity(b => b.UseLockoutPolicy(() => policy)); + Assert.Equal(policy, services.BuildServiceProvider().GetService()); + } + + [Fact] + public void CanSpecifyPasswordHasherInstance() + { + CanOverride(); + } + + [Fact] + public void CanSpecifyClaimsIdentityFactoryInstance() + { + CanOverride, ClaimsIdentityFactory>(); + } + + [Fact] + public void EnsureDefaultServices() + { + var services = new ServiceCollection(); + var builder = new IdentityBuilder(services); + builder.UseIdentity(); + + var provider = services.BuildServiceProvider(); + var userValidator = provider.GetService>() as UserValidator; + Assert.NotNull(userValidator); + Assert.True(userValidator.AllowOnlyAlphanumericUserNames); + Assert.False(userValidator.RequireUniqueEmail); + + var pwdValidator = provider.GetService() as PasswordValidator; + Assert.NotNull(userValidator); + Assert.True(pwdValidator.RequireDigit); + Assert.True(pwdValidator.RequireLowercase); + Assert.True(pwdValidator.RequireNonLetterOrDigit); + Assert.True(pwdValidator.RequireUppercase); + Assert.Equal(6, pwdValidator.RequiredLength); + + var hasher = provider.GetService() as PasswordHasher; + Assert.NotNull(hasher); + + var claimsFactory = provider.GetService>() as ClaimsIdentityFactory; + Assert.NotNull(claimsFactory); + Assert.Equal(ClaimTypes.Role, claimsFactory.RoleClaimType); + Assert.Equal(ClaimsIdentityFactory.DefaultSecurityStampClaimType, claimsFactory.SecurityStampClaimType); + Assert.Equal(ClaimTypes.Name, claimsFactory.UserNameClaimType); + Assert.Equal(ClaimTypes.NameIdentifier, claimsFactory.UserIdClaimType); + } + + private static void CanOverride() where TImplementation : TService,new() + { + var services = new ServiceCollection(); + var instance = new TImplementation(); + services.AddIdentity(b => b.Use(() => instance)); + Assert.Equal(instance, services.BuildServiceProvider().GetService()); + } + + } +} \ No newline at end of file diff --git a/test/Microsoft.AspNet.Identity.Test/RoleManagerTest.cs b/test/Microsoft.AspNet.Identity.Test/RoleManagerTest.cs index 7c4687605b..8e17a87533 100644 --- a/test/Microsoft.AspNet.Identity.Test/RoleManagerTest.cs +++ b/test/Microsoft.AspNet.Identity.Test/RoleManagerTest.cs @@ -11,7 +11,7 @@ namespace Microsoft.AspNet.Identity.Test [Fact] public void ConstructorThrowsWithNullStore() { - Assert.Throws("store", () => new RoleManager(null)); + Assert.Throws("store", () => new RoleManager((IRoleStore)null)); } [Fact] @@ -34,8 +34,9 @@ namespace Microsoft.AspNet.Identity.Test public async Task RoleManagerPublicNullChecks() { Assert.Throws("store", - () => new RoleManager(null)); + () => new RoleManager((IRoleStore)null)); var manager = new RoleManager(new NotImplementedStore()); + Assert.Throws("services", () => manager.Initialize(null)); await Assert.ThrowsAsync("role", async () => await manager.CreateAsync(null)); await Assert.ThrowsAsync("role", async () => await manager.UpdateAsync(null)); await Assert.ThrowsAsync("role", async () => await manager.DeleteAsync(null)); diff --git a/test/Microsoft.AspNet.Identity.Test/TestServices.cs b/test/Microsoft.AspNet.Identity.Test/TestServices.cs deleted file mode 100644 index e8665e3258..0000000000 --- a/test/Microsoft.AspNet.Identity.Test/TestServices.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Microsoft.AspNet.DependencyInjection; -using System.Collections.Generic; - -namespace Microsoft.AspNet.Identity.Test -{ - public static class TestServices - { - public static IEnumerable DefaultServices() - where TUser : class - { - var describer = new ServiceDescriber(); - yield return describer.Transient(); - yield return describer.Transient, UserValidator>(); - yield return describer.Transient(); - yield return describer.Transient, ClaimsIdentityFactory>(); - yield return describer.Transient, NoopUserStore>(); - } - - } -} \ No newline at end of file diff --git a/test/Microsoft.AspNet.Identity.Test/UserManagerTest.cs b/test/Microsoft.AspNet.Identity.Test/UserManagerTest.cs index 1690ee5b1f..dc48be66b0 100644 --- a/test/Microsoft.AspNet.Identity.Test/UserManagerTest.cs +++ b/test/Microsoft.AspNet.Identity.Test/UserManagerTest.cs @@ -1,3 +1,4 @@ +using Microsoft.AspNet.DependencyInjection; using Microsoft.AspNet.DependencyInjection.Fallback; using Moq; using System; @@ -20,13 +21,19 @@ namespace Microsoft.AspNet.Identity.Test } [Fact] - public void ServiceProviderWireupTest() + public void EnsureDefaultServicesDefaultsWithStoreWorks() { - var manager = new TestManager(TestServices.DefaultServices().BuildServiceProvider()); + var services = new ServiceCollection {IdentityServices.GetDefaultUserServices()}; + services.AddInstance>(new NoopUserStore()); + var manager = new TestManager(services.BuildServiceProvider()); Assert.NotNull(manager.PasswordHasher); Assert.NotNull(manager.PasswordValidator); Assert.NotNull(manager.UserValidator); Assert.NotNull(manager.StorePublic); + Assert.NotNull(manager.LockoutPolicy); + Assert.Equal(TimeSpan.FromMinutes(5), manager.LockoutPolicy.DefaultAccountLockoutTimeSpan); + Assert.Equal(5, manager.LockoutPolicy.MaxFailedAccessAttemptsBeforeLockout); + Assert.False(manager.LockoutPolicy.UserLockoutEnabledByDefault); } #if NET45 @@ -419,13 +426,12 @@ namespace Microsoft.AspNet.Identity.Test [Fact] public async Task ManagerPublicNullChecks() { - Assert.Throws("store", - () => new UserManager((IUserStore) null)); Assert.Throws("serviceProvider", () => new UserManager((IServiceProvider)null)); var manager = new UserManager(new NotImplementedStore()); Assert.Throws(() => manager.ClaimsIdentityFactory = null); Assert.Throws(() => manager.PasswordHasher = null); + Assert.Throws("serviceProvider", () => manager.Initialize(null)); await Assert.ThrowsAsync("user", async () => await manager.CreateIdentityAsync(null, "whatever")); diff --git a/test/Microsoft.AspNet.Identity.Test/project.json b/test/Microsoft.AspNet.Identity.Test/project.json index 93c8d50651..3619ac420d 100644 --- a/test/Microsoft.AspNet.Identity.Test/project.json +++ b/test/Microsoft.AspNet.Identity.Test/project.json @@ -3,7 +3,7 @@ "dependencies": { "Microsoft.AspNet.ConfigurationModel" : "0.1-alpha-*", "Microsoft.AspNet.DependencyInjection" : "0.1-alpha-*", - "Microsoft.AspNet.Identity" : "", + "Microsoft.AspNet.Identity" : "0.1-alpha-*", "Microsoft.AspNet.Testing" : "0.1-alpha-*", "Xunit.KRunner": "0.1-alpha-*", "xunit.abstractions": "2.0.0-aspnet-*",