Browse Source

feat: Add `IsAvailableAsync` to resource permission management providers

Introduces `IsAvailableAsync()` to `IResourcePermissionManagementProvider` and `IResourcePermissionProviderKeyLookupService`, allowing providers to opt out in certain contexts.

`ResourcePermissionManager` respects this flag in permission checks, writes, and UI lookup service listing.

OpenIddict and IdentityServer client providers override `IsAvailableAsync()` to return `false` when the current context is a tenant (host-only concept).
pull/24951/head
maliming 1 month ago
parent
commit
fddf02774a
No known key found for this signature in database GPG Key ID: A646B9CB645ECEA4
  1. 5
      modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo/Abp/PermissionManagement/Identity/RoleResourcePermissionProviderKeyLookupService.cs
  2. 5
      modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo/Abp/PermissionManagement/Identity/UserResourcePermissionProviderKeyLookupService.cs
  3. 5
      modules/identityserver/src/Volo.Abp.PermissionManagement.Domain.IdentityServer/Volo/Abp/PermissionManagement/IdentityServer/ClientResourcePermissionManagementProvider.cs
  4. 13
      modules/identityserver/src/Volo.Abp.PermissionManagement.Domain.IdentityServer/Volo/Abp/PermissionManagement/IdentityServer/ClientResourcePermissionProviderKeyLookupService.cs
  5. 5
      modules/openiddict/src/Volo.Abp.PermissionManagement.Domain.OpenIddict/Volo/Abp/PermissionManagement/OpenIddict/ApplicationResourcePermissionManagementProvider.cs
  6. 13
      modules/openiddict/src/Volo.Abp.PermissionManagement.Domain.OpenIddict/Volo/Abp/PermissionManagement/OpenIddict/ApplicationResourcePermissionProviderKeyLookupService.cs
  7. 2
      modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IResourcePermissionManagementProvider.cs
  8. 2
      modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IResourcePermissionProviderKeyLookupService.cs
  9. 5
      modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/ResourcePermissionManagementProvider.cs
  10. 23
      modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/ResourcePermissionManager.cs
  11. 51
      modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/ResourcePermissionManager_Tests.cs
  12. 2
      modules/permission-management/test/Volo.Abp.PermissionManagement.TestBase/Volo/Abp/PermissionManagement/AbpPermissionManagementTestBaseModule.cs
  13. 5
      modules/permission-management/test/Volo.Abp.PermissionManagement.TestBase/Volo/Abp/PermissionManagement/TestResourcePermissionProviderKeyLookupService.cs
  14. 26
      modules/permission-management/test/Volo.Abp.PermissionManagement.TestBase/Volo/Abp/PermissionManagement/TestUnavailableResourcePermissionManagementProvider.cs
  15. 29
      modules/permission-management/test/Volo.Abp.PermissionManagement.TestBase/Volo/Abp/PermissionManagement/TestUnavailableResourcePermissionProviderKeyLookupService.cs

5
modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo/Abp/PermissionManagement/Identity/RoleResourcePermissionProviderKeyLookupService.cs

@ -24,6 +24,11 @@ public class RoleResourcePermissionProviderKeyLookupService : IResourcePermissio
DisplayName = LocalizableString.Create<IdentityResource>(nameof(RoleResourcePermissionProviderKeyLookupService));
}
public virtual Task<bool> IsAvailableAsync()
{
return Task.FromResult(true);
}
public virtual async Task<List<ResourcePermissionProviderKeyInfo>> SearchAsync(string filter = null, int page = 1, CancellationToken cancellationToken = default)
{
var roles = await UserRoleFinder.SearchRoleAsync(filter, page);

5
modules/identity/src/Volo.Abp.PermissionManagement.Domain.Identity/Volo/Abp/PermissionManagement/Identity/UserResourcePermissionProviderKeyLookupService.cs

@ -25,6 +25,11 @@ public class UserResourcePermissionProviderKeyLookupService : IResourcePermissio
DisplayName = LocalizableString.Create<IdentityResource>(nameof(UserResourcePermissionProviderKeyLookupService));
}
public virtual Task<bool> IsAvailableAsync()
{
return Task.FromResult(true);
}
public virtual async Task<List<ResourcePermissionProviderKeyInfo>> SearchAsync(string filter = null, int page = 1, CancellationToken cancellationToken = default)
{
var users = await UserRoleFinder.SearchUserAsync(filter, page);

5
modules/identityserver/src/Volo.Abp.PermissionManagement.Domain.IdentityServer/Volo/Abp/PermissionManagement/IdentityServer/ClientResourcePermissionManagementProvider.cs

@ -20,6 +20,11 @@ public class ClientResourcePermissionManagementProvider : ResourcePermissionMana
{
}
public override Task<bool> IsAvailableAsync()
{
return Task.FromResult(CurrentTenant.Id == null);
}
public override Task<ResourcePermissionValueProviderGrantInfo> CheckAsync(string name, string resourceName, string resourceKey, string providerName, string providerKey)
{
using (CurrentTenant.Change(null))

13
modules/identityserver/src/Volo.Abp.PermissionManagement.Domain.IdentityServer/Volo/Abp/PermissionManagement/IdentityServer/ClientResourcePermissionProviderKeyLookupService.cs

@ -8,6 +8,7 @@ using Volo.Abp.DependencyInjection;
using Volo.Abp.IdentityServer.Clients;
using Volo.Abp.IdentityServer.Localization;
using Volo.Abp.Localization;
using Volo.Abp.MultiTenancy;
namespace Volo.Abp.PermissionManagement.IdentityServer;
@ -19,12 +20,22 @@ public class ClientResourcePermissionProviderKeyLookupService : IResourcePermiss
protected IClientFinder ClientFinder { get; }
public ClientResourcePermissionProviderKeyLookupService(IClientFinder clientFinder)
protected ICurrentTenant CurrentTenant { get; }
public ClientResourcePermissionProviderKeyLookupService(
IClientFinder clientFinder,
ICurrentTenant currentTenant)
{
ClientFinder = clientFinder;
CurrentTenant = currentTenant;
DisplayName = LocalizableString.Create<AbpIdentityServerResource>(nameof(ClientResourcePermissionProviderKeyLookupService));
}
public virtual Task<bool> IsAvailableAsync()
{
return Task.FromResult(CurrentTenant.Id == null);
}
public virtual async Task<List<ResourcePermissionProviderKeyInfo>> SearchAsync(string filter = null, int page = 1, CancellationToken cancellationToken = default)
{
var clients = await ClientFinder.SearchAsync(filter, page);

5
modules/openiddict/src/Volo.Abp.PermissionManagement.Domain.OpenIddict/Volo/Abp/PermissionManagement/OpenIddict/ApplicationResourcePermissionManagementProvider.cs

@ -17,6 +17,11 @@ public class ApplicationResourcePermissionManagementProvider : ResourcePermissio
{
}
public override Task<bool> IsAvailableAsync()
{
return Task.FromResult(CurrentTenant.Id == null);
}
public override Task<ResourcePermissionValueProviderGrantInfo> CheckAsync(string name, string resourceName, string resourceKey, string providerName, string providerKey)
{
using (CurrentTenant.Change(null))

13
modules/openiddict/src/Volo.Abp.PermissionManagement.Domain.OpenIddict/Volo/Abp/PermissionManagement/OpenIddict/ApplicationResourcePermissionProviderKeyLookupService.cs

@ -6,6 +6,7 @@ using System.Threading.Tasks;
using Volo.Abp.Authorization.Permissions.Resources;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Localization;
using Volo.Abp.MultiTenancy;
using Volo.Abp.OpenIddict.Applications;
using Volo.Abp.OpenIddict.Localization;
@ -19,12 +20,22 @@ public class ApplicationResourcePermissionProviderKeyLookupService : IResourcePe
protected IApplicationFinder ApplicationFinder { get; }
public ApplicationResourcePermissionProviderKeyLookupService(IApplicationFinder applicationFinder)
protected ICurrentTenant CurrentTenant { get; }
public ApplicationResourcePermissionProviderKeyLookupService(
IApplicationFinder applicationFinder,
ICurrentTenant currentTenant)
{
ApplicationFinder = applicationFinder;
CurrentTenant = currentTenant;
DisplayName = LocalizableString.Create<AbpOpenIddictResource>(nameof(ApplicationResourcePermissionProviderKeyLookupService));
}
public virtual Task<bool> IsAvailableAsync()
{
return Task.FromResult(CurrentTenant.Id == null);
}
public virtual async Task<List<ResourcePermissionProviderKeyInfo>> SearchAsync(string filter = null, int page = 1, CancellationToken cancellationToken = default)
{
var applications = await ApplicationFinder.SearchAsync(filter, page);

2
modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IResourcePermissionManagementProvider.cs

@ -8,6 +8,8 @@ public interface IResourcePermissionManagementProvider : ISingletonDependency //
{
string Name { get; }
Task<bool> IsAvailableAsync();
Task<ResourcePermissionValueProviderGrantInfo> CheckAsync(
[NotNull] string name,
[NotNull] string resourceName,

2
modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/IResourcePermissionProviderKeyLookupService.cs

@ -9,6 +9,8 @@ public interface IResourcePermissionProviderKeyLookupService
{
public string Name { get; }
Task<bool> IsAvailableAsync();
public ILocalizableString DisplayName { get; }
Task<List<ResourcePermissionProviderKeyInfo>> SearchAsync(string filter = null, int page = 1, CancellationToken cancellationToken = default);

5
modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/ResourcePermissionManagementProvider.cs

@ -26,6 +26,11 @@ public abstract class ResourcePermissionManagementProvider : IResourcePermission
CurrentTenant = currentTenant;
}
public virtual Task<bool> IsAvailableAsync()
{
return Task.FromResult(true);
}
public virtual async Task<ResourcePermissionValueProviderGrantInfo> CheckAsync(string name, string resourceName, string resourceKey, string providerName, string providerKey)
{
var multiplePermissionValueProviderGrantInfo = await CheckAsync(new[] { name }, resourceName, resourceKey, providerName, providerKey);

23
modules/permission-management/src/Volo.Abp.PermissionManagement.Domain/Volo/Abp/PermissionManagement/ResourcePermissionManager.cs

@ -70,9 +70,17 @@ public class ResourcePermissionManager : IResourcePermissionManager, ISingletonD
);
}
public virtual Task<List<IResourcePermissionProviderKeyLookupService>> GetProviderKeyLookupServicesAsync()
public virtual async Task<List<IResourcePermissionProviderKeyLookupService>> GetProviderKeyLookupServicesAsync()
{
return Task.FromResult(_lazyProviderKeyLookupServices.Value);
var availableServices = new List<IResourcePermissionProviderKeyLookupService>();
foreach (var service in _lazyProviderKeyLookupServices.Value)
{
if (await service.IsAvailableAsync())
{
availableServices.Add(service);
}
}
return availableServices;
}
public virtual Task<IResourcePermissionProviderKeyLookupService> GetProviderKeyLookupServiceAsync(string serviceName)
@ -282,6 +290,12 @@ public class ResourcePermissionManager : IResourcePermissionManager, ISingletonD
throw new AbpException("Unknown resource permission management provider: " + providerName);
}
if (!await provider.IsAvailableAsync())
{
//TODO: BusinessException
throw new AbpException($"The resource permission management provider '{providerName}' is not available in the current context.");
}
await provider.SetAsync(permissionName, resourceName, resourceKey, providerKey, isGranted);
}
@ -378,6 +392,11 @@ public class ResourcePermissionManager : IResourcePermissionManager, ISingletonD
foreach (var provider in ManagementProviders)
{
if (!await provider.IsAvailableAsync())
{
continue;
}
permissionNames = resourcePermissions.Select(x => x.Name).ToArray();
var multiplePermissionValueProviderGrantInfo = await provider.CheckAsync(permissionNames, resourceName, resourceKey, providerName, providerKey);

51
modules/permission-management/test/Volo.Abp.PermissionManagement.Domain.Tests/Volo/Abp/PermissionManagement/ResourcePermissionManager_Tests.cs

@ -334,4 +334,55 @@ public class ResourcePermissionManager_Tests : PermissionTestBase
"Test",
"Test")).ShouldBeNull();
}
[Fact]
public async Task GetProviderKeyLookupServicesAsync_Should_Not_Return_Unavailable_Services()
{
var lookupServices = await _resourcePermissionManager.GetProviderKeyLookupServicesAsync();
lookupServices.ShouldContain(s => s.Name == "Test");
lookupServices.ShouldNotContain(s => s.Name == "TestUnavailable");
}
[Fact]
public async Task GetAsync_Should_Not_Return_Grant_From_Unavailable_Provider()
{
// Insert a grant directly via repository to simulate data stored by an unavailable provider
await _resourcePermissionGrantRepository.InsertAsync(new ResourcePermissionGrant(
Guid.NewGuid(),
"MyResourcePermission1",
TestEntityResource.ResourceName,
TestEntityResource.ResourceKey1,
"TestUnavailable",
"someKey")
);
var grantedProviders = await _resourcePermissionManager.GetAsync(
"MyResourcePermission1",
TestEntityResource.ResourceName,
TestEntityResource.ResourceKey1,
"TestUnavailable",
"someKey");
// The unavailable provider is skipped, so the permission should not be considered granted via it
grantedProviders.IsGranted.ShouldBeFalse();
grantedProviders.Providers.ShouldNotContain(p => p.Name == "TestUnavailable");
}
[Fact]
public async Task SetAsync_Should_Throw_When_Provider_Is_Unavailable()
{
var exception = await Assert.ThrowsAsync<AbpException>(async () =>
{
await _resourcePermissionManager.SetAsync(
"MyResourcePermission1",
TestEntityResource.ResourceName,
TestEntityResource.ResourceKey1,
"TestUnavailable",
"someKey",
true);
});
exception.Message.ShouldBe("The resource permission management provider 'TestUnavailable' is not available in the current context.");
}
}

2
modules/permission-management/test/Volo.Abp.PermissionManagement.TestBase/Volo/Abp/PermissionManagement/AbpPermissionManagementTestBaseModule.cs

@ -23,7 +23,9 @@ public class AbpPermissionManagementTestBaseModule : AbpModule
{
options.ManagementProviders.Add<TestPermissionManagementProvider>();
options.ResourceManagementProviders.Add<TestResourcePermissionManagementProvider>();
options.ResourceManagementProviders.Add<TestUnavailableResourcePermissionManagementProvider>();
options.ResourcePermissionProviderKeyLookupServices.Add<TestResourcePermissionProviderKeyLookupService>();
options.ResourcePermissionProviderKeyLookupServices.Add<TestUnavailableResourcePermissionProviderKeyLookupService>();
});
}

5
modules/permission-management/test/Volo.Abp.PermissionManagement.TestBase/Volo/Abp/PermissionManagement/TestResourcePermissionProviderKeyLookupService.cs

@ -12,6 +12,11 @@ public class TestResourcePermissionProviderKeyLookupService : IResourcePermissio
public ILocalizableString DisplayName => new LocalizableString("Test", "TestResource");
public Task<bool> IsAvailableAsync()
{
return Task.FromResult(true);
}
public Task<List<ResourcePermissionProviderKeyInfo>> SearchAsync(string filter = null, int page = 1, CancellationToken cancellationToken = default)
{
throw new System.NotImplementedException();

26
modules/permission-management/test/Volo.Abp.PermissionManagement.TestBase/Volo/Abp/PermissionManagement/TestUnavailableResourcePermissionManagementProvider.cs

@ -0,0 +1,26 @@
using System.Threading.Tasks;
using Volo.Abp.Guids;
using Volo.Abp.MultiTenancy;
namespace Volo.Abp.PermissionManagement;
public class TestUnavailableResourcePermissionManagementProvider : ResourcePermissionManagementProvider
{
public override string Name => "TestUnavailable";
public TestUnavailableResourcePermissionManagementProvider(
IResourcePermissionGrantRepository resourcePermissionGrantRepository,
IGuidGenerator guidGenerator,
ICurrentTenant currentTenant)
: base(
resourcePermissionGrantRepository,
guidGenerator,
currentTenant)
{
}
public override Task<bool> IsAvailableAsync()
{
return Task.FromResult(false);
}
}

29
modules/permission-management/test/Volo.Abp.PermissionManagement.TestBase/Volo/Abp/PermissionManagement/TestUnavailableResourcePermissionProviderKeyLookupService.cs

@ -0,0 +1,29 @@
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Localization;
namespace Volo.Abp.PermissionManagement;
public class TestUnavailableResourcePermissionProviderKeyLookupService : IResourcePermissionProviderKeyLookupService, ITransientDependency
{
public string Name => "TestUnavailable";
public ILocalizableString DisplayName => new LocalizableString("TestUnavailable", "TestResource");
public Task<bool> IsAvailableAsync()
{
return Task.FromResult(false);
}
public Task<List<ResourcePermissionProviderKeyInfo>> SearchAsync(string filter = null, int page = 1, CancellationToken cancellationToken = default)
{
throw new System.NotImplementedException();
}
public Task<List<ResourcePermissionProviderKeyInfo>> SearchAsync(string[] keys, CancellationToken cancellationToken = default)
{
throw new System.NotImplementedException();
}
}
Loading…
Cancel
Save