From e6f3ebf5810c793edc6f3b4ca3438194786b86a2 Mon Sep 17 00:00:00 2001 From: Hao Kung Date: Tue, 23 May 2017 11:21:39 -0700 Subject: [PATCH] Refactor Identity into Core + Stores --- Identity.sln | 30 + .../Controllers/AccountController.cs | 9 +- .../IdentitySample.Mvc.csproj | 2 - .../Models/ApplicationUser.cs | 2 +- .../Models/ManageViewModels/IndexViewModel.cs | 3 - samples/IdentitySample.Mvc/Startup.cs | 1 + .../IdentityDbContext.cs | 46 +- ...etCore.Identity.EntityFrameworkCore.csproj | 1 + .../UserStore.cs | 868 +------------ .../breakingchanges.netcore.json | 135 +- .../IdentityServiceDbContext.cs | 13 +- .../IdentityServiceOptionsSetup.cs | 2 +- ...ntityServiceServiceCollectionExtensions.cs | 4 +- .../IdentitySpecificationTestBase.cs | 6 +- .../AspNetRoleManager.cs | 45 + .../AspNetUserManager.cs | 54 + .../DataProtectionTokenProvider.cs | 1 - .../IdentityBuilder.cs | 8 +- .../IdentityConstants.cs | 32 + .../IdentityCookieOptions.cs | 83 -- .../IdentityServiceCollectionExtensions.cs | 28 +- .../Microsoft.AspNetCore.Identity.csproj | 4 + .../PasswordHasher.cs | 4 +- .../Properties/Resources.Designer.cs | 708 +--------- .../Resources.resx | 176 --- .../SecurityStampValidator.cs | 10 +- .../SecurityStampValidatorOptions.cs | 27 + .../SignInManager.cs | 36 +- .../TotpSecurityStampBasedTokenProvider.cs | 1 - .../UpperInvariantLookupNormalizer.cs | 2 - .../UserClaimsPrincipalFactory.cs | 2 +- .../Base32.cs | 119 ++ .../ClaimsIdentityOptions.cs | 0 .../ILookupNormalizer.cs | 0 .../IPasswordHasher.cs | 0 .../IPasswordValidator.cs | 0 .../IQueryableRoleStore.cs | 0 .../IQueryableUserStore.cs | 0 .../IRoleClaimStore.cs | 0 .../IRoleStore.cs | 0 .../IRoleValidator.cs | 0 .../IUserAuthenticationTokenStore.cs | 0 .../IUserAuthenticatorInfoStore.cs | 0 .../IUserClaimStore.cs | 0 .../IUserClaimsPrincipalFactory.cs | 0 .../IUserEmailStore.cs | 0 .../IUserLockoutStore.cs | 0 .../IUserLoginStore.cs | 0 .../IUserPasswordStore.cs | 0 .../IUserPhoneNumberStore.cs | 0 .../IUserRoleStore.cs | 0 .../IUserSecurityStampStore.cs | 0 .../IUserStore.cs | 0 .../IUserTwoFactorRecoveryCodeStore.cs | 0 .../IUserTwoFactorStore.cs | 0 .../IUserTwoFactorTokenProvider.cs | 0 .../IUserValidator.cs | 0 .../IdentityError.cs | 0 .../IdentityErrorDescriber.cs | 0 .../IdentityOptions.cs | 23 - .../IdentityResult.cs | 0 .../LockoutOptions.cs | 0 .../Microsoft.Extensions.Identity.Core.csproj | 24 + .../PasswordHasherCompatibilityMode.cs | 0 .../PasswordOptions.cs | 0 .../PasswordVerificationResult.cs | 0 .../PrincipalExtensions.cs | 0 .../Properties/AssemblyInfo.cs | 10 + .../Properties/Resources.Designer.cs | 782 +++++++++++ .../Resources.resx | 308 +++++ .../RoleManager.cs | 17 +- .../SignInOptions.cs | 0 .../SignInResult.cs | 2 - .../TokenOptions.cs | 22 +- .../TokenProviderDescriptor.cs | 0 .../UserLoginInfo.cs | 0 .../UserManager.cs | 49 +- .../UserOptions.cs | 0 .../IdentityRole.cs | 12 +- .../IdentityRoleClaim.cs | 2 +- .../IdentityUser.cs | 22 +- .../IdentityUserClaim.cs | 2 +- .../IdentityUserLogin.cs | 2 +- .../IdentityUserRole.cs | 2 +- .../IdentityUserToken.cs | 2 +- ...icrosoft.Extensions.Identity.Stores.csproj | 28 + .../RoleStoreBase.cs | 272 ++++ .../UserStoreBase.cs | 1142 +++++++++++++++++ .../DefaultPocoTest.cs | 122 -- .../ControllerTest.cs | 2 +- .../FunctionalTest.cs | 6 +- .../IdentityBuilderTest.cs | 2 +- .../IdentityResultTest.cs | 1 - .../RoleManagerTest.cs | 2 +- .../SecurityStampValidatorTest.cs | 66 +- .../SignInManagerTest.cs | 63 +- .../UserClaimsPrincipalFactoryTest.cs | 2 +- .../UserManagerTest.cs | 9 +- test/Shared/MockHelpers.cs | 7 +- 99 files changed, 3236 insertions(+), 2231 deletions(-) create mode 100644 src/Microsoft.AspNetCore.Identity/AspNetRoleManager.cs create mode 100644 src/Microsoft.AspNetCore.Identity/AspNetUserManager.cs create mode 100644 src/Microsoft.AspNetCore.Identity/IdentityConstants.cs delete mode 100644 src/Microsoft.AspNetCore.Identity/IdentityCookieOptions.cs create mode 100644 src/Microsoft.AspNetCore.Identity/SecurityStampValidatorOptions.cs create mode 100644 src/Microsoft.Extensions.Identity.Core/Base32.cs rename src/{Microsoft.AspNetCore.Identity => Microsoft.Extensions.Identity.Core}/ClaimsIdentityOptions.cs (100%) rename src/{Microsoft.AspNetCore.Identity => Microsoft.Extensions.Identity.Core}/ILookupNormalizer.cs (100%) rename src/{Microsoft.AspNetCore.Identity => Microsoft.Extensions.Identity.Core}/IPasswordHasher.cs (100%) rename src/{Microsoft.AspNetCore.Identity => Microsoft.Extensions.Identity.Core}/IPasswordValidator.cs (100%) rename src/{Microsoft.AspNetCore.Identity => Microsoft.Extensions.Identity.Core}/IQueryableRoleStore.cs (100%) rename src/{Microsoft.AspNetCore.Identity => Microsoft.Extensions.Identity.Core}/IQueryableUserStore.cs (100%) rename src/{Microsoft.AspNetCore.Identity => Microsoft.Extensions.Identity.Core}/IRoleClaimStore.cs (100%) rename src/{Microsoft.AspNetCore.Identity => Microsoft.Extensions.Identity.Core}/IRoleStore.cs (100%) rename src/{Microsoft.AspNetCore.Identity => Microsoft.Extensions.Identity.Core}/IRoleValidator.cs (100%) rename src/{Microsoft.AspNetCore.Identity => Microsoft.Extensions.Identity.Core}/IUserAuthenticationTokenStore.cs (100%) rename src/{Microsoft.AspNetCore.Identity => Microsoft.Extensions.Identity.Core}/IUserAuthenticatorInfoStore.cs (100%) rename src/{Microsoft.AspNetCore.Identity => Microsoft.Extensions.Identity.Core}/IUserClaimStore.cs (100%) rename src/{Microsoft.AspNetCore.Identity => Microsoft.Extensions.Identity.Core}/IUserClaimsPrincipalFactory.cs (100%) rename src/{Microsoft.AspNetCore.Identity => Microsoft.Extensions.Identity.Core}/IUserEmailStore.cs (100%) rename src/{Microsoft.AspNetCore.Identity => Microsoft.Extensions.Identity.Core}/IUserLockoutStore.cs (100%) rename src/{Microsoft.AspNetCore.Identity => Microsoft.Extensions.Identity.Core}/IUserLoginStore.cs (100%) rename src/{Microsoft.AspNetCore.Identity => Microsoft.Extensions.Identity.Core}/IUserPasswordStore.cs (100%) rename src/{Microsoft.AspNetCore.Identity => Microsoft.Extensions.Identity.Core}/IUserPhoneNumberStore.cs (100%) rename src/{Microsoft.AspNetCore.Identity => Microsoft.Extensions.Identity.Core}/IUserRoleStore.cs (100%) rename src/{Microsoft.AspNetCore.Identity => Microsoft.Extensions.Identity.Core}/IUserSecurityStampStore.cs (100%) rename src/{Microsoft.AspNetCore.Identity => Microsoft.Extensions.Identity.Core}/IUserStore.cs (100%) rename src/{Microsoft.AspNetCore.Identity => Microsoft.Extensions.Identity.Core}/IUserTwoFactorRecoveryCodeStore.cs (100%) rename src/{Microsoft.AspNetCore.Identity => Microsoft.Extensions.Identity.Core}/IUserTwoFactorStore.cs (100%) rename src/{Microsoft.AspNetCore.Identity => Microsoft.Extensions.Identity.Core}/IUserTwoFactorTokenProvider.cs (100%) rename src/{Microsoft.AspNetCore.Identity => Microsoft.Extensions.Identity.Core}/IUserValidator.cs (100%) rename src/{Microsoft.AspNetCore.Identity => Microsoft.Extensions.Identity.Core}/IdentityError.cs (100%) rename src/{Microsoft.AspNetCore.Identity => Microsoft.Extensions.Identity.Core}/IdentityErrorDescriber.cs (100%) rename src/{Microsoft.AspNetCore.Identity => Microsoft.Extensions.Identity.Core}/IdentityOptions.cs (69%) rename src/{Microsoft.AspNetCore.Identity => Microsoft.Extensions.Identity.Core}/IdentityResult.cs (100%) rename src/{Microsoft.AspNetCore.Identity => Microsoft.Extensions.Identity.Core}/LockoutOptions.cs (100%) create mode 100644 src/Microsoft.Extensions.Identity.Core/Microsoft.Extensions.Identity.Core.csproj rename src/{Microsoft.AspNetCore.Identity => Microsoft.Extensions.Identity.Core}/PasswordHasherCompatibilityMode.cs (100%) rename src/{Microsoft.AspNetCore.Identity => Microsoft.Extensions.Identity.Core}/PasswordOptions.cs (100%) rename src/{Microsoft.AspNetCore.Identity => Microsoft.Extensions.Identity.Core}/PasswordVerificationResult.cs (100%) rename src/{Microsoft.AspNetCore.Identity => Microsoft.Extensions.Identity.Core}/PrincipalExtensions.cs (100%) create mode 100644 src/Microsoft.Extensions.Identity.Core/Properties/AssemblyInfo.cs create mode 100644 src/Microsoft.Extensions.Identity.Core/Properties/Resources.Designer.cs create mode 100644 src/Microsoft.Extensions.Identity.Core/Resources.resx rename src/{Microsoft.AspNetCore.Identity => Microsoft.Extensions.Identity.Core}/RoleManager.cs (96%) rename src/{Microsoft.AspNetCore.Identity => Microsoft.Extensions.Identity.Core}/SignInOptions.cs (100%) rename src/{Microsoft.AspNetCore.Identity => Microsoft.Extensions.Identity.Core}/SignInResult.cs (99%) rename src/{Microsoft.AspNetCore.Identity => Microsoft.Extensions.Identity.Core}/TokenOptions.cs (69%) rename src/{Microsoft.AspNetCore.Identity => Microsoft.Extensions.Identity.Core}/TokenProviderDescriptor.cs (100%) rename src/{Microsoft.AspNetCore.Identity => Microsoft.Extensions.Identity.Core}/UserLoginInfo.cs (100%) rename src/{Microsoft.AspNetCore.Identity => Microsoft.Extensions.Identity.Core}/UserManager.cs (98%) rename src/{Microsoft.AspNetCore.Identity => Microsoft.Extensions.Identity.Core}/UserOptions.cs (100%) rename src/{Microsoft.AspNetCore.Identity.EntityFrameworkCore => Microsoft.Extensions.Identity.Stores}/IdentityRole.cs (89%) rename src/{Microsoft.AspNetCore.Identity.EntityFrameworkCore => Microsoft.Extensions.Identity.Stores}/IdentityRoleClaim.cs (96%) rename src/{Microsoft.AspNetCore.Identity.EntityFrameworkCore => Microsoft.Extensions.Identity.Stores}/IdentityUser.cs (87%) rename src/{Microsoft.AspNetCore.Identity.EntityFrameworkCore => Microsoft.Extensions.Identity.Stores}/IdentityUserClaim.cs (96%) rename src/{Microsoft.AspNetCore.Identity.EntityFrameworkCore => Microsoft.Extensions.Identity.Stores}/IdentityUserLogin.cs (95%) rename src/{Microsoft.AspNetCore.Identity.EntityFrameworkCore => Microsoft.Extensions.Identity.Stores}/IdentityUserRole.cs (92%) rename src/{Microsoft.AspNetCore.Identity.EntityFrameworkCore => Microsoft.Extensions.Identity.Stores}/IdentityUserToken.cs (94%) create mode 100644 src/Microsoft.Extensions.Identity.Stores/Microsoft.Extensions.Identity.Stores.csproj create mode 100644 src/Microsoft.Extensions.Identity.Stores/RoleStoreBase.cs create mode 100644 src/Microsoft.Extensions.Identity.Stores/UserStoreBase.cs diff --git a/Identity.sln b/Identity.sln index 02d0353edc..8c276944ae 100644 --- a/Identity.sln +++ b/Identity.sln @@ -54,6 +54,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Identi EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Identity.Service.InMemory.Test", "test\Microsoft.AspNetCore.Identity.Service.InMemory.Test\Microsoft.AspNetCore.Identity.Service.InMemory.Test.csproj", "{94EC586A-2AE6-4AF2-894A-B0973C65BD68}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.Identity.Core", "src\Microsoft.Extensions.Identity.Core\Microsoft.Extensions.Identity.Core.csproj", "{D5905D78-A32E-44B8-8F21-EDAEDC95D9B8}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Extensions.Identity.Stores", "src\Microsoft.Extensions.Identity.Stores\Microsoft.Extensions.Identity.Stores.csproj", "{FADA11FC-DC06-4832-A569-7B2374A6CD42}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -326,6 +330,30 @@ Global {94EC586A-2AE6-4AF2-894A-B0973C65BD68}.Release|Mixed Platforms.Build.0 = Release|Any CPU {94EC586A-2AE6-4AF2-894A-B0973C65BD68}.Release|x86.ActiveCfg = Release|Any CPU {94EC586A-2AE6-4AF2-894A-B0973C65BD68}.Release|x86.Build.0 = Release|Any CPU + {D5905D78-A32E-44B8-8F21-EDAEDC95D9B8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D5905D78-A32E-44B8-8F21-EDAEDC95D9B8}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D5905D78-A32E-44B8-8F21-EDAEDC95D9B8}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {D5905D78-A32E-44B8-8F21-EDAEDC95D9B8}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {D5905D78-A32E-44B8-8F21-EDAEDC95D9B8}.Debug|x86.ActiveCfg = Debug|Any CPU + {D5905D78-A32E-44B8-8F21-EDAEDC95D9B8}.Debug|x86.Build.0 = Debug|Any CPU + {D5905D78-A32E-44B8-8F21-EDAEDC95D9B8}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D5905D78-A32E-44B8-8F21-EDAEDC95D9B8}.Release|Any CPU.Build.0 = Release|Any CPU + {D5905D78-A32E-44B8-8F21-EDAEDC95D9B8}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {D5905D78-A32E-44B8-8F21-EDAEDC95D9B8}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {D5905D78-A32E-44B8-8F21-EDAEDC95D9B8}.Release|x86.ActiveCfg = Release|Any CPU + {D5905D78-A32E-44B8-8F21-EDAEDC95D9B8}.Release|x86.Build.0 = Release|Any CPU + {FADA11FC-DC06-4832-A569-7B2374A6CD42}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FADA11FC-DC06-4832-A569-7B2374A6CD42}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FADA11FC-DC06-4832-A569-7B2374A6CD42}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {FADA11FC-DC06-4832-A569-7B2374A6CD42}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {FADA11FC-DC06-4832-A569-7B2374A6CD42}.Debug|x86.ActiveCfg = Debug|Any CPU + {FADA11FC-DC06-4832-A569-7B2374A6CD42}.Debug|x86.Build.0 = Debug|Any CPU + {FADA11FC-DC06-4832-A569-7B2374A6CD42}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FADA11FC-DC06-4832-A569-7B2374A6CD42}.Release|Any CPU.Build.0 = Release|Any CPU + {FADA11FC-DC06-4832-A569-7B2374A6CD42}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {FADA11FC-DC06-4832-A569-7B2374A6CD42}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {FADA11FC-DC06-4832-A569-7B2374A6CD42}.Release|x86.ActiveCfg = Release|Any CPU + {FADA11FC-DC06-4832-A569-7B2374A6CD42}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -354,5 +382,7 @@ Global {7423EB30-FFE9-4707-A44B-571E89A7CA15} = {52D59F18-62D2-4D17-8CF2-BE192445AF8E} {4F5D777E-3CFA-4EDF-BA89-4FE04BBF7A66} = {52D59F18-62D2-4D17-8CF2-BE192445AF8E} {94EC586A-2AE6-4AF2-894A-B0973C65BD68} = {52D59F18-62D2-4D17-8CF2-BE192445AF8E} + {D5905D78-A32E-44B8-8F21-EDAEDC95D9B8} = {0F647068-6602-4E24-B1DC-8ED91481A50A} + {FADA11FC-DC06-4832-A569-7B2374A6CD42} = {0F647068-6602-4E24-B1DC-8ED91481A50A} EndGlobalSection EndGlobal diff --git a/samples/IdentitySample.Mvc/Controllers/AccountController.cs b/samples/IdentitySample.Mvc/Controllers/AccountController.cs index 78188a9e29..ca996ea292 100644 --- a/samples/IdentitySample.Mvc/Controllers/AccountController.cs +++ b/samples/IdentitySample.Mvc/Controllers/AccountController.cs @@ -1,17 +1,14 @@ -using System; -using System.Collections.Generic; using System.Linq; using System.Security.Claims; using System.Threading.Tasks; +using IdentitySample.Models; +using IdentitySample.Models.AccountViewModels; +using IdentitySample.Services; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Rendering; -using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; -using IdentitySample.Models; -using IdentitySample.Models.AccountViewModels; -using IdentitySample.Services; namespace IdentitySample.Controllers { diff --git a/samples/IdentitySample.Mvc/IdentitySample.Mvc.csproj b/samples/IdentitySample.Mvc/IdentitySample.Mvc.csproj index a7060d0952..f4601bf543 100644 --- a/samples/IdentitySample.Mvc/IdentitySample.Mvc.csproj +++ b/samples/IdentitySample.Mvc/IdentitySample.Mvc.csproj @@ -9,12 +9,10 @@ - - diff --git a/samples/IdentitySample.Mvc/Models/ApplicationUser.cs b/samples/IdentitySample.Mvc/Models/ApplicationUser.cs index 28be309e48..1034780fdf 100644 --- a/samples/IdentitySample.Mvc/Models/ApplicationUser.cs +++ b/samples/IdentitySample.Mvc/Models/ApplicationUser.cs @@ -2,7 +2,7 @@ using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; -using Microsoft.AspNetCore.Identity.EntityFrameworkCore; +using Microsoft.AspNetCore.Identity; namespace IdentitySample.Models { diff --git a/samples/IdentitySample.Mvc/Models/ManageViewModels/IndexViewModel.cs b/samples/IdentitySample.Mvc/Models/ManageViewModels/IndexViewModel.cs index cc874ae833..e8967b459e 100644 --- a/samples/IdentitySample.Mvc/Models/ManageViewModels/IndexViewModel.cs +++ b/samples/IdentitySample.Mvc/Models/ManageViewModels/IndexViewModel.cs @@ -1,7 +1,4 @@ -using System; using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; using Microsoft.AspNetCore.Identity; namespace IdentitySample.Models.ManageViewModels diff --git a/samples/IdentitySample.Mvc/Startup.cs b/samples/IdentitySample.Mvc/Startup.cs index 9b63d0ecbe..24e657848e 100644 --- a/samples/IdentitySample.Mvc/Startup.cs +++ b/samples/IdentitySample.Mvc/Startup.cs @@ -2,6 +2,7 @@ using IdentitySample.Models; using IdentitySample.Services; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; +using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Identity.EntityFrameworkCore; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Configuration; diff --git a/src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/IdentityDbContext.cs b/src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/IdentityDbContext.cs index 2a409a4820..2fafc38694 100644 --- a/src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/IdentityDbContext.cs +++ b/src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/IdentityDbContext.cs @@ -15,14 +15,12 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore /// Initializes a new instance of . /// /// The options to be used by a . - public IdentityDbContext(DbContextOptions options) : base(options) - { } + public IdentityDbContext(DbContextOptions options) : base(options) { } /// /// Initializes a new instance of the class. /// - protected IdentityDbContext() - { } + protected IdentityDbContext() { } } /// @@ -35,14 +33,12 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore /// Initializes a new instance of . /// /// The options to be used by a . - public IdentityDbContext(DbContextOptions options) : base(options) - { } + public IdentityDbContext(DbContextOptions options) : base(options) { } /// /// Initializes a new instance of the class. /// - protected IdentityDbContext() - { } + protected IdentityDbContext() { } } /// @@ -57,17 +53,15 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore where TKey : IEquatable { /// - /// Initializes a new instance of . + /// Initializes a new instance of the db context. /// /// The options to be used by a . - public IdentityDbContext(DbContextOptions options) : base(options) - { } + public IdentityDbContext(DbContextOptions options) : base(options) { } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// - protected IdentityDbContext() - { } + protected IdentityDbContext() { } } /// @@ -92,17 +86,15 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore where TUserToken : IdentityUserToken { /// - /// Initializes a new instance of . + /// Initializes a new instance of the class. /// /// The options to be used by a . - public IdentityDbContext(DbContextOptions options) : base(options) - { } + public IdentityDbContext(DbContextOptions options) : base(options) { } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// - protected IdentityDbContext() - { } + protected IdentityDbContext() { } /// /// Gets or sets the of Users. @@ -159,10 +151,12 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore b.Property(u => u.NormalizedUserName).HasMaxLength(256); b.Property(u => u.Email).HasMaxLength(256); b.Property(u => u.NormalizedEmail).HasMaxLength(256); - b.HasMany(u => u.Claims).WithOne().HasForeignKey(uc => uc.UserId).IsRequired(); - b.HasMany(u => u.Logins).WithOne().HasForeignKey(ul => ul.UserId).IsRequired(); - b.HasMany(u => u.Roles).WithOne().HasForeignKey(ur => ur.UserId).IsRequired(); - b.HasMany(u => u.Tokens).WithOne().HasForeignKey(ut => ut.UserId).IsRequired(); + + // Replace with b.HasMany(). + b.HasMany().WithOne().HasForeignKey(uc => uc.UserId).IsRequired(); + b.HasMany().WithOne().HasForeignKey(ul => ul.UserId).IsRequired(); + b.HasMany().WithOne().HasForeignKey(ur => ur.UserId).IsRequired(); + b.HasMany().WithOne().HasForeignKey(ut => ut.UserId).IsRequired(); }); builder.Entity(b => @@ -175,8 +169,8 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore b.Property(u => u.Name).HasMaxLength(256); b.Property(u => u.NormalizedName).HasMaxLength(256); - b.HasMany(r => r.Users).WithOne().HasForeignKey(ur => ur.RoleId).IsRequired(); - b.HasMany(r => r.Claims).WithOne().HasForeignKey(rc => rc.RoleId).IsRequired(); + b.HasMany().WithOne().HasForeignKey(ur => ur.RoleId).IsRequired(); + b.HasMany().WithOne().HasForeignKey(rc => rc.RoleId).IsRequired(); }); builder.Entity(b => diff --git a/src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/Microsoft.AspNetCore.Identity.EntityFrameworkCore.csproj b/src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/Microsoft.AspNetCore.Identity.EntityFrameworkCore.csproj index b81a8114cd..a76627f45a 100644 --- a/src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/Microsoft.AspNetCore.Identity.EntityFrameworkCore.csproj +++ b/src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/Microsoft.AspNetCore.Identity.EntityFrameworkCore.csproj @@ -11,6 +11,7 @@ + diff --git a/src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/UserStore.cs b/src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/UserStore.cs index 5899ab71a1..35135ec080 100644 --- a/src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/UserStore.cs +++ b/src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/UserStore.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using System.ComponentModel; using System.Globalization; using System.Linq; using System.Security.Claims; @@ -96,6 +95,7 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore /// The type representing a user token. /// The type representing a role claim. public class UserStore : + UserStoreBase, IUserLoginStore, IUserRoleStore, IUserClaimStore, @@ -120,32 +120,24 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore where TRoleClaim : IdentityRoleClaim, new() { /// - /// Creates a new instance of . + /// Creates a new instance of the store. /// /// The context used to access the store. /// The used to describe store errors. - public UserStore(TContext context, IdentityErrorDescriber describer = null) + public UserStore(TContext context, IdentityErrorDescriber describer = null) : base(describer ?? new IdentityErrorDescriber()) { if (context == null) { throw new ArgumentNullException(nameof(context)); } Context = context; - ErrorDescriber = describer ?? new IdentityErrorDescriber(); } - private bool _disposed; - /// /// Gets the database context for this store. /// public TContext Context { get; private set; } - /// - /// Gets or sets the for any error that occurred with the current operation. - /// - public IdentityErrorDescriber ErrorDescriber { get; set; } - private DbSet UsersSet { get { return Context.Set(); } } private DbSet Roles { get { return Context.Set(); } } private DbSet UserClaims { get { return Context.Set(); } } @@ -153,70 +145,6 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore private DbSet UserLogins { get { return Context.Set(); } } private DbSet UserTokens { get { return Context.Set(); } } - /// - /// Called to create a new instance of a . - /// - /// The associated user. - /// The associated role. - /// - protected virtual TUserRole CreateUserRole(TUser user, TRole role) - { - return new TUserRole() - { - UserId = user.Id, - RoleId = role.Id - }; - } - - /// - /// Called to create a new instance of a . - /// - /// The associated user. - /// The associated claim. - /// - protected virtual TUserClaim CreateUserClaim(TUser user, Claim claim) - { - var userClaim = new TUserClaim { UserId = user.Id }; - userClaim.InitializeFromClaim(claim); - return userClaim; - } - - /// - /// Called to create a new instance of a . - /// - /// The associated user. - /// The sasociated login. - /// - protected virtual TUserLogin CreateUserLogin(TUser user, UserLoginInfo login) - { - return new TUserLogin - { - UserId = user.Id, - ProviderKey = login.ProviderKey, - LoginProvider = login.LoginProvider, - ProviderDisplayName = login.ProviderDisplayName - }; - } - - /// - /// Called to create a new instance of a . - /// - /// The associated user. - /// The associated login provider. - /// The name of the user token. - /// The value of the user token. - /// - protected virtual TUserToken CreateUserToken(TUser user, string loginProvider, string name, string value) - { - return new TUserToken - { - UserId = user.Id, - LoginProvider = loginProvider, - Name = name, - Value = value - }; - } - /// /// Gets or sets a flag indicating if changes should be persisted after CreateAsync, UpdateAsync and DeleteAsync are called. /// @@ -233,102 +161,13 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore return AutoSaveChanges ? Context.SaveChangesAsync(cancellationToken) : TaskCache.CompletedTask; } - /// - /// Gets the user identifier for the specified . - /// - /// The user whose identifier should be retrieved. - /// The used to propagate notifications that the operation should be canceled. - /// The that represents the asynchronous operation, containing the identifier for the specified . - public virtual Task GetUserIdAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken)) - { - cancellationToken.ThrowIfCancellationRequested(); - ThrowIfDisposed(); - if (user == null) - { - throw new ArgumentNullException(nameof(user)); - } - return Task.FromResult(ConvertIdToString(user.Id)); - } - - /// - /// Gets the user name for the specified . - /// - /// The user whose name should be retrieved. - /// The used to propagate notifications that the operation should be canceled. - /// The that represents the asynchronous operation, containing the name for the specified . - public virtual Task GetUserNameAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken)) - { - cancellationToken.ThrowIfCancellationRequested(); - ThrowIfDisposed(); - if (user == null) - { - throw new ArgumentNullException(nameof(user)); - } - return Task.FromResult(user.UserName); - } - - /// - /// Sets the given for the specified . - /// - /// The user whose name should be set. - /// The user name to set. - /// The used to propagate notifications that the operation should be canceled. - /// The that represents the asynchronous operation. - public virtual Task SetUserNameAsync(TUser user, string userName, CancellationToken cancellationToken = default(CancellationToken)) - { - cancellationToken.ThrowIfCancellationRequested(); - ThrowIfDisposed(); - if (user == null) - { - throw new ArgumentNullException(nameof(user)); - } - user.UserName = userName; - return TaskCache.CompletedTask; - } - - /// - /// Gets the normalized user name for the specified . - /// - /// The user whose normalized name should be retrieved. - /// The used to propagate notifications that the operation should be canceled. - /// The that represents the asynchronous operation, containing the normalized user name for the specified . - public virtual Task GetNormalizedUserNameAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken)) - { - cancellationToken.ThrowIfCancellationRequested(); - ThrowIfDisposed(); - if (user == null) - { - throw new ArgumentNullException(nameof(user)); - } - return Task.FromResult(user.NormalizedUserName); - } - - /// - /// Sets the given normalized name for the specified . - /// - /// The user whose name should be set. - /// The normalized name to set. - /// The used to propagate notifications that the operation should be canceled. - /// The that represents the asynchronous operation. - public virtual Task SetNormalizedUserNameAsync(TUser user, string normalizedName, CancellationToken cancellationToken = default(CancellationToken)) - { - cancellationToken.ThrowIfCancellationRequested(); - ThrowIfDisposed(); - if (user == null) - { - throw new ArgumentNullException(nameof(user)); - } - user.NormalizedUserName = normalizedName; - return TaskCache.CompletedTask; - } - /// /// Creates the specified in the user store. /// /// The user to create. /// The used to propagate notifications that the operation should be canceled. /// The that represents the asynchronous operation, containing the of the creation operation. - public async virtual Task CreateAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken)) + public async override Task CreateAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken)) { cancellationToken.ThrowIfCancellationRequested(); ThrowIfDisposed(); @@ -347,7 +186,7 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore /// The user to update. /// The used to propagate notifications that the operation should be canceled. /// The that represents the asynchronous operation, containing the of the update operation. - public async virtual Task UpdateAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken)) + public async override Task UpdateAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken)) { cancellationToken.ThrowIfCancellationRequested(); ThrowIfDisposed(); @@ -376,7 +215,7 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore /// The user to delete. /// The used to propagate notifications that the operation should be canceled. /// The that represents the asynchronous operation, containing the of the update operation. - public async virtual Task DeleteAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken)) + public async override Task DeleteAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken)) { cancellationToken.ThrowIfCancellationRequested(); ThrowIfDisposed(); @@ -405,7 +244,7 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore /// /// The that represents the asynchronous operation, containing the user matching the specified if it exists. /// - public virtual Task FindByIdAsync(string userId, CancellationToken cancellationToken = default(CancellationToken)) + public override Task FindByIdAsync(string userId, CancellationToken cancellationToken = default(CancellationToken)) { cancellationToken.ThrowIfCancellationRequested(); ThrowIfDisposed(); @@ -413,34 +252,6 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore return UsersSet.FindAsync(new object[] { id }, cancellationToken); } - /// - /// Converts the provided to a strongly typed key object. - /// - /// The id to convert. - /// An instance of representing the provided . - public virtual TKey ConvertIdFromString(string id) - { - if (id == null) - { - return default(TKey); - } - return (TKey)TypeDescriptor.GetConverter(typeof(TKey)).ConvertFromInvariantString(id); - } - - /// - /// Converts the provided to its string representation. - /// - /// The id to convert. - /// An representation of the provided . - public virtual string ConvertIdToString(TKey id) - { - if (object.Equals(id, default(TKey))) - { - return null; - } - return id.ToString(); - } - /// /// Finds and returns a user, if any, who has the specified normalized user name. /// @@ -449,7 +260,7 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore /// /// The that represents the asynchronous operation, containing the user matching the specified if it exists. /// - public virtual Task FindByNameAsync(string normalizedUserName, CancellationToken cancellationToken = default(CancellationToken)) + public override Task FindByNameAsync(string normalizedUserName, CancellationToken cancellationToken = default(CancellationToken)) { cancellationToken.ThrowIfCancellationRequested(); ThrowIfDisposed(); @@ -459,67 +270,18 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore /// /// A navigation property for the users the store contains. /// - public virtual IQueryable Users + public override IQueryable Users { get { return UsersSet; } } - /// - /// Sets the password hash for a user. - /// - /// The user to set the password hash for. - /// The password hash to set. - /// The used to propagate notifications that the operation should be canceled. - /// The that represents the asynchronous operation. - public virtual Task SetPasswordHashAsync(TUser user, string passwordHash, CancellationToken cancellationToken = default(CancellationToken)) - { - cancellationToken.ThrowIfCancellationRequested(); - ThrowIfDisposed(); - if (user == null) - { - throw new ArgumentNullException(nameof(user)); - } - user.PasswordHash = passwordHash; - return TaskCache.CompletedTask; - } - - /// - /// Gets the password hash for a user. - /// - /// The user to retrieve the password hash for. - /// The used to propagate notifications that the operation should be canceled. - /// A that contains the password hash for the user. - public virtual Task GetPasswordHashAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken)) - { - cancellationToken.ThrowIfCancellationRequested(); - ThrowIfDisposed(); - if (user == null) - { - throw new ArgumentNullException(nameof(user)); - } - return Task.FromResult(user.PasswordHash); - } - - /// - /// Returns a flag indicating if the specified user has a password. - /// - /// The user to retrieve the password hash for. - /// The used to propagate notifications that the operation should be canceled. - /// A containing a flag indicating if the specified user has a password. If the - /// user has a password the returned value with be true, otherwise it will be false. - public virtual Task HasPasswordAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken)) - { - cancellationToken.ThrowIfCancellationRequested(); - return Task.FromResult(user.PasswordHash != null); - } - /// /// Return a role with the normalized name if it exists. /// /// The normalized role name. /// The used to propagate notifications that the operation should be canceled. /// The role if it exists. - protected virtual Task FindRoleAsync(string normalizedRoleName, CancellationToken cancellationToken) + protected override Task FindRoleAsync(string normalizedRoleName, CancellationToken cancellationToken) { return Roles.SingleOrDefaultAsync(r => r.NormalizedName == normalizedRoleName, cancellationToken); } @@ -531,7 +293,7 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore /// The role's id. /// The used to propagate notifications that the operation should be canceled. /// The user role if it exists. - protected virtual Task FindUserRoleAsync(TKey userId, TKey roleId, CancellationToken cancellationToken) + protected override Task FindUserRoleAsync(TKey userId, TKey roleId, CancellationToken cancellationToken) { return UserRoles.FindAsync(new object[] { userId, roleId }, cancellationToken); } @@ -542,7 +304,7 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore /// The user's id. /// The used to propagate notifications that the operation should be canceled. /// The user if it exists. - protected virtual Task FindUserAsync(TKey userId, CancellationToken cancellationToken) + protected override Task FindUserAsync(TKey userId, CancellationToken cancellationToken) { return Users.SingleOrDefaultAsync(u => u.Id.Equals(userId), cancellationToken); } @@ -555,7 +317,7 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore /// The key provided by the to identify a user. /// The used to propagate notifications that the operation should be canceled. /// The user login if it exists. - protected virtual Task FindUserLoginAsync(TKey userId, string loginProvider, string providerKey, CancellationToken cancellationToken) + protected override Task FindUserLoginAsync(TKey userId, string loginProvider, string providerKey, CancellationToken cancellationToken) { return UserLogins.SingleOrDefaultAsync(userLogin => userLogin.UserId.Equals(userId) && userLogin.LoginProvider == loginProvider && userLogin.ProviderKey == providerKey, cancellationToken); } @@ -567,7 +329,7 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore /// The key provided by the to identify a user. /// The used to propagate notifications that the operation should be canceled. /// The user login if it exists. - protected virtual Task FindUserLoginAsync(string loginProvider, string providerKey, CancellationToken cancellationToken) + protected override Task FindUserLoginAsync(string loginProvider, string providerKey, CancellationToken cancellationToken) { return UserLogins.SingleOrDefaultAsync(userLogin => userLogin.LoginProvider == loginProvider && userLogin.ProviderKey == providerKey, cancellationToken); } @@ -580,7 +342,7 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore /// The role to add. /// The used to propagate notifications that the operation should be canceled. /// The that represents the asynchronous operation. - public async virtual Task AddToRoleAsync(TUser user, string normalizedRoleName, CancellationToken cancellationToken = default(CancellationToken)) + public async override Task AddToRoleAsync(TUser user, string normalizedRoleName, CancellationToken cancellationToken = default(CancellationToken)) { cancellationToken.ThrowIfCancellationRequested(); ThrowIfDisposed(); @@ -607,7 +369,7 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore /// The role to remove. /// The used to propagate notifications that the operation should be canceled. /// The that represents the asynchronous operation. - public async virtual Task RemoveFromRoleAsync(TUser user, string normalizedRoleName, CancellationToken cancellationToken = default(CancellationToken)) + public async override Task RemoveFromRoleAsync(TUser user, string normalizedRoleName, CancellationToken cancellationToken = default(CancellationToken)) { cancellationToken.ThrowIfCancellationRequested(); ThrowIfDisposed(); @@ -636,7 +398,7 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore /// The user whose roles should be retrieved. /// The used to propagate notifications that the operation should be canceled. /// A that contains the roles the user is a member of. - public virtual async Task> GetRolesAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken)) + public override async Task> GetRolesAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken)) { cancellationToken.ThrowIfCancellationRequested(); ThrowIfDisposed(); @@ -660,7 +422,7 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore /// The used to propagate notifications that the operation should be canceled. /// A containing a flag indicating if the specified user is a member of the given group. If the /// user is a member of the group the returned value with be true, otherwise it will be false. - public virtual async Task IsInRoleAsync(TUser user, string normalizedRoleName, CancellationToken cancellationToken = default(CancellationToken)) + public override async Task IsInRoleAsync(TUser user, string normalizedRoleName, CancellationToken cancellationToken = default(CancellationToken)) { cancellationToken.ThrowIfCancellationRequested(); ThrowIfDisposed(); @@ -681,32 +443,13 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore return false; } - /// - /// Throws if this class has been disposed. - /// - protected void ThrowIfDisposed() - { - if (_disposed) - { - throw new ObjectDisposedException(GetType().Name); - } - } - - /// - /// Dispose the store - /// - public void Dispose() - { - _disposed = true; - } - /// /// Get the claims associated with the specified as an asynchronous operation. /// /// The user whose claims should be retrieved. /// The used to propagate notifications that the operation should be canceled. /// A that contains the claims granted to a user. - public async virtual Task> GetClaimsAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken)) + public async override Task> GetClaimsAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken)) { ThrowIfDisposed(); if (user == null) @@ -724,7 +467,7 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore /// The claim to add to the user. /// The used to propagate notifications that the operation should be canceled. /// The that represents the asynchronous operation. - public virtual Task AddClaimsAsync(TUser user, IEnumerable claims, CancellationToken cancellationToken = default(CancellationToken)) + public override Task AddClaimsAsync(TUser user, IEnumerable claims, CancellationToken cancellationToken = default(CancellationToken)) { ThrowIfDisposed(); if (user == null) @@ -750,7 +493,7 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore /// The new claim replacing the . /// The used to propagate notifications that the operation should be canceled. /// The that represents the asynchronous operation. - public async virtual Task ReplaceClaimAsync(TUser user, Claim claim, Claim newClaim, CancellationToken cancellationToken = default(CancellationToken)) + public async override Task ReplaceClaimAsync(TUser user, Claim claim, Claim newClaim, CancellationToken cancellationToken = default(CancellationToken)) { ThrowIfDisposed(); if (user == null) @@ -781,7 +524,7 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore /// The claim to remove. /// The used to propagate notifications that the operation should be canceled. /// The that represents the asynchronous operation. - public async virtual Task RemoveClaimsAsync(TUser user, IEnumerable claims, CancellationToken cancellationToken = default(CancellationToken)) + public async override Task RemoveClaimsAsync(TUser user, IEnumerable claims, CancellationToken cancellationToken = default(CancellationToken)) { ThrowIfDisposed(); if (user == null) @@ -809,7 +552,7 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore /// The login to add to the user. /// The used to propagate notifications that the operation should be canceled. /// The that represents the asynchronous operation. - public virtual Task AddLoginAsync(TUser user, UserLoginInfo login, + public override Task AddLoginAsync(TUser user, UserLoginInfo login, CancellationToken cancellationToken = default(CancellationToken)) { cancellationToken.ThrowIfCancellationRequested(); @@ -834,7 +577,7 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore /// The key provided by the to identify a user. /// The used to propagate notifications that the operation should be canceled. /// The that represents the asynchronous operation. - public virtual async Task RemoveLoginAsync(TUser user, string loginProvider, string providerKey, + public override async Task RemoveLoginAsync(TUser user, string loginProvider, string providerKey, CancellationToken cancellationToken = default(CancellationToken)) { cancellationToken.ThrowIfCancellationRequested(); @@ -858,7 +601,7 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore /// /// The for the asynchronous operation, containing a list of for the specified , if any. /// - public async virtual Task> GetLoginsAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken)) + public async override Task> GetLoginsAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken)) { cancellationToken.ThrowIfCancellationRequested(); ThrowIfDisposed(); @@ -880,7 +623,7 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore /// /// The for the asynchronous operation, containing the user, if any which matched the specified login provider and key. /// - public async virtual Task FindByLoginAsync(string loginProvider, string providerKey, + public async override Task FindByLoginAsync(string loginProvider, string providerKey, CancellationToken cancellationToken = default(CancellationToken)) { cancellationToken.ThrowIfCancellationRequested(); @@ -893,120 +636,6 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore return null; } - /// - /// Gets a flag indicating whether the email address for the specified has been verified, true if the email address is verified otherwise - /// false. - /// - /// The user whose email confirmation status should be returned. - /// The used to propagate notifications that the operation should be canceled. - /// - /// The task object containing the results of the asynchronous operation, a flag indicating whether the email address for the specified - /// has been confirmed or not. - /// - public virtual Task GetEmailConfirmedAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken)) - { - cancellationToken.ThrowIfCancellationRequested(); - ThrowIfDisposed(); - if (user == null) - { - throw new ArgumentNullException(nameof(user)); - } - return Task.FromResult(user.EmailConfirmed); - } - - /// - /// Sets the flag indicating whether the specified 's email address has been confirmed or not. - /// - /// The user whose email confirmation status should be set. - /// A flag indicating if the email address has been confirmed, true if the address is confirmed otherwise false. - /// The used to propagate notifications that the operation should be canceled. - /// The task object representing the asynchronous operation. - public virtual Task SetEmailConfirmedAsync(TUser user, bool confirmed, CancellationToken cancellationToken = default(CancellationToken)) - { - cancellationToken.ThrowIfCancellationRequested(); - ThrowIfDisposed(); - if (user == null) - { - throw new ArgumentNullException(nameof(user)); - } - user.EmailConfirmed = confirmed; - return TaskCache.CompletedTask; - } - - /// - /// Sets the address for a . - /// - /// The user whose email should be set. - /// The email to set. - /// The used to propagate notifications that the operation should be canceled. - /// The task object representing the asynchronous operation. - public virtual Task SetEmailAsync(TUser user, string email, CancellationToken cancellationToken = default(CancellationToken)) - { - cancellationToken.ThrowIfCancellationRequested(); - ThrowIfDisposed(); - if (user == null) - { - throw new ArgumentNullException(nameof(user)); - } - user.Email = email; - return TaskCache.CompletedTask; - } - - /// - /// Gets the email address for the specified . - /// - /// The user whose email should be returned. - /// The used to propagate notifications that the operation should be canceled. - /// The task object containing the results of the asynchronous operation, the email address for the specified . - public virtual Task GetEmailAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken)) - { - cancellationToken.ThrowIfCancellationRequested(); - ThrowIfDisposed(); - if (user == null) - { - throw new ArgumentNullException(nameof(user)); - } - return Task.FromResult(user.Email); - } - - /// - /// Returns the normalized email for the specified . - /// - /// The user whose email address to retrieve. - /// The used to propagate notifications that the operation should be canceled. - /// - /// The task object containing the results of the asynchronous lookup operation, the normalized email address if any associated with the specified user. - /// - public virtual Task GetNormalizedEmailAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken)) - { - cancellationToken.ThrowIfCancellationRequested(); - ThrowIfDisposed(); - if (user == null) - { - throw new ArgumentNullException(nameof(user)); - } - return Task.FromResult(user.NormalizedEmail); - } - - /// - /// Sets the normalized email for the specified . - /// - /// The user whose email address to set. - /// The normalized email to set for the specified . - /// The used to propagate notifications that the operation should be canceled. - /// The task object representing the asynchronous operation. - public virtual Task SetNormalizedEmailAsync(TUser user, string normalizedEmail, CancellationToken cancellationToken = default(CancellationToken)) - { - cancellationToken.ThrowIfCancellationRequested(); - ThrowIfDisposed(); - if (user == null) - { - throw new ArgumentNullException(nameof(user)); - } - user.NormalizedEmail = normalizedEmail; - return TaskCache.CompletedTask; - } - /// /// Gets the user, if any, associated with the specified, normalized email address. /// @@ -1015,301 +644,13 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore /// /// The task object containing the results of the asynchronous lookup operation, the user if any associated with the specified normalized email address. /// - public virtual Task FindByEmailAsync(string normalizedEmail, CancellationToken cancellationToken = default(CancellationToken)) + public override Task FindByEmailAsync(string normalizedEmail, CancellationToken cancellationToken = default(CancellationToken)) { cancellationToken.ThrowIfCancellationRequested(); ThrowIfDisposed(); return Users.FirstOrDefaultAsync(u => u.NormalizedEmail == normalizedEmail, cancellationToken); } - /// - /// Gets the last a user's last lockout expired, if any. - /// Any time in the past should be indicates a user is not locked out. - /// - /// The user whose lockout date should be retrieved. - /// The used to propagate notifications that the operation should be canceled. - /// - /// A that represents the result of the asynchronous query, a containing the last time - /// a user's lockout expired, if any. - /// - public virtual Task GetLockoutEndDateAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken)) - { - cancellationToken.ThrowIfCancellationRequested(); - ThrowIfDisposed(); - if (user == null) - { - throw new ArgumentNullException(nameof(user)); - } - return Task.FromResult(user.LockoutEnd); - } - - /// - /// Locks out a user until the specified end date has passed. Setting a end date in the past immediately unlocks a user. - /// - /// The user whose lockout date should be set. - /// The after which the 's lockout should end. - /// The used to propagate notifications that the operation should be canceled. - /// The that represents the asynchronous operation. - public virtual Task SetLockoutEndDateAsync(TUser user, DateTimeOffset? lockoutEnd, CancellationToken cancellationToken = default(CancellationToken)) - { - cancellationToken.ThrowIfCancellationRequested(); - ThrowIfDisposed(); - if (user == null) - { - throw new ArgumentNullException(nameof(user)); - } - user.LockoutEnd = lockoutEnd; - return TaskCache.CompletedTask; - } - - /// - /// Records that a failed access has occurred, incrementing the failed access count. - /// - /// The user whose cancellation count should be incremented. - /// The used to propagate notifications that the operation should be canceled. - /// The that represents the asynchronous operation, containing the incremented failed access count. - public virtual Task IncrementAccessFailedCountAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken)) - { - cancellationToken.ThrowIfCancellationRequested(); - ThrowIfDisposed(); - if (user == null) - { - throw new ArgumentNullException(nameof(user)); - } - user.AccessFailedCount++; - return Task.FromResult(user.AccessFailedCount); - } - - /// - /// Resets a user's failed access count. - /// - /// The user whose failed access count should be reset. - /// The used to propagate notifications that the operation should be canceled. - /// The that represents the asynchronous operation. - /// This is typically called after the account is successfully accessed. - public virtual Task ResetAccessFailedCountAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken)) - { - cancellationToken.ThrowIfCancellationRequested(); - ThrowIfDisposed(); - if (user == null) - { - throw new ArgumentNullException(nameof(user)); - } - user.AccessFailedCount = 0; - return TaskCache.CompletedTask; - } - - /// - /// Retrieves the current failed access count for the specified . - /// - /// The user whose failed access count should be retrieved. - /// The used to propagate notifications that the operation should be canceled. - /// The that represents the asynchronous operation, containing the failed access count. - public virtual Task GetAccessFailedCountAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken)) - { - cancellationToken.ThrowIfCancellationRequested(); - ThrowIfDisposed(); - if (user == null) - { - throw new ArgumentNullException(nameof(user)); - } - return Task.FromResult(user.AccessFailedCount); - } - - /// - /// Retrieves a flag indicating whether user lockout can enabled for the specified user. - /// - /// The user whose ability to be locked out should be returned. - /// The used to propagate notifications that the operation should be canceled. - /// - /// The that represents the asynchronous operation, true if a user can be locked out, otherwise false. - /// - public virtual Task GetLockoutEnabledAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken)) - { - cancellationToken.ThrowIfCancellationRequested(); - ThrowIfDisposed(); - if (user == null) - { - throw new ArgumentNullException(nameof(user)); - } - return Task.FromResult(user.LockoutEnabled); - } - - /// - /// Set the flag indicating if the specified can be locked out. - /// - /// The user whose ability to be locked out should be set. - /// A flag indicating if lock out can be enabled for the specified . - /// The used to propagate notifications that the operation should be canceled. - /// The that represents the asynchronous operation. - public virtual Task SetLockoutEnabledAsync(TUser user, bool enabled, CancellationToken cancellationToken = default(CancellationToken)) - { - cancellationToken.ThrowIfCancellationRequested(); - ThrowIfDisposed(); - if (user == null) - { - throw new ArgumentNullException(nameof(user)); - } - user.LockoutEnabled = enabled; - return TaskCache.CompletedTask; - } - - /// - /// Sets the telephone number for the specified . - /// - /// The user whose telephone number should be set. - /// The telephone number to set. - /// The used to propagate notifications that the operation should be canceled. - /// The that represents the asynchronous operation. - public virtual Task SetPhoneNumberAsync(TUser user, string phoneNumber, CancellationToken cancellationToken = default(CancellationToken)) - { - cancellationToken.ThrowIfCancellationRequested(); - ThrowIfDisposed(); - if (user == null) - { - throw new ArgumentNullException(nameof(user)); - } - user.PhoneNumber = phoneNumber; - return TaskCache.CompletedTask; - } - - /// - /// Gets the telephone number, if any, for the specified . - /// - /// The user whose telephone number should be retrieved. - /// The used to propagate notifications that the operation should be canceled. - /// The that represents the asynchronous operation, containing the user's telephone number, if any. - public virtual Task GetPhoneNumberAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken)) - { - cancellationToken.ThrowIfCancellationRequested(); - ThrowIfDisposed(); - if (user == null) - { - throw new ArgumentNullException(nameof(user)); - } - return Task.FromResult(user.PhoneNumber); - } - - /// - /// Gets a flag indicating whether the specified 's telephone number has been confirmed. - /// - /// The user to return a flag for, indicating whether their telephone number is confirmed. - /// The used to propagate notifications that the operation should be canceled. - /// - /// The that represents the asynchronous operation, returning true if the specified has a confirmed - /// telephone number otherwise false. - /// - public virtual Task GetPhoneNumberConfirmedAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken)) - { - cancellationToken.ThrowIfCancellationRequested(); - ThrowIfDisposed(); - if (user == null) - { - throw new ArgumentNullException(nameof(user)); - } - return Task.FromResult(user.PhoneNumberConfirmed); - } - - /// - /// Sets a flag indicating if the specified 's phone number has been confirmed. - /// - /// The user whose telephone number confirmation status should be set. - /// A flag indicating whether the user's telephone number has been confirmed. - /// The used to propagate notifications that the operation should be canceled. - /// The that represents the asynchronous operation. - public virtual Task SetPhoneNumberConfirmedAsync(TUser user, bool confirmed, CancellationToken cancellationToken = default(CancellationToken)) - { - cancellationToken.ThrowIfCancellationRequested(); - ThrowIfDisposed(); - if (user == null) - { - throw new ArgumentNullException(nameof(user)); - } - user.PhoneNumberConfirmed = confirmed; - return TaskCache.CompletedTask; - } - - /// - /// Sets the provided security for the specified . - /// - /// The user whose security stamp should be set. - /// The security stamp to set. - /// The used to propagate notifications that the operation should be canceled. - /// The that represents the asynchronous operation. - public virtual Task SetSecurityStampAsync(TUser user, string stamp, CancellationToken cancellationToken = default(CancellationToken)) - { - cancellationToken.ThrowIfCancellationRequested(); - ThrowIfDisposed(); - if (user == null) - { - throw new ArgumentNullException(nameof(user)); - } - if (stamp == null) - { - throw new ArgumentNullException(nameof(stamp)); - } - user.SecurityStamp = stamp; - return TaskCache.CompletedTask; - } - - /// - /// Get the security stamp for the specified . - /// - /// The user whose security stamp should be set. - /// The used to propagate notifications that the operation should be canceled. - /// The that represents the asynchronous operation, containing the security stamp for the specified . - public virtual Task GetSecurityStampAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken)) - { - cancellationToken.ThrowIfCancellationRequested(); - ThrowIfDisposed(); - if (user == null) - { - throw new ArgumentNullException(nameof(user)); - } - return Task.FromResult(user.SecurityStamp); - } - - /// - /// Sets a flag indicating whether the specified has two factor authentication enabled or not, - /// as an asynchronous operation. - /// - /// The user whose two factor authentication enabled status should be set. - /// A flag indicating whether the specified has two factor authentication enabled. - /// The used to propagate notifications that the operation should be canceled. - /// The that represents the asynchronous operation. - public virtual Task SetTwoFactorEnabledAsync(TUser user, bool enabled, CancellationToken cancellationToken = default(CancellationToken)) - { - cancellationToken.ThrowIfCancellationRequested(); - ThrowIfDisposed(); - if (user == null) - { - throw new ArgumentNullException(nameof(user)); - } - user.TwoFactorEnabled = enabled; - return TaskCache.CompletedTask; - } - - /// - /// Returns a flag indicating whether the specified has two factor authentication enabled or not, - /// as an asynchronous operation. - /// - /// The user whose two factor authentication enabled status should be set. - /// The used to propagate notifications that the operation should be canceled. - /// - /// The that represents the asynchronous operation, containing a flag indicating whether the specified - /// has two factor authentication enabled or not. - /// - public virtual Task GetTwoFactorEnabledAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken)) - { - cancellationToken.ThrowIfCancellationRequested(); - ThrowIfDisposed(); - if (user == null) - { - throw new ArgumentNullException(nameof(user)); - } - return Task.FromResult(user.TwoFactorEnabled); - } - /// /// Retrieves all users with the specified claim. /// @@ -1318,7 +659,7 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore /// /// The contains a list of users, if any, that contain the specified claim. /// - public async virtual Task> GetUsersForClaimAsync(Claim claim, CancellationToken cancellationToken = default(CancellationToken)) + public async override Task> GetUsersForClaimAsync(Claim claim, CancellationToken cancellationToken = default(CancellationToken)) { cancellationToken.ThrowIfCancellationRequested(); ThrowIfDisposed(); @@ -1344,7 +685,7 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore /// /// The contains a list of users, if any, that are in the specified role. /// - public async virtual Task> GetUsersInRoleAsync(string normalizedRoleName, CancellationToken cancellationToken = default(CancellationToken)) + public async override Task> GetUsersInRoleAsync(string normalizedRoleName, CancellationToken cancellationToken = default(CancellationToken)) { cancellationToken.ThrowIfCancellationRequested(); ThrowIfDisposed(); @@ -1375,155 +716,30 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore /// The name of the token. /// The used to propagate notifications that the operation should be canceled. /// The user token if it exists. - protected virtual Task FindTokenAsync(TUser user, string loginProvider, string name, CancellationToken cancellationToken) + protected override Task FindTokenAsync(TUser user, string loginProvider, string name, CancellationToken cancellationToken) => UserTokens.FindAsync(new object[] { user.Id, loginProvider, name }, cancellationToken); /// - /// Sets the token value for a particular user. + /// Add a new user token. /// - /// The user. - /// The authentication provider for the token. - /// The name of the token. - /// The value of the token. - /// The used to propagate notifications that the operation should be canceled. - /// The that represents the asynchronous operation. - public virtual async Task SetTokenAsync(TUser user, string loginProvider, string name, string value, CancellationToken cancellationToken) + /// The token to be added. + /// + protected override Task AddUserTokenAsync(TUserToken token) { - cancellationToken.ThrowIfCancellationRequested(); - ThrowIfDisposed(); - - if (user == null) - { - throw new ArgumentNullException(nameof(user)); - } - - var token = await FindTokenAsync(user, loginProvider, name, cancellationToken); - if (token == null) - { - UserTokens.Add(CreateUserToken(user, loginProvider, name, value)); - } - else - { - token.Value = value; - } + UserTokens.Add(token); + return TaskCache.CompletedTask; } - /// - /// Deletes a token for a user. - /// - /// The user. - /// The authentication provider for the token. - /// The name of the token. - /// The used to propagate notifications that the operation should be canceled. - /// The that represents the asynchronous operation. - public virtual async Task RemoveTokenAsync(TUser user, string loginProvider, string name, CancellationToken cancellationToken) - { - cancellationToken.ThrowIfCancellationRequested(); - ThrowIfDisposed(); - - if (user == null) - { - throw new ArgumentNullException(nameof(user)); - } - var entry = await FindTokenAsync(user, loginProvider, name, cancellationToken); - if (entry != null) - { - UserTokens.Remove(entry); - } - } /// - /// Returns the token value. + /// Remove a new user token. /// - /// The user. - /// The authentication provider for the token. - /// The name of the token. - /// The used to propagate notifications that the operation should be canceled. - /// The that represents the asynchronous operation. - public virtual async Task GetTokenAsync(TUser user, string loginProvider, string name, CancellationToken cancellationToken) + /// The token to be removed. + /// + protected override Task RemoveUserTokenAsync(TUserToken token) { - cancellationToken.ThrowIfCancellationRequested(); - ThrowIfDisposed(); - - if (user == null) - { - throw new ArgumentNullException(nameof(user)); - } - var entry = await FindTokenAsync(user, loginProvider, name, cancellationToken); - return entry?.Value; - } - - private const string InternalLoginProvider = "[AspNetUserStore]"; - private const string AuthenticatorKeyTokenName = "AuthenticatorKey"; - private const string RecoveryCodeTokenName = "RecoveryCodes"; - - /// - /// Sets the authenticator key for the specified . - /// - /// The user whose authenticator key should be set. - /// The authenticator key to set. - /// The used to propagate notifications that the operation should be canceled. - /// The that represents the asynchronous operation. - public virtual Task SetAuthenticatorKeyAsync(TUser user, string key, CancellationToken cancellationToken) - { - return SetTokenAsync(user, InternalLoginProvider, AuthenticatorKeyTokenName, key, cancellationToken); - } - - /// - /// Get the authenticator key for the specified . - /// - /// The user whose security stamp should be set. - /// The used to propagate notifications that the operation should be canceled. - /// The that represents the asynchronous operation, containing the security stamp for the specified . - public virtual Task GetAuthenticatorKeyAsync(TUser user, CancellationToken cancellationToken) - { - return GetTokenAsync(user, InternalLoginProvider, AuthenticatorKeyTokenName, cancellationToken); - } - - /// - /// Updates the recovery codes for the user while invalidating any previous recovery codes. - /// - /// The user to store new recovery codes for. - /// The new recovery codes for the user. - /// The used to propagate notifications that the operation should be canceled. - /// The new recovery codes for the user. - public virtual Task ReplaceCodesAsync(TUser user, IEnumerable recoveryCodes, CancellationToken cancellationToken) - { - var mergedCodes = string.Join(";", recoveryCodes); - return SetTokenAsync(user, InternalLoginProvider, RecoveryCodeTokenName, mergedCodes, cancellationToken); - } - - /// - /// Returns whether a recovery code is valid for a user. Note: recovery codes are only valid - /// once, and will be invalid after use. - /// - /// The user who owns the recovery code. - /// The recovery code to use. - /// The used to propagate notifications that the operation should be canceled. - /// True if the recovery code was found for the user. - public virtual async Task RedeemCodeAsync(TUser user, string code, CancellationToken cancellationToken) - { - cancellationToken.ThrowIfCancellationRequested(); - ThrowIfDisposed(); - - if (user == null) - { - throw new ArgumentNullException(nameof(user)); - } - if (code == null) - { - throw new ArgumentNullException(nameof(code)); - } - - var mergedCodes = await GetTokenAsync(user, InternalLoginProvider, RecoveryCodeTokenName, cancellationToken) ?? ""; - var splitCodes = mergedCodes.Split(';'); - if (splitCodes.Contains(code)) - { - var updatedCodes = new List(splitCodes.Where(s => s != code)); - await ReplaceCodesAsync(user, updatedCodes, cancellationToken); - return true; - } - return false; + UserTokens.Remove(token); + return TaskCache.CompletedTask; } } } diff --git a/src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/breakingchanges.netcore.json b/src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/breakingchanges.netcore.json index fc028d1e5c..93954d1e96 100644 --- a/src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/breakingchanges.netcore.json +++ b/src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/breakingchanges.netcore.json @@ -1,36 +1,103 @@ [ - { - "TypeId": "public abstract class Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityDbContext : Microsoft.EntityFrameworkCore.DbContext where T0 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUser where T1 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole where T2 : System.IEquatable where T3 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserClaim where T4 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserRole where T5 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserLogin where T6 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRoleClaim where T7 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserToken", - "Kind": "Removal" - }, - { - "TypeId": "public abstract class Microsoft.AspNetCore.Identity.EntityFrameworkCore.RoleStore : Microsoft.AspNetCore.Identity.IQueryableRoleStore, Microsoft.AspNetCore.Identity.IRoleClaimStore where T0 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole where T1 : Microsoft.EntityFrameworkCore.DbContext where T2 : System.IEquatable where T3 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserRole where T4 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRoleClaim", - "Kind": "Removal" - }, - { - "TypeId": "public abstract class Microsoft.AspNetCore.Identity.EntityFrameworkCore.UserStore : Microsoft.AspNetCore.Identity.IUserLoginStore, Microsoft.AspNetCore.Identity.IUserRoleStore, Microsoft.AspNetCore.Identity.IUserClaimStore, Microsoft.AspNetCore.Identity.IUserPasswordStore, Microsoft.AspNetCore.Identity.IUserSecurityStampStore, Microsoft.AspNetCore.Identity.IUserEmailStore, Microsoft.AspNetCore.Identity.IUserLockoutStore, Microsoft.AspNetCore.Identity.IUserPhoneNumberStore, Microsoft.AspNetCore.Identity.IQueryableUserStore, Microsoft.AspNetCore.Identity.IUserTwoFactorStore, Microsoft.AspNetCore.Identity.IUserAuthenticationTokenStore where T0 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUser where T1 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole> where T2 : Microsoft.EntityFrameworkCore.DbContext where T3 : System.IEquatable where T4 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserClaim where T5 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserRole where T6 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserLogin where T7 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserToken", - "Kind": "Removal" - }, - { - "TypeId": "public class Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUser where T0 : System.IEquatable", - "Kind": "Removal" - }, - { - "TypeId": "public class Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUser : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUser, Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserRole, Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserLogin> where T0 : System.IEquatable", - "Kind": "Removal" - }, - { - "TypeId": "public class Microsoft.AspNetCore.Identity.EntityFrameworkCore.UserStore : Microsoft.AspNetCore.Identity.EntityFrameworkCore.UserStore, Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserRole, Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserLogin, Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserToken> where T0 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUser where T1 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole where T2 : Microsoft.EntityFrameworkCore.DbContext where T3 : System.IEquatable", - "Kind": "Removal" - }, - { - "TypeId": "public class Microsoft.AspNetCore.Identity.EntityFrameworkCore.RoleStore : Microsoft.AspNetCore.Identity.EntityFrameworkCore.RoleStore, Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRoleClaim> where T0 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole where T1 : Microsoft.EntityFrameworkCore.DbContext where T2 : System.IEquatable", - "MemberId": "protected override Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRoleClaim CreateRoleClaim(T0 role, System.Security.Claims.Claim claim)", - "Kind": "Removal" - }, - { - "TypeId": "public static class Microsoft.Extensions.DependencyInjection.IdentityEntityFrameworkBuilderExtensions", - "MemberId": "public static new Microsoft.AspNetCore.Identity.IdentityBuilder AddEntityFrameworkStores(this Microsoft.AspNetCore.Identity.IdentityBuilder builder) where T0 : Microsoft.EntityFrameworkCore.DbContext where T1 : System.IEquatable", - "Kind": "Removal" - } + { + "TypeId": "public class Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityDbContext : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityDbContext", + "Kind": "Removal" + }, + { + "TypeId": "public class Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityDbContext : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityDbContext, Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserRole, Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserLogin, Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRoleClaim, Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserToken> where T0 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUser where T1 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole where T2 : System.IEquatable", + "Kind": "Removal" + }, + { + "TypeId": "public class Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityDbContext : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityDbContext where T0 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUser", + "Kind": "Removal" + }, + { + "TypeId": "public class Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole", + "Kind": "Removal" + }, + { + "TypeId": "public class Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole where T0 : System.IEquatable where T1 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserRole where T2 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRoleClaim", + "Kind": "Removal" + }, + { + "TypeId": "public class Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole, Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRoleClaim> where T0 : System.IEquatable", + "Kind": "Removal" + }, + { + "TypeId": "public class Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRoleClaim where T0 : System.IEquatable", + "Kind": "Removal" + }, + { + "TypeId": "public class Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUser : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUser", + "Kind": "Removal" + }, + { + "TypeId": "public class Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserClaim where T0 : System.IEquatable", + "Kind": "Removal" + }, + { + "TypeId": "public class Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserLogin where T0 : System.IEquatable", + "Kind": "Removal" + }, + { + "TypeId": "public class Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserRole where T0 : System.IEquatable", + "Kind": "Removal" + }, + { + "TypeId": "public class Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserToken where T0 : System.IEquatable", + "Kind": "Removal" + }, + { + "TypeId": "public class Microsoft.AspNetCore.Identity.EntityFrameworkCore.RoleStore : Microsoft.AspNetCore.Identity.EntityFrameworkCore.RoleStore, Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRoleClaim> where T0 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole where T1 : Microsoft.EntityFrameworkCore.DbContext where T2 : System.IEquatable", + "Kind": "Removal" + }, + { + "TypeId": "public class Microsoft.AspNetCore.Identity.EntityFrameworkCore.RoleStore : Microsoft.AspNetCore.Identity.EntityFrameworkCore.RoleStore where T0 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole where T1 : Microsoft.EntityFrameworkCore.DbContext", + "Kind": "Removal" + }, + { + "TypeId": "public class Microsoft.AspNetCore.Identity.EntityFrameworkCore.RoleStore : Microsoft.AspNetCore.Identity.EntityFrameworkCore.RoleStore where T0 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole", + "Kind": "Removal" + }, + { + "TypeId": "public class Microsoft.AspNetCore.Identity.EntityFrameworkCore.UserStore : Microsoft.AspNetCore.Identity.EntityFrameworkCore.UserStore>", + "Kind": "Removal" + }, + { + "TypeId": "public class Microsoft.AspNetCore.Identity.EntityFrameworkCore.UserStore : Microsoft.AspNetCore.Identity.EntityFrameworkCore.UserStore where T0 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUser where T1 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole where T2 : Microsoft.EntityFrameworkCore.DbContext", + "Kind": "Removal" + }, + { + "TypeId": "public class Microsoft.AspNetCore.Identity.EntityFrameworkCore.UserStore : Microsoft.AspNetCore.Identity.EntityFrameworkCore.UserStore where T0 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUser, new()", + "Kind": "Removal" + }, + { + "TypeId": "public abstract class Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityDbContext : Microsoft.EntityFrameworkCore.DbContext where T0 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUser where T1 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole where T2 : System.IEquatable where T3 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserClaim where T4 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserRole where T5 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserLogin where T6 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRoleClaim where T7 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserToken", + "Kind": "Removal" + }, + { + "TypeId": "public abstract class Microsoft.AspNetCore.Identity.EntityFrameworkCore.RoleStore : Microsoft.AspNetCore.Identity.IQueryableRoleStore, Microsoft.AspNetCore.Identity.IRoleClaimStore where T0 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole where T1 : Microsoft.EntityFrameworkCore.DbContext where T2 : System.IEquatable where T3 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserRole where T4 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRoleClaim", + "Kind": "Removal" + }, + { + "TypeId": "public abstract class Microsoft.AspNetCore.Identity.EntityFrameworkCore.UserStore : Microsoft.AspNetCore.Identity.IUserLoginStore, Microsoft.AspNetCore.Identity.IUserRoleStore, Microsoft.AspNetCore.Identity.IUserClaimStore, Microsoft.AspNetCore.Identity.IUserPasswordStore, Microsoft.AspNetCore.Identity.IUserSecurityStampStore, Microsoft.AspNetCore.Identity.IUserEmailStore, Microsoft.AspNetCore.Identity.IUserLockoutStore, Microsoft.AspNetCore.Identity.IUserPhoneNumberStore, Microsoft.AspNetCore.Identity.IQueryableUserStore, Microsoft.AspNetCore.Identity.IUserTwoFactorStore, Microsoft.AspNetCore.Identity.IUserAuthenticationTokenStore where T0 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUser where T1 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole> where T2 : Microsoft.EntityFrameworkCore.DbContext where T3 : System.IEquatable where T4 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserClaim where T5 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserRole where T6 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserLogin where T7 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserToken", + "Kind": "Removal" + }, + { + "TypeId": "public class Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUser where T0 : System.IEquatable", + "Kind": "Removal" + }, + { + "TypeId": "public class Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUser : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUser, Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserRole, Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserLogin> where T0 : System.IEquatable", + "Kind": "Removal" + }, + { + "TypeId": "public class Microsoft.AspNetCore.Identity.EntityFrameworkCore.UserStore : Microsoft.AspNetCore.Identity.EntityFrameworkCore.UserStore, Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserRole, Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserLogin, Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUserToken> where T0 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityUser where T1 : Microsoft.AspNetCore.Identity.EntityFrameworkCore.IdentityRole where T2 : Microsoft.EntityFrameworkCore.DbContext where T3 : System.IEquatable", + "Kind": "Removal" + }, + { + "TypeId": "public static class Microsoft.Extensions.DependencyInjection.IdentityEntityFrameworkBuilderExtensions", + "MemberId": "public static new Microsoft.AspNetCore.Identity.IdentityBuilder AddEntityFrameworkStores(this Microsoft.AspNetCore.Identity.IdentityBuilder builder) where T0 : Microsoft.EntityFrameworkCore.DbContext where T1 : System.IEquatable", + "Kind": "Removal" + } ] \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Identity.Service.EntityFrameworkCore/IdentityServiceDbContext.cs b/src/Microsoft.AspNetCore.Identity.Service.EntityFrameworkCore/IdentityServiceDbContext.cs index 4c5d20d166..f14807c6bb 100644 --- a/src/Microsoft.AspNetCore.Identity.Service.EntityFrameworkCore/IdentityServiceDbContext.cs +++ b/src/Microsoft.AspNetCore.Identity.Service.EntityFrameworkCore/IdentityServiceDbContext.cs @@ -12,10 +12,7 @@ namespace Microsoft.AspNetCore.Identity.Service.EntityFrameworkCore where TUser : IdentityUser where TApplication : IdentityServiceApplication { - public IdentityServiceDbContext(DbContextOptions options) - : base(options) - { - } + public IdentityServiceDbContext(DbContextOptions options) : base(options) { } } public abstract class IdentityServiceDbContext @@ -39,10 +36,7 @@ namespace Microsoft.AspNetCore.Identity.Service.EntityFrameworkCore where TApplication : IdentityServiceApplication where TApplicationKey : IEquatable { - public IdentityServiceDbContext(DbContextOptions options) - : base(options) - { - } + public IdentityServiceDbContext(DbContextOptions options) : base(options) { } } public abstract class IdentityServiceDbContext< @@ -76,8 +70,7 @@ namespace Microsoft.AspNetCore.Identity.Service.EntityFrameworkCore { public IdentityServiceDbContext(DbContextOptions options) : base(options) - { - } + { } protected override void OnModelCreating(ModelBuilder builder) { diff --git a/src/Microsoft.AspNetCore.Identity.Service/Configuration/IdentityServiceOptionsSetup.cs b/src/Microsoft.AspNetCore.Identity.Service/Configuration/IdentityServiceOptionsSetup.cs index 84bb3b9730..2a3b082b95 100644 --- a/src/Microsoft.AspNetCore.Identity.Service/Configuration/IdentityServiceOptionsSetup.cs +++ b/src/Microsoft.AspNetCore.Identity.Service/Configuration/IdentityServiceOptionsSetup.cs @@ -28,7 +28,7 @@ namespace Microsoft.AspNetCore.Identity.Service.Configuration .AddSingle(IdentityServiceClaimTypes.Name, _options.Value.ClaimsIdentity.UserNameClaimType); options.LoginPolicy = new AuthorizationPolicyBuilder(options.LoginPolicy) - .AddAuthenticationSchemes(IdentityCookieOptions.ApplicationScheme) + .AddAuthenticationSchemes(IdentityConstants.ApplicationScheme) .Build(); } } diff --git a/src/Microsoft.AspNetCore.Identity.Service/IdentityServiceServiceCollectionExtensions.cs b/src/Microsoft.AspNetCore.Identity.Service/IdentityServiceServiceCollectionExtensions.cs index 4441e14cce..7a240dd84a 100644 --- a/src/Microsoft.AspNetCore.Identity.Service/IdentityServiceServiceCollectionExtensions.cs +++ b/src/Microsoft.AspNetCore.Identity.Service/IdentityServiceServiceCollectionExtensions.cs @@ -64,8 +64,8 @@ namespace Microsoft.Extensions.DependencyInjection options.CookiePath = $"/tfp/IdentityService"; }); services.ConfigureApplicationCookie(options => options.CookiePath = $"/tfp/IdentityService"); - services.Configure(IdentityCookieOptions.TwoFactorRememberMeScheme, options => options.CookiePath = $"/tfp/IdentityService"); - services.Configure(IdentityCookieOptions.TwoFactorUserIdScheme, options => options.CookiePath = $"/tfp/IdentityService"); + services.Configure(IdentityConstants.TwoFactorRememberMeScheme, options => options.CookiePath = $"/tfp/IdentityService"); + services.Configure(IdentityConstants.TwoFactorUserIdScheme, options => options.CookiePath = $"/tfp/IdentityService"); services.AddTransient, IdentityServiceAuthorizationOptionsSetup>(); diff --git a/src/Microsoft.AspNetCore.Identity.Specification.Tests/IdentitySpecificationTestBase.cs b/src/Microsoft.AspNetCore.Identity.Specification.Tests/IdentitySpecificationTestBase.cs index aa87c90804..220dd11818 100644 --- a/src/Microsoft.AspNetCore.Identity.Specification.Tests/IdentitySpecificationTestBase.cs +++ b/src/Microsoft.AspNetCore.Identity.Specification.Tests/IdentitySpecificationTestBase.cs @@ -6,14 +6,12 @@ using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Security.Claims; -using System.Text; using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; using Xunit; namespace Microsoft.AspNetCore.Identity.Test @@ -2084,7 +2082,7 @@ namespace Microsoft.AspNetCore.Identity.Test var stamp = await manager.GetSecurityStampAsync(user); IdentityResultAssert.IsFailure(await manager.ChangePhoneNumberAsync(user, "111-111-1111", "bogus"), "Invalid token."); - IdentityResultAssert.VerifyLogMessage(manager.Logger, $"VerifyChangePhoneNumberTokenAsync() failed for user {await manager.GetUserIdAsync(user)}."); + IdentityResultAssert.VerifyLogMessage(manager.Logger, $"VerifyUserTokenAsync() failed with purpose: ChangePhoneNumber:111-111-1111 for user { await manager.GetUserIdAsync(user)}."); Assert.False(await manager.IsPhoneNumberConfirmedAsync(user)); Assert.Equal("123-456-7890", await manager.GetPhoneNumberAsync(user)); Assert.Equal(stamp, await manager.GetSecurityStampAsync(user)); @@ -2139,7 +2137,7 @@ namespace Microsoft.AspNetCore.Identity.Test Assert.True(await manager.VerifyChangePhoneNumberTokenAsync(user, token2, num2)); Assert.False(await manager.VerifyChangePhoneNumberTokenAsync(user, token2, num1)); Assert.False(await manager.VerifyChangePhoneNumberTokenAsync(user, token1, num2)); - IdentityResultAssert.VerifyLogMessage(manager.Logger, $"VerifyChangePhoneNumberTokenAsync() failed for user {await manager.GetUserIdAsync(user)}."); + IdentityResultAssert.VerifyLogMessage(manager.Logger, $"VerifyUserTokenAsync() failed with purpose: ChangePhoneNumber:111-123-4567 for user {await manager.GetUserIdAsync(user)}."); } /// diff --git a/src/Microsoft.AspNetCore.Identity/AspNetRoleManager.cs b/src/Microsoft.AspNetCore.Identity/AspNetRoleManager.cs new file mode 100644 index 0000000000..79e7f6207d --- /dev/null +++ b/src/Microsoft.AspNetCore.Identity/AspNetRoleManager.cs @@ -0,0 +1,45 @@ +// 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; +using System.Threading; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Logging; + +namespace Microsoft.AspNetCore.Identity +{ + /// + /// Provides the APIs for managing roles in a persistence store. + /// + /// The type encapsulating a role. + public class AspNetRoleManager : RoleManager, IDisposable where TRole : class + { + private readonly CancellationToken _cancel; + + /// + /// Constructs a new instance of . + /// + /// The persistence store the manager will operate over. + /// A collection of validators for roles. + /// The normalizer to use when normalizing role names to keys. + /// The used to provider error messages. + /// The logger used to log messages, warnings and errors. + /// The accessor used to access the . + public AspNetRoleManager(IRoleStore store, + IEnumerable> roleValidators, + ILookupNormalizer keyNormalizer, + IdentityErrorDescriber errors, + ILogger> logger, + IHttpContextAccessor contextAccessor) + : base(store, roleValidators, keyNormalizer, errors, logger) + { + _cancel = contextAccessor?.HttpContext?.RequestAborted ?? CancellationToken.None; + } + + /// + /// The cancellation token assocated with the current HttpContext.RequestAborted or CancellationToken.None if unavailable. + /// + protected override CancellationToken CancellationToken => _cancel; + } +} diff --git a/src/Microsoft.AspNetCore.Identity/AspNetUserManager.cs b/src/Microsoft.AspNetCore.Identity/AspNetUserManager.cs new file mode 100644 index 0000000000..0e824445c3 --- /dev/null +++ b/src/Microsoft.AspNetCore.Identity/AspNetUserManager.cs @@ -0,0 +1,54 @@ +// 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; +using System.Threading; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; + +namespace Microsoft.AspNetCore.Identity +{ + /// + /// Provides the APIs for managing user in a persistence store. + /// + /// The type encapsulating a user. + public class AspNetUserManager : UserManager, IDisposable where TUser : class + { + private readonly CancellationToken _cancel; + + /// + /// Constructs a new instance of . + /// + /// The persistence store the manager will operate over. + /// The accessor used to access the . + /// The password hashing implementation to use when saving passwords. + /// A collection of to validate users against. + /// A collection of to validate passwords against. + /// The to use when generating index keys for users. + /// The used to provider error messages. + /// The used to resolve services. + /// The logger used to log messages, warnings and errors. + public AspNetUserManager(IUserStore store, + IOptions optionsAccessor, + IPasswordHasher passwordHasher, + IEnumerable> userValidators, + IEnumerable> passwordValidators, + ILookupNormalizer keyNormalizer, + IdentityErrorDescriber errors, + IServiceProvider services, + ILogger> logger) + : base(store, optionsAccessor, passwordHasher, userValidators, passwordValidators, keyNormalizer, errors, services, logger) + { + _cancel = services?.GetService()?.HttpContext?.RequestAborted ?? CancellationToken.None; + } + + /// + /// The cancellation token assocated with the current HttpContext.RequestAborted or CancellationToken.None if unavailable. + /// + protected override CancellationToken CancellationToken => _cancel; + } +} diff --git a/src/Microsoft.AspNetCore.Identity/DataProtectionTokenProvider.cs b/src/Microsoft.AspNetCore.Identity/DataProtectionTokenProvider.cs index 9e285f5e61..b268cc142d 100644 --- a/src/Microsoft.AspNetCore.Identity/DataProtectionTokenProvider.cs +++ b/src/Microsoft.AspNetCore.Identity/DataProtectionTokenProvider.cs @@ -4,7 +4,6 @@ using System; using System.IO; using System.Text; -using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.DataProtection; using Microsoft.Extensions.Options; diff --git a/src/Microsoft.AspNetCore.Identity/IdentityBuilder.cs b/src/Microsoft.AspNetCore.Identity/IdentityBuilder.cs index e95ee544c2..486958e5cc 100644 --- a/src/Microsoft.AspNetCore.Identity/IdentityBuilder.cs +++ b/src/Microsoft.AspNetCore.Identity/IdentityBuilder.cs @@ -149,7 +149,7 @@ namespace Microsoft.AspNetCore.Identity { if (!typeof(IUserTwoFactorTokenProvider<>).MakeGenericType(UserType).GetTypeInfo().IsAssignableFrom(provider.GetTypeInfo())) { - throw new InvalidOperationException(Resources.FormatInvalidManagerType(provider.Name, "IUserTokenProvider", UserType.Name)); + throw new InvalidOperationException(AspNetIdentityResources.FormatInvalidManagerType(provider.Name, "IUserTokenProvider", UserType.Name)); } Services.Configure(options => { @@ -188,7 +188,7 @@ namespace Microsoft.AspNetCore.Identity if (userManagerType == customType || !userManagerType.GetTypeInfo().IsAssignableFrom(customType.GetTypeInfo())) { - throw new InvalidOperationException(Resources.FormatInvalidManagerType(customType.Name, "UserManager", UserType.Name)); + throw new InvalidOperationException(AspNetIdentityResources.FormatInvalidManagerType(customType.Name, "UserManager", UserType.Name)); } Services.AddScoped(customType, services => services.GetRequiredService(userManagerType)); return AddScoped(userManagerType, customType); @@ -206,7 +206,7 @@ namespace Microsoft.AspNetCore.Identity if (managerType == customType || !managerType.GetTypeInfo().IsAssignableFrom(customType.GetTypeInfo())) { - throw new InvalidOperationException(Resources.FormatInvalidManagerType(customType.Name, "RoleManager", RoleType.Name)); + throw new InvalidOperationException(AspNetIdentityResources.FormatInvalidManagerType(customType.Name, "RoleManager", RoleType.Name)); } Services.AddScoped(typeof(TRoleManager), services => services.GetRequiredService(managerType)); return AddScoped(managerType, typeof(TRoleManager)); @@ -224,7 +224,7 @@ namespace Microsoft.AspNetCore.Identity if (managerType == customType || !managerType.GetTypeInfo().IsAssignableFrom(customType.GetTypeInfo())) { - throw new InvalidOperationException(Resources.FormatInvalidManagerType(customType.Name, "SignInManager", UserType.Name)); + throw new InvalidOperationException(AspNetIdentityResources.FormatInvalidManagerType(customType.Name, "SignInManager", UserType.Name)); } Services.AddScoped(typeof(TSignInManager), services => services.GetRequiredService(managerType)); return AddScoped(managerType, typeof(TSignInManager)); diff --git a/src/Microsoft.AspNetCore.Identity/IdentityConstants.cs b/src/Microsoft.AspNetCore.Identity/IdentityConstants.cs new file mode 100644 index 0000000000..0843a33bd4 --- /dev/null +++ b/src/Microsoft.AspNetCore.Identity/IdentityConstants.cs @@ -0,0 +1,32 @@ +// 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. + +namespace Microsoft.AspNetCore.Identity +{ + /// + /// Represents all the options you can use to configure the cookies middleware uesd by the identity system. + /// + public class IdentityConstants + { + private static readonly string CookiePrefix = "Identity"; + /// + /// The scheme used to identify application authentication cookies. + /// + public static readonly string ApplicationScheme = CookiePrefix + ".Application"; + + /// + /// The scheme used to identify external authentication cookies. + /// + public static readonly string ExternalScheme = CookiePrefix + ".External"; + + /// + /// The scheme used to identify Two Factor authentication cookies for saving the Remember Me state. + /// + public static readonly string TwoFactorRememberMeScheme = CookiePrefix + ".TwoFactorRememberMe"; + + /// + /// The scheme used to identify Two Factor authentication cookies for round tripping user identities. + /// + public static readonly string TwoFactorUserIdScheme = CookiePrefix + ".TwoFactorUserId"; + } +} diff --git a/src/Microsoft.AspNetCore.Identity/IdentityCookieOptions.cs b/src/Microsoft.AspNetCore.Identity/IdentityCookieOptions.cs deleted file mode 100644 index 5e9afd81e8..0000000000 --- a/src/Microsoft.AspNetCore.Identity/IdentityCookieOptions.cs +++ /dev/null @@ -1,83 +0,0 @@ -// 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.AspNetCore.Authentication.Cookies; - -namespace Microsoft.AspNetCore.Identity -{ - /// - /// Represents all the options you can use to configure the cookies middleware uesd by the identity system. - /// - public class IdentityCookieOptions - { - private static readonly string CookiePrefix = "Identity"; - /// - /// The scheme used to identify application authentication cookies. - /// - public static readonly string ApplicationScheme = CookiePrefix + ".Application"; - - /// - /// The scheme used to identify external authentication cookies. - /// - public static readonly string ExternalScheme = CookiePrefix + ".External"; - - /// - /// The scheme used to identify Two Factor authentication cookies for saving the Remember Me state. - /// - public static readonly string TwoFactorRememberMeScheme = CookiePrefix + ".TwoFactorRememberMe"; - - /// - /// The scheme used to identify Two Factor authentication cookies for round tripping user identities. - /// - public static readonly string TwoFactorUserIdScheme = CookiePrefix + ".TwoFactorUserId"; - - /// - /// The options for the application cookie. - /// - [Obsolete("See https://go.microsoft.com/fwlink/?linkid=845470", error: true)] - public CookieAuthenticationOptions ApplicationCookie { get; set; } - - /// - /// The options for the external cookie. - /// - [Obsolete("See https://go.microsoft.com/fwlink/?linkid=845470", error: true)] - public CookieAuthenticationOptions ExternalCookie { get; set; } - - /// - /// The options for the two factor remember me cookie. - /// - [Obsolete("See https://go.microsoft.com/fwlink/?linkid=845470", error: true)] - public CookieAuthenticationOptions TwoFactorRememberMeCookie { get; set; } - - /// - /// The options for the two factor user id cookie. - /// - [Obsolete("See https://go.microsoft.com/fwlink/?linkid=845470", error: true)] - public CookieAuthenticationOptions TwoFactorUserIdCookie { get; set; } - - /// - /// Gets the scheme used to identify application authentication cookies. - /// - /// The scheme used to identify application authentication cookies. - public string ApplicationCookieAuthenticationScheme { get; set; } = ApplicationScheme; - - /// - /// Gets the scheme used to identify external authentication cookies. - /// - /// The scheme used to identify external authentication cookies. - public string ExternalCookieAuthenticationScheme { get; set; } = ExternalScheme; - - /// - /// Gets 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; } = TwoFactorUserIdScheme; - - /// - /// Gets 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; } = TwoFactorRememberMeScheme; - } -} diff --git a/src/Microsoft.AspNetCore.Identity/IdentityServiceCollectionExtensions.cs b/src/Microsoft.AspNetCore.Identity/IdentityServiceCollectionExtensions.cs index fc782ae493..af0d7e62eb 100644 --- a/src/Microsoft.AspNetCore.Identity/IdentityServiceCollectionExtensions.cs +++ b/src/Microsoft.AspNetCore.Identity/IdentityServiceCollectionExtensions.cs @@ -46,7 +46,7 @@ namespace Microsoft.Extensions.DependencyInjection /// An action to configure the . /// The services. public static IServiceCollection ConfigureApplicationCookie(this IServiceCollection services, Action configure) - => services.Configure(IdentityCookieOptions.ApplicationScheme, configure); + => services.Configure(IdentityConstants.ApplicationScheme, configure); /// /// Configure the external cookie. @@ -55,7 +55,7 @@ namespace Microsoft.Extensions.DependencyInjection /// An action to configure the . /// The services. public static IServiceCollection ConfigureExternalCookie(this IServiceCollection services, Action configure) - => services.Configure(IdentityCookieOptions.ExternalScheme, configure); + => services.Configure(IdentityConstants.ExternalScheme, configure); /// /// Adds and configures the identity system for the specified User and Role types. @@ -74,12 +74,12 @@ namespace Microsoft.Extensions.DependencyInjection // Services used by identity services.AddAuthenticationCore(options => { - options.DefaultAuthenticateScheme = IdentityCookieOptions.ApplicationScheme; - options.DefaultChallengeScheme = IdentityCookieOptions.ApplicationScheme; - options.DefaultSignInScheme = IdentityCookieOptions.ExternalScheme; + options.DefaultAuthenticateScheme = IdentityConstants.ApplicationScheme; + options.DefaultChallengeScheme = IdentityConstants.ApplicationScheme; + options.DefaultSignInScheme = IdentityConstants.ExternalScheme; }); - services.AddCookieAuthentication(IdentityCookieOptions.ApplicationScheme, o => + services.AddCookieAuthentication(IdentityConstants.ApplicationScheme, o => { o.LoginPath = new PathString("/Account/Login"); o.Events = new CookieAuthenticationEvents @@ -88,18 +88,18 @@ namespace Microsoft.Extensions.DependencyInjection }; }); - services.AddCookieAuthentication(IdentityCookieOptions.ExternalScheme, o => + services.AddCookieAuthentication(IdentityConstants.ExternalScheme, o => { - o.CookieName = IdentityCookieOptions.ExternalScheme; + o.CookieName = IdentityConstants.ExternalScheme; o.ExpireTimeSpan = TimeSpan.FromMinutes(5); }); - services.AddCookieAuthentication(IdentityCookieOptions.TwoFactorRememberMeScheme, - o => o.CookieName = IdentityCookieOptions.TwoFactorRememberMeScheme); + services.AddCookieAuthentication(IdentityConstants.TwoFactorRememberMeScheme, + o => o.CookieName = IdentityConstants.TwoFactorRememberMeScheme); - services.AddCookieAuthentication(IdentityCookieOptions.TwoFactorUserIdScheme, o => + services.AddCookieAuthentication(IdentityConstants.TwoFactorUserIdScheme, o => { - o.CookieName = IdentityCookieOptions.TwoFactorUserIdScheme; + o.CookieName = IdentityConstants.TwoFactorUserIdScheme; o.ExpireTimeSpan = TimeSpan.FromMinutes(5); }); @@ -115,9 +115,9 @@ namespace Microsoft.Extensions.DependencyInjection services.TryAddScoped(); services.TryAddScoped>(); services.TryAddScoped, UserClaimsPrincipalFactory>(); - services.TryAddScoped, UserManager>(); + services.TryAddScoped, AspNetUserManager>(); services.TryAddScoped, SignInManager>(); - services.TryAddScoped, RoleManager>(); + services.TryAddScoped, AspNetRoleManager>(); services.AddSingleton, IdentityConfigureOptions>(); if (setupAction != null) diff --git a/src/Microsoft.AspNetCore.Identity/Microsoft.AspNetCore.Identity.csproj b/src/Microsoft.AspNetCore.Identity/Microsoft.AspNetCore.Identity.csproj index 6f9cc06366..329faa3233 100644 --- a/src/Microsoft.AspNetCore.Identity/Microsoft.AspNetCore.Identity.csproj +++ b/src/Microsoft.AspNetCore.Identity/Microsoft.AspNetCore.Identity.csproj @@ -18,4 +18,8 @@ + + + + diff --git a/src/Microsoft.AspNetCore.Identity/PasswordHasher.cs b/src/Microsoft.AspNetCore.Identity/PasswordHasher.cs index a3ab3ba6ad..0f861aa94e 100644 --- a/src/Microsoft.AspNetCore.Identity/PasswordHasher.cs +++ b/src/Microsoft.AspNetCore.Identity/PasswordHasher.cs @@ -53,12 +53,12 @@ namespace Microsoft.AspNetCore.Identity _iterCount = options.IterationCount; if (_iterCount < 1) { - throw new InvalidOperationException(Resources.InvalidPasswordHasherIterationCount); + throw new InvalidOperationException(AspNetIdentityResources.InvalidPasswordHasherIterationCount); } break; default: - throw new InvalidOperationException(Resources.InvalidPasswordHasherCompatibilityMode); + throw new InvalidOperationException(AspNetIdentityResources.InvalidPasswordHasherCompatibilityMode); } _rng = options.Rng; diff --git a/src/Microsoft.AspNetCore.Identity/Properties/Resources.Designer.cs b/src/Microsoft.AspNetCore.Identity/Properties/Resources.Designer.cs index 6d1fe59d2c..35f03f932a 100644 --- a/src/Microsoft.AspNetCore.Identity/Properties/Resources.Designer.cs +++ b/src/Microsoft.AspNetCore.Identity/Properties/Resources.Designer.cs @@ -5,106 +5,10 @@ namespace Microsoft.AspNetCore.Identity using System.Reflection; using System.Resources; - internal static class Resources + internal static class AspNetIdentityResources { private static readonly ResourceManager _resourceManager - = new ResourceManager("Microsoft.AspNetCore.Identity.Resources", typeof(Resources).GetTypeInfo().Assembly); - - /// - /// Optimistic concurrency failure, object has been modified. - /// - internal static string ConcurrencyFailure - { - get { return GetString("ConcurrencyFailure"); } - } - - /// - /// Optimistic concurrency failure, object has been modified. - /// - internal static string FormatConcurrencyFailure() - { - return GetString("ConcurrencyFailure"); - } - - /// - /// An unknown failure has occurred. - /// - internal static string DefaultError - { - get { return GetString("DefaultError"); } - } - - /// - /// An unknown failure has occurred. - /// - internal static string FormatDefaultError() - { - return GetString("DefaultError"); - } - - /// - /// Email '{0}' is already taken. - /// - internal static string DuplicateEmail - { - get { return GetString("DuplicateEmail"); } - } - - /// - /// Email '{0}' is already taken. - /// - internal static string FormatDuplicateEmail(object p0) - { - return string.Format(CultureInfo.CurrentCulture, GetString("DuplicateEmail"), p0); - } - - /// - /// Role name '{0}' is already taken. - /// - internal static string DuplicateRoleName - { - get { return GetString("DuplicateRoleName"); } - } - - /// - /// Role name '{0}' is already taken. - /// - internal static string FormatDuplicateRoleName(object p0) - { - return string.Format(CultureInfo.CurrentCulture, GetString("DuplicateRoleName"), p0); - } - - /// - /// User name '{0}' is already taken. - /// - internal static string DuplicateUserName - { - get { return GetString("DuplicateUserName"); } - } - - /// - /// User name '{0}' is already taken. - /// - internal static string FormatDuplicateUserName(object p0) - { - return string.Format(CultureInfo.CurrentCulture, GetString("DuplicateUserName"), p0); - } - - /// - /// Email '{0}' is invalid. - /// - internal static string InvalidEmail - { - get { return GetString("InvalidEmail"); } - } - - /// - /// Email '{0}' is invalid. - /// - internal static string FormatInvalidEmail(object p0) - { - return string.Format(CultureInfo.CurrentCulture, GetString("InvalidEmail"), p0); - } + = new ResourceManager("Microsoft.AspNetCore.Identity.Resources", typeof(AspNetIdentityResources).GetTypeInfo().Assembly); /// /// Type {0} must derive from {1}<{2}>. @@ -154,614 +58,6 @@ namespace Microsoft.AspNetCore.Identity return GetString("InvalidPasswordHasherIterationCount"); } - /// - /// Role name '{0}' is invalid. - /// - internal static string InvalidRoleName - { - get { return GetString("InvalidRoleName"); } - } - - /// - /// Role name '{0}' is invalid. - /// - internal static string FormatInvalidRoleName(object p0) - { - return string.Format(CultureInfo.CurrentCulture, GetString("InvalidRoleName"), p0); - } - - /// - /// Invalid token. - /// - internal static string InvalidToken - { - get { return GetString("InvalidToken"); } - } - - /// - /// Invalid token. - /// - internal static string FormatInvalidToken() - { - return GetString("InvalidToken"); - } - - /// - /// User name '{0}' is invalid, can only contain letters or digits. - /// - internal static string InvalidUserName - { - get { return GetString("InvalidUserName"); } - } - - /// - /// User name '{0}' is invalid, can only contain letters or digits. - /// - internal static string FormatInvalidUserName(object p0) - { - return string.Format(CultureInfo.CurrentCulture, GetString("InvalidUserName"), p0); - } - - /// - /// A user with this login already exists. - /// - internal static string LoginAlreadyAssociated - { - get { return GetString("LoginAlreadyAssociated"); } - } - - /// - /// A user with this login already exists. - /// - internal static string FormatLoginAlreadyAssociated() - { - return GetString("LoginAlreadyAssociated"); - } - - /// - /// AddIdentity must be called on the service collection. - /// - internal static string MustCallAddIdentity - { - get { return GetString("MustCallAddIdentity"); } - } - - /// - /// AddIdentity must be called on the service collection. - /// - internal static string FormatMustCallAddIdentity() - { - return GetString("MustCallAddIdentity"); - } - - /// - /// No IUserTokenProvider named '{0}' is registered. - /// - internal static string NoTokenProvider - { - get { return GetString("NoTokenProvider"); } - } - - /// - /// No IUserTokenProvider named '{0}' is registered. - /// - internal static string FormatNoTokenProvider(object p0) - { - return string.Format(CultureInfo.CurrentCulture, GetString("NoTokenProvider"), p0); - } - - /// - /// User security stamp cannot be null. - /// - internal static string NullSecurityStamp - { - get { return GetString("NullSecurityStamp"); } - } - - /// - /// User security stamp cannot be null. - /// - internal static string FormatNullSecurityStamp() - { - return GetString("NullSecurityStamp"); - } - - /// - /// Incorrect password. - /// - internal static string PasswordMismatch - { - get { return GetString("PasswordMismatch"); } - } - - /// - /// Incorrect password. - /// - internal static string FormatPasswordMismatch() - { - return GetString("PasswordMismatch"); - } - - /// - /// Passwords must have at least one digit ('0'-'9'). - /// - internal static string PasswordRequiresDigit - { - get { return GetString("PasswordRequiresDigit"); } - } - - /// - /// Passwords must have at least one digit ('0'-'9'). - /// - internal static string FormatPasswordRequiresDigit() - { - return GetString("PasswordRequiresDigit"); - } - - /// - /// Passwords must have at least one lowercase ('a'-'z'). - /// - internal static string PasswordRequiresLower - { - get { return GetString("PasswordRequiresLower"); } - } - - /// - /// Passwords must have at least one lowercase ('a'-'z'). - /// - internal static string FormatPasswordRequiresLower() - { - return GetString("PasswordRequiresLower"); - } - - /// - /// Passwords must have at least one non alphanumeric character. - /// - internal static string PasswordRequiresNonAlphanumeric - { - get { return GetString("PasswordRequiresNonAlphanumeric"); } - } - - /// - /// Passwords must have at least one non alphanumeric character. - /// - internal static string FormatPasswordRequiresNonAlphanumeric() - { - return GetString("PasswordRequiresNonAlphanumeric"); - } - - /// - /// Passwords must have at least one uppercase ('A'-'Z'). - /// - internal static string PasswordRequiresUpper - { - get { return GetString("PasswordRequiresUpper"); } - } - - /// - /// Passwords must have at least one uppercase ('A'-'Z'). - /// - internal static string FormatPasswordRequiresUpper() - { - return GetString("PasswordRequiresUpper"); - } - - /// - /// Passwords must be at least {0} characters. - /// - internal static string PasswordTooShort - { - get { return GetString("PasswordTooShort"); } - } - - /// - /// Passwords must be at least {0} characters. - /// - internal static string FormatPasswordTooShort(object p0) - { - return string.Format(CultureInfo.CurrentCulture, GetString("PasswordTooShort"), p0); - } - - /// - /// Role {0} does not exist. - /// - internal static string RoleNotFound - { - get { return GetString("RoleNotFound"); } - } - - /// - /// Role {0} does not exist. - /// - internal static string FormatRoleNotFound(object p0) - { - return string.Format(CultureInfo.CurrentCulture, GetString("RoleNotFound"), p0); - } - - /// - /// Store does not implement IQueryableRoleStore<TRole>. - /// - internal static string StoreNotIQueryableRoleStore - { - get { return GetString("StoreNotIQueryableRoleStore"); } - } - - /// - /// Store does not implement IQueryableRoleStore<TRole>. - /// - internal static string FormatStoreNotIQueryableRoleStore() - { - return GetString("StoreNotIQueryableRoleStore"); - } - - /// - /// Store does not implement IQueryableUserStore<TUser>. - /// - internal static string StoreNotIQueryableUserStore - { - get { return GetString("StoreNotIQueryableUserStore"); } - } - - /// - /// Store does not implement IQueryableUserStore<TUser>. - /// - internal static string FormatStoreNotIQueryableUserStore() - { - return GetString("StoreNotIQueryableUserStore"); - } - - /// - /// Store does not implement IRoleClaimStore<TRole>. - /// - internal static string StoreNotIRoleClaimStore - { - get { return GetString("StoreNotIRoleClaimStore"); } - } - - /// - /// Store does not implement IRoleClaimStore<TRole>. - /// - internal static string FormatStoreNotIRoleClaimStore() - { - return GetString("StoreNotIRoleClaimStore"); - } - - /// - /// Store does not implement IUserAuthenticationTokenStore<User>. - /// - internal static string StoreNotIUserAuthenticationTokenStore - { - get { return GetString("StoreNotIUserAuthenticationTokenStore"); } - } - - /// - /// Store does not implement IUserAuthenticationTokenStore<User>. - /// - internal static string FormatStoreNotIUserAuthenticationTokenStore() - { - return GetString("StoreNotIUserAuthenticationTokenStore"); - } - - /// - /// Store does not implement IUserClaimStore<TUser>. - /// - internal static string StoreNotIUserClaimStore - { - get { return GetString("StoreNotIUserClaimStore"); } - } - - /// - /// Store does not implement IUserClaimStore<TUser>. - /// - internal static string FormatStoreNotIUserClaimStore() - { - return GetString("StoreNotIUserClaimStore"); - } - - /// - /// Store does not implement IUserConfirmationStore<TUser>. - /// - internal static string StoreNotIUserConfirmationStore - { - get { return GetString("StoreNotIUserConfirmationStore"); } - } - - /// - /// Store does not implement IUserConfirmationStore<TUser>. - /// - internal static string FormatStoreNotIUserConfirmationStore() - { - return GetString("StoreNotIUserConfirmationStore"); - } - - /// - /// Store does not implement IUserEmailStore<TUser>. - /// - internal static string StoreNotIUserEmailStore - { - get { return GetString("StoreNotIUserEmailStore"); } - } - - /// - /// Store does not implement IUserEmailStore<TUser>. - /// - internal static string FormatStoreNotIUserEmailStore() - { - return GetString("StoreNotIUserEmailStore"); - } - - /// - /// Store does not implement IUserLockoutStore<TUser>. - /// - internal static string StoreNotIUserLockoutStore - { - get { return GetString("StoreNotIUserLockoutStore"); } - } - - /// - /// Store does not implement IUserLockoutStore<TUser>. - /// - internal static string FormatStoreNotIUserLockoutStore() - { - return GetString("StoreNotIUserLockoutStore"); - } - - /// - /// Store does not implement IUserLoginStore<TUser>. - /// - internal static string StoreNotIUserLoginStore - { - get { return GetString("StoreNotIUserLoginStore"); } - } - - /// - /// Store does not implement IUserLoginStore<TUser>. - /// - internal static string FormatStoreNotIUserLoginStore() - { - return GetString("StoreNotIUserLoginStore"); - } - - /// - /// Store does not implement IUserPasswordStore<TUser>. - /// - internal static string StoreNotIUserPasswordStore - { - get { return GetString("StoreNotIUserPasswordStore"); } - } - - /// - /// Store does not implement IUserPasswordStore<TUser>. - /// - internal static string FormatStoreNotIUserPasswordStore() - { - return GetString("StoreNotIUserPasswordStore"); - } - - /// - /// Store does not implement IUserPhoneNumberStore<TUser>. - /// - internal static string StoreNotIUserPhoneNumberStore - { - get { return GetString("StoreNotIUserPhoneNumberStore"); } - } - - /// - /// Store does not implement IUserPhoneNumberStore<TUser>. - /// - internal static string FormatStoreNotIUserPhoneNumberStore() - { - return GetString("StoreNotIUserPhoneNumberStore"); - } - - /// - /// Store does not implement IUserRoleStore<TUser>. - /// - internal static string StoreNotIUserRoleStore - { - get { return GetString("StoreNotIUserRoleStore"); } - } - - /// - /// Store does not implement IUserRoleStore<TUser>. - /// - internal static string FormatStoreNotIUserRoleStore() - { - return GetString("StoreNotIUserRoleStore"); - } - - /// - /// Store does not implement IUserSecurityStampStore<TUser>. - /// - internal static string StoreNotIUserSecurityStampStore - { - get { return GetString("StoreNotIUserSecurityStampStore"); } - } - - /// - /// Store does not implement IUserSecurityStampStore<TUser>. - /// - internal static string FormatStoreNotIUserSecurityStampStore() - { - return GetString("StoreNotIUserSecurityStampStore"); - } - - /// - /// Store does not implement IUserAuthenticatorKeyStore<User>. - /// - internal static string StoreNotIUserAuthenticatorKeyStore - { - get { return GetString("StoreNotIUserAuthenticatorKeyStore"); } - } - - /// - /// Store does not implement IUserAuthenticatorKeyStore<User>. - /// - internal static string FormatStoreNotIUserAuthenticatorKeyStore() - { - return GetString("StoreNotIUserAuthenticatorKeyStore"); - } - - /// - /// Store does not implement IUserTwoFactorStore<TUser>. - /// - internal static string StoreNotIUserTwoFactorStore - { - get { return GetString("StoreNotIUserTwoFactorStore"); } - } - - /// - /// Store does not implement IUserTwoFactorStore<TUser>. - /// - internal static string FormatStoreNotIUserTwoFactorStore() - { - return GetString("StoreNotIUserTwoFactorStore"); - } - - /// - /// Recovery code redemption failed. - /// - internal static string RecoveryCodeRedemptionFailed - { - get { return GetString("RecoveryCodeRedemptionFailed"); } - } - - /// - /// Recovery code redemption failed. - /// - internal static string FormatRecoveryCodeRedemptionFailed() - { - return GetString("RecoveryCodeRedemptionFailed"); - } - - /// - /// User already has a password set. - /// - internal static string UserAlreadyHasPassword - { - get { return GetString("UserAlreadyHasPassword"); } - } - - /// - /// User already has a password set. - /// - internal static string FormatUserAlreadyHasPassword() - { - return GetString("UserAlreadyHasPassword"); - } - - /// - /// User already in role '{0}'. - /// - internal static string UserAlreadyInRole - { - get { return GetString("UserAlreadyInRole"); } - } - - /// - /// User already in role '{0}'. - /// - internal static string FormatUserAlreadyInRole(object p0) - { - return string.Format(CultureInfo.CurrentCulture, GetString("UserAlreadyInRole"), p0); - } - - /// - /// User is locked out. - /// - internal static string UserLockedOut - { - get { return GetString("UserLockedOut"); } - } - - /// - /// User is locked out. - /// - internal static string FormatUserLockedOut() - { - return GetString("UserLockedOut"); - } - - /// - /// Lockout is not enabled for this user. - /// - internal static string UserLockoutNotEnabled - { - get { return GetString("UserLockoutNotEnabled"); } - } - - /// - /// Lockout is not enabled for this user. - /// - internal static string FormatUserLockoutNotEnabled() - { - return GetString("UserLockoutNotEnabled"); - } - - /// - /// User {0} does not exist. - /// - internal static string UserNameNotFound - { - get { return GetString("UserNameNotFound"); } - } - - /// - /// User {0} does not exist. - /// - internal static string FormatUserNameNotFound(object p0) - { - return string.Format(CultureInfo.CurrentCulture, GetString("UserNameNotFound"), p0); - } - - /// - /// User is not in role '{0}'. - /// - internal static string UserNotInRole - { - get { return GetString("UserNotInRole"); } - } - - /// - /// User is not in role '{0}'. - /// - internal static string FormatUserNotInRole(object p0) - { - return string.Format(CultureInfo.CurrentCulture, GetString("UserNotInRole"), p0); - } - - /// - /// Store does not implement IUserTwoFactorRecoveryCodeStore<User>. - /// - internal static string StoreNotIUserTwoFactorRecoveryCodeStore - { - get { return GetString("StoreNotIUserTwoFactorRecoveryCodeStore"); } - } - - /// - /// Store does not implement IUserTwoFactorRecoveryCodeStore<User>. - /// - internal static string FormatStoreNotIUserTwoFactorRecoveryCodeStore() - { - return GetString("StoreNotIUserTwoFactorRecoveryCodeStore"); - } - - /// - /// Passwords must use at least {0} different characters. - /// - internal static string PasswordRequiresUniqueChars - { - get { return GetString("PasswordRequiresUniqueChars"); } - } - - /// - /// Passwords must use at least {0} different characters. - /// - internal static string FormatPasswordRequiresUniqueChars(object p0) - { - return string.Format(CultureInfo.CurrentCulture, GetString("PasswordRequiresUniqueChars"), p0); - } - private static string GetString(string name, params string[] formatterNames) { var value = _resourceManager.GetString(name); diff --git a/src/Microsoft.AspNetCore.Identity/Resources.resx b/src/Microsoft.AspNetCore.Identity/Resources.resx index 39a1443a4b..0c4e8fddfe 100644 --- a/src/Microsoft.AspNetCore.Identity/Resources.resx +++ b/src/Microsoft.AspNetCore.Identity/Resources.resx @@ -117,30 +117,6 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - Optimistic concurrency failure, object has been modified. - Error when optimistic concurrency fails - - - An unknown failure has occurred. - Default identity result error message - - - Email '{0}' is already taken. - Error for duplicate emails - - - Role name '{0}' is already taken. - Error for duplicate roles - - - User name '{0}' is already taken. - Error for duplicate user names - - - Email '{0}' is invalid. - Invalid email - Type {0} must derive from {1}<{2}>. Error when the manager type is not derived correctly @@ -153,156 +129,4 @@ The iteration count must be a positive integer. Error when the iteration count is < 1. - - Role name '{0}' is invalid. - Error for invalid role names - - - Invalid token. - Error when a token is not recognized - - - User name '{0}' is invalid, can only contain letters or digits. - User names can only contain letters or digits - - - A user with this login already exists. - Error when a login already linked - - - AddIdentity must be called on the service collection. - Error when AddIdentity is not called - - - No IUserTokenProvider named '{0}' is registered. - Error when there is no IUserTokenProvider - - - User security stamp cannot be null. - Error when a user's security stamp is null. - - - Incorrect password. - Error when a password doesn't match - - - Passwords must have at least one digit ('0'-'9'). - Error when passwords do not have a digit - - - Passwords must have at least one lowercase ('a'-'z'). - Error when passwords do not have a lowercase letter - - - Passwords must have at least one non alphanumeric character. - Error when password does not have enough non alphanumeric characters - - - Passwords must have at least one uppercase ('A'-'Z'). - Error when passwords do not have an uppercase letter - - - Passwords must be at least {0} characters. - Error message for passwords that are too short - - - Role {0} does not exist. - Error when a role does not exist - - - Store does not implement IQueryableRoleStore<TRole>. - Error when the store does not implement this interface - - - Store does not implement IQueryableUserStore<TUser>. - Error when the store does not implement this interface - - - Store does not implement IRoleClaimStore<TRole>. - Error when the store does not implement this interface - - - Store does not implement IUserAuthenticationTokenStore<User>. - Error when the store does not implement this interface - - - Store does not implement IUserClaimStore<TUser>. - Error when the store does not implement this interface - - - Store does not implement IUserConfirmationStore<TUser>. - Error when the store does not implement this interface - - - Store does not implement IUserEmailStore<TUser>. - Error when the store does not implement this interface - - - Store does not implement IUserLockoutStore<TUser>. - Error when the store does not implement this interface - - - Store does not implement IUserLoginStore<TUser>. - Error when the store does not implement this interface - - - Store does not implement IUserPasswordStore<TUser>. - Error when the store does not implement this interface - - - Store does not implement IUserPhoneNumberStore<TUser>. - Error when the store does not implement this interface - - - Store does not implement IUserRoleStore<TUser>. - Error when the store does not implement this interface - - - Store does not implement IUserSecurityStampStore<TUser>. - Error when the store does not implement this interface - - - Store does not implement IUserAuthenticatorKeyStore<User>. - Error when the store does not implement this interface - - - Store does not implement IUserTwoFactorStore<TUser>. - Error when the store does not implement this interface - - - Recovery code redemption failed. - Error when a recovery code is not redeemed. - - - User already has a password set. - Error when AddPasswordAsync called when a user already has a password - - - User already in role '{0}'. - Error when a user is already in a role - - - User is locked out. - Error when a user is locked out - - - Lockout is not enabled for this user. - Error when lockout is not enabled - - - User {0} does not exist. - Error when a user does not exist - - - User is not in role '{0}'. - Error when a user is not in the role - - - Store does not implement IUserTwoFactorRecoveryCodeStore<User>. - Error when the store does not implement this interface - - - Passwords must use at least {0} different characters. - Error message for passwords that are based on similar characters - \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Identity/SecurityStampValidator.cs b/src/Microsoft.AspNetCore.Identity/SecurityStampValidator.cs index e5873a69d0..1307997d42 100644 --- a/src/Microsoft.AspNetCore.Identity/SecurityStampValidator.cs +++ b/src/Microsoft.AspNetCore.Identity/SecurityStampValidator.cs @@ -18,7 +18,7 @@ namespace Microsoft.AspNetCore.Identity public class SecurityStampValidator : ISecurityStampValidator where TUser : class { private readonly SignInManager _signInManager; - private readonly IdentityOptions _options; + private readonly SecurityStampValidatorOptions _options; private ISystemClock _clock; /// @@ -27,7 +27,7 @@ namespace Microsoft.AspNetCore.Identity /// Used to access the . /// The . /// The system clock. - public SecurityStampValidator(IOptions options, SignInManager signInManager, ISystemClock clock) + public SecurityStampValidator(IOptions options, SignInManager signInManager, ISystemClock clock) { if (options == null) { @@ -63,7 +63,7 @@ namespace Microsoft.AspNetCore.Identity if (issuedUtc != null) { var timeElapsed = currentUtc.Subtract(issuedUtc.Value); - validate = timeElapsed > _options.SecurityStampValidationInterval; + validate = timeElapsed > _options.ValidationInterval; } if (validate) { @@ -72,7 +72,7 @@ namespace Microsoft.AspNetCore.Identity { var newPrincipal = await _signInManager.CreateUserPrincipalAsync(user); - if (_options.OnSecurityStampRefreshingPrincipal != null) + if (_options.OnRefreshingPrincipal != null) { var replaceContext = new SecurityStampRefreshingPrincipalContext { @@ -81,7 +81,7 @@ namespace Microsoft.AspNetCore.Identity }; // Note: a null principal is allowed and results in a failed authentication. - await _options.OnSecurityStampRefreshingPrincipal(replaceContext); + await _options.OnRefreshingPrincipal(replaceContext); newPrincipal = replaceContext.NewPrincipal; } diff --git a/src/Microsoft.AspNetCore.Identity/SecurityStampValidatorOptions.cs b/src/Microsoft.AspNetCore.Identity/SecurityStampValidatorOptions.cs new file mode 100644 index 0000000000..08380ad0f0 --- /dev/null +++ b/src/Microsoft.AspNetCore.Identity/SecurityStampValidatorOptions.cs @@ -0,0 +1,27 @@ +// 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.Threading.Tasks; + +namespace Microsoft.AspNetCore.Identity +{ + /// + /// Options for . + /// + public class SecurityStampValidatorOptions + { + /// + /// Gets or sets the after which security stamps are re-validated. + /// + /// + /// The after which security stamps are re-validated. + /// + public TimeSpan ValidationInterval { get; set; } = TimeSpan.FromMinutes(30); + + /// + /// Invoked when the default security stamp validator replaces the user's ClaimsPrincipal in the cookie. + /// + public Func OnRefreshingPrincipal { get; set; } + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Identity/SignInManager.cs b/src/Microsoft.AspNetCore.Identity/SignInManager.cs index f40afcd499..566477cd1b 100644 --- a/src/Microsoft.AspNetCore.Identity/SignInManager.cs +++ b/src/Microsoft.AspNetCore.Identity/SignInManager.cs @@ -126,7 +126,7 @@ namespace Microsoft.AspNetCore.Identity throw new ArgumentNullException(nameof(principal)); } return principal?.Identities != null && - principal.Identities.Any(i => i.AuthenticationType == Options.Cookies.ApplicationCookieAuthenticationScheme); + principal.Identities.Any(i => i.AuthenticationType == IdentityConstants.ApplicationScheme); } /// @@ -161,7 +161,7 @@ namespace Microsoft.AspNetCore.Identity /// The task object representing the asynchronous operation. public virtual async Task RefreshSignInAsync(TUser user) { - var auth = await Context.AuthenticateAsync(Options.Cookies.ApplicationCookieAuthenticationScheme); + var auth = await Context.AuthenticateAsync(IdentityConstants.ApplicationScheme); var authenticationMethod = auth?.Principal?.FindFirstValue(ClaimTypes.AuthenticationMethod); await SignInAsync(user, auth?.Properties, authenticationMethod); } @@ -193,7 +193,7 @@ namespace Microsoft.AspNetCore.Identity { userPrincipal.Identities.First().AddClaim(new Claim(ClaimTypes.AuthenticationMethod, authenticationMethod)); } - await Context.SignInAsync(Options.Cookies.ApplicationCookieAuthenticationScheme, + await Context.SignInAsync(IdentityConstants.ApplicationScheme, userPrincipal, authenticationProperties ?? new AuthenticationProperties()); } @@ -203,9 +203,9 @@ namespace Microsoft.AspNetCore.Identity /// public virtual async Task SignOutAsync() { - await Context.SignOutAsync(Options.Cookies.ApplicationCookieAuthenticationScheme); - await Context.SignOutAsync(Options.Cookies.ExternalCookieAuthenticationScheme); - await Context.SignOutAsync(Options.Cookies.TwoFactorUserIdCookieAuthenticationScheme); + await Context.SignOutAsync(IdentityConstants.ApplicationScheme); + await Context.SignOutAsync(IdentityConstants.ExternalScheme); + await Context.SignOutAsync(IdentityConstants.TwoFactorUserIdScheme); } /// @@ -333,7 +333,7 @@ namespace Microsoft.AspNetCore.Identity public virtual async Task IsTwoFactorClientRememberedAsync(TUser user) { var userId = await UserManager.GetUserIdAsync(user); - var result = await Context.AuthenticateAsync(Options.Cookies.TwoFactorRememberMeCookieAuthenticationScheme); + var result = await Context.AuthenticateAsync(IdentityConstants.TwoFactorRememberMeScheme); return (result?.Principal != null && result.Principal.FindFirstValue(ClaimTypes.Name) == userId); } @@ -346,9 +346,9 @@ namespace Microsoft.AspNetCore.Identity public virtual async Task RememberTwoFactorClientAsync(TUser user) { var userId = await UserManager.GetUserIdAsync(user); - var rememberBrowserIdentity = new ClaimsIdentity(Options.Cookies.TwoFactorRememberMeCookieAuthenticationScheme); + var rememberBrowserIdentity = new ClaimsIdentity(IdentityConstants.TwoFactorRememberMeScheme); rememberBrowserIdentity.AddClaim(new Claim(ClaimTypes.Name, userId)); - await Context.SignInAsync(Options.Cookies.TwoFactorRememberMeCookieAuthenticationScheme, + await Context.SignInAsync(IdentityConstants.TwoFactorRememberMeScheme, new ClaimsPrincipal(rememberBrowserIdentity), new AuthenticationProperties { IsPersistent = true }); } @@ -359,7 +359,7 @@ namespace Microsoft.AspNetCore.Identity /// The task object representing the asynchronous operation. public virtual Task ForgetTwoFactorClientAsync() { - return Context.SignOutAsync(Options.Cookies.TwoFactorRememberMeCookieAuthenticationScheme); + return Context.SignOutAsync(IdentityConstants.TwoFactorRememberMeScheme); } /// @@ -399,10 +399,10 @@ namespace Microsoft.AspNetCore.Identity // Cleanup external cookie if (twoFactorInfo.LoginProvider != null) { - await Context.SignOutAsync(Options.Cookies.ExternalCookieAuthenticationScheme); + await Context.SignOutAsync(IdentityConstants.ExternalScheme); } // Cleanup two factor user id cookie - await Context.SignOutAsync(Options.Cookies.TwoFactorUserIdCookieAuthenticationScheme); + await Context.SignOutAsync(IdentityConstants.TwoFactorUserIdScheme); if (rememberClient) { await RememberTwoFactorClientAsync(user); @@ -556,7 +556,7 @@ namespace Microsoft.AspNetCore.Identity /// for the sign-in attempt. public virtual async Task GetExternalLoginInfoAsync(string expectedXsrf = null) { - var auth = await Context.AuthenticateAsync(Options.Cookies.ExternalCookieAuthenticationScheme); + var auth = await Context.AuthenticateAsync(IdentityConstants.ExternalScheme); var items = auth?.Properties?.Items; if (auth?.Principal == null || items == null || !items.ContainsKey(LoginProviderKey)) { @@ -648,7 +648,7 @@ namespace Microsoft.AspNetCore.Identity /// A containing the user 2fa information. internal ClaimsPrincipal StoreTwoFactorInfo(string userId, string loginProvider) { - var identity = new ClaimsIdentity(Options.Cookies.TwoFactorUserIdCookieAuthenticationScheme); + var identity = new ClaimsIdentity(IdentityConstants.TwoFactorUserIdScheme); identity.AddClaim(new Claim(ClaimTypes.Name, userId)); if (loginProvider != null) { @@ -663,7 +663,7 @@ namespace Microsoft.AspNetCore.Identity { return null; } - var identity = new ClaimsIdentity(Options.Cookies.TwoFactorUserIdCookieAuthenticationScheme); + var identity = new ClaimsIdentity(IdentityConstants.TwoFactorUserIdScheme); identity.AddClaim(new Claim(ClaimTypes.Name, info.UserId)); if (info.LoginProvider != null) { @@ -683,14 +683,14 @@ namespace Microsoft.AspNetCore.Identity { // Store the userId for use after two factor check var userId = await UserManager.GetUserIdAsync(user); - await Context.SignInAsync(Options.Cookies.TwoFactorUserIdCookieAuthenticationScheme, StoreTwoFactorInfo(userId, loginProvider)); + await Context.SignInAsync(IdentityConstants.TwoFactorUserIdScheme, StoreTwoFactorInfo(userId, loginProvider)); return SignInResult.TwoFactorRequired; } } // Cleanup external cookie if (loginProvider != null) { - await Context.SignOutAsync(Options.Cookies.ExternalCookieAuthenticationScheme); + await Context.SignOutAsync(IdentityConstants.ExternalScheme); } await SignInAsync(user, isPersistent, loginProvider); return SignInResult.Success; @@ -698,7 +698,7 @@ namespace Microsoft.AspNetCore.Identity private async Task RetrieveTwoFactorInfoAsync() { - var result = await Context.AuthenticateAsync(Options.Cookies.TwoFactorUserIdCookieAuthenticationScheme); + var result = await Context.AuthenticateAsync(IdentityConstants.TwoFactorUserIdScheme); if (result?.Principal != null) { return new TwoFactorAuthenticationInfo diff --git a/src/Microsoft.AspNetCore.Identity/TotpSecurityStampBasedTokenProvider.cs b/src/Microsoft.AspNetCore.Identity/TotpSecurityStampBasedTokenProvider.cs index 82d27668ad..117fb0752f 100644 --- a/src/Microsoft.AspNetCore.Identity/TotpSecurityStampBasedTokenProvider.cs +++ b/src/Microsoft.AspNetCore.Identity/TotpSecurityStampBasedTokenProvider.cs @@ -1,6 +1,5 @@ using System; using System.Globalization; -using System.Threading; using System.Threading.Tasks; namespace Microsoft.AspNetCore.Identity diff --git a/src/Microsoft.AspNetCore.Identity/UpperInvariantLookupNormalizer.cs b/src/Microsoft.AspNetCore.Identity/UpperInvariantLookupNormalizer.cs index 3ab3f9f647..ec3fe26420 100644 --- a/src/Microsoft.AspNetCore.Identity/UpperInvariantLookupNormalizer.cs +++ b/src/Microsoft.AspNetCore.Identity/UpperInvariantLookupNormalizer.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.AspNetCore.Identity { /// diff --git a/src/Microsoft.AspNetCore.Identity/UserClaimsPrincipalFactory.cs b/src/Microsoft.AspNetCore.Identity/UserClaimsPrincipalFactory.cs index a60f61dc55..e58ba0ae99 100644 --- a/src/Microsoft.AspNetCore.Identity/UserClaimsPrincipalFactory.cs +++ b/src/Microsoft.AspNetCore.Identity/UserClaimsPrincipalFactory.cs @@ -83,7 +83,7 @@ namespace Microsoft.AspNetCore.Identity } var userId = await UserManager.GetUserIdAsync(user); var userName = await UserManager.GetUserNameAsync(user); - var id = new ClaimsIdentity(Options.Cookies.ApplicationCookieAuthenticationScheme, + var id = new ClaimsIdentity(IdentityConstants.ApplicationScheme, Options.ClaimsIdentity.UserNameClaimType, Options.ClaimsIdentity.RoleClaimType); id.AddClaim(new Claim(Options.ClaimsIdentity.UserIdClaimType, userId)); diff --git a/src/Microsoft.Extensions.Identity.Core/Base32.cs b/src/Microsoft.Extensions.Identity.Core/Base32.cs new file mode 100644 index 0000000000..579a58feac --- /dev/null +++ b/src/Microsoft.Extensions.Identity.Core/Base32.cs @@ -0,0 +1,119 @@ +// 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.Text; + +namespace Microsoft.AspNetCore.Identity +{ + // See http://tools.ietf.org/html/rfc3548#section-5 + internal static class Base32 + { + private static readonly string _base32Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; + + public static string ToBase32(byte[] input) + { + if (input == null) + { + throw new ArgumentNullException(nameof(input)); + } + + StringBuilder sb = new StringBuilder(); + for (int offset = 0; offset < input.Length;) + { + byte a, b, c, d, e, f, g, h; + int numCharsToOutput = GetNextGroup(input, ref offset, out a, out b, out c, out d, out e, out f, out g, out h); + + sb.Append((numCharsToOutput >= 1) ? _base32Chars[a] : '='); + sb.Append((numCharsToOutput >= 2) ? _base32Chars[b] : '='); + sb.Append((numCharsToOutput >= 3) ? _base32Chars[c] : '='); + sb.Append((numCharsToOutput >= 4) ? _base32Chars[d] : '='); + sb.Append((numCharsToOutput >= 5) ? _base32Chars[e] : '='); + sb.Append((numCharsToOutput >= 6) ? _base32Chars[f] : '='); + sb.Append((numCharsToOutput >= 7) ? _base32Chars[g] : '='); + sb.Append((numCharsToOutput >= 8) ? _base32Chars[h] : '='); + } + + return sb.ToString(); + } + + public static byte[] FromBase32(string input) + { + if (input == null) + { + throw new ArgumentNullException(nameof(input)); + } + input = input.TrimEnd('=').ToUpperInvariant(); + if (input.Length == 0) + { + return new byte[0]; + } + + var output = new byte[input.Length * 5 / 8]; + var bitIndex = 0; + var inputIndex = 0; + var outputBits = 0; + var outputIndex = 0; + while (outputIndex < output.Length) + { + var byteIndex = _base32Chars.IndexOf(input[inputIndex]); + if (byteIndex < 0) + { + throw new FormatException(); + } + + var bits = Math.Min(5 - bitIndex, 8 - outputBits); + output[outputIndex] <<= bits; + output[outputIndex] |= (byte)(byteIndex >> (5 - (bitIndex + bits))); + + bitIndex += bits; + if (bitIndex >= 5) + { + inputIndex++; + bitIndex = 0; + } + + outputBits += bits; + if (outputBits >= 8) + { + outputIndex++; + outputBits = 0; + } + } + return output; + } + + // returns the number of bytes that were output + private static int GetNextGroup(byte[] input, ref int offset, out byte a, out byte b, out byte c, out byte d, out byte e, out byte f, out byte g, out byte h) + { + uint b1, b2, b3, b4, b5; + + int retVal; + switch (offset - input.Length) + { + case 1: retVal = 2; break; + case 2: retVal = 4; break; + case 3: retVal = 5; break; + case 4: retVal = 7; break; + default: retVal = 8; break; + } + + b1 = (offset < input.Length) ? input[offset++] : 0U; + b2 = (offset < input.Length) ? input[offset++] : 0U; + b3 = (offset < input.Length) ? input[offset++] : 0U; + b4 = (offset < input.Length) ? input[offset++] : 0U; + b5 = (offset < input.Length) ? input[offset++] : 0U; + + a = (byte)(b1 >> 3); + b = (byte)(((b1 & 0x07) << 2) | (b2 >> 6)); + c = (byte)((b2 >> 1) & 0x1f); + d = (byte)(((b2 & 0x01) << 4) | (b3 >> 4)); + e = (byte)(((b3 & 0x0f) << 1) | (b4 >> 7)); + f = (byte)((b4 >> 2) & 0x1f); + g = (byte)(((b4 & 0x3) << 3) | (b5 >> 5)); + h = (byte)(b5 & 0x1f); + + return retVal; + } + } +} diff --git a/src/Microsoft.AspNetCore.Identity/ClaimsIdentityOptions.cs b/src/Microsoft.Extensions.Identity.Core/ClaimsIdentityOptions.cs similarity index 100% rename from src/Microsoft.AspNetCore.Identity/ClaimsIdentityOptions.cs rename to src/Microsoft.Extensions.Identity.Core/ClaimsIdentityOptions.cs diff --git a/src/Microsoft.AspNetCore.Identity/ILookupNormalizer.cs b/src/Microsoft.Extensions.Identity.Core/ILookupNormalizer.cs similarity index 100% rename from src/Microsoft.AspNetCore.Identity/ILookupNormalizer.cs rename to src/Microsoft.Extensions.Identity.Core/ILookupNormalizer.cs diff --git a/src/Microsoft.AspNetCore.Identity/IPasswordHasher.cs b/src/Microsoft.Extensions.Identity.Core/IPasswordHasher.cs similarity index 100% rename from src/Microsoft.AspNetCore.Identity/IPasswordHasher.cs rename to src/Microsoft.Extensions.Identity.Core/IPasswordHasher.cs diff --git a/src/Microsoft.AspNetCore.Identity/IPasswordValidator.cs b/src/Microsoft.Extensions.Identity.Core/IPasswordValidator.cs similarity index 100% rename from src/Microsoft.AspNetCore.Identity/IPasswordValidator.cs rename to src/Microsoft.Extensions.Identity.Core/IPasswordValidator.cs diff --git a/src/Microsoft.AspNetCore.Identity/IQueryableRoleStore.cs b/src/Microsoft.Extensions.Identity.Core/IQueryableRoleStore.cs similarity index 100% rename from src/Microsoft.AspNetCore.Identity/IQueryableRoleStore.cs rename to src/Microsoft.Extensions.Identity.Core/IQueryableRoleStore.cs diff --git a/src/Microsoft.AspNetCore.Identity/IQueryableUserStore.cs b/src/Microsoft.Extensions.Identity.Core/IQueryableUserStore.cs similarity index 100% rename from src/Microsoft.AspNetCore.Identity/IQueryableUserStore.cs rename to src/Microsoft.Extensions.Identity.Core/IQueryableUserStore.cs diff --git a/src/Microsoft.AspNetCore.Identity/IRoleClaimStore.cs b/src/Microsoft.Extensions.Identity.Core/IRoleClaimStore.cs similarity index 100% rename from src/Microsoft.AspNetCore.Identity/IRoleClaimStore.cs rename to src/Microsoft.Extensions.Identity.Core/IRoleClaimStore.cs diff --git a/src/Microsoft.AspNetCore.Identity/IRoleStore.cs b/src/Microsoft.Extensions.Identity.Core/IRoleStore.cs similarity index 100% rename from src/Microsoft.AspNetCore.Identity/IRoleStore.cs rename to src/Microsoft.Extensions.Identity.Core/IRoleStore.cs diff --git a/src/Microsoft.AspNetCore.Identity/IRoleValidator.cs b/src/Microsoft.Extensions.Identity.Core/IRoleValidator.cs similarity index 100% rename from src/Microsoft.AspNetCore.Identity/IRoleValidator.cs rename to src/Microsoft.Extensions.Identity.Core/IRoleValidator.cs diff --git a/src/Microsoft.AspNetCore.Identity/IUserAuthenticationTokenStore.cs b/src/Microsoft.Extensions.Identity.Core/IUserAuthenticationTokenStore.cs similarity index 100% rename from src/Microsoft.AspNetCore.Identity/IUserAuthenticationTokenStore.cs rename to src/Microsoft.Extensions.Identity.Core/IUserAuthenticationTokenStore.cs diff --git a/src/Microsoft.AspNetCore.Identity/IUserAuthenticatorInfoStore.cs b/src/Microsoft.Extensions.Identity.Core/IUserAuthenticatorInfoStore.cs similarity index 100% rename from src/Microsoft.AspNetCore.Identity/IUserAuthenticatorInfoStore.cs rename to src/Microsoft.Extensions.Identity.Core/IUserAuthenticatorInfoStore.cs diff --git a/src/Microsoft.AspNetCore.Identity/IUserClaimStore.cs b/src/Microsoft.Extensions.Identity.Core/IUserClaimStore.cs similarity index 100% rename from src/Microsoft.AspNetCore.Identity/IUserClaimStore.cs rename to src/Microsoft.Extensions.Identity.Core/IUserClaimStore.cs diff --git a/src/Microsoft.AspNetCore.Identity/IUserClaimsPrincipalFactory.cs b/src/Microsoft.Extensions.Identity.Core/IUserClaimsPrincipalFactory.cs similarity index 100% rename from src/Microsoft.AspNetCore.Identity/IUserClaimsPrincipalFactory.cs rename to src/Microsoft.Extensions.Identity.Core/IUserClaimsPrincipalFactory.cs diff --git a/src/Microsoft.AspNetCore.Identity/IUserEmailStore.cs b/src/Microsoft.Extensions.Identity.Core/IUserEmailStore.cs similarity index 100% rename from src/Microsoft.AspNetCore.Identity/IUserEmailStore.cs rename to src/Microsoft.Extensions.Identity.Core/IUserEmailStore.cs diff --git a/src/Microsoft.AspNetCore.Identity/IUserLockoutStore.cs b/src/Microsoft.Extensions.Identity.Core/IUserLockoutStore.cs similarity index 100% rename from src/Microsoft.AspNetCore.Identity/IUserLockoutStore.cs rename to src/Microsoft.Extensions.Identity.Core/IUserLockoutStore.cs diff --git a/src/Microsoft.AspNetCore.Identity/IUserLoginStore.cs b/src/Microsoft.Extensions.Identity.Core/IUserLoginStore.cs similarity index 100% rename from src/Microsoft.AspNetCore.Identity/IUserLoginStore.cs rename to src/Microsoft.Extensions.Identity.Core/IUserLoginStore.cs diff --git a/src/Microsoft.AspNetCore.Identity/IUserPasswordStore.cs b/src/Microsoft.Extensions.Identity.Core/IUserPasswordStore.cs similarity index 100% rename from src/Microsoft.AspNetCore.Identity/IUserPasswordStore.cs rename to src/Microsoft.Extensions.Identity.Core/IUserPasswordStore.cs diff --git a/src/Microsoft.AspNetCore.Identity/IUserPhoneNumberStore.cs b/src/Microsoft.Extensions.Identity.Core/IUserPhoneNumberStore.cs similarity index 100% rename from src/Microsoft.AspNetCore.Identity/IUserPhoneNumberStore.cs rename to src/Microsoft.Extensions.Identity.Core/IUserPhoneNumberStore.cs diff --git a/src/Microsoft.AspNetCore.Identity/IUserRoleStore.cs b/src/Microsoft.Extensions.Identity.Core/IUserRoleStore.cs similarity index 100% rename from src/Microsoft.AspNetCore.Identity/IUserRoleStore.cs rename to src/Microsoft.Extensions.Identity.Core/IUserRoleStore.cs diff --git a/src/Microsoft.AspNetCore.Identity/IUserSecurityStampStore.cs b/src/Microsoft.Extensions.Identity.Core/IUserSecurityStampStore.cs similarity index 100% rename from src/Microsoft.AspNetCore.Identity/IUserSecurityStampStore.cs rename to src/Microsoft.Extensions.Identity.Core/IUserSecurityStampStore.cs diff --git a/src/Microsoft.AspNetCore.Identity/IUserStore.cs b/src/Microsoft.Extensions.Identity.Core/IUserStore.cs similarity index 100% rename from src/Microsoft.AspNetCore.Identity/IUserStore.cs rename to src/Microsoft.Extensions.Identity.Core/IUserStore.cs diff --git a/src/Microsoft.AspNetCore.Identity/IUserTwoFactorRecoveryCodeStore.cs b/src/Microsoft.Extensions.Identity.Core/IUserTwoFactorRecoveryCodeStore.cs similarity index 100% rename from src/Microsoft.AspNetCore.Identity/IUserTwoFactorRecoveryCodeStore.cs rename to src/Microsoft.Extensions.Identity.Core/IUserTwoFactorRecoveryCodeStore.cs diff --git a/src/Microsoft.AspNetCore.Identity/IUserTwoFactorStore.cs b/src/Microsoft.Extensions.Identity.Core/IUserTwoFactorStore.cs similarity index 100% rename from src/Microsoft.AspNetCore.Identity/IUserTwoFactorStore.cs rename to src/Microsoft.Extensions.Identity.Core/IUserTwoFactorStore.cs diff --git a/src/Microsoft.AspNetCore.Identity/IUserTwoFactorTokenProvider.cs b/src/Microsoft.Extensions.Identity.Core/IUserTwoFactorTokenProvider.cs similarity index 100% rename from src/Microsoft.AspNetCore.Identity/IUserTwoFactorTokenProvider.cs rename to src/Microsoft.Extensions.Identity.Core/IUserTwoFactorTokenProvider.cs diff --git a/src/Microsoft.AspNetCore.Identity/IUserValidator.cs b/src/Microsoft.Extensions.Identity.Core/IUserValidator.cs similarity index 100% rename from src/Microsoft.AspNetCore.Identity/IUserValidator.cs rename to src/Microsoft.Extensions.Identity.Core/IUserValidator.cs diff --git a/src/Microsoft.AspNetCore.Identity/IdentityError.cs b/src/Microsoft.Extensions.Identity.Core/IdentityError.cs similarity index 100% rename from src/Microsoft.AspNetCore.Identity/IdentityError.cs rename to src/Microsoft.Extensions.Identity.Core/IdentityError.cs diff --git a/src/Microsoft.AspNetCore.Identity/IdentityErrorDescriber.cs b/src/Microsoft.Extensions.Identity.Core/IdentityErrorDescriber.cs similarity index 100% rename from src/Microsoft.AspNetCore.Identity/IdentityErrorDescriber.cs rename to src/Microsoft.Extensions.Identity.Core/IdentityErrorDescriber.cs diff --git a/src/Microsoft.AspNetCore.Identity/IdentityOptions.cs b/src/Microsoft.Extensions.Identity.Core/IdentityOptions.cs similarity index 69% rename from src/Microsoft.AspNetCore.Identity/IdentityOptions.cs rename to src/Microsoft.Extensions.Identity.Core/IdentityOptions.cs index 519a7ad44c..f0f39b3b1a 100644 --- a/src/Microsoft.AspNetCore.Identity/IdentityOptions.cs +++ b/src/Microsoft.Extensions.Identity.Core/IdentityOptions.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; -using System.Threading.Tasks; using Microsoft.AspNetCore.Identity; namespace Microsoft.AspNetCore.Builder @@ -52,14 +50,6 @@ namespace Microsoft.AspNetCore.Builder /// 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. /// @@ -67,18 +57,5 @@ namespace Microsoft.AspNetCore.Builder /// The for the identity system. /// public TokenOptions Tokens { get; set; } = new TokenOptions(); - - /// - /// Gets or sets the after which security stamps are re-validated. - /// - /// - /// The after which security stamps are re-validated. - /// - public TimeSpan SecurityStampValidationInterval { get; set; } = TimeSpan.FromMinutes(30); - - /// - /// Invoked when the default security stamp validator replaces the user's ClaimsPrincipal in the cookie. - /// - public Func OnSecurityStampRefreshingPrincipal { get; set; } } } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Identity/IdentityResult.cs b/src/Microsoft.Extensions.Identity.Core/IdentityResult.cs similarity index 100% rename from src/Microsoft.AspNetCore.Identity/IdentityResult.cs rename to src/Microsoft.Extensions.Identity.Core/IdentityResult.cs diff --git a/src/Microsoft.AspNetCore.Identity/LockoutOptions.cs b/src/Microsoft.Extensions.Identity.Core/LockoutOptions.cs similarity index 100% rename from src/Microsoft.AspNetCore.Identity/LockoutOptions.cs rename to src/Microsoft.Extensions.Identity.Core/LockoutOptions.cs diff --git a/src/Microsoft.Extensions.Identity.Core/Microsoft.Extensions.Identity.Core.csproj b/src/Microsoft.Extensions.Identity.Core/Microsoft.Extensions.Identity.Core.csproj new file mode 100644 index 0000000000..6fbe472822 --- /dev/null +++ b/src/Microsoft.Extensions.Identity.Core/Microsoft.Extensions.Identity.Core.csproj @@ -0,0 +1,24 @@ + + + + + + ASP.NET Core Identity is the membership system for building ASP.NET Core web applications, including membership, login, and user data. ASP.NET Core Identity allows you to add login features to your application and makes it easy to customize data about the logged in user. + netstandard1.3 + true + aspnetcore;identity;membership + false + + + + + + + + + + + + + + diff --git a/src/Microsoft.AspNetCore.Identity/PasswordHasherCompatibilityMode.cs b/src/Microsoft.Extensions.Identity.Core/PasswordHasherCompatibilityMode.cs similarity index 100% rename from src/Microsoft.AspNetCore.Identity/PasswordHasherCompatibilityMode.cs rename to src/Microsoft.Extensions.Identity.Core/PasswordHasherCompatibilityMode.cs diff --git a/src/Microsoft.AspNetCore.Identity/PasswordOptions.cs b/src/Microsoft.Extensions.Identity.Core/PasswordOptions.cs similarity index 100% rename from src/Microsoft.AspNetCore.Identity/PasswordOptions.cs rename to src/Microsoft.Extensions.Identity.Core/PasswordOptions.cs diff --git a/src/Microsoft.AspNetCore.Identity/PasswordVerificationResult.cs b/src/Microsoft.Extensions.Identity.Core/PasswordVerificationResult.cs similarity index 100% rename from src/Microsoft.AspNetCore.Identity/PasswordVerificationResult.cs rename to src/Microsoft.Extensions.Identity.Core/PasswordVerificationResult.cs diff --git a/src/Microsoft.AspNetCore.Identity/PrincipalExtensions.cs b/src/Microsoft.Extensions.Identity.Core/PrincipalExtensions.cs similarity index 100% rename from src/Microsoft.AspNetCore.Identity/PrincipalExtensions.cs rename to src/Microsoft.Extensions.Identity.Core/PrincipalExtensions.cs diff --git a/src/Microsoft.Extensions.Identity.Core/Properties/AssemblyInfo.cs b/src/Microsoft.Extensions.Identity.Core/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..c81ac16167 --- /dev/null +++ b/src/Microsoft.Extensions.Identity.Core/Properties/AssemblyInfo.cs @@ -0,0 +1,10 @@ +// 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.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Identity.Specification.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] +[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Identity.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] +[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] +[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Identity.EntityFrameworkCore.InMemory.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] +[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Identity.InMemory.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")] diff --git a/src/Microsoft.Extensions.Identity.Core/Properties/Resources.Designer.cs b/src/Microsoft.Extensions.Identity.Core/Properties/Resources.Designer.cs new file mode 100644 index 0000000000..d39c98abad --- /dev/null +++ b/src/Microsoft.Extensions.Identity.Core/Properties/Resources.Designer.cs @@ -0,0 +1,782 @@ +// +namespace Microsoft.AspNetCore.Identity +{ + using System.Globalization; + using System.Reflection; + using System.Resources; + + internal static class Resources + { + private static readonly ResourceManager _resourceManager + = new ResourceManager("Microsoft.Extensions.Identity.Core.Resources", typeof(Resources).GetTypeInfo().Assembly); + + /// + /// Optimistic concurrency failure, object has been modified. + /// + internal static string ConcurrencyFailure + { + get { return GetString("ConcurrencyFailure"); } + } + + /// + /// Optimistic concurrency failure, object has been modified. + /// + internal static string FormatConcurrencyFailure() + { + return GetString("ConcurrencyFailure"); + } + + /// + /// An unknown failure has occurred. + /// + internal static string DefaultError + { + get { return GetString("DefaultError"); } + } + + /// + /// An unknown failure has occurred. + /// + internal static string FormatDefaultError() + { + return GetString("DefaultError"); + } + + /// + /// Email '{0}' is already taken. + /// + internal static string DuplicateEmail + { + get { return GetString("DuplicateEmail"); } + } + + /// + /// Email '{0}' is already taken. + /// + internal static string FormatDuplicateEmail(object p0) + { + return string.Format(CultureInfo.CurrentCulture, GetString("DuplicateEmail"), p0); + } + + /// + /// Role name '{0}' is already taken. + /// + internal static string DuplicateRoleName + { + get { return GetString("DuplicateRoleName"); } + } + + /// + /// Role name '{0}' is already taken. + /// + internal static string FormatDuplicateRoleName(object p0) + { + return string.Format(CultureInfo.CurrentCulture, GetString("DuplicateRoleName"), p0); + } + + /// + /// User name '{0}' is already taken. + /// + internal static string DuplicateUserName + { + get { return GetString("DuplicateUserName"); } + } + + /// + /// User name '{0}' is already taken. + /// + internal static string FormatDuplicateUserName(object p0) + { + return string.Format(CultureInfo.CurrentCulture, GetString("DuplicateUserName"), p0); + } + + /// + /// Email '{0}' is invalid. + /// + internal static string InvalidEmail + { + get { return GetString("InvalidEmail"); } + } + + /// + /// Email '{0}' is invalid. + /// + internal static string FormatInvalidEmail(object p0) + { + return string.Format(CultureInfo.CurrentCulture, GetString("InvalidEmail"), p0); + } + + /// + /// Type {0} must derive from {1}<{2}>. + /// + internal static string InvalidManagerType + { + get { return GetString("InvalidManagerType"); } + } + + /// + /// Type {0} must derive from {1}<{2}>. + /// + internal static string FormatInvalidManagerType(object p0, object p1, object p2) + { + return string.Format(CultureInfo.CurrentCulture, GetString("InvalidManagerType"), p0, p1, p2); + } + + /// + /// The provided PasswordHasherCompatibilityMode is invalid. + /// + internal static string InvalidPasswordHasherCompatibilityMode + { + get { return GetString("InvalidPasswordHasherCompatibilityMode"); } + } + + /// + /// The provided PasswordHasherCompatibilityMode is invalid. + /// + internal static string FormatInvalidPasswordHasherCompatibilityMode() + { + return GetString("InvalidPasswordHasherCompatibilityMode"); + } + + /// + /// The iteration count must be a positive integer. + /// + internal static string InvalidPasswordHasherIterationCount + { + get { return GetString("InvalidPasswordHasherIterationCount"); } + } + + /// + /// The iteration count must be a positive integer. + /// + internal static string FormatInvalidPasswordHasherIterationCount() + { + return GetString("InvalidPasswordHasherIterationCount"); + } + + /// + /// Role name '{0}' is invalid. + /// + internal static string InvalidRoleName + { + get { return GetString("InvalidRoleName"); } + } + + /// + /// Role name '{0}' is invalid. + /// + internal static string FormatInvalidRoleName(object p0) + { + return string.Format(CultureInfo.CurrentCulture, GetString("InvalidRoleName"), p0); + } + + /// + /// Invalid token. + /// + internal static string InvalidToken + { + get { return GetString("InvalidToken"); } + } + + /// + /// Invalid token. + /// + internal static string FormatInvalidToken() + { + return GetString("InvalidToken"); + } + + /// + /// User name '{0}' is invalid, can only contain letters or digits. + /// + internal static string InvalidUserName + { + get { return GetString("InvalidUserName"); } + } + + /// + /// User name '{0}' is invalid, can only contain letters or digits. + /// + internal static string FormatInvalidUserName(object p0) + { + return string.Format(CultureInfo.CurrentCulture, GetString("InvalidUserName"), p0); + } + + /// + /// A user with this login already exists. + /// + internal static string LoginAlreadyAssociated + { + get { return GetString("LoginAlreadyAssociated"); } + } + + /// + /// A user with this login already exists. + /// + internal static string FormatLoginAlreadyAssociated() + { + return GetString("LoginAlreadyAssociated"); + } + + /// + /// AddIdentity must be called on the service collection. + /// + internal static string MustCallAddIdentity + { + get { return GetString("MustCallAddIdentity"); } + } + + /// + /// AddIdentity must be called on the service collection. + /// + internal static string FormatMustCallAddIdentity() + { + return GetString("MustCallAddIdentity"); + } + + /// + /// No IUserTokenProvider named '{0}' is registered. + /// + internal static string NoTokenProvider + { + get { return GetString("NoTokenProvider"); } + } + + /// + /// No IUserTokenProvider named '{0}' is registered. + /// + internal static string FormatNoTokenProvider(object p0) + { + return string.Format(CultureInfo.CurrentCulture, GetString("NoTokenProvider"), p0); + } + + /// + /// User security stamp cannot be null. + /// + internal static string NullSecurityStamp + { + get { return GetString("NullSecurityStamp"); } + } + + /// + /// User security stamp cannot be null. + /// + internal static string FormatNullSecurityStamp() + { + return GetString("NullSecurityStamp"); + } + + /// + /// Incorrect password. + /// + internal static string PasswordMismatch + { + get { return GetString("PasswordMismatch"); } + } + + /// + /// Incorrect password. + /// + internal static string FormatPasswordMismatch() + { + return GetString("PasswordMismatch"); + } + + /// + /// Passwords must have at least one digit ('0'-'9'). + /// + internal static string PasswordRequiresDigit + { + get { return GetString("PasswordRequiresDigit"); } + } + + /// + /// Passwords must have at least one digit ('0'-'9'). + /// + internal static string FormatPasswordRequiresDigit() + { + return GetString("PasswordRequiresDigit"); + } + + /// + /// Passwords must have at least one lowercase ('a'-'z'). + /// + internal static string PasswordRequiresLower + { + get { return GetString("PasswordRequiresLower"); } + } + + /// + /// Passwords must have at least one lowercase ('a'-'z'). + /// + internal static string FormatPasswordRequiresLower() + { + return GetString("PasswordRequiresLower"); + } + + /// + /// Passwords must have at least one non alphanumeric character. + /// + internal static string PasswordRequiresNonAlphanumeric + { + get { return GetString("PasswordRequiresNonAlphanumeric"); } + } + + /// + /// Passwords must have at least one non alphanumeric character. + /// + internal static string FormatPasswordRequiresNonAlphanumeric() + { + return GetString("PasswordRequiresNonAlphanumeric"); + } + + /// + /// Passwords must have at least one uppercase ('A'-'Z'). + /// + internal static string PasswordRequiresUpper + { + get { return GetString("PasswordRequiresUpper"); } + } + + /// + /// Passwords must have at least one uppercase ('A'-'Z'). + /// + internal static string FormatPasswordRequiresUpper() + { + return GetString("PasswordRequiresUpper"); + } + + /// + /// Passwords must be at least {0} characters. + /// + internal static string PasswordTooShort + { + get { return GetString("PasswordTooShort"); } + } + + /// + /// Passwords must be at least {0} characters. + /// + internal static string FormatPasswordTooShort(object p0) + { + return string.Format(CultureInfo.CurrentCulture, GetString("PasswordTooShort"), p0); + } + + /// + /// Role {0} does not exist. + /// + internal static string RoleNotFound + { + get { return GetString("RoleNotFound"); } + } + + /// + /// Role {0} does not exist. + /// + internal static string FormatRoleNotFound(object p0) + { + return string.Format(CultureInfo.CurrentCulture, GetString("RoleNotFound"), p0); + } + + /// + /// Store does not implement IQueryableRoleStore<TRole>. + /// + internal static string StoreNotIQueryableRoleStore + { + get { return GetString("StoreNotIQueryableRoleStore"); } + } + + /// + /// Store does not implement IQueryableRoleStore<TRole>. + /// + internal static string FormatStoreNotIQueryableRoleStore() + { + return GetString("StoreNotIQueryableRoleStore"); + } + + /// + /// Store does not implement IQueryableUserStore<TUser>. + /// + internal static string StoreNotIQueryableUserStore + { + get { return GetString("StoreNotIQueryableUserStore"); } + } + + /// + /// Store does not implement IQueryableUserStore<TUser>. + /// + internal static string FormatStoreNotIQueryableUserStore() + { + return GetString("StoreNotIQueryableUserStore"); + } + + /// + /// Store does not implement IRoleClaimStore<TRole>. + /// + internal static string StoreNotIRoleClaimStore + { + get { return GetString("StoreNotIRoleClaimStore"); } + } + + /// + /// Store does not implement IRoleClaimStore<TRole>. + /// + internal static string FormatStoreNotIRoleClaimStore() + { + return GetString("StoreNotIRoleClaimStore"); + } + + /// + /// Store does not implement IUserAuthenticationTokenStore<User>. + /// + internal static string StoreNotIUserAuthenticationTokenStore + { + get { return GetString("StoreNotIUserAuthenticationTokenStore"); } + } + + /// + /// Store does not implement IUserAuthenticationTokenStore<User>. + /// + internal static string FormatStoreNotIUserAuthenticationTokenStore() + { + return GetString("StoreNotIUserAuthenticationTokenStore"); + } + + /// + /// Store does not implement IUserClaimStore<TUser>. + /// + internal static string StoreNotIUserClaimStore + { + get { return GetString("StoreNotIUserClaimStore"); } + } + + /// + /// Store does not implement IUserClaimStore<TUser>. + /// + internal static string FormatStoreNotIUserClaimStore() + { + return GetString("StoreNotIUserClaimStore"); + } + + /// + /// Store does not implement IUserConfirmationStore<TUser>. + /// + internal static string StoreNotIUserConfirmationStore + { + get { return GetString("StoreNotIUserConfirmationStore"); } + } + + /// + /// Store does not implement IUserConfirmationStore<TUser>. + /// + internal static string FormatStoreNotIUserConfirmationStore() + { + return GetString("StoreNotIUserConfirmationStore"); + } + + /// + /// Store does not implement IUserEmailStore<TUser>. + /// + internal static string StoreNotIUserEmailStore + { + get { return GetString("StoreNotIUserEmailStore"); } + } + + /// + /// Store does not implement IUserEmailStore<TUser>. + /// + internal static string FormatStoreNotIUserEmailStore() + { + return GetString("StoreNotIUserEmailStore"); + } + + /// + /// Store does not implement IUserLockoutStore<TUser>. + /// + internal static string StoreNotIUserLockoutStore + { + get { return GetString("StoreNotIUserLockoutStore"); } + } + + /// + /// Store does not implement IUserLockoutStore<TUser>. + /// + internal static string FormatStoreNotIUserLockoutStore() + { + return GetString("StoreNotIUserLockoutStore"); + } + + /// + /// Store does not implement IUserLoginStore<TUser>. + /// + internal static string StoreNotIUserLoginStore + { + get { return GetString("StoreNotIUserLoginStore"); } + } + + /// + /// Store does not implement IUserLoginStore<TUser>. + /// + internal static string FormatStoreNotIUserLoginStore() + { + return GetString("StoreNotIUserLoginStore"); + } + + /// + /// Store does not implement IUserPasswordStore<TUser>. + /// + internal static string StoreNotIUserPasswordStore + { + get { return GetString("StoreNotIUserPasswordStore"); } + } + + /// + /// Store does not implement IUserPasswordStore<TUser>. + /// + internal static string FormatStoreNotIUserPasswordStore() + { + return GetString("StoreNotIUserPasswordStore"); + } + + /// + /// Store does not implement IUserPhoneNumberStore<TUser>. + /// + internal static string StoreNotIUserPhoneNumberStore + { + get { return GetString("StoreNotIUserPhoneNumberStore"); } + } + + /// + /// Store does not implement IUserPhoneNumberStore<TUser>. + /// + internal static string FormatStoreNotIUserPhoneNumberStore() + { + return GetString("StoreNotIUserPhoneNumberStore"); + } + + /// + /// Store does not implement IUserRoleStore<TUser>. + /// + internal static string StoreNotIUserRoleStore + { + get { return GetString("StoreNotIUserRoleStore"); } + } + + /// + /// Store does not implement IUserRoleStore<TUser>. + /// + internal static string FormatStoreNotIUserRoleStore() + { + return GetString("StoreNotIUserRoleStore"); + } + + /// + /// Store does not implement IUserSecurityStampStore<TUser>. + /// + internal static string StoreNotIUserSecurityStampStore + { + get { return GetString("StoreNotIUserSecurityStampStore"); } + } + + /// + /// Store does not implement IUserSecurityStampStore<TUser>. + /// + internal static string FormatStoreNotIUserSecurityStampStore() + { + return GetString("StoreNotIUserSecurityStampStore"); + } + + /// + /// Store does not implement IUserAuthenticatorKeyStore<User>. + /// + internal static string StoreNotIUserAuthenticatorKeyStore + { + get { return GetString("StoreNotIUserAuthenticatorKeyStore"); } + } + + /// + /// Store does not implement IUserAuthenticatorKeyStore<User>. + /// + internal static string FormatStoreNotIUserAuthenticatorKeyStore() + { + return GetString("StoreNotIUserAuthenticatorKeyStore"); + } + + /// + /// Store does not implement IUserTwoFactorStore<TUser>. + /// + internal static string StoreNotIUserTwoFactorStore + { + get { return GetString("StoreNotIUserTwoFactorStore"); } + } + + /// + /// Store does not implement IUserTwoFactorStore<TUser>. + /// + internal static string FormatStoreNotIUserTwoFactorStore() + { + return GetString("StoreNotIUserTwoFactorStore"); + } + + /// + /// Recovery code redemption failed. + /// + internal static string RecoveryCodeRedemptionFailed + { + get { return GetString("RecoveryCodeRedemptionFailed"); } + } + + /// + /// Recovery code redemption failed. + /// + internal static string FormatRecoveryCodeRedemptionFailed() + { + return GetString("RecoveryCodeRedemptionFailed"); + } + + /// + /// User already has a password set. + /// + internal static string UserAlreadyHasPassword + { + get { return GetString("UserAlreadyHasPassword"); } + } + + /// + /// User already has a password set. + /// + internal static string FormatUserAlreadyHasPassword() + { + return GetString("UserAlreadyHasPassword"); + } + + /// + /// User already in role '{0}'. + /// + internal static string UserAlreadyInRole + { + get { return GetString("UserAlreadyInRole"); } + } + + /// + /// User already in role '{0}'. + /// + internal static string FormatUserAlreadyInRole(object p0) + { + return string.Format(CultureInfo.CurrentCulture, GetString("UserAlreadyInRole"), p0); + } + + /// + /// User is locked out. + /// + internal static string UserLockedOut + { + get { return GetString("UserLockedOut"); } + } + + /// + /// User is locked out. + /// + internal static string FormatUserLockedOut() + { + return GetString("UserLockedOut"); + } + + /// + /// Lockout is not enabled for this user. + /// + internal static string UserLockoutNotEnabled + { + get { return GetString("UserLockoutNotEnabled"); } + } + + /// + /// Lockout is not enabled for this user. + /// + internal static string FormatUserLockoutNotEnabled() + { + return GetString("UserLockoutNotEnabled"); + } + + /// + /// User {0} does not exist. + /// + internal static string UserNameNotFound + { + get { return GetString("UserNameNotFound"); } + } + + /// + /// User {0} does not exist. + /// + internal static string FormatUserNameNotFound(object p0) + { + return string.Format(CultureInfo.CurrentCulture, GetString("UserNameNotFound"), p0); + } + + /// + /// User is not in role '{0}'. + /// + internal static string UserNotInRole + { + get { return GetString("UserNotInRole"); } + } + + /// + /// User is not in role '{0}'. + /// + internal static string FormatUserNotInRole(object p0) + { + return string.Format(CultureInfo.CurrentCulture, GetString("UserNotInRole"), p0); + } + + /// + /// Store does not implement IUserTwoFactorRecoveryCodeStore<User>. + /// + internal static string StoreNotIUserTwoFactorRecoveryCodeStore + { + get { return GetString("StoreNotIUserTwoFactorRecoveryCodeStore"); } + } + + /// + /// Store does not implement IUserTwoFactorRecoveryCodeStore<User>. + /// + internal static string FormatStoreNotIUserTwoFactorRecoveryCodeStore() + { + return GetString("StoreNotIUserTwoFactorRecoveryCodeStore"); + } + + /// + /// Passwords must use at least {0} different characters. + /// + internal static string PasswordRequiresUniqueChars + { + get { return GetString("PasswordRequiresUniqueChars"); } + } + + /// + /// Passwords must use at least {0} different characters. + /// + internal static string FormatPasswordRequiresUniqueChars(object p0) + { + return string.Format(CultureInfo.CurrentCulture, GetString("PasswordRequiresUniqueChars"), p0); + } + + private static string GetString(string name, params string[] formatterNames) + { + var value = _resourceManager.GetString(name); + + System.Diagnostics.Debug.Assert(value != null); + + if (formatterNames != null) + { + for (var i = 0; i < formatterNames.Length; i++) + { + value = value.Replace("{" + formatterNames[i] + "}", "{" + i + "}"); + } + } + + return value; + } + } +} diff --git a/src/Microsoft.Extensions.Identity.Core/Resources.resx b/src/Microsoft.Extensions.Identity.Core/Resources.resx new file mode 100644 index 0000000000..39a1443a4b --- /dev/null +++ b/src/Microsoft.Extensions.Identity.Core/Resources.resx @@ -0,0 +1,308 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Optimistic concurrency failure, object has been modified. + Error when optimistic concurrency fails + + + An unknown failure has occurred. + Default identity result error message + + + Email '{0}' is already taken. + Error for duplicate emails + + + Role name '{0}' is already taken. + Error for duplicate roles + + + User name '{0}' is already taken. + Error for duplicate user names + + + Email '{0}' is invalid. + Invalid email + + + Type {0} must derive from {1}<{2}>. + Error when the manager type is not derived correctly + + + The provided PasswordHasherCompatibilityMode is invalid. + Error when the password hasher doesn't understand the format it's being asked to produce. + + + The iteration count must be a positive integer. + Error when the iteration count is < 1. + + + Role name '{0}' is invalid. + Error for invalid role names + + + Invalid token. + Error when a token is not recognized + + + User name '{0}' is invalid, can only contain letters or digits. + User names can only contain letters or digits + + + A user with this login already exists. + Error when a login already linked + + + AddIdentity must be called on the service collection. + Error when AddIdentity is not called + + + No IUserTokenProvider named '{0}' is registered. + Error when there is no IUserTokenProvider + + + User security stamp cannot be null. + Error when a user's security stamp is null. + + + Incorrect password. + Error when a password doesn't match + + + Passwords must have at least one digit ('0'-'9'). + Error when passwords do not have a digit + + + Passwords must have at least one lowercase ('a'-'z'). + Error when passwords do not have a lowercase letter + + + Passwords must have at least one non alphanumeric character. + Error when password does not have enough non alphanumeric characters + + + Passwords must have at least one uppercase ('A'-'Z'). + Error when passwords do not have an uppercase letter + + + Passwords must be at least {0} characters. + Error message for passwords that are too short + + + Role {0} does not exist. + Error when a role does not exist + + + Store does not implement IQueryableRoleStore<TRole>. + Error when the store does not implement this interface + + + Store does not implement IQueryableUserStore<TUser>. + Error when the store does not implement this interface + + + Store does not implement IRoleClaimStore<TRole>. + Error when the store does not implement this interface + + + Store does not implement IUserAuthenticationTokenStore<User>. + Error when the store does not implement this interface + + + Store does not implement IUserClaimStore<TUser>. + Error when the store does not implement this interface + + + Store does not implement IUserConfirmationStore<TUser>. + Error when the store does not implement this interface + + + Store does not implement IUserEmailStore<TUser>. + Error when the store does not implement this interface + + + Store does not implement IUserLockoutStore<TUser>. + Error when the store does not implement this interface + + + Store does not implement IUserLoginStore<TUser>. + Error when the store does not implement this interface + + + Store does not implement IUserPasswordStore<TUser>. + Error when the store does not implement this interface + + + Store does not implement IUserPhoneNumberStore<TUser>. + Error when the store does not implement this interface + + + Store does not implement IUserRoleStore<TUser>. + Error when the store does not implement this interface + + + Store does not implement IUserSecurityStampStore<TUser>. + Error when the store does not implement this interface + + + Store does not implement IUserAuthenticatorKeyStore<User>. + Error when the store does not implement this interface + + + Store does not implement IUserTwoFactorStore<TUser>. + Error when the store does not implement this interface + + + Recovery code redemption failed. + Error when a recovery code is not redeemed. + + + User already has a password set. + Error when AddPasswordAsync called when a user already has a password + + + User already in role '{0}'. + Error when a user is already in a role + + + User is locked out. + Error when a user is locked out + + + Lockout is not enabled for this user. + Error when lockout is not enabled + + + User {0} does not exist. + Error when a user does not exist + + + User is not in role '{0}'. + Error when a user is not in the role + + + Store does not implement IUserTwoFactorRecoveryCodeStore<User>. + Error when the store does not implement this interface + + + Passwords must use at least {0} different characters. + Error message for passwords that are based on similar characters + + \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Identity/RoleManager.cs b/src/Microsoft.Extensions.Identity.Core/RoleManager.cs similarity index 96% rename from src/Microsoft.AspNetCore.Identity/RoleManager.cs rename to src/Microsoft.Extensions.Identity.Core/RoleManager.cs index b64facc200..fdccba2441 100644 --- a/src/Microsoft.AspNetCore.Identity/RoleManager.cs +++ b/src/Microsoft.Extensions.Identity.Core/RoleManager.cs @@ -7,7 +7,6 @@ using System.Linq; using System.Security.Claims; using System.Threading; using System.Threading.Tasks; -using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; namespace Microsoft.AspNetCore.Identity @@ -19,8 +18,11 @@ namespace Microsoft.AspNetCore.Identity public class RoleManager : IDisposable where TRole : class { private bool _disposed; - private readonly HttpContext _context; - private CancellationToken CancellationToken => _context?.RequestAborted ?? CancellationToken.None; + + /// + /// The cancellation token used to cancel operations. + /// + protected virtual CancellationToken CancellationToken => CancellationToken.None; /// /// Constructs a new instance of . @@ -30,22 +32,19 @@ namespace Microsoft.AspNetCore.Identity /// The normalizer to use when normalizing role names to keys. /// The used to provider error messages. /// The logger used to log messages, warnings and errors. - /// The accessor used to access the . public RoleManager(IRoleStore store, IEnumerable> roleValidators, ILookupNormalizer keyNormalizer, IdentityErrorDescriber errors, - ILogger> logger, - IHttpContextAccessor contextAccessor) + ILogger> logger) { if (store == null) { throw new ArgumentNullException(nameof(store)); } Store = store; - KeyNormalizer = keyNormalizer ?? new UpperInvariantLookupNormalizer(); - ErrorDescriber = errors ?? new IdentityErrorDescriber(); - _context = contextAccessor?.HttpContext; + KeyNormalizer = keyNormalizer; + ErrorDescriber = errors; Logger = logger; if (roleValidators != null) diff --git a/src/Microsoft.AspNetCore.Identity/SignInOptions.cs b/src/Microsoft.Extensions.Identity.Core/SignInOptions.cs similarity index 100% rename from src/Microsoft.AspNetCore.Identity/SignInOptions.cs rename to src/Microsoft.Extensions.Identity.Core/SignInOptions.cs diff --git a/src/Microsoft.AspNetCore.Identity/SignInResult.cs b/src/Microsoft.Extensions.Identity.Core/SignInResult.cs similarity index 99% rename from src/Microsoft.AspNetCore.Identity/SignInResult.cs rename to src/Microsoft.Extensions.Identity.Core/SignInResult.cs index fae100e2a6..faae170c3b 100644 --- a/src/Microsoft.AspNetCore.Identity/SignInResult.cs +++ b/src/Microsoft.Extensions.Identity.Core/SignInResult.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 Microsoft.Extensions.Logging; - namespace Microsoft.AspNetCore.Identity { /// diff --git a/src/Microsoft.AspNetCore.Identity/TokenOptions.cs b/src/Microsoft.Extensions.Identity.Core/TokenOptions.cs similarity index 69% rename from src/Microsoft.AspNetCore.Identity/TokenOptions.cs rename to src/Microsoft.Extensions.Identity.Core/TokenOptions.cs index d7a23a1b13..bb54619c2e 100644 --- a/src/Microsoft.AspNetCore.Identity/TokenOptions.cs +++ b/src/Microsoft.Extensions.Identity.Core/TokenOptions.cs @@ -17,17 +17,17 @@ namespace Microsoft.AspNetCore.Identity public static readonly string DefaultProvider = "Default"; /// - /// Default token provider name used by the . + /// Default token provider name used by the email provider. />. /// public static readonly string DefaultEmailProvider = "Email"; /// - /// Default token provider name used by the . + /// Default token provider name used by the phone provider. />. /// public static readonly string DefaultPhoneProvider = "Phone"; /// - /// Default token provider name used by the . + /// Default token provider name used by the . /// public static readonly string DefaultAuthenticatorProvider = "Authenticator"; @@ -37,18 +37,18 @@ namespace Microsoft.AspNetCore.Identity public Dictionary ProviderMap { get; set; } = new Dictionary(); /// - /// Gets or sets the used to generate tokens used in account confirmation emails. + /// Gets or sets the token provider used to generate tokens used in account confirmation emails. /// /// - /// 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. + /// Gets or sets the used to generate tokens used in password reset emails. /// /// - /// 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; @@ -60,6 +60,14 @@ namespace Microsoft.AspNetCore.Identity /// public string ChangeEmailTokenProvider { get; set; } = DefaultProvider; + /// + /// Gets or sets the used to generate tokens used when changing phone numbers. + /// + /// + /// The used to generate tokens used when changing phone numbers. + /// + public string ChangePhoneNumberTokenProvider { get; set; } = DefaultProvider; + /// /// Gets or sets the used to validate two factor sign ins with an authenticator. /// diff --git a/src/Microsoft.AspNetCore.Identity/TokenProviderDescriptor.cs b/src/Microsoft.Extensions.Identity.Core/TokenProviderDescriptor.cs similarity index 100% rename from src/Microsoft.AspNetCore.Identity/TokenProviderDescriptor.cs rename to src/Microsoft.Extensions.Identity.Core/TokenProviderDescriptor.cs diff --git a/src/Microsoft.AspNetCore.Identity/UserLoginInfo.cs b/src/Microsoft.Extensions.Identity.Core/UserLoginInfo.cs similarity index 100% rename from src/Microsoft.AspNetCore.Identity/UserLoginInfo.cs rename to src/Microsoft.Extensions.Identity.Core/UserLoginInfo.cs diff --git a/src/Microsoft.AspNetCore.Identity/UserManager.cs b/src/Microsoft.Extensions.Identity.Core/UserManager.cs similarity index 98% rename from src/Microsoft.AspNetCore.Identity/UserManager.cs rename to src/Microsoft.Extensions.Identity.Core/UserManager.cs index 589a1dcfe9..6ab877124b 100644 --- a/src/Microsoft.AspNetCore.Identity/UserManager.cs +++ b/src/Microsoft.Extensions.Identity.Core/UserManager.cs @@ -6,11 +6,11 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Security.Claims; +using System.Security.Cryptography; using System.Text; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; @@ -28,6 +28,11 @@ namespace Microsoft.AspNetCore.Identity /// protected const string ResetPasswordTokenPurpose = "ResetPassword"; + /// + /// The data protection purpose used for the change phone number methods. + /// + protected const string ChangePhoneNumberTokenPurpose = "ChangePhoneNumber"; + /// /// The data protection purpose used for the email confirmation related methods. /// @@ -38,12 +43,13 @@ namespace Microsoft.AspNetCore.Identity private TimeSpan _defaultLockout = TimeSpan.Zero; private bool _disposed; - private readonly HttpContext _context; + private static readonly RandomNumberGenerator _rng = RandomNumberGenerator.Create(); + /// - /// The cancellation token assocated with the current HttpContext.RequestAborted or CancellationToken.None if unavailable. + /// The cancellation token used to cancel operations. /// - protected CancellationToken CancellationToken => _context?.RequestAborted ?? CancellationToken.None; + protected virtual CancellationToken CancellationToken => CancellationToken.None; /// /// Constructs a new instance of . @@ -95,7 +101,6 @@ namespace Microsoft.AspNetCore.Identity if (services != null) { - _context = services.GetService()?.HttpContext; foreach (var providerName in Options.Tokens.ProviderMap.Keys) { var description = Options.Tokens.ProviderMap[providerName]; @@ -1575,12 +1580,10 @@ namespace Microsoft.AspNetCore.Identity /// /// The that represents the asynchronous operation, containing the telephone change number token. /// - public virtual async Task GenerateChangePhoneNumberTokenAsync(TUser user, string phoneNumber) + public virtual Task GenerateChangePhoneNumberTokenAsync(TUser user, string phoneNumber) { ThrowIfDisposed(); - return Rfc6238AuthenticationService.GenerateCode( - await CreateSecurityTokenAsync(user), phoneNumber) - .ToString(CultureInfo.InvariantCulture); + return GenerateUserTokenAsync(user, Options.Tokens.ChangePhoneNumberTokenProvider, ChangePhoneNumberTokenPurpose + ":" + phoneNumber); } /// @@ -1594,21 +1597,16 @@ namespace Microsoft.AspNetCore.Identity /// The that represents the asynchronous operation, returning true if the /// is valid, otherwise false. /// - public virtual async Task VerifyChangePhoneNumberTokenAsync(TUser user, string token, string phoneNumber) + public virtual Task VerifyChangePhoneNumberTokenAsync(TUser user, string token, string phoneNumber) { ThrowIfDisposed(); - - var securityToken = await CreateSecurityTokenAsync(user); - int code; - if (securityToken != null && Int32.TryParse(token, out code)) + if (user == null) { - if (Rfc6238AuthenticationService.ValidateCode(securityToken, code, phoneNumber)) - { - return true; - } + throw new ArgumentNullException(nameof(user)); } - Logger.LogWarning(8, "VerifyChangePhoneNumberTokenAsync() failed for user {userId}.", await GetUserIdAsync(user)); - return false; + + // Make sure the token is valid and the stamp matches + return VerifyUserTokenAsync(user, Options.Tokens.ChangePhoneNumberTokenProvider, ChangePhoneNumberTokenPurpose+":"+ phoneNumber, token); } /// @@ -2159,7 +2157,9 @@ namespace Microsoft.AspNetCore.Identity /// The new security secret. public virtual string GenerateNewAuthenticatorKey() { - return Base32.ToBase32(Rfc6238AuthenticationService.GenerateRandomKey()); + byte[] bytes = new byte[20]; + _rng.GetBytes(bytes); + return Base32.ToBase32(bytes); } /// @@ -2278,7 +2278,12 @@ namespace Microsoft.AspNetCore.Identity return cast; } - internal async Task CreateSecurityTokenAsync(TUser user) + /// + /// Creates bytes to use as a security token from the user's security stamp. + /// + /// The user. + /// The security token bytes. + public virtual async Task CreateSecurityTokenAsync(TUser user) { return Encoding.Unicode.GetBytes(await GetSecurityStampAsync(user)); } diff --git a/src/Microsoft.AspNetCore.Identity/UserOptions.cs b/src/Microsoft.Extensions.Identity.Core/UserOptions.cs similarity index 100% rename from src/Microsoft.AspNetCore.Identity/UserOptions.cs rename to src/Microsoft.Extensions.Identity.Core/UserOptions.cs diff --git a/src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/IdentityRole.cs b/src/Microsoft.Extensions.Identity.Stores/IdentityRole.cs similarity index 89% rename from src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/IdentityRole.cs rename to src/Microsoft.Extensions.Identity.Stores/IdentityRole.cs index f8d4aca9d9..a5cb111b12 100644 --- a/src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/IdentityRole.cs +++ b/src/Microsoft.Extensions.Identity.Stores/IdentityRole.cs @@ -4,7 +4,7 @@ using System; using System.Collections.Generic; -namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore +namespace Microsoft.AspNetCore.Identity { /// /// The default implementation of which uses a string as the primary key. @@ -82,16 +82,6 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore Name = roleName; } - /// - /// Navigation property for the users in this role. - /// - public virtual ICollection Users { get; } = new List(); - - /// - /// Navigation property for claims in this role. - /// - public virtual ICollection Claims { get; } = new List(); - /// /// Gets or sets the primary key for this role. /// diff --git a/src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/IdentityRoleClaim.cs b/src/Microsoft.Extensions.Identity.Stores/IdentityRoleClaim.cs similarity index 96% rename from src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/IdentityRoleClaim.cs rename to src/Microsoft.Extensions.Identity.Stores/IdentityRoleClaim.cs index 1a4c55e996..ff257d59ed 100644 --- a/src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/IdentityRoleClaim.cs +++ b/src/Microsoft.Extensions.Identity.Stores/IdentityRoleClaim.cs @@ -4,7 +4,7 @@ using System; using System.Security.Claims; -namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore +namespace Microsoft.AspNetCore.Identity { /// /// Represents a claim that is granted to all users within a role. diff --git a/src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/IdentityUser.cs b/src/Microsoft.Extensions.Identity.Stores/IdentityUser.cs similarity index 87% rename from src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/IdentityUser.cs rename to src/Microsoft.Extensions.Identity.Stores/IdentityUser.cs index f4035bb53e..efc8a9b713 100644 --- a/src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/IdentityUser.cs +++ b/src/Microsoft.Extensions.Identity.Stores/IdentityUser.cs @@ -4,7 +4,7 @@ using System; using System.Collections.Generic; -namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore +namespace Microsoft.AspNetCore.Identity { /// /// The default implementation of which uses a string as a primary key. @@ -149,26 +149,6 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore /// public virtual int AccessFailedCount { get; set; } - /// - /// Navigation property for the roles this user belongs to. - /// - public virtual ICollection Roles { get; } = new List(); - - /// - /// Navigation property for the claims this user possesses. - /// - public virtual ICollection Claims { get; } = new List(); - - /// - /// Navigation property for this users login accounts. - /// - public virtual ICollection Logins { get; } = new List(); - - /// - /// Navigation property for this users tokens. - /// - public virtual ICollection Tokens { get; } = new List(); - /// /// Returns the username for this user. /// diff --git a/src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/IdentityUserClaim.cs b/src/Microsoft.Extensions.Identity.Stores/IdentityUserClaim.cs similarity index 96% rename from src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/IdentityUserClaim.cs rename to src/Microsoft.Extensions.Identity.Stores/IdentityUserClaim.cs index 823a1a4969..bbdd2ac3cf 100644 --- a/src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/IdentityUserClaim.cs +++ b/src/Microsoft.Extensions.Identity.Stores/IdentityUserClaim.cs @@ -4,7 +4,7 @@ using System; using System.Security.Claims; -namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore +namespace Microsoft.AspNetCore.Identity { /// /// Represents a claim that a user possesses. diff --git a/src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/IdentityUserLogin.cs b/src/Microsoft.Extensions.Identity.Stores/IdentityUserLogin.cs similarity index 95% rename from src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/IdentityUserLogin.cs rename to src/Microsoft.Extensions.Identity.Stores/IdentityUserLogin.cs index 81b1951c88..f2c6d165d0 100644 --- a/src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/IdentityUserLogin.cs +++ b/src/Microsoft.Extensions.Identity.Stores/IdentityUserLogin.cs @@ -3,7 +3,7 @@ using System; -namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore +namespace Microsoft.AspNetCore.Identity { /// /// Represents a login and its associated provider for a user. diff --git a/src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/IdentityUserRole.cs b/src/Microsoft.Extensions.Identity.Stores/IdentityUserRole.cs similarity index 92% rename from src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/IdentityUserRole.cs rename to src/Microsoft.Extensions.Identity.Stores/IdentityUserRole.cs index f0d9be5083..44613952e7 100644 --- a/src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/IdentityUserRole.cs +++ b/src/Microsoft.Extensions.Identity.Stores/IdentityUserRole.cs @@ -3,7 +3,7 @@ using System; -namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore +namespace Microsoft.AspNetCore.Identity { /// /// Represents the link between a user and a role. diff --git a/src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/IdentityUserToken.cs b/src/Microsoft.Extensions.Identity.Stores/IdentityUserToken.cs similarity index 94% rename from src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/IdentityUserToken.cs rename to src/Microsoft.Extensions.Identity.Stores/IdentityUserToken.cs index 3c1eb76bdf..007701b623 100644 --- a/src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/IdentityUserToken.cs +++ b/src/Microsoft.Extensions.Identity.Stores/IdentityUserToken.cs @@ -3,7 +3,7 @@ using System; -namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore +namespace Microsoft.AspNetCore.Identity { /// /// Represents an authentication token for a user. diff --git a/src/Microsoft.Extensions.Identity.Stores/Microsoft.Extensions.Identity.Stores.csproj b/src/Microsoft.Extensions.Identity.Stores/Microsoft.Extensions.Identity.Stores.csproj new file mode 100644 index 0000000000..2bb6600bb4 --- /dev/null +++ b/src/Microsoft.Extensions.Identity.Stores/Microsoft.Extensions.Identity.Stores.csproj @@ -0,0 +1,28 @@ + + + + + + ASP.NET Core Identity is the membership system for building ASP.NET Core web applications, including membership, login, and user data. ASP.NET Core Identity allows you to add login features to your application and makes it easy to customize data about the logged in user. + netstandard1.3 + true + aspnetcore;identity;membership + false + + + + + + + + + + + + + + + + + + diff --git a/src/Microsoft.Extensions.Identity.Stores/RoleStoreBase.cs b/src/Microsoft.Extensions.Identity.Stores/RoleStoreBase.cs new file mode 100644 index 0000000000..3e7c5de7b1 --- /dev/null +++ b/src/Microsoft.Extensions.Identity.Stores/RoleStoreBase.cs @@ -0,0 +1,272 @@ +// 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; +using System.ComponentModel; +using System.Linq; +using System.Security.Claims; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.Internal; + +namespace Microsoft.AspNetCore.Identity +{ + /// + /// Creates a new instance of a persistence store for roles. + /// + /// The type of the class representing a role. + /// The type of the primary key for a role. + /// The type of the class representing a user role. + /// The type of the class representing a role claim. + public abstract class RoleStoreBase : + IQueryableRoleStore, + IRoleClaimStore + where TRole : IdentityRole + where TKey : IEquatable + where TUserRole : IdentityUserRole, new() + where TRoleClaim : IdentityRoleClaim, new() + { + /// + /// Constructs a new instance of . + /// + /// The . + public RoleStoreBase(IdentityErrorDescriber describer) + { + if (describer == null) + { + throw new ArgumentNullException(nameof(describer)); + } + + ErrorDescriber = describer; + } + + private bool _disposed; + + /// + /// Gets or sets the for any error that occurred with the current operation. + /// + public IdentityErrorDescriber ErrorDescriber { get; set; } + + /// + /// Creates a new role in a store as an asynchronous operation. + /// + /// The role to create in the store. + /// The used to propagate notifications that the operation should be canceled. + /// A that represents the of the asynchronous query. + public abstract Task CreateAsync(TRole role, CancellationToken cancellationToken = default(CancellationToken)); + + /// + /// Updates a role in a store as an asynchronous operation. + /// + /// The role to update in the store. + /// The used to propagate notifications that the operation should be canceled. + /// A that represents the of the asynchronous query. + public abstract Task UpdateAsync(TRole role, CancellationToken cancellationToken = default(CancellationToken)); + + /// + /// Deletes a role from the store as an asynchronous operation. + /// + /// The role to delete from the store. + /// The used to propagate notifications that the operation should be canceled. + /// A that represents the of the asynchronous query. + public abstract Task DeleteAsync(TRole role, CancellationToken cancellationToken = default(CancellationToken)); + + /// + /// Gets the ID for a role from the store as an asynchronous operation. + /// + /// The role whose ID should be returned. + /// The used to propagate notifications that the operation should be canceled. + /// A that contains the ID of the role. + public virtual Task GetRoleIdAsync(TRole role, CancellationToken cancellationToken = default(CancellationToken)) + { + cancellationToken.ThrowIfCancellationRequested(); + ThrowIfDisposed(); + if (role == null) + { + throw new ArgumentNullException(nameof(role)); + } + return Task.FromResult(ConvertIdToString(role.Id)); + } + + /// + /// Gets the name of a role from the store as an asynchronous operation. + /// + /// The role whose name should be returned. + /// The used to propagate notifications that the operation should be canceled. + /// A that contains the name of the role. + public virtual Task GetRoleNameAsync(TRole role, CancellationToken cancellationToken = default(CancellationToken)) + { + cancellationToken.ThrowIfCancellationRequested(); + ThrowIfDisposed(); + if (role == null) + { + throw new ArgumentNullException(nameof(role)); + } + return Task.FromResult(role.Name); + } + + /// + /// Sets the name of a role in the store as an asynchronous operation. + /// + /// The role whose name should be set. + /// The name of the role. + /// The used to propagate notifications that the operation should be canceled. + /// The that represents the asynchronous operation. + public virtual Task SetRoleNameAsync(TRole role, string roleName, CancellationToken cancellationToken = default(CancellationToken)) + { + cancellationToken.ThrowIfCancellationRequested(); + ThrowIfDisposed(); + if (role == null) + { + throw new ArgumentNullException(nameof(role)); + } + role.Name = roleName; + return TaskCache.CompletedTask; + } + + /// + /// Converts the provided to a strongly typed key object. + /// + /// The id to convert. + /// An instance of representing the provided . + public virtual TKey ConvertIdFromString(string id) + { + if (id == null) + { + return default(TKey); + } + return (TKey)TypeDescriptor.GetConverter(typeof(TKey)).ConvertFromInvariantString(id); + } + + /// + /// Converts the provided to its string representation. + /// + /// The id to convert. + /// An representation of the provided . + public virtual string ConvertIdToString(TKey id) + { + if (id.Equals(default(TKey))) + { + return null; + } + return id.ToString(); + } + + /// + /// Finds the role who has the specified ID as an asynchronous operation. + /// + /// The role ID to look for. + /// The used to propagate notifications that the operation should be canceled. + /// A that result of the look up. + public abstract Task FindByIdAsync(string id, CancellationToken cancellationToken = default(CancellationToken)); + + /// + /// Finds the role who has the specified normalized name as an asynchronous operation. + /// + /// The normalized role name to look for. + /// The used to propagate notifications that the operation should be canceled. + /// A that result of the look up. + public abstract Task FindByNameAsync(string normalizedName, CancellationToken cancellationToken = default(CancellationToken)); + + /// + /// Get a role's normalized name as an asynchronous operation. + /// + /// The role whose normalized name should be retrieved. + /// The used to propagate notifications that the operation should be canceled. + /// A that contains the name of the role. + public virtual Task GetNormalizedRoleNameAsync(TRole role, CancellationToken cancellationToken = default(CancellationToken)) + { + cancellationToken.ThrowIfCancellationRequested(); + ThrowIfDisposed(); + if (role == null) + { + throw new ArgumentNullException(nameof(role)); + } + return Task.FromResult(role.NormalizedName); + } + + /// + /// Set a role's normalized name as an asynchronous operation. + /// + /// The role whose normalized name should be set. + /// The normalized name to set + /// The used to propagate notifications that the operation should be canceled. + /// The that represents the asynchronous operation. + public virtual Task SetNormalizedRoleNameAsync(TRole role, string normalizedName, CancellationToken cancellationToken = default(CancellationToken)) + { + cancellationToken.ThrowIfCancellationRequested(); + ThrowIfDisposed(); + if (role == null) + { + throw new ArgumentNullException(nameof(role)); + } + role.NormalizedName = normalizedName; + return TaskCache.CompletedTask; + } + + /// + /// Throws if this class has been disposed. + /// + protected void ThrowIfDisposed() + { + if (_disposed) + { + throw new ObjectDisposedException(GetType().Name); + } + } + + /// + /// Dispose the stores + /// + public void Dispose() + { + _disposed = true; + } + + /// + /// Get the claims associated with the specified as an asynchronous operation. + /// + /// The role whose claims should be retrieved. + /// The used to propagate notifications that the operation should be canceled. + /// A that contains the claims granted to a role. + public abstract Task> GetClaimsAsync(TRole role, CancellationToken cancellationToken = default(CancellationToken)); + + /// + /// Adds the given to the specified . + /// + /// The role to add the claim to. + /// The claim to add to the role. + /// The used to propagate notifications that the operation should be canceled. + /// The that represents the asynchronous operation. + public abstract Task AddClaimAsync(TRole role, Claim claim, CancellationToken cancellationToken = default(CancellationToken)); + + /// + /// Removes the given from the specified . + /// + /// The role to remove the claim from. + /// The claim to remove from the role. + /// The used to propagate notifications that the operation should be canceled. + /// The that represents the asynchronous operation. + public abstract Task RemoveClaimAsync(TRole role, Claim claim, CancellationToken cancellationToken = default(CancellationToken)); + + /// + /// A navigation property for the roles the store contains. + /// + public abstract IQueryable Roles + { + get; + } + + /// + /// Creates a entity representing a role claim. + /// + /// The associated role. + /// The associated claim. + /// The role claim entity. + protected virtual TRoleClaim CreateRoleClaim(TRole role, Claim claim) + { + return new TRoleClaim { RoleId = role.Id, ClaimType = claim.Type, ClaimValue = claim.Value }; + } + } +} diff --git a/src/Microsoft.Extensions.Identity.Stores/UserStoreBase.cs b/src/Microsoft.Extensions.Identity.Stores/UserStoreBase.cs new file mode 100644 index 0000000000..80d7ebab9d --- /dev/null +++ b/src/Microsoft.Extensions.Identity.Stores/UserStoreBase.cs @@ -0,0 +1,1142 @@ +// 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; +using System.ComponentModel; +using System.Linq; +using System.Security.Claims; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Extensions.Internal; + +namespace Microsoft.AspNetCore.Identity +{ + /// + /// Represents a new instance of a persistence store for the specified user and role types. + /// + /// The type representing a user. + /// The type representing a role. + /// The type of the primary key for a role. + /// The type representing a claim. + /// The type representing a user role. + /// The type representing a user external login. + /// The type representing a user token. + /// The type representing a role claim. + public abstract class UserStoreBase : + IUserLoginStore, + IUserRoleStore, + IUserClaimStore, + IUserPasswordStore, + IUserSecurityStampStore, + IUserEmailStore, + IUserLockoutStore, + IUserPhoneNumberStore, + IQueryableUserStore, + IUserTwoFactorStore, + IUserAuthenticationTokenStore, + IUserAuthenticatorKeyStore, + IUserTwoFactorRecoveryCodeStore + where TUser : IdentityUser + where TRole : IdentityRole + where TKey : IEquatable + where TUserClaim : IdentityUserClaim, new() + where TUserRole : IdentityUserRole, new() + where TUserLogin : IdentityUserLogin, new() + where TUserToken : IdentityUserToken, new() + where TRoleClaim : IdentityRoleClaim, new() + { + /// + /// Creates a new instance. + /// + /// The used to describe store errors. + public UserStoreBase(IdentityErrorDescriber describer) + { + if (describer == null) + { + throw new ArgumentNullException(nameof(describer)); + } + + ErrorDescriber = describer; + } + + private bool _disposed; + + /// + /// Gets or sets the for any error that occurred with the current operation. + /// + public IdentityErrorDescriber ErrorDescriber { get; set; } + + /// + /// Called to create a new instance of a . + /// + /// The associated user. + /// The associated role. + /// + protected virtual TUserRole CreateUserRole(TUser user, TRole role) + { + return new TUserRole() + { + UserId = user.Id, + RoleId = role.Id + }; + } + + /// + /// Called to create a new instance of a . + /// + /// The associated user. + /// The associated claim. + /// + protected virtual TUserClaim CreateUserClaim(TUser user, Claim claim) + { + var userClaim = new TUserClaim { UserId = user.Id }; + userClaim.InitializeFromClaim(claim); + return userClaim; + } + + /// + /// Called to create a new instance of a . + /// + /// The associated user. + /// The sasociated login. + /// + protected virtual TUserLogin CreateUserLogin(TUser user, UserLoginInfo login) + { + return new TUserLogin + { + UserId = user.Id, + ProviderKey = login.ProviderKey, + LoginProvider = login.LoginProvider, + ProviderDisplayName = login.ProviderDisplayName + }; + } + + /// + /// Called to create a new instance of a . + /// + /// The associated user. + /// The associated login provider. + /// The name of the user token. + /// The value of the user token. + /// + protected virtual TUserToken CreateUserToken(TUser user, string loginProvider, string name, string value) + { + return new TUserToken + { + UserId = user.Id, + LoginProvider = loginProvider, + Name = name, + Value = value + }; + } + + /// + /// Gets the user identifier for the specified . + /// + /// The user whose identifier should be retrieved. + /// The used to propagate notifications that the operation should be canceled. + /// The that represents the asynchronous operation, containing the identifier for the specified . + public virtual Task GetUserIdAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken)) + { + cancellationToken.ThrowIfCancellationRequested(); + ThrowIfDisposed(); + if (user == null) + { + throw new ArgumentNullException(nameof(user)); + } + return Task.FromResult(ConvertIdToString(user.Id)); + } + + /// + /// Gets the user name for the specified . + /// + /// The user whose name should be retrieved. + /// The used to propagate notifications that the operation should be canceled. + /// The that represents the asynchronous operation, containing the name for the specified . + public virtual Task GetUserNameAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken)) + { + cancellationToken.ThrowIfCancellationRequested(); + ThrowIfDisposed(); + if (user == null) + { + throw new ArgumentNullException(nameof(user)); + } + return Task.FromResult(user.UserName); + } + + /// + /// Sets the given for the specified . + /// + /// The user whose name should be set. + /// The user name to set. + /// The used to propagate notifications that the operation should be canceled. + /// The that represents the asynchronous operation. + public virtual Task SetUserNameAsync(TUser user, string userName, CancellationToken cancellationToken = default(CancellationToken)) + { + cancellationToken.ThrowIfCancellationRequested(); + ThrowIfDisposed(); + if (user == null) + { + throw new ArgumentNullException(nameof(user)); + } + user.UserName = userName; + return TaskCache.CompletedTask; + } + + /// + /// Gets the normalized user name for the specified . + /// + /// The user whose normalized name should be retrieved. + /// The used to propagate notifications that the operation should be canceled. + /// The that represents the asynchronous operation, containing the normalized user name for the specified . + public virtual Task GetNormalizedUserNameAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken)) + { + cancellationToken.ThrowIfCancellationRequested(); + ThrowIfDisposed(); + if (user == null) + { + throw new ArgumentNullException(nameof(user)); + } + return Task.FromResult(user.NormalizedUserName); + } + + /// + /// Sets the given normalized name for the specified . + /// + /// The user whose name should be set. + /// The normalized name to set. + /// The used to propagate notifications that the operation should be canceled. + /// The that represents the asynchronous operation. + public virtual Task SetNormalizedUserNameAsync(TUser user, string normalizedName, CancellationToken cancellationToken = default(CancellationToken)) + { + cancellationToken.ThrowIfCancellationRequested(); + ThrowIfDisposed(); + if (user == null) + { + throw new ArgumentNullException(nameof(user)); + } + user.NormalizedUserName = normalizedName; + return TaskCache.CompletedTask; + } + + /// + /// Creates the specified in the user store. + /// + /// The user to create. + /// The used to propagate notifications that the operation should be canceled. + /// The that represents the asynchronous operation, containing the of the creation operation. + public abstract Task CreateAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken)); + + /// + /// Updates the specified in the user store. + /// + /// The user to update. + /// The used to propagate notifications that the operation should be canceled. + /// The that represents the asynchronous operation, containing the of the update operation. + public abstract Task UpdateAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken)); + + /// + /// Deletes the specified from the user store. + /// + /// The user to delete. + /// The used to propagate notifications that the operation should be canceled. + /// The that represents the asynchronous operation, containing the of the update operation. + public abstract Task DeleteAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken)); + + /// + /// Finds and returns a user, if any, who has the specified . + /// + /// The user ID to search for. + /// The used to propagate notifications that the operation should be canceled. + /// + /// The that represents the asynchronous operation, containing the user matching the specified if it exists. + /// + public abstract Task FindByIdAsync(string userId, CancellationToken cancellationToken = default(CancellationToken)); + + /// + /// Converts the provided to a strongly typed key object. + /// + /// The id to convert. + /// An instance of representing the provided . + public virtual TKey ConvertIdFromString(string id) + { + if (id == null) + { + return default(TKey); + } + return (TKey)TypeDescriptor.GetConverter(typeof(TKey)).ConvertFromInvariantString(id); + } + + /// + /// Converts the provided to its string representation. + /// + /// The id to convert. + /// An representation of the provided . + public virtual string ConvertIdToString(TKey id) + { + if (object.Equals(id, default(TKey))) + { + return null; + } + return id.ToString(); + } + + /// + /// Finds and returns a user, if any, who has the specified normalized user name. + /// + /// The normalized user name to search for. + /// The used to propagate notifications that the operation should be canceled. + /// + /// The that represents the asynchronous operation, containing the user matching the specified if it exists. + /// + public abstract Task FindByNameAsync(string normalizedUserName, CancellationToken cancellationToken = default(CancellationToken)); + + /// + /// A navigation property for the users the store contains. + /// + public abstract IQueryable Users + { + get; + } + + /// + /// Sets the password hash for a user. + /// + /// The user to set the password hash for. + /// The password hash to set. + /// The used to propagate notifications that the operation should be canceled. + /// The that represents the asynchronous operation. + public virtual Task SetPasswordHashAsync(TUser user, string passwordHash, CancellationToken cancellationToken = default(CancellationToken)) + { + cancellationToken.ThrowIfCancellationRequested(); + ThrowIfDisposed(); + if (user == null) + { + throw new ArgumentNullException(nameof(user)); + } + user.PasswordHash = passwordHash; + return TaskCache.CompletedTask; + } + + /// + /// Gets the password hash for a user. + /// + /// The user to retrieve the password hash for. + /// The used to propagate notifications that the operation should be canceled. + /// A that contains the password hash for the user. + public virtual Task GetPasswordHashAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken)) + { + cancellationToken.ThrowIfCancellationRequested(); + ThrowIfDisposed(); + if (user == null) + { + throw new ArgumentNullException(nameof(user)); + } + return Task.FromResult(user.PasswordHash); + } + + /// + /// Returns a flag indicating if the specified user has a password. + /// + /// The user to retrieve the password hash for. + /// The used to propagate notifications that the operation should be canceled. + /// A containing a flag indicating if the specified user has a password. If the + /// user has a password the returned value with be true, otherwise it will be false. + public virtual Task HasPasswordAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken)) + { + cancellationToken.ThrowIfCancellationRequested(); + return Task.FromResult(user.PasswordHash != null); + } + + /// + /// Return a role with the normalized name if it exists. + /// + /// The normalized role name. + /// The used to propagate notifications that the operation should be canceled. + /// The role if it exists. + protected abstract Task FindRoleAsync(string normalizedRoleName, CancellationToken cancellationToken); + + /// + /// Return a user role for the userId and roleId if it exists. + /// + /// The user's id. + /// The role's id. + /// The used to propagate notifications that the operation should be canceled. + /// The user role if it exists. + protected abstract Task FindUserRoleAsync(TKey userId, TKey roleId, CancellationToken cancellationToken); + + /// + /// Return a user with the matching userId if it exists. + /// + /// The user's id. + /// The used to propagate notifications that the operation should be canceled. + /// The user if it exists. + protected abstract Task FindUserAsync(TKey userId, CancellationToken cancellationToken); + + /// + /// Return a user login with the matching userId, provider, providerKey if it exists. + /// + /// The user's id. + /// The login provider name. + /// The key provided by the to identify a user. + /// The used to propagate notifications that the operation should be canceled. + /// The user login if it exists. + protected abstract Task FindUserLoginAsync(TKey userId, string loginProvider, string providerKey, CancellationToken cancellationToken); + + /// + /// Return a user login with provider, providerKey if it exists. + /// + /// The login provider name. + /// The key provided by the to identify a user. + /// The used to propagate notifications that the operation should be canceled. + /// The user login if it exists. + protected abstract Task FindUserLoginAsync(string loginProvider, string providerKey, CancellationToken cancellationToken); + + /// + /// Adds the given to the specified . + /// + /// The user to add the role to. + /// The role to add. + /// The used to propagate notifications that the operation should be canceled. + /// The that represents the asynchronous operation. + public abstract Task AddToRoleAsync(TUser user, string normalizedRoleName, CancellationToken cancellationToken = default(CancellationToken)); + + /// + /// Removes the given from the specified . + /// + /// The user to remove the role from. + /// The role to remove. + /// The used to propagate notifications that the operation should be canceled. + /// The that represents the asynchronous operation. + public abstract Task RemoveFromRoleAsync(TUser user, string normalizedRoleName, CancellationToken cancellationToken = default(CancellationToken)); + + /// + /// Retrieves the roles the specified is a member of. + /// + /// The user whose roles should be retrieved. + /// The used to propagate notifications that the operation should be canceled. + /// A that contains the roles the user is a member of. + public abstract Task> GetRolesAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken)); + + /// + /// Returns a flag indicating if the specified user is a member of the give . + /// + /// The user whose role membership should be checked. + /// The role to check membership of + /// The used to propagate notifications that the operation should be canceled. + /// A containing a flag indicating if the specified user is a member of the given group. If the + /// user is a member of the group the returned value with be true, otherwise it will be false. + public abstract Task IsInRoleAsync(TUser user, string normalizedRoleName, CancellationToken cancellationToken = default(CancellationToken)); + + /// + /// Throws if this class has been disposed. + /// + protected void ThrowIfDisposed() + { + if (_disposed) + { + throw new ObjectDisposedException(GetType().Name); + } + } + + /// + /// Dispose the store + /// + public void Dispose() + { + _disposed = true; + } + + /// + /// Get the claims associated with the specified as an asynchronous operation. + /// + /// The user whose claims should be retrieved. + /// The used to propagate notifications that the operation should be canceled. + /// A that contains the claims granted to a user. + public abstract Task> GetClaimsAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken)); + + /// + /// Adds the given to the specified . + /// + /// The user to add the claim to. + /// The claim to add to the user. + /// The used to propagate notifications that the operation should be canceled. + /// The that represents the asynchronous operation. + public abstract Task AddClaimsAsync(TUser user, IEnumerable claims, CancellationToken cancellationToken = default(CancellationToken)); + + /// + /// Replaces the on the specified , with the . + /// + /// The user to replace the claim on. + /// The claim replace. + /// The new claim replacing the . + /// The used to propagate notifications that the operation should be canceled. + /// The that represents the asynchronous operation. + public abstract Task ReplaceClaimAsync(TUser user, Claim claim, Claim newClaim, CancellationToken cancellationToken = default(CancellationToken)); + + /// + /// Removes the given from the specified . + /// + /// The user to remove the claims from. + /// The claim to remove. + /// The used to propagate notifications that the operation should be canceled. + /// The that represents the asynchronous operation. + public abstract Task RemoveClaimsAsync(TUser user, IEnumerable claims, CancellationToken cancellationToken = default(CancellationToken)); + + /// + /// Adds the given to the specified . + /// + /// The user to add the login to. + /// The login to add to the user. + /// The used to propagate notifications that the operation should be canceled. + /// The that represents the asynchronous operation. + public abstract Task AddLoginAsync(TUser user, UserLoginInfo login, CancellationToken cancellationToken = default(CancellationToken)); + + /// + /// Removes the given from the specified . + /// + /// The user to remove the login from. + /// The login to remove from the user. + /// The key provided by the to identify a user. + /// The used to propagate notifications that the operation should be canceled. + /// The that represents the asynchronous operation. + public abstract Task RemoveLoginAsync(TUser user, string loginProvider, string providerKey, CancellationToken cancellationToken = default(CancellationToken)); + + /// + /// Retrieves the associated logins for the specified . + /// + /// The user whose associated logins to retrieve. + /// The used to propagate notifications that the operation should be canceled. + /// + /// The for the asynchronous operation, containing a list of for the specified , if any. + /// + public abstract Task> GetLoginsAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken)); + + /// + /// Retrieves the user associated with the specified login provider and login provider key.. + /// + /// The login provider who provided the . + /// The key provided by the to identify a user. + /// The used to propagate notifications that the operation should be canceled. + /// + /// The for the asynchronous operation, containing the user, if any which matched the specified login provider and key. + /// + public async virtual Task FindByLoginAsync(string loginProvider, string providerKey, + CancellationToken cancellationToken = default(CancellationToken)) + { + cancellationToken.ThrowIfCancellationRequested(); + ThrowIfDisposed(); + var userLogin = await FindUserLoginAsync(loginProvider, providerKey, cancellationToken); + if (userLogin != null) + { + return await FindUserAsync(userLogin.UserId, cancellationToken); + } + return null; + } + + /// + /// Gets a flag indicating whether the email address for the specified has been verified, true if the email address is verified otherwise + /// false. + /// + /// The user whose email confirmation status should be returned. + /// The used to propagate notifications that the operation should be canceled. + /// + /// The task object containing the results of the asynchronous operation, a flag indicating whether the email address for the specified + /// has been confirmed or not. + /// + public virtual Task GetEmailConfirmedAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken)) + { + cancellationToken.ThrowIfCancellationRequested(); + ThrowIfDisposed(); + if (user == null) + { + throw new ArgumentNullException(nameof(user)); + } + return Task.FromResult(user.EmailConfirmed); + } + + /// + /// Sets the flag indicating whether the specified 's email address has been confirmed or not. + /// + /// The user whose email confirmation status should be set. + /// A flag indicating if the email address has been confirmed, true if the address is confirmed otherwise false. + /// The used to propagate notifications that the operation should be canceled. + /// The task object representing the asynchronous operation. + public virtual Task SetEmailConfirmedAsync(TUser user, bool confirmed, CancellationToken cancellationToken = default(CancellationToken)) + { + cancellationToken.ThrowIfCancellationRequested(); + ThrowIfDisposed(); + if (user == null) + { + throw new ArgumentNullException(nameof(user)); + } + user.EmailConfirmed = confirmed; + return TaskCache.CompletedTask; + } + + /// + /// Sets the address for a . + /// + /// The user whose email should be set. + /// The email to set. + /// The used to propagate notifications that the operation should be canceled. + /// The task object representing the asynchronous operation. + public virtual Task SetEmailAsync(TUser user, string email, CancellationToken cancellationToken = default(CancellationToken)) + { + cancellationToken.ThrowIfCancellationRequested(); + ThrowIfDisposed(); + if (user == null) + { + throw new ArgumentNullException(nameof(user)); + } + user.Email = email; + return TaskCache.CompletedTask; + } + + /// + /// Gets the email address for the specified . + /// + /// The user whose email should be returned. + /// The used to propagate notifications that the operation should be canceled. + /// The task object containing the results of the asynchronous operation, the email address for the specified . + public virtual Task GetEmailAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken)) + { + cancellationToken.ThrowIfCancellationRequested(); + ThrowIfDisposed(); + if (user == null) + { + throw new ArgumentNullException(nameof(user)); + } + return Task.FromResult(user.Email); + } + + /// + /// Returns the normalized email for the specified . + /// + /// The user whose email address to retrieve. + /// The used to propagate notifications that the operation should be canceled. + /// + /// The task object containing the results of the asynchronous lookup operation, the normalized email address if any associated with the specified user. + /// + public virtual Task GetNormalizedEmailAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken)) + { + cancellationToken.ThrowIfCancellationRequested(); + ThrowIfDisposed(); + if (user == null) + { + throw new ArgumentNullException(nameof(user)); + } + return Task.FromResult(user.NormalizedEmail); + } + + /// + /// Sets the normalized email for the specified . + /// + /// The user whose email address to set. + /// The normalized email to set for the specified . + /// The used to propagate notifications that the operation should be canceled. + /// The task object representing the asynchronous operation. + public virtual Task SetNormalizedEmailAsync(TUser user, string normalizedEmail, CancellationToken cancellationToken = default(CancellationToken)) + { + cancellationToken.ThrowIfCancellationRequested(); + ThrowIfDisposed(); + if (user == null) + { + throw new ArgumentNullException(nameof(user)); + } + user.NormalizedEmail = normalizedEmail; + return TaskCache.CompletedTask; + } + + /// + /// Gets the user, if any, associated with the specified, normalized email address. + /// + /// The normalized email address to return the user for. + /// The used to propagate notifications that the operation should be canceled. + /// + /// The task object containing the results of the asynchronous lookup operation, the user if any associated with the specified normalized email address. + /// + public abstract Task FindByEmailAsync(string normalizedEmail, CancellationToken cancellationToken = default(CancellationToken)); + + /// + /// Gets the last a user's last lockout expired, if any. + /// Any time in the past should be indicates a user is not locked out. + /// + /// The user whose lockout date should be retrieved. + /// The used to propagate notifications that the operation should be canceled. + /// + /// A that represents the result of the asynchronous query, a containing the last time + /// a user's lockout expired, if any. + /// + public virtual Task GetLockoutEndDateAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken)) + { + cancellationToken.ThrowIfCancellationRequested(); + ThrowIfDisposed(); + if (user == null) + { + throw new ArgumentNullException(nameof(user)); + } + return Task.FromResult(user.LockoutEnd); + } + + /// + /// Locks out a user until the specified end date has passed. Setting a end date in the past immediately unlocks a user. + /// + /// The user whose lockout date should be set. + /// The after which the 's lockout should end. + /// The used to propagate notifications that the operation should be canceled. + /// The that represents the asynchronous operation. + public virtual Task SetLockoutEndDateAsync(TUser user, DateTimeOffset? lockoutEnd, CancellationToken cancellationToken = default(CancellationToken)) + { + cancellationToken.ThrowIfCancellationRequested(); + ThrowIfDisposed(); + if (user == null) + { + throw new ArgumentNullException(nameof(user)); + } + user.LockoutEnd = lockoutEnd; + return TaskCache.CompletedTask; + } + + /// + /// Records that a failed access has occurred, incrementing the failed access count. + /// + /// The user whose cancellation count should be incremented. + /// The used to propagate notifications that the operation should be canceled. + /// The that represents the asynchronous operation, containing the incremented failed access count. + public virtual Task IncrementAccessFailedCountAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken)) + { + cancellationToken.ThrowIfCancellationRequested(); + ThrowIfDisposed(); + if (user == null) + { + throw new ArgumentNullException(nameof(user)); + } + user.AccessFailedCount++; + return Task.FromResult(user.AccessFailedCount); + } + + /// + /// Resets a user's failed access count. + /// + /// The user whose failed access count should be reset. + /// The used to propagate notifications that the operation should be canceled. + /// The that represents the asynchronous operation. + /// This is typically called after the account is successfully accessed. + public virtual Task ResetAccessFailedCountAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken)) + { + cancellationToken.ThrowIfCancellationRequested(); + ThrowIfDisposed(); + if (user == null) + { + throw new ArgumentNullException(nameof(user)); + } + user.AccessFailedCount = 0; + return TaskCache.CompletedTask; + } + + /// + /// Retrieves the current failed access count for the specified .. + /// + /// The user whose failed access count should be retrieved. + /// The used to propagate notifications that the operation should be canceled. + /// The that represents the asynchronous operation, containing the failed access count. + public virtual Task GetAccessFailedCountAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken)) + { + cancellationToken.ThrowIfCancellationRequested(); + ThrowIfDisposed(); + if (user == null) + { + throw new ArgumentNullException(nameof(user)); + } + return Task.FromResult(user.AccessFailedCount); + } + + /// + /// Retrieves a flag indicating whether user lockout can enabled for the specified user. + /// + /// The user whose ability to be locked out should be returned. + /// The used to propagate notifications that the operation should be canceled. + /// + /// The that represents the asynchronous operation, true if a user can be locked out, otherwise false. + /// + public virtual Task GetLockoutEnabledAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken)) + { + cancellationToken.ThrowIfCancellationRequested(); + ThrowIfDisposed(); + if (user == null) + { + throw new ArgumentNullException(nameof(user)); + } + return Task.FromResult(user.LockoutEnabled); + } + + /// + /// Set the flag indicating if the specified can be locked out.. + /// + /// The user whose ability to be locked out should be set. + /// A flag indicating if lock out can be enabled for the specified . + /// The used to propagate notifications that the operation should be canceled. + /// The that represents the asynchronous operation. + public virtual Task SetLockoutEnabledAsync(TUser user, bool enabled, CancellationToken cancellationToken = default(CancellationToken)) + { + cancellationToken.ThrowIfCancellationRequested(); + ThrowIfDisposed(); + if (user == null) + { + throw new ArgumentNullException(nameof(user)); + } + user.LockoutEnabled = enabled; + return TaskCache.CompletedTask; + } + + /// + /// Sets the telephone number for the specified . + /// + /// The user whose telephone number should be set. + /// The telephone number to set. + /// The used to propagate notifications that the operation should be canceled. + /// The that represents the asynchronous operation. + public virtual Task SetPhoneNumberAsync(TUser user, string phoneNumber, CancellationToken cancellationToken = default(CancellationToken)) + { + cancellationToken.ThrowIfCancellationRequested(); + ThrowIfDisposed(); + if (user == null) + { + throw new ArgumentNullException(nameof(user)); + } + user.PhoneNumber = phoneNumber; + return TaskCache.CompletedTask; + } + + /// + /// Gets the telephone number, if any, for the specified . + /// + /// The user whose telephone number should be retrieved. + /// The used to propagate notifications that the operation should be canceled. + /// The that represents the asynchronous operation, containing the user's telephone number, if any. + public virtual Task GetPhoneNumberAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken)) + { + cancellationToken.ThrowIfCancellationRequested(); + ThrowIfDisposed(); + if (user == null) + { + throw new ArgumentNullException(nameof(user)); + } + return Task.FromResult(user.PhoneNumber); + } + + /// + /// Gets a flag indicating whether the specified 's telephone number has been confirmed. + /// + /// The user to return a flag for, indicating whether their telephone number is confirmed. + /// The used to propagate notifications that the operation should be canceled. + /// + /// The that represents the asynchronous operation, returning true if the specified has a confirmed + /// telephone number otherwise false. + /// + public virtual Task GetPhoneNumberConfirmedAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken)) + { + cancellationToken.ThrowIfCancellationRequested(); + ThrowIfDisposed(); + if (user == null) + { + throw new ArgumentNullException(nameof(user)); + } + return Task.FromResult(user.PhoneNumberConfirmed); + } + + /// + /// Sets a flag indicating if the specified 's phone number has been confirmed.. + /// + /// The user whose telephone number confirmation status should be set. + /// A flag indicating whether the user's telephone number has been confirmed. + /// The used to propagate notifications that the operation should be canceled. + /// The that represents the asynchronous operation. + public virtual Task SetPhoneNumberConfirmedAsync(TUser user, bool confirmed, CancellationToken cancellationToken = default(CancellationToken)) + { + cancellationToken.ThrowIfCancellationRequested(); + ThrowIfDisposed(); + if (user == null) + { + throw new ArgumentNullException(nameof(user)); + } + user.PhoneNumberConfirmed = confirmed; + return TaskCache.CompletedTask; + } + + /// + /// Sets the provided security for the specified . + /// + /// The user whose security stamp should be set. + /// The security stamp to set. + /// The used to propagate notifications that the operation should be canceled. + /// The that represents the asynchronous operation. + public virtual Task SetSecurityStampAsync(TUser user, string stamp, CancellationToken cancellationToken = default(CancellationToken)) + { + cancellationToken.ThrowIfCancellationRequested(); + ThrowIfDisposed(); + if (user == null) + { + throw new ArgumentNullException(nameof(user)); + } + if (stamp == null) + { + throw new ArgumentNullException(nameof(stamp)); + } + user.SecurityStamp = stamp; + return TaskCache.CompletedTask; + } + + /// + /// Get the security stamp for the specified . + /// + /// The user whose security stamp should be set. + /// The used to propagate notifications that the operation should be canceled. + /// The that represents the asynchronous operation, containing the security stamp for the specified . + public virtual Task GetSecurityStampAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken)) + { + cancellationToken.ThrowIfCancellationRequested(); + ThrowIfDisposed(); + if (user == null) + { + throw new ArgumentNullException(nameof(user)); + } + return Task.FromResult(user.SecurityStamp); + } + + /// + /// Sets a flag indicating whether the specified has two factor authentication enabled or not, + /// as an asynchronous operation. + /// + /// The user whose two factor authentication enabled status should be set. + /// A flag indicating whether the specified has two factor authentication enabled. + /// The used to propagate notifications that the operation should be canceled. + /// The that represents the asynchronous operation. + public virtual Task SetTwoFactorEnabledAsync(TUser user, bool enabled, CancellationToken cancellationToken = default(CancellationToken)) + { + cancellationToken.ThrowIfCancellationRequested(); + ThrowIfDisposed(); + if (user == null) + { + throw new ArgumentNullException(nameof(user)); + } + user.TwoFactorEnabled = enabled; + return TaskCache.CompletedTask; + } + + /// + /// Returns a flag indicating whether the specified has two factor authentication enabled or not, + /// as an asynchronous operation. + /// + /// The user whose two factor authentication enabled status should be set. + /// The used to propagate notifications that the operation should be canceled. + /// + /// The that represents the asynchronous operation, containing a flag indicating whether the specified + /// has two factor authentication enabled or not. + /// + public virtual Task GetTwoFactorEnabledAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken)) + { + cancellationToken.ThrowIfCancellationRequested(); + ThrowIfDisposed(); + if (user == null) + { + throw new ArgumentNullException(nameof(user)); + } + return Task.FromResult(user.TwoFactorEnabled); + } + + /// + /// Retrieves all users with the specified claim. + /// + /// The claim whose users should be retrieved. + /// The used to propagate notifications that the operation should be canceled. + /// + /// The contains a list of users, if any, that contain the specified claim. + /// + public abstract Task> GetUsersForClaimAsync(Claim claim, CancellationToken cancellationToken = default(CancellationToken)); + + /// + /// Retrieves all users in the specified role. + /// + /// The role whose users should be retrieved. + /// The used to propagate notifications that the operation should be canceled. + /// + /// The contains a list of users, if any, that are in the specified role. + /// + public abstract Task> GetUsersInRoleAsync(string normalizedRoleName, CancellationToken cancellationToken = default(CancellationToken)); + + /// + /// Find a user token if it exists. + /// + /// The token owner. + /// The login provider for the token. + /// The name of the token. + /// The used to propagate notifications that the operation should be canceled. + /// The user token if it exists. + protected abstract Task FindTokenAsync(TUser user, string loginProvider, string name, CancellationToken cancellationToken); + + /// + /// Add a new user token. + /// + /// The token to be added. + /// + protected abstract Task AddUserTokenAsync(TUserToken token); + + /// + /// Remove a new user token. + /// + /// The token to be removed. + /// + protected abstract Task RemoveUserTokenAsync(TUserToken token); + + /// + /// Sets the token value for a particular user. + /// + /// The user. + /// The authentication provider for the token. + /// The name of the token. + /// The value of the token. + /// The used to propagate notifications that the operation should be canceled. + /// The that represents the asynchronous operation. + public virtual async Task SetTokenAsync(TUser user, string loginProvider, string name, string value, CancellationToken cancellationToken) + { + cancellationToken.ThrowIfCancellationRequested(); + ThrowIfDisposed(); + + if (user == null) + { + throw new ArgumentNullException(nameof(user)); + } + + var token = await FindTokenAsync(user, loginProvider, name, cancellationToken); + if (token == null) + { + await AddUserTokenAsync(CreateUserToken(user, loginProvider, name, value)); + } + else + { + token.Value = value; + } + } + + /// + /// Deletes a token for a user. + /// + /// The user. + /// The authentication provider for the token. + /// The name of the token. + /// The used to propagate notifications that the operation should be canceled. + /// The that represents the asynchronous operation. + public virtual async Task RemoveTokenAsync(TUser user, string loginProvider, string name, CancellationToken cancellationToken) + { + cancellationToken.ThrowIfCancellationRequested(); + ThrowIfDisposed(); + + if (user == null) + { + throw new ArgumentNullException(nameof(user)); + } + var entry = await FindTokenAsync(user, loginProvider, name, cancellationToken); + if (entry != null) + { + await RemoveUserTokenAsync(entry); + } + } + + /// + /// Returns the token value. + /// + /// The user. + /// The authentication provider for the token. + /// The name of the token. + /// The used to propagate notifications that the operation should be canceled. + /// The that represents the asynchronous operation. + public virtual async Task GetTokenAsync(TUser user, string loginProvider, string name, CancellationToken cancellationToken) + { + cancellationToken.ThrowIfCancellationRequested(); + ThrowIfDisposed(); + + if (user == null) + { + throw new ArgumentNullException(nameof(user)); + } + var entry = await FindTokenAsync(user, loginProvider, name, cancellationToken); + return entry?.Value; + } + + private const string InternalLoginProvider = "[AspNetUserStore]"; + private const string AuthenticatorKeyTokenName = "AuthenticatorKey"; + private const string RecoveryCodeTokenName = "RecoveryCodes"; + + /// + /// Sets the authenticator key for the specified . + /// + /// The user whose authenticator key should be set. + /// The authenticator key to set. + /// The used to propagate notifications that the operation should be canceled. + /// The that represents the asynchronous operation. + public virtual Task SetAuthenticatorKeyAsync(TUser user, string key, CancellationToken cancellationToken) + { + return SetTokenAsync(user, InternalLoginProvider, AuthenticatorKeyTokenName, key, cancellationToken); + } + + /// + /// Get the authenticator key for the specified . + /// + /// The user whose security stamp should be set. + /// The used to propagate notifications that the operation should be canceled. + /// The that represents the asynchronous operation, containing the security stamp for the specified . + public virtual Task GetAuthenticatorKeyAsync(TUser user, CancellationToken cancellationToken) + { + return GetTokenAsync(user, InternalLoginProvider, AuthenticatorKeyTokenName, cancellationToken); + } + + /// + /// Updates the recovery codes for the user while invalidating any previous recovery codes. + /// + /// The user to store new recovery codes for. + /// The new recovery codes for the user. + /// The used to propagate notifications that the operation should be canceled. + /// The new recovery codes for the user. + public virtual Task ReplaceCodesAsync(TUser user, IEnumerable recoveryCodes, CancellationToken cancellationToken) + { + var mergedCodes = string.Join(";", recoveryCodes); + return SetTokenAsync(user, InternalLoginProvider, RecoveryCodeTokenName, mergedCodes, cancellationToken); + } + + /// + /// Returns whether a recovery code is valid for a user. Note: recovery codes are only valid + /// once, and will be invalid after use. + /// + /// The user who owns the recovery code. + /// The recovery code to use. + /// The used to propagate notifications that the operation should be canceled. + /// True if the recovery code was found for the user. + public virtual async Task RedeemCodeAsync(TUser user, string code, CancellationToken cancellationToken) + { + cancellationToken.ThrowIfCancellationRequested(); + ThrowIfDisposed(); + + if (user == null) + { + throw new ArgumentNullException(nameof(user)); + } + if (code == null) + { + throw new ArgumentNullException(nameof(code)); + } + + var mergedCodes = await GetTokenAsync(user, InternalLoginProvider, RecoveryCodeTokenName, cancellationToken) ?? ""; + var splitCodes = mergedCodes.Split(';'); + if (splitCodes.Contains(code)) + { + var updatedCodes = new List(splitCodes.Where(s => s != code)); + await ReplaceCodesAsync(user, updatedCodes, cancellationToken); + return true; + } + return false; + } + } +} diff --git a/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/DefaultPocoTest.cs b/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/DefaultPocoTest.cs index 2c787bf2da..4a3d13feed 100644 --- a/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/DefaultPocoTest.cs +++ b/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/DefaultPocoTest.cs @@ -60,127 +60,5 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test IdentityResultAssert.IsSuccess(await userManager.CreateAsync(user, password)); IdentityResultAssert.IsSuccess(await userManager.DeleteAsync(user)); } - - [ConditionalFact] - [FrameworkSkipCondition(RuntimeFrameworks.Mono)] - [OSSkipCondition(OperatingSystems.Linux)] - [OSSkipCondition(OperatingSystems.MacOSX)] - public async Task CanIncludeUserClaimsTest() - { - // Arrange - var userManager = _builder.ApplicationServices.GetRequiredService>(); - var dbContext = _builder.ApplicationServices.GetRequiredService(); - - var username = "user" + new Random().Next(); - var user = new IdentityUser() { UserName = username }; - IdentityResultAssert.IsSuccess(await userManager.CreateAsync(user)); - - for (var i = 0; i < 10; i++) - { - IdentityResultAssert.IsSuccess(await userManager.AddClaimAsync(user, new Claim(i.ToString(), "foo"))); - } - - user = dbContext.Users.Include(x => x.Claims).FirstOrDefault(x => x.UserName == username); - - // Assert - Assert.NotNull(user); - Assert.NotNull(user.Claims); - Assert.Equal(10, user.Claims.Count()); - } - - [ConditionalFact] - [FrameworkSkipCondition(RuntimeFrameworks.Mono)] - [OSSkipCondition(OperatingSystems.Linux)] - [OSSkipCondition(OperatingSystems.MacOSX)] - public async Task CanIncludeUserLoginsTest() - { - // Arrange - var userManager = _builder.ApplicationServices.GetRequiredService>(); - var dbContext = _builder.ApplicationServices.GetRequiredService(); - - var username = "user" + new Random().Next(); - var user = new IdentityUser() { UserName = username }; - IdentityResultAssert.IsSuccess(await userManager.CreateAsync(user)); - - for (var i = 0; i < 10; i++) - { - IdentityResultAssert.IsSuccess(await userManager.AddLoginAsync(user, new UserLoginInfo("foo" + i, "bar" + i, "foo"))); - } - - user = dbContext.Users.Include(x => x.Logins).FirstOrDefault(x => x.UserName == username); - - // Assert - Assert.NotNull(user); - Assert.NotNull(user.Logins); - Assert.Equal(10, user.Logins.Count()); - } - - [ConditionalFact] - [FrameworkSkipCondition(RuntimeFrameworks.Mono)] - [OSSkipCondition(OperatingSystems.Linux)] - [OSSkipCondition(OperatingSystems.MacOSX)] - public async Task CanIncludeUserRolesTest() - { - // Arrange - var userManager = _builder.ApplicationServices.GetRequiredService>(); - var roleManager = _builder.ApplicationServices.GetRequiredService>(); - var dbContext = _builder.ApplicationServices.GetRequiredService(); - - const string roleName = "Admin"; - for (var i = 0; i < 10; i++) - { - IdentityResultAssert.IsSuccess(await roleManager.CreateAsync(new IdentityRole(roleName + i))); - } - var username = "user" + new Random().Next(); - var user = new IdentityUser() { UserName = username }; - IdentityResultAssert.IsSuccess(await userManager.CreateAsync(user)); - - for (var i = 0; i < 10; i++) - { - IdentityResultAssert.IsSuccess(await userManager.AddToRoleAsync(user, roleName + i)); - } - - user = dbContext.Users.Include(x => x.Roles).FirstOrDefault(x => x.UserName == username); - - // Assert - Assert.NotNull(user); - Assert.NotNull(user.Roles); - Assert.Equal(10, user.Roles.Count()); - - for (var i = 0; i < 10; i++) - { - var role = dbContext.Roles.Include(r => r.Users).FirstOrDefault(r => r.Name == (roleName + i)); - Assert.NotNull(role); - Assert.NotNull(role.Users); - Assert.Equal(1, role.Users.Count()); - } - } - - [ConditionalFact] - [FrameworkSkipCondition(RuntimeFrameworks.Mono)] - [OSSkipCondition(OperatingSystems.Linux)] - [OSSkipCondition(OperatingSystems.MacOSX)] - public async Task CanIncludeRoleClaimsTest() - { - // Arrange - var roleManager = _builder.ApplicationServices.GetRequiredService>(); - var dbContext = _builder.ApplicationServices.GetRequiredService(); - - var role = new IdentityRole("Admin"); - - IdentityResultAssert.IsSuccess(await roleManager.CreateAsync(role)); - - for (var i = 0; i < 10; i++) - { - IdentityResultAssert.IsSuccess(await roleManager.AddClaimAsync(role, new Claim("foo" + i, "bar" + i))); - } - - role = dbContext.Roles.Include(x => x.Claims).FirstOrDefault(x => x.Name == "Admin"); - - // Assert - Assert.NotNull(role); - Assert.NotNull(role.Claims); - Assert.Equal(10, role.Claims.Count()); - } } } \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Identity.InMemory.Test/ControllerTest.cs b/test/Microsoft.AspNetCore.Identity.InMemory.Test/ControllerTest.cs index 77bae7ed9a..b15903aefb 100644 --- a/test/Microsoft.AspNetCore.Identity.InMemory.Test/ControllerTest.cs +++ b/test/Microsoft.AspNetCore.Identity.InMemory.Test/ControllerTest.cs @@ -23,7 +23,7 @@ namespace Microsoft.AspNetCore.Identity.InMemory.Test { var context = new DefaultHttpContext(); var auth = MockAuth(context); - auth.Setup(a => a.SignInAsync(context, new IdentityCookieOptions().ApplicationCookieAuthenticationScheme, + auth.Setup(a => a.SignInAsync(context, IdentityConstants.ApplicationScheme, It.IsAny(), It.IsAny())).Returns(Task.FromResult(0)).Verifiable(); // REVIEW: is persistant mocking broken diff --git a/test/Microsoft.AspNetCore.Identity.InMemory.Test/FunctionalTest.cs b/test/Microsoft.AspNetCore.Identity.InMemory.Test/FunctionalTest.cs index 385f653f24..d98020a10d 100644 --- a/test/Microsoft.AspNetCore.Identity.InMemory.Test/FunctionalTest.cs +++ b/test/Microsoft.AspNetCore.Identity.InMemory.Test/FunctionalTest.cs @@ -137,9 +137,9 @@ namespace Microsoft.AspNetCore.Identity.InMemory var clock = new TestClock(); var server = CreateServer(services => { - services.Configure(options => + services.Configure(options => { - options.OnSecurityStampRefreshingPrincipal = c => + options.OnRefreshingPrincipal = c => { var newId = new ClaimsIdentity(); newId.AddClaim(new Claim("PreviousName", c.CurrentPrincipal.Identity.Name)); @@ -195,7 +195,7 @@ namespace Microsoft.AspNetCore.Identity.InMemory Assert.Equal(HttpStatusCode.OK, transaction2.Response.StatusCode); var setCookie = transaction2.SetCookie; - Assert.Contains(new IdentityCookieOptions().TwoFactorRememberMeCookieAuthenticationScheme + "=", setCookie); + Assert.Contains(IdentityConstants.TwoFactorRememberMeScheme + "=", setCookie); Assert.Contains("; expires=", setCookie); var transaction3 = await SendAsync(server, "http://example.com/isTwoFactorRememebered", transaction2.CookieNameValue); diff --git a/test/Microsoft.AspNetCore.Identity.Test/IdentityBuilderTest.cs b/test/Microsoft.AspNetCore.Identity.Test/IdentityBuilderTest.cs index e0ea1ca46e..7622fc3a6b 100644 --- a/test/Microsoft.AspNetCore.Identity.Test/IdentityBuilderTest.cs +++ b/test/Microsoft.AspNetCore.Identity.Test/IdentityBuilderTest.cs @@ -321,7 +321,7 @@ namespace Microsoft.AspNetCore.Identity.Test private class MyRoleManager : RoleManager { public MyRoleManager(IRoleStore store, - IEnumerable> roleValidators) : base(store, null, null, null, null, null) + IEnumerable> roleValidators) : base(store, null, null, null, null) { } diff --git a/test/Microsoft.AspNetCore.Identity.Test/IdentityResultTest.cs b/test/Microsoft.AspNetCore.Identity.Test/IdentityResultTest.cs index 2e4d0ff646..19d2c727ad 100644 --- a/test/Microsoft.AspNetCore.Identity.Test/IdentityResultTest.cs +++ b/test/Microsoft.AspNetCore.Identity.Test/IdentityResultTest.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.Linq; -using System.Text; using Xunit; namespace Microsoft.AspNetCore.Identity.Test diff --git a/test/Microsoft.AspNetCore.Identity.Test/RoleManagerTest.cs b/test/Microsoft.AspNetCore.Identity.Test/RoleManagerTest.cs index 2b745ff321..4e82ec6f1a 100644 --- a/test/Microsoft.AspNetCore.Identity.Test/RoleManagerTest.cs +++ b/test/Microsoft.AspNetCore.Identity.Test/RoleManagerTest.cs @@ -124,7 +124,7 @@ namespace Microsoft.AspNetCore.Identity.Test public async Task RoleManagerPublicNullChecks() { Assert.Throws("store", - () => new RoleManager(null, null, null, null, null, null)); + () => new RoleManager(null, null, null, null, null)); var manager = CreateRoleManager(new NotImplementedStore()); await Assert.ThrowsAsync("role", async () => await manager.CreateAsync(null)); await Assert.ThrowsAsync("role", async () => await manager.UpdateAsync(null)); diff --git a/test/Microsoft.AspNetCore.Identity.Test/SecurityStampValidatorTest.cs b/test/Microsoft.AspNetCore.Identity.Test/SecurityStampValidatorTest.cs index 793fabd211..024d7dd8d2 100644 --- a/test/Microsoft.AspNetCore.Identity.Test/SecurityStampValidatorTest.cs +++ b/test/Microsoft.AspNetCore.Identity.Test/SecurityStampValidatorTest.cs @@ -55,9 +55,9 @@ namespace Microsoft.AspNetCore.Identity.Test { var httpContext = new Mock(); httpContext.Setup(c => c.RequestServices).Returns(new ServiceCollection().BuildServiceProvider()); - var id = new ClaimsPrincipal(new ClaimsIdentity(IdentityCookieOptions.ApplicationScheme)); - var ticket = new AuthenticationTicket(id, new AuthenticationProperties { IssuedUtc = DateTimeOffset.UtcNow }, IdentityCookieOptions.ApplicationScheme); - var context = new CookieValidatePrincipalContext(httpContext.Object, new AuthenticationSchemeBuilder(IdentityCookieOptions.ApplicationScheme) { HandlerType = typeof(NoopHandler) }.Build(), ticket, new CookieAuthenticationOptions()); + var id = new ClaimsPrincipal(new ClaimsIdentity(IdentityConstants.ApplicationScheme)); + var ticket = new AuthenticationTicket(id, new AuthenticationProperties { IssuedUtc = DateTimeOffset.UtcNow }, IdentityConstants.ApplicationScheme); + var context = new CookieValidatePrincipalContext(httpContext.Object, new AuthenticationSchemeBuilder(IdentityConstants.ApplicationScheme) { HandlerType = typeof(NoopHandler) }.Build(), ticket, new CookieAuthenticationOptions()); var ex = await Assert.ThrowsAsync(() => SecurityStampValidator.ValidatePrincipalAsync(context)); } @@ -69,19 +69,20 @@ namespace Microsoft.AspNetCore.Identity.Test var user = new TestUser("test"); var userManager = MockHelpers.MockUserManager(); var claimsManager = new Mock>(); - var identityOptions = new IdentityOptions { SecurityStampValidationInterval = TimeSpan.Zero }; - var options = new Mock>(); - options.Setup(a => a.Value).Returns(identityOptions); + var identityOptions = new Mock>(); + identityOptions.Setup(a => a.Value).Returns(new IdentityOptions()); + var options = new Mock>(); + options.Setup(a => a.Value).Returns(new SecurityStampValidatorOptions { ValidationInterval = TimeSpan.Zero }); var httpContext = new Mock(); var contextAccessor = new Mock(); contextAccessor.Setup(a => a.HttpContext).Returns(httpContext.Object); - var id = new ClaimsIdentity(identityOptions.Cookies.ApplicationCookieAuthenticationScheme); + var id = new ClaimsIdentity(IdentityConstants.ApplicationScheme); id.AddClaim(new Claim(ClaimTypes.NameIdentifier, user.Id)); var principal = new ClaimsPrincipal(id); var properties = new AuthenticationProperties { IssuedUtc = DateTimeOffset.UtcNow.AddSeconds(-1), IsPersistent = isPersistent }; var signInManager = new Mock>(userManager.Object, - contextAccessor.Object, claimsManager.Object, options.Object, null, new Mock().Object); + contextAccessor.Object, claimsManager.Object, identityOptions.Object, null, new Mock().Object); signInManager.Setup(s => s.ValidateSecurityStampAsync(It.IsAny())).ReturnsAsync(user).Verifiable(); signInManager.Setup(s => s.CreateUserPrincipalAsync(user)).ReturnsAsync(principal).Verifiable(); var services = new ServiceCollection(); @@ -92,8 +93,8 @@ namespace Microsoft.AspNetCore.Identity.Test var ticket = new AuthenticationTicket(principal, properties, - identityOptions.Cookies.ApplicationCookieAuthenticationScheme); - var context = new CookieValidatePrincipalContext(httpContext.Object, new AuthenticationSchemeBuilder(identityOptions.Cookies.ApplicationCookieAuthenticationScheme) { HandlerType = typeof(NoopHandler) }.Build(), ticket, new CookieAuthenticationOptions()); + IdentityConstants.ApplicationScheme); + var context = new CookieValidatePrincipalContext(httpContext.Object, new AuthenticationSchemeBuilder(IdentityConstants.ApplicationScheme) { HandlerType = typeof(NoopHandler) }.Build(), ticket, new CookieAuthenticationOptions()); Assert.NotNull(context.Properties); Assert.NotNull(context.Options); Assert.NotNull(context.Principal); @@ -109,27 +110,28 @@ namespace Microsoft.AspNetCore.Identity.Test var user = new TestUser("test"); var userManager = MockHelpers.MockUserManager(); var claimsManager = new Mock>(); - var identityOptions = new IdentityOptions { SecurityStampValidationInterval = TimeSpan.Zero }; - var options = new Mock>(); - options.Setup(a => a.Value).Returns(identityOptions); + var identityOptions = new Mock>(); + identityOptions.Setup(a => a.Value).Returns(new IdentityOptions()); + var options = new Mock>(); + options.Setup(a => a.Value).Returns(new SecurityStampValidatorOptions { ValidationInterval = TimeSpan.Zero }); var httpContext = new Mock(); var contextAccessor = new Mock(); contextAccessor.Setup(a => a.HttpContext).Returns(httpContext.Object); var signInManager = new Mock>(userManager.Object, - contextAccessor.Object, claimsManager.Object, options.Object, null, new Mock().Object); + contextAccessor.Object, claimsManager.Object, identityOptions.Object, null, new Mock().Object); signInManager.Setup(s => s.ValidateSecurityStampAsync(It.IsAny())).ReturnsAsync(default(TestUser)).Verifiable(); var services = new ServiceCollection(); services.AddSingleton(options.Object); services.AddSingleton(signInManager.Object); services.AddSingleton(new SecurityStampValidator(options.Object, signInManager.Object, new SystemClock())); httpContext.Setup(c => c.RequestServices).Returns(services.BuildServiceProvider()); - var id = new ClaimsIdentity(identityOptions.Cookies.ApplicationCookieAuthenticationScheme); + var id = new ClaimsIdentity(IdentityConstants.ApplicationScheme); id.AddClaim(new Claim(ClaimTypes.NameIdentifier, user.Id)); var ticket = new AuthenticationTicket(new ClaimsPrincipal(id), new AuthenticationProperties { IssuedUtc = DateTimeOffset.UtcNow.AddSeconds(-1) }, - identityOptions.Cookies.ApplicationCookieAuthenticationScheme); - var context = new CookieValidatePrincipalContext(httpContext.Object, new AuthenticationSchemeBuilder(identityOptions.Cookies.ApplicationCookieAuthenticationScheme) { HandlerType = typeof(NoopHandler) }.Build(), ticket, new CookieAuthenticationOptions()); + IdentityConstants.ApplicationScheme); + var context = new CookieValidatePrincipalContext(httpContext.Object, new AuthenticationSchemeBuilder(IdentityConstants.ApplicationScheme) { HandlerType = typeof(NoopHandler) }.Build(), ticket, new CookieAuthenticationOptions()); Assert.NotNull(context.Properties); Assert.NotNull(context.Options); Assert.NotNull(context.Principal); @@ -144,27 +146,28 @@ namespace Microsoft.AspNetCore.Identity.Test var user = new TestUser("test"); var httpContext = new Mock(); var userManager = MockHelpers.MockUserManager(); + var identityOptions = new Mock>(); + identityOptions.Setup(a => a.Value).Returns(new IdentityOptions()); var claimsManager = new Mock>(); - var identityOptions = new IdentityOptions { SecurityStampValidationInterval = TimeSpan.Zero }; - var options = new Mock>(); - options.Setup(a => a.Value).Returns(identityOptions); + var options = new Mock>(); + options.Setup(a => a.Value).Returns(new SecurityStampValidatorOptions { ValidationInterval = TimeSpan.Zero }); var contextAccessor = new Mock(); contextAccessor.Setup(a => a.HttpContext).Returns(httpContext.Object); var signInManager = new Mock>(userManager.Object, - contextAccessor.Object, claimsManager.Object, options.Object, null, new Mock().Object); + contextAccessor.Object, claimsManager.Object, identityOptions.Object, null, new Mock().Object); signInManager.Setup(s => s.ValidateSecurityStampAsync(It.IsAny())).ReturnsAsync(default(TestUser)).Verifiable(); var services = new ServiceCollection(); services.AddSingleton(options.Object); services.AddSingleton(signInManager.Object); services.AddSingleton(new SecurityStampValidator(options.Object, signInManager.Object, new SystemClock())); httpContext.Setup(c => c.RequestServices).Returns(services.BuildServiceProvider()); - var id = new ClaimsIdentity(identityOptions.Cookies.ApplicationCookieAuthenticationScheme); + var id = new ClaimsIdentity(IdentityConstants.ApplicationScheme); id.AddClaim(new Claim(ClaimTypes.NameIdentifier, user.Id)); var ticket = new AuthenticationTicket(new ClaimsPrincipal(id), new AuthenticationProperties(), - identityOptions.Cookies.ApplicationCookieAuthenticationScheme); - var context = new CookieValidatePrincipalContext(httpContext.Object, new AuthenticationSchemeBuilder(identityOptions.Cookies.ApplicationCookieAuthenticationScheme) { HandlerType = typeof(NoopHandler) }.Build(), ticket, new CookieAuthenticationOptions()); + IdentityConstants.ApplicationScheme); + var context = new CookieValidatePrincipalContext(httpContext.Object, new AuthenticationSchemeBuilder(IdentityConstants.ApplicationScheme) { HandlerType = typeof(NoopHandler) }.Build(), ticket, new CookieAuthenticationOptions()); Assert.NotNull(context.Properties); Assert.NotNull(context.Options); Assert.NotNull(context.Principal); @@ -179,14 +182,15 @@ namespace Microsoft.AspNetCore.Identity.Test var user = new TestUser("test"); var httpContext = new Mock(); var userManager = MockHelpers.MockUserManager(); + var identityOptions = new Mock>(); + identityOptions.Setup(a => a.Value).Returns(new IdentityOptions()); var claimsManager = new Mock>(); - var identityOptions = new IdentityOptions { SecurityStampValidationInterval = TimeSpan.FromDays(1) }; - var options = new Mock>(); - options.Setup(a => a.Value).Returns(identityOptions); + var options = new Mock>(); + options.Setup(a => a.Value).Returns(new SecurityStampValidatorOptions { ValidationInterval = TimeSpan.FromDays(1) }); var contextAccessor = new Mock(); contextAccessor.Setup(a => a.HttpContext).Returns(httpContext.Object); var signInManager = new Mock>(userManager.Object, - contextAccessor.Object, claimsManager.Object, options.Object, null, new Mock().Object); + contextAccessor.Object, claimsManager.Object, identityOptions.Object, null, new Mock().Object); signInManager.Setup(s => s.ValidateSecurityStampAsync(It.IsAny())).Throws(new Exception("Shouldn't be called")); signInManager.Setup(s => s.SignInAsync(user, false, null)).Throws(new Exception("Shouldn't be called")); var services = new ServiceCollection(); @@ -194,13 +198,13 @@ namespace Microsoft.AspNetCore.Identity.Test services.AddSingleton(signInManager.Object); services.AddSingleton(new SecurityStampValidator(options.Object, signInManager.Object, new SystemClock())); httpContext.Setup(c => c.RequestServices).Returns(services.BuildServiceProvider()); - var id = new ClaimsIdentity(identityOptions.Cookies.ApplicationCookieAuthenticationScheme); + var id = new ClaimsIdentity(IdentityConstants.ApplicationScheme); id.AddClaim(new Claim(ClaimTypes.NameIdentifier, user.Id)); var ticket = new AuthenticationTicket(new ClaimsPrincipal(id), new AuthenticationProperties { IssuedUtc = DateTimeOffset.UtcNow }, - identityOptions.Cookies.ApplicationCookieAuthenticationScheme); - var context = new CookieValidatePrincipalContext(httpContext.Object, new AuthenticationSchemeBuilder(identityOptions.Cookies.ApplicationCookieAuthenticationScheme) { HandlerType = typeof(NoopHandler) }.Build(), ticket, new CookieAuthenticationOptions()); + IdentityConstants.ApplicationScheme); + var context = new CookieValidatePrincipalContext(httpContext.Object, new AuthenticationSchemeBuilder(IdentityConstants.ApplicationScheme) { HandlerType = typeof(NoopHandler) }.Build(), ticket, new CookieAuthenticationOptions()); Assert.NotNull(context.Properties); Assert.NotNull(context.Options); Assert.NotNull(context.Principal); diff --git a/test/Microsoft.AspNetCore.Identity.Test/SignInManagerTest.cs b/test/Microsoft.AspNetCore.Identity.Test/SignInManagerTest.cs index 328925d6a8..a5bf8a134f 100644 --- a/test/Microsoft.AspNetCore.Identity.Test/SignInManagerTest.cs +++ b/test/Microsoft.AspNetCore.Identity.Test/SignInManagerTest.cs @@ -293,7 +293,7 @@ namespace Microsoft.AspNetCore.Identity.Test var context = new DefaultHttpContext(); var helper = SetupSignInManager(manager.Object, context); var auth = MockAuth(context); - auth.Setup(a => a.SignInAsync(context, helper.Options.Cookies.TwoFactorUserIdCookieAuthenticationScheme, + auth.Setup(a => a.SignInAsync(context, IdentityConstants.TwoFactorUserIdScheme, It.Is(id => id.FindFirstValue(ClaimTypes.Name) == user.Id), It.IsAny())).Returns(Task.FromResult(0)).Verifiable(); @@ -337,7 +337,7 @@ namespace Microsoft.AspNetCore.Identity.Test } else { - auth.Setup(a => a.SignInAsync(context, helper.Options.Cookies.TwoFactorUserIdCookieAuthenticationScheme, + auth.Setup(a => a.SignInAsync(context, IdentityConstants.TwoFactorUserIdScheme, It.Is(id => id.FindFirstValue(ClaimTypes.Name) == user.Id), It.IsAny())).Returns(Task.FromResult(0)).Verifiable(); } @@ -386,14 +386,14 @@ namespace Microsoft.AspNetCore.Identity.Test } var id = helper.StoreTwoFactorInfo(user.Id, null); SetupSignIn(context, auth, user.Id, isPersistent); - auth.Setup(a => a.AuthenticateAsync(context, helper.Options.Cookies.TwoFactorUserIdCookieAuthenticationScheme)) - .ReturnsAsync(AuthenticateResult.Success(new AuthenticationTicket(id, null, helper.Options.Cookies.TwoFactorUserIdCookieAuthenticationScheme))).Verifiable(); + auth.Setup(a => a.AuthenticateAsync(context, IdentityConstants.TwoFactorUserIdScheme)) + .ReturnsAsync(AuthenticateResult.Success(new AuthenticationTicket(id, null, IdentityConstants.TwoFactorUserIdScheme))).Verifiable(); if (rememberClient) { auth.Setup(a => a.SignInAsync(context, - helper.Options.Cookies.TwoFactorRememberMeCookieAuthenticationScheme, + IdentityConstants.TwoFactorRememberMeScheme, It.Is(i => i.FindFirstValue(ClaimTypes.Name) == user.Id - && i.Identities.First().AuthenticationType == helper.Options.Cookies.TwoFactorRememberMeCookieAuthenticationScheme), + && i.Identities.First().AuthenticationType == IdentityConstants.TwoFactorRememberMeScheme), It.IsAny())).Returns(Task.FromResult(0)).Verifiable(); } @@ -432,19 +432,19 @@ namespace Microsoft.AspNetCore.Identity.Test if (externalLogin) { auth.Setup(a => a.SignInAsync(context, - helper.Options.Cookies.ApplicationCookieAuthenticationScheme, + IdentityConstants.ApplicationScheme, It.Is(i => i.FindFirstValue(ClaimTypes.AuthenticationMethod) == loginProvider && i.FindFirstValue(ClaimTypes.NameIdentifier) == user.Id), It.IsAny())).Returns(Task.FromResult(0)).Verifiable(); - auth.Setup(a => a.SignOutAsync(context, helper.Options.Cookies.ExternalCookieAuthenticationScheme, It.IsAny())).Returns(Task.FromResult(0)).Verifiable(); - auth.Setup(a => a.SignOutAsync(context, helper.Options.Cookies.TwoFactorUserIdCookieAuthenticationScheme, It.IsAny())).Returns(Task.FromResult(0)).Verifiable(); + auth.Setup(a => a.SignOutAsync(context, IdentityConstants.ExternalScheme, It.IsAny())).Returns(Task.FromResult(0)).Verifiable(); + auth.Setup(a => a.SignOutAsync(context, IdentityConstants.TwoFactorUserIdScheme, It.IsAny())).Returns(Task.FromResult(0)).Verifiable(); } else { SetupSignIn(context, auth, user.Id); } - auth.Setup(a => a.AuthenticateAsync(context, helper.Options.Cookies.TwoFactorUserIdCookieAuthenticationScheme)) - .ReturnsAsync(AuthenticateResult.Success(new AuthenticationTicket(id, null, helper.Options.Cookies.TwoFactorUserIdCookieAuthenticationScheme))).Verifiable(); + auth.Setup(a => a.AuthenticateAsync(context, IdentityConstants.TwoFactorUserIdScheme)) + .ReturnsAsync(AuthenticateResult.Success(new AuthenticationTicket(id, null, IdentityConstants.TwoFactorUserIdScheme))).Verifiable(); // Act var result = await helper.TwoFactorRecoveryCodeSignInAsync(bypassCode); @@ -508,7 +508,7 @@ namespace Microsoft.AspNetCore.Identity.Test // REVIEW: auth changes we lost the ability to mock is persistent //var properties = new AuthenticationProperties { IsPersistent = isPersistent }; var authResult = AuthenticateResult.None(); - auth.Setup(a => a.AuthenticateAsync(context, new IdentityCookieOptions().ApplicationCookieAuthenticationScheme)) + auth.Setup(a => a.AuthenticateAsync(context, IdentityConstants.ApplicationScheme)) .Returns(Task.FromResult(authResult)).Verifiable(); var manager = SetupUserManager(user); var signInManager = new Mock>(manager.Object, @@ -569,14 +569,14 @@ namespace Microsoft.AspNetCore.Identity.Test if (externalLogin) { auth.Setup(a => a.SignInAsync(context, - helper.Options.Cookies.ApplicationCookieAuthenticationScheme, + IdentityConstants.ApplicationScheme, 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(context, helper.Options.Cookies.ExternalCookieAuthenticationScheme, It.IsAny())).Returns(Task.FromResult(0)).Verifiable(); - auth.Setup(a => a.SignOutAsync(context, helper.Options.Cookies.TwoFactorUserIdCookieAuthenticationScheme, It.IsAny())).Returns(Task.FromResult(0)).Verifiable(); + auth.Setup(a => a.SignOutAsync(context, IdentityConstants.ExternalScheme, It.IsAny())).Returns(Task.FromResult(0)).Verifiable(); + auth.Setup(a => a.SignOutAsync(context, IdentityConstants.TwoFactorUserIdScheme, It.IsAny())).Returns(Task.FromResult(0)).Verifiable(); } else { @@ -585,14 +585,14 @@ namespace Microsoft.AspNetCore.Identity.Test if (rememberClient) { auth.Setup(a => a.SignInAsync(context, - helper.Options.Cookies.TwoFactorRememberMeCookieAuthenticationScheme, + IdentityConstants.TwoFactorRememberMeScheme, It.Is(i => i.FindFirstValue(ClaimTypes.Name) == user.Id - && i.Identities.First().AuthenticationType == helper.Options.Cookies.TwoFactorRememberMeCookieAuthenticationScheme), + && i.Identities.First().AuthenticationType == IdentityConstants.TwoFactorRememberMeScheme), It.IsAny())).Returns(Task.FromResult(0)).Verifiable(); //It.Is(v => v.IsPersistent == true))).Returns(Task.FromResult(0)).Verifiable(); } - auth.Setup(a => a.AuthenticateAsync(context, helper.Options.Cookies.TwoFactorUserIdCookieAuthenticationScheme)) - .ReturnsAsync(AuthenticateResult.Success(new AuthenticationTicket(id, null, helper.Options.Cookies.TwoFactorUserIdCookieAuthenticationScheme))).Verifiable(); + auth.Setup(a => a.AuthenticateAsync(context, IdentityConstants.TwoFactorUserIdScheme)) + .ReturnsAsync(AuthenticateResult.Success(new AuthenticationTicket(id, null, IdentityConstants.TwoFactorUserIdScheme))).Verifiable(); // Act var result = await helper.TwoFactorSignInAsync(provider, code, isPersistent, rememberClient); @@ -614,9 +614,9 @@ namespace Microsoft.AspNetCore.Identity.Test var helper = SetupSignInManager(manager.Object, context); auth.Setup(a => a.SignInAsync( context, - manager.Object.Options.Cookies.TwoFactorRememberMeCookieAuthenticationScheme, + IdentityConstants.TwoFactorRememberMeScheme, It.Is(i => i.FindFirstValue(ClaimTypes.Name) == user.Id - && i.Identities.First().AuthenticationType == manager.Object.Options.Cookies.TwoFactorRememberMeCookieAuthenticationScheme), + && i.Identities.First().AuthenticationType == IdentityConstants.TwoFactorRememberMeScheme), It.Is(v => v.IsPersistent == true))).Returns(Task.FromResult(0)).Verifiable(); @@ -647,10 +647,10 @@ namespace Microsoft.AspNetCore.Identity.Test var context = new DefaultHttpContext(); var auth = MockAuth(context); SetupSignIn(context, auth); - var id = new ClaimsIdentity(manager.Object.Options.Cookies.TwoFactorRememberMeCookieAuthenticationScheme); + var id = new ClaimsIdentity(IdentityConstants.TwoFactorRememberMeScheme); id.AddClaim(new Claim(ClaimTypes.Name, user.Id)); - auth.Setup(a => a.AuthenticateAsync(context, manager.Object.Options.Cookies.TwoFactorRememberMeCookieAuthenticationScheme)) - .ReturnsAsync(AuthenticateResult.Success(new AuthenticationTicket(new ClaimsPrincipal(id), null, manager.Object.Options.Cookies.TwoFactorRememberMeCookieAuthenticationScheme))).Verifiable(); + auth.Setup(a => a.AuthenticateAsync(context, IdentityConstants.TwoFactorRememberMeScheme)) + .ReturnsAsync(AuthenticateResult.Success(new AuthenticationTicket(new ClaimsPrincipal(id), null, IdentityConstants.TwoFactorRememberMeScheme))).Verifiable(); var helper = SetupSignInManager(manager.Object, context); // Act @@ -669,19 +669,16 @@ namespace Microsoft.AspNetCore.Identity.Test return auth; } - [Theory] - [InlineData("Microsoft.AspNetCore.Identity.Authentication.Application")] - [InlineData("Foo")] - public async Task SignOutCallsContextResponseSignOut(string authenticationScheme) + [Fact] + public async Task SignOutCallsContextResponseSignOut() { // Setup var manager = MockHelpers.TestUserManager(); - manager.Options.Cookies.ApplicationCookieAuthenticationScheme = authenticationScheme; var context = new DefaultHttpContext(); var auth = MockAuth(context); - auth.Setup(a => a.SignOutAsync(context, authenticationScheme, It.IsAny())).Returns(Task.FromResult(0)).Verifiable(); - auth.Setup(a => a.SignOutAsync(context, manager.Options.Cookies.TwoFactorUserIdCookieAuthenticationScheme, It.IsAny())).Returns(Task.FromResult(0)).Verifiable(); - auth.Setup(a => a.SignOutAsync(context, manager.Options.Cookies.ExternalCookieAuthenticationScheme, It.IsAny())).Returns(Task.FromResult(0)).Verifiable(); + auth.Setup(a => a.SignOutAsync(context, IdentityConstants.ApplicationScheme, It.IsAny())).Returns(Task.FromResult(0)).Verifiable(); + auth.Setup(a => a.SignOutAsync(context, IdentityConstants.TwoFactorUserIdScheme, It.IsAny())).Returns(Task.FromResult(0)).Verifiable(); + auth.Setup(a => a.SignOutAsync(context, IdentityConstants.ExternalScheme, It.IsAny())).Returns(Task.FromResult(0)).Verifiable(); var helper = SetupSignInManager(manager, context, null, manager.Options); // Act @@ -828,7 +825,7 @@ namespace Microsoft.AspNetCore.Identity.Test private static void SetupSignIn(HttpContext context, Mock auth, string userId = null, bool? isPersistent = null, string loginProvider = null) { auth.Setup(a => a.SignInAsync(context, - new IdentityCookieOptions().ApplicationCookieAuthenticationScheme, + IdentityConstants.ApplicationScheme, It.Is(id => (userId == null || id.FindFirstValue(ClaimTypes.NameIdentifier) == userId) && (loginProvider == null || id.FindFirstValue(ClaimTypes.AuthenticationMethod) == loginProvider)), diff --git a/test/Microsoft.AspNetCore.Identity.Test/UserClaimsPrincipalFactoryTest.cs b/test/Microsoft.AspNetCore.Identity.Test/UserClaimsPrincipalFactoryTest.cs index 1dbb269c92..cbd8ba62d0 100644 --- a/test/Microsoft.AspNetCore.Identity.Test/UserClaimsPrincipalFactoryTest.cs +++ b/test/Microsoft.AspNetCore.Identity.Test/UserClaimsPrincipalFactoryTest.cs @@ -84,7 +84,7 @@ namespace Microsoft.AspNetCore.Identity.Test var manager = userManager.Object; Assert.NotNull(identity); Assert.Equal(1, principal.Identities.Count()); - Assert.Equal(identityOptions.Cookies.ApplicationCookieAuthenticationScheme, identity.AuthenticationType); + Assert.Equal(IdentityConstants.ApplicationScheme, identity.AuthenticationType); var claims = identity.Claims.ToList(); Assert.NotNull(claims); Assert.True( diff --git a/test/Microsoft.AspNetCore.Identity.Test/UserManagerTest.cs b/test/Microsoft.AspNetCore.Identity.Test/UserManagerTest.cs index 6370d397e5..92ff64558f 100644 --- a/test/Microsoft.AspNetCore.Identity.Test/UserManagerTest.cs +++ b/test/Microsoft.AspNetCore.Identity.Test/UserManagerTest.cs @@ -5,8 +5,6 @@ using System; using System.Collections.Generic; using System.Linq; using System.Security.Claims; -using System.Security.Cryptography; -using System.Text; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; @@ -31,7 +29,6 @@ namespace Microsoft.AspNetCore.Identity.Test services.AddLogging(); var manager = services.BuildServiceProvider().GetRequiredService>(); Assert.NotNull(manager.PasswordHasher); - Assert.NotNull(manager.Store); Assert.NotNull(manager.Options); } @@ -64,7 +61,7 @@ namespace Microsoft.AspNetCore.Identity.Test public class CustomRoleManager : RoleManager { - public CustomRoleManager() : base(new Mock>().Object, null, null, null, null, null) + public CustomRoleManager() : base(new Mock>().Object, null, null, null, null) { } } @@ -639,9 +636,9 @@ namespace Microsoft.AspNetCore.Identity.Test await Assert.ThrowsAsync(() => manager.UpdateSecurityStampAsync(null)); await Assert.ThrowsAsync(() => manager.GetSecurityStampAsync(null)); await Assert.ThrowsAsync( - () => manager.VerifyChangePhoneNumberTokenAsync(null, "1", "111-111-1111")); + () => manager.VerifyChangePhoneNumberTokenAsync(new TestUser(), "1", "111-111-1111")); await Assert.ThrowsAsync( - () => manager.GenerateChangePhoneNumberTokenAsync(null, "111-111-1111")); + () => manager.GenerateChangePhoneNumberTokenAsync(new TestUser(), "111-111-1111")); } [Fact] diff --git a/test/Shared/MockHelpers.cs b/test/Shared/MockHelpers.cs index ef612b2b72..1b563e1435 100644 --- a/test/Shared/MockHelpers.cs +++ b/test/Shared/MockHelpers.cs @@ -3,8 +3,8 @@ using System; using System.Collections.Generic; -using System.Threading.Tasks; using System.Text; +using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; @@ -30,7 +30,8 @@ namespace Microsoft.AspNetCore.Identity.Test store = store ?? new Mock>().Object; var roles = new List>(); roles.Add(new RoleValidator()); - return new Mock>(store, roles, null, null, null, null); + return new Mock>(store, roles, new UpperInvariantLookupNormalizer(), + new IdentityErrorDescriber(), null); } public static Mock> MockILogger(StringBuilder logStore = null) where T : class @@ -88,7 +89,7 @@ namespace Microsoft.AspNetCore.Identity.Test store = store ?? new Mock>().Object; var roles = new List>(); roles.Add(new RoleValidator()); - return new RoleManager(store, roles, + return new AspNetRoleManager(store, roles, new UpperInvariantLookupNormalizer(), new IdentityErrorDescriber(), null,