This is an automated email from the ASF dual-hosted git repository.
roryqi pushed a commit to branch branch-1.1
in repository https://gitbox.apache.org/repos/asf/gravitino.git
The following commit(s) were added to refs/heads/branch-1.1 by this push:
new 0ac2295299 [#9291] improvement(authz): Add comment explaining why deny
privileges are injected into allowEnforcer (#9455)
0ac2295299 is described below
commit 0ac22952999fdf5dae8c59b71a973318f64cfd98
Author: github-actions[bot]
<41898282+github-actions[bot]@users.noreply.github.com>
AuthorDate: Thu Dec 11 15:35:39 2025 +0800
[#9291] improvement(authz): Add comment explaining why deny privileges are
injected into allowEnforcer (#9455)
### What changes were proposed in this pull request?
Add comment explaining why deny privileges are injected into
allowEnforcer
### Why are the changes needed?
Fix: #9291
### Does this PR introduce _any_ user-facing change?
None
### How was this patch tested?
None
Co-authored-by: yangyang zhong <[email protected]>
---
.../expression/AuthorizationExpressionConverter.java | 15 +++++++++++++++
.../server/authorization/jcasbin/JcasbinAuthorizer.java | 8 ++++++++
2 files changed, 23 insertions(+)
diff --git
a/server-common/src/main/java/org/apache/gravitino/server/authorization/expression/AuthorizationExpressionConverter.java
b/server-common/src/main/java/org/apache/gravitino/server/authorization/expression/AuthorizationExpressionConverter.java
index 160f22069f..34648782b4 100644
---
a/server-common/src/main/java/org/apache/gravitino/server/authorization/expression/AuthorizationExpressionConverter.java
+++
b/server-common/src/main/java/org/apache/gravitino/server/authorization/expression/AuthorizationExpressionConverter.java
@@ -207,6 +207,21 @@ public class AuthorizationExpressionConverter {
public static String replaceAnyPrivilege(String expression) {
expression = expression.replaceAll("SERVICE_ADMIN",
"authorizer.isServiceAdmin()");
expression = expression.replaceAll("METALAKE_USER",
"authorizer.isMetalakeUser(METALAKE_NAME)");
+
+ // A single privilege (e.g., SELECT_TABLE) can be granted or denied at
multiple namespace
+ // levels: metalake, catalog, schema, and table.
+ //
+ // Deny takes precedence over allow: if deny is set for the privilege at
any level in the
+ // hierarchy,
+ // the user is not considered to have that privilege—even if an allow
exists at a more specific
+ // level.
+ //
+ // Examples:
+ // - If role1 is allowed SELECT_TABLE on metalake1 but denied on catalog1,
+ // then SELECT_TABLE is denied for all objects under catalog1.
+ // - If role1 is denied SELECT_TABLE on metalake1, any allow on catalog1
(or deeper) is
+ // overridden,
+ // and SELECT_TABLE remains denied for catalog1 and its descendants.
expression =
expression.replaceAll(
"ANY_USE_CATALOG",
diff --git
a/server-common/src/main/java/org/apache/gravitino/server/authorization/jcasbin/JcasbinAuthorizer.java
b/server-common/src/main/java/org/apache/gravitino/server/authorization/jcasbin/JcasbinAuthorizer.java
index 034a742c48..68125aec56 100644
---
a/server-common/src/main/java/org/apache/gravitino/server/authorization/jcasbin/JcasbinAuthorizer.java
+++
b/server-common/src/main/java/org/apache/gravitino/server/authorization/jcasbin/JcasbinAuthorizer.java
@@ -535,6 +535,14 @@ public class JcasbinAuthorizer implements
GravitinoAuthorizer {
.toUpperCase(java.util.Locale.ROOT),
AuthConstants.ALLOW);
}
+ // Since different roles of a user may simultaneously hold both
"allow" and "deny"
+ // permissions
+ // for the same privilege on a given MetadataObject, the allowEnforcer
must also incorporate
+ // the "deny" privilege to ensure that the authorize method correctly
returns false in such
+ // cases. For example, if role1 has an "allow" privilege for
SELECT_TABLE on table1, while
+ // role2 has a "deny" privilege for the same action on table1, then a
user assigned both
+ // roles should receive a false result when calling the authorize
method.
+
allowEnforcer.addPolicy(
String.valueOf(roleEntity.id()),
securableObject.type().name(),