This is an automated email from the ASF dual-hosted git repository.
jshao pushed a commit to branch branch-metadata-authz
in repository https://gitbox.apache.org/repos/asf/gravitino.git
The following commit(s) were added to refs/heads/branch-metadata-authz by this
push:
new 04464568e4 [#6827] feat(authz): Jcasbin model file for Gravitino
(#7086)
04464568e4 is described below
commit 04464568e47767f09dcbab765d3e9c153e96aa05
Author: yangyang zhong <[email protected]>
AuthorDate: Wed May 21 15:25:27 2025 +0800
[#6827] feat(authz): Jcasbin model file for Gravitino (#7086)
### What changes were proposed in this pull request?
Define the jcasbin permission model
### Why are the changes needed?
Fix: #6827
### Does this PR introduce _any_ user-facing change?
None
### How was this patch tested?
org.apache.gravitino.server.authorization.TestJcasbinModel
---
LICENSE.bin | 1 +
gradle/libs.versions.toml | 4 +-
server-common/build.gradle.kts | 3 +-
.../src/main/resources/jcasbin_model.conf | 55 ++
.../server/authorization/TestJcasbinModel.java | 569 +++++++++++++++++++++
.../src/test/resources/jcasbin_policy.txt | 28 +
6 files changed, 658 insertions(+), 2 deletions(-)
diff --git a/LICENSE.bin b/LICENSE.bin
index 6f3ad84f26..69a6b9f800 100644
--- a/LICENSE.bin
+++ b/LICENSE.bin
@@ -377,6 +377,7 @@
Jettison
Awaitility
Ognl
+ Jcasbin
This product bundles various third-party components also under the
Apache Software Foundation License 1.1
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 944bb7019b..22583b9d16 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -119,6 +119,7 @@ hudi = "0.15.0"
google-auth = "1.28.0"
aliyun-credentials = "0.3.12"
openlineage = "1.29.0"
+jcasbin = "1.81.0"
ognl = "3.4.7"
[libraries]
@@ -281,8 +282,9 @@ google-auth-credentials = { group = "com.google.auth", name
= "google-auth-libra
aliyun-credentials-sdk = { group='com.aliyun', name='credentials-java',
version.ref='aliyun-credentials' }
flinkjdbc = {group='org.apache.flink',name='flink-connector-jdbc',
version.ref='flinkjdbc'}
+jcasbin = { group='org.casbin', name='jcasbin', version.ref="jcasbin" }
openlineage-java= { group = "io.openlineage", name = "openlineage-java",
version.ref = "openlineage" }
-ognl = {group='ognl',name='ognl',version.ref="ognl"}
+ognl = { group='ognl', name='ognl', version.ref="ognl" }
[bundles]
log4j = ["slf4j-api", "log4j-slf4j2-impl", "log4j-api", "log4j-core",
"log4j-12-api", "log4j-layout-template-json"]
diff --git a/server-common/build.gradle.kts b/server-common/build.gradle.kts
index f8d27a0446..52f74c9c41 100644
--- a/server-common/build.gradle.kts
+++ b/server-common/build.gradle.kts
@@ -43,8 +43,9 @@ dependencies {
implementation(libs.jackson.datatype.jdk8)
implementation(libs.jackson.datatype.jsr310)
implementation(libs.jackson.databind)
- implementation(libs.prometheus.servlet)
+ implementation(libs.jcasbin)
implementation(libs.ognl)
+ implementation(libs.prometheus.servlet)
testImplementation(libs.commons.io)
testImplementation(libs.junit.jupiter.api)
diff --git a/server-common/src/main/resources/jcasbin_model.conf
b/server-common/src/main/resources/jcasbin_model.conf
new file mode 100644
index 0000000000..3247012b3b
--- /dev/null
+++ b/server-common/src/main/resources/jcasbin_model.conf
@@ -0,0 +1,55 @@
+; Licensed to the Apache Software Foundation (ASF) under one
+; or more contributor license agreements. See the NOTICE file
+; distributed with this work for additional information
+; regarding copyright ownership. The ASF licenses this file
+; to you under the Apache License, Version 2.0 (the
+; "License"); you may not use this file except in compliance
+; with the License. You may obtain a copy of the License at
+;
+; http://www.apache.org/licenses/LICENSE-2.0
+;
+; Unless required by applicable law or agreed to in writing,
+; software distributed under the License is distributed on an
+; "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+; KIND, either express or implied. See the License for the
+; specific language governing permissions and limitations
+; under the License.
+
+; The model file of jcasbin defines a permission model used to describe the
permissions
+; of users, groups, and roles for a single metadata type.
+
+; "r" represents the parameters passed when making a request to jCasbin.
+; "sub" represents a roleId, userId, or groupCodeId.
+; The combination of `sub` and `metalakeId` uniquely identifies a user, role,
or group.
+; "metadataType" represents the type of metadata.
+; "metadataId" represents the id of metadata
+; "act" represents the privilege that needs to be authorized or whether it is
an OWNER.
+[request_definition]
+r = sub, metadataType, metadataId, act
+
+; "p" represents a permission policy.
+; "eft" stands for "effect" which can be either "allow" or "deny".
+[policy_definition]
+p = sub, metadataType, metadataId, act, eft
+
+; "g" represents the membership or ownership relationship of users, groups, or
roles.
+[role_definition]
+g = _, _
+
+; "e" represents the effect of the "eft",eft performs a logical combination
judgment on the matching results
+; of Matchers.
+; e = some(where(p.eft == allow)): This statement means that if the matching
strategy result p.eft has the result
+; of (some) allow
+; e = some(where (p.eft == allow)) && !some(where (p.eft == deny)): The
logical meaning of this example combination
+; is: if there is a strategy that matches the result of allow and no strategy
that matches the result of deny,
+; the result is true. In other words, it is true when the matching strategies
are all allow. If there is any deny,
+; both are false (more simply, when allow and deny exist at the same time,
deny takes precedence).
+;
+; see more in https://casbin.org/zh/docs/how-it-works/#effect
+[policy_effect]
+e = some(where (p.eft == allow)) && !some(where (p.eft == deny))
+
+; "m" represents the matching rules of the model
+[matchers]
+m = g(r.sub, p.sub) && r.metadataId == p.metadataId && r.metadataType ==
p.metadataType && ( p.act == "OWNER" || r.act == p.act )
+
diff --git
a/server-common/src/test/java/org/apache/gravitino/server/authorization/TestJcasbinModel.java
b/server-common/src/test/java/org/apache/gravitino/server/authorization/TestJcasbinModel.java
new file mode 100644
index 0000000000..43410b8f28
--- /dev/null
+++
b/server-common/src/test/java/org/apache/gravitino/server/authorization/TestJcasbinModel.java
@@ -0,0 +1,569 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.gravitino.server.authorization;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+import java.util.stream.Collectors;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.IOUtils;
+import org.apache.gravitino.MetadataObject;
+import org.apache.gravitino.authorization.Privilege;
+import org.casbin.jcasbin.main.Enforcer;
+import org.casbin.jcasbin.model.Model;
+import org.casbin.jcasbin.persist.file_adapter.FileAdapter;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+/** Test for jcasbin model. */
+public class TestJcasbinModel {
+
+ /** Jcasbin enforcer */
+ private static Enforcer enforcer;
+
+ @BeforeAll
+ public static void init() throws IOException {
+ // Load jcasbin policy from jcasbin_policy.txt
+ URL resource = TestJcasbinModel.class.getResource("/jcasbin_policy.txt");
+ Assertions.assertNotNull(resource);
+ List<String> policyWithLicense =
+ FileUtils.readLines(new File(resource.getFile()),
StandardCharsets.UTF_8);
+ // remove license
+ String policy =
+ policyWithLicense.stream()
+ .filter(line -> !line.startsWith("#"))
+ .collect(Collectors.joining("\n"));
+ try (InputStream modelStream =
+ TestJcasbinModel.class.getResourceAsStream("/jcasbin_model.conf");
+ InputStream policyInputStream =
+ new ByteArrayInputStream(policy.getBytes(StandardCharsets.UTF_8)))
{
+ Assertions.assertNotNull(modelStream);
+ String modelString = IOUtils.toString(modelStream,
StandardCharsets.UTF_8);
+ Model model = new Model();
+ model.loadModelFromText(modelString);
+ FileAdapter fileAdapter = new FileAdapter(policyInputStream);
+ enforcer = new Enforcer(model, fileAdapter);
+ }
+ }
+
+ /**
+ * "role1" is the OWNER of metalake1. Determine whether role1 has the OWNER
permission for
+ * metalake1.
+ */
+ @Test
+ public void testMetalakeOwner() {
+ Assertions.assertTrue(
+ enforcer.enforce("role1", MetadataObject.Type.METALAKE.name(),
"metalake1", "OWNER"));
+ Assertions.assertTrue(
+ enforcer.enforce(
+ "role1",
+ MetadataObject.Type.METALAKE.name(),
+ "metalake1",
+ Privilege.Name.USE_CATALOG.name()));
+ Assertions.assertFalse(
+ enforcer.enforce("role1", MetadataObject.Type.METALAKE.name(),
"metalake2", "OWNER"));
+ Assertions.assertFalse(
+ enforcer.enforce(
+ "role1",
+ MetadataObject.Type.METALAKE.name(),
+ "metalake2",
+ Privilege.Name.USE_CATALOG.name()));
+ }
+
+ /**
+ * "role2" is the OWNER of catalog1. Determine whether role2 has the OWNER
permission for
+ * catalog2.
+ */
+ @Test
+ public void testCatalogOwner() {
+ Assertions.assertTrue(
+ enforcer.enforce("role2", MetadataObject.Type.CATALOG.name(),
"catalog1", "OWNER"));
+ Assertions.assertTrue(
+ enforcer.enforce(
+ "role2",
+ MetadataObject.Type.CATALOG.name(),
+ "catalog1",
+ Privilege.Name.USE_SCHEMA.name()));
+ Assertions.assertTrue(
+ enforcer.enforce(
+ "role2",
+ MetadataObject.Type.CATALOG.name(),
+ "catalog1",
+ Privilege.Name.USE_CATALOG.name()));
+ Assertions.assertFalse(
+ enforcer.enforce("role2", MetadataObject.Type.CATALOG.name(),
"catalog2", "OWNER"));
+ Assertions.assertFalse(
+ enforcer.enforce(
+ "role2",
+ MetadataObject.Type.CATALOG.name(),
+ "catalog2",
+ Privilege.Name.USE_CATALOG.name()));
+ }
+
+ /**
+ * role3 is the owner of schema1. Determine whether role3 has the owner
permission for schema1.
+ */
+ @Test
+ public void testSchemaOwner() {
+ Assertions.assertTrue(
+ enforcer.enforce("role3", MetadataObject.Type.SCHEMA.name(),
"schema1", "OWNER"));
+ Assertions.assertTrue(
+ enforcer.enforce(
+ "role3",
+ MetadataObject.Type.SCHEMA.name(),
+ "schema1",
+ Privilege.Name.SELECT_TABLE.name()));
+ Assertions.assertFalse(
+ enforcer.enforce("role3", MetadataObject.Type.SCHEMA.name(),
"schema2", "OWNER"));
+ Assertions.assertFalse(
+ enforcer.enforce(
+ "role3",
+ MetadataObject.Type.SCHEMA.name(),
+ "schema2",
+ Privilege.Name.SELECT_TABLE.name()));
+ }
+
+ /** "role4" is the owner of table1. Determine whether role4 has the
permissions for table1. */
+ @Test
+ public void testTableOwner() {
+ Assertions.assertTrue(
+ enforcer.enforce("role4", MetadataObject.Type.TABLE.name(), "table1",
"OWNER"));
+ Assertions.assertTrue(
+ enforcer.enforce(
+ "role4",
+ MetadataObject.Type.TABLE.name(),
+ "table1",
+ Privilege.Name.MODIFY_TABLE.name()));
+ Assertions.assertTrue(
+ enforcer.enforce(
+ "role4",
+ MetadataObject.Type.TABLE.name(),
+ "table1",
+ Privilege.Name.SELECT_TABLE.name()));
+ Assertions.assertFalse(
+ enforcer.enforce("role3", MetadataObject.Type.SCHEMA.name(), "table1",
"OWNER"));
+ Assertions.assertFalse(
+ enforcer.enforce("role3", MetadataObject.Type.SCHEMA.name(), "table2",
"OWNER"));
+ Assertions.assertFalse(
+ enforcer.enforce(
+ "role4",
+ MetadataObject.Type.TABLE.name(),
+ "table2",
+ Privilege.Name.SELECT_TABLE.name()));
+ }
+
+ /** Check whether a role can have privileges. */
+ @Test
+ public void testRolePrivilege() {
+ // "role5" has partial privilege.
+ Assertions.assertFalse(
+ enforcer.enforce("role5", MetadataObject.Type.METALAKE.name(),
"metalake1", "OWNER"));
+
+ Assertions.assertTrue(
+ enforcer.enforce(
+ "role5",
+ MetadataObject.Type.METALAKE.name(),
+ "metalake1",
+ Privilege.Name.SELECT_TABLE.name()));
+ Assertions.assertTrue(
+ enforcer.enforce(
+ "role5",
+ MetadataObject.Type.METALAKE.name(),
+ "metalake1",
+ Privilege.Name.USE_CATALOG.name()));
+ Assertions.assertTrue(
+ enforcer.enforce(
+ "role5",
+ MetadataObject.Type.TABLE.name(),
+ "table1",
+ Privilege.Name.SELECT_TABLE.name()));
+ Assertions.assertFalse(
+ enforcer.enforce(
+ "role5",
+ MetadataObject.Type.METALAKE.name(),
+ "metalake2",
+ Privilege.Name.SELECT_TABLE.name()));
+ Assertions.assertFalse(
+ enforcer.enforce(
+ "role5",
+ MetadataObject.Type.METALAKE.name(),
+ "metalake2",
+ Privilege.Name.USE_CATALOG.name()));
+ Assertions.assertFalse(
+ enforcer.enforce(
+ "role5",
+ MetadataObject.Type.TABLE.name(),
+ "table2",
+ Privilege.Name.SELECT_TABLE.name()));
+ Assertions.assertFalse(
+ enforcer.enforce(
+ "role5",
+ MetadataObject.Type.TABLE.name(),
+ "table1",
+ Privilege.Name.MODIFY_TABLE.name()));
+
+ // role1000 has no privilege.
+ Assertions.assertFalse(
+ enforcer.enforce("role1000", MetadataObject.Type.METALAKE.name(),
"metalake1", "OWNER"));
+
+ Assertions.assertFalse(
+ enforcer.enforce(
+ "role1000",
+ MetadataObject.Type.METALAKE.name(),
+ "metalake1",
+ Privilege.Name.SELECT_TABLE.name()));
+ Assertions.assertFalse(
+ enforcer.enforce(
+ "role1000",
+ MetadataObject.Type.METALAKE.name(),
+ "metalake1",
+ Privilege.Name.USE_CATALOG.name()));
+ Assertions.assertFalse(
+ enforcer.enforce(
+ "role1000",
+ MetadataObject.Type.TABLE.name(),
+ "table1",
+ Privilege.Name.SELECT_TABLE.name()));
+ Assertions.assertFalse(
+ enforcer.enforce(
+ "role1000",
+ MetadataObject.Type.METALAKE.name(),
+ "metalake2",
+ Privilege.Name.SELECT_TABLE.name()));
+ Assertions.assertFalse(
+ enforcer.enforce(
+ "role1000",
+ MetadataObject.Type.METALAKE.name(),
+ "metalake2",
+ Privilege.Name.USE_CATALOG.name()));
+ Assertions.assertFalse(
+ enforcer.enforce(
+ "role1000",
+ MetadataObject.Type.TABLE.name(),
+ "table2",
+ Privilege.Name.SELECT_TABLE.name()));
+ Assertions.assertFalse(
+ enforcer.enforce(
+ "role1000",
+ MetadataObject.Type.TABLE.name(),
+ "table1",
+ Privilege.Name.MODIFY_TABLE.name()));
+ }
+
+ /**
+ * Determine whether a group, after being assigned a role, can inherit the
permissions of that
+ * role.
+ */
+ @Test
+ public void testGroupPrivilege() {
+ // "group1" possesses role5, and therefore, group5 has the permissions of
role5.
+ Assertions.assertFalse(
+ enforcer.enforce("group1", MetadataObject.Type.METALAKE.name(),
"metalake1", "OWNER"));
+
+ Assertions.assertTrue(
+ enforcer.enforce(
+ "group1",
+ MetadataObject.Type.METALAKE.name(),
+ "metalake1",
+ Privilege.Name.SELECT_TABLE.name()));
+ Assertions.assertTrue(
+ enforcer.enforce(
+ "group1",
+ MetadataObject.Type.METALAKE.name(),
+ "metalake1",
+ Privilege.Name.USE_CATALOG.name()));
+ Assertions.assertTrue(
+ enforcer.enforce(
+ "group1",
+ MetadataObject.Type.TABLE.name(),
+ "table1",
+ Privilege.Name.SELECT_TABLE.name()));
+ Assertions.assertFalse(
+ enforcer.enforce(
+ "group1",
+ MetadataObject.Type.METALAKE.name(),
+ "metalake2",
+ Privilege.Name.SELECT_TABLE.name()));
+ Assertions.assertFalse(
+ enforcer.enforce(
+ "group1",
+ MetadataObject.Type.METALAKE.name(),
+ "metalake2",
+ Privilege.Name.USE_CATALOG.name()));
+ Assertions.assertFalse(
+ enforcer.enforce(
+ "group1",
+ MetadataObject.Type.TABLE.name(),
+ "table2",
+ Privilege.Name.SELECT_TABLE.name()));
+ Assertions.assertFalse(
+ enforcer.enforce(
+ "group1",
+ MetadataObject.Type.TABLE.name(),
+ "table1",
+ Privilege.Name.MODIFY_TABLE.name()));
+
+ // group1000 has no roles and therefore has no permissions.
+ Assertions.assertFalse(
+ enforcer.enforce("group1000", MetadataObject.Type.METALAKE.name(),
"metalake1", "OWNER"));
+
+ Assertions.assertFalse(
+ enforcer.enforce(
+ "group1000",
+ MetadataObject.Type.METALAKE.name(),
+ "metalake1",
+ Privilege.Name.SELECT_TABLE.name()));
+ Assertions.assertFalse(
+ enforcer.enforce(
+ "group1000",
+ MetadataObject.Type.METALAKE.name(),
+ "metalake1",
+ Privilege.Name.USE_CATALOG.name()));
+ Assertions.assertFalse(
+ enforcer.enforce(
+ "group1000",
+ MetadataObject.Type.TABLE.name(),
+ "table1",
+ Privilege.Name.SELECT_TABLE.name()));
+ Assertions.assertFalse(
+ enforcer.enforce(
+ "group1000",
+ MetadataObject.Type.METALAKE.name(),
+ "metalake2",
+ Privilege.Name.SELECT_TABLE.name()));
+ Assertions.assertFalse(
+ enforcer.enforce(
+ "group1000",
+ MetadataObject.Type.METALAKE.name(),
+ "metalake2",
+ Privilege.Name.USE_CATALOG.name()));
+ Assertions.assertFalse(
+ enforcer.enforce(
+ "group1000",
+ MetadataObject.Type.TABLE.name(),
+ "table2",
+ Privilege.Name.SELECT_TABLE.name()));
+ Assertions.assertFalse(
+ enforcer.enforce(
+ "group1000",
+ MetadataObject.Type.TABLE.name(),
+ "table1",
+ Privilege.Name.MODIFY_TABLE.name()));
+ }
+
+ /**
+ * Determine whether a user can have the corresponding permissions after
being granted a role or
+ * belonging to a user group.
+ */
+ @Test
+ public void testUserPrivilege() {
+ // ”user1" has the privilege of role5.
+ Assertions.assertFalse(
+ enforcer.enforce("user1", MetadataObject.Type.METALAKE.name(),
"metalake1", "OWNER"));
+
+ Assertions.assertTrue(
+ enforcer.enforce(
+ "user1",
+ MetadataObject.Type.METALAKE.name(),
+ "metalake1",
+ Privilege.Name.SELECT_TABLE.name()));
+ Assertions.assertTrue(
+ enforcer.enforce(
+ "user1",
+ MetadataObject.Type.METALAKE.name(),
+ "metalake1",
+ Privilege.Name.USE_CATALOG.name()));
+ Assertions.assertTrue(
+ enforcer.enforce(
+ "user1",
+ MetadataObject.Type.TABLE.name(),
+ "table1",
+ Privilege.Name.SELECT_TABLE.name()));
+ Assertions.assertFalse(
+ enforcer.enforce(
+ "user1",
+ MetadataObject.Type.METALAKE.name(),
+ "metalake2",
+ Privilege.Name.SELECT_TABLE.name()));
+ Assertions.assertFalse(
+ enforcer.enforce(
+ "user1",
+ MetadataObject.Type.METALAKE.name(),
+ "metalake2",
+ Privilege.Name.USE_CATALOG.name()));
+ Assertions.assertFalse(
+ enforcer.enforce(
+ "user1",
+ MetadataObject.Type.TABLE.name(),
+ "table2",
+ Privilege.Name.SELECT_TABLE.name()));
+ Assertions.assertFalse(
+ enforcer.enforce(
+ "user1",
+ MetadataObject.Type.TABLE.name(),
+ "table1",
+ Privilege.Name.MODIFY_TABLE.name()));
+
+ // ”user2" has the privilege of group1.
+ Assertions.assertFalse(
+ enforcer.enforce("user2", MetadataObject.Type.METALAKE.name(),
"metalake1", "OWNER"));
+
+ Assertions.assertTrue(
+ enforcer.enforce(
+ "user2",
+ MetadataObject.Type.METALAKE.name(),
+ "metalake1",
+ Privilege.Name.SELECT_TABLE.name()));
+ Assertions.assertTrue(
+ enforcer.enforce(
+ "user2",
+ MetadataObject.Type.METALAKE.name(),
+ "metalake1",
+ Privilege.Name.USE_CATALOG.name()));
+ Assertions.assertFalse(
+ enforcer.enforce(
+ "user2",
+ MetadataObject.Type.TABLE.name(),
+ "table1",
+ Privilege.Name.MODIFY_TABLE.name()));
+ Assertions.assertFalse(
+ enforcer.enforce(
+ "user2",
+ MetadataObject.Type.METALAKE.name(),
+ "metalake2",
+ Privilege.Name.SELECT_TABLE.name()));
+ Assertions.assertFalse(
+ enforcer.enforce(
+ "user2",
+ MetadataObject.Type.METALAKE.name(),
+ "metalake2",
+ Privilege.Name.USE_CATALOG.name()));
+ Assertions.assertFalse(
+ enforcer.enforce(
+ "user2",
+ MetadataObject.Type.TABLE.name(),
+ "table2",
+ Privilege.Name.SELECT_TABLE.name()));
+ Assertions.assertFalse(
+ enforcer.enforce(
+ "user2",
+ MetadataObject.Type.TABLE.name(),
+ "table1",
+ Privilege.Name.MODIFY_TABLE.name()));
+
+ // "user3" has the privilege of both role1 and group1.
+ Assertions.assertTrue(
+ enforcer.enforce("user3", MetadataObject.Type.METALAKE.name(),
"metalake1", "OWNER"));
+
+ Assertions.assertTrue(
+ enforcer.enforce(
+ "user3",
+ MetadataObject.Type.METALAKE.name(),
+ "metalake1",
+ Privilege.Name.SELECT_TABLE.name()));
+ Assertions.assertTrue(
+ enforcer.enforce(
+ "user3",
+ MetadataObject.Type.METALAKE.name(),
+ "metalake1",
+ Privilege.Name.USE_CATALOG.name()));
+ Assertions.assertFalse(
+ enforcer.enforce(
+ "user3",
+ MetadataObject.Type.TABLE.name(),
+ "table1",
+ Privilege.Name.MODIFY_TABLE.name()));
+ Assertions.assertFalse(
+ enforcer.enforce(
+ "user3",
+ MetadataObject.Type.METALAKE.name(),
+ "metalake2",
+ Privilege.Name.SELECT_TABLE.name()));
+ Assertions.assertFalse(
+ enforcer.enforce(
+ "user3",
+ MetadataObject.Type.METALAKE.name(),
+ "metalake2",
+ Privilege.Name.USE_CATALOG.name()));
+ Assertions.assertFalse(
+ enforcer.enforce(
+ "user3",
+ MetadataObject.Type.TABLE.name(),
+ "table2",
+ Privilege.Name.SELECT_TABLE.name()));
+ Assertions.assertFalse(
+ enforcer.enforce(
+ "user3",
+ MetadataObject.Type.TABLE.name(),
+ "table1",
+ Privilege.Name.MODIFY_TABLE.name()));
+
+ Assertions.assertFalse(
+ enforcer.enforce("user1000", MetadataObject.Type.METALAKE.name(),
"metalake1", "OWNER"));
+
+ // "user1000" has no roles and therefore has no permissions.
+ Assertions.assertFalse(
+ enforcer.enforce(
+ "user1000",
+ MetadataObject.Type.METALAKE.name(),
+ "metalake1",
+ Privilege.Name.SELECT_TABLE.name()));
+ Assertions.assertFalse(
+ enforcer.enforce(
+ "user1000",
+ MetadataObject.Type.METALAKE.name(),
+ "metalake1",
+ Privilege.Name.USE_CATALOG.name()));
+ Assertions.assertFalse(
+ enforcer.enforce(
+ "user1000",
+ MetadataObject.Type.TABLE.name(),
+ "table1",
+ Privilege.Name.MODIFY_TABLE.name()));
+ Assertions.assertFalse(
+ enforcer.enforce(
+ "user1000",
+ MetadataObject.Type.METALAKE.name(),
+ "metalake2",
+ Privilege.Name.SELECT_TABLE.name()));
+ Assertions.assertFalse(
+ enforcer.enforce(
+ "user1000",
+ MetadataObject.Type.METALAKE.name(),
+ "metalake2",
+ Privilege.Name.USE_CATALOG.name()));
+ Assertions.assertFalse(
+ enforcer.enforce(
+ "user1000",
+ MetadataObject.Type.TABLE.name(),
+ "table2",
+ Privilege.Name.MODIFY_TABLE.name()));
+ Assertions.assertFalse(
+ enforcer.enforce(
+ "user1000",
+ MetadataObject.Type.TABLE.name(),
+ "table1",
+ Privilege.Name.SELECT_TABLE.name()));
+ }
+}
diff --git a/server-common/src/test/resources/jcasbin_policy.txt
b/server-common/src/test/resources/jcasbin_policy.txt
new file mode 100644
index 0000000000..e71a5b6c54
--- /dev/null
+++ b/server-common/src/test/resources/jcasbin_policy.txt
@@ -0,0 +1,28 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+# http://www.apache.org/licenses/LICENSE-2.0
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+p, role1, METALAKE, metalake1, OWNER, allow
+p, role2, CATALOG, catalog1, OWNER, allow
+p, role3, SCHEMA, schema1, OWNER, allow
+p, role4, TABLE, table1, OWNER, allow
+p, role5, METALAKE, metalake1, SELECT_TABLE, allow
+p, role5, METALAKE, metalake1, USE_CATALOG, allow
+p, role5, TABLE, table1, SELECT_TABLE, allow
+
+g, user1, role5
+g, group1, role5
+g, user2, group1
+g, user3, role1
+g, user3, group1