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 41aa5213839cd1..7a2779b43b1c6b 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 @@ -18,6 +18,7 @@ package org.apache.doris.catalog.authorizer.ranger; import org.apache.doris.analysis.UserIdentity; +import org.apache.doris.catalog.authorizer.ranger.doris.DorisAccessType; import org.apache.doris.common.AuthorizationException; import org.apache.doris.mysql.privilege.CatalogAccessController; import org.apache.doris.mysql.privilege.DataMaskPolicy; @@ -92,6 +93,11 @@ public List evalRowFilterPolicies(UserIdentity curren String tbl) { RangerAccessResourceImpl resource = createResource(ctl, db, tbl); RangerAccessRequestImpl request = createRequest(currentUser); + // If the access type is not set here, it defaults to ANY1 ACCESS. + // The internal logic of the ranger is to traverse all permission items. + // Since the ranger UI will set the access type to 'SELECT', + // we will keep it consistent with the UI here to avoid performance issues + request.setAccessType(DorisAccessType.SELECT.name()); request.setResource(resource); if (LOG.isDebugEnabled()) { @@ -119,6 +125,7 @@ public Optional evalDataMaskPolicy(UserIdentity currentUser, Str String col) { RangerAccessResourceImpl resource = createResource(ctl, db, tbl, col); RangerAccessRequestImpl request = createRequest(currentUser); + request.setAccessType(DorisAccessType.SELECT.name()); request.setResource(resource); if (LOG.isDebugEnabled()) { diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/authorizer/ranger/cache/CatalogCacheAccessController.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/authorizer/ranger/cache/CatalogCacheAccessController.java deleted file mode 100644 index 4b2aca0628a59a..00000000000000 --- a/fe/fe-core/src/main/java/org/apache/doris/catalog/authorizer/ranger/cache/CatalogCacheAccessController.java +++ /dev/null @@ -1,91 +0,0 @@ -// 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.catalog.authorizer.ranger.cache; - -import org.apache.doris.analysis.ResourceTypeEnum; -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.PrivPredicate; -import org.apache.doris.mysql.privilege.RowFilterPolicy; - -import java.util.List; -import java.util.Optional; -import java.util.Set; - -public abstract class CatalogCacheAccessController implements CatalogAccessController { - public abstract CatalogAccessController getProxyController(); - - public abstract RangerCache getCache(); - - - @Override - public boolean checkGlobalPriv(UserIdentity currentUser, PrivPredicate wanted) { - return getProxyController().checkGlobalPriv(currentUser, wanted); - } - - @Override - public boolean checkCtlPriv(UserIdentity currentUser, String ctl, PrivPredicate wanted) { - return getProxyController().checkCtlPriv(currentUser, ctl, wanted); - } - - @Override - public boolean checkDbPriv(UserIdentity currentUser, String ctl, String db, PrivPredicate wanted) { - return getProxyController().checkDbPriv(currentUser, ctl, db, wanted); - } - - @Override - public boolean checkTblPriv(UserIdentity currentUser, String ctl, String db, String tbl, PrivPredicate wanted) { - return getProxyController().checkTblPriv(currentUser, ctl, db, tbl, wanted); - } - - @Override - public boolean checkResourcePriv(UserIdentity currentUser, String resourceName, PrivPredicate wanted) { - return getProxyController().checkResourcePriv(currentUser, resourceName, wanted); - } - - @Override - public boolean checkWorkloadGroupPriv(UserIdentity currentUser, String workloadGroupName, PrivPredicate wanted) { - return getProxyController().checkWorkloadGroupPriv(currentUser, workloadGroupName, wanted); - } - - @Override - public void checkColsPriv(UserIdentity currentUser, String ctl, String db, String tbl, Set cols, - PrivPredicate wanted) throws AuthorizationException { - getProxyController().checkColsPriv(currentUser, ctl, db, tbl, cols, wanted); - } - - @Override - public boolean checkCloudPriv(UserIdentity currentUser, String resourceName, PrivPredicate wanted, - ResourceTypeEnum type) { - return getProxyController().checkCloudPriv(currentUser, resourceName, wanted, type); - } - - @Override - public Optional evalDataMaskPolicy(UserIdentity currentUser, String ctl, String db, String tbl, - String col) { - return getCache().getDataMask(new DatamaskCacheKey(currentUser, ctl, db, tbl, col)); - } - - @Override - public List evalRowFilterPolicies(UserIdentity currentUser, String ctl, String db, - String tbl) { - return getCache().getRowFilters(new RowFilterCacheKey(currentUser, ctl, db, tbl)); - } -} diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/authorizer/ranger/cache/DatamaskCacheKey.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/authorizer/ranger/cache/DatamaskCacheKey.java deleted file mode 100644 index d2262d094f9cef..00000000000000 --- a/fe/fe-core/src/main/java/org/apache/doris/catalog/authorizer/ranger/cache/DatamaskCacheKey.java +++ /dev/null @@ -1,89 +0,0 @@ -// 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.catalog.authorizer.ranger.cache; - -import org.apache.doris.analysis.UserIdentity; - -import com.google.common.base.Objects; - -public class DatamaskCacheKey { - private UserIdentity userIdentity; - private String ctl; - private String db; - private String tbl; - private String col; - - public DatamaskCacheKey(UserIdentity userIdentity, String ctl, String db, String tbl, String col) { - this.userIdentity = userIdentity; - this.ctl = ctl; - this.db = db; - this.tbl = tbl; - this.col = col; - } - - public UserIdentity getUserIdentity() { - return userIdentity; - } - - public String getCtl() { - return ctl; - } - - public String getDb() { - return db; - } - - public String getTbl() { - return tbl; - } - - public String getCol() { - return col; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - DatamaskCacheKey that = (DatamaskCacheKey) o; - return Objects.equal(userIdentity, that.userIdentity) - && Objects.equal(ctl, that.ctl) && Objects.equal(db, that.db) - && Objects.equal(tbl, that.tbl) && Objects.equal(col, - that.col); - } - - @Override - public int hashCode() { - return Objects.hashCode(userIdentity, ctl, db, tbl, col); - } - - @Override - public String toString() { - return "DatamaskCacheKey{" - + "userIdentity=" + userIdentity - + ", ctl='" + ctl + '\'' - + ", db='" + db + '\'' - + ", tbl='" + tbl + '\'' - + ", col='" + col + '\'' - + '}'; - } -} diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/authorizer/ranger/cache/RangerCache.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/authorizer/ranger/cache/RangerCache.java deleted file mode 100644 index 29c068b1aff991..00000000000000 --- a/fe/fe-core/src/main/java/org/apache/doris/catalog/authorizer/ranger/cache/RangerCache.java +++ /dev/null @@ -1,107 +0,0 @@ -// 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.catalog.authorizer.ranger.cache; - -import org.apache.doris.common.Config; -import org.apache.doris.datasource.CacheException; -import org.apache.doris.mysql.privilege.CatalogAccessController; -import org.apache.doris.mysql.privilege.DataMaskPolicy; -import org.apache.doris.mysql.privilege.RowFilterPolicy; - -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.CacheLoader; -import com.google.common.cache.LoadingCache; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.List; -import java.util.Objects; -import java.util.Optional; -import java.util.concurrent.ExecutionException; - -public class RangerCache { - private static final Logger LOG = LoggerFactory.getLogger(RangerCache.class); - - private CatalogAccessController controller; - private LoadingCache> datamaskCache = CacheBuilder.newBuilder() - .maximumSize(Config.ranger_cache_size) - .build(new CacheLoader>() { - @Override - public Optional load(DatamaskCacheKey key) { - return loadDataMask(key); - } - }); - - private LoadingCache> rowFilterCache = CacheBuilder.newBuilder() - .maximumSize(Config.ranger_cache_size) - .build(new CacheLoader>() { - @Override - public List load(RowFilterCacheKey key) { - return loadRowFilter(key); - } - }); - - public RangerCache() { - } - - public void init(CatalogAccessController controller) { - this.controller = controller; - } - - private Optional loadDataMask(DatamaskCacheKey key) { - Objects.requireNonNull(controller, "controller can not be null"); - if (LOG.isDebugEnabled()) { - LOG.debug("load datamask: {}", key); - } - return controller.evalDataMaskPolicy(key.getUserIdentity(), key.getCtl(), key.getDb(), key.getTbl(), - key.getCol()); - } - - private List loadRowFilter(RowFilterCacheKey key) { - Objects.requireNonNull(controller, "controller can not be null"); - if (LOG.isDebugEnabled()) { - LOG.debug("load row filter: {}", key); - } - return controller.evalRowFilterPolicies(key.getUserIdentity(), key.getCtl(), key.getDb(), key.getTbl()); - } - - public void invalidateDataMaskCache() { - datamaskCache.invalidateAll(); - } - - public void invalidateRowFilterCache() { - rowFilterCache.invalidateAll(); - } - - public Optional getDataMask(DatamaskCacheKey key) { - try { - return datamaskCache.get(key); - } catch (ExecutionException e) { - throw new CacheException("failed to get datamask for:" + key, e); - } - } - - public List getRowFilters(RowFilterCacheKey key) { - try { - return rowFilterCache.get(key); - } catch (ExecutionException e) { - throw new CacheException("failed to get row filter for:" + key, e); - } - } - -} diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/authorizer/ranger/cache/RangerCacheInvalidateListener.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/authorizer/ranger/cache/RangerCacheInvalidateListener.java deleted file mode 100644 index 4af56a8ff1bacf..00000000000000 --- a/fe/fe-core/src/main/java/org/apache/doris/catalog/authorizer/ranger/cache/RangerCacheInvalidateListener.java +++ /dev/null @@ -1,41 +0,0 @@ -// 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.catalog.authorizer.ranger.cache; - -import org.apache.doris.catalog.authorizer.ranger.doris.RangerDorisAccessController; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.apache.ranger.plugin.service.RangerAuthContextListener; - -public class RangerCacheInvalidateListener implements RangerAuthContextListener { - private static final Logger LOG = LogManager.getLogger(RangerDorisAccessController.class); - - private RangerCache cache; - - public RangerCacheInvalidateListener(RangerCache cache) { - this.cache = cache; - } - - @Override - public void contextChanged() { - LOG.info("ranger context changed"); - cache.invalidateDataMaskCache(); - cache.invalidateRowFilterCache(); - } -} diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/authorizer/ranger/cache/RowFilterCacheKey.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/authorizer/ranger/cache/RowFilterCacheKey.java deleted file mode 100644 index 08afcb40fcb59b..00000000000000 --- a/fe/fe-core/src/main/java/org/apache/doris/catalog/authorizer/ranger/cache/RowFilterCacheKey.java +++ /dev/null @@ -1,82 +0,0 @@ -// 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.catalog.authorizer.ranger.cache; - -import org.apache.doris.analysis.UserIdentity; - -import com.google.common.base.Objects; - -public class RowFilterCacheKey { - private UserIdentity userIdentity; - private String ctl; - private String db; - private String tbl; - - public RowFilterCacheKey(UserIdentity userIdentity, String ctl, String db, String tbl) { - this.userIdentity = userIdentity; - this.ctl = ctl; - this.db = db; - this.tbl = tbl; - } - - public UserIdentity getUserIdentity() { - return userIdentity; - } - - public String getCtl() { - return ctl; - } - - public String getDb() { - return db; - } - - public String getTbl() { - return tbl; - } - - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - RowFilterCacheKey that = (RowFilterCacheKey) o; - return Objects.equal(userIdentity, that.userIdentity) - && Objects.equal(ctl, that.ctl) && Objects.equal(db, that.db) - && Objects.equal(tbl, that.tbl); - } - - @Override - public int hashCode() { - return Objects.hashCode(userIdentity, ctl, db, tbl); - } - - @Override - public String toString() { - return "DatamaskCacheKey{" - + "userIdentity=" + userIdentity - + ", ctl='" + ctl + '\'' - + ", db='" + db + '\'' - + ", tbl='" + tbl + '\'' - + '}'; - } -} 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 259646557da1ef..77d7bfefc239d5 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 @@ -17,66 +17,45 @@ package org.apache.doris.catalog.authorizer.ranger.doris; -import org.apache.doris.mysql.privilege.PrivPredicate; +import org.apache.doris.mysql.privilege.Privilege; // Same as defined in PrivPredicate.java public enum DorisAccessType { - SHOW, - SHOW_VIEW, - SHOW_RESOURCES, - SHOW_WORKLOAD_GROUP, - GRANT, + NODE, ADMIN, + GRANT, + SELECT, LOAD, ALTER, CREATE, - ALTER_CREATE, - ALTER_CREATE_DROP, DROP, - SELECT, - OPERATOR, USAGE, - ALL, - NODE, + SHOW_VIEW, NONE; - - public static DorisAccessType toAccessType(PrivPredicate priv) { - if (priv == PrivPredicate.SHOW) { - return SHOW; - } else if (priv == PrivPredicate.SHOW_VIEW) { - return SHOW_VIEW; - } else if (priv == PrivPredicate.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 USAGE; - } else if (priv == PrivPredicate.GRANT) { - return GRANT; - } else if (priv == PrivPredicate.ADMIN) { - return ADMIN; - } else if (priv == PrivPredicate.LOAD) { - return LOAD; - } else if (priv == PrivPredicate.ALTER) { - return ALTER; - } else if (priv == PrivPredicate.CREATE) { - return CREATE; - } else if (priv == PrivPredicate.ALTER_CREATE) { - return ALTER_CREATE; - } else if (priv == PrivPredicate.ALTER_CREATE_DROP) { - return ALTER_CREATE_DROP; - } else if (priv == PrivPredicate.DROP) { - return DROP; - } else if (priv == PrivPredicate.SELECT) { - return SELECT; - } else if (priv == PrivPredicate.OPERATOR) { - return OPERATOR; - } else if (priv == PrivPredicate.USAGE) { - return USAGE; - } else if (priv == PrivPredicate.ALL) { - return ALL; - } else { - return NONE; + public static DorisAccessType toAccessType(Privilege privilege) { + switch (privilege) { + case ADMIN_PRIV: + return ADMIN; + case NODE_PRIV: + return NODE; + case GRANT_PRIV: + return GRANT; + case SELECT_PRIV: + return SELECT; + case LOAD_PRIV: + return LOAD; + case ALTER_PRIV: + return ALTER; + case CREATE_PRIV: + return CREATE; + case DROP_PRIV: + return DROP; + case USAGE_PRIV: + return USAGE; + case SHOW_VIEW_PRIV: + return SHOW_VIEW; + default: + return NONE; } } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/authorizer/ranger/doris/DorisObjectType.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/authorizer/ranger/doris/DorisObjectType.java index dd7002117ef2c2..cafff6bd6e1747 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/catalog/authorizer/ranger/doris/DorisObjectType.java +++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/authorizer/ranger/doris/DorisObjectType.java @@ -18,5 +18,5 @@ package org.apache.doris.catalog.authorizer.ranger.doris; public enum DorisObjectType { - NONE, CATALOG, DATABASE, TABLE, COLUMN, RESOURCE, WORKLOAD_GROUP + NONE, CATALOG, DATABASE, TABLE, COLUMN, RESOURCE, WORKLOAD_GROUP, GLOBAL } diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/authorizer/ranger/doris/RangerCacheDorisAccessController.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/authorizer/ranger/doris/RangerCacheDorisAccessController.java deleted file mode 100644 index 2cbc8111d52c9c..00000000000000 --- a/fe/fe-core/src/main/java/org/apache/doris/catalog/authorizer/ranger/doris/RangerCacheDorisAccessController.java +++ /dev/null @@ -1,44 +0,0 @@ -// 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.catalog.authorizer.ranger.doris; - -import org.apache.doris.catalog.authorizer.ranger.cache.CatalogCacheAccessController; -import org.apache.doris.catalog.authorizer.ranger.cache.RangerCache; -import org.apache.doris.catalog.authorizer.ranger.cache.RangerCacheInvalidateListener; -import org.apache.doris.mysql.privilege.CatalogAccessController; - -public class RangerCacheDorisAccessController extends CatalogCacheAccessController { - private CatalogAccessController proxyController; - private RangerCache cache; - - public RangerCacheDorisAccessController(String serviceName) { - this.cache = new RangerCache(); - this.proxyController = new RangerDorisAccessController(serviceName, new RangerCacheInvalidateListener(cache)); - this.cache.init(proxyController); - } - - @Override - public CatalogAccessController getProxyController() { - return proxyController; - } - - @Override - public RangerCache getCache() { - return cache; - } -} 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 b0deea1887b370..8a7bea57534f6e 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 @@ -19,32 +19,32 @@ import org.apache.doris.analysis.ResourceTypeEnum; import org.apache.doris.analysis.UserIdentity; -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.AuthorizationException; +import org.apache.doris.mysql.privilege.PrivBitSet; import org.apache.doris.mysql.privilege.PrivPredicate; +import org.apache.doris.mysql.privilege.Privilege; 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; +import org.apache.ranger.plugin.policyengine.RangerAccessRequest.ResourceMatchingScope; 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.RangerAuthContextListener; 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.Set; -import java.util.stream.Collectors; public class RangerDorisAccessController extends RangerAccessController { private static final Logger LOG = LogManager.getLogger(RangerDorisAccessController.class); + // ranger must set name, we agreed that this name must be used + private static final String GLOBAL_PRIV_FIXED_NAME = "*"; + private RangerBasePlugin dorisPlugin; // private static ScheduledThreadPoolExecutor logFlushTimer = ThreadPoolManager.newDaemonScheduledThreadPool(1, // "ranger-doris-audit-log-flusher-timer", true); @@ -77,10 +77,6 @@ private RangerAccessRequestImpl createRequest(UserIdentity currentUser, DorisAcc protected 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); @@ -89,84 +85,161 @@ protected RangerAccessRequestImpl createRequest(UserIdentity currentUser) { return request; } - private void checkPrivileges(UserIdentity currentUser, DorisAccessType accessType, - List dorisResources) throws AuthorizationException { - List requests = new ArrayList<>(); - for (RangerDorisResource resource : dorisResources) { - RangerAccessRequestImpl request = createRequest(currentUser, accessType); - request.setResource(resource); - requests.add(request); - } - - Collection results = dorisPlugin.isAccessAllowed(requests); - checkRequestResults(results, accessType.name()); - } - - private boolean checkPrivilege(UserIdentity currentUser, DorisAccessType accessType, + private boolean checkPrivilegeByPlugin(UserIdentity currentUser, DorisAccessType accessType, RangerDorisResource resource) { RangerAccessRequestImpl request = createRequest(currentUser, accessType); request.setResource(resource); - if (LOG.isDebugEnabled()) { LOG.debug("ranger request: {}", request); } - RangerAccessResult result = dorisPlugin.isAccessAllowed(request); return checkRequestResult(request, result, accessType.name()); } + private boolean checkShowPrivilegeByPlugin(UserIdentity currentUser, RangerDorisResource resource) { + RangerAccessRequestImpl request = createRequest(currentUser); + request.setResource(resource); + request.setResourceMatchingScope(ResourceMatchingScope.SELF_OR_DESCENDANTS); + if (LOG.isDebugEnabled()) { + LOG.debug("ranger request: {}", request); + } + RangerAccessResult result = dorisPlugin.isAccessAllowed(request); + return checkRequestResult(request, result, DorisAccessType.NONE.name()); + } + + private boolean checkPrivilege(UserIdentity currentUser, PrivPredicate wanted, + RangerDorisResource resource, PrivBitSet checkedPrivs) { + PrivBitSet copy = wanted.getPrivs().copy(); + // avoid duplicate check auth at different levels + copy.remove(checkedPrivs); + for (Privilege privilege : copy.toPrivilegeList()) { + boolean res = checkPrivilegeByPlugin(currentUser, DorisAccessType.toAccessType(privilege), resource); + if (res) { + checkedPrivs.set(privilege.getIdx()); + } + if (Privilege.satisfy(checkedPrivs, wanted)) { + return true; + } + } + return false; + } + @Override public boolean checkGlobalPriv(UserIdentity currentUser, PrivPredicate wanted) { - // ranger does not support global privilege, - // use internal privilege check instead - return Env.getCurrentEnv().getAuth().checkGlobalPriv(currentUser, wanted); + PrivBitSet checkedPrivs = PrivBitSet.of(); + return checkGlobalPrivInternal(currentUser, wanted, checkedPrivs); + } + + private boolean checkGlobalPrivInternal(UserIdentity currentUser, PrivPredicate wanted, PrivBitSet checkedPrivs) { + RangerDorisResource resource = new RangerDorisResource(DorisObjectType.GLOBAL, GLOBAL_PRIV_FIXED_NAME); + return checkPrivilege(currentUser, wanted, resource, checkedPrivs); } @Override public boolean checkCtlPriv(UserIdentity currentUser, String ctl, PrivPredicate wanted) { + PrivBitSet checkedPrivs = PrivBitSet.of(); + if (checkGlobalPrivInternal(currentUser, wanted, checkedPrivs) + || checkCtlPrivInternal(currentUser, ctl, wanted, checkedPrivs)) { + return true; + } + if (wanted == PrivPredicate.SHOW && checkAnyPrivWithinCtl(currentUser, ctl)) { + return true; + } + return false; + } + + private boolean checkCtlPrivInternal(UserIdentity currentUser, String ctl, PrivPredicate wanted, + PrivBitSet checkedPrivs) { + RangerDorisResource resource = new RangerDorisResource(DorisObjectType.CATALOG, ctl); + return checkPrivilege(currentUser, wanted, resource, checkedPrivs); + } + + private boolean checkAnyPrivWithinCtl(UserIdentity currentUser, String ctl) { RangerDorisResource resource = new RangerDorisResource(DorisObjectType.CATALOG, ctl); - return checkPrivilege(currentUser, DorisAccessType.toAccessType(wanted), resource); + return checkShowPrivilegeByPlugin(currentUser, resource); } @Override public boolean checkDbPriv(UserIdentity currentUser, String ctl, String db, PrivPredicate wanted) { - boolean res = checkCtlPriv(currentUser, ctl, wanted); - if (res) { + PrivBitSet checkedPrivs = PrivBitSet.of(); + if (checkGlobalPrivInternal(currentUser, wanted, checkedPrivs) + || checkCtlPrivInternal(currentUser, ctl, wanted, checkedPrivs) + || checkDbPrivInternal(currentUser, ctl, db, wanted, checkedPrivs)) { return true; } + if (wanted == PrivPredicate.SHOW && checkAnyPrivWithinDb(currentUser, ctl, db)) { + return true; + } + return false; + } + + private boolean checkDbPrivInternal(UserIdentity currentUser, String ctl, String db, PrivPredicate wanted, + PrivBitSet checkedPrivs) { RangerDorisResource resource = new RangerDorisResource(DorisObjectType.DATABASE, ctl, ClusterNamespace.getNameFromFullName(db)); - return checkPrivilege(currentUser, DorisAccessType.toAccessType(wanted), resource); + return checkPrivilege(currentUser, wanted, resource, checkedPrivs); + } + + private boolean checkAnyPrivWithinDb(UserIdentity currentUser, String ctl, String db) { + RangerDorisResource resource = new RangerDorisResource(DorisObjectType.DATABASE, ctl, + ClusterNamespace.getNameFromFullName(db)); + return checkShowPrivilegeByPlugin(currentUser, resource); } @Override public boolean checkTblPriv(UserIdentity currentUser, String ctl, String db, String tbl, PrivPredicate wanted) { - boolean res = checkDbPriv(currentUser, ctl, db, wanted); - if (res) { + PrivBitSet checkedPrivs = PrivBitSet.of(); + if (checkGlobalPrivInternal(currentUser, wanted, checkedPrivs) + || checkCtlPrivInternal(currentUser, ctl, wanted, checkedPrivs) + || checkDbPrivInternal(currentUser, ctl, db, wanted, checkedPrivs) + || checkTblPrivInternal(currentUser, ctl, db, tbl, wanted, checkedPrivs)) { return true; } + if (wanted == PrivPredicate.SHOW && checkAnyPrivWithinTbl(currentUser, ctl, db, tbl)) { + return true; + } + return false; + } + + private boolean checkTblPrivInternal(UserIdentity currentUser, String ctl, String db, String tbl, + PrivPredicate wanted, PrivBitSet checkedPrivs) { + RangerDorisResource resource = new RangerDorisResource(DorisObjectType.TABLE, + ctl, ClusterNamespace.getNameFromFullName(db), tbl); + return checkPrivilege(currentUser, wanted, resource, checkedPrivs); + } + private boolean checkAnyPrivWithinTbl(UserIdentity currentUser, String ctl, String db, String tbl) { RangerDorisResource resource = new RangerDorisResource(DorisObjectType.TABLE, ctl, ClusterNamespace.getNameFromFullName(db), tbl); - return checkPrivilege(currentUser, DorisAccessType.toAccessType(wanted), resource); + return checkShowPrivilegeByPlugin(currentUser, resource); } @Override public void checkColsPriv(UserIdentity currentUser, String ctl, String db, String tbl, Set cols, PrivPredicate wanted) throws AuthorizationException { - boolean res = checkTblPriv(currentUser, ctl, db, tbl, wanted); - if (res) { + PrivBitSet checkedPrivs = PrivBitSet.of(); + boolean hasTablePriv = checkGlobalPrivInternal(currentUser, wanted, checkedPrivs) + || checkCtlPrivInternal(currentUser, ctl, wanted, checkedPrivs) + || checkDbPrivInternal(currentUser, ctl, db, wanted, checkedPrivs) + || checkTblPrivInternal(currentUser, ctl, db, tbl, wanted, checkedPrivs); + if (hasTablePriv) { return; } - List resources = new ArrayList<>(); for (String col : cols) { - RangerDorisResource resource = new RangerDorisResource(DorisObjectType.COLUMN, - ctl, ClusterNamespace.getNameFromFullName(db), tbl, col); - resources.add(resource); + if (!checkColPrivInternal(currentUser, ctl, db, tbl, col, wanted, checkedPrivs.copy())) { + throw new AuthorizationException(String.format( + "Permission denied: user [%s] does not have privilege for [%s] command on [%s].[%s].[%s].[%s]", + currentUser, wanted, ctl, db, tbl, col)); + } } + } - checkPrivileges(currentUser, DorisAccessType.toAccessType(wanted), resources); + private boolean checkColPrivInternal(UserIdentity currentUser, String ctl, String db, String tbl, String col, + PrivPredicate wanted, PrivBitSet checkedPrivs) { + RangerDorisResource resource = new RangerDorisResource(DorisObjectType.COLUMN, + ctl, ClusterNamespace.getNameFromFullName(db), tbl, col); + return checkPrivilege(currentUser, wanted, resource, checkedPrivs); } @Override @@ -177,8 +250,15 @@ public boolean checkCloudPriv(UserIdentity currentUser, String resourceName, @Override public boolean checkResourcePriv(UserIdentity currentUser, String resourceName, PrivPredicate wanted) { + PrivBitSet checkedPrivs = PrivBitSet.of(); + return checkGlobalPrivInternal(currentUser, wanted, checkedPrivs) + || checkResourcePrivInternal(currentUser, resourceName, wanted, checkedPrivs); + } + + private boolean checkResourcePrivInternal(UserIdentity currentUser, String resourceName, PrivPredicate wanted, + PrivBitSet checkedPrivs) { RangerDorisResource resource = new RangerDorisResource(DorisObjectType.RESOURCE, resourceName); - return checkPrivilege(currentUser, DorisAccessType.toAccessType(wanted), resource); + return checkPrivilege(currentUser, wanted, resource, checkedPrivs); } @Override @@ -187,8 +267,15 @@ public boolean checkWorkloadGroupPriv(UserIdentity currentUser, String workloadG if (WorkloadGroupMgr.DEFAULT_GROUP_NAME.equals(workloadGroupName)) { return true; } + PrivBitSet checkedPrivs = PrivBitSet.of(); + return checkGlobalPrivInternal(currentUser, wanted, checkedPrivs) + || checkWorkloadGroupInternal(currentUser, workloadGroupName, wanted, checkedPrivs); + } + + private boolean checkWorkloadGroupInternal(UserIdentity currentUser, String workloadGroupName, PrivPredicate wanted, + PrivBitSet checkedPrivs) { RangerDorisResource resource = new RangerDorisResource(DorisObjectType.WORKLOAD_GROUP, workloadGroupName); - return checkPrivilege(currentUser, DorisAccessType.toAccessType(wanted), resource); + return checkPrivilege(currentUser, wanted, resource, checkedPrivs); } @Override diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/authorizer/ranger/doris/RangerDorisResource.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/authorizer/ranger/doris/RangerDorisResource.java index 648a76acdb3b30..db173a25354d4f 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/catalog/authorizer/ranger/doris/RangerDorisResource.java +++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/authorizer/ranger/doris/RangerDorisResource.java @@ -20,6 +20,7 @@ import org.apache.ranger.plugin.policyengine.RangerAccessResourceImpl; public class RangerDorisResource extends RangerAccessResourceImpl { + public static final String KEY_GLOBAL = "global"; public static final String KEY_CATALOG = "catalog"; public static final String KEY_DATABASE = "database"; public static final String KEY_TABLE = "table"; @@ -27,7 +28,7 @@ public class RangerDorisResource extends RangerAccessResourceImpl { public static final String KEY_RESOURCE = "resource"; public static final String KEY_WORKLOAD_GROUP = "workload_group"; - // FirstLevelResource => Catalog / Resource / WorkloadGroup + // FirstLevelResource => Catalog / Resource / WorkloadGroup / GLOBAL // SecondLevelResource => Database // ThirdLevelResource => Table // FourthLevelResource => Column @@ -48,6 +49,9 @@ public RangerDorisResource(DorisObjectType objectType, String firstLevelResource String thirdLevelResource, String fourthLevelResource) { // set essential info according to objectType switch (objectType) { + case GLOBAL: + setValue(KEY_GLOBAL, firstLevelResource); + break; case CATALOG: setValue(KEY_CATALOG, firstLevelResource); break; diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/authorizer/ranger/hive/RangerCacheHiveAccessController.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/authorizer/ranger/hive/RangerCacheHiveAccessController.java deleted file mode 100644 index f4f510a12e641c..00000000000000 --- a/fe/fe-core/src/main/java/org/apache/doris/catalog/authorizer/ranger/hive/RangerCacheHiveAccessController.java +++ /dev/null @@ -1,47 +0,0 @@ -// 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.catalog.authorizer.ranger.hive; - -import org.apache.doris.catalog.authorizer.ranger.cache.CatalogCacheAccessController; -import org.apache.doris.catalog.authorizer.ranger.cache.RangerCache; -import org.apache.doris.catalog.authorizer.ranger.cache.RangerCacheInvalidateListener; -import org.apache.doris.mysql.privilege.CatalogAccessController; - -import java.util.Map; - -public class RangerCacheHiveAccessController extends CatalogCacheAccessController { - - private CatalogAccessController proxyController; - private RangerCache cache; - - public RangerCacheHiveAccessController(Map properties) { - this.cache = new RangerCache(); - this.proxyController = new RangerHiveAccessController(properties, new RangerCacheInvalidateListener(cache)); - this.cache.init(proxyController); - } - - @Override - public CatalogAccessController getProxyController() { - return proxyController; - } - - @Override - public RangerCache getCache() { - return cache; - } -} diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/authorizer/ranger/hive/RangerHiveAccessControllerFactory.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/authorizer/ranger/hive/RangerHiveAccessControllerFactory.java index 33e3f4a64c199a..a45632ff9e619c 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/catalog/authorizer/ranger/hive/RangerHiveAccessControllerFactory.java +++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/authorizer/ranger/hive/RangerHiveAccessControllerFactory.java @@ -31,6 +31,6 @@ public String factoryIdentifier() { @Override public CatalogAccessController createAccessController(Map prop) { - return new RangerCacheHiveAccessController(prop); + return new RangerHiveAccessController(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 bfdf0a7b095bcc..678ff704d3902f 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 @@ -227,9 +227,13 @@ public void checkColumnsPriv(UserIdentity currentUser, String PrivPredicate wanted) throws UserException { boolean hasGlobal = checkGlobalPriv(currentUser, wanted); CatalogAccessController accessController = getAccessControllerOrDefault(ctl); + long start = System.currentTimeMillis(); accessController.checkColsPriv(hasGlobal, currentUser, ctl, qualifiedDb, tbl, cols, wanted); - + if (LOG.isDebugEnabled()) { + LOG.debug("checkColumnsPriv use {} mills, user: {}, ctl: {}, db: {}, table: {}, cols: {}", + System.currentTimeMillis() - start, currentUser, ctl, qualifiedDb, tbl, cols); + } } // ==== Resource ==== diff --git a/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/RangerDorisAccessControllerFactory.java b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/RangerDorisAccessControllerFactory.java index 297fe5c708c434..28093ad7886ee7 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/RangerDorisAccessControllerFactory.java +++ b/fe/fe-core/src/main/java/org/apache/doris/mysql/privilege/RangerDorisAccessControllerFactory.java @@ -17,7 +17,7 @@ package org.apache.doris.mysql.privilege; -import org.apache.doris.catalog.authorizer.ranger.doris.RangerCacheDorisAccessController; +import org.apache.doris.catalog.authorizer.ranger.doris.RangerDorisAccessController; import java.util.Map; @@ -28,7 +28,7 @@ public String factoryIdentifier() { } @Override - public RangerCacheDorisAccessController createAccessController(Map prop) { - return new RangerCacheDorisAccessController("doris"); + public RangerDorisAccessController createAccessController(Map prop) { + return new RangerDorisAccessController("doris"); } }