From 696861065cfaf3b91b46acab0d6f03ed3eb27b56 Mon Sep 17 00:00:00 2001 From: Alper Ebicoglu Date: Tue, 9 Jan 2018 17:23:29 +0300 Subject: [PATCH] added IdentityResourceStore --- .../AbpIdentityServerDomainModule.cs | 4 +- .../ApiResources/ApiResources.cs | 23 +++++ .../IIdentityResourceRepository.cs | 18 ++++ .../IdentityResourceStore.cs | 50 ++++++++++ .../IdentityResourceRepository.cs | 76 +++++++++++++++ .../AbpIdentityServerTestDataBuilder.cs | 28 +++++- .../Clients/IdentityResourceStore_Tests.cs | 92 +++++++++++++++++++ 7 files changed, 288 insertions(+), 3 deletions(-) create mode 100644 src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/ApiResources/ApiResources.cs create mode 100644 src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/IdentityResources/IIdentityResourceRepository.cs create mode 100644 src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/IdentityResources/IdentityResourceStore.cs create mode 100644 src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/IdentityResourceRepository.cs create mode 100644 test/Abp.IdentityServer.EntityFrameworkCore.Tests/Volo/Abp/IdentityServer/Clients/IdentityResourceStore_Tests.cs diff --git a/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AbpIdentityServerDomainModule.cs b/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AbpIdentityServerDomainModule.cs index 012282784f..884979ade4 100644 --- a/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AbpIdentityServerDomainModule.cs +++ b/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AbpIdentityServerDomainModule.cs @@ -33,8 +33,8 @@ namespace Volo.Abp.IdentityServer //TODO: Remove in-memory stores once EF Core stores are fully completed. identityServerBuilder.AddDeveloperSigningCredential() - .AddInMemoryClients(IdentityServerConfig.GetClients()) - .AddInMemoryApiResources(IdentityServerConfig.GetApiResources()) + //.AddInMemoryClients(IdentityServerConfig.GetClients()) + //.AddInMemoryApiResources(IdentityServerConfig.GetApiResources()) .AddAbpIdentityServer(); services.ExecutePreConfiguredActions(identityServerBuilder); diff --git a/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/ApiResources/ApiResources.cs b/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/ApiResources/ApiResources.cs new file mode 100644 index 0000000000..b3fc51ddc0 --- /dev/null +++ b/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/ApiResources/ApiResources.cs @@ -0,0 +1,23 @@ +using System.Threading.Tasks; +using Volo.Abp.IdentityServer.IdentityResources; + +namespace Volo.Abp.IdentityServer.ApiResources +{ + public class ApiResources + { + public Task Resources { get; set; } + + public Task IdentityResources { get; set; } + + public ApiResources() + { + + } + + public ApiResources(Task resources, Task identityResources) + { + Resources = resources; + IdentityResources = identityResources; + } + } +} \ No newline at end of file diff --git a/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/IdentityResources/IIdentityResourceRepository.cs b/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/IdentityResources/IIdentityResourceRepository.cs new file mode 100644 index 0000000000..277e917375 --- /dev/null +++ b/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/IdentityResources/IIdentityResourceRepository.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Volo.Abp.Domain.Repositories; +using ApiResource = Volo.Abp.IdentityServer.ApiResources.ApiResource; + +namespace Volo.Abp.IdentityServer.IdentityResources +{ + public interface IIdentityResourceRepository : IRepository + { + Task> FindIdentityResourcesByScopeAsync(string[] scopeNames); + + Task> FindApiResourcesByScopeAsync(string[] scopeNames); + + Task FindApiResourceAsync(string name); + + Task GetAllResourcesAsync(); + } +} \ No newline at end of file diff --git a/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/IdentityResources/IdentityResourceStore.cs b/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/IdentityResources/IdentityResourceStore.cs new file mode 100644 index 0000000000..e1f15844b8 --- /dev/null +++ b/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/IdentityResources/IdentityResourceStore.cs @@ -0,0 +1,50 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using IdentityServer4.Models; +using IdentityServer4.Stores; +using Volo.Abp.DependencyInjection; +using Volo.Abp.ObjectMapping; + +namespace Volo.Abp.IdentityServer.IdentityResources +{ + public class IdentityResourceStore : IResourceStore, ITransientDependency + { + private readonly IIdentityResourceRepository _identityResourceRepository; + private readonly IObjectMapper _objectMapper; + + public IdentityResourceStore(IIdentityResourceRepository identityResourceRepository, IObjectMapper objectMapper) + { + _identityResourceRepository = identityResourceRepository; + _objectMapper = objectMapper; + } + + public virtual async Task> FindIdentityResourcesByScopeAsync(IEnumerable scopeNames) + { + var results = await _identityResourceRepository.FindIdentityResourcesByScopeAsync(scopeNames.ToArray()); + return _objectMapper.Map, List>(results); + } + + public virtual async Task> FindApiResourcesByScopeAsync(IEnumerable scopeNames) + { + var results = await _identityResourceRepository.FindApiResourcesByScopeAsync(scopeNames.ToArray()); + return results?.Select(x => _objectMapper.Map(x)); + } + + public virtual async Task FindApiResourceAsync(string name) + { + var result = await _identityResourceRepository.FindApiResourceAsync(name); + return _objectMapper.Map(result); + } + + public virtual async Task GetAllResourcesAsync() + { + var result = await _identityResourceRepository.GetAllResourcesAsync(); + return new Resources + ( + result.Resources.Result.Select(y => _objectMapper.Map(y)), + result.IdentityResources.Result.Select(x => _objectMapper.Map(x)) + ); + } + } +} diff --git a/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/IdentityResourceRepository.cs b/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/IdentityResourceRepository.cs new file mode 100644 index 0000000000..91326dd523 --- /dev/null +++ b/src/Volo.Abp.IdentityServer.EntityFrameworkCore/Volo/Abp/IdentityServer/IdentityResourceRepository.cs @@ -0,0 +1,76 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; +using Volo.Abp.Domain.Repositories.EntityFrameworkCore; +using Volo.Abp.EntityFrameworkCore; +using Volo.Abp.IdentityServer.EntityFrameworkCore; +using Volo.Abp.IdentityServer.IdentityResources; +using ApiResource = Volo.Abp.IdentityServer.ApiResources.ApiResource; +using IdentityResource = Volo.Abp.IdentityServer.IdentityResources.IdentityResource; + +namespace Volo.Abp.IdentityServer +{ + public class IdentityResourceRepository : EfCoreRepository, IIdentityResourceRepository + { + public IdentityResourceRepository(IDbContextProvider dbContextProvider) : base(dbContextProvider) + { + + } + + public Task> FindIdentityResourcesByScopeAsync(string[] scopeNames) + { + var query = from identityResource in DbSet.Include(x => x.UserClaims) + where scopeNames.Contains(identityResource.Name) + select identityResource; + + return query.ToListAsync(); + } + + public Task> FindApiResourcesByScopeAsync(string[] scopeNames) + { + var names = scopeNames.ToArray(); + + var query = from api in DbContext.ApiResources + where api.Scopes.Any(x => names.Contains(x.Name)) + select api; + + var apis = query + .Include(x => x.Secrets) + .Include(x => x.Scopes) + .ThenInclude(s => s.UserClaims) + .Include(x => x.UserClaims); + + return apis.ToListAsync(); + } + + public Task FindApiResourceAsync(string name) + { + var query = from apiResource in DbContext.ApiResources + where apiResource.Name == name + select apiResource; + + var apis = query + .Include(x => x.Secrets) + .Include(x => x.Scopes) + .ThenInclude(s => s.UserClaims) + .Include(x => x.UserClaims); + + return apis.FirstOrDefaultAsync(); + } + + public Task GetAllResourcesAsync() + { + var identity = DbContext.IdentityResources + .Include(x => x.UserClaims); + + var apis = DbContext.ApiResources + .Include(x => x.Secrets) + .Include(x => x.Scopes) + .ThenInclude(s => s.UserClaims) + .Include(x => x.UserClaims); + + return Task.FromResult(new ApiResources.ApiResources(identity.ToArrayAsync(), apis.ToArrayAsync())); + } + } +} diff --git a/test/Abp.IdentityServer.EntityFrameworkCore.Tests/Volo/Abp/IdentityServer/AbpIdentityServerTestDataBuilder.cs b/test/Abp.IdentityServer.EntityFrameworkCore.Tests/Volo/Abp/IdentityServer/AbpIdentityServerTestDataBuilder.cs index b3f1fa420b..acdfa56255 100644 --- a/test/Abp.IdentityServer.EntityFrameworkCore.Tests/Volo/Abp/IdentityServer/AbpIdentityServerTestDataBuilder.cs +++ b/test/Abp.IdentityServer.EntityFrameworkCore.Tests/Volo/Abp/IdentityServer/AbpIdentityServerTestDataBuilder.cs @@ -4,6 +4,7 @@ using Volo.Abp.Guids; using Volo.Abp.IdentityServer.ApiResources; using Volo.Abp.IdentityServer.Clients; using Volo.Abp.IdentityServer.Grants; +using Volo.Abp.IdentityServer.IdentityResources; namespace Volo.Abp.IdentityServer { @@ -13,17 +14,20 @@ namespace Volo.Abp.IdentityServer private readonly IClientRepository _clientRepository; private readonly IPersistentGrantRepository _persistentGrantRepository; private readonly IApiResourceRepository _apiResourceRepository; + private readonly IIdentityResourceRepository _identityResourceRepository; public AbpIdentityServerTestDataBuilder( IClientRepository clientRepository, IGuidGenerator guidGenerator, IPersistentGrantRepository persistentGrantRepository, - IApiResourceRepository apiResourceRepository) + IApiResourceRepository apiResourceRepository, + IIdentityResourceRepository identityResourceRepository) { _clientRepository = clientRepository; _guidGenerator = guidGenerator; _persistentGrantRepository = persistentGrantRepository; _apiResourceRepository = apiResourceRepository; + _identityResourceRepository = identityResourceRepository; } public void Build() @@ -31,6 +35,7 @@ namespace Volo.Abp.IdentityServer AddClients(); AddPersistentGrants(); AddApiResources(); + AddIdentityResources(); } private void AddClients() @@ -119,5 +124,26 @@ namespace Volo.Abp.IdentityServer } }); } + + private void AddIdentityResources() + { + _identityResourceRepository.Insert(new IdentityResource(_guidGenerator.Create()) + { + Enabled = true, + Description = "Test-Identity-Resource-Description-1", + DisplayName = "Test-Identity-Resource-DisplayName-1", + Name = "Test-Identity-Resource-Name-1", + Required = true, + ShowInDiscoveryDocument = true, + Emphasize = true, + UserClaims = new List + { + new IdentityClaim(_guidGenerator.Create()) + { + Type = "Test-Identity-Resource-1-IdentityClaim-Type-1" + } + } + }); + } } } diff --git a/test/Abp.IdentityServer.EntityFrameworkCore.Tests/Volo/Abp/IdentityServer/Clients/IdentityResourceStore_Tests.cs b/test/Abp.IdentityServer.EntityFrameworkCore.Tests/Volo/Abp/IdentityServer/Clients/IdentityResourceStore_Tests.cs new file mode 100644 index 0000000000..bd15fed89b --- /dev/null +++ b/test/Abp.IdentityServer.EntityFrameworkCore.Tests/Volo/Abp/IdentityServer/Clients/IdentityResourceStore_Tests.cs @@ -0,0 +1,92 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using IdentityServer4.Models; +using IdentityServer4.Stores; +using Microsoft.Extensions.DependencyInjection; +using Shouldly; +using Xunit; + +namespace Volo.Abp.IdentityServer.Clients +{ + public class IdentityResourceStore_Tests : AbpIdentityServerTestBase + { + private readonly IResourceStore _resourceStore; + + public IdentityResourceStore_Tests() + { + _resourceStore = ServiceProvider.GetRequiredService(); + } + + [Fact] + public async Task FindApiResourceAsync_Should_Return_Null_If_Not_Found() + { + //Act + var resource = await _resourceStore.FindApiResourceAsync("non-existing-name"); + + //Assert + resource.ShouldBeNull(); + } + + [Fact] + public async Task FindApiResourceAsync_Should_Return_If_Found() + { + //Act + var apiResource = await _resourceStore.FindApiResourceAsync("Test-ApiResource-Name-1"); + + //Assert + apiResource.ShouldNotBe(null); + apiResource.Name.ShouldBe("Test-ApiResource-Name-1"); + apiResource.Description.ShouldBe("Test-ApiResource-Description-1"); + apiResource.DisplayName.ShouldBe("Test-ApiResource-DisplayName-1"); + } + + [Fact] + public async Task FindApiResourcesByScopeAsync_Should_Return_If_Found() + { + //Act + var apiResourcesByScope = await _resourceStore.FindApiResourcesByScopeAsync(new List + { + "Test-ApiResource-ApiScope-Name-1" + }); + + //Assert + var apiResources = apiResourcesByScope as ApiResource[] ?? apiResourcesByScope.ToArray(); + apiResources.ShouldNotBe(null); + + apiResources[0].Scopes.GroupBy(x => x.Name).Count().ShouldBe(1); + apiResources[0].Scopes.GroupBy(x => x.Name).First().Key.ShouldBe("Test-ApiResource-ApiScope-Name-1"); + } + + [Fact] + public async Task FindIdentityResourcesByScopeAsync_Should_Return_For_Given_Scopes() + { + //Act + var identityResourcesByScope = await _resourceStore.FindIdentityResourcesByScopeAsync(new List + { + "Test-Identity-Resource-Name-1" + }); + + //Assert + var resourcesByScope = identityResourcesByScope as IdentityResource[] ?? identityResourcesByScope.ToArray(); + resourcesByScope.Length.ShouldBe(1); + resourcesByScope.First().DisplayName.ShouldBe("Test-Identity-Resource-DisplayName-1"); + resourcesByScope.First().Description.ShouldBe("Test-Identity-Resource-Description-1"); + resourcesByScope.First().Required.ShouldBe(true); + } + + [Fact] + public async Task GetAllResourcesAsync_Should_Return() + { + //Act + var resources = await _resourceStore.GetAllResourcesAsync(); + + //Assert + resources.ShouldNotBe(null); + resources.ApiResources.Count.ShouldBe(1); + resources.ApiResources.First().Name.ShouldBe("Test-ApiResource-Name-1"); + resources.IdentityResources.First().Name.ShouldBe("Test-Identity-Resource-Name-1"); + resources.IdentityResources.First().Required.ShouldBe(true); + } + } +}