Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace SecuritySystem.Expanders;

public interface ISecurityRoleGroupExpander
{
DomainSecurityRule.ExpandedRoleGroupSecurityRule Expand(DomainSecurityRule.NonExpandedRoleGroupSecurityRule securityRule);

DomainSecurityRule.ExpandedRoleGroupSecurityRule Expand(DomainSecurityRule.NonExpandedRolesSecurityRule securityRule);
}
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
52 changes: 36 additions & 16 deletions src/SecuritySystem.Abstractions/SecurityRule/DomainSecurityRule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down Expand Up @@ -78,8 +78,6 @@ public abstract record RoleBaseSecurityRule : DomainSecurityRule, IRoleBaseSecur
/// </summary>
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;
Expand All @@ -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
Expand All @@ -117,12 +120,29 @@ public interface IRoleBaseSecurityRuleCustomData
public SecurityPathRestriction? CustomRestriction { get; }
}

public record RoleGroupSecurityRule(DeepEqualsCollection<RoleBaseSecurityRule> Children) : RoleBaseSecurityRule;

public record AnyRoleSecurityRule : RoleBaseSecurityRule;

public record RoleFactorySecurityRule(Type RoleFactoryType) : RoleBaseSecurityRule;

public record NonExpandedRoleGroupSecurityRule(DeepEqualsCollection<NonExpandedRolesSecurityRule> Children) : RoleBaseSecurityRule
{
public NonExpandedRoleGroupSecurityRule(IEnumerable<NonExpandedRolesSecurityRule> children)
: this(children.ToArray())
{
}
}

public record ExpandedRoleGroupSecurityRule(DeepEqualsCollection<ExpandedRolesSecurityRule> Children) : RoleBaseSecurityRule
{
public ExpandedRoleGroupSecurityRule(IEnumerable<ExpandedRolesSecurityRule> children)
: this(children.ToArray())
{
}

public IEnumerable<ExpandedRolesSecurityRule> GetActualChildren() =>
this.Children.Select(c => c.ApplyCustoms(this));
}

public record OperationSecurityRule(SecurityOperation SecurityOperation) : RoleBaseSecurityRule
{
public override string ToString() => this.SecurityOperation.Name;
Expand All @@ -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
{
Expand All @@ -163,22 +183,22 @@ public override string ToString() => this.SecurityRoles.Count == 1
/// <param name="SecurityRoles">Список развёрнутых ролей</param>
public record ExpandedRolesSecurityRule(DeepEqualsCollection<SecurityRole> SecurityRoles) : RoleBaseSecurityRule
{
public static ExpandedRolesSecurityRule Empty { get; } = Create([]);
public ExpandedRolesSecurityRule(IEnumerable<SecurityRole> 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<SecurityRole> 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
{
Expand Down
9 changes: 6 additions & 3 deletions src/SecuritySystem.Abstractions/SecurityRule/SecurityRule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ namespace SecuritySystem;

public abstract record SecurityRule
{
public SecurityRuleCredential? CustomCredential { get; init; }


/// <summary>
/// Правило доступа для просмотра объекта
/// </summary>
Expand All @@ -27,14 +30,14 @@ 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
{
public override string ToString() => this.Name;

public DomainSecurityRule.DomainModeSecurityRule ToDomain<TDomainObject>() => 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 };
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -124,58 +123,83 @@ 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
};
}

extension<TSecurityRule>(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>(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<TResult>(Func<TSecurityRule, TResult> selector)
where TResult : SecurityRule =>
selector(securityRule.WithDefaultCredential()).ForceApply(securityRule.CustomCredential);
}

public static RoleBaseSecurityRule ToSecurityRule(
this IEnumerable<RoleBaseSecurityRule> securityRules,
HierarchicalExpandType? customExpandType = null,
this IEnumerable<NonExpandedRolesSecurityRule> 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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ public interface IDomainSecurityRoleExtractor
{
IEnumerable<SecurityRole> ExtractSecurityRoles(DomainSecurityRule securityRule);

DomainSecurityRule.RoleBaseSecurityRule ExtractSecurityRule(DomainSecurityRule securityRule);
DomainSecurityRule.ExpandedRoleGroupSecurityRule ExtractSecurityRule(DomainSecurityRule securityRule);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@

public interface ISecurityRolesIdentsResolver
{
Dictionary<Type, Array> Resolve(DomainSecurityRule.RoleBaseSecurityRule securityRule, bool includeVirtual = false);
IReadOnlyDictionary<Type, Array> Resolve(DomainSecurityRule.RoleBaseSecurityRule securityRule, bool includeVirtual = false);
}
52 changes: 36 additions & 16 deletions src/SecuritySystem.DiTests/SecurityRoleTests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using HierarchicalExpand;

using Microsoft.Extensions.DependencyInjection;

using SecuritySystem.DiTests.Rules;
Expand All @@ -25,16 +26,21 @@ public void AdministratorRole_ShouldNotContains_SystemIntegrationRole()
public void SecurityRoleExpander_ExpandDeepChild_AllRolesExpanded()
{
// Arrange
var expander = this.RootServiceProvider.GetRequiredService<ISecurityRoleExpander>();
var expander = this.RootServiceProvider.GetRequiredService<ISecurityRoleGroupExpander>();

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]
Expand Down Expand Up @@ -69,15 +75,22 @@ public void SecurityRoleExpander_FullExpandWithCustomExpandType_SecurityRuleCorr
// Arrange
var expander = this.RootServiceProvider.GetRequiredService<ISecurityRuleExpander>();

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]
Expand All @@ -86,14 +99,21 @@ public void SecurityRoleExpander_FullExpandWithCustomExpandTypeFromOperations_Se
// Arrange
var expander = this.RootServiceProvider.GetRequiredService<ISecurityRuleExpander>();

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);
}
}
Loading
Loading