This is an automated email from the ASF dual-hosted git repository.

morningman pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/master by this push:
     new 545d3b1c3e [Enhancement](auth)support ranger col priv (#17915)
545d3b1c3e is described below

commit 545d3b1c3e2ceba2c890421288894be651ca93f4
Author: zhangdong <[email protected]>
AuthorDate: Wed Mar 22 09:00:17 2023 +0800

    [Enhancement](auth)support ranger col priv (#17915)
    
    1.When querying data, it is no longer necessary to verify the permissions 
of the entire table, but rather to verify the
    permissions of the queried columns. Currently, the 'ranger' already 
supports column permissions, and the internal
    catalog provides the implementation of dummy column permissions (the actual 
verified permissions are still table
    permissions)
    
    2.delete roles in userIdentity
    
    3.Change trigger logic of initAccessController
---
 .../java/org/apache/doris/analysis/SelectStmt.java |  9 -----
 .../org/apache/doris/analysis/UserIdentity.java    | 13 --------
 .../authorizer/RangerHiveAccessController.java     | 38 ++++++++-------------
 .../apache/doris/datasource/ExternalCatalog.java   |  3 +-
 .../mysql/privilege/AccessControllerManager.java   | 39 +++++++++++++++++++---
 .../org/apache/doris/mysql/privilege/Auth.java     | 21 ++++++++----
 .../apache/doris/datasource/ColumnPrivTest.java    |  6 +---
 .../account_p0/test_nereids_authentication.groovy  |  4 +--
 8 files changed, 67 insertions(+), 66 deletions(-)

diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/SelectStmt.java 
b/fe/fe-core/src/main/java/org/apache/doris/analysis/SelectStmt.java
index 9d1fe108d9..1de0d1fdf8 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/analysis/SelectStmt.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/SelectStmt.java
@@ -24,7 +24,6 @@ import org.apache.doris.analysis.CompoundPredicate.Operator;
 import org.apache.doris.catalog.AggregateFunction;
 import org.apache.doris.catalog.Column;
 import org.apache.doris.catalog.DatabaseIf;
-import org.apache.doris.catalog.Env;
 import org.apache.doris.catalog.FunctionSet;
 import org.apache.doris.catalog.OlapTable;
 import org.apache.doris.catalog.Table;
@@ -43,7 +42,6 @@ import org.apache.doris.common.TableAliasGenerator;
 import org.apache.doris.common.TreeNode;
 import org.apache.doris.common.UserException;
 import org.apache.doris.common.util.SqlUtils;
-import org.apache.doris.mysql.privilege.PrivPredicate;
 import org.apache.doris.qe.ConnectContext;
 import org.apache.doris.rewrite.ExprRewriter;
 import org.apache.doris.rewrite.mvrewrite.MVSelectFailedException;
@@ -382,13 +380,6 @@ public class SelectStmt extends QueryStmt {
                     View view = (View) table;
                     view.getQueryStmt().getTables(analyzer, expandView, 
tableMap, parentViewNameSet);
                 } else {
-                    // check auth
-                    if (!Env.getCurrentEnv().getAccessManager()
-                            .checkTblPriv(ConnectContext.get(), 
tblRef.getName(), PrivPredicate.SELECT)) {
-                        
ErrorReport.reportAnalysisException(ErrorCode.ERR_TABLEACCESS_DENIED_ERROR, 
"SELECT",
-                                ConnectContext.get().getQualifiedUser(), 
ConnectContext.get().getRemoteIP(),
-                                dbName + "." + tableName);
-                    }
                     tableMap.put(table.getId(), table);
                 }
             }
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/analysis/UserIdentity.java 
b/fe/fe-core/src/main/java/org/apache/doris/analysis/UserIdentity.java
index 0dae2ff17a..dbaa1427d8 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/analysis/UserIdentity.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/UserIdentity.java
@@ -41,7 +41,6 @@ import org.apache.logging.log4j.Logger;
 import java.io.DataInput;
 import java.io.DataOutput;
 import java.io.IOException;
-import java.util.Set;
 
 // https://dev.mysql.com/doc/refman/8.0/en/account-names.html
 // user name must be literally matched.
@@ -58,10 +57,6 @@ public class UserIdentity implements Writable, 
GsonPostProcessable {
     private String host;
     @SerializedName(value = "isDomain")
     private boolean isDomain;
-    // The roles which this user belongs to.
-    // Used for authorization in Access Controller
-    // This field is only set when getting current user from auth and not need 
to persist
-    private Set<String> roles;
 
     private boolean isAnalyzed = false;
 
@@ -129,14 +124,6 @@ public class UserIdentity implements Writable, 
GsonPostProcessable {
         this.isAnalyzed = true;
     }
 
-    public void setRoles(Set<String> roles) {
-        this.roles = roles;
-    }
-
-    public Set<String> getRoles() {
-        return roles;
-    }
-
     public void analyze(String clusterName) throws AnalysisException {
         if (isAnalyzed) {
             return;
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/catalog/authorizer/RangerHiveAccessController.java
 
b/fe/fe-core/src/main/java/org/apache/doris/catalog/authorizer/RangerHiveAccessController.java
index 127f925f06..cacf8043db 100644
--- 
a/fe/fe-core/src/main/java/org/apache/doris/catalog/authorizer/RangerHiveAccessController.java
+++ 
b/fe/fe-core/src/main/java/org/apache/doris/catalog/authorizer/RangerHiveAccessController.java
@@ -18,12 +18,12 @@
 package org.apache.doris.catalog.authorizer;
 
 import org.apache.doris.analysis.UserIdentity;
+import org.apache.doris.catalog.Env;
 import org.apache.doris.cluster.ClusterNamespace;
 import org.apache.doris.common.AuthorizationException;
 import org.apache.doris.common.ThreadPoolManager;
 import org.apache.doris.mysql.privilege.CatalogAccessController;
 import org.apache.doris.mysql.privilege.PrivPredicate;
-import org.apache.doris.mysql.privilege.Role;
 
 import 
org.apache.hadoop.hive.ql.security.authorization.plugin.HiveAccessControlException;
 import org.apache.logging.log4j.LogManager;
@@ -36,12 +36,12 @@ import 
org.apache.ranger.plugin.policyengine.RangerPolicyEngine;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Date;
-import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ScheduledThreadPoolExecutor;
 import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
 
 public class RangerHiveAccessController implements CatalogAccessController {
     public static final String CLIENT_TYPE_DORIS = "doris";
@@ -62,20 +62,10 @@ public class RangerHiveAccessController implements 
CatalogAccessController {
     private RangerAccessRequestImpl createRequest(UserIdentity currentUser, 
HiveAccessType accessType) {
         RangerAccessRequestImpl request = new RangerAccessRequestImpl();
         String user = currentUser.getQualifiedUser();
-        if (user.indexOf(":") != -1) {
-            // user is as of form: default_cluster:user1, only use `user1`
-            request.setUser(user.split(":")[1]);
-        } else {
-            request.setUser(user);
-        }
-        Set<String> roles = new HashSet<>();
-        for (String role : currentUser.getRoles()) {
-            // default role is as of form: default_role_rbac_xxx@%, not useful 
for Ranger
-            if (!Role.isDefaultRoleName(role)) {
-                roles.add(role);
-            }
-        }
-        request.setUserRoles(roles);
+        request.setUser(ClusterNamespace.getNameFromFullName(user));
+        Set<String> roles = 
Env.getCurrentEnv().getAuth().getRolesByUser(currentUser, false);
+        request.setUserRoles(roles.stream().map(role -> 
ClusterNamespace.getNameFromFullName(role)).collect(
+                Collectors.toSet()));
         request.setAction(accessType.name());
         if (accessType == HiveAccessType.USE) {
             request.setAccessType(RangerPolicyEngine.ANY_ACCESS);
@@ -91,7 +81,7 @@ public class RangerHiveAccessController implements 
CatalogAccessController {
     }
 
     private void checkPrivileges(UserIdentity currentUser, HiveAccessType 
accessType,
-                                List<RangerHiveResource> hiveResources) throws 
AuthorizationException {
+            List<RangerHiveResource> hiveResources) throws 
AuthorizationException {
         List<RangerAccessRequest> requests = new ArrayList<>();
         for (RangerHiveResource resource : hiveResources) {
             RangerAccessRequestImpl request = createRequest(currentUser, 
accessType);
@@ -106,15 +96,15 @@ public class RangerHiveAccessController implements 
CatalogAccessController {
             if (!result.getIsAllowed()) {
                 LOG.debug(result.getReason());
                 throw new AuthorizationException(String.format(
-                    "Permission denied: user [%s] does not have privilege for 
[%s] command on [%s]",
-                    result.getAccessRequest().getUser(), accessType.name(),
-                    result.getAccessRequest().getResource().getAsString()));
+                        "Permission denied: user [%s] does not have privilege 
for [%s] command on [%s]",
+                        result.getAccessRequest().getUser(), accessType.name(),
+                        
result.getAccessRequest().getResource().getAsString()));
             }
         }
     }
 
     private boolean checkPrivilege(UserIdentity currentUser, HiveAccessType 
accessType,
-                                  RangerHiveResource resource) {
+            RangerHiveResource resource) {
         RangerAccessRequestImpl request = createRequest(currentUser, 
accessType);
         request.setResource(resource);
 
@@ -139,7 +129,7 @@ public class RangerHiveAccessController implements 
CatalogAccessController {
     }
 
     public String getFilterExpr(UserIdentity currentUser, HiveAccessType 
accessType,
-                              RangerHiveResource resource) throws 
HiveAccessControlException {
+            RangerHiveResource resource) throws HiveAccessControlException {
         RangerAccessRequestImpl request = createRequest(currentUser, 
accessType);
         request.setResource(resource);
         RangerAccessResult result = hivePlugin.isAccessAllowed(request, 
auditHandler);
@@ -148,7 +138,7 @@ public class RangerHiveAccessController implements 
CatalogAccessController {
     }
 
     public void getColumnMask(UserIdentity currentUser, HiveAccessType 
accessType,
-                              RangerHiveResource resource) {
+            RangerHiveResource resource) {
         RangerAccessRequestImpl request = createRequest(currentUser, 
accessType);
         request.setResource(resource);
         RangerAccessResult result = hivePlugin.isAccessAllowed(request, 
auditHandler);
@@ -198,7 +188,7 @@ public class RangerHiveAccessController implements 
CatalogAccessController {
 
     @Override
     public void checkColsPriv(UserIdentity currentUser, String ctl, String db, 
String tbl, Set<String> cols,
-                              PrivPredicate wanted) throws 
AuthorizationException {
+            PrivPredicate wanted) throws AuthorizationException {
         List<RangerHiveResource> resources = new ArrayList<>();
         for (String col : cols) {
             RangerHiveResource resource = new 
RangerHiveResource(HiveObjectType.COLUMN,
diff --git 
a/fe/fe-core/src/main/java/org/apache/doris/datasource/ExternalCatalog.java 
b/fe/fe-core/src/main/java/org/apache/doris/datasource/ExternalCatalog.java
index 8d0990e206..5bda6d6e2c 100644
--- a/fe/fe-core/src/main/java/org/apache/doris/datasource/ExternalCatalog.java
+++ b/fe/fe-core/src/main/java/org/apache/doris/datasource/ExternalCatalog.java
@@ -144,7 +144,6 @@ public abstract class ExternalCatalog implements 
CatalogIf<ExternalDatabase>, Wr
     protected final void initLocalObjects() {
         if (!objectCreated) {
             initLocalObjectsImpl();
-            initAccessController();
             objectCreated = true;
         }
     }
@@ -165,7 +164,7 @@ public abstract class ExternalCatalog implements 
CatalogIf<ExternalDatabase>, Wr
      * "access_controller.properties.prop2" = "yyy",
      * )
      */
-    private void initAccessController() {
+    public void initAccessController() {
         Map<String, String> properties = getCatalogProperty().getProperties();
         // 1. get access controller class name
         String className = 
properties.getOrDefault(CatalogMgr.ACCESS_CONTROLLER_CLASS_PROP, "");
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 eb81d1d692..2096cb39e2 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
@@ -20,11 +20,16 @@ package org.apache.doris.mysql.privilege;
 import org.apache.doris.analysis.TableName;
 import org.apache.doris.analysis.UserIdentity;
 import org.apache.doris.catalog.AuthorizationInfo;
+import org.apache.doris.catalog.Env;
+import org.apache.doris.cluster.ClusterNamespace;
 import org.apache.doris.common.AuthorizationException;
 import org.apache.doris.common.UserException;
+import org.apache.doris.datasource.CatalogIf;
+import org.apache.doris.datasource.ExternalCatalog;
 import org.apache.doris.datasource.InternalCatalog;
 import org.apache.doris.mysql.privilege.Auth.PrivLevel;
 import org.apache.doris.qe.ConnectContext;
+import org.apache.doris.system.SystemInfoService;
 
 import com.google.common.base.Preconditions;
 import com.google.common.collect.HashMultimap;
@@ -56,9 +61,30 @@ public class AccessControllerManager {
     }
 
     private CatalogAccessController getAccessControllerOrDefault(String ctl) {
-        return ctlToCtlAccessController.getOrDefault(ctl, 
internalAccessController);
+        CatalogAccessController catalogAccessController = 
ctlToCtlAccessController.get(ctl);
+        if (catalogAccessController != null) {
+            return catalogAccessController;
+        }
+        CatalogIf catalog = 
Env.getCurrentEnv().getCatalogMgr().getCatalog(ctl);
+        if (catalog != null && catalog instanceof ExternalCatalog) {
+            lazyLoadCtlAccessController((ExternalCatalog) catalog);
+            return ctlToCtlAccessController.get(ctl);
+        }
+
+        return internalAccessController;
+    }
+
+    private synchronized void lazyLoadCtlAccessController(ExternalCatalog 
catalog) {
+        if (ctlToCtlAccessController.containsKey(catalog.getName())) {
+            return;
+        }
+        catalog.initAccessController();
+        if (!ctlToCtlAccessController.containsKey(catalog.getName())) {
+            ctlToCtlAccessController.put(catalog.getName(), 
internalAccessController);
+        }
     }
 
+
     public boolean checkIfAccessControllerExist(String ctl) {
         return ctlToCtlAccessController.containsKey(ctl);
     }
@@ -151,22 +177,25 @@ public class AccessControllerManager {
     }
 
     // ==== Column ====
-    public void checkColumnsPriv(UserIdentity currentUser, String ctl, 
HashMultimap<TableName, String> tableToColsMap,
+    public void checkColumnsPriv(UserIdentity currentUser, String
+            ctl, HashMultimap<TableName, String> tableToColsMap,
             PrivPredicate wanted) throws UserException {
         boolean hasGlobal = sysAccessController.checkGlobalPriv(currentUser, 
wanted);
         CatalogAccessController accessController = 
getAccessControllerOrDefault(ctl);
         for (TableName tableName : tableToColsMap.keySet()) {
-            accessController.checkColsPriv(hasGlobal, currentUser, ctl, 
tableName.getDb(),
+            accessController.checkColsPriv(hasGlobal, currentUser, ctl, 
ClusterNamespace
+                            .getFullName(SystemInfoService.DEFAULT_CLUSTER, 
tableName.getDb()),
                     tableName.getTbl(), tableToColsMap.get(tableName), wanted);
         }
     }
 
-    public boolean checkColumnsPriv(UserIdentity currentUser, String db, 
String tbl, Set<String> cols,
+    public boolean checkColumnsPriv(UserIdentity currentUser, String 
qualifiedDb, String tbl, Set<String> cols,
             PrivPredicate wanted) {
         boolean hasGlobal = sysAccessController.checkGlobalPriv(currentUser, 
wanted);
         CatalogAccessController accessController = 
getAccessControllerOrDefault(Auth.DEFAULT_CATALOG);
         try {
-            accessController.checkColsPriv(hasGlobal, currentUser, 
Auth.DEFAULT_CATALOG, db, tbl, cols, wanted);
+            accessController
+                    .checkColsPriv(hasGlobal, currentUser, 
Auth.DEFAULT_CATALOG, qualifiedDb, tbl, cols, wanted);
             return true;
         } catch (AuthorizationException e) {
             return false;
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 22ed226254..1adb0df808 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
@@ -183,8 +183,6 @@ public class Auth implements Writable {
         readLock();
         try {
             userManager.checkPassword(remoteUser, remoteHost, remotePasswd, 
randomString, currentUser);
-            Set<String> roles = 
userRoleManager.getRolesByUser(currentUser.get(0));
-            currentUser.get(0).setRoles(roles);
         } finally {
             readUnlock();
         }
@@ -201,6 +199,15 @@ public class Auth implements Writable {
         }
     }
 
+    public Set<String> getRolesByUser(UserIdentity user, boolean 
showUserDefaultRole) {
+        readLock();
+        try {
+            return userRoleManager.getRolesByUser(user, showUserDefaultRole);
+        } finally {
+            readUnlock();
+        }
+    }
+
     public void checkPlainPassword(String remoteUser, String remoteHost, 
String remotePasswd,
             List<UserIdentity> currentUser) throws AuthenticationException {
         // Check the LDAP password when the user exists in the LDAP service.
@@ -217,10 +224,6 @@ public class Auth implements Writable {
                 readUnlock();
             }
         }
-        if (currentUser != null) {
-            Set<String> roles = 
userRoleManager.getRolesByUser(currentUser.get(0));
-            currentUser.get(0).setRoles(roles);
-        }
     }
 
     // ==== Global ====
@@ -317,6 +320,12 @@ public class Auth implements Writable {
     public void checkColsPriv(UserIdentity currentUser, String ctl, String db, 
String tbl, Set<String> cols,
             PrivPredicate wanted) throws AuthorizationException {
         // TODO: Support column priv
+        // we check if have tbl priv,until internal support col auth.
+        if (!checkTblPriv(currentUser, ctl, db, tbl, wanted)) {
+            throw new AuthorizationException(String.format(
+                    "Permission denied: user [%s] does not have privilege for 
[%s] command on [%s].[%s].[%s]",
+                    currentUser, wanted, ctl, db, tbl));
+        }
     }
 
 
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 257b6bbad3..9bda2d25c5 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
@@ -44,7 +44,6 @@ import org.apache.doris.utframe.TestWithFeService;
 
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
 import org.junit.Assert;
 import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
@@ -166,9 +165,6 @@ public class ColumnPrivTest extends TestWithFeService {
         //      tbl21:  c11(bigint), c12(string), c13(float)
 
         UserIdentity user1 = 
UserIdentity.createAnalyzedUserIdentWithIp("default_cluster:user1", "%");
-        Set<String> roles = Sets.newHashSet();
-        roles.add("role1");
-        user1.setRoles(roles);
         ConnectContext user1Ctx = createCtx(user1, "127.0.0.1");
 
         // 1. query inner table
@@ -250,7 +246,7 @@ public class ColumnPrivTest extends TestWithFeService {
                     PrivPredicate wanted) throws AuthorizationException {
                 if (currentUser.getQualifiedUser().contains("user1")) {
                     if (ctl.equals("test1")) {
-                        if (db.equals("db1")) {
+                        if (db.equals("default_cluster:db1")) {
                             if (tbl.equals("tbl11")) {
                                 if (cols.contains("a11")) {
                                     throw new AuthorizationException("Access 
deny to column a11");
diff --git 
a/regression-test/suites/account_p0/test_nereids_authentication.groovy 
b/regression-test/suites/account_p0/test_nereids_authentication.groovy
index bd9449cf53..2d5d2cbb13 100644
--- a/regression-test/suites/account_p0/test_nereids_authentication.groovy
+++ b/regression-test/suites/account_p0/test_nereids_authentication.groovy
@@ -57,7 +57,7 @@ suite("test_nereids_authentication", "query") {
             fail()
         } catch (Exception e) {
             log.info(e.getMessage())
-            assertTrue(e.getMessage().contains('SELECT command denied to 
user'))
+            assertTrue(e.getMessage().contains('Permission denied'))
         }
     }
 
@@ -67,7 +67,7 @@ suite("test_nereids_authentication", "query") {
             fail()
         } catch (Exception e) {
             log.info(e.getMessage())
-            assertTrue(e.getMessage().contains('SELECT command denied to 
user'))
+            assertTrue(e.getMessage().contains('Permission denied'))
         }
     }
 


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to