-
Notifications
You must be signed in to change notification settings - Fork 313
feat: Role inheritance for entity permissions + dab configure --show-effective-permissions
#3164
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
66e2112
22f6714
dab4c6f
c69318b
04819a6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -119,6 +119,7 @@ public bool IsValidRoleContext(HttpContext httpContext) | |
| /// <inheritdoc /> | ||
| public bool AreRoleAndOperationDefinedForEntity(string entityIdentifier, string roleName, EntityActionOperation operation) | ||
| { | ||
| roleName = GetEffectiveRoleName(entityIdentifier, roleName); | ||
| if (EntityPermissionsMap.TryGetValue(entityIdentifier, out EntityMetadata? valueOfEntityToRole)) | ||
| { | ||
| if (valueOfEntityToRole.RoleToOperationMap.TryGetValue(roleName, out RoleMetadata? valueOfRoleToOperation)) | ||
|
|
@@ -135,6 +136,7 @@ public bool AreRoleAndOperationDefinedForEntity(string entityIdentifier, string | |
|
|
||
| public bool IsStoredProcedureExecutionPermitted(string entityName, string roleName, SupportedHttpVerb httpVerb) | ||
| { | ||
| roleName = GetEffectiveRoleName(entityName, roleName); | ||
| bool executionPermitted = EntityPermissionsMap.TryGetValue(entityName, out EntityMetadata? entityMetadata) | ||
| && entityMetadata is not null | ||
| && entityMetadata.RoleToOperationMap.TryGetValue(roleName, out _); | ||
|
|
@@ -144,6 +146,7 @@ public bool IsStoredProcedureExecutionPermitted(string entityName, string roleNa | |
| /// <inheritdoc /> | ||
| public bool AreColumnsAllowedForOperation(string entityName, string roleName, EntityActionOperation operation, IEnumerable<string> columns) | ||
| { | ||
| roleName = GetEffectiveRoleName(entityName, roleName); | ||
| string dataSourceName = _runtimeConfigProvider.GetConfig().GetDataSourceNameFromEntityName(entityName); | ||
| ISqlMetadataProvider metadataProvider = _metadataProviderFactory.GetMetadataProvider(dataSourceName); | ||
|
|
||
|
|
@@ -210,6 +213,7 @@ public string ProcessDBPolicy(string entityName, string roleName, EntityActionOp | |
| /// <inheritdoc /> | ||
| public string GetDBPolicyForRequest(string entityName, string roleName, EntityActionOperation operation) | ||
| { | ||
| roleName = GetEffectiveRoleName(entityName, roleName); | ||
| if (!EntityPermissionsMap[entityName].RoleToOperationMap.TryGetValue(roleName, out RoleMetadata? roleMetadata)) | ||
| { | ||
| return string.Empty; | ||
|
|
@@ -426,6 +430,46 @@ private static void CopyOverPermissionsFromAnonymousToAuthenticatedRole( | |
| } | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Returns the effective role name for permission lookups, implementing role inheritance. | ||
| /// System roles (anonymous, authenticated) always resolve to themselves. | ||
| /// For any other named role not explicitly configured for the entity, this method falls back | ||
| /// to the 'authenticated' role if it is present (which itself may already inherit from 'anonymous'). | ||
| /// Inheritance chain: named-role → authenticated → anonymous → none. | ||
| /// </summary> | ||
|
Comment on lines
+433
to
+439
|
||
| /// <param name="entityName">Name of the entity being accessed.</param> | ||
| /// <param name="roleName">Role name from the request.</param> | ||
| /// <returns>The role name whose permissions should apply for this request.</returns> | ||
| private string GetEffectiveRoleName(string entityName, string roleName) | ||
| { | ||
| // System roles always resolve to themselves; they do not inherit from other roles. | ||
| if (roleName.Equals(ROLE_ANONYMOUS, StringComparison.OrdinalIgnoreCase) || | ||
| roleName.Equals(ROLE_AUTHENTICATED, StringComparison.OrdinalIgnoreCase)) | ||
| { | ||
| return roleName; | ||
| } | ||
|
|
||
| if (!EntityPermissionsMap.TryGetValue(entityName, out EntityMetadata? entityMetadata)) | ||
| { | ||
| return roleName; | ||
| } | ||
|
|
||
| // Named role explicitly configured: use its own permissions. | ||
| if (entityMetadata.RoleToOperationMap.ContainsKey(roleName)) | ||
| { | ||
| return roleName; | ||
| } | ||
|
|
||
| // Named role not configured: inherit from 'authenticated' if present. | ||
| // Note: 'authenticated' itself may already inherit from 'anonymous' via setup-time copy. | ||
| if (entityMetadata.RoleToOperationMap.ContainsKey(ROLE_AUTHENTICATED)) | ||
| { | ||
| return ROLE_AUTHENTICATED; | ||
| } | ||
|
|
||
| return roleName; | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Returns a list of all possible operations depending on the provided EntitySourceType. | ||
| /// Stored procedures only support Operation.Execute. | ||
|
|
@@ -474,6 +518,7 @@ private static void PopulateAllowedExposedColumns( | |
| /// <inheritdoc /> | ||
| public IEnumerable<string> GetAllowedExposedColumns(string entityName, string roleName, EntityActionOperation operation) | ||
| { | ||
| roleName = GetEffectiveRoleName(entityName, roleName); | ||
| return EntityPermissionsMap[entityName].RoleToOperationMap[roleName].OperationToColumnMap[operation].AllowedExposedColumns; | ||
| } | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The new
--show-effective-permissionsexecution path isn’t covered by CLI unit tests. Sincesrc/Cli.Tests/ConfigureOptionsTests.csalready exercisesConfigureOptionsextensively, add tests validating this mode (e.g., output ordering by entity/role, authenticated-inherits-anonymous line, and the final inheritance note), and that it doesn’t inadvertently modify the config file.