diff --git a/src/ServiceControl.Infrastructure/Auth/Permissions.cs b/src/ServiceControl.Infrastructure/Auth/Permissions.cs index 006fccf0f5..04f6582c14 100644 --- a/src/ServiceControl.Infrastructure/Auth/Permissions.cs +++ b/src/ServiceControl.Infrastructure/Auth/Permissions.cs @@ -85,7 +85,7 @@ public static class Permissions /// public const string ErrorThroughputManage = "error:throughput:manage"; - /// Platform connections area — viewing and managing broker/platform connection settings. + /// Platform connections area — viewing and managing platform connection settings. public const string ErrorConnectionsView = "error:connections:view"; /// public const string ErrorConnectionsManage = "error:connections:manage"; diff --git a/src/ServiceControl.Infrastructure/Auth/RolePermissions.cs b/src/ServiceControl.Infrastructure/Auth/RolePermissions.cs index bb79f98f02..8b5d64d6d7 100644 --- a/src/ServiceControl.Infrastructure/Auth/RolePermissions.cs +++ b/src/ServiceControl.Infrastructure/Auth/RolePermissions.cs @@ -37,15 +37,17 @@ public static class RolePermissions static readonly Dictionary RolePatterns = new(StringComparer.OrdinalIgnoreCase) { [Reader] = ["*:*:view"], - [Writer] = ["*:*:*"], + [Writer] = + [ + "*:*:*", + "-error:licensing:*", + "-error:notifications:*", + "-error:redirects:*", + "-error:throughput:*", + ], [Admin] = [ - "*:*:view", - "error:licensing:*", - "error:notifications:*", - "error:redirects:*", - "error:throughput:*", - "error:connections:*", + "*:*:*", ], }; @@ -106,15 +108,23 @@ static FrozenDictionary> Expand() foreach (var (role, patterns) in RolePatterns) { + var includePatterns = patterns.Where(pattern => pattern[0] != '-'); + var excludePatterns = patterns.Where(pattern => pattern[0] == '-').Select(pattern => pattern[1..]); + expanded[role] = Permissions.All - .Where(permission => patterns.Any(pattern => Matches(pattern, permission))) + .Where(permission => includePatterns.Any(pattern => Matches(pattern, permission)) + && !excludePatterns.Any(pattern => Matches(pattern, permission))) .ToFrozenSet(StringComparer.Ordinal); } return expanded.ToFrozenDictionary(StringComparer.OrdinalIgnoreCase); } - /// Matches a colon-delimited permission against a pattern where * is a segment wildcard. + /// + /// Matches a colon-delimited permission against a pattern where * is a segment wildcard. + /// A leading - on the pattern (stripped by before calling this method) + /// marks the pattern as an exclusion rather than a grant. + /// static bool Matches(string pattern, string permission) { var patternSegments = pattern.Split(':');