This is an automated email from the ASF dual-hosted git repository. morningman pushed a commit to branch branch-2.1 in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/branch-2.1 by this push: new 3cb0deae9ce [opt](ranger) modify and enhance the feature of ranger access controller (#34392) (#34426) 3cb0deae9ce is described below commit 3cb0deae9ceef92c71c35444c495bc5b94de6c7c Author: Mingyu Chen <morning...@163.com> AuthorDate: Mon May 6 17:08:47 2024 +0800 [opt](ranger) modify and enhance the feature of ranger access controller (#34392) (#34426) bp #34392 --- .../authorizer/ranger/RangerAccessController.java | 29 ++- .../authorizer/ranger/doris/DorisAccessType.java | 6 +- .../ranger/doris/RangerDorisAccessController.java | 27 ++- .../ranger/hive/RangerHiveAccessController.java | 4 +- .../org/apache/doris/common/util/PrintableMap.java | 11 +- .../org/apache/doris/mysql/privilege/Auth.java | 3 +- .../expressions/functions/scalar/DateTrunc.java | 2 +- .../apache/doris/mysql/privilege/RangerTest.java | 230 +++++++++++++++++++++ 8 files changed, 297 insertions(+), 15 deletions(-) diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/authorizer/ranger/RangerAccessController.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/authorizer/ranger/RangerAccessController.java index 5f49f4d5735..41aa5213839 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/catalog/authorizer/ranger/RangerAccessController.java +++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/authorizer/ranger/RangerAccessController.java @@ -68,7 +68,6 @@ public abstract class RangerAccessController implements CatalogAccessController } } - public static void checkRequestResults(Collection<RangerAccessResult> results, String name) throws AuthorizationException { for (RangerAccessResult result : results) { @@ -82,7 +81,8 @@ public abstract class RangerAccessController implements CatalogAccessController throw new AuthorizationException(String.format( "Permission denied: user [%s] does not have privilege for [%s] command on [%s]", result.getAccessRequest().getUser(), name, - result.getAccessRequest().getResource().getAsString().replaceAll("/", "."))); + Optional.ofNullable(result.getAccessRequest().getResource().getAsString()) + .orElse("unknown resource").replaceAll("/", "."))); } } } @@ -135,12 +135,27 @@ public abstract class RangerAccessController implements CatalogAccessController if (StringUtils.isEmpty(maskType)) { return Optional.empty(); } - String transformer = policy.getMaskTypeDef().getTransformer(); - if (StringUtils.isEmpty(transformer)) { - return Optional.empty(); + switch (maskType) { + case "MASK_NULL": + return Optional.of(new RangerDataMaskPolicy(currentUser, ctl, db, tbl, col, policy.getPolicyId(), + policy.getPolicyVersion(), maskType, "NULL")); + case "MASK_NONE": + return Optional.empty(); + case "CUSTOM": + String maskedValue = policy.getMaskedValue(); + if (StringUtils.isEmpty(maskedValue)) { + return Optional.empty(); + } + return Optional.of(new RangerDataMaskPolicy(currentUser, ctl, db, tbl, col, policy.getPolicyId(), + policy.getPolicyVersion(), maskType, maskedValue.replace("{col}", col))); + default: + String transformer = policy.getMaskTypeDef().getTransformer(); + if (StringUtils.isEmpty(transformer)) { + return Optional.empty(); + } + return Optional.of(new RangerDataMaskPolicy(currentUser, ctl, db, tbl, col, policy.getPolicyId(), + policy.getPolicyVersion(), maskType, transformer.replace("{col}", col))); } - return Optional.of(new RangerDataMaskPolicy(currentUser, ctl, db, tbl, col, policy.getPolicyId(), - policy.getPolicyVersion(), maskType, transformer.replace("{col}", col))); } protected abstract RangerAccessRequestImpl createRequest(UserIdentity currentUser); diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/authorizer/ranger/doris/DorisAccessType.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/authorizer/ranger/doris/DorisAccessType.java index e71d6847e8a..259646557da 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/catalog/authorizer/ranger/doris/DorisAccessType.java +++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/authorizer/ranger/doris/DorisAccessType.java @@ -46,9 +46,11 @@ public enum DorisAccessType { } else if (priv == PrivPredicate.SHOW_VIEW) { return SHOW_VIEW; } else if (priv == PrivPredicate.SHOW_RESOURCES) { - return SHOW_RESOURCES; + // For Ranger, there is only USAGE priv for RESOURCE and WORKLOAD_GROUP. + // So when checking SHOW_XXX priv, convert it to USAGE priv and pass to Ranger. + return USAGE; } else if (priv == PrivPredicate.SHOW_WORKLOAD_GROUP) { - return SHOW_WORKLOAD_GROUP; + return USAGE; } else if (priv == PrivPredicate.GRANT) { return GRANT; } else if (priv == PrivPredicate.ADMIN) { diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/authorizer/ranger/doris/RangerDorisAccessController.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/authorizer/ranger/doris/RangerDorisAccessController.java index 280321cf26f..fdf9064a5f7 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/catalog/authorizer/ranger/doris/RangerDorisAccessController.java +++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/authorizer/ranger/doris/RangerDorisAccessController.java @@ -23,7 +23,9 @@ import org.apache.doris.catalog.authorizer.ranger.RangerAccessController; import org.apache.doris.cluster.ClusterNamespace; import org.apache.doris.common.AuthorizationException; import org.apache.doris.mysql.privilege.PrivPredicate; +import org.apache.doris.resource.workloadgroup.WorkloadGroupMgr; +import com.google.common.annotations.VisibleForTesting; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.ranger.plugin.policyengine.RangerAccessRequest; @@ -41,7 +43,7 @@ import java.util.stream.Collectors; public class RangerDorisAccessController extends RangerAccessController { private static final Logger LOG = LogManager.getLogger(RangerDorisAccessController.class); - private RangerDorisPlugin dorisPlugin; + private RangerBasePlugin dorisPlugin; // private static ScheduledThreadPoolExecutor logFlushTimer = ThreadPoolManager.newDaemonScheduledThreadPool(1, // "ranger-doris-audit-log-flusher-timer", true); // private RangerHiveAuditHandler auditHandler; @@ -53,6 +55,11 @@ public class RangerDorisAccessController extends RangerAccessController { // logFlushTimer.scheduleAtFixedRate(new RangerHiveAuditLogFlusher(auditHandler), 10, 20L, TimeUnit.SECONDS); } + @VisibleForTesting + public RangerDorisAccessController(RangerBasePlugin plugin) { + dorisPlugin = plugin; + } + private RangerAccessRequestImpl createRequest(UserIdentity currentUser, DorisAccessType accessType) { RangerAccessRequestImpl request = createRequest(currentUser); request.setAction(accessType.name()); @@ -117,6 +124,10 @@ public class RangerDorisAccessController extends RangerAccessController { @Override public boolean checkDbPriv(UserIdentity currentUser, String ctl, String db, PrivPredicate wanted) { + boolean res = checkCtlPriv(currentUser, ctl, wanted); + if (res) { + return true; + } RangerDorisResource resource = new RangerDorisResource(DorisObjectType.DATABASE, ctl, ClusterNamespace.getNameFromFullName(db)); return checkPrivilege(currentUser, DorisAccessType.toAccessType(wanted), resource); @@ -124,6 +135,11 @@ public class RangerDorisAccessController extends RangerAccessController { @Override public boolean checkTblPriv(UserIdentity currentUser, String ctl, String db, String tbl, PrivPredicate wanted) { + boolean res = checkDbPriv(currentUser, ctl, db, wanted); + if (res) { + return true; + } + RangerDorisResource resource = new RangerDorisResource(DorisObjectType.TABLE, ctl, ClusterNamespace.getNameFromFullName(db), tbl); return checkPrivilege(currentUser, DorisAccessType.toAccessType(wanted), resource); @@ -132,6 +148,11 @@ public class RangerDorisAccessController extends RangerAccessController { @Override public void checkColsPriv(UserIdentity currentUser, String ctl, String db, String tbl, Set<String> cols, PrivPredicate wanted) throws AuthorizationException { + boolean res = checkTblPriv(currentUser, ctl, db, tbl, wanted); + if (res) { + return; + } + List<RangerDorisResource> resources = new ArrayList<>(); for (String col : cols) { RangerDorisResource resource = new RangerDorisResource(DorisObjectType.COLUMN, @@ -150,6 +171,10 @@ public class RangerDorisAccessController extends RangerAccessController { @Override public boolean checkWorkloadGroupPriv(UserIdentity currentUser, String workloadGroupName, PrivPredicate wanted) { + // For compatibility with older versions, it is not needed to check the privileges of the default group. + if (WorkloadGroupMgr.DEFAULT_GROUP_NAME.equals(workloadGroupName)) { + return true; + } RangerDorisResource resource = new RangerDorisResource(DorisObjectType.WORKLOAD_GROUP, workloadGroupName); return checkPrivilege(currentUser, DorisAccessType.toAccessType(wanted), resource); } diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/authorizer/ranger/hive/RangerHiveAccessController.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/authorizer/ranger/hive/RangerHiveAccessController.java index 789ba9ddf4a..f746607303d 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/catalog/authorizer/ranger/hive/RangerHiveAccessController.java +++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/authorizer/ranger/hive/RangerHiveAccessController.java @@ -184,7 +184,9 @@ public class RangerHiveAccessController extends RangerAccessController { @Override public boolean checkWorkloadGroupPriv(UserIdentity currentUser, String workloadGroupName, PrivPredicate wanted) { - return false; + // Not support workload group privilege in ranger hive plugin. + // So always return true to pass the check + return true; } @Override diff --git a/fe/fe-core/src/main/java/org/apache/doris/common/util/PrintableMap.java b/fe/fe-core/src/main/java/org/apache/doris/common/util/PrintableMap.java index 27d6468827b..734f0ae2268 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/common/util/PrintableMap.java +++ b/fe/fe-core/src/main/java/org/apache/doris/common/util/PrintableMap.java @@ -55,8 +55,15 @@ public class PrintableMap<K, V> { SENSITIVE_KEY.add("bos_secret_accesskey"); SENSITIVE_KEY.add("jdbc.password"); SENSITIVE_KEY.add("elasticsearch.password"); - SENSITIVE_KEY.addAll(Arrays.asList(S3Properties.SECRET_KEY, ObsProperties.SECRET_KEY, OssProperties.SECRET_KEY, - GCSProperties.SECRET_KEY, CosProperties.SECRET_KEY, GlueProperties.SECRET_KEY, MCProperties.SECRET_KEY, + SENSITIVE_KEY.addAll(Arrays.asList( + S3Properties.SECRET_KEY, + S3Properties.Env.SECRET_KEY, + ObsProperties.SECRET_KEY, + OssProperties.SECRET_KEY, + GCSProperties.SECRET_KEY, + CosProperties.SECRET_KEY, + GlueProperties.SECRET_KEY, + MCProperties.SECRET_KEY, DLFProperties.SECRET_KEY)); HIDDEN_KEY = Sets.newHashSet(); HIDDEN_KEY.addAll(S3Properties.Env.FS_KEYS); diff --git a/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/Auth.java b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/Auth.java index cd47128beed..2c7d99d4195 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/Auth.java +++ b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/Auth.java @@ -386,12 +386,13 @@ public class Auth implements Writable { public boolean checkWorkloadGroupPriv(UserIdentity currentUser, String workloadGroupName, PrivPredicate wanted) { readLock(); try { - Set<Role> roles = getRolesByUserWithLdap(currentUser); // currently stream load not support ip based auth, so normal should not auth temporary // need remove later if (WorkloadGroupMgr.DEFAULT_GROUP_NAME.equals(workloadGroupName)) { return true; } + + Set<Role> roles = getRolesByUserWithLdap(currentUser); for (Role role : roles) { if (role.checkWorkloadGroupPriv(workloadGroupName, wanted)) { return true; diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/DateTrunc.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/DateTrunc.java index 03408b48dd5..743976c6c1a 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/DateTrunc.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/DateTrunc.java @@ -68,7 +68,7 @@ public class DateTrunc extends ScalarFunction final String constParam = ((VarcharLiteral) getArgument(1)).getStringValue().toLowerCase(); if (!Lists.newArrayList("year", "quarter", "month", "week", "day", "hour", "minute", "second") .contains(constParam)) { - throw new AnalysisException("date_trunc function second param only support argument is" + throw new AnalysisException("date_trunc function second param only support argument is " + "year|quarter|month|week|day|hour|minute|second"); } } diff --git a/fe/fe-core/src/test/java/org/apache/doris/mysql/privilege/RangerTest.java b/fe/fe-core/src/test/java/org/apache/doris/mysql/privilege/RangerTest.java new file mode 100644 index 00000000000..a0f0ef0f2d1 --- /dev/null +++ b/fe/fe-core/src/test/java/org/apache/doris/mysql/privilege/RangerTest.java @@ -0,0 +1,230 @@ +// 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.doris.mysql.privilege; + +import org.apache.doris.analysis.UserIdentity; +import org.apache.doris.catalog.authorizer.ranger.doris.RangerDorisAccessController; +import org.apache.doris.catalog.authorizer.ranger.doris.RangerDorisResource; +import org.apache.doris.common.AuthorizationException; + +import com.google.common.base.Strings; +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; +import org.apache.ranger.plugin.policyengine.RangerAccessRequest; +import org.apache.ranger.plugin.policyengine.RangerAccessResource; +import org.apache.ranger.plugin.policyengine.RangerAccessResult; +import org.apache.ranger.plugin.policyengine.RangerAccessResultProcessor; +import org.apache.ranger.plugin.service.RangerBasePlugin; +import org.junit.Test; +import org.junit.jupiter.api.Assertions; + +import java.util.Collection; +import java.util.List; +import java.util.Optional; +import java.util.Set; + +public class RangerTest { + + public static class DorisTestPlugin extends RangerBasePlugin { + public DorisTestPlugin(String serviceName) { + super(serviceName, null, null); + // super.init(); + } + + @Override + public Collection<RangerAccessResult> isAccessAllowed(Collection<RangerAccessRequest> requests) { + List<RangerAccessResult> results = Lists.newArrayList(); + for (RangerAccessRequest request : requests) { + RangerAccessResult result = isAccessAllowed(request); + if (result != null) { + results.add(result); + } + } + return results; + } + + @Override + public RangerAccessResult isAccessAllowed(RangerAccessRequest request) { + RangerAccessResource resource = request.getResource(); + String ctl = (String) resource.getValue(RangerDorisResource.KEY_CATALOG); + String db = (String) resource.getValue(RangerDorisResource.KEY_DATABASE); + String tbl = (String) resource.getValue(RangerDorisResource.KEY_TABLE); + String col = (String) resource.getValue(RangerDorisResource.KEY_COLUMN); + String rs = (String) resource.getValue(RangerDorisResource.KEY_RESOURCE); + String wg = (String) resource.getValue(RangerDorisResource.KEY_WORKLOAD_GROUP); + String user = request.getUser(); + return returnAccessResult(request, ctl, db, tbl, col, rs, wg, user); + } + + @Override + public RangerAccessResult evalDataMaskPolicies(RangerAccessRequest request, + RangerAccessResultProcessor resultProcessor) { + RangerAccessResource resource = request.getResource(); + String ctl = (String) resource.getValue(RangerDorisResource.KEY_CATALOG); + String db = (String) resource.getValue(RangerDorisResource.KEY_DATABASE); + String tbl = (String) resource.getValue(RangerDorisResource.KEY_TABLE); + String col = (String) resource.getValue(RangerDorisResource.KEY_COLUMN); + + RangerAccessResult result = new RangerAccessResult(2, "test", null, request); + result.setPolicyVersion(1L); + if ("ctl1".equals(ctl) && "db1".equals(db) && "tbl1".equals(tbl) && "col1".equals(col)) { + result.addAdditionalInfo("maskType", "MASK_NULL"); + } else if ("ctl1".equals(ctl) && "db1".equals(db) && "tbl1".equals(tbl) && "col2".equals(col)) { + result.addAdditionalInfo("maskType", "MASK_NONE"); + } else if ("ctl1".equals(ctl) && "db1".equals(db) && "tbl1".equals(tbl) && "col3".equals(col)) { + result.addAdditionalInfo("maskType", "CUSTOM"); + result.addAdditionalInfo("maskedValue", "hex({col})"); + } else { + // Unable to mock other mask type + result.addAdditionalInfo("maskType", ""); + } + return result; + } + + private RangerAccessResult returnAccessResult( + RangerAccessRequest request, String ctl, String db, String tbl, + String col, String rs, String wg, String user) { + RangerAccessResult result = new RangerAccessResult(1, "test", null, request); + if (!Strings.isNullOrEmpty(wg)) { + result.setIsAllowed(wg.equals("wg1")); + } else if (!Strings.isNullOrEmpty(rs)) { + result.setIsAllowed(wg.equals("rs1")); + } else if (!Strings.isNullOrEmpty(col)) { + boolean res = ("ctl1".equals(ctl) && "db1".equals(db) && "tbl1".equals(tbl) && "col1".equals(col)) + || ("ctl1".equals(ctl) && "db1".equals(db) && "tbl1".equals(tbl) && "col2".equals(col)); + result.setIsAllowed(res); + } else if (!Strings.isNullOrEmpty(tbl)) { + result.setIsAllowed("ctl2".equals(ctl) && "db2".equals(db) && "tbl2".equals(tbl)); + } else if (!Strings.isNullOrEmpty(db)) { + result.setIsAllowed("ctl3".equals(ctl) && "db3".equals(db)); + } else if (!Strings.isNullOrEmpty(ctl)) { + result.setIsAllowed("ctl4".equals(ctl)); + } else { + result.setIsAllowed(false); + } + return result; + } + } + + // Does not have priv on ctl1.db1.tbl1.col3 + @Test(expected = AuthorizationException.class) + public void testNoAuthCol() throws AuthorizationException { + DorisTestPlugin plugin = new DorisTestPlugin("test"); + RangerDorisAccessController ac = new RangerDorisAccessController(plugin); + UserIdentity ui = UserIdentity.createAnalyzedUserIdentWithIp("user1", "%"); + Set<String> cols = Sets.newHashSet(); + cols.add("col1"); + cols.add("col3"); + ac.checkColsPriv(ui, "ctl1", "db1", "tbl1", cols, PrivPredicate.SELECT); + } + + // Have priv on ctl1.db1.tbl1.col1 & col2 + @Test + public void testAuthCol() throws AuthorizationException { + DorisTestPlugin plugin = new DorisTestPlugin("test"); + RangerDorisAccessController ac = new RangerDorisAccessController(plugin); + UserIdentity ui = UserIdentity.createAnalyzedUserIdentWithIp("user1", "%"); + Set<String> cols = Sets.newHashSet(); + cols.add("col1"); + cols.add("col2"); + ac.checkColsPriv(ui, "ctl1", "db1", "tbl1", cols, PrivPredicate.SELECT); + } + + // Have priv on ctl2.db2.tbl2, so when checking auth on col1 & col2, can pass + @Test + public void testUsingTableAuthAsColAuth() throws AuthorizationException { + DorisTestPlugin plugin = new DorisTestPlugin("test"); + RangerDorisAccessController ac = new RangerDorisAccessController(plugin); + UserIdentity ui = UserIdentity.createAnalyzedUserIdentWithIp("user1", "%"); + Set<String> cols = Sets.newHashSet(); + cols.add("col1"); + cols.add("col2"); + ac.checkColsPriv(ui, "ctl2", "db2", "tbl2", cols, PrivPredicate.SELECT); + } + + // Does not have priv on ctl2.db2.tbl3, so when checking auth on col1 & col2, can not pass + @Test(expected = AuthorizationException.class) + public void testUsingNoTableAuthAsColAuth() throws AuthorizationException { + DorisTestPlugin plugin = new DorisTestPlugin("test"); + RangerDorisAccessController ac = new RangerDorisAccessController(plugin); + UserIdentity ui = UserIdentity.createAnalyzedUserIdentWithIp("user1", "%"); + Set<String> cols = Sets.newHashSet(); + cols.add("col1"); + cols.add("col2"); + ac.checkColsPriv(ui, "ctl2", "db2", "tbl3", cols, PrivPredicate.SELECT); + } + + // Have priv on ctl3.db3, so when checking auth on tbl1 and (tbl1.col1 & tbl1.col2), can pass + @Test + public void testUsingDbAuthAsColAndTableAuth() throws AuthorizationException { + DorisTestPlugin plugin = new DorisTestPlugin("test"); + RangerDorisAccessController ac = new RangerDorisAccessController(plugin); + UserIdentity ui = UserIdentity.createAnalyzedUserIdentWithIp("user1", "%"); + Set<String> cols = Sets.newHashSet(); + cols.add("col1"); + cols.add("col2"); + ac.checkColsPriv(ui, "ctl3", "db3", "tbl1", cols, PrivPredicate.SELECT); + ac.checkTblPriv(ui, "ctl3", "db3", "tbl1", PrivPredicate.SELECT); + } + + + // Does not have priv on ctl2.db3, so when checking auth on col1 & col2, can not pass + @Test(expected = AuthorizationException.class) + public void testNoDbAuthAsColAndTableAuth() throws AuthorizationException { + DorisTestPlugin plugin = new DorisTestPlugin("test"); + RangerDorisAccessController ac = new RangerDorisAccessController(plugin); + UserIdentity ui = UserIdentity.createAnalyzedUserIdentWithIp("user1", "%"); + Set<String> cols = Sets.newHashSet(); + cols.add("col1"); + cols.add("col2"); + ac.checkColsPriv(ui, "ctl2", "db3", "tbl3", cols, PrivPredicate.SELECT); + } + + // Have priv on ctl4, so when checking auth on objs under ctl4, can pass + @Test + public void testUsingCtlAuthAsColAndTableAndDbAuth() throws AuthorizationException { + DorisTestPlugin plugin = new DorisTestPlugin("test"); + RangerDorisAccessController ac = new RangerDorisAccessController(plugin); + UserIdentity ui = UserIdentity.createAnalyzedUserIdentWithIp("user1", "%"); + Set<String> cols = Sets.newHashSet(); + cols.add("col1"); + cols.add("col2"); + ac.checkColsPriv(ui, "ctl4", "db1", "tbl1", cols, PrivPredicate.SELECT); + ac.checkTblPriv(ui, "ctl4", "db2", "tbl2", PrivPredicate.SELECT); + ac.checkDbPriv(ui, "ctl4", "db3", PrivPredicate.SELECT); + } + + @Test + public void testDataMask() { + DorisTestPlugin plugin = new DorisTestPlugin("test"); + RangerDorisAccessController ac = new RangerDorisAccessController(plugin); + UserIdentity ui = UserIdentity.createAnalyzedUserIdentWithIp("user1", "%"); + // MASK_NULL + Optional<DataMaskPolicy> policy = ac.evalDataMaskPolicy(ui, "ctl1", "db1", "tbl1", "col1"); + Assertions.assertEquals("NULL", policy.get().getMaskTypeDef()); + // MASK_NONE + policy = ac.evalDataMaskPolicy(ui, "ctl1", "db1", "tbl1", "col2"); + Assertions.assertTrue(!policy.isPresent()); + // CUSTOM + policy = ac.evalDataMaskPolicy(ui, "ctl1", "db1", "tbl1", "col3"); + Assertions.assertEquals("hex(col3)", policy.get().getMaskTypeDef()); + // Others + policy = ac.evalDataMaskPolicy(ui, "ctl1", "db1", "tbl1", "col4"); + Assertions.assertTrue(!policy.isPresent()); + } +} --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@doris.apache.org For additional commands, e-mail: commits-h...@doris.apache.org