Skip to content

Commit 00fbbee

Browse files
committed
Allow exclusions for finer grained control
1 parent 3825fc2 commit 00fbbee

2 files changed

Lines changed: 20 additions & 10 deletions

File tree

src/ServiceControl.Infrastructure/Auth/Permissions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ public static class Permissions
8585
/// <inheritdoc cref="ErrorThroughputView"/>
8686
public const string ErrorThroughputManage = "error:throughput:manage";
8787

88-
/// <summary>Platform connections area — viewing and managing broker/platform connection settings.</summary>
88+
/// <summary>Platform connections area — viewing and managing platform connection settings.</summary>
8989
public const string ErrorConnectionsView = "error:connections:view";
9090
/// <inheritdoc cref="ErrorConnectionsView"/>
9191
public const string ErrorConnectionsManage = "error:connections:manage";

src/ServiceControl.Infrastructure/Auth/RolePermissions.cs

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -37,15 +37,17 @@ public static class RolePermissions
3737
static readonly Dictionary<string, string[]> RolePatterns = new(StringComparer.OrdinalIgnoreCase)
3838
{
3939
[Reader] = ["*:*:view"],
40-
[Writer] = ["*:*:*"],
40+
[Writer] =
41+
[
42+
"*:*:*",
43+
"-error:licensing:*",
44+
"-error:notifications:*",
45+
"-error:redirects:*",
46+
"-error:throughput:*",
47+
],
4148
[Admin] =
4249
[
43-
"*:*:view",
44-
"error:licensing:*",
45-
"error:notifications:*",
46-
"error:redirects:*",
47-
"error:throughput:*",
48-
"error:connections:*",
50+
"*:*:*",
4951
],
5052
};
5153

@@ -106,15 +108,23 @@ static FrozenDictionary<string, FrozenSet<string>> Expand()
106108

107109
foreach (var (role, patterns) in RolePatterns)
108110
{
111+
var includePatterns = patterns.Where(pattern => pattern[0] != '-');
112+
var excludePatterns = patterns.Where(pattern => pattern[0] == '-').Select(pattern => pattern[1..]);
113+
109114
expanded[role] = Permissions.All
110-
.Where(permission => patterns.Any(pattern => Matches(pattern, permission)))
115+
.Where(permission => includePatterns.Any(pattern => Matches(pattern, permission))
116+
&& !excludePatterns.Any(pattern => Matches(pattern, permission)))
111117
.ToFrozenSet(StringComparer.Ordinal);
112118
}
113119

114120
return expanded.ToFrozenDictionary(StringComparer.OrdinalIgnoreCase);
115121
}
116122

117-
/// <summary>Matches a colon-delimited permission against a pattern where <c>*</c> is a segment wildcard.</summary>
123+
/// <summary>
124+
/// Matches a colon-delimited permission against a pattern where <c>*</c> is a segment wildcard.
125+
/// A leading <c>-</c> on the pattern (stripped by <see cref="Expand"/> before calling this method)
126+
/// marks the pattern as an exclusion rather than a grant.
127+
/// </summary>
118128
static bool Matches(string pattern, string permission)
119129
{
120130
var patternSegments = pattern.Split(':');

0 commit comments

Comments
 (0)