From 7ba61d6c6f6ce4eaee4c5018e71fa374d99bc868 Mon Sep 17 00:00:00 2001 From: Hao Kung Date: Thu, 4 Feb 2016 14:09:11 -0800 Subject: [PATCH] UserManager should normalize role name --- Identity.sln | 16 --- .../UserStore.cs | 48 +++---- .../RoleManager.cs | 4 +- .../UserManager.cs | 30 ++-- .../UserStoreTest.cs | 12 +- .../FunctionalTest.cs | 4 +- .../HttpSignInTest.cs | 4 +- .../InMemoryRoleStore.cs | 117 ---------------- ...{InMemoryUserStore.cs => InMemoryStore.cs} | 130 +++++++++++++++++- .../InMemoryStoreTest.cs | 6 +- test/Shared/UserManagerTestBase.cs | 1 + 11 files changed, 179 insertions(+), 193 deletions(-) delete mode 100644 test/Microsoft.AspNetCore.Identity.InMemory.Test/InMemoryRoleStore.cs rename test/Microsoft.AspNetCore.Identity.InMemory.Test/{InMemoryUserStore.cs => InMemoryStore.cs} (74%) diff --git a/Identity.sln b/Identity.sln index a257e646bd..1eac0bdf30 100644 --- a/Identity.sln +++ b/Identity.sln @@ -1,4 +1,3 @@ - Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 VisualStudioVersion = 14.0.23107.0 @@ -28,8 +27,6 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.Identi EndProject Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.AspNetCore.Identity.EntityFrameworkCore", "src\Microsoft.AspNetCore.Identity.EntityFrameworkCore\Microsoft.AspNetCore.Identity.EntityFrameworkCore.xproj", "{4490894C-3572-4E63-86F1-EE5105CE8A06}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Interop45", "samples\Interop45\Interop45.csproj", "{9A46D74F-8347-4821-A888-8DA0844443EF}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -110,18 +107,6 @@ Global {4490894C-3572-4E63-86F1-EE5105CE8A06}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {4490894C-3572-4E63-86F1-EE5105CE8A06}.Release|Mixed Platforms.Build.0 = Release|Any CPU {4490894C-3572-4E63-86F1-EE5105CE8A06}.Release|x86.ActiveCfg = Release|Any CPU - {9A46D74F-8347-4821-A888-8DA0844443EF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {9A46D74F-8347-4821-A888-8DA0844443EF}.Debug|Any CPU.Build.0 = Debug|Any CPU - {9A46D74F-8347-4821-A888-8DA0844443EF}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {9A46D74F-8347-4821-A888-8DA0844443EF}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {9A46D74F-8347-4821-A888-8DA0844443EF}.Debug|x86.ActiveCfg = Debug|Any CPU - {9A46D74F-8347-4821-A888-8DA0844443EF}.Debug|x86.Build.0 = Debug|Any CPU - {9A46D74F-8347-4821-A888-8DA0844443EF}.Release|Any CPU.ActiveCfg = Release|Any CPU - {9A46D74F-8347-4821-A888-8DA0844443EF}.Release|Any CPU.Build.0 = Release|Any CPU - {9A46D74F-8347-4821-A888-8DA0844443EF}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {9A46D74F-8347-4821-A888-8DA0844443EF}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {9A46D74F-8347-4821-A888-8DA0844443EF}.Release|x86.ActiveCfg = Release|Any CPU - {9A46D74F-8347-4821-A888-8DA0844443EF}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -134,6 +119,5 @@ Global {37236EA3-915D-46D5-997C-DF513C500E4B} = {52D59F18-62D2-4D17-8CF2-BE192445AF8E} {EA7EB28F-53B8-4009-9C6B-74DB090CA8DD} = {52D59F18-62D2-4D17-8CF2-BE192445AF8E} {4490894C-3572-4E63-86F1-EE5105CE8A06} = {0F647068-6602-4E24-B1DC-8ED91481A50A} - {9A46D74F-8347-4821-A888-8DA0844443EF} = {58D94A0E-C2B7-43A7-8826-99ECBB1E0A50} EndGlobalSection EndGlobal diff --git a/src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/UserStore.cs b/src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/UserStore.cs index 814938f1cf..8d01f2131c 100644 --- a/src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/UserStore.cs +++ b/src/Microsoft.AspNetCore.Identity.EntityFrameworkCore/UserStore.cs @@ -394,13 +394,13 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore } /// - /// Adds the given to the specified . + /// Adds the given to the specified . /// /// The user to add the role to. - /// The role to add. + /// 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 roleName, CancellationToken cancellationToken = default(CancellationToken)) + public async virtual Task AddToRoleAsync(TUser user, string normalizedRoleName, CancellationToken cancellationToken = default(CancellationToken)) { cancellationToken.ThrowIfCancellationRequested(); ThrowIfDisposed(); @@ -408,27 +408,27 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore { throw new ArgumentNullException(nameof(user)); } - if (string.IsNullOrWhiteSpace(roleName)) + if (string.IsNullOrWhiteSpace(normalizedRoleName)) { - throw new ArgumentException(Resources.ValueCannotBeNullOrEmpty, nameof(roleName)); + throw new ArgumentException(Resources.ValueCannotBeNullOrEmpty, nameof(normalizedRoleName)); } - var roleEntity = await Roles.SingleOrDefaultAsync(r => r.Name.ToUpper() == roleName.ToUpper(), cancellationToken); + var roleEntity = await Roles.SingleOrDefaultAsync(r => r.NormalizedName == normalizedRoleName, cancellationToken); if (roleEntity == null) { - throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, Resources.RoleNotFound, roleName)); + throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, Resources.RoleNotFound, normalizedRoleName)); } var ur = new IdentityUserRole { UserId = user.Id, RoleId = roleEntity.Id }; UserRoles.Add(ur); } /// - /// Removes the given from the specified . + /// Removes the given from the specified . /// /// The user to remove the role from. - /// The role to remove. + /// 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 roleName, CancellationToken cancellationToken = default(CancellationToken)) + public async virtual Task RemoveFromRoleAsync(TUser user, string normalizedRoleName, CancellationToken cancellationToken = default(CancellationToken)) { cancellationToken.ThrowIfCancellationRequested(); ThrowIfDisposed(); @@ -436,11 +436,11 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore { throw new ArgumentNullException(nameof(user)); } - if (string.IsNullOrWhiteSpace(roleName)) + if (string.IsNullOrWhiteSpace(normalizedRoleName)) { - throw new ArgumentException(Resources.ValueCannotBeNullOrEmpty, nameof(roleName)); + throw new ArgumentException(Resources.ValueCannotBeNullOrEmpty, nameof(normalizedRoleName)); } - var roleEntity = await Roles.SingleOrDefaultAsync(r => r.Name.ToUpper() == roleName.ToUpper(), cancellationToken); + var roleEntity = await Roles.SingleOrDefaultAsync(r => r.NormalizedName == normalizedRoleName, cancellationToken); if (roleEntity != null) { var userRole = await UserRoles.FirstOrDefaultAsync(r => roleEntity.Id.Equals(r.RoleId) && r.UserId.Equals(user.Id), cancellationToken); @@ -474,14 +474,14 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore } /// - /// Returns a flag indicating if the specified user is a member of the give . + /// 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 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 virtual async Task IsInRoleAsync(TUser user, string roleName, CancellationToken cancellationToken = default(CancellationToken)) + public virtual async Task IsInRoleAsync(TUser user, string normalizedRoleName, CancellationToken cancellationToken = default(CancellationToken)) { cancellationToken.ThrowIfCancellationRequested(); ThrowIfDisposed(); @@ -489,11 +489,11 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore { throw new ArgumentNullException(nameof(user)); } - if (string.IsNullOrWhiteSpace(roleName)) + if (string.IsNullOrWhiteSpace(normalizedRoleName)) { - throw new ArgumentException(Resources.ValueCannotBeNullOrEmpty, nameof(roleName)); + throw new ArgumentException(Resources.ValueCannotBeNullOrEmpty, nameof(normalizedRoleName)); } - var role = await Roles.SingleOrDefaultAsync(r => r.Name.ToUpper() == roleName.ToUpper(), cancellationToken); + var role = await Roles.SingleOrDefaultAsync(r => r.NormalizedName == normalizedRoleName, cancellationToken); if (role != null) { var userId = user.Id; @@ -1168,21 +1168,21 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore /// /// Retrieves all users in the specified role. /// - /// The role whose users should be retrieved. + /// 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 async virtual Task> GetUsersInRoleAsync(string roleName, CancellationToken cancellationToken = default(CancellationToken)) + public async virtual Task> GetUsersInRoleAsync(string normalizedRoleName, CancellationToken cancellationToken = default(CancellationToken)) { cancellationToken.ThrowIfCancellationRequested(); ThrowIfDisposed(); - if (String.IsNullOrEmpty(roleName)) + if (String.IsNullOrEmpty(normalizedRoleName)) { - throw new ArgumentNullException(nameof(roleName)); + throw new ArgumentNullException(nameof(normalizedRoleName)); } - var role = await Roles.Where(x => x.Name.Equals(roleName)).FirstOrDefaultAsync(cancellationToken); + var role = await Roles.Where(x => x.NormalizedName == normalizedRoleName).FirstOrDefaultAsync(cancellationToken); if (role != null) { diff --git a/src/Microsoft.AspNetCore.Identity/RoleManager.cs b/src/Microsoft.AspNetCore.Identity/RoleManager.cs index 6080356f06..430e0d4f29 100644 --- a/src/Microsoft.AspNetCore.Identity/RoleManager.cs +++ b/src/Microsoft.AspNetCore.Identity/RoleManager.cs @@ -4,11 +4,9 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Runtime.CompilerServices; using System.Security.Claims; using System.Threading; using System.Threading.Tasks; -using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; @@ -17,7 +15,7 @@ namespace Microsoft.AspNetCore.Identity /// /// Provides the APIs for managing roles in a persistence store. /// - /// The type encapsulating a role. + /// The type encapsulating a role. public class RoleManager : IDisposable where TRole : class { private bool _disposed; diff --git a/src/Microsoft.AspNetCore.Identity/UserManager.cs b/src/Microsoft.AspNetCore.Identity/UserManager.cs index 8e05b8e09f..acd61b2b21 100644 --- a/src/Microsoft.AspNetCore.Identity/UserManager.cs +++ b/src/Microsoft.AspNetCore.Identity/UserManager.cs @@ -434,9 +434,9 @@ namespace Microsoft.AspNetCore.Identity } /// - /// Finds and returns a user, if any, who has the specified normalized user name. + /// Finds and returns a user, if any, who has the specified user name. /// - /// The normalized user name to search for. + /// The 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. @@ -1038,7 +1038,7 @@ namespace Microsoft.AspNetCore.Identity /// /// Gets a list of s to be belonging to the specified as an asynchronous operation. /// - /// The role whose claims to retrieve. + /// The user whose claims to retrieve. /// /// A that represents the result of the asynchronous query, a list of s. /// @@ -1071,11 +1071,12 @@ namespace Microsoft.AspNetCore.Identity throw new ArgumentNullException("user"); } - if (await userRoleStore.IsInRoleAsync(user, role, CancellationToken)) + var normalizedRole = NormalizeKey(role); + if (await userRoleStore.IsInRoleAsync(user, normalizedRole, CancellationToken)) { return await UserAlreadyInRoleError(user, role); } - await userRoleStore.AddToRoleAsync(user, role, CancellationToken); + await userRoleStore.AddToRoleAsync(user, normalizedRole, CancellationToken); return await UpdateUserAsync(user); } @@ -1103,11 +1104,12 @@ namespace Microsoft.AspNetCore.Identity foreach (var role in roles.Distinct()) { - if (await userRoleStore.IsInRoleAsync(user, role, CancellationToken)) + var normalizedRole = NormalizeKey(role); + if (await userRoleStore.IsInRoleAsync(user, normalizedRole, CancellationToken)) { return await UserAlreadyInRoleError(user, role); } - await userRoleStore.AddToRoleAsync(user, role, CancellationToken); + await userRoleStore.AddToRoleAsync(user, normalizedRole, CancellationToken); } return await UpdateUserAsync(user); } @@ -1130,11 +1132,12 @@ namespace Microsoft.AspNetCore.Identity throw new ArgumentNullException("user"); } - if (!await userRoleStore.IsInRoleAsync(user, role, CancellationToken)) + var normalizedRole = NormalizeKey(role); + if (!await userRoleStore.IsInRoleAsync(user, normalizedRole, CancellationToken)) { return await UserNotInRoleError(user, role); } - await userRoleStore.RemoveFromRoleAsync(user, role, CancellationToken); + await userRoleStore.RemoveFromRoleAsync(user, normalizedRole, CancellationToken); return await UpdateUserAsync(user); } @@ -1174,11 +1177,12 @@ namespace Microsoft.AspNetCore.Identity foreach (var role in roles) { - if (!await userRoleStore.IsInRoleAsync(user, role, CancellationToken)) + var normalizedRole = NormalizeKey(role); + if (!await userRoleStore.IsInRoleAsync(user, normalizedRole, CancellationToken)) { return await UserNotInRoleError(user, role); } - await userRoleStore.RemoveFromRoleAsync(user, role, CancellationToken); + await userRoleStore.RemoveFromRoleAsync(user, normalizedRole, CancellationToken); } return await UpdateUserAsync(user); } @@ -1216,7 +1220,7 @@ namespace Microsoft.AspNetCore.Identity { throw new ArgumentNullException("user"); } - return await userRoleStore.IsInRoleAsync(user, role, CancellationToken); + return await userRoleStore.IsInRoleAsync(user, NormalizeKey(role), CancellationToken); } /// @@ -1950,7 +1954,7 @@ namespace Microsoft.AspNetCore.Identity throw new ArgumentNullException("role"); } - return store.GetUsersInRoleAsync(roleName, CancellationToken); + return store.GetUsersInRoleAsync(NormalizeKey(roleName), CancellationToken); } /// diff --git a/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/UserStoreTest.cs b/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/UserStoreTest.cs index 434c4a0234..adcfe3cac8 100644 --- a/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/UserStoreTest.cs +++ b/test/Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test/UserStoreTest.cs @@ -172,12 +172,12 @@ namespace Microsoft.AspNetCore.Identity.EntityFrameworkCore.Test await Assert.ThrowsAsync("user", async () => await store.SetLockoutEndDateAsync(null, new DateTimeOffset())); await Assert.ThrowsAsync("user", async () => await store.ResetAccessFailedCountAsync(null)); await Assert.ThrowsAsync("user", async () => await store.IncrementAccessFailedCountAsync(null)); - await Assert.ThrowsAsync("roleName", async () => await store.AddToRoleAsync(new IdentityUser("fake"), null)); - await Assert.ThrowsAsync("roleName", async () => await store.RemoveFromRoleAsync(new IdentityUser("fake"), null)); - await Assert.ThrowsAsync("roleName", async () => await store.IsInRoleAsync(new IdentityUser("fake"), null)); - await Assert.ThrowsAsync("roleName", async () => await store.AddToRoleAsync(new IdentityUser("fake"), "")); - await Assert.ThrowsAsync("roleName", async () => await store.RemoveFromRoleAsync(new IdentityUser("fake"), "")); - await Assert.ThrowsAsync("roleName", async () => await store.IsInRoleAsync(new IdentityUser("fake"), "")); + await Assert.ThrowsAsync("normalizedRoleName", async () => await store.AddToRoleAsync(new IdentityUser("fake"), null)); + await Assert.ThrowsAsync("normalizedRoleName", async () => await store.RemoveFromRoleAsync(new IdentityUser("fake"), null)); + await Assert.ThrowsAsync("normalizedRoleName", async () => await store.IsInRoleAsync(new IdentityUser("fake"), null)); + await Assert.ThrowsAsync("normalizedRoleName", async () => await store.AddToRoleAsync(new IdentityUser("fake"), "")); + await Assert.ThrowsAsync("normalizedRoleName", async () => await store.RemoveFromRoleAsync(new IdentityUser("fake"), "")); + await Assert.ThrowsAsync("normalizedRoleName", async () => await store.IsInRoleAsync(new IdentityUser("fake"), "")); } [ConditionalFact] diff --git a/test/Microsoft.AspNetCore.Identity.InMemory.Test/FunctionalTest.cs b/test/Microsoft.AspNetCore.Identity.InMemory.Test/FunctionalTest.cs index 89f8dd1088..3653453092 100644 --- a/test/Microsoft.AspNetCore.Identity.InMemory.Test/FunctionalTest.cs +++ b/test/Microsoft.AspNetCore.Identity.InMemory.Test/FunctionalTest.cs @@ -257,8 +257,8 @@ namespace Microsoft.AspNetCore.Identity.InMemory .ConfigureServices(services => { services.AddIdentity(); - services.AddSingleton, InMemoryUserStore>(); - services.AddSingleton, InMemoryRoleStore>(); + services.AddSingleton, InMemoryStore>(); + services.AddSingleton, InMemoryStore>(); if (configureServices != null) { configureServices(services); diff --git a/test/Microsoft.AspNetCore.Identity.InMemory.Test/HttpSignInTest.cs b/test/Microsoft.AspNetCore.Identity.InMemory.Test/HttpSignInTest.cs index 8db0d32964..1ca48f21a3 100644 --- a/test/Microsoft.AspNetCore.Identity.InMemory.Test/HttpSignInTest.cs +++ b/test/Microsoft.AspNetCore.Identity.InMemory.Test/HttpSignInTest.cs @@ -37,8 +37,8 @@ namespace Microsoft.AspNetCore.Identity.InMemory.Test services.AddLogging(); services.AddSingleton(contextAccessor.Object); services.AddIdentity(); - services.AddSingleton, InMemoryUserStore>(); - services.AddSingleton, InMemoryRoleStore>(); + services.AddSingleton, InMemoryStore>(); + services.AddSingleton, InMemoryStore>(); var app = new ApplicationBuilder(services.BuildServiceProvider()); app.UseCookieAuthentication(); diff --git a/test/Microsoft.AspNetCore.Identity.InMemory.Test/InMemoryRoleStore.cs b/test/Microsoft.AspNetCore.Identity.InMemory.Test/InMemoryRoleStore.cs deleted file mode 100644 index 976840f550..0000000000 --- a/test/Microsoft.AspNetCore.Identity.InMemory.Test/InMemoryRoleStore.cs +++ /dev/null @@ -1,117 +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 System.Collections.Generic; -using System.Linq; -using System.Security.Claims; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.AspNetCore.Identity.Test; - -namespace Microsoft.AspNetCore.Identity.InMemory -{ - public class InMemoryRoleStore : IQueryableRoleStore, IRoleClaimStore where TRole : TestRole - - { - private readonly Dictionary _roles = new Dictionary(); - - public Task CreateAsync(TRole role, CancellationToken cancellationToken = default(CancellationToken)) - { - _roles[role.Id] = role; - return Task.FromResult(IdentityResult.Success); - } - - public Task DeleteAsync(TRole role, CancellationToken cancellationToken = default(CancellationToken)) - { - if (role == null || !_roles.ContainsKey(role.Id)) - { - throw new InvalidOperationException("Unknown role"); - } - _roles.Remove(role.Id); - return Task.FromResult(IdentityResult.Success); - } - - public Task GetRoleIdAsync(TRole role, CancellationToken cancellationToken = default(CancellationToken)) - { - return Task.FromResult(role.Id); - } - - public Task GetRoleNameAsync(TRole role, CancellationToken cancellationToken = default(CancellationToken)) - { - return Task.FromResult(role.Name); - } - - public Task SetRoleNameAsync(TRole role, string roleName, CancellationToken cancellationToken = default(CancellationToken)) - { - role.Name = roleName; - return Task.FromResult(0); - } - - public Task UpdateAsync(TRole role, CancellationToken cancellationToken = default(CancellationToken)) - { - _roles[role.Id] = role; - return Task.FromResult(IdentityResult.Success); - } - - public Task FindByIdAsync(string roleId, CancellationToken cancellationToken = default(CancellationToken)) - { - if (_roles.ContainsKey(roleId)) - { - return Task.FromResult(_roles[roleId]); - } - return Task.FromResult(null); - } - - public Task FindByNameAsync(string roleName, CancellationToken cancellationToken = default(CancellationToken)) - { - return - Task.FromResult( - Roles.SingleOrDefault(r => String.Equals(r.Name, roleName, StringComparison.OrdinalIgnoreCase))); - } - - public void Dispose() - { - } - - public Task> GetClaimsAsync(TRole role, CancellationToken cancellationToken = default(CancellationToken)) - { - var claims = role.Claims.Select(c => new Claim(c.ClaimType, c.ClaimValue)).ToList(); - return Task.FromResult>(claims); - } - - public Task AddClaimAsync(TRole role, Claim claim, CancellationToken cancellationToken = default(CancellationToken)) - { - role.Claims.Add(new TestRoleClaim { ClaimType = claim.Type, ClaimValue = claim.Value, RoleId = role.Id }); - return Task.FromResult(0); - } - - public Task RemoveClaimAsync(TRole role, Claim claim, CancellationToken cancellationToken = default(CancellationToken)) - { - var entity = - role.Claims.FirstOrDefault( - ur => ur.RoleId == role.Id && ur.ClaimType == claim.Type && ur.ClaimValue == claim.Value); - if (entity != null) - { - role.Claims.Remove(entity); - } - return Task.FromResult(0); - } - - public Task GetNormalizedRoleNameAsync(TRole role, CancellationToken cancellationToken = default(CancellationToken)) - { - return Task.FromResult(role.NormalizedName); - } - - public Task SetNormalizedRoleNameAsync(TRole role, string normalizedName, CancellationToken cancellationToken = default(CancellationToken)) - { - role.NormalizedName = normalizedName; - return Task.FromResult(0); - } - - public IQueryable Roles - { - get { return _roles.Values.AsQueryable(); } - } - } -} \ No newline at end of file diff --git a/test/Microsoft.AspNetCore.Identity.InMemory.Test/InMemoryUserStore.cs b/test/Microsoft.AspNetCore.Identity.InMemory.Test/InMemoryStore.cs similarity index 74% rename from test/Microsoft.AspNetCore.Identity.InMemory.Test/InMemoryUserStore.cs rename to test/Microsoft.AspNetCore.Identity.InMemory.Test/InMemoryStore.cs index c8998f17d0..c555fe9ad2 100644 --- a/test/Microsoft.AspNetCore.Identity.InMemory.Test/InMemoryUserStore.cs +++ b/test/Microsoft.AspNetCore.Identity.InMemory.Test/InMemoryStore.cs @@ -11,7 +11,7 @@ using Microsoft.AspNetCore.Identity.Test; namespace Microsoft.AspNetCore.Identity.InMemory { - public class InMemoryUserStore : + public class InMemoryStore : IUserLoginStore, IUserRoleStore, IUserClaimStore, @@ -21,7 +21,10 @@ namespace Microsoft.AspNetCore.Identity.InMemory IUserLockoutStore, IUserPhoneNumberStore, IQueryableUserStore, - IUserTwoFactorStore + IUserTwoFactorStore, + IQueryableRoleStore, + IRoleClaimStore + where TRole : TestRole where TUser : TestUser { private readonly Dictionary _logins = new Dictionary(); @@ -305,14 +308,19 @@ namespace Microsoft.AspNetCore.Identity.InMemory // RoleId == roleName for InMemory public Task AddToRoleAsync(TUser user, string role, CancellationToken cancellationToken = default(CancellationToken)) { - user.Roles.Add(new TestUserRole { RoleId = role, UserId = user.Id }); + var roleEntity = _roles.Values.SingleOrDefault(r => r.NormalizedName == role); + if (roleEntity != null) + { + user.Roles.Add(new TestUserRole { RoleId = roleEntity.Id, UserId = user.Id }); + } return Task.FromResult(0); } // RoleId == roleName for InMemory public Task RemoveFromRoleAsync(TUser user, string role, CancellationToken cancellationToken = default(CancellationToken)) { - var roleEntity = user.Roles.SingleOrDefault(ur => ur.RoleId == role); + var roleObject = _roles.Values.SingleOrDefault(r => r.NormalizedName == role); + var roleEntity = user.Roles.SingleOrDefault(ur => ur.RoleId == roleObject.Id); if (roleEntity != null) { user.Roles.Remove(roleEntity); @@ -322,12 +330,19 @@ namespace Microsoft.AspNetCore.Identity.InMemory public Task> GetRolesAsync(TUser user, CancellationToken cancellationToken = default(CancellationToken)) { - return Task.FromResult>(user.Roles.Select(ur => ur.RoleId).ToList()); + IList roles = new List(); + foreach (var r in user.Roles.Select(ur => ur.RoleId)) + { + roles.Add(_roles[r].Name); + } + return Task.FromResult(roles); } public Task IsInRoleAsync(TUser user, string role, CancellationToken cancellationToken = default(CancellationToken)) { - return Task.FromResult(user.Roles.Any(ur => ur.RoleId == role)); + var roleObject = _roles.Values.SingleOrDefault(r => r.NormalizedName == role); + bool result = roleObject != null && user.Roles.Any(ur => ur.RoleId == roleObject.Id); + return Task.FromResult(result); } public Task SetSecurityStampAsync(TUser user, string stamp, CancellationToken cancellationToken = default(CancellationToken)) @@ -371,7 +386,12 @@ namespace Microsoft.AspNetCore.Identity.InMemory throw new ArgumentNullException(nameof(roleName)); } - return Task.FromResult>(Users.Where(u => (u.Roles.Where(x => x.RoleId == roleName).Count() > 0)).Select(x => x).ToList()); + var role = _roles.Values.Where(x => x.NormalizedName.Equals(roleName)).SingleOrDefault(); + if (role == null) + { + return Task.FromResult>(new List()); + } + return Task.FromResult>(Users.Where(u => (u.Roles.Where(x => x.RoleId == role.Id).Count() > 0)).Select(x => x).ToList()); } public Task> GetUsersForClaimAsync(Claim claim, CancellationToken cancellationToken = default(CancellationToken)) @@ -387,5 +407,101 @@ namespace Microsoft.AspNetCore.Identity.InMemory return Task.FromResult>(query.ToList()); } + + private readonly Dictionary _roles = new Dictionary(); + + public Task CreateAsync(TRole role, CancellationToken cancellationToken = default(CancellationToken)) + { + _roles[role.Id] = role; + return Task.FromResult(IdentityResult.Success); + } + + public Task DeleteAsync(TRole role, CancellationToken cancellationToken = default(CancellationToken)) + { + if (role == null || !_roles.ContainsKey(role.Id)) + { + throw new InvalidOperationException("Unknown role"); + } + _roles.Remove(role.Id); + return Task.FromResult(IdentityResult.Success); + } + + public Task GetRoleIdAsync(TRole role, CancellationToken cancellationToken = default(CancellationToken)) + { + return Task.FromResult(role.Id); + } + + public Task GetRoleNameAsync(TRole role, CancellationToken cancellationToken = default(CancellationToken)) + { + return Task.FromResult(role.Name); + } + + public Task SetRoleNameAsync(TRole role, string roleName, CancellationToken cancellationToken = default(CancellationToken)) + { + role.Name = roleName; + return Task.FromResult(0); + } + + public Task UpdateAsync(TRole role, CancellationToken cancellationToken = default(CancellationToken)) + { + _roles[role.Id] = role; + return Task.FromResult(IdentityResult.Success); + } + + Task IRoleStore.FindByIdAsync(string roleId, CancellationToken cancellationToken) + { + if (_roles.ContainsKey(roleId)) + { + return Task.FromResult(_roles[roleId]); + } + return Task.FromResult(null); + } + + Task IRoleStore.FindByNameAsync(string roleName, CancellationToken cancellationToken) + { + return + Task.FromResult( + Roles.SingleOrDefault(r => String.Equals(r.NormalizedName, roleName, StringComparison.OrdinalIgnoreCase))); + } + + public Task> GetClaimsAsync(TRole role, CancellationToken cancellationToken = default(CancellationToken)) + { + var claims = role.Claims.Select(c => new Claim(c.ClaimType, c.ClaimValue)).ToList(); + return Task.FromResult>(claims); + } + + public Task AddClaimAsync(TRole role, Claim claim, CancellationToken cancellationToken = default(CancellationToken)) + { + role.Claims.Add(new TestRoleClaim { ClaimType = claim.Type, ClaimValue = claim.Value, RoleId = role.Id }); + return Task.FromResult(0); + } + + public Task RemoveClaimAsync(TRole role, Claim claim, CancellationToken cancellationToken = default(CancellationToken)) + { + var entity = + role.Claims.FirstOrDefault( + ur => ur.RoleId == role.Id && ur.ClaimType == claim.Type && ur.ClaimValue == claim.Value); + if (entity != null) + { + role.Claims.Remove(entity); + } + return Task.FromResult(0); + } + + public Task GetNormalizedRoleNameAsync(TRole role, CancellationToken cancellationToken = default(CancellationToken)) + { + return Task.FromResult(role.NormalizedName); + } + + public Task SetNormalizedRoleNameAsync(TRole role, string normalizedName, CancellationToken cancellationToken = default(CancellationToken)) + { + role.NormalizedName = normalizedName; + return Task.FromResult(0); + } + + public IQueryable Roles + { + get { return _roles.Values.AsQueryable(); } + } } } diff --git a/test/Microsoft.AspNetCore.Identity.InMemory.Test/InMemoryStoreTest.cs b/test/Microsoft.AspNetCore.Identity.InMemory.Test/InMemoryStoreTest.cs index aa0694fe31..83384bd4aa 100644 --- a/test/Microsoft.AspNetCore.Identity.InMemory.Test/InMemoryStoreTest.cs +++ b/test/Microsoft.AspNetCore.Identity.InMemory.Test/InMemoryStoreTest.cs @@ -12,17 +12,17 @@ namespace Microsoft.AspNetCore.Identity.InMemory.Test { protected override object CreateTestContext() { - return null; + return new InMemoryStore(); } protected override void AddUserStore(IServiceCollection services, object context = null) { - services.AddSingleton, InMemoryUserStore>(); + services.AddSingleton>((InMemoryStore)context); } protected override void AddRoleStore(IServiceCollection services, object context = null) { - services.AddSingleton, InMemoryRoleStore>(); + services.AddSingleton>((InMemoryStore)context); } protected override void SetUserPasswordHash(TestUser user, string hashedPassword) diff --git a/test/Shared/UserManagerTestBase.cs b/test/Shared/UserManagerTestBase.cs index c7ffff5ebb..11ff6e88df 100644 --- a/test/Shared/UserManagerTestBase.cs +++ b/test/Shared/UserManagerTestBase.cs @@ -1467,6 +1467,7 @@ namespace Microsoft.AspNetCore.Identity.Test { return; } + var context = CreateTestContext(); var userManager = CreateManager(context); var roleManager = CreateRoleManager(context);