Browse Source

Resolved #826: Implement IdentityServer Cors Policy Service.

pull/839/head
Halil ibrahim Kalkan 7 years ago
parent
commit
d31893a709
  1. 15
      framework/src/Volo.Abp.Caching/Volo/Abp/Caching/CacheNameAttribute.cs
  2. 8
      framework/src/Volo.Abp.Caching/Volo/Abp/Caching/DistributedCache.cs
  3. 3
      modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/AbpIdentityDomainSharedModule.cs
  4. 10
      modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/AbpIdentityDomainModule.cs
  5. 1
      modules/identityserver/src/Volo.Abp.IdentityServer.Domain.Shared/Volo.Abp.IdentityServer.Domain.Shared.csproj
  6. 7
      modules/identityserver/src/Volo.Abp.IdentityServer.Domain.Shared/Volo/Abp/IdentityServer/AbpIdentityServerDomainSharedModule.cs
  7. 57
      modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AbpCorsPolicyService.cs
  8. 1
      modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AbpIdentityServerDomainModule.cs
  9. 9
      modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AllowedCorsOriginsCacheItem.cs
  10. 24
      modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AllowedCorsOriginsCacheItemInvalidator.cs
  11. 3
      modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/IdentityServerBuilderExtensions.cs
  12. 10
      modules/identityserver/test/Volo.Abp.IdentityServer.Domain.Tests/Volo/Abp/IdentityServer/AbpIdentityServerDomainTestBase.cs
  13. 41
      modules/identityserver/test/Volo.Abp.IdentityServer.Domain.Tests/Volo/Abp/IdentityServer/CorsPolicyService_Tests.cs
  14. 3
      modules/identityserver/test/Volo.Abp.IdentityServer.MongoDB.Tests/Volo/Abp/IdentityServer/AbpIdentityServerMongoDbTestModule.cs
  15. 2
      modules/identityserver/test/Volo.Abp.IdentityServer.TestBase/Volo/Abp/IdentityServer/AbpIdentityServerTestDataBuilder.cs

15
framework/src/Volo.Abp.Caching/Volo/Abp/Caching/CacheNameAttribute.cs

@ -15,5 +15,20 @@ namespace Volo.Abp.Caching
Name = name; Name = name;
} }
public static string GetCacheName(Type cacheItemType)
{
var cacheNameAttribute = cacheItemType
.GetCustomAttributes(true)
.OfType<CacheNameAttribute>()
.FirstOrDefault();
if (cacheNameAttribute != null)
{
return cacheNameAttribute.Name;
}
return cacheItemType.FullName.RemovePostFix("CacheItem");
}
} }
} }

8
framework/src/Volo.Abp.Caching/Volo/Abp/Caching/DistributedCache.cs

@ -326,13 +326,7 @@ namespace Volo.Abp.Caching
protected virtual void SetDefaultOptions() protected virtual void SetDefaultOptions()
{ {
//CacheName CacheName = CacheNameAttribute.GetCacheName(typeof(TCacheItem));
var cacheNameAttribute = typeof(TCacheItem)
.GetCustomAttributes(true)
.OfType<CacheNameAttribute>()
.FirstOrDefault();
CacheName = cacheNameAttribute != null ? cacheNameAttribute.Name : typeof(TCacheItem).FullName;
//IgnoreMultiTenancy //IgnoreMultiTenancy
IgnoreMultiTenancy = typeof(TCacheItem).IsDefined(typeof(IgnoreMultiTenancyAttribute), true); IgnoreMultiTenancy = typeof(TCacheItem).IsDefined(typeof(IgnoreMultiTenancyAttribute), true);

3
modules/identity/src/Volo.Abp.Identity.Domain.Shared/Volo/Abp/Identity/AbpIdentityDomainSharedModule.cs

@ -1,5 +1,4 @@
using Microsoft.Extensions.DependencyInjection; using Volo.Abp.Identity.Localization;
using Volo.Abp.Identity.Localization;
using Volo.Abp.Localization; using Volo.Abp.Localization;
using Volo.Abp.Modularity; using Volo.Abp.Modularity;
using Volo.Abp.Users; using Volo.Abp.Users;

10
modules/identity/src/Volo.Abp.Identity.Domain/Volo/Abp/Identity/AbpIdentityDomainModule.cs

@ -7,15 +7,19 @@ using Volo.Abp.EventBus.Distributed;
using Volo.Abp.Identity.Localization; using Volo.Abp.Identity.Localization;
using Volo.Abp.Localization; using Volo.Abp.Localization;
using Volo.Abp.Modularity; using Volo.Abp.Modularity;
using Volo.Abp.SettingManagement;
using Volo.Abp.Settings; using Volo.Abp.Settings;
using Volo.Abp.Users; using Volo.Abp.Users;
using Volo.Abp.VirtualFileSystem; using Volo.Abp.VirtualFileSystem;
namespace Volo.Abp.Identity namespace Volo.Abp.Identity
{ {
[DependsOn(typeof(AbpDddDomainModule))] [DependsOn(
[DependsOn(typeof(AbpIdentityDomainSharedModule))] typeof(AbpDddDomainModule),
[DependsOn(typeof(AbpUsersDomainModule))] typeof(AbpIdentityDomainSharedModule),
typeof(AbpUsersDomainModule),
typeof(AbpSettingManagementDomainModule)
)]
public class AbpIdentityDomainModule : AbpModule public class AbpIdentityDomainModule : AbpModule
{ {
public override void ConfigureServices(ServiceConfigurationContext context) public override void ConfigureServices(ServiceConfigurationContext context)

1
modules/identityserver/src/Volo.Abp.IdentityServer.Domain.Shared/Volo.Abp.IdentityServer.Domain.Shared.csproj

@ -14,7 +14,6 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\..\..\framework\src\Volo.Abp.Core\Volo.Abp.Core.csproj" />
<ProjectReference Include="..\..\..\..\framework\src\Volo.Abp.Localization\Volo.Abp.Localization.csproj" /> <ProjectReference Include="..\..\..\..\framework\src\Volo.Abp.Localization\Volo.Abp.Localization.csproj" />
</ItemGroup> </ItemGroup>

7
modules/identityserver/src/Volo.Abp.IdentityServer.Domain.Shared/Volo/Abp/IdentityServer/AbpIdentityServerDomainSharedModule.cs

@ -1,13 +1,14 @@
using Microsoft.Extensions.DependencyInjection; using Volo.Abp.IdentityServer.Localization;
using Volo.Abp.IdentityServer.Localization;
using Volo.Abp.Localization; using Volo.Abp.Localization;
using Volo.Abp.Modularity; using Volo.Abp.Modularity;
namespace Volo.Abp.IdentityServer namespace Volo.Abp.IdentityServer
{ {
[DependsOn(
typeof(AbpLocalizationModule)
)]
public class AbpIdentityServerDomainSharedModule : AbpModule public class AbpIdentityServerDomainSharedModule : AbpModule
{ {
public override void ConfigureServices(ServiceConfigurationContext context) public override void ConfigureServices(ServiceConfigurationContext context)
{ {
Configure<AbpLocalizationOptions>(options => Configure<AbpLocalizationOptions>(options =>

57
modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AbpCorsPolicyService.cs

@ -0,0 +1,57 @@
using IdentityServer4.Services;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using System;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.Caching;
using Volo.Abp.DependencyInjection;
using Volo.Abp.IdentityServer.Clients;
namespace Volo.Abp.IdentityServer
{
public class AbpCorsPolicyService : ICorsPolicyService
{
public ILogger<AbpCorsPolicyService> Logger { get; set; }
protected IHybridServiceScopeFactory HybridServiceScopeFactory { get; }
protected IDistributedCache<AllowedCorsOriginsCacheItem> Cache { get; }
public AbpCorsPolicyService(
IDistributedCache<AllowedCorsOriginsCacheItem> cache,
IHybridServiceScopeFactory hybridServiceScopeFactory)
{
Cache = cache;
HybridServiceScopeFactory = hybridServiceScopeFactory;
Logger = NullLogger<AbpCorsPolicyService>.Instance;
}
public async Task<bool> IsOriginAllowedAsync(string origin)
{
var cacheItem = await Cache.GetOrAddAsync(AllowedCorsOriginsCacheItem.AllOrigins, CreateCacheItemAsync);
var isAllowed = cacheItem.AllowedOrigins.Contains(origin, StringComparer.OrdinalIgnoreCase);
if (!isAllowed)
{
Logger.LogWarning($"Origin is not allowed: {origin}");
}
return isAllowed;
}
protected virtual async Task<AllowedCorsOriginsCacheItem> CreateCacheItemAsync()
{
// doing this here and not in the ctor because: https://github.com/aspnet/AspNetCore/issues/2377
using (var scope = HybridServiceScopeFactory.CreateScope())
{
var clientRepository = scope.ServiceProvider.GetRequiredService<IClientRepository>();
return new AllowedCorsOriginsCacheItem
{
AllowedOrigins = (await clientRepository.GetAllDistinctAllowedCorsOriginsAsync()).ToArray()
};
}
}
}
}

1
modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AbpIdentityServerDomainModule.cs

@ -12,7 +12,6 @@ namespace Volo.Abp.IdentityServer
{ {
[DependsOn( [DependsOn(
typeof(AbpIdentityServerDomainSharedModule), typeof(AbpIdentityServerDomainSharedModule),
typeof(AbpDddDomainModule),
typeof(AbpAutoMapperModule), typeof(AbpAutoMapperModule),
typeof(AbpIdentityDomainModule), typeof(AbpIdentityDomainModule),
typeof(AbpSecurityModule) typeof(AbpSecurityModule)

9
modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AllowedCorsOriginsCacheItem.cs

@ -0,0 +1,9 @@
namespace Volo.Abp.IdentityServer
{
public class AllowedCorsOriginsCacheItem
{
public const string AllOrigins = "AllOrigins";
public string[] AllowedOrigins { get; set; }
}
}

24
modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/AllowedCorsOriginsCacheItemInvalidator.cs

@ -0,0 +1,24 @@
using System.Threading.Tasks;
using Volo.Abp.Caching;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Entities.Events;
using Volo.Abp.EventBus;
using Volo.Abp.IdentityServer.Clients;
namespace Volo.Abp.IdentityServer
{
public class AllowedCorsOriginsCacheItemInvalidator : ILocalEventHandler<EntityChangedEventData<Client>>, ITransientDependency
{
protected IDistributedCache<AllowedCorsOriginsCacheItem> Cache { get; }
public AllowedCorsOriginsCacheItemInvalidator(IDistributedCache<AllowedCorsOriginsCacheItem> cache)
{
Cache = cache;
}
public async Task HandleEventAsync(EntityChangedEventData<Client> eventData)
{
await Cache.RemoveAsync(AllowedCorsOriginsCacheItem.AllOrigins);
}
}
}

3
modules/identityserver/src/Volo.Abp.IdentityServer.Domain/Volo/Abp/IdentityServer/IdentityServerBuilderExtensions.cs

@ -13,7 +13,8 @@ namespace Volo.Abp.IdentityServer
return builder return builder
.AddClientStore<ClientStore>() .AddClientStore<ClientStore>()
.AddResourceStore<ResourceStore>(); .AddResourceStore<ResourceStore>()
.AddCorsPolicyService<AbpCorsPolicyService>();
} }
} }
} }

10
modules/identityserver/test/Volo.Abp.IdentityServer.Domain.Tests/Volo/Abp/IdentityServer/AbpIdentityServerDomainTestBase.cs

@ -0,0 +1,10 @@
namespace Volo.Abp.IdentityServer
{
public class AbpIdentityServerDomainTestBase : AbpIntegratedTest<AbpIdentityServerDomainTestModule>
{
protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options)
{
options.UseAutofac();
}
}
}

41
modules/identityserver/test/Volo.Abp.IdentityServer.Domain.Tests/Volo/Abp/IdentityServer/CorsPolicyService_Tests.cs

@ -0,0 +1,41 @@
using System.Threading.Tasks;
using IdentityServer4.Services;
using Shouldly;
using Volo.Abp.IdentityServer.Clients;
using Xunit;
namespace Volo.Abp.IdentityServer
{
public class CorsPolicyService_Tests : AbpIdentityServerDomainTestBase
{
private readonly ICorsPolicyService _corsPolicyService;
private readonly IClientRepository _clientRepository;
public CorsPolicyService_Tests()
{
_corsPolicyService = GetRequiredService<ICorsPolicyService>();
_clientRepository = GetRequiredService<IClientRepository>();
}
[Fact]
public async Task IsOriginAllowedAsync()
{
(await _corsPolicyService.IsOriginAllowedAsync("https://client1-origin.com")).ShouldBeTrue();
(await _corsPolicyService.IsOriginAllowedAsync("https://unknown-origin.com")).ShouldBeFalse();
}
[Fact]
public async Task IsOriginAllowedAsync_Should_Invalidate_Cache_On_Update()
{
//It does not exists before
(await _corsPolicyService.IsOriginAllowedAsync("https://new-origin.com")).ShouldBeFalse();
var client1 = await _clientRepository.FindByCliendIdAsync("ClientId1");
client1.AddCorsOrigin("https://new-origin.com");
await _clientRepository.UpdateAsync(client1);
//It does exists now
(await _corsPolicyService.IsOriginAllowedAsync("https://new-origin.com")).ShouldBeTrue();
}
}
}

3
modules/identityserver/test/Volo.Abp.IdentityServer.MongoDB.Tests/Volo/Abp/IdentityServer/AbpIdentityServerMongoDbTestModule.cs

@ -1,5 +1,4 @@
using Microsoft.Extensions.DependencyInjection; using Mongo2Go;
using Mongo2Go;
using Volo.Abp.Data; using Volo.Abp.Data;
using Volo.Abp.IdentityServer.MongoDB; using Volo.Abp.IdentityServer.MongoDB;
using Volo.Abp.Modularity; using Volo.Abp.Modularity;

2
modules/identityserver/test/Volo.Abp.IdentityServer.TestBase/Volo/Abp/IdentityServer/AbpIdentityServerTestDataBuilder.cs

@ -90,7 +90,7 @@ namespace Volo.Abp.IdentityServer
FrontChannelLogoutUri = nameof(Client.FrontChannelLogoutUri) FrontChannelLogoutUri = nameof(Client.FrontChannelLogoutUri)
}; };
client.AddCorsOrigin(nameof(ClientCorsOrigin.Origin)); client.AddCorsOrigin("https://client1-origin.com");
client.AddClaim(nameof(ClientClaim.Value), nameof(ClientClaim.Type)); client.AddClaim(nameof(ClientClaim.Value), nameof(ClientClaim.Type));
client.AddGrantType(nameof(ClientGrantType.GrantType)); client.AddGrantType(nameof(ClientGrantType.GrantType));
client.AddIdentityProviderRestriction(nameof(ClientIdPRestriction.Provider)); client.AddIdentityProviderRestriction(nameof(ClientIdPRestriction.Provider));

Loading…
Cancel
Save