From 6b923c655434a87a51b147d1b9e8769298eec13b Mon Sep 17 00:00:00 2001 From: zhangdong <493738387@qq.com> Date: Tue, 12 Mar 2024 19:04:26 +0800 Subject: [PATCH 1/3] 1 --- .../ranger/hive/RangerHiveAccessController.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) 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 3e7d3a89cd7f61..8cabd7523dae5e 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 @@ -90,7 +90,10 @@ private void checkPrivileges(UserIdentity currentUser, HiveAccessType accessType request.setResource(resource); requests.add(request); } - + for (RangerAccessRequest request: requests) { + RangerAccessResult evalResult = hivePlugin.evalDataMaskPolicies(request, auditHandler); + RangerAccessResult rowPolicyResult = hivePlugin.evalRowFilterPolicies(request, auditHandler); + } Collection results = hivePlugin.isAccessAllowed(requests, auditHandler); checkRequestResults(results, accessType.name()); } @@ -101,6 +104,10 @@ private boolean checkPrivilege(UserIdentity currentUser, HiveAccessType accessTy request.setResource(resource); RangerAccessResult result = hivePlugin.isAccessAllowed(request, auditHandler); + RangerAccessResult evalResult = hivePlugin.evalDataMaskPolicies(request, auditHandler); + String maskType = evalResult.getMaskType(); + RangerAccessResult rowPolicyResult = hivePlugin.evalRowFilterPolicies(request, auditHandler); + String filterExpr = rowPolicyResult.getFilterExpr(); return checkRequestResult(request, result, accessType.name()); } From a290e3e7a9d94fd14eacadb4017b2af1ff089694 Mon Sep 17 00:00:00 2001 From: zhangdong <493738387@qq.com> Date: Wed, 13 Mar 2024 22:01:34 +0800 Subject: [PATCH 2/3] 1 --- .../doris/RangerDorisAccessController.java | 99 ++++++++++---- .../hive/RangerHiveAccessController.java | 106 ++++++++++----- .../privilege/AccessControllerManager.java | 24 +++- .../privilege/CatalogAccessController.java | 9 ++ .../doris/mysql/privilege/DataMaskPolicy.java | 24 ++++ .../privilege/InternalAccessController.java | 32 ++++- .../mysql/privilege/RangerDataMaskPolicy.java | 123 ++++++++++++++++++ .../privilege/RangerRowFilterPolicy.java | 103 +++++++++++++++ .../mysql/privilege/RowFilterPolicy.java | 30 +++++ .../plans/logical/LogicalCheckPolicy.java | 27 ++-- .../org/apache/doris/policy/RowPolicy.java | 14 +- .../doris/datasource/ColumnPrivTest.java | 16 +++ .../privileges/TestCheckPrivileges.java | 15 +++ 13 files changed, 556 insertions(+), 66 deletions(-) create mode 100644 fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/DataMaskPolicy.java create mode 100644 fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/RangerDataMaskPolicy.java create mode 100644 fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/RangerRowFilterPolicy.java create mode 100644 fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/RowFilterPolicy.java 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 2f9ef5b8210367..84477d398c7611 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 @@ -21,11 +21,17 @@ import org.apache.doris.analysis.UserIdentity; import org.apache.doris.catalog.Env; import org.apache.doris.catalog.authorizer.ranger.RangerAccessController; -import org.apache.doris.catalog.authorizer.ranger.hive.RangerHiveResource; import org.apache.doris.cluster.ClusterNamespace; +import org.apache.doris.common.AnalysisException; import org.apache.doris.common.AuthorizationException; +import org.apache.doris.mysql.privilege.DataMaskPolicy; import org.apache.doris.mysql.privilege.PrivPredicate; +import org.apache.doris.mysql.privilege.RangerDataMaskPolicy; +import org.apache.doris.mysql.privilege.RangerRowFilterPolicy; +import org.apache.doris.mysql.privilege.RowFilterPolicy; +import com.google.common.collect.Lists; +import org.apache.commons.lang3.StringUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.ranger.plugin.policyengine.RangerAccessRequest; @@ -36,6 +42,7 @@ import java.util.Collection; import java.util.Date; import java.util.List; +import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; @@ -70,6 +77,21 @@ private RangerAccessRequestImpl createRequest(UserIdentity currentUser, DorisAcc return request; } + private RangerAccessRequestImpl createRequest(UserIdentity currentUser) { + RangerAccessRequestImpl request = new RangerAccessRequestImpl(); + request.setUser(ClusterNamespace.getNameFromFullName(currentUser.getQualifiedUser())); + Set roles = Env.getCurrentEnv().getAuth().getRolesByUser(currentUser, false); + request.setUserRoles(roles.stream().map(role -> ClusterNamespace.getNameFromFullName(role)).collect( + Collectors.toSet())); + + request.setClientIPAddress(currentUser.getHost()); + request.setClusterType(CLIENT_TYPE_DORIS); + request.setClientType(CLIENT_TYPE_DORIS); + request.setAccessTime(new Date()); + + return request; + } + private void checkPrivileges(UserIdentity currentUser, DorisAccessType accessType, List dorisResources) throws AuthorizationException { List requests = new ArrayList<>(); @@ -96,27 +118,6 @@ private boolean checkPrivilege(UserIdentity currentUser, DorisAccessType accessT return checkRequestResult(request, result, accessType.name()); } - public String getFilterExpr(UserIdentity currentUser, DorisAccessType accessType, - RangerHiveResource resource) { - RangerAccessRequestImpl request = createRequest(currentUser, accessType); - request.setResource(resource); - RangerAccessResult result = dorisPlugin.isAccessAllowed(request); - - return result.getFilterExpr(); - } - - public void getColumnMask(UserIdentity currentUser, DorisAccessType accessType, - RangerHiveResource resource) { - RangerAccessRequestImpl request = createRequest(currentUser, accessType); - request.setResource(resource); - RangerAccessResult result = dorisPlugin.isAccessAllowed(request); - - if (LOG.isDebugEnabled()) { - LOG.debug(String.format("maskType: %s, maskTypeDef: %s, maskedValue: %s", result.getMaskType(), - result.getMaskTypeDef(), result.getMaskedValue())); - } - } - @Override public boolean checkGlobalPriv(UserIdentity currentUser, PrivPredicate wanted) { // ranger does not support global privilege, @@ -159,7 +160,7 @@ public void checkColsPriv(UserIdentity currentUser, String ctl, String db, Strin @Override public boolean checkCloudPriv(UserIdentity currentUser, String resourceName, - PrivPredicate wanted, ResourceTypeEnum type) { + PrivPredicate wanted, ResourceTypeEnum type) { return false; } @@ -175,6 +176,58 @@ public boolean checkWorkloadGroupPriv(UserIdentity currentUser, String workloadG return checkPrivilege(currentUser, DorisAccessType.toAccessType(wanted), resource); } + @Override + public Optional evalDataMaskPolicy(UserIdentity currentUser, String ctl, String db, String tbl, + String col) { + RangerDorisResource resource = new RangerDorisResource(DorisObjectType.COLUMN, + ctl, ClusterNamespace.getNameFromFullName(db), tbl, col); + RangerAccessRequestImpl request = createRequest(currentUser); + request.setResource(resource); + + if (LOG.isDebugEnabled()) { + LOG.debug("ranger request: {}", request); + } + RangerAccessResult policy = dorisPlugin.evalDataMaskPolicies(request, null); + if (policy == null) { + return Optional.empty(); + } + String maskType = policy.getMaskType(); + if (StringUtils.isEmpty(maskType)) { + return Optional.empty(); + } + 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))); + } + + @Override + public List evalRowFilterPolicies(UserIdentity currentUser, String ctl, String db, + String tbl) throws AnalysisException { + RangerDorisResource resource = new RangerDorisResource(DorisObjectType.TABLE, + ctl, ClusterNamespace.getNameFromFullName(db), tbl); + RangerAccessRequestImpl request = createRequest(currentUser); + request.setResource(resource); + + if (LOG.isDebugEnabled()) { + LOG.debug("ranger request: {}", request); + } + List res = Lists.newArrayList(); + RangerAccessResult policy = dorisPlugin.evalRowFilterPolicies(request, null); + if (policy == null) { + return res; + } + String filterExpr = policy.getFilterExpr(); + if (StringUtils.isEmpty(filterExpr)) { + return res; + } + res.add(new RangerRowFilterPolicy(currentUser, ctl, db, tbl, policy.getPolicyId(), policy.getPolicyVersion(), + filterExpr)); + return res; + } + // For test only public static void main(String[] args) { RangerDorisAccessController ac = new RangerDorisAccessController("doris"); 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 8cabd7523dae5e..66d22e26b31a81 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 @@ -22,13 +22,19 @@ import org.apache.doris.catalog.Env; import org.apache.doris.catalog.authorizer.ranger.RangerAccessController; import org.apache.doris.cluster.ClusterNamespace; +import org.apache.doris.common.AnalysisException; import org.apache.doris.common.AuthorizationException; import org.apache.doris.common.ThreadPoolManager; import org.apache.doris.datasource.InternalCatalog; +import org.apache.doris.mysql.privilege.DataMaskPolicy; import org.apache.doris.mysql.privilege.PrivPredicate; +import org.apache.doris.mysql.privilege.RangerDataMaskPolicy; +import org.apache.doris.mysql.privilege.RangerRowFilterPolicy; +import org.apache.doris.mysql.privilege.RowFilterPolicy; +import com.google.common.collect.Lists; import com.google.common.collect.Maps; -import org.apache.hadoop.hive.ql.security.authorization.plugin.HiveAccessControlException; +import org.apache.commons.lang3.StringUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.ranger.plugin.policyengine.RangerAccessRequest; @@ -41,6 +47,7 @@ import java.util.Date; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; @@ -82,6 +89,21 @@ private RangerAccessRequestImpl createRequest(UserIdentity currentUser, HiveAcce return request; } + private RangerAccessRequestImpl createRequest(UserIdentity currentUser) { + RangerAccessRequestImpl request = new RangerAccessRequestImpl(); + String user = currentUser.getQualifiedUser(); + request.setUser(ClusterNamespace.getNameFromFullName(user)); + Set roles = Env.getCurrentEnv().getAuth().getRolesByUser(currentUser, false); + request.setUserRoles(roles.stream().map(role -> ClusterNamespace.getNameFromFullName(role)).collect( + Collectors.toSet())); + request.setClientIPAddress(currentUser.getHost()); + request.setClusterType(CLIENT_TYPE_DORIS); + request.setClientType(CLIENT_TYPE_DORIS); + request.setAccessTime(new Date()); + + return request; + } + private void checkPrivileges(UserIdentity currentUser, HiveAccessType accessType, List hiveResources) throws AuthorizationException { List requests = new ArrayList<>(); @@ -90,10 +112,7 @@ private void checkPrivileges(UserIdentity currentUser, HiveAccessType accessType request.setResource(resource); requests.add(request); } - for (RangerAccessRequest request: requests) { - RangerAccessResult evalResult = hivePlugin.evalDataMaskPolicies(request, auditHandler); - RangerAccessResult rowPolicyResult = hivePlugin.evalRowFilterPolicies(request, auditHandler); - } + Collection results = hivePlugin.isAccessAllowed(requests, auditHandler); checkRequestResults(results, accessType.name()); } @@ -104,34 +123,9 @@ private boolean checkPrivilege(UserIdentity currentUser, HiveAccessType accessTy request.setResource(resource); RangerAccessResult result = hivePlugin.isAccessAllowed(request, auditHandler); - RangerAccessResult evalResult = hivePlugin.evalDataMaskPolicies(request, auditHandler); - String maskType = evalResult.getMaskType(); - RangerAccessResult rowPolicyResult = hivePlugin.evalRowFilterPolicies(request, auditHandler); - String filterExpr = rowPolicyResult.getFilterExpr(); return checkRequestResult(request, result, accessType.name()); } - public String getFilterExpr(UserIdentity currentUser, HiveAccessType accessType, - RangerHiveResource resource) throws HiveAccessControlException { - RangerAccessRequestImpl request = createRequest(currentUser, accessType); - request.setResource(resource); - RangerAccessResult result = hivePlugin.isAccessAllowed(request, auditHandler); - - return result.getFilterExpr(); - } - - public void getColumnMask(UserIdentity currentUser, HiveAccessType accessType, - RangerHiveResource resource) { - RangerAccessRequestImpl request = createRequest(currentUser, accessType); - request.setResource(resource); - RangerAccessResult result = hivePlugin.isAccessAllowed(request, auditHandler); - - if (LOG.isDebugEnabled()) { - LOG.debug(String.format("maskType: %s, maskTypeDef: %s, maskedValue: %s", result.getMaskType(), - result.getMaskTypeDef(), result.getMaskedValue())); - } - } - private HiveAccessType convertToAccessType(PrivPredicate predicate) { if (predicate == PrivPredicate.SHOW) { return HiveAccessType.USE; @@ -198,6 +192,58 @@ public boolean checkCloudPriv(UserIdentity currentUser, String resourceName, return false; } + @Override + public Optional evalDataMaskPolicy(UserIdentity currentUser, String ctl, String db, String tbl, + String col) { + RangerHiveResource resource = new RangerHiveResource(HiveObjectType.COLUMN, + ClusterNamespace.getNameFromFullName(db), tbl, col); + RangerAccessRequestImpl request = createRequest(currentUser); + request.setResource(resource); + + if (LOG.isDebugEnabled()) { + LOG.debug("ranger request: {}", request); + } + RangerAccessResult policy = hivePlugin.evalDataMaskPolicies(request, auditHandler); + if (policy == null) { + return Optional.empty(); + } + String maskType = policy.getMaskType(); + if (StringUtils.isEmpty(maskType)) { + return Optional.empty(); + } + 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))); + } + + @Override + public List evalRowFilterPolicies(UserIdentity currentUser, String ctl, String db, + String tbl) throws AnalysisException { + RangerHiveResource resource = new RangerHiveResource(HiveObjectType.TABLE, + ClusterNamespace.getNameFromFullName(db), tbl); + RangerAccessRequestImpl request = createRequest(currentUser); + request.setResource(resource); + + if (LOG.isDebugEnabled()) { + LOG.debug("ranger request: {}", request); + } + List res = Lists.newArrayList(); + RangerAccessResult policy = hivePlugin.evalRowFilterPolicies(request, auditHandler); + if (policy == null) { + return res; + } + String filterExpr = policy.getFilterExpr(); + if (StringUtils.isEmpty(filterExpr)) { + return res; + } + res.add(new RangerRowFilterPolicy(currentUser, ctl, db, tbl, policy.getPolicyId(), policy.getPolicyVersion(), + filterExpr)); + return res; + } + @Override public boolean checkResourcePriv(UserIdentity currentUser, String resourceName, PrivPredicate wanted) { return false; diff --git a/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/AccessControllerManager.java b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/AccessControllerManager.java index 1223778a67eb73..6046aa07e2e29f 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/AccessControllerManager.java +++ b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/AccessControllerManager.java @@ -23,6 +23,7 @@ import org.apache.doris.catalog.AuthorizationInfo; import org.apache.doris.catalog.Env; import org.apache.doris.catalog.authorizer.ranger.doris.RangerDorisAccessController; +import org.apache.doris.common.AnalysisException; import org.apache.doris.common.Config; import org.apache.doris.common.UserException; import org.apache.doris.datasource.CatalogIf; @@ -36,7 +37,9 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; /** @@ -229,7 +232,7 @@ public boolean checkCloudPriv(ConnectContext ctx, String cloudName, PrivPredicat } public boolean checkCloudPriv(UserIdentity currentUser, String cloudName, - PrivPredicate wanted, ResourceTypeEnum type) { + PrivPredicate wanted, ResourceTypeEnum type) { return defaultAccessController.checkCloudPriv(currentUser, cloudName, wanted, type); } @@ -260,4 +263,23 @@ public boolean checkPrivByAuthInfo(ConnectContext ctx, AuthorizationInfo authInf } return true; } + + public Map> evalDataMaskPolicies(UserIdentity currentUser, String + ctl, String db, String tbl, Set cols) { + Map> res = Maps.newHashMap(); + for (String col : cols) { + res.put(col, evalDataMaskPolicy(currentUser, ctl, db, tbl, col)); + } + return res; + } + + public Optional evalDataMaskPolicy(UserIdentity currentUser, String + ctl, String db, String tbl, String col) { + return getAccessControllerOrDefault(ctl).evalDataMaskPolicy(currentUser, ctl, db, tbl, col); + } + + public List evalRowFilterPolicies(UserIdentity currentUser, String + ctl, String db, String tbl) throws AnalysisException { + return getAccessControllerOrDefault(ctl).evalRowFilterPolicies(currentUser, ctl, db, tbl); + } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/CatalogAccessController.java b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/CatalogAccessController.java index f9d4cdbd03c88a..57af911e61d4fc 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/CatalogAccessController.java +++ b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/CatalogAccessController.java @@ -19,8 +19,11 @@ import org.apache.doris.analysis.ResourceTypeEnum; import org.apache.doris.analysis.UserIdentity; +import org.apache.doris.common.AnalysisException; import org.apache.doris.common.AuthorizationException; +import java.util.List; +import java.util.Optional; import java.util.Set; public interface CatalogAccessController { @@ -77,4 +80,10 @@ void checkColsPriv(UserIdentity currentUser, String ctl, String db, String tbl, // ==== Cloud ==== boolean checkCloudPriv(UserIdentity currentUser, String resourceName, PrivPredicate wanted, ResourceTypeEnum type); + + Optional evalDataMaskPolicy(UserIdentity currentUser, String ctl, String db, String tbl, + String col); + + List evalRowFilterPolicies(UserIdentity currentUser, String ctl, String db, String tbl) + throws AnalysisException; } diff --git a/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/DataMaskPolicy.java b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/DataMaskPolicy.java new file mode 100644 index 00000000000000..ca22129628e445 --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/DataMaskPolicy.java @@ -0,0 +1,24 @@ +// 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; + +public interface DataMaskPolicy { + String getMaskTypeDef(); + + String getPolicyIdent(); +} diff --git a/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/InternalAccessController.java b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/InternalAccessController.java index 0e3fac621347aa..219c68ad78c608 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/InternalAccessController.java +++ b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/InternalAccessController.java @@ -19,8 +19,18 @@ import org.apache.doris.analysis.ResourceTypeEnum; import org.apache.doris.analysis.UserIdentity; +import org.apache.doris.catalog.Database; +import org.apache.doris.catalog.Env; +import org.apache.doris.catalog.Table; +import org.apache.doris.common.AnalysisException; import org.apache.doris.common.AuthorizationException; +import org.apache.doris.datasource.InternalCatalog; +import org.apache.doris.policy.PolicyMgr; +import com.google.common.collect.Lists; + +import java.util.List; +import java.util.Optional; import java.util.Set; public class InternalAccessController implements CatalogAccessController { @@ -68,7 +78,27 @@ public boolean checkWorkloadGroupPriv(UserIdentity currentUser, String workloadG @Override public boolean checkCloudPriv(UserIdentity currentUser, String resourceName, - PrivPredicate wanted, ResourceTypeEnum type) { + PrivPredicate wanted, ResourceTypeEnum type) { return auth.checkResourcePriv(currentUser, resourceName, wanted); } + + @Override + public Optional evalDataMaskPolicy(UserIdentity currentUser, String ctl, String db, String tbl, + String col) { + return Optional.empty(); + } + + @Override + public List evalRowFilterPolicies(UserIdentity currentUser, String ctl, String db, + String tbl) + throws AnalysisException { + // current not support external catalog + if (!InternalCatalog.INTERNAL_CATALOG_NAME.equals(ctl)) { + return Lists.newArrayList(); + } + PolicyMgr policyMgr = Env.getCurrentEnv().getPolicyMgr(); + Database database = Env.getCurrentEnv().getInternalCatalog().getDbOrAnalysisException(db); + Table table = database.getTableOrAnalysisException(tbl); + return policyMgr.getUserPolicies(database.getId(), table.getId(), currentUser); + } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/RangerDataMaskPolicy.java b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/RangerDataMaskPolicy.java new file mode 100644 index 00000000000000..cfc9184e13d7a0 --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/RangerDataMaskPolicy.java @@ -0,0 +1,123 @@ +// 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; + +public class RangerDataMaskPolicy implements DataMaskPolicy { + private UserIdentity userIdentity; + private String ctl; + private String db; + private String tbl; + private String col; + private long policyId; + private long policyVersion; + private String maskType; + private String maskTypeDef; + + public RangerDataMaskPolicy(UserIdentity userIdentity, String ctl, String db, String tbl, String col, + long policyId, + long policyVersion, String maskType, String maskTypeDef) { + this.userIdentity = userIdentity; + this.ctl = ctl; + this.db = db; + this.tbl = tbl; + this.col = col; + this.policyId = policyId; + this.policyVersion = policyVersion; + this.maskType = maskType; + this.maskTypeDef = maskTypeDef; + } + + public UserIdentity getUserIdentity() { + return userIdentity; + } + + public void setUserIdentity(UserIdentity userIdentity) { + this.userIdentity = userIdentity; + } + + public String getCtl() { + return ctl; + } + + public void setCtl(String ctl) { + this.ctl = ctl; + } + + public String getDb() { + return db; + } + + public void setDb(String db) { + this.db = db; + } + + public String getTbl() { + return tbl; + } + + public void setTbl(String tbl) { + this.tbl = tbl; + } + + public String getCol() { + return col; + } + + public void setCol(String col) { + this.col = col; + } + + public long getPolicyId() { + return policyId; + } + + public void setPolicyId(long policyId) { + this.policyId = policyId; + } + + public long getPolicyVersion() { + return policyVersion; + } + + public void setPolicyVersion(long policyVersion) { + this.policyVersion = policyVersion; + } + + public String getMaskType() { + return maskType; + } + + public void setMaskType(String maskType) { + this.maskType = maskType; + } + + public String getMaskTypeDef() { + return maskTypeDef; + } + + public void setMaskTypeDef(String maskTypeDef) { + this.maskTypeDef = maskTypeDef; + } + + @Override + public String getPolicyIdent() { + return getPolicyId() + ":" + getPolicyVersion(); + } +} diff --git a/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/RangerRowFilterPolicy.java b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/RangerRowFilterPolicy.java new file mode 100644 index 00000000000000..a64330d1dcced3 --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/RangerRowFilterPolicy.java @@ -0,0 +1,103 @@ +// 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; + +public class RangerRowFilterPolicy implements RowFilterPolicy { + private UserIdentity userIdentity; + private String ctl; + private String db; + private String tbl; + private long policyId; + private long policyVersion; + private String filterExpr; + + public RangerRowFilterPolicy(UserIdentity userIdentity, String ctl, String db, String tbl, long policyId, + long policyVersion, String filterExpr) { + this.userIdentity = userIdentity; + this.ctl = ctl; + this.db = db; + this.tbl = tbl; + this.policyId = policyId; + this.policyVersion = policyVersion; + this.filterExpr = filterExpr; + } + + public UserIdentity getUserIdentity() { + return userIdentity; + } + + public void setUserIdentity(UserIdentity userIdentity) { + this.userIdentity = userIdentity; + } + + public String getCtl() { + return ctl; + } + + public void setCtl(String ctl) { + this.ctl = ctl; + } + + public String getDb() { + return db; + } + + public void setDb(String db) { + this.db = db; + } + + public String getTbl() { + return tbl; + } + + public void setTbl(String tbl) { + this.tbl = tbl; + } + + public long getPolicyId() { + return policyId; + } + + public void setPolicyId(long policyId) { + this.policyId = policyId; + } + + public long getPolicyVersion() { + return policyVersion; + } + + public void setPolicyVersion(long policyVersion) { + this.policyVersion = policyVersion; + } + + @Override + public String getFilterExpr() { + return filterExpr; + } + + public void setFilterExpr(String filterExpr) { + this.filterExpr = filterExpr; + } + + @Override + public String getPolicyIdent() { + return getPolicyId() + ":" + getPolicyVersion(); + } +} diff --git a/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/RowFilterPolicy.java b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/RowFilterPolicy.java new file mode 100644 index 00000000000000..7e87dae5e4fcb5 --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/RowFilterPolicy.java @@ -0,0 +1,30 @@ +// 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.policy.FilterType; + +public interface RowFilterPolicy { + default FilterType getFilterType() { + return FilterType.RESTRICTIVE; + } + + String getFilterExpr(); + + String getPolicyIdent(); +} diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalCheckPolicy.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalCheckPolicy.java index 5630153c0ced4a..e0aa028b22ba29 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalCheckPolicy.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalCheckPolicy.java @@ -18,6 +18,8 @@ package org.apache.doris.nereids.trees.plans.logical; import org.apache.doris.analysis.UserIdentity; +import org.apache.doris.mysql.privilege.AccessControllerManager; +import org.apache.doris.mysql.privilege.RowFilterPolicy; import org.apache.doris.nereids.exceptions.AnalysisException; import org.apache.doris.nereids.memo.GroupExpression; import org.apache.doris.nereids.parser.NereidsParser; @@ -33,8 +35,6 @@ import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor; import org.apache.doris.nereids.util.ExpressionUtils; import org.apache.doris.nereids.util.Utils; -import org.apache.doris.policy.PolicyMgr; -import org.apache.doris.policy.RowPolicy; import org.apache.doris.qe.ConnectContext; import com.google.common.base.Preconditions; @@ -125,32 +125,39 @@ public Optional getFilter(LogicalRelation logicalRelation, ConnectCo return Optional.empty(); } - PolicyMgr policyMgr = connectContext.getEnv().getPolicyMgr(); + AccessControllerManager accessManager = connectContext.getEnv().getAccessManager(); UserIdentity currentUserIdentity = connectContext.getCurrentUserIdentity(); if (currentUserIdentity.isRootUser() || currentUserIdentity.isAdminUser()) { return Optional.empty(); } CatalogRelation catalogRelation = (CatalogRelation) logicalRelation; - long dbId = catalogRelation.getDatabase().getId(); - long tableId = catalogRelation.getTable().getId(); - List policies = policyMgr.getUserPolicies(dbId, tableId, currentUserIdentity); + String ctlName = catalogRelation.getDatabase().getCatalog().getName(); + String dbName = catalogRelation.getDatabase().getFullName(); + String tableName = catalogRelation.getTable().getName(); + List policies = null; + try { + policies = accessManager.evalRowFilterPolicies(currentUserIdentity, ctlName, + dbName, tableName); + } catch (org.apache.doris.common.AnalysisException e) { + throw new AnalysisException(e.getMessage(), e); + } if (policies.isEmpty()) { return Optional.empty(); } return Optional.ofNullable(mergeRowPolicy(policies)); } - private Expression mergeRowPolicy(List policies) { + private Expression mergeRowPolicy(List policies) { List orList = new ArrayList<>(); List andList = new ArrayList<>(); - for (RowPolicy policy : policies) { - String sql = policy.getOriginStmt(); + for (RowFilterPolicy policy : policies) { + String sql = policy.getFilterExpr(); NereidsParser nereidsParser = new NereidsParser(); CreatePolicyCommand command = (CreatePolicyCommand) nereidsParser.parseSingle(sql); Optional wherePredicate = command.getWherePredicate(); if (!wherePredicate.isPresent()) { - throw new AnalysisException("Invalid row policy [" + policy.getPolicyName() + "], " + sql); + throw new AnalysisException("Invalid row policy [" + policy.getPolicyIdent() + "], " + sql); } switch (policy.getFilterType()) { case PERMISSIVE: diff --git a/fe/fe-core/src/main/java/org/apache/doris/policy/RowPolicy.java b/fe/fe-core/src/main/java/org/apache/doris/policy/RowPolicy.java index d69468d9d4333a..4d0999db78abc0 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/policy/RowPolicy.java +++ b/fe/fe-core/src/main/java/org/apache/doris/policy/RowPolicy.java @@ -29,6 +29,7 @@ import org.apache.doris.catalog.Table; import org.apache.doris.common.AnalysisException; import org.apache.doris.common.util.SqlParserUtils; +import org.apache.doris.mysql.privilege.RowFilterPolicy; import org.apache.doris.qe.ShowResultSetMetaData; import com.google.common.collect.Lists; @@ -47,7 +48,7 @@ * Save policy for filtering data. **/ @Data -public class RowPolicy extends Policy { +public class RowPolicy extends Policy implements RowFilterPolicy { public static final ShowResultSetMetaData ROW_META_DATA = ShowResultSetMetaData.builder() @@ -186,4 +187,15 @@ public boolean matchPolicy(DropPolicyLog checkedDropPolicyLogCondition) { public boolean isInvalid() { return (wherePredicate == null); } + + @Override + public String getFilterExpr() { + return getOriginStmt(); + } + + @Override + public String getPolicyIdent() { + return getPolicyName(); + } + } diff --git a/fe/fe-core/src/test/java/org/apache/doris/datasource/ColumnPrivTest.java b/fe/fe-core/src/test/java/org/apache/doris/datasource/ColumnPrivTest.java index 690649fae7d1c4..967c79f88f5fca 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/datasource/ColumnPrivTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/datasource/ColumnPrivTest.java @@ -33,13 +33,16 @@ import org.apache.doris.catalog.Env; import org.apache.doris.catalog.PrimitiveType; import org.apache.doris.cluster.ClusterNamespace; +import org.apache.doris.common.AnalysisException; import org.apache.doris.common.AuthorizationException; import org.apache.doris.common.FeConstants; import org.apache.doris.datasource.test.TestExternalCatalog.TestCatalogProvider; import org.apache.doris.mysql.privilege.AccessControllerFactory; import org.apache.doris.mysql.privilege.Auth; import org.apache.doris.mysql.privilege.CatalogAccessController; +import org.apache.doris.mysql.privilege.DataMaskPolicy; import org.apache.doris.mysql.privilege.PrivPredicate; +import org.apache.doris.mysql.privilege.RowFilterPolicy; import org.apache.doris.qe.ConnectContext; import org.apache.doris.qe.ShowExecutor; import org.apache.doris.qe.ShowResultSet; @@ -54,6 +57,7 @@ import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; // when `select` suppport `col auth`,will open ColumnPrivTest @@ -320,6 +324,18 @@ public void checkColsPriv(UserIdentity currentUser, String ctl, String db, Strin public boolean checkCloudPriv(UserIdentity currentUser, String resourceName, PrivPredicate wanted, ResourceTypeEnum type) { return false; } + + @Override + public Optional evalDataMaskPolicy(UserIdentity currentUser, String ctl, String db, + String tbl, String col) { + return Optional.empty(); + } + + @Override + public List evalRowFilterPolicies(UserIdentity currentUser, String ctl, + String db, String tbl) throws AnalysisException { + return null; + } } } diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/privileges/TestCheckPrivileges.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/privileges/TestCheckPrivileges.java index f9f6eb9100238e..cfba61b0cd763b 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/nereids/privileges/TestCheckPrivileges.java +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/privileges/TestCheckPrivileges.java @@ -29,7 +29,9 @@ import org.apache.doris.mysql.privilege.AccessControllerFactory; import org.apache.doris.mysql.privilege.AccessControllerManager; import org.apache.doris.mysql.privilege.CatalogAccessController; +import org.apache.doris.mysql.privilege.DataMaskPolicy; import org.apache.doris.mysql.privilege.PrivPredicate; +import org.apache.doris.mysql.privilege.RowFilterPolicy; import org.apache.doris.nereids.exceptions.AnalysisException; import org.apache.doris.nereids.util.PlanChecker; import org.apache.doris.utframe.TestWithFeService; @@ -46,6 +48,7 @@ import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; public class TestCheckPrivileges extends TestWithFeService { @@ -305,6 +308,18 @@ public boolean checkCloudPriv(UserIdentity currentUser, String resourceName, Pri ResourceTypeEnum type) { return true; } + + @Override + public Optional evalDataMaskPolicy(UserIdentity currentUser, String ctl, String db, String tbl, + String col) { + return Optional.empty(); + } + + @Override + public List evalRowFilterPolicies(UserIdentity currentUser, String ctl, String db, + String tbl) throws org.apache.doris.common.AnalysisException { + return Lists.newArrayList(); + } } private static class MakePrivileges { From 04d9e659938a2116c7a4245f13c0e77ac146693e Mon Sep 17 00:00:00 2001 From: zhangdong <493738387@qq.com> Date: Thu, 14 Mar 2024 20:42:05 +0800 Subject: [PATCH 3/3] 1 --- .../ranger/RangerAccessController.java | 78 +++++++++++++++ .../doris/RangerDorisAccessController.java | 83 ++++------------ .../hive/RangerHiveAccessController.java | 94 ++++++------------- .../privilege/AccessControllerManager.java | 12 ++- .../mysql/privilege/RangerDataMaskPolicy.java | 52 ++++------ .../privilege/RangerRowFilterPolicy.java | 46 ++++----- .../mysql/privilege/RowFilterPolicy.java | 4 +- .../plans/logical/LogicalCheckPolicy.java | 17 ++-- .../org/apache/doris/policy/RowPolicy.java | 15 ++- 9 files changed, 194 insertions(+), 207 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 30b42e19976477..5f49f4d5735914 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 @@ -17,15 +17,27 @@ package org.apache.doris.catalog.authorizer.ranger; +import org.apache.doris.analysis.UserIdentity; import org.apache.doris.common.AuthorizationException; import org.apache.doris.mysql.privilege.CatalogAccessController; +import org.apache.doris.mysql.privilege.DataMaskPolicy; +import org.apache.doris.mysql.privilege.RangerDataMaskPolicy; +import org.apache.doris.mysql.privilege.RangerRowFilterPolicy; +import org.apache.doris.mysql.privilege.RowFilterPolicy; +import com.google.common.collect.Lists; +import org.apache.commons.lang3.StringUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.ranger.plugin.policyengine.RangerAccessRequestImpl; +import org.apache.ranger.plugin.policyengine.RangerAccessResourceImpl; import org.apache.ranger.plugin.policyengine.RangerAccessResult; +import org.apache.ranger.plugin.policyengine.RangerAccessResultProcessor; +import org.apache.ranger.plugin.service.RangerBasePlugin; import java.util.Collection; +import java.util.List; +import java.util.Optional; public abstract class RangerAccessController implements CatalogAccessController { private static final Logger LOG = LogManager.getLogger(RangerAccessController.class); @@ -74,4 +86,70 @@ public static void checkRequestResults(Collection results, S } } } + + @Override + public List evalRowFilterPolicies(UserIdentity currentUser, String ctl, String db, + String tbl) { + RangerAccessResourceImpl resource = createResource(ctl, db, tbl); + RangerAccessRequestImpl request = createRequest(currentUser); + request.setResource(resource); + + if (LOG.isDebugEnabled()) { + LOG.debug("ranger request: {}", request); + } + List res = Lists.newArrayList(); + RangerAccessResult policy = getPlugin().evalRowFilterPolicies(request, getAccessResultProcessor()); + if (LOG.isDebugEnabled()) { + LOG.debug("ranger response: {}", policy); + } + if (policy == null) { + return res; + } + String filterExpr = policy.getFilterExpr(); + if (StringUtils.isEmpty(filterExpr)) { + return res; + } + res.add(new RangerRowFilterPolicy(currentUser, ctl, db, tbl, policy.getPolicyId(), policy.getPolicyVersion(), + filterExpr)); + return res; + } + + @Override + public Optional evalDataMaskPolicy(UserIdentity currentUser, String ctl, String db, String tbl, + String col) { + RangerAccessResourceImpl resource = createResource(ctl, db, tbl, col); + RangerAccessRequestImpl request = createRequest(currentUser); + request.setResource(resource); + + if (LOG.isDebugEnabled()) { + LOG.debug("ranger request: {}", request); + } + RangerAccessResult policy = getPlugin().evalDataMaskPolicies(request, getAccessResultProcessor()); + if (LOG.isDebugEnabled()) { + LOG.debug("ranger response: {}", policy); + } + if (policy == null) { + return Optional.empty(); + } + String maskType = policy.getMaskType(); + if (StringUtils.isEmpty(maskType)) { + return Optional.empty(); + } + 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))); + } + + protected abstract RangerAccessRequestImpl createRequest(UserIdentity currentUser); + + protected abstract RangerAccessResourceImpl createResource(String ctl, String db, String tbl); + + protected abstract RangerAccessResourceImpl createResource(String ctl, String db, String tbl, String col); + + protected abstract RangerBasePlugin getPlugin(); + + protected abstract RangerAccessResultProcessor getAccessResultProcessor(); } 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 84477d398c7611..f8c38ba78e9da5 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 @@ -22,27 +22,21 @@ import org.apache.doris.catalog.Env; import org.apache.doris.catalog.authorizer.ranger.RangerAccessController; import org.apache.doris.cluster.ClusterNamespace; -import org.apache.doris.common.AnalysisException; import org.apache.doris.common.AuthorizationException; -import org.apache.doris.mysql.privilege.DataMaskPolicy; import org.apache.doris.mysql.privilege.PrivPredicate; -import org.apache.doris.mysql.privilege.RangerDataMaskPolicy; -import org.apache.doris.mysql.privilege.RangerRowFilterPolicy; -import org.apache.doris.mysql.privilege.RowFilterPolicy; -import com.google.common.collect.Lists; -import org.apache.commons.lang3.StringUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.ranger.plugin.policyengine.RangerAccessRequest; import org.apache.ranger.plugin.policyengine.RangerAccessRequestImpl; import org.apache.ranger.plugin.policyengine.RangerAccessResult; +import org.apache.ranger.plugin.policyengine.RangerAccessResultProcessor; +import org.apache.ranger.plugin.service.RangerBasePlugin; import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.List; -import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; @@ -61,23 +55,14 @@ public RangerDorisAccessController(String serviceName) { } private RangerAccessRequestImpl createRequest(UserIdentity currentUser, DorisAccessType accessType) { - RangerAccessRequestImpl request = new RangerAccessRequestImpl(); - request.setUser(ClusterNamespace.getNameFromFullName(currentUser.getQualifiedUser())); - Set roles = Env.getCurrentEnv().getAuth().getRolesByUser(currentUser, false); - request.setUserRoles(roles.stream().map(role -> ClusterNamespace.getNameFromFullName(role)).collect( - Collectors.toSet())); - + RangerAccessRequestImpl request = createRequest(currentUser); request.setAction(accessType.name()); request.setAccessType(accessType.name()); - request.setClientIPAddress(currentUser.getHost()); - request.setClusterType(CLIENT_TYPE_DORIS); - request.setClientType(CLIENT_TYPE_DORIS); - request.setAccessTime(new Date()); - return request; } - private RangerAccessRequestImpl createRequest(UserIdentity currentUser) { + @Override + protected RangerAccessRequestImpl createRequest(UserIdentity currentUser) { RangerAccessRequestImpl request = new RangerAccessRequestImpl(); request.setUser(ClusterNamespace.getNameFromFullName(currentUser.getQualifiedUser())); Set roles = Env.getCurrentEnv().getAuth().getRolesByUser(currentUser, false); @@ -177,55 +162,25 @@ public boolean checkWorkloadGroupPriv(UserIdentity currentUser, String workloadG } @Override - public Optional evalDataMaskPolicy(UserIdentity currentUser, String ctl, String db, String tbl, - String col) { - RangerDorisResource resource = new RangerDorisResource(DorisObjectType.COLUMN, - ctl, ClusterNamespace.getNameFromFullName(db), tbl, col); - RangerAccessRequestImpl request = createRequest(currentUser); - request.setResource(resource); + protected RangerDorisResource createResource(String ctl, String db, String tbl) { + return new RangerDorisResource(DorisObjectType.TABLE, + ctl, ClusterNamespace.getNameFromFullName(db), tbl); + } - if (LOG.isDebugEnabled()) { - LOG.debug("ranger request: {}", request); - } - RangerAccessResult policy = dorisPlugin.evalDataMaskPolicies(request, null); - if (policy == null) { - return Optional.empty(); - } - String maskType = policy.getMaskType(); - if (StringUtils.isEmpty(maskType)) { - return Optional.empty(); - } - 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))); + @Override + protected RangerDorisResource createResource(String ctl, String db, String tbl, String col) { + return new RangerDorisResource(DorisObjectType.COLUMN, + ctl, ClusterNamespace.getNameFromFullName(db), tbl, col); } @Override - public List evalRowFilterPolicies(UserIdentity currentUser, String ctl, String db, - String tbl) throws AnalysisException { - RangerDorisResource resource = new RangerDorisResource(DorisObjectType.TABLE, - ctl, ClusterNamespace.getNameFromFullName(db), tbl); - RangerAccessRequestImpl request = createRequest(currentUser); - request.setResource(resource); + protected RangerBasePlugin getPlugin() { + return dorisPlugin; + } - if (LOG.isDebugEnabled()) { - LOG.debug("ranger request: {}", request); - } - List res = Lists.newArrayList(); - RangerAccessResult policy = dorisPlugin.evalRowFilterPolicies(request, null); - if (policy == null) { - return res; - } - String filterExpr = policy.getFilterExpr(); - if (StringUtils.isEmpty(filterExpr)) { - return res; - } - res.add(new RangerRowFilterPolicy(currentUser, ctl, db, tbl, policy.getPolicyId(), policy.getPolicyVersion(), - filterExpr)); - return res; + @Override + protected RangerAccessResultProcessor getAccessResultProcessor() { + return null; } // For test only 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 66d22e26b31a81..8c7f672bdcbf1b 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 @@ -22,25 +22,21 @@ import org.apache.doris.catalog.Env; import org.apache.doris.catalog.authorizer.ranger.RangerAccessController; import org.apache.doris.cluster.ClusterNamespace; -import org.apache.doris.common.AnalysisException; import org.apache.doris.common.AuthorizationException; import org.apache.doris.common.ThreadPoolManager; import org.apache.doris.datasource.InternalCatalog; import org.apache.doris.mysql.privilege.DataMaskPolicy; import org.apache.doris.mysql.privilege.PrivPredicate; -import org.apache.doris.mysql.privilege.RangerDataMaskPolicy; -import org.apache.doris.mysql.privilege.RangerRowFilterPolicy; -import org.apache.doris.mysql.privilege.RowFilterPolicy; -import com.google.common.collect.Lists; import com.google.common.collect.Maps; -import org.apache.commons.lang3.StringUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.ranger.plugin.policyengine.RangerAccessRequest; import org.apache.ranger.plugin.policyengine.RangerAccessRequestImpl; import org.apache.ranger.plugin.policyengine.RangerAccessResult; +import org.apache.ranger.plugin.policyengine.RangerAccessResultProcessor; import org.apache.ranger.plugin.policyengine.RangerPolicyEngine; +import org.apache.ranger.plugin.service.RangerBasePlugin; import java.util.ArrayList; import java.util.Collection; @@ -64,32 +60,22 @@ public RangerHiveAccessController(Map properties) { String serviceName = properties.get("ranger.service.name"); hivePlugin = new RangerHivePlugin(serviceName); auditHandler = new RangerHiveAuditHandler(hivePlugin.getConfig()); - //start a timed log flusher + // start a timed log flusher logFlushTimer.scheduleAtFixedRate(new RangerHiveAuditLogFlusher(auditHandler), 10, 20L, TimeUnit.SECONDS); } private RangerAccessRequestImpl createRequest(UserIdentity currentUser, HiveAccessType accessType) { - RangerAccessRequestImpl request = new RangerAccessRequestImpl(); - String user = currentUser.getQualifiedUser(); - request.setUser(ClusterNamespace.getNameFromFullName(user)); - Set roles = Env.getCurrentEnv().getAuth().getRolesByUser(currentUser, false); - request.setUserRoles(roles.stream().map(role -> ClusterNamespace.getNameFromFullName(role)).collect( - Collectors.toSet())); - request.setAction(accessType.name()); + RangerAccessRequestImpl request = createRequest(currentUser); if (accessType == HiveAccessType.USE) { request.setAccessType(RangerPolicyEngine.ANY_ACCESS); } else { request.setAccessType(accessType.name().toLowerCase()); } - request.setClientIPAddress(currentUser.getHost()); - request.setClusterType(CLIENT_TYPE_DORIS); - request.setClientType(CLIENT_TYPE_DORIS); - request.setAccessTime(new Date()); - return request; } - private RangerAccessRequestImpl createRequest(UserIdentity currentUser) { + @Override + protected RangerAccessRequestImpl createRequest(UserIdentity currentUser) { RangerAccessRequestImpl request = new RangerAccessRequestImpl(); String user = currentUser.getQualifiedUser(); request.setUser(ClusterNamespace.getNameFromFullName(user)); @@ -188,70 +174,46 @@ public void checkColsPriv(UserIdentity currentUser, String ctl, String db, Strin @Override public boolean checkCloudPriv(UserIdentity currentUser, String resourceName, - PrivPredicate wanted, ResourceTypeEnum type) { + PrivPredicate wanted, ResourceTypeEnum type) { return false; } @Override public Optional evalDataMaskPolicy(UserIdentity currentUser, String ctl, String db, String tbl, String col) { - RangerHiveResource resource = new RangerHiveResource(HiveObjectType.COLUMN, - ClusterNamespace.getNameFromFullName(db), tbl, col); - RangerAccessRequestImpl request = createRequest(currentUser); - request.setResource(resource); + return Optional.empty(); + } - if (LOG.isDebugEnabled()) { - LOG.debug("ranger request: {}", request); - } - RangerAccessResult policy = hivePlugin.evalDataMaskPolicies(request, auditHandler); - if (policy == null) { - return Optional.empty(); - } - String maskType = policy.getMaskType(); - if (StringUtils.isEmpty(maskType)) { - return Optional.empty(); - } - 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))); + @Override + public boolean checkResourcePriv(UserIdentity currentUser, String resourceName, PrivPredicate wanted) { + return false; } @Override - public List evalRowFilterPolicies(UserIdentity currentUser, String ctl, String db, - String tbl) throws AnalysisException { - RangerHiveResource resource = new RangerHiveResource(HiveObjectType.TABLE, + public boolean checkWorkloadGroupPriv(UserIdentity currentUser, String workloadGroupName, PrivPredicate wanted) { + return false; + } + + @Override + protected RangerHiveResource createResource(String ctl, String db, String tbl) { + return new RangerHiveResource(HiveObjectType.TABLE, ClusterNamespace.getNameFromFullName(db), tbl); - RangerAccessRequestImpl request = createRequest(currentUser); - request.setResource(resource); + } - if (LOG.isDebugEnabled()) { - LOG.debug("ranger request: {}", request); - } - List res = Lists.newArrayList(); - RangerAccessResult policy = hivePlugin.evalRowFilterPolicies(request, auditHandler); - if (policy == null) { - return res; - } - String filterExpr = policy.getFilterExpr(); - if (StringUtils.isEmpty(filterExpr)) { - return res; - } - res.add(new RangerRowFilterPolicy(currentUser, ctl, db, tbl, policy.getPolicyId(), policy.getPolicyVersion(), - filterExpr)); - return res; + @Override + protected RangerHiveResource createResource(String ctl, String db, String tbl, String col) { + return new RangerHiveResource(HiveObjectType.COLUMN, + ClusterNamespace.getNameFromFullName(db), tbl, col); } @Override - public boolean checkResourcePriv(UserIdentity currentUser, String resourceName, PrivPredicate wanted) { - return false; + protected RangerBasePlugin getPlugin() { + return hivePlugin; } @Override - public boolean checkWorkloadGroupPriv(UserIdentity currentUser, String workloadGroupName, PrivPredicate wanted) { - return false; + protected RangerAccessResultProcessor getAccessResultProcessor() { + return auditHandler; } // For test only diff --git a/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/AccessControllerManager.java b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/AccessControllerManager.java index 6046aa07e2e29f..cc0cf619042f75 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/AccessControllerManager.java +++ b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/AccessControllerManager.java @@ -39,6 +39,7 @@ import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.Set; @@ -275,11 +276,20 @@ public Map> evalDataMaskPolicies(UserIdentity c public Optional evalDataMaskPolicy(UserIdentity currentUser, String ctl, String db, String tbl, String col) { - return getAccessControllerOrDefault(ctl).evalDataMaskPolicy(currentUser, ctl, db, tbl, col); + Objects.requireNonNull(currentUser, "require currentUser object"); + Objects.requireNonNull(ctl, "require ctl object"); + Objects.requireNonNull(db, "require db object"); + Objects.requireNonNull(tbl, "require tbl object"); + Objects.requireNonNull(col, "require col object"); + return getAccessControllerOrDefault(ctl).evalDataMaskPolicy(currentUser, ctl, db, tbl, col.toLowerCase()); } public List evalRowFilterPolicies(UserIdentity currentUser, String ctl, String db, String tbl) throws AnalysisException { + Objects.requireNonNull(currentUser, "require currentUser object"); + Objects.requireNonNull(ctl, "require ctl object"); + Objects.requireNonNull(db, "require db object"); + Objects.requireNonNull(tbl, "require tbl object"); return getAccessControllerOrDefault(ctl).evalRowFilterPolicies(currentUser, ctl, db, tbl); } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/RangerDataMaskPolicy.java b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/RangerDataMaskPolicy.java index cfc9184e13d7a0..91010f80cb378f 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/RangerDataMaskPolicy.java +++ b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/RangerDataMaskPolicy.java @@ -48,76 +48,56 @@ public UserIdentity getUserIdentity() { return userIdentity; } - public void setUserIdentity(UserIdentity userIdentity) { - this.userIdentity = userIdentity; - } - public String getCtl() { return ctl; } - public void setCtl(String ctl) { - this.ctl = ctl; - } - public String getDb() { return db; } - public void setDb(String db) { - this.db = db; - } - public String getTbl() { return tbl; } - public void setTbl(String tbl) { - this.tbl = tbl; - } - public String getCol() { return col; } - public void setCol(String col) { - this.col = col; - } - public long getPolicyId() { return policyId; } - public void setPolicyId(long policyId) { - this.policyId = policyId; - } - public long getPolicyVersion() { return policyVersion; } - public void setPolicyVersion(long policyVersion) { - this.policyVersion = policyVersion; - } - public String getMaskType() { return maskType; } - public void setMaskType(String maskType) { - this.maskType = maskType; - } - + @Override public String getMaskTypeDef() { return maskTypeDef; } - public void setMaskTypeDef(String maskTypeDef) { - this.maskTypeDef = maskTypeDef; - } - @Override public String getPolicyIdent() { return getPolicyId() + ":" + getPolicyVersion(); } + + @Override + public String toString() { + return "RangerDataMaskPolicy{" + + "userIdentity=" + userIdentity + + ", ctl='" + ctl + '\'' + + ", db='" + db + '\'' + + ", tbl='" + tbl + '\'' + + ", col='" + col + '\'' + + ", policyId=" + policyId + + ", policyVersion=" + policyVersion + + ", maskType='" + maskType + '\'' + + ", maskTypeDef='" + maskTypeDef + '\'' + + '}'; + } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/RangerRowFilterPolicy.java b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/RangerRowFilterPolicy.java index a64330d1dcced3..661efcf8a4a852 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/RangerRowFilterPolicy.java +++ b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/RangerRowFilterPolicy.java @@ -18,6 +18,8 @@ package org.apache.doris.mysql.privilege; import org.apache.doris.analysis.UserIdentity; +import org.apache.doris.nereids.parser.NereidsParser; +import org.apache.doris.nereids.trees.expressions.Expression; public class RangerRowFilterPolicy implements RowFilterPolicy { private UserIdentity userIdentity; @@ -43,61 +45,51 @@ public UserIdentity getUserIdentity() { return userIdentity; } - public void setUserIdentity(UserIdentity userIdentity) { - this.userIdentity = userIdentity; - } - public String getCtl() { return ctl; } - public void setCtl(String ctl) { - this.ctl = ctl; - } - public String getDb() { return db; } - public void setDb(String db) { - this.db = db; - } - public String getTbl() { return tbl; } - public void setTbl(String tbl) { - this.tbl = tbl; - } - public long getPolicyId() { return policyId; } - public void setPolicyId(long policyId) { - this.policyId = policyId; - } - public long getPolicyVersion() { return policyVersion; } - public void setPolicyVersion(long policyVersion) { - this.policyVersion = policyVersion; - } - - @Override public String getFilterExpr() { return filterExpr; } - public void setFilterExpr(String filterExpr) { - this.filterExpr = filterExpr; + @Override + public Expression getFilterExpression() { + NereidsParser nereidsParser = new NereidsParser(); + return nereidsParser.parseExpression(filterExpr); } @Override public String getPolicyIdent() { return getPolicyId() + ":" + getPolicyVersion(); } + + @Override + public String toString() { + return "RangerRowFilterPolicy{" + + "userIdentity=" + userIdentity + + ", ctl='" + ctl + '\'' + + ", db='" + db + '\'' + + ", tbl='" + tbl + '\'' + + ", policyId=" + policyId + + ", policyVersion=" + policyVersion + + ", filterExpr='" + filterExpr + '\'' + + '}'; + } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/RowFilterPolicy.java b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/RowFilterPolicy.java index 7e87dae5e4fcb5..678a1927e243dc 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/RowFilterPolicy.java +++ b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/RowFilterPolicy.java @@ -17,6 +17,8 @@ package org.apache.doris.mysql.privilege; +import org.apache.doris.common.AnalysisException; +import org.apache.doris.nereids.trees.expressions.Expression; import org.apache.doris.policy.FilterType; public interface RowFilterPolicy { @@ -24,7 +26,7 @@ default FilterType getFilterType() { return FilterType.RESTRICTIVE; } - String getFilterExpr(); + Expression getFilterExpression() throws AnalysisException; String getPolicyIdent(); } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalCheckPolicy.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalCheckPolicy.java index e0aa028b22ba29..e7ed8bf20ad1a0 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalCheckPolicy.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalCheckPolicy.java @@ -22,7 +22,6 @@ import org.apache.doris.mysql.privilege.RowFilterPolicy; import org.apache.doris.nereids.exceptions.AnalysisException; import org.apache.doris.nereids.memo.GroupExpression; -import org.apache.doris.nereids.parser.NereidsParser; import org.apache.doris.nereids.properties.LogicalProperties; import org.apache.doris.nereids.trees.expressions.And; import org.apache.doris.nereids.trees.expressions.Expression; @@ -31,7 +30,6 @@ import org.apache.doris.nereids.trees.plans.PlanType; import org.apache.doris.nereids.trees.plans.PropagateFuncDeps; import org.apache.doris.nereids.trees.plans.algebra.CatalogRelation; -import org.apache.doris.nereids.trees.plans.commands.CreatePolicyCommand; import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor; import org.apache.doris.nereids.util.ExpressionUtils; import org.apache.doris.nereids.util.Utils; @@ -152,19 +150,18 @@ private Expression mergeRowPolicy(List policies) { List orList = new ArrayList<>(); List andList = new ArrayList<>(); for (RowFilterPolicy policy : policies) { - String sql = policy.getFilterExpr(); - NereidsParser nereidsParser = new NereidsParser(); - CreatePolicyCommand command = (CreatePolicyCommand) nereidsParser.parseSingle(sql); - Optional wherePredicate = command.getWherePredicate(); - if (!wherePredicate.isPresent()) { - throw new AnalysisException("Invalid row policy [" + policy.getPolicyIdent() + "], " + sql); + Expression wherePredicate = null; + try { + wherePredicate = policy.getFilterExpression(); + } catch (org.apache.doris.common.AnalysisException e) { + throw new AnalysisException(e.getMessage(), e); } switch (policy.getFilterType()) { case PERMISSIVE: - orList.add(wherePredicate.get()); + orList.add(wherePredicate); break; case RESTRICTIVE: - andList.add(wherePredicate.get()); + andList.add(wherePredicate); break; default: throw new IllegalStateException("Invalid operator"); diff --git a/fe/fe-core/src/main/java/org/apache/doris/policy/RowPolicy.java b/fe/fe-core/src/main/java/org/apache/doris/policy/RowPolicy.java index 4d0999db78abc0..86dbeca28d25fa 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/policy/RowPolicy.java +++ b/fe/fe-core/src/main/java/org/apache/doris/policy/RowPolicy.java @@ -30,6 +30,9 @@ import org.apache.doris.common.AnalysisException; import org.apache.doris.common.util.SqlParserUtils; import org.apache.doris.mysql.privilege.RowFilterPolicy; +import org.apache.doris.nereids.parser.NereidsParser; +import org.apache.doris.nereids.trees.expressions.Expression; +import org.apache.doris.nereids.trees.plans.commands.CreatePolicyCommand; import org.apache.doris.qe.ShowResultSetMetaData; import com.google.common.collect.Lists; @@ -43,6 +46,7 @@ import java.io.StringReader; import java.util.List; import java.util.Objects; +import java.util.Optional; /** * Save policy for filtering data. @@ -189,8 +193,15 @@ public boolean isInvalid() { } @Override - public String getFilterExpr() { - return getOriginStmt(); + public Expression getFilterExpression() throws AnalysisException { + NereidsParser nereidsParser = new NereidsParser(); + String sql = getOriginStmt(); + CreatePolicyCommand command = (CreatePolicyCommand) nereidsParser.parseSingle(sql); + Optional wherePredicate = command.getWherePredicate(); + if (!wherePredicate.isPresent()) { + throw new AnalysisException("Invalid row policy [" + getPolicyIdent() + "], " + sql); + } + return wherePredicate.get(); } @Override