diff --git a/src/SecuritySystem.Abstractions/Expanders/ISecurityRoleExpander.cs b/src/SecuritySystem.Abstractions/Expanders/ISecurityRoleExpander.cs deleted file mode 100644 index 54f368e..0000000 --- a/src/SecuritySystem.Abstractions/Expanders/ISecurityRoleExpander.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace SecuritySystem.Expanders; - -public interface ISecurityRoleExpander -{ - DomainSecurityRule.ExpandedRolesSecurityRule Expand(DomainSecurityRule.NonExpandedRolesSecurityRule securityRule); -} diff --git a/src/SecuritySystem.Abstractions/Expanders/ISecurityRoleGroupExpander.cs b/src/SecuritySystem.Abstractions/Expanders/ISecurityRoleGroupExpander.cs new file mode 100644 index 0000000..d25897f --- /dev/null +++ b/src/SecuritySystem.Abstractions/Expanders/ISecurityRoleGroupExpander.cs @@ -0,0 +1,8 @@ +namespace SecuritySystem.Expanders; + +public interface ISecurityRoleGroupExpander +{ + DomainSecurityRule.ExpandedRoleGroupSecurityRule Expand(DomainSecurityRule.NonExpandedRoleGroupSecurityRule securityRule); + + DomainSecurityRule.ExpandedRoleGroupSecurityRule Expand(DomainSecurityRule.NonExpandedRolesSecurityRule securityRule); +} \ No newline at end of file diff --git a/src/SecuritySystem.Abstractions/Expanders/ISecurityRuleExpander.cs b/src/SecuritySystem.Abstractions/Expanders/ISecurityRuleExpander.cs index c29d5cc..01aaeaa 100644 --- a/src/SecuritySystem.Abstractions/Expanders/ISecurityRuleExpander.cs +++ b/src/SecuritySystem.Abstractions/Expanders/ISecurityRuleExpander.cs @@ -2,12 +2,12 @@ public interface ISecurityRuleExpander : ISecurityModeExpander, ISecurityOperationExpander, - ISecurityRoleExpander, + ISecurityRoleGroupExpander, IRoleFactorySecurityRuleExpander, IClientSecurityRuleExpander, ISecurityRuleHeaderExpander { - DomainSecurityRule.ExpandedRolesSecurityRule FullRoleExpand(DomainSecurityRule.RoleBaseSecurityRule securityRule); + DomainSecurityRule.ExpandedRoleGroupSecurityRule FullRoleExpand(DomainSecurityRule.RoleBaseSecurityRule securityRule); DomainSecurityRule FullDomainExpand(DomainSecurityRule securityRule); } diff --git a/src/SecuritySystem.Abstractions/SecurityRule/DomainSecurityRule.cs b/src/SecuritySystem.Abstractions/SecurityRule/DomainSecurityRule.cs index 5b0c31b..5fc9378 100644 --- a/src/SecuritySystem.Abstractions/SecurityRule/DomainSecurityRule.cs +++ b/src/SecuritySystem.Abstractions/SecurityRule/DomainSecurityRule.cs @@ -31,7 +31,7 @@ public abstract record DomainSecurityRule : SecurityRule public static implicit operator DomainSecurityRule(SecurityRole[] securityRoles) => securityRoles.ToSecurityRule(); - public static implicit operator DomainSecurityRule(RoleBaseSecurityRule[] securityRules) => securityRules.ToSecurityRule(); + public static implicit operator DomainSecurityRule(NonExpandedRolesSecurityRule[] securityRules) => securityRules.ToSecurityRule(); public record SecurityRuleHeader(string Name) : DomainSecurityRule { @@ -78,8 +78,6 @@ public abstract record RoleBaseSecurityRule : DomainSecurityRule, IRoleBaseSecur /// public HierarchicalExpandType? CustomExpandType { get; init; } = null; - public SecurityRuleCredential? CustomCredential { get; init; } = null; - public SecurityPathRestriction? CustomRestriction { get; init; } = null; public HierarchicalExpandType GetSafeExpandType () => this.CustomExpandType ?? HierarchicalExpandType.Children; @@ -99,13 +97,18 @@ public bool EqualsCustoms(RoleBaseSecurityRule other) && this.CustomRestriction == other.CustomRestriction; } + public bool HasDefaultCustoms() + { + return this.CustomExpandType is null && this.CustomCredential is null && this.CustomRestriction is null; + } + public static implicit operator RoleBaseSecurityRule(SecurityOperation securityOperation) => securityOperation.ToSecurityRule(); public static implicit operator RoleBaseSecurityRule(SecurityRole securityRole) => securityRole.ToSecurityRule(); public static implicit operator RoleBaseSecurityRule(SecurityRole[] securityRoles) => securityRoles.ToSecurityRule(); - public static implicit operator RoleBaseSecurityRule(RoleBaseSecurityRule[] securityRules) => securityRules.ToSecurityRule(); + public static implicit operator RoleBaseSecurityRule(NonExpandedRolesSecurityRule[] securityRules) => securityRules.ToSecurityRule(); } public interface IRoleBaseSecurityRuleCustomData @@ -117,12 +120,29 @@ public interface IRoleBaseSecurityRuleCustomData public SecurityPathRestriction? CustomRestriction { get; } } - public record RoleGroupSecurityRule(DeepEqualsCollection Children) : RoleBaseSecurityRule; - public record AnyRoleSecurityRule : RoleBaseSecurityRule; public record RoleFactorySecurityRule(Type RoleFactoryType) : RoleBaseSecurityRule; + public record NonExpandedRoleGroupSecurityRule(DeepEqualsCollection Children) : RoleBaseSecurityRule + { + public NonExpandedRoleGroupSecurityRule(IEnumerable children) + : this(children.ToArray()) + { + } + } + + public record ExpandedRoleGroupSecurityRule(DeepEqualsCollection Children) : RoleBaseSecurityRule + { + public ExpandedRoleGroupSecurityRule(IEnumerable children) + : this(children.ToArray()) + { + } + + public IEnumerable GetActualChildren() => + this.Children.Select(c => c.ApplyCustoms(this)); + } + public record OperationSecurityRule(SecurityOperation SecurityOperation) : RoleBaseSecurityRule { public override string ToString() => this.SecurityOperation.Name; @@ -144,11 +164,11 @@ public override string ToString() => this.SecurityRoles.Count == 1 public static implicit operator NonExpandedRolesSecurityRule(SecurityRole[] securityRoles) => securityRoles.ToSecurityRule(); - public static NonExpandedRolesSecurityRule operator +(NonExpandedRolesSecurityRule rule1, NonExpandedRolesSecurityRule rule2) + public static RoleBaseSecurityRule operator +(NonExpandedRolesSecurityRule rule1, NonExpandedRolesSecurityRule rule2) { if (!rule1.EqualsCustoms(rule2)) { - throw new InvalidOperationException("Diff customs"); + return new NonExpandedRoleGroupSecurityRule([rule1, rule2]); } else { @@ -163,22 +183,22 @@ public override string ToString() => this.SecurityRoles.Count == 1 /// Список развёрнутых ролей public record ExpandedRolesSecurityRule(DeepEqualsCollection SecurityRoles) : RoleBaseSecurityRule { - public static ExpandedRolesSecurityRule Empty { get; } = Create([]); + public ExpandedRolesSecurityRule(IEnumerable securityRoles) + :this(securityRoles.ToArray()) + { + } + + public static ExpandedRolesSecurityRule Empty { get; } = new([]); public override string ToString() => this.SecurityRoles.Count == 1 ? this.SecurityRoles.Single().Name : $"[{this.SecurityRoles.Join(", ", sr => sr.Name)}]"; - public static ExpandedRolesSecurityRule Create(IEnumerable securityRoles) - { - return new ExpandedRolesSecurityRule(securityRoles.ToArray()); - } - - public static ExpandedRolesSecurityRule operator +(ExpandedRolesSecurityRule rule1, ExpandedRolesSecurityRule rule2) + public static RoleBaseSecurityRule operator +(ExpandedRolesSecurityRule rule1, ExpandedRolesSecurityRule rule2) { if (!rule1.EqualsCustoms(rule2)) { - throw new InvalidOperationException("Diff customs"); + return new ExpandedRoleGroupSecurityRule([rule1, rule2]); } else { diff --git a/src/SecuritySystem.Abstractions/SecurityRule/SecurityRule.cs b/src/SecuritySystem.Abstractions/SecurityRule/SecurityRule.cs index 7007956..ac435d0 100644 --- a/src/SecuritySystem.Abstractions/SecurityRule/SecurityRule.cs +++ b/src/SecuritySystem.Abstractions/SecurityRule/SecurityRule.cs @@ -5,6 +5,9 @@ namespace SecuritySystem; public abstract record SecurityRule { + public SecurityRuleCredential? CustomCredential { get; init; } + + /// /// Правило доступа для просмотра объекта /// @@ -27,7 +30,7 @@ public abstract record SecurityRule public static implicit operator SecurityRule(SecurityRole[] securityRoles) => securityRoles.ToSecurityRule(); - public static implicit operator SecurityRule(DomainSecurityRule.RoleBaseSecurityRule[] securityRules) => securityRules.ToSecurityRule(); + public static implicit operator SecurityRule(DomainSecurityRule.NonExpandedRolesSecurityRule[] securityRules) => securityRules.ToSecurityRule(); public record ModeSecurityRule(string Name) : SecurityRule { @@ -35,6 +38,6 @@ public record ModeSecurityRule(string Name) : SecurityRule public DomainSecurityRule.DomainModeSecurityRule ToDomain() => this.ToDomain(typeof(TDomainObject)); - public DomainSecurityRule.DomainModeSecurityRule ToDomain(Type domainType) => new(domainType, this); + public DomainSecurityRule.DomainModeSecurityRule ToDomain(Type domainType) => new(domainType, this) { CustomCredential = this.CustomCredential }; } -} +} \ No newline at end of file diff --git a/src/SecuritySystem.Abstractions/SecurityRule/SecurityRuleExtensions.cs b/src/SecuritySystem.Abstractions/SecurityRule/SecurityRuleExtensions.cs index fb4455c..d3e95e2 100644 --- a/src/SecuritySystem.Abstractions/SecurityRule/SecurityRuleExtensions.cs +++ b/src/SecuritySystem.Abstractions/SecurityRule/SecurityRuleExtensions.cs @@ -59,9 +59,8 @@ public DomainSecurityRule Except(DomainSecurityRule otherSecurityRule) => public NonExpandedRolesSecurityRule ToSecurityRule( HierarchicalExpandType? customExpandType = null, - SecurityRuleCredential? customCredential = null, SecurityPathRestriction? customRestriction = null) => - new[] { securityRole }.ToSecurityRule(customExpandType, customCredential, customRestriction); + new[] { securityRole }.ToSecurityRule(customExpandType, customRestriction); } extension(SecurityOperation securityOperation) @@ -124,13 +123,11 @@ public DomainSecurityRule Except(DomainSecurityRule otherSecurityRule) => public NonExpandedRolesSecurityRule ToSecurityRule( HierarchicalExpandType? customExpandType = null, - SecurityRuleCredential? customCredential = null, SecurityPathRestriction? customRestriction = null) => new( securityRoles.OrderBy(sr => sr.Name).ToArray()) { CustomExpandType = customExpandType, - CustomCredential = customCredential, CustomRestriction = customRestriction }; } @@ -138,44 +135,71 @@ public NonExpandedRolesSecurityRule ToSecurityRule( extension(TSecurityRule securityRule) where TSecurityRule : RoleBaseSecurityRule { - public TSecurityRule TryApplyCredential(SecurityRuleCredential credential) => - securityRule.CustomCredential == null ? securityRule with { CustomCredential = credential } : securityRule; - public TSecurityRule WithoutRunAs() => securityRule with { CustomCredential = new SecurityRuleCredential.CurrentUserWithoutRunAsCredential() }; - public TSecurityRule TryApplyCustoms(HierarchicalExpandType? customExpandType = null, + public TSecurityRule ApplyCustoms(IRoleBaseSecurityRuleCustomData customData) => + + securityRule.ApplyCustoms(customData.CustomCredential, customData.CustomExpandType, customData.CustomRestriction); + + public TSecurityRule ApplyCustoms( SecurityRuleCredential? customCredential = null, + HierarchicalExpandType? customExpandType = null, SecurityPathRestriction? customRestriction = null) => - customExpandType is null && customCredential is null && customRestriction is null + securityRule + .ForceApply(customCredential) + .TryApply(customExpandType) + .TryApply(customRestriction); + + public TSecurityRule TryApply(SecurityPathRestriction? customRestriction) => + customRestriction == null || securityRule.CustomRestriction != null + ? securityRule + : securityRule with { CustomRestriction = customRestriction }; + + public TSecurityRule TryApply(HierarchicalExpandType? customExpandType) => + customExpandType == null || securityRule.CustomExpandType != null + ? securityRule + : securityRule with { CustomExpandType = customExpandType }; + } + + + extension(TSecurityRule securityRule) + where TSecurityRule : SecurityRule + { + public TSecurityRule TryApply(SecurityRuleCredential? customCredential) => + customCredential == null || securityRule.CustomCredential != null ? securityRule - : securityRule with - { - CustomExpandType = securityRule.CustomExpandType ?? customExpandType, - CustomCredential = securityRule.CustomCredential ?? customCredential, - CustomRestriction = securityRule.CustomRestriction ?? customRestriction, - }; - - public TSecurityRule TryApplyCustoms(IRoleBaseSecurityRuleCustomData customSource) => - securityRule.TryApplyCustoms(customSource.CustomExpandType, customSource.CustomCredential, customSource.CustomRestriction); + : securityRule with { CustomCredential = customCredential }; + + public TSecurityRule ForceApply(SecurityRuleCredential? customCredential) => + customCredential == null || customCredential == securityRule.CustomCredential + ? securityRule + : securityRule with { CustomCredential = customCredential }; + + public TSecurityRule WithDefaultCredential() => + securityRule with { CustomCredential = null }; + + public TResult WithDefaultCredential(Func selector) + where TResult : SecurityRule => + selector(securityRule.WithDefaultCredential()).ForceApply(securityRule.CustomCredential); } public static RoleBaseSecurityRule ToSecurityRule( - this IEnumerable securityRules, - HierarchicalExpandType? customExpandType = null, + this IEnumerable securityRules, SecurityRuleCredential? customCredential = null, + HierarchicalExpandType? customExpandType = null, SecurityPathRestriction? customRestriction = null) { var cache = securityRules.ToList(); if (cache.Count == 1) { - return cache.Single().TryApplyCustoms(customExpandType, customCredential, customRestriction); + return cache.Single().ApplyCustoms(customCredential, customExpandType, customRestriction); } else { - return new RoleGroupSecurityRule(cache.ToArray()) + return new NonExpandedRoleGroupSecurityRule(cache) { CustomExpandType = customExpandType, CustomCredential = customCredential, diff --git a/src/SecuritySystem.Abstractions/SecurityRuleInfo/IDomainSecurityRoleExtractor.cs b/src/SecuritySystem.Abstractions/SecurityRuleInfo/IDomainSecurityRoleExtractor.cs index bbefff7..4292599 100644 --- a/src/SecuritySystem.Abstractions/SecurityRuleInfo/IDomainSecurityRoleExtractor.cs +++ b/src/SecuritySystem.Abstractions/SecurityRuleInfo/IDomainSecurityRoleExtractor.cs @@ -4,5 +4,5 @@ public interface IDomainSecurityRoleExtractor { IEnumerable ExtractSecurityRoles(DomainSecurityRule securityRule); - DomainSecurityRule.RoleBaseSecurityRule ExtractSecurityRule(DomainSecurityRule securityRule); + DomainSecurityRule.ExpandedRoleGroupSecurityRule ExtractSecurityRule(DomainSecurityRule securityRule); } diff --git a/src/SecuritySystem.Abstractions/Services/ISecurityRolesIdentsResolver.cs b/src/SecuritySystem.Abstractions/Services/ISecurityRolesIdentsResolver.cs index 8056252..8822fcd 100644 --- a/src/SecuritySystem.Abstractions/Services/ISecurityRolesIdentsResolver.cs +++ b/src/SecuritySystem.Abstractions/Services/ISecurityRolesIdentsResolver.cs @@ -2,5 +2,5 @@ public interface ISecurityRolesIdentsResolver { - Dictionary Resolve(DomainSecurityRule.RoleBaseSecurityRule securityRule, bool includeVirtual = false); + IReadOnlyDictionary Resolve(DomainSecurityRule.RoleBaseSecurityRule securityRule, bool includeVirtual = false); } \ No newline at end of file diff --git a/src/SecuritySystem.DiTests/SecurityRoleTests.cs b/src/SecuritySystem.DiTests/SecurityRoleTests.cs index 29c91fd..c2c1eed 100644 --- a/src/SecuritySystem.DiTests/SecurityRoleTests.cs +++ b/src/SecuritySystem.DiTests/SecurityRoleTests.cs @@ -1,4 +1,5 @@ using HierarchicalExpand; + using Microsoft.Extensions.DependencyInjection; using SecuritySystem.DiTests.Rules; @@ -25,16 +26,21 @@ public void AdministratorRole_ShouldNotContains_SystemIntegrationRole() public void SecurityRoleExpander_ExpandDeepChild_AllRolesExpanded() { // Arrange - var expander = this.RootServiceProvider.GetRequiredService(); + var expander = this.RootServiceProvider.GetRequiredService(); + + var expectedResult = new DomainSecurityRule.ExpandedRoleGroupSecurityRule( + [ + new DomainSecurityRule.ExpandedRolesSecurityRule([ExampleSecurityRole.TestRole, ExampleSecurityRole.TestRole2, ExampleSecurityRole.TestRole3]) + { CustomRestriction = SecurityPathRestriction.Default }, + + new DomainSecurityRule.ExpandedRolesSecurityRule([SecurityRole.Administrator]) { CustomRestriction = SecurityPathRestriction.Ignored }, + ]); // Act var expandResult = expander.Expand(ExampleSecurityRole.TestRole3); // Assert - expandResult.SecurityRoles.Should().BeEquivalentTo( - [ - SecurityRole.Administrator, ExampleSecurityRole.TestRole, ExampleSecurityRole.TestRole2, ExampleSecurityRole.TestRole3 - ]); + expandResult.Should().BeEquivalentTo(expectedResult); } [Fact] @@ -69,15 +75,22 @@ public void SecurityRoleExpander_FullExpandWithCustomExpandType_SecurityRuleCorr // Arrange var expander = this.RootServiceProvider.GetRequiredService(); + var customExpandType = HierarchicalExpandType.All; + + var expectedResult = new DomainSecurityRule.ExpandedRoleGroupSecurityRule( + [ + new DomainSecurityRule.ExpandedRolesSecurityRule([ExampleSecurityRole.TestRole]) + { CustomRestriction = SecurityPathRestriction.Default, CustomExpandType = customExpandType }, + + new DomainSecurityRule.ExpandedRolesSecurityRule([SecurityRole.Administrator]) + { CustomRestriction = SecurityPathRestriction.Ignored } + ]); + // Act - var expandResult = expander.FullRoleExpand(ExampleSecurityOperation.EmployeeView.ToSecurityRule(HierarchicalExpandType.All)); + var expandResult = expander.FullRoleExpand(ExampleSecurityOperation.EmployeeView.ToSecurityRule(customExpandType)); // Assert - expandResult.Should() - .Subject - .Should() - .BeEquivalentTo( - new[] { SecurityRole.Administrator, ExampleSecurityRole.TestRole }.ToSecurityRule(HierarchicalExpandType.All)); + expandResult.Should().BeEquivalentTo(expectedResult); } [Fact] @@ -86,14 +99,21 @@ public void SecurityRoleExpander_FullExpandWithCustomExpandTypeFromOperations_Se // Arrange var expander = this.RootServiceProvider.GetRequiredService(); + var customExpandType = HierarchicalExpandType.None; + // Act var expandResult = expander.FullRoleExpand(ExampleSecurityOperation.BusinessUnitView); + var expectedResult = new DomainSecurityRule.ExpandedRoleGroupSecurityRule( + [ + new DomainSecurityRule.ExpandedRolesSecurityRule([ExampleSecurityRole.TestRole4]) + { CustomRestriction = SecurityPathRestriction.Default, CustomExpandType = customExpandType }, + + new DomainSecurityRule.ExpandedRolesSecurityRule([SecurityRole.Administrator]) + { CustomRestriction = SecurityPathRestriction.Ignored } + ]); + // Assert - expandResult.Should() - .Subject - .Should() - .BeEquivalentTo( - new[] { SecurityRole.Administrator, ExampleSecurityRole.TestRole4 }.ToSecurityRule(HierarchicalExpandType.None)); + expandResult.Should().BeEquivalentTo(expectedResult); } } \ No newline at end of file diff --git a/src/SecuritySystem.DiTests/Services/ExamplePermissionSource.cs b/src/SecuritySystem.DiTests/Services/ExamplePermissionSource.cs index fb10084..5f83200 100644 --- a/src/SecuritySystem.DiTests/Services/ExamplePermissionSource.cs +++ b/src/SecuritySystem.DiTests/Services/ExamplePermissionSource.cs @@ -4,13 +4,13 @@ namespace SecuritySystem.DiTests.Services; -public class ExamplePermissionSource(TestPermissionData data, DomainSecurityRule.ExpandedRolesSecurityRule securityRule) : IPermissionSource +public class ExamplePermissionSource(TestPermissionData data, DomainSecurityRule.ExpandedRoleGroupSecurityRule securityRule) : IPermissionSource { public bool HasAccess() => throw new NotImplementedException(); public List> GetPermissions(IEnumerable _) { - var roles = securityRule.SecurityRoles.ToHashSet(); + var roles = securityRule.Children.SelectMany(c => c.SecurityRoles).ToHashSet(); var request = from permission in data.Permissions diff --git a/src/SecuritySystem.GeneralPermission/GeneralPermissionSource.cs b/src/SecuritySystem.GeneralPermission/GeneralPermissionSource.cs index 21bb7e5..f175311 100644 --- a/src/SecuritySystem.GeneralPermission/GeneralPermissionSource.cs +++ b/src/SecuritySystem.GeneralPermission/GeneralPermissionSource.cs @@ -2,12 +2,12 @@ using CommonFramework.GenericRepository; using CommonFramework.IdentitySource; using CommonFramework.VisualIdentitySource; +using CommonFramework.DependencyInjection; using SecuritySystem.ExternalSystem; using SecuritySystem.Services; using System.Linq.Expressions; -using CommonFramework.DependencyInjection; namespace SecuritySystem.GeneralPermission; diff --git a/src/SecuritySystem.GeneralPermission/GeneralPermissionSystem.cs b/src/SecuritySystem.GeneralPermission/GeneralPermissionSystem.cs index ff18de5..5a3b77e 100644 --- a/src/SecuritySystem.GeneralPermission/GeneralPermissionSystem.cs +++ b/src/SecuritySystem.GeneralPermission/GeneralPermissionSystem.cs @@ -3,17 +3,17 @@ using CommonFramework.IdentitySource; using GenericQueryable; + using SecuritySystem.ExternalSystem; using SecuritySystem.Services; namespace SecuritySystem.GeneralPermission; - public class GeneralPermissionSystem( IServiceProxyFactory serviceProxyFactory, IIdentityInfoSource identityInfoSource, IGeneralPermissionBindingInfoSource bindingInfoSource, - SecurityRuleCredential securityRuleCredential) : IPermissionSystem + SecurityRuleCredential defaultSecurityRuleCredential) : IPermissionSystem { private readonly Lazy> lazyInnerService = new(() => { @@ -30,7 +30,7 @@ public class GeneralPermissionSystem( innerServiceType, generalBindingInfo, securityRoleIdentityInfo, - securityRuleCredential); + defaultSecurityRuleCredential); }); private IPermissionSystem InnerService => this.lazyInnerService.Value; @@ -58,7 +58,7 @@ public class GeneralPermissionSystem generalBindingInfo, IAvailablePermissionSource availablePermissionSource, ISecurityRoleSource securityRoleSource, - SecurityRuleCredential securityRuleCredential, + SecurityRuleCredential defaultSecurityRuleCredential, IdentityInfo securityRoleIdentityInfo) : IPermissionSystem @@ -71,24 +71,23 @@ public class GeneralPermissionSystem GetRestrictionSource( SecurityContextRestrictionFilterInfo? restrictionFilterInfo) where TSecurityContext : class, ISecurityContext - where TSecurityContextIdent : notnull - { - return serviceProxyFactory + where TSecurityContextIdent : notnull => + + serviceProxyFactory .Create, GeneralPermissionRestrictionSource>( new Tuple?>(restrictionFilterInfo)); - } - public IPermissionSource GetPermissionSource(DomainSecurityRule.RoleBaseSecurityRule securityRule) - { - return serviceProxyFactory.Create, GeneralPermissionSource>( - securityRule.TryApplyCredential(securityRuleCredential)); - } + + public IPermissionSource GetPermissionSource(DomainSecurityRule.RoleBaseSecurityRule securityRule) => + + serviceProxyFactory.Create, GeneralPermissionSource>( + securityRule.TryApply(defaultSecurityRuleCredential)); public async Task> GetAvailableSecurityRoles(CancellationToken cancellationToken) { var dbRolesIdents = await availablePermissionSource - .GetQueryable(DomainSecurityRule.AnyRole with { CustomCredential = securityRuleCredential }) + .GetQueryable(DomainSecurityRule.AnyRole with { CustomCredential = defaultSecurityRuleCredential }) .Select(generalBindingInfo.SecurityRole.Path.Select(securityRoleIdentityInfo.Id.Path)) .Distinct() .GenericToListAsync(cancellationToken); diff --git a/src/SecuritySystem.GeneralPermission/GeneralPrincipalSourceService.cs b/src/SecuritySystem.GeneralPermission/GeneralPrincipalSourceService.cs index 001f972..72ac4e5 100644 --- a/src/SecuritySystem.GeneralPermission/GeneralPrincipalSourceService.cs +++ b/src/SecuritySystem.GeneralPermission/GeneralPrincipalSourceService.cs @@ -12,53 +12,53 @@ namespace SecuritySystem.GeneralPermission; public class GeneralPrincipalSourceService( - IQueryableSource queryableSource, - IVisualIdentityInfoSource visualIdentityInfoSource, - IAvailablePrincipalSource availablePrincipalSource, - IManagedPrincipalHeaderConverter principalHeaderConverter, + IQueryableSource queryableSource, + IVisualIdentityInfoSource visualIdentityInfoSource, + IAvailablePrincipalSource availablePrincipalSource, + IManagedPrincipalHeaderConverter principalHeaderConverter, IManagedPrincipalConverter principalConverter, IUserQueryableSource userQueryableSource) : IPrincipalSourceService - where TPrincipal : class + where TPrincipal : class { - private readonly PropertyAccessors nameAccessors = visualIdentityInfoSource.GetVisualIdentityInfo().Name; + private readonly PropertyAccessors nameAccessors = visualIdentityInfoSource.GetVisualIdentityInfo().Name; - private readonly IQueryable principalQueryable = queryableSource.GetQueryable(); + private readonly IQueryable principalQueryable = queryableSource.GetQueryable(); public Type PrincipalType { get; } = typeof(TPrincipal); public async Task> GetPrincipalsAsync(string nameFilter, int limit, CancellationToken cancellationToken) - { - return await principalQueryable - .Pipe( - !string.IsNullOrWhiteSpace(nameFilter), - q => q.Where(this.nameAccessors.Path.Select(principalName => principalName.Contains(nameFilter)))) - .Select(principalHeaderConverter.ConvertExpression) - .GenericToListAsync(cancellationToken); - } + { + return await principalQueryable + .Pipe( + !string.IsNullOrWhiteSpace(nameFilter), + q => q.Where(this.nameAccessors.Path.Select(principalName => principalName.Contains(nameFilter)))) + .Select(principalHeaderConverter.ConvertExpression) + .GenericToListAsync(cancellationToken); + } - public async Task TryGetPrincipalAsync(UserCredential userCredential, CancellationToken cancellationToken) - { - var principal = await userQueryableSource.GetQueryable(userCredential).GenericSingleOrDefaultAsync(cancellationToken); + public async Task TryGetPrincipalAsync(UserCredential userCredential, CancellationToken cancellationToken) + { + var principal = await userQueryableSource.GetQueryable(userCredential).GenericSingleOrDefaultAsync(cancellationToken); - if (principal is null) - { - return null; - } - else - { - return await principalConverter.ToManagedPrincipalAsync(principal, cancellationToken); - } - } + if (principal is null) + { + return null; + } + else + { + return await principalConverter.ToManagedPrincipalAsync(principal, cancellationToken); + } + } - public async Task> GetLinkedPrincipalsAsync(IEnumerable securityRoles, CancellationToken cancellationToken) - { - return await availablePrincipalSource.GetAvailablePrincipalsQueryable( - DomainSecurityRule.ExpandedRolesSecurityRule.Create(securityRoles) with - { - CustomCredential = new SecurityRuleCredential.AnyUserCredential() - }) - .Select(this.nameAccessors.Path) + public async Task> GetLinkedPrincipalsAsync(IEnumerable securityRoles, CancellationToken cancellationToken) + { + return await availablePrincipalSource.GetAvailablePrincipalsQueryable( + new DomainSecurityRule.ExpandedRolesSecurityRule(securityRoles) + { + CustomCredential = new SecurityRuleCredential.AnyUserCredential() + }) + .Select(this.nameAccessors.Path) .Distinct() .GenericToListAsync(cancellationToken); - } + } } \ No newline at end of file diff --git a/src/SecuritySystem.GeneralPermission/PermissionSecurityRoleFilterFactory.cs b/src/SecuritySystem.GeneralPermission/PermissionSecurityRoleFilterFactory.cs index 72e6438..f974358 100644 --- a/src/SecuritySystem.GeneralPermission/PermissionSecurityRoleFilterFactory.cs +++ b/src/SecuritySystem.GeneralPermission/PermissionSecurityRoleFilterFactory.cs @@ -1,10 +1,10 @@ using CommonFramework; using CommonFramework.IdentitySource; +using CommonFramework.DependencyInjection; using SecuritySystem.Services; using System.Linq.Expressions; -using CommonFramework.DependencyInjection; namespace SecuritySystem.GeneralPermission; diff --git a/src/SecuritySystem.VirtualPermission/VirtualPermissionSource.cs b/src/SecuritySystem.VirtualPermission/VirtualPermissionSource.cs index c601546..93222b3 100644 --- a/src/SecuritySystem.VirtualPermission/VirtualPermissionSource.cs +++ b/src/SecuritySystem.VirtualPermission/VirtualPermissionSource.cs @@ -13,14 +13,12 @@ namespace SecuritySystem.VirtualPermission; - public class VirtualPermissionSource( IServiceProxyFactory serviceProxyFactory, IVisualIdentityInfoSource visualIdentityInfoSource, IPermissionBindingInfoSource bindingInfoSource, VirtualPermissionBindingInfo virtualBindingInfo, - DomainSecurityRule.RoleBaseSecurityRule securityRule, - SecurityRuleCredential defaultSecurityRuleCredential) : IPermissionSource + DomainSecurityRule.RoleBaseSecurityRule securityRule) : IPermissionSource where TPermission : class { private readonly Lazy> lazyInnerService = new(() => @@ -38,8 +36,7 @@ public class VirtualPermissionSource( bindingInfo, virtualBindingInfo, principalVisualIdentityInfo, - securityRule, - defaultSecurityRuleCredential); + securityRule); }); private IPermissionSource InnerService => this.lazyInnerService.Value; diff --git a/src/SecuritySystem.VirtualPermission/VirtualPermissionSystem.cs b/src/SecuritySystem.VirtualPermission/VirtualPermissionSystem.cs index 59f4dc1..cb392e9 100644 --- a/src/SecuritySystem.VirtualPermission/VirtualPermissionSystem.cs +++ b/src/SecuritySystem.VirtualPermission/VirtualPermissionSystem.cs @@ -31,10 +31,10 @@ public IPermissionRestrictionSource GetRestr public IPermissionSource GetPermissionSource(DomainSecurityRule.RoleBaseSecurityRule securityRule) { - if (securityRuleExpander.FullRoleExpand(securityRule).SecurityRoles.Contains(virtualBindingInfo.SecurityRole)) + if (securityRuleExpander.FullRoleExpand(securityRule).Children.SelectMany(c => c.SecurityRoles).Contains(virtualBindingInfo.SecurityRole)) { - return serviceProxyFactory.Create, VirtualPermissionSource>(virtualBindingInfo, securityRule, - securityRuleCredential); + return serviceProxyFactory.Create, VirtualPermissionSource>(virtualBindingInfo, + securityRule with { CustomCredential = securityRuleCredential }); } else { diff --git a/src/SecuritySystem/Builders/_Factory/FilterBuilderFactoryBase.cs b/src/SecuritySystem/Builders/_Factory/FilterBuilderFactoryBase.cs index 8775203..40cff93 100644 --- a/src/SecuritySystem/Builders/_Factory/FilterBuilderFactoryBase.cs +++ b/src/SecuritySystem/Builders/_Factory/FilterBuilderFactoryBase.cs @@ -31,9 +31,9 @@ public virtual TBuilder CreateBuilder( .CreateGenericMethod(securityPathType.GetGenericArguments().Skip(1).ToArray()) .Invoke(this, baseSecurityPath, securityContextRestrictions); } - else if (securityPathType.BaseType.Maybe(baseType => baseType.IsGenericTypeImplementation(typeof(SecurityPath<>)))) + else if (baseSecurityPath is IContextSecurityPath contextSecurityPath) { - var securityContextType = securityPathType.GetGenericArguments().Skip(1).Single(); + var securityContextType = contextSecurityPath.SecurityContextType; var restrictionFilterInfo = securityContextRestrictions.SingleOrDefault(v => v.SecurityContextType == securityContextType); diff --git a/src/SecuritySystem/DependencyInjection/SecuritySystemSettings.cs b/src/SecuritySystem/DependencyInjection/SecuritySystemSettings.cs index 35e95fd..b2b16e4 100644 --- a/src/SecuritySystem/DependencyInjection/SecuritySystemSettings.cs +++ b/src/SecuritySystem/DependencyInjection/SecuritySystemSettings.cs @@ -4,7 +4,9 @@ using CommonFramework.IdentitySource.DependencyInjection; using CommonFramework.RelativePath; using CommonFramework.VisualIdentitySource.DependencyInjection; + using HierarchicalExpand.DependencyInjection; + using Microsoft.Extensions.DependencyInjection; using SecuritySystem.AccessDenied; using SecuritySystem.DependencyInjection.Domain; diff --git a/src/SecuritySystem/DependencyInjection/ServiceCollectionExtensions.cs b/src/SecuritySystem/DependencyInjection/ServiceCollectionExtensions.cs index e980deb..ba561d2 100644 --- a/src/SecuritySystem/DependencyInjection/ServiceCollectionExtensions.cs +++ b/src/SecuritySystem/DependencyInjection/ServiceCollectionExtensions.cs @@ -103,11 +103,13 @@ private IServiceCollection RegisterGeneralServices() .AddSingleton() .AddSingleton() + .AddSingleton() + .AddSingleton() .AddSingleton() .AddSingleton() .AddSingleton() - .AddSingleton() + .AddSingleton() .AddSingleton() .AddSingleton() .AddSingleton() diff --git a/src/SecuritySystem/DomainServices/ContextDomainSecurityService.cs b/src/SecuritySystem/DomainServices/ContextDomainSecurityService.cs index 92c3091..6472bfc 100644 --- a/src/SecuritySystem/DomainServices/ContextDomainSecurityService.cs +++ b/src/SecuritySystem/DomainServices/ContextDomainSecurityService.cs @@ -1,7 +1,5 @@ using SecuritySystem.Expanders; using SecuritySystem.Providers; - - using SecuritySystem.Services; namespace SecuritySystem.DomainServices; diff --git a/src/SecuritySystem/DomainServices/DependencySecurity/DependencyDomainSecurityService.cs b/src/SecuritySystem/DomainServices/DependencySecurity/DependencyDomainSecurityService.cs index 58ae4ef..eb2673a 100644 --- a/src/SecuritySystem/DomainServices/DependencySecurity/DependencyDomainSecurityService.cs +++ b/src/SecuritySystem/DomainServices/DependencySecurity/DependencyDomainSecurityService.cs @@ -13,16 +13,11 @@ public class DependencyDomainSecurityService( IDomainSecurityService baseDomainSecurityService, IQueryableSource queryableSource, IRelativeDomainPathInfo relativeDomainPathInfo) - : DependencyDomainSecurityServiceBase( - securityRuleExpander, - baseDomainSecurityService) + : DependencyDomainSecurityServiceBase(securityRuleExpander, baseDomainSecurityService) where TBaseDomainObject : class { protected override ISecurityProvider CreateDependencySecurityProvider(ISecurityProvider baseProvider) { - return new DependencySecurityProvider( - baseProvider, - relativeDomainPathInfo, - queryableSource); + return new DependencySecurityProvider(baseProvider, relativeDomainPathInfo, queryableSource); } -} +} \ No newline at end of file diff --git a/src/SecuritySystem/DomainServices/DomainSecurityService.cs b/src/SecuritySystem/DomainServices/DomainSecurityService.cs index d0aa30f..a83703b 100644 --- a/src/SecuritySystem/DomainServices/DomainSecurityService.cs +++ b/src/SecuritySystem/DomainServices/DomainSecurityService.cs @@ -1,7 +1,6 @@ using SecuritySystem.Expanders; using SecuritySystem.Providers; - namespace SecuritySystem.DomainServices; public abstract class DomainSecurityService(ISecurityRuleExpander securityRuleExpander) : DomainSecurityServiceBase diff --git a/src/SecuritySystem/Expanders/ClientSecurityRuleExpander.cs b/src/SecuritySystem/Expanders/ClientSecurityRuleExpander.cs index bfce418..b2ab3c7 100644 --- a/src/SecuritySystem/Expanders/ClientSecurityRuleExpander.cs +++ b/src/SecuritySystem/Expanders/ClientSecurityRuleExpander.cs @@ -4,14 +4,13 @@ namespace SecuritySystem.Expanders; public class ClientSecurityRuleExpander(IClientSecurityRuleInfoSource clientSecurityRuleInfoSource) : IClientSecurityRuleExpander { - private readonly IReadOnlyDictionary dict = clientSecurityRuleInfoSource - .GetInfos() - .ToDictionary(info => info.Rule, info => info.Implementation); + private readonly IReadOnlyDictionary dict = + clientSecurityRuleInfoSource.GetInfos().ToDictionary(info => info.Rule, info => info.Implementation); - - public DomainSecurityRule Expand(DomainSecurityRule.ClientSecurityRule securityRule) + public DomainSecurityRule Expand(DomainSecurityRule.ClientSecurityRule baseSecurityRule) { - return this.dict.GetValueOrDefault(securityRule) - ?? throw new ArgumentOutOfRangeException(nameof(securityRule), $"{nameof(DomainSecurityRule.ClientSecurityRule)} with name \"{securityRule.Name}\" not found"); + return baseSecurityRule.WithDefaultCredential(securityRule => + this.dict.GetValueOrDefault(securityRule) ?? throw new ArgumentOutOfRangeException(nameof(securityRule), + $"{nameof(DomainSecurityRule.ClientSecurityRule)} with name \"{securityRule.Name}\" not found")); } -} +} \ No newline at end of file diff --git a/src/SecuritySystem/Expanders/ExpandedRoleGroupSecurityRuleSetOptimizer.cs b/src/SecuritySystem/Expanders/ExpandedRoleGroupSecurityRuleSetOptimizer.cs new file mode 100644 index 0000000..ce835d8 --- /dev/null +++ b/src/SecuritySystem/Expanders/ExpandedRoleGroupSecurityRuleSetOptimizer.cs @@ -0,0 +1,39 @@ + +namespace SecuritySystem.Expanders; + +public class ExpandedRoleGroupSecurityRuleSetOptimizer(ISecurityRoleSource securityRoleSource) : IExpandedRoleGroupSecurityRuleSetOptimizer +{ + public DomainSecurityRule.ExpandedRoleGroupSecurityRule Optimize(IEnumerable roleRules) => + this.Optimize([new DomainSecurityRule.ExpandedRoleGroupSecurityRule(roleRules)]); + + public DomainSecurityRule.ExpandedRoleGroupSecurityRule Optimize(IEnumerable roleRuleGroups) + { + var request = + + from roleRuleGroup in roleRuleGroups + + from roleRule in roleRuleGroup.Children + + from role in roleRule.SecurityRoles + + let roleInfo = securityRoleSource.GetSecurityRole(role) + + group role by new + { + CustomCredential = roleRuleGroup.CustomCredential ?? roleRule.CustomCredential, + CustomExpandType = roleRuleGroup.CustomExpandType ?? roleRule.CustomExpandType ?? roleInfo.Information.CustomExpandType, + CustomRestriction = roleRuleGroup.CustomRestriction ?? roleRule.CustomRestriction ?? roleInfo.Information.Restriction + } + + into g + + select new DomainSecurityRule.ExpandedRolesSecurityRule(g.Distinct()) + { + CustomCredential = g.Key.CustomCredential, + CustomExpandType = g.Key.CustomExpandType, + CustomRestriction = g.Key.CustomRestriction + }; + + return new(request); + } +} \ No newline at end of file diff --git a/src/SecuritySystem/Expanders/IExpandedRoleGroupSecurityRuleSetOptimizer.cs b/src/SecuritySystem/Expanders/IExpandedRoleGroupSecurityRuleSetOptimizer.cs new file mode 100644 index 0000000..d46af1c --- /dev/null +++ b/src/SecuritySystem/Expanders/IExpandedRoleGroupSecurityRuleSetOptimizer.cs @@ -0,0 +1,8 @@ +namespace SecuritySystem.Expanders; + +public interface IExpandedRoleGroupSecurityRuleSetOptimizer +{ + DomainSecurityRule.ExpandedRoleGroupSecurityRule Optimize(IEnumerable roleRules); + + DomainSecurityRule.ExpandedRoleGroupSecurityRule Optimize(IEnumerable roleRules); +} \ No newline at end of file diff --git a/src/SecuritySystem/Expanders/RoleFactorySecurityRuleExpander.cs b/src/SecuritySystem/Expanders/RoleFactorySecurityRuleExpander.cs index 005caf0..359be95 100644 --- a/src/SecuritySystem/Expanders/RoleFactorySecurityRuleExpander.cs +++ b/src/SecuritySystem/Expanders/RoleFactorySecurityRuleExpander.cs @@ -10,6 +10,6 @@ public DomainSecurityRule.RoleBaseSecurityRule Expand(DomainSecurityRule.RoleFac { var factory = (IFactory)serviceProvider.GetRequiredService(securityRule.RoleFactoryType); - return factory.Create().TryApplyCustoms(securityRule); + return factory.Create().ApplyCustoms(securityRule); } } diff --git a/src/SecuritySystem/Expanders/RootSecurityRuleExpande.cs b/src/SecuritySystem/Expanders/RootSecurityRuleExpande.cs index 17569de..cbfd15d 100644 --- a/src/SecuritySystem/Expanders/RootSecurityRuleExpande.cs +++ b/src/SecuritySystem/Expanders/RootSecurityRuleExpande.cs @@ -5,13 +5,17 @@ namespace SecuritySystem.Expanders; public class RootSecurityRuleExpander( ISecurityModeExpander securityModeExpander, ISecurityOperationExpander securityOperationExpander, - ISecurityRoleExpander securityRoleExpander, + ISecurityRoleGroupExpander securityRoleGroupExpander, IRoleFactorySecurityRuleExpander roleFactorySecurityRuleExpander, ISecurityRoleSource securityRoleSource, IClientSecurityRuleExpander clientSecurityRuleExpander, ISecurityRuleHeaderExpander securityRuleHeaderExpander) : ISecurityRuleExpander { + private readonly Lazy anyRoleExpandedSecurityRule = new(() => + + new ([new(securityRoleSource.SecurityRoles)])); + public DomainSecurityRule? TryExpand(DomainSecurityRule.DomainModeSecurityRule securityRule) { return securityModeExpander.TryExpand(securityRule); @@ -19,42 +23,38 @@ public class RootSecurityRuleExpander( public DomainSecurityRule Expand(DomainSecurityRule.SecurityRuleHeader securityRuleHeader) => securityRuleHeaderExpander.Expand(securityRuleHeader); - public DomainSecurityRule Expand(DomainSecurityRule.ClientSecurityRule securityRule) - { - return clientSecurityRuleExpander.Expand(securityRule); - } + public DomainSecurityRule Expand(DomainSecurityRule.ClientSecurityRule securityRule) => + clientSecurityRuleExpander.Expand(securityRule); - public DomainSecurityRule.NonExpandedRolesSecurityRule Expand(DomainSecurityRule.OperationSecurityRule securityRule) - { - return securityOperationExpander.Expand(securityRule); - } + public DomainSecurityRule.NonExpandedRolesSecurityRule Expand(DomainSecurityRule.OperationSecurityRule securityRule) => + securityOperationExpander.Expand(securityRule); - public DomainSecurityRule.ExpandedRolesSecurityRule Expand(DomainSecurityRule.NonExpandedRolesSecurityRule securityRule) - { - return securityRoleExpander.Expand(securityRule); - } + public DomainSecurityRule.ExpandedRoleGroupSecurityRule Expand(DomainSecurityRule.NonExpandedRoleGroupSecurityRule securityRule) => + securityRoleGroupExpander.Expand(securityRule); + + public DomainSecurityRule.ExpandedRoleGroupSecurityRule Expand(DomainSecurityRule.NonExpandedRolesSecurityRule securityRule) => + securityRoleGroupExpander.Expand(securityRule); public DomainSecurityRule.RoleBaseSecurityRule Expand(DomainSecurityRule.RoleFactorySecurityRule securityRule) { return roleFactorySecurityRuleExpander.Expand(securityRule); } - public DomainSecurityRule.ExpandedRolesSecurityRule FullRoleExpand(DomainSecurityRule.RoleBaseSecurityRule securityRule) + public DomainSecurityRule.ExpandedRoleGroupSecurityRule FullRoleExpand(DomainSecurityRule.RoleBaseSecurityRule securityRule) { return securityRule switch { - DomainSecurityRule.AnyRoleSecurityRule => DomainSecurityRule.ExpandedRolesSecurityRule.Create(securityRoleSource.SecurityRoles) - .TryApplyCustoms(securityRule), + DomainSecurityRule.AnyRoleSecurityRule => this.anyRoleExpandedSecurityRule.Value.ApplyCustoms(securityRule), + + DomainSecurityRule.ExpandedRoleGroupSecurityRule expandedRoleGroupSecurityRule => expandedRoleGroupSecurityRule, - DomainSecurityRule.RoleGroupSecurityRule roleGroupSecurityRule => roleGroupSecurityRule.Children.Select(this.FullRoleExpand) - .Aggregate(DomainSecurityRule.ExpandedRolesSecurityRule.Empty, (r1, r2) => r1 + r2) - .TryApplyCustoms(securityRule), + DomainSecurityRule.NonExpandedRoleGroupSecurityRule roleGroupSecurityRule => this.Expand(roleGroupSecurityRule), DomainSecurityRule.OperationSecurityRule operationSecurityRule => this.Expand(this.Expand(operationSecurityRule)), DomainSecurityRule.NonExpandedRolesSecurityRule nonExpandedRolesSecurityRule => this.Expand(nonExpandedRolesSecurityRule), - DomainSecurityRule.ExpandedRolesSecurityRule expandedRolesSecurityRule => expandedRolesSecurityRule, + DomainSecurityRule.ExpandedRolesSecurityRule expandedRolesSecurityRule => new([expandedRolesSecurityRule]), DomainSecurityRule.RoleFactorySecurityRule dynamicRoleSecurityRule => this.FullRoleExpand(this.Expand(dynamicRoleSecurityRule)), diff --git a/src/SecuritySystem/Expanders/SecurityModeExpander.cs b/src/SecuritySystem/Expanders/SecurityModeExpander.cs index 4ce496b..44c3308 100644 --- a/src/SecuritySystem/Expanders/SecurityModeExpander.cs +++ b/src/SecuritySystem/Expanders/SecurityModeExpander.cs @@ -1,4 +1,6 @@ -using SecuritySystem.SecurityRuleInfo; +using CommonFramework; + +using SecuritySystem.SecurityRuleInfo; namespace SecuritySystem.Expanders; @@ -9,6 +11,6 @@ public class SecurityModeExpander(IEnumerable infoLi public DomainSecurityRule? TryExpand(DomainSecurityRule.DomainModeSecurityRule securityRule) { - return this.dict.GetValueOrDefault(securityRule); + return this.dict.GetValueOrDefault(securityRule.WithDefaultCredential()).Maybe(v => v with { CustomCredential = securityRule.CustomCredential }); } -} +} \ No newline at end of file diff --git a/src/SecuritySystem/Expanders/SecurityOperationExpander.cs b/src/SecuritySystem/Expanders/SecurityOperationExpander.cs index 3394a0d..8ed218b 100644 --- a/src/SecuritySystem/Expanders/SecurityOperationExpander.cs +++ b/src/SecuritySystem/Expanders/SecurityOperationExpander.cs @@ -1,33 +1,29 @@ -using CommonFramework.DictionaryCache; +using System.Collections.Concurrent; namespace SecuritySystem.Expanders; public class SecurityOperationExpander(ISecurityRoleSource securityRoleSource, ISecurityOperationInfoSource securityOperationInfoSource) : ISecurityOperationExpander { - private readonly IDictionaryCache cache = - new DictionaryCache( - securityRule => - { - var securityRoles = securityRoleSource.SecurityRoles - .Where(sr => sr.Information.Operations.Contains(securityRule.SecurityOperation)) - .ToArray(); - - if (securityRoles.Length == 0) - { - throw new ArgumentOutOfRangeException(nameof(securityRule), $"No security roles found for operation \"{securityRule.SecurityOperation}\""); - } + private readonly ConcurrentDictionary cache = new(); - return securityRoles.ToSecurityRule( - securityRule.CustomExpandType - ?? securityOperationInfoSource.GetSecurityOperationInfo(securityRule.SecurityOperation).CustomExpandType, - securityRule.CustomCredential, - securityRule.CustomRestriction); + public DomainSecurityRule.NonExpandedRolesSecurityRule Expand(DomainSecurityRule.OperationSecurityRule baseSecurityRule) + { + return baseSecurityRule.WithDefaultCredential(securityRule => this.cache.GetOrAdd(securityRule, _ => + { + var securityRoles = securityRoleSource.SecurityRoles + .Where(sr => sr.Information.Operations.Contains(securityRule.SecurityOperation)) + .ToArray(); - }).WithLock(); + if (securityRoles.Length == 0) + { + throw new ArgumentOutOfRangeException(nameof(securityRule), $"No security roles found for operation \"{securityRule.SecurityOperation}\""); + } - public DomainSecurityRule.NonExpandedRolesSecurityRule Expand(DomainSecurityRule.OperationSecurityRule securityRule) - { - return this.cache[securityRule]; + return securityRoles.ToSecurityRule( + securityRule.CustomExpandType + ?? securityOperationInfoSource.GetSecurityOperationInfo(securityRule.SecurityOperation).CustomExpandType, + securityRule.CustomRestriction); + })); } -} +} \ No newline at end of file diff --git a/src/SecuritySystem/Expanders/SecurityRoleExpander.cs b/src/SecuritySystem/Expanders/SecurityRoleExpander.cs index d28700f..060242b 100644 --- a/src/SecuritySystem/Expanders/SecurityRoleExpander.cs +++ b/src/SecuritySystem/Expanders/SecurityRoleExpander.cs @@ -1,43 +1,49 @@ using CommonFramework; -using CommonFramework.DictionaryCache; + +using System.Collections.Concurrent; namespace SecuritySystem.Expanders; -public class SecurityRoleExpander : ISecurityRoleExpander +public class SecurityRoleGroupExpander(ISecurityRoleSource securityRoleSource, IExpandedRoleGroupSecurityRuleSetOptimizer setOptimizer) + : ISecurityRoleGroupExpander { - private readonly IDictionaryCache - expandCache; - - public SecurityRoleExpander(ISecurityRoleSource securityRoleSource) - { - this.expandCache = - new DictionaryCache( - securityRule => - { - if (securityRule.SecurityRoles.Count == 0) - { - throw new ArgumentOutOfRangeException(nameof(securityRule), "The list of security roles cannot be empty"); - } - - var securityRoles = securityRoleSource.SecurityRoles - .Where( - sr => sr.GetAllElements( - c => c.Information.Children.Select( - securityRoleSource.GetSecurityRole)) - .IsIntersected(securityRule.SecurityRoles)) - .Concat(securityRule.SecurityRoles) - .Distinct() - .OrderBy(sr => sr.Name) - .ToArray(); - - return new DomainSecurityRule.ExpandedRolesSecurityRule(securityRoles.ToArray()) - .TryApplyCustoms(securityRule); - - }).WithLock(); - } - - public DomainSecurityRule.ExpandedRolesSecurityRule Expand(DomainSecurityRule.NonExpandedRolesSecurityRule securityRule) - { - return this.expandCache[securityRule]; - } -} + private readonly ConcurrentDictionary cache = new(); + + private readonly ConcurrentDictionary innerCache = new(); + + public DomainSecurityRule.ExpandedRoleGroupSecurityRule Expand(DomainSecurityRule.NonExpandedRoleGroupSecurityRule baseSecurityRule) => + + baseSecurityRule.WithDefaultCredential(securityRule => + + this.cache.GetOrAdd(securityRule, _ => + { + var request = + + from c in securityRule.Children + + let g = this.Expand(c) + + from r in g.Children + + select r.ApplyCustoms(g); + + return setOptimizer.Optimize(request); + })); + + public DomainSecurityRule.ExpandedRoleGroupSecurityRule Expand(DomainSecurityRule.NonExpandedRolesSecurityRule baseSecurityRule) => + + baseSecurityRule.WithDefaultCredential(securityRule => + + this.innerCache.GetOrAdd(securityRule, _ => + { + var otherSecurityRoles = securityRoleSource.SecurityRoles.Where(sr => + sr.GetAllElements(c => c.Information.Children.Select(securityRoleSource.GetSecurityRole)).IsIntersected(securityRule.SecurityRoles)) + .Distinct() + .Except(securityRule.SecurityRoles); + + return setOptimizer.Optimize([ + new DomainSecurityRule.ExpandedRolesSecurityRule(securityRule.SecurityRoles).ApplyCustoms(securityRule), + new(otherSecurityRoles) + ]); + })); +} \ No newline at end of file diff --git a/src/SecuritySystem/Expanders/SecurityRuleHeaderExpander.cs b/src/SecuritySystem/Expanders/SecurityRuleHeaderExpander.cs index 12ea059..43d407c 100644 --- a/src/SecuritySystem/Expanders/SecurityRuleHeaderExpander.cs +++ b/src/SecuritySystem/Expanders/SecurityRuleHeaderExpander.cs @@ -4,19 +4,15 @@ namespace SecuritySystem.Expanders; -public class SecurityRuleHeaderExpander : ISecurityRuleHeaderExpander +public class SecurityRuleHeaderExpander(IEnumerable securityRuleFullInfoList) : ISecurityRuleHeaderExpander { - private readonly IReadOnlyDictionary dict; + private readonly IReadOnlyDictionary dict = + securityRuleFullInfoList.ToDictionary(pair => pair.Header, pair => pair.Implementation); - public SecurityRuleHeaderExpander(IEnumerable securityRuleFullInfoList) - { - this.dict = securityRuleFullInfoList.ToDictionary(pair => pair.Header, pair => pair.Implementation); - } - - public DomainSecurityRule Expand(DomainSecurityRule.SecurityRuleHeader securityRuleHeader) - { - return this.dict.GetValue( - securityRuleHeader, - () => new ArgumentOutOfRangeException(nameof(securityRuleHeader), $"Implementation for {nameof(SecurityRule)} \"{securityRuleHeader}\" not found")); - } -} + public DomainSecurityRule Expand(DomainSecurityRule.SecurityRuleHeader baseSecurityRule) => + baseSecurityRule.WithDefaultCredential(securityRuleHeader => + this.dict.GetValue( + securityRuleHeader, + () => new ArgumentOutOfRangeException(nameof(securityRuleHeader), + $"Implementation for {nameof(SecurityRule)} \"{securityRuleHeader}\" not found"))); +} \ No newline at end of file diff --git a/src/SecuritySystem/SecurityRuleInfo/ClientSecurityRuleResolver.cs b/src/SecuritySystem/SecurityRuleInfo/ClientSecurityRuleResolver.cs index 78a0c82..300c0e7 100644 --- a/src/SecuritySystem/SecurityRuleInfo/ClientSecurityRuleResolver.cs +++ b/src/SecuritySystem/SecurityRuleInfo/ClientSecurityRuleResolver.cs @@ -1,4 +1,4 @@ -using CommonFramework.DictionaryCache; +using System.Collections.Concurrent; namespace SecuritySystem.SecurityRuleInfo; @@ -6,20 +6,19 @@ public class ClientSecurityRuleResolver( IDomainSecurityRoleExtractor domainSecurityRoleExtractor, IClientSecurityRuleInfoSource clientSecurityRuleInfoSource) : IClientSecurityRuleResolver { - private readonly IDictionaryCache> cache = - new DictionaryCache>( - securityRole => - { - var request = from clientSecurityRuleInfo in clientSecurityRuleInfoSource.GetInfos() + private readonly ConcurrentDictionary cache = new(); - let roles = domainSecurityRoleExtractor.ExtractSecurityRoles(clientSecurityRuleInfo.Implementation) + public IEnumerable Resolve(SecurityRole securityRole) => + this.cache.GetOrAdd(securityRole, _ => + { + var request = from clientSecurityRuleInfo in clientSecurityRuleInfoSource.GetInfos() - where roles.Contains(securityRole) + let roles = domainSecurityRoleExtractor.ExtractSecurityRoles(clientSecurityRuleInfo.Implementation) - select clientSecurityRuleInfo.Rule; + where roles.Contains(securityRole) - return request.ToList(); - }).WithLock(); + select clientSecurityRuleInfo.Rule; - public IEnumerable Resolve(SecurityRole securityRole) => this.cache[securityRole]; -} + return request.ToArray(); + }); +} \ No newline at end of file diff --git a/src/SecuritySystem/SecurityRuleInfo/DomainSecurityRoleExtractor.cs b/src/SecuritySystem/SecurityRuleInfo/DomainSecurityRoleExtractor.cs index d85fb82..f5fbd30 100644 --- a/src/SecuritySystem/SecurityRuleInfo/DomainSecurityRoleExtractor.cs +++ b/src/SecuritySystem/SecurityRuleInfo/DomainSecurityRoleExtractor.cs @@ -1,45 +1,39 @@ -using CommonFramework.DictionaryCache; +using System.Collections.Concurrent; using SecuritySystem.Expanders; using SecuritySystem.Services; namespace SecuritySystem.SecurityRuleInfo; -public class DomainSecurityRoleExtractor : IDomainSecurityRoleExtractor +public class DomainSecurityRoleExtractor(ISecurityRuleExpander expander, IExpandedRoleGroupSecurityRuleSetOptimizer securityRuleSetOptimizer) + : IDomainSecurityRoleExtractor { - private readonly IDictionaryCache rulesCache; + private readonly ConcurrentDictionary rulesCache = new(); - private readonly IDictionaryCache> rolesCache; + private readonly ConcurrentDictionary> rolesCache = new(); - public DomainSecurityRoleExtractor(ISecurityRuleExpander expander) - { - this.rulesCache = - new DictionaryCache( - securityRule => - { - var usedRules = new HashSet(); - - new ScanVisitor(usedRules).Visit(expander.FullDomainExpand(securityRule)); + public IEnumerable ExtractSecurityRoles(DomainSecurityRule securityRule) => + this.rolesCache.GetOrAdd(securityRule.WithDefaultCredential(), _ => + expander.FullRoleExpand(this.rulesCache[securityRule]).Children.SelectMany(c => c.SecurityRoles).ToHashSet()); - return usedRules.ToArray(); - }).WithLock(); + public DomainSecurityRule.ExpandedRoleGroupSecurityRule ExtractSecurityRule(DomainSecurityRule securityRule) => + this.rulesCache.GetOrAdd(securityRule, _ => + { + var usedRules = new HashSet(); - this.rolesCache = - new DictionaryCache>( - securityRule => expander.FullRoleExpand(this.rulesCache[securityRule]).SecurityRoles.ToHashSet()).WithLock(); - } + new ScanVisitor(usedRules).Visit(expander.FullDomainExpand(securityRule)); - public IEnumerable ExtractSecurityRoles(DomainSecurityRule securityRule) => this.rolesCache[securityRule]; + return securityRuleSetOptimizer.Optimize(usedRules); + }); - public DomainSecurityRule.RoleBaseSecurityRule ExtractSecurityRule(DomainSecurityRule securityRule) => this.rulesCache[securityRule]; - private class ScanVisitor(ISet usedRules) : SecurityRuleVisitor + private class ScanVisitor(ISet usedRules) : SecurityRuleVisitor { - protected override DomainSecurityRule Visit(DomainSecurityRule.ExpandedRolesSecurityRule securityRule) + protected override DomainSecurityRule Visit(DomainSecurityRule.ExpandedRoleGroupSecurityRule securityRule) { usedRules.Add(securityRule); return securityRule; } } -} +} \ No newline at end of file diff --git a/src/SecuritySystem/Services/DomainSecurityProviderFactory.cs b/src/SecuritySystem/Services/DomainSecurityProviderFactory.cs index a4707e6..56d5c93 100644 --- a/src/SecuritySystem/Services/DomainSecurityProviderFactory.cs +++ b/src/SecuritySystem/Services/DomainSecurityProviderFactory.cs @@ -18,12 +18,8 @@ public class DomainSecurityProviderFactory( ISecurityRuleDeepOptimizer deepOptimizer, IRoleBaseSecurityProviderFactory roleBaseSecurityProviderFactory) : IDomainSecurityProviderFactory { - public virtual ISecurityProvider Create( - DomainSecurityRule securityRule, - SecurityPath securityPath) - { - return this.CreateInternal(deepOptimizer.Optimize(securityRule), securityPath); - } + public virtual ISecurityProvider Create(DomainSecurityRule securityRule, SecurityPath securityPath) => + this.CreateInternal(deepOptimizer.Optimize(securityRule), securityPath); protected virtual ISecurityProvider CreateInternal( DomainSecurityRule baseSecurityRule, diff --git a/src/SecuritySystem/Services/IDomainSecurityProviderFactory.cs b/src/SecuritySystem/Services/IDomainSecurityProviderFactory.cs index 694011d..51368b3 100644 --- a/src/SecuritySystem/Services/IDomainSecurityProviderFactory.cs +++ b/src/SecuritySystem/Services/IDomainSecurityProviderFactory.cs @@ -4,9 +4,5 @@ namespace SecuritySystem.Services; public interface IDomainSecurityProviderFactory { - ISecurityProvider Create( - DomainSecurityRule securityRule, - SecurityPath securityPath); -} - - + ISecurityProvider Create(DomainSecurityRule securityRule, SecurityPath securityPath); +} \ No newline at end of file diff --git a/src/SecuritySystem/Services/ISecurityRuleBasicOptimizer.cs b/src/SecuritySystem/Services/ISecurityRuleBasicOptimizer.cs index d060e64..39c4392 100644 --- a/src/SecuritySystem/Services/ISecurityRuleBasicOptimizer.cs +++ b/src/SecuritySystem/Services/ISecurityRuleBasicOptimizer.cs @@ -1,6 +1,4 @@ - - -namespace SecuritySystem.Services; +namespace SecuritySystem.Services; public interface ISecurityRuleBasicOptimizer { diff --git a/src/SecuritySystem/Services/RoleBaseSecurityProviderFactory.cs b/src/SecuritySystem/Services/RoleBaseSecurityProviderFactory.cs index 0aca1ad..a30574c 100644 --- a/src/SecuritySystem/Services/RoleBaseSecurityProviderFactory.cs +++ b/src/SecuritySystem/Services/RoleBaseSecurityProviderFactory.cs @@ -8,57 +8,21 @@ public class RoleBaseSecurityProviderFactory( ISecurityFilterFactory securityFilterFactory, IAccessorsFilterFactory accessorsFilterFactory, ISecurityRuleExpander securityRuleExpander, - ISecurityRoleSource securityRoleSource, ISecurityPathRestrictionService securityPathRestrictionService) : IRoleBaseSecurityProviderFactory { - public virtual ISecurityProvider Create( - DomainSecurityRule.RoleBaseSecurityRule securityRule, - SecurityPath securityPath) - { - return this.GetRegroupedRoles(securityRule) - .Select(g => this.Create(g.SecurityRule, securityPath, g.Restriction)).Or(); - } + public virtual ISecurityProvider Create(DomainSecurityRule.RoleBaseSecurityRule securityRule, SecurityPath securityPath) => - private ISecurityProvider Create( - DomainSecurityRule.RoleBaseSecurityRule securityRule, - SecurityPath securityPath, - SecurityPathRestriction restriction) - { - return new RoleBaseSecurityPathProvider( + securityRuleExpander + .FullRoleExpand(securityRule) + .GetActualChildren() + .Select(innerSecurityRule => this.Create(innerSecurityRule, securityPath)) + .Or(); + + private ISecurityProvider Create(DomainSecurityRule.ExpandedRolesSecurityRule securityRule, SecurityPath securityPath) => + + new RoleBaseSecurityPathProvider( securityFilterFactory, accessorsFilterFactory, securityRule, - securityPathRestrictionService.ApplyRestriction(securityPath, restriction)); - } - - private IEnumerable<(DomainSecurityRule.ExpandedRolesSecurityRule SecurityRule, SecurityPathRestriction Restriction)> GetRegroupedRoles( - DomainSecurityRule.RoleBaseSecurityRule securityRule) - { - var expandedSecurityRule = securityRuleExpander.FullRoleExpand(securityRule); - - return from securityRole in expandedSecurityRule.SecurityRoles - - let securityRoleInfo = securityRoleSource.GetSecurityRole(securityRole).Information - - let actualCustomExpandType = expandedSecurityRule.CustomExpandType - ?? securityRule.CustomExpandType ?? securityRoleInfo.CustomExpandType - - let actualCredential = expandedSecurityRule.CustomCredential ?? securityRule.CustomCredential - - let actualRestriction = expandedSecurityRule.CustomRestriction - ?? securityRule.CustomRestriction ?? securityRoleInfo.Restriction - - group securityRole by new { actualCustomExpandType, actualCredential, actualRestriction } - - into g - - let rule = new DomainSecurityRule.ExpandedRolesSecurityRule(g.ToArray()) - { - CustomExpandType = g.Key.actualCustomExpandType, - CustomCredential = g.Key.actualCredential, - CustomRestriction = g.Key.actualRestriction - } - - select (rule, g.Key.actualRestriction); - } -} + securityPathRestrictionService.ApplyRestriction(securityPath, securityRule.CustomRestriction ?? SecurityPathRestriction.Default)); +} \ No newline at end of file diff --git a/src/SecuritySystem/Services/SecurityRolesIdentsResolver.cs b/src/SecuritySystem/Services/SecurityRolesIdentsResolver.cs index bcaae77..cfa2023 100644 --- a/src/SecuritySystem/Services/SecurityRolesIdentsResolver.cs +++ b/src/SecuritySystem/Services/SecurityRolesIdentsResolver.cs @@ -1,22 +1,28 @@ -using CommonFramework; +using System.Collections.Concurrent; + +using CommonFramework; using SecuritySystem.Expanders; namespace SecuritySystem.Services; -public class SecurityRolesIdentsResolver( - ISecurityRuleExpander securityRuleExpander, - ISecurityRoleSource securityRoleSource) - : ISecurityRolesIdentsResolver +public class SecurityRolesIdentsResolver(ISecurityRuleExpander securityRuleExpander, ISecurityRoleSource securityRoleSource) : ISecurityRolesIdentsResolver { - public Dictionary Resolve(DomainSecurityRule.RoleBaseSecurityRule securityRule, bool includeVirtual = false) + private readonly ConcurrentDictionary<(DomainSecurityRule.RoleBaseSecurityRule, bool), Dictionary> cache = new(); + + public IReadOnlyDictionary Resolve(DomainSecurityRule.RoleBaseSecurityRule baseSecurityRule, bool includeVirtual = false) { - return securityRuleExpander.FullRoleExpand(securityRule) - .SecurityRoles - .Select(securityRoleSource.GetSecurityRole) - .Where(sr => includeVirtual || !sr.Information.IsVirtual) - .Select(sr => sr.Identity) - .GroupBy(i => i.IdentType, i => i.GetId()) - .ToDictionary(g => g.Key, g => g.ToArray(g.Key)); + return this.cache.GetOrAdd((baseSecurityRule.WithDefaultCredential(), includeVirtual), pair => + + securityRuleExpander + .FullRoleExpand(pair.Item1) + .Children + .SelectMany(c => c.SecurityRoles) + .Distinct() + .Select(securityRoleSource.GetSecurityRole) + .Where(sr => includeVirtual || !sr.Information.IsVirtual) + .Select(sr => sr.Identity) + .GroupBy(i => i.IdentType, i => i.GetId()) + .ToDictionary(g => g.Key, g => g.ToArray(g.Key))); } } \ No newline at end of file diff --git a/src/SecuritySystem/Services/SecurityRuleBasicOptimizer.cs b/src/SecuritySystem/Services/SecurityRuleBasicOptimizer.cs index 8db99de..cdf8ce2 100644 --- a/src/SecuritySystem/Services/SecurityRuleBasicOptimizer.cs +++ b/src/SecuritySystem/Services/SecurityRuleBasicOptimizer.cs @@ -27,10 +27,10 @@ protected override DomainSecurityRule Visit(OrSecurityRule baseSecurityRule) when left.EqualsCustoms(right) => left + right, OrSecurityRule - { - Left: OrSecurityRule { Left: ExpandedRolesSecurityRule leftLeft, Right: { } leftRight }, - Right: ExpandedRolesSecurityRule right - } + { + Left: OrSecurityRule { Left: ExpandedRolesSecurityRule leftLeft, Right: { } leftRight }, + Right: ExpandedRolesSecurityRule right + } when leftLeft.EqualsCustoms(right) => leftRight.Or(leftLeft + right), OrSecurityRule @@ -40,17 +40,17 @@ when leftLeft.EqualsCustoms(right) => leftRight.Or(leftLeft + right), } when leftRight.EqualsCustoms(right) => leftLeft.Or(leftRight + right), OrSecurityRule - { - Left: ExpandedRolesSecurityRule left, - Right: OrSecurityRule { Left: ExpandedRolesSecurityRule rightLeft, Right: { } rightRight } - } + { + Left: ExpandedRolesSecurityRule left, + Right: OrSecurityRule { Left: ExpandedRolesSecurityRule rightLeft, Right: { } rightRight } + } when left.EqualsCustoms(rightLeft) => (left + rightLeft).Or(rightRight), OrSecurityRule - { - Left: ExpandedRolesSecurityRule left, - Right: OrSecurityRule { Left: { } rightLeft, Right: ExpandedRolesSecurityRule rightRight } - } + { + Left: ExpandedRolesSecurityRule left, + Right: OrSecurityRule { Left: { } rightLeft, Right: ExpandedRolesSecurityRule rightRight } + } when left.EqualsCustoms(rightRight) => (left + rightRight).Or(rightLeft), //NonExpandedRolesSecurityRule @@ -59,31 +59,31 @@ when left.EqualsCustoms(rightRight) => (left + rightRight).Or(rightLeft), when left.EqualsCustoms(right) => left + right, OrSecurityRule - { - Left: OrSecurityRule { Left: NonExpandedRolesSecurityRule leftLeft, Right: { } leftRight }, - Right: NonExpandedRolesSecurityRule right - } + { + Left: OrSecurityRule { Left: NonExpandedRolesSecurityRule leftLeft, Right: { } leftRight }, + Right: NonExpandedRolesSecurityRule right + } when leftLeft.EqualsCustoms(right) => leftRight.Or(leftLeft + right), OrSecurityRule - { - Left: OrSecurityRule { Left: { } leftLeft, Right: NonExpandedRolesSecurityRule leftRight }, - Right: NonExpandedRolesSecurityRule right - } + { + Left: OrSecurityRule { Left: { } leftLeft, Right: NonExpandedRolesSecurityRule leftRight }, + Right: NonExpandedRolesSecurityRule right + } when leftRight.EqualsCustoms(right) => leftLeft.Or(leftRight + right), OrSecurityRule - { - Left: NonExpandedRolesSecurityRule left, - Right: OrSecurityRule { Left: NonExpandedRolesSecurityRule rightLeft, Right: { } rightRight } - } + { + Left: NonExpandedRolesSecurityRule left, + Right: OrSecurityRule { Left: NonExpandedRolesSecurityRule rightLeft, Right: { } rightRight } + } when left.EqualsCustoms(rightLeft) => (left + rightLeft).Or(rightRight), OrSecurityRule - { - Left: NonExpandedRolesSecurityRule left, - Right: OrSecurityRule { Left: { } rightLeft, Right: NonExpandedRolesSecurityRule rightRight } - } + { + Left: NonExpandedRolesSecurityRule left, + Right: OrSecurityRule { Left: { } rightLeft, Right: NonExpandedRolesSecurityRule rightRight } + } when left.EqualsCustoms(rightRight) => (left + rightRight).Or(rightLeft), _ => visitedBase diff --git a/src/SecuritySystem/Services/SecurityRuleVisitor.cs b/src/SecuritySystem/Services/SecurityRuleVisitor.cs index 4268802..3eba994 100644 --- a/src/SecuritySystem/Services/SecurityRuleVisitor.cs +++ b/src/SecuritySystem/Services/SecurityRuleVisitor.cs @@ -2,6 +2,11 @@ public abstract class SecurityRuleVisitor { + protected virtual DomainSecurityRule Visit(DomainSecurityRule.ExpandedRoleGroupSecurityRule securityRule) + { + return securityRule; + } + protected virtual DomainSecurityRule Visit(DomainSecurityRule.ExpandedRolesSecurityRule securityRule) { return securityRule; @@ -80,6 +85,7 @@ protected virtual DomainSecurityRule Visit(DomainSecurityRule.NegateSecurityRule protected virtual DomainSecurityRule Visit(DomainSecurityRule.RoleBaseSecurityRule baseSecurityRule) => baseSecurityRule switch { + DomainSecurityRule.ExpandedRoleGroupSecurityRule securityRule => this.Visit(securityRule), DomainSecurityRule.ExpandedRolesSecurityRule securityRule => this.Visit(securityRule), DomainSecurityRule.NonExpandedRolesSecurityRule securityRule => this.Visit(securityRule), DomainSecurityRule.OperationSecurityRule securityRule => this.Visit(securityRule), diff --git a/src/__SolutionItems/CommonAssemblyInfo.cs b/src/__SolutionItems/CommonAssemblyInfo.cs index 31a5340..e8718fb 100644 --- a/src/__SolutionItems/CommonAssemblyInfo.cs +++ b/src/__SolutionItems/CommonAssemblyInfo.cs @@ -3,7 +3,7 @@ [assembly: AssemblyProduct("SecuritySystem")] [assembly: AssemblyCompany("IvAt")] -[assembly: AssemblyVersion("2.0.17.0")] +[assembly: AssemblyVersion("2.1.0.0")] [assembly: AssemblyInformationalVersion("changes at build")] #if DEBUG