[feature](ranger) Support Apache ranger for Doris (#27864)

For usage, see:
5d340ce24f/docs/zh-CN/docs/admin-manual/privilege-ldap/ranger.md

For range-doris-plugin, see:
https://github.com/morningman/ranger/tree/doris-plugin

To support ranger, there are several other modification:

1. Support `show resources like "pattern"`
2. Support `show workload group like "pattern"`
3. Support `show schemas like "pattern"`
This commit is contained in:
Mingyu Chen
2024-01-27 09:08:15 +08:00
committed by yiguolei
parent 2284575afa
commit 5d7543b30b
51 changed files with 1367 additions and 274 deletions

View File

@ -17,7 +17,6 @@
package org.apache.doris.analysis;
import org.apache.doris.analysis.CompoundPredicate.Operator;
import org.apache.doris.catalog.Env;
import org.apache.doris.common.AnalysisException;
import org.apache.doris.common.ErrorCode;
@ -25,9 +24,7 @@ import org.apache.doris.common.ErrorReport;
import org.apache.doris.common.FeNameFormat;
import org.apache.doris.common.UserException;
import org.apache.doris.common.util.InternalDatabaseUtil;
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.qe.ConnectContext;
import com.google.common.base.Strings;
@ -57,7 +54,7 @@ public class AlterDatabaseRename extends DdlStmt {
}
InternalDatabaseUtil.checkDatabase(dbName, ConnectContext.get());
if (!Env.getCurrentEnv().getAccessManager().checkDbPriv(ConnectContext.get(), dbName,
PrivPredicate.of(PrivBitSet.of(Privilege.ADMIN_PRIV, Privilege.ALTER_PRIV), Operator.OR))) {
PrivPredicate.ALTER)) {
ErrorReport.reportAnalysisException(ErrorCode.ERR_DBACCESS_DENIED_ERROR,
analyzer.getQualifiedUser(), dbName);
}

View File

@ -22,7 +22,6 @@ import org.apache.doris.common.AnalysisException;
import org.apache.doris.common.ErrorCode;
import org.apache.doris.common.ErrorReport;
import org.apache.doris.common.UserException;
import org.apache.doris.mysql.privilege.Auth.PrivLevel;
import org.apache.doris.mysql.privilege.PasswordPolicy.FailedLoginPolicy;
import org.apache.doris.mysql.privilege.PrivPredicate;
import org.apache.doris.qe.ConnectContext;
@ -121,9 +120,7 @@ public class AlterUserStmt extends DdlStmt {
throw new AnalysisException("Only support doing one type of operation at one time");
}
// check if current user has GRANT priv on GLOBAL or DATABASE level.
if (!Env.getCurrentEnv().getAccessManager().checkHasPriv(ConnectContext.get(),
PrivPredicate.GRANT, PrivLevel.GLOBAL, PrivLevel.DATABASE)) {
if (!Env.getCurrentEnv().getAccessManager().checkGlobalPriv(ConnectContext.get(), PrivPredicate.GRANT)) {
ErrorReport.reportAnalysisException(ErrorCode.ERR_SPECIFIC_ACCESS_DENIED_ERROR, "GRANT");
}
}

View File

@ -22,7 +22,6 @@ import org.apache.doris.common.ErrorCode;
import org.apache.doris.common.ErrorReport;
import org.apache.doris.common.FeNameFormat;
import org.apache.doris.common.UserException;
import org.apache.doris.mysql.privilege.Auth.PrivLevel;
import org.apache.doris.mysql.privilege.PrivPredicate;
import org.apache.doris.mysql.privilege.Role;
import org.apache.doris.qe.ConnectContext;
@ -127,9 +126,7 @@ public class CreateUserStmt extends DdlStmt {
passwordOptions.analyze();
// check if current user has GRANT priv on GLOBAL or DATABASE level.
if (!Env.getCurrentEnv().getAccessManager().checkHasPriv(ConnectContext.get(),
PrivPredicate.GRANT, PrivLevel.GLOBAL, PrivLevel.DATABASE)) {
if (!Env.getCurrentEnv().getAccessManager().checkGlobalPriv(ConnectContext.get(), PrivPredicate.GRANT)) {
ErrorReport.reportAnalysisException(ErrorCode.ERR_SPECIFIC_ACCESS_DENIED_ERROR, "GRANT");
}
}

View File

@ -17,15 +17,12 @@
package org.apache.doris.analysis;
import org.apache.doris.analysis.CompoundPredicate.Operator;
import org.apache.doris.catalog.Env;
import org.apache.doris.common.AnalysisException;
import org.apache.doris.common.ErrorCode;
import org.apache.doris.common.ErrorReport;
import org.apache.doris.common.UserException;
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.qe.ConnectContext;
import com.google.common.base.Strings;
@ -63,8 +60,7 @@ public class RecoverDbStmt extends DdlStmt {
}
if (!Env.getCurrentEnv().getAccessManager().checkDbPriv(ConnectContext.get(), dbName,
PrivPredicate.of(PrivBitSet.of(
Privilege.ALTER_PRIV, Privilege.CREATE_PRIV, Privilege.ADMIN_PRIV), Operator.OR))) {
PrivPredicate.ALTER_CREATE)) {
ErrorReport.reportAnalysisException(
ErrorCode.ERR_DBACCESS_DENIED_ERROR, analyzer.getQualifiedUser(), dbName);
}

View File

@ -17,16 +17,13 @@
package org.apache.doris.analysis;
import org.apache.doris.analysis.CompoundPredicate.Operator;
import org.apache.doris.catalog.Env;
import org.apache.doris.common.AnalysisException;
import org.apache.doris.common.ErrorCode;
import org.apache.doris.common.ErrorReport;
import org.apache.doris.common.UserException;
import org.apache.doris.common.util.Util;
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.qe.ConnectContext;
import com.google.common.base.Strings;
@ -72,8 +69,7 @@ public class RecoverPartitionStmt extends DdlStmt {
// disallow external catalog
Util.prohibitExternalCatalog(dbTblName.getCtl(), this.getClass().getSimpleName());
if (!Env.getCurrentEnv().getAccessManager().checkTblPriv(ConnectContext.get(), dbTblName.getDb(),
dbTblName.getTbl(), PrivPredicate.of(PrivBitSet.of(
Privilege.ALTER_PRIV, Privilege.CREATE_PRIV, Privilege.ADMIN_PRIV), Operator.OR))) {
dbTblName.getTbl(), PrivPredicate.ALTER_CREATE)) {
ErrorReport.reportAnalysisException(ErrorCode.ERR_TABLEACCESS_DENIED_ERROR, "RECOVERY",
ConnectContext.get().getQualifiedUser(),
ConnectContext.get().getRemoteIP(),

View File

@ -17,16 +17,13 @@
package org.apache.doris.analysis;
import org.apache.doris.analysis.CompoundPredicate.Operator;
import org.apache.doris.catalog.Env;
import org.apache.doris.common.AnalysisException;
import org.apache.doris.common.ErrorCode;
import org.apache.doris.common.ErrorReport;
import org.apache.doris.common.UserException;
import org.apache.doris.common.util.Util;
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.qe.ConnectContext;
import com.google.common.base.Strings;
@ -67,13 +64,11 @@ public class RecoverTableStmt extends DdlStmt {
Util.prohibitExternalCatalog(dbTblName.getCtl(), this.getClass().getSimpleName());
if (!Env.getCurrentEnv().getAccessManager().checkTblPriv(
ConnectContext.get(), dbTblName.getDb(), dbTblName.getTbl(), PrivPredicate.of(
PrivBitSet.of(Privilege.ALTER_PRIV, Privilege.CREATE_PRIV, Privilege.ADMIN_PRIV),
Operator.OR))) {
ConnectContext.get(), dbTblName.getDb(), dbTblName.getTbl(), PrivPredicate.ALTER_CREATE)) {
ErrorReport.reportAnalysisException(ErrorCode.ERR_TABLEACCESS_DENIED_ERROR, "RECOVERY",
ConnectContext.get().getQualifiedUser(),
ConnectContext.get().getRemoteIP(),
dbTblName.getDb() + ": " + dbTblName.getTbl());
ConnectContext.get().getQualifiedUser(),
ConnectContext.get().getRemoteIP(),
dbTblName.getDb() + ": " + dbTblName.getTbl());
}
}

View File

@ -17,7 +17,6 @@
package org.apache.doris.analysis;
import org.apache.doris.analysis.CompoundPredicate.Operator;
import org.apache.doris.catalog.Column;
import org.apache.doris.catalog.Env;
import org.apache.doris.catalog.ScalarType;
@ -25,9 +24,7 @@ import org.apache.doris.common.AnalysisException;
import org.apache.doris.common.ErrorCode;
import org.apache.doris.common.ErrorReport;
import org.apache.doris.common.UserException;
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.qe.ConnectContext;
import org.apache.doris.qe.ShowResultSetMetaData;
@ -61,13 +58,9 @@ public class ShowCreateDbStmt extends ShowStmt {
}
if (!Env.getCurrentEnv().getAccessManager().checkDbPriv(ConnectContext.get(), db,
PrivPredicate.of(PrivBitSet.of(Privilege.ADMIN_PRIV,
Privilege.ALTER_PRIV,
Privilege.CREATE_PRIV,
Privilege.DROP_PRIV),
Operator.OR))) {
PrivPredicate.ALTER_CREATE_DROP)) {
ErrorReport.reportAnalysisException(ErrorCode.ERR_DBACCESS_DENIED_ERROR,
ConnectContext.get().getQualifiedUser(), db);
ConnectContext.get().getQualifiedUser(), db);
}
}

View File

@ -43,6 +43,7 @@ import java.util.Set;
public class ShowResourcesStmt extends ShowStmt {
private static final Logger LOG = LogManager.getLogger(ShowResourcesStmt.class);
private String pattern;
private Expr whereClause;
private LimitElement limitElement;
private List<OrderByElement> orderByElements;
@ -56,7 +57,9 @@ public class ShowResourcesStmt extends ShowStmt {
public ShowResourcesStmt() {
}
public ShowResourcesStmt(Expr labelExpr, List<OrderByElement> orderByElements, LimitElement limitElement) {
public ShowResourcesStmt(String pattern, Expr labelExpr,
List<OrderByElement> orderByElements, LimitElement limitElement) {
this.pattern = pattern;
this.whereClause = labelExpr;
this.orderByElements = orderByElements;
this.limitElement = limitElement;
@ -66,6 +69,10 @@ public class ShowResourcesStmt extends ShowStmt {
this.isAccurateMatch = false;
}
public String getPattern() {
return pattern;
}
public ArrayList<OrderByPair> getOrderByPairs() {
return this.orderByPairs;
}
@ -107,22 +114,26 @@ public class ShowResourcesStmt extends ShowStmt {
public void analyze(Analyzer analyzer) throws UserException {
super.analyze(analyzer);
// analyze where clause
boolean isValid;
if (whereClause instanceof CompoundPredicate) {
CompoundPredicate cp = (CompoundPredicate) whereClause;
if (cp.getOp() != org.apache.doris.analysis.CompoundPredicate.Operator.AND) {
throw new AnalysisException("Only allow compound predicate with operator AND");
// If pattern is null, analyze where clause,
// otherwise, ignore where clause.
if (this.pattern == null) {
// analyze where clause
boolean isValid;
if (whereClause instanceof CompoundPredicate) {
CompoundPredicate cp = (CompoundPredicate) whereClause;
if (cp.getOp() != org.apache.doris.analysis.CompoundPredicate.Operator.AND) {
throw new AnalysisException("Only allow compound predicate with operator AND");
}
isValid = isWhereClauseValid(cp.getChild(0)) && isWhereClauseValid(cp.getChild(1));
} else {
isValid = isWhereClauseValid(whereClause);
}
isValid = isWhereClauseValid(cp.getChild(0)) && isWhereClauseValid(cp.getChild(1));
} else {
isValid = isWhereClauseValid(whereClause);
}
if (!isValid) {
throw new AnalysisException("Where clause should looks like: NAME = \"your_resource_name\","
+ " or NAME LIKE \"matcher\", " + " or RESOURCETYPE = \"resource_type\", "
+ " or compound predicate with operator AND");
if (!isValid) {
throw new AnalysisException("Where clause should looks like: NAME = \"your_resource_name\","
+ " or NAME LIKE \"matcher\", " + " or RESOURCETYPE = \"resource_type\", "
+ " or compound predicate with operator AND");
}
}
// order by
@ -203,9 +214,12 @@ public class ShowResourcesStmt extends ShowStmt {
public String toSql() {
StringBuilder sb = new StringBuilder();
sb.append("SHOW RESOURCES");
if (whereClause != null) {
sb.append(" WHERE ").append(whereClause.toSql());
if (pattern != null) {
sb.append(" LIKE '").append(pattern).append("'");
} else {
if (whereClause != null) {
sb.append(" WHERE ").append(whereClause.toSql());
}
}
// Order By clause
@ -225,7 +239,6 @@ public class ShowResourcesStmt extends ShowStmt {
if (getOffset() != -1L) {
sb.append(" OFFSET ").append(getOffset());
}
return sb.toString();
}

View File

@ -19,6 +19,7 @@ package org.apache.doris.analysis;
import org.apache.doris.catalog.Column;
import org.apache.doris.catalog.ScalarType;
import org.apache.doris.common.AnalysisException;
import org.apache.doris.common.UserException;
import org.apache.doris.qe.ConnectContext;
import org.apache.doris.qe.ShowResultSetMetaData;
@ -26,16 +27,34 @@ import org.apache.doris.resource.workloadgroup.WorkloadGroupMgr;
public class ShowWorkloadGroupsStmt extends ShowStmt {
public ShowWorkloadGroupsStmt() {}
private String pattern;
// TODO: not supported yet
private Expr whereClause;
public ShowWorkloadGroupsStmt(String pattern, Expr where) {
this.pattern = pattern;
this.whereClause = where;
}
public String getPattern() {
return pattern;
}
@Override
public void analyze(Analyzer analyzer) throws UserException {
super.analyze(analyzer);
if (this.whereClause != null) {
throw new AnalysisException("Where clause is not supported in show workload groups statement");
}
}
@Override
public String toSql() {
return "SHOW RESOURCE GROUPS";
String sql = "SHOW WORKLOAD GROUPS";
if (this.pattern != null) {
sql += " LIKE '" + pattern + "'";
}
return sql;
}
@Override

View File

@ -23,6 +23,7 @@ import org.apache.doris.analysis.DropResourceStmt;
import org.apache.doris.catalog.Resource.ResourceType;
import org.apache.doris.common.AnalysisException;
import org.apache.doris.common.DdlException;
import org.apache.doris.common.PatternMatcher;
import org.apache.doris.common.io.Text;
import org.apache.doris.common.io.Writable;
import org.apache.doris.common.proc.BaseProcResult;
@ -173,7 +174,8 @@ public class ResourceMgr implements Writable {
.collect(Collectors.toList());
}
public List<List<Comparable>> getResourcesInfo(String name, boolean accurateMatch, Set<String> typeSets) {
public List<List<Comparable>> getResourcesInfo(PatternMatcher matcher,
String name, boolean accurateMatch, Set<String> typeSets) {
List<List<String>> targetRows = procNode.fetchResult().getRows();
List<List<Comparable>> returnRows = Lists.newArrayList();
@ -185,6 +187,10 @@ public class ResourceMgr implements Writable {
String resourceName = row.get(0);
String resourceType = row.get(1);
if (matcher != null && !matcher.match(resourceName)) {
continue;
}
if (name != null) {
if (accurateMatch && !resourceName.equals(name)) {
continue;

View File

@ -0,0 +1,69 @@
// 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;
import org.apache.doris.common.AuthorizationException;
import org.apache.doris.mysql.privilege.CatalogAccessController;
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.RangerAccessResult;
import java.util.Collection;
public abstract class RangerAccessController implements CatalogAccessController {
private static final Logger LOG = LogManager.getLogger(RangerAccessController.class);
protected static final String CLIENT_TYPE_DORIS = "doris";
protected static boolean checkRequestResult(RangerAccessRequestImpl request,
RangerAccessResult result, String name) {
if (result == null) {
LOG.warn("Error getting authorizer result, please check your ranger config. Make sure "
+ "ranger policy engine is initialized. Request: {}", request);
return false;
}
if (result.getIsAllowed()) {
LOG.debug("request {} match policy {}", request, result.getPolicyId());
return true;
} else {
LOG.debug(String.format(
"Permission denied: user [%s] does not have privilege for [%s] command on [%s]",
result.getAccessRequest().getUser(), name,
result.getAccessRequest().getResource().getAsString()));
return false;
}
}
public static void checkRequestResults(Collection<RangerAccessResult> results, String name)
throws AuthorizationException {
for (RangerAccessResult result : results) {
LOG.debug("request {} match policy {}", result.getAccessRequest(), result.getPolicyId());
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(), name,
result.getAccessRequest().getResource().getAsString().replaceAll("/", ".")));
}
}
}
}

View File

@ -0,0 +1,80 @@
// 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.mysql.privilege.PrivPredicate;
// Same as defined in PrivPredicate.java
public enum DorisAccessType {
SHOW,
SHOW_VIEW,
SHOW_RESOURCES,
SHOW_WORKLOAD_GROUP,
GRANT,
ADMIN,
LOAD,
ALTER,
CREATE,
ALTER_CREATE,
ALTER_CREATE_DROP,
DROP,
SELECT,
OPERATOR,
USAGE,
ALL,
NODE,
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) {
return SHOW_RESOURCES;
} else if (priv == PrivPredicate.SHOW_WORKLOAD_GROUP) {
return SHOW_WORKLOAD_GROUP;
} 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;
}
}
}

View File

@ -0,0 +1,22 @@
// 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;
public enum DorisObjectType {
NONE, CATALOG, DATABASE, TABLE, COLUMN, RESOURCE, WORKLOAD_GROUP
}

View File

@ -0,0 +1,181 @@
// 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.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.AuthorizationException;
import org.apache.doris.mysql.privilege.PrivPredicate;
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 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);
private RangerDorisPlugin dorisPlugin;
// private static ScheduledThreadPoolExecutor logFlushTimer = ThreadPoolManager.newDaemonScheduledThreadPool(1,
// "ranger-doris-audit-log-flusher-timer", true);
// private RangerHiveAuditHandler auditHandler;
public RangerDorisAccessController(String serviceName) {
dorisPlugin = new RangerDorisPlugin(serviceName);
// auditHandler = new RangerHiveAuditHandler(dorisPlugin.getConfig());
// start a timed log flusher
// logFlushTimer.scheduleAtFixedRate(new RangerHiveAuditLogFlusher(auditHandler), 10, 20L, TimeUnit.SECONDS);
}
private RangerAccessRequestImpl createRequest(UserIdentity currentUser, DorisAccessType accessType) {
RangerAccessRequestImpl request = new RangerAccessRequestImpl();
request.setUser(ClusterNamespace.getNameFromFullName(currentUser.getQualifiedUser()));
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());
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 void checkPrivileges(UserIdentity currentUser, DorisAccessType accessType,
List<RangerDorisResource> dorisResources) throws AuthorizationException {
List<RangerAccessRequest> requests = new ArrayList<>();
for (RangerDorisResource resource : dorisResources) {
RangerAccessRequestImpl request = createRequest(currentUser, accessType);
request.setResource(resource);
requests.add(request);
}
Collection<RangerAccessResult> results = dorisPlugin.isAccessAllowed(requests);
checkRequestResults(results, accessType.name());
}
private boolean checkPrivilege(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());
}
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);
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,
// use internal privilege check instead
return Env.getCurrentEnv().getAuth().checkGlobalPriv(currentUser, wanted);
}
@Override
public boolean checkCtlPriv(UserIdentity currentUser, String ctl, PrivPredicate wanted) {
RangerDorisResource resource = new RangerDorisResource(DorisObjectType.CATALOG, ctl);
return checkPrivilege(currentUser, DorisAccessType.toAccessType(wanted), resource);
}
@Override
public boolean checkDbPriv(UserIdentity currentUser, String ctl, String db, PrivPredicate wanted) {
RangerDorisResource resource = new RangerDorisResource(DorisObjectType.DATABASE, ctl,
ClusterNamespace.getNameFromFullName(db));
return checkPrivilege(currentUser, DorisAccessType.toAccessType(wanted), resource);
}
@Override
public boolean checkTblPriv(UserIdentity currentUser, String ctl, String db, String tbl, PrivPredicate wanted) {
RangerDorisResource resource = new RangerDorisResource(DorisObjectType.TABLE,
ctl, ClusterNamespace.getNameFromFullName(db), tbl);
return checkPrivilege(currentUser, DorisAccessType.toAccessType(wanted), resource);
}
@Override
public void checkColsPriv(UserIdentity currentUser, String ctl, String db, String tbl, Set<String> cols,
PrivPredicate wanted) throws AuthorizationException {
List<RangerDorisResource> resources = new ArrayList<>();
for (String col : cols) {
RangerDorisResource resource = new RangerDorisResource(DorisObjectType.COLUMN,
ctl, ClusterNamespace.getNameFromFullName(db), tbl, col);
resources.add(resource);
}
checkPrivileges(currentUser, DorisAccessType.toAccessType(wanted), resources);
}
@Override
public boolean checkResourcePriv(UserIdentity currentUser, String resourceName, PrivPredicate wanted) {
RangerDorisResource resource = new RangerDorisResource(DorisObjectType.RESOURCE, resourceName);
return checkPrivilege(currentUser, DorisAccessType.toAccessType(wanted), resource);
}
@Override
public boolean checkWorkloadGroupPriv(UserIdentity currentUser, String workloadGroupName, PrivPredicate wanted) {
RangerDorisResource resource = new RangerDorisResource(DorisObjectType.WORKLOAD_GROUP, workloadGroupName);
return checkPrivilege(currentUser, DorisAccessType.toAccessType(wanted), resource);
}
// For test only
public static void main(String[] args) {
RangerDorisAccessController ac = new RangerDorisAccessController("doris");
UserIdentity user = new UserIdentity("user1", "127.0.0.1");
user.setIsAnalyzed();
boolean res = ac.checkDbPriv(user, "internal", "db1", PrivPredicate.SHOW);
System.out.println("res: " + res);
user = new UserIdentity("user2", "127.0.0.1");
user.setIsAnalyzed();
res = ac.checkTblPriv(user, "internal", "db1", "tbl1", PrivPredicate.SELECT);
System.out.println("res: " + res);
}
}

View File

@ -0,0 +1,27 @@
// 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.ranger.plugin.service.RangerBasePlugin;
public class RangerDorisPlugin extends RangerBasePlugin {
public RangerDorisPlugin(String serviceName) {
super(serviceName, null, null);
super.init();
}
}

View File

@ -0,0 +1,80 @@
// 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.ranger.plugin.policyengine.RangerAccessResourceImpl;
public class RangerDorisResource extends RangerAccessResourceImpl {
public static final String KEY_CATALOG = "catalog";
public static final String KEY_DATABASE = "database";
public static final String KEY_TABLE = "table";
public static final String KEY_COLUMN = "column";
public static final String KEY_RESOURCE = "resource";
public static final String KEY_WORKLOAD_GROUP = "workload_group";
// FirstLevelResource => Catalog / Resource / WorkloadGroup
// SecondLevelResource => Database
// ThirdLevelResource => Table
// FourthLevelResource => Column
public RangerDorisResource(DorisObjectType objectType, String firstLevelResource) {
this(objectType, firstLevelResource, null, null, null);
}
public RangerDorisResource(DorisObjectType objectType, String firstLevelResource, String secondLevelResource) {
this(objectType, firstLevelResource, secondLevelResource, null, null);
}
public RangerDorisResource(DorisObjectType objectType, String firstLevelResource, String secondLevelResource,
String thirdLevelResource) {
this(objectType, firstLevelResource, secondLevelResource, thirdLevelResource, null);
}
public RangerDorisResource(DorisObjectType objectType, String firstLevelResource, String secondLevelResource,
String thirdLevelResource, String fourthLevelResource) {
// set essential info according to objectType
switch (objectType) {
case CATALOG:
setValue(KEY_CATALOG, firstLevelResource);
break;
case DATABASE:
setValue(KEY_CATALOG, firstLevelResource);
setValue(KEY_DATABASE, secondLevelResource);
break;
case TABLE:
setValue(KEY_CATALOG, firstLevelResource);
setValue(KEY_DATABASE, secondLevelResource);
setValue(KEY_TABLE, thirdLevelResource);
break;
case COLUMN:
setValue(KEY_CATALOG, firstLevelResource);
setValue(KEY_DATABASE, secondLevelResource);
setValue(KEY_TABLE, thirdLevelResource);
setValue(KEY_COLUMN, fourthLevelResource);
break;
case RESOURCE:
setValue(KEY_RESOURCE, firstLevelResource);
break;
case WORKLOAD_GROUP:
setValue(KEY_WORKLOAD_GROUP, firstLevelResource);
break;
case NONE:
default:
break;
}
}
}

View File

@ -15,7 +15,7 @@
// specific language governing permissions and limitations
// under the License.
package org.apache.doris.catalog.authorizer;
package org.apache.doris.catalog.authorizer.ranger.hive;
public enum HiveAccessType {
NONE, CREATE, ALTER, DROP, INDEX, LOCK, SELECT, UPDATE, USE, READ, WRITE, ALL, SERVICEADMIN,

View File

@ -15,7 +15,7 @@
// specific language governing permissions and limitations
// under the License.
package org.apache.doris.catalog.authorizer;
package org.apache.doris.catalog.authorizer.ranger.hive;
public enum HiveObjectType {
NONE, DATABASE, TABLE, VIEW, INDEX, COLUMN, FUNCTION;

View File

@ -15,16 +15,18 @@
// specific language governing permissions and limitations
// under the License.
package org.apache.doris.catalog.authorizer;
package org.apache.doris.catalog.authorizer.ranger.hive;
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.common.ThreadPoolManager;
import org.apache.doris.mysql.privilege.CatalogAccessController;
import org.apache.doris.datasource.InternalCatalog;
import org.apache.doris.mysql.privilege.PrivPredicate;
import com.google.common.collect.Maps;
import org.apache.hadoop.hive.ql.security.authorization.plugin.HiveAccessControlException;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@ -43,8 +45,7 @@ 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";
public class RangerHiveAccessController extends RangerAccessController {
private static final Logger LOG = LogManager.getLogger(RangerHiveAccessController.class);
private static ScheduledThreadPoolExecutor logFlushTimer = ThreadPoolManager.newDaemonScheduledThreadPool(1,
"ranger-hive-audit-log-flusher-timer", true);
@ -86,21 +87,11 @@ public class RangerHiveAccessController implements CatalogAccessController {
for (RangerHiveResource resource : hiveResources) {
RangerAccessRequestImpl request = createRequest(currentUser, accessType);
request.setResource(resource);
requests.add(request);
}
Collection<RangerAccessResult> results = hivePlugin.isAccessAllowed(requests, auditHandler);
for (RangerAccessResult result : results) {
LOG.debug(String.format("request %s match policy %s", result.getAccessRequest(), result.getPolicyId()));
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().replaceAll("/", ".")));
}
}
checkRequestResults(results, accessType.name());
}
private boolean checkPrivilege(UserIdentity currentUser, HiveAccessType accessType,
@ -109,23 +100,7 @@ public class RangerHiveAccessController implements CatalogAccessController {
request.setResource(resource);
RangerAccessResult result = hivePlugin.isAccessAllowed(request, auditHandler);
if (result == null) {
LOG.warn(String.format("Error getting authorizer result, please check your ranger config. Make sure "
+ "ranger policy engine is initialized. Request: %s", request));
return false;
}
if (result.getIsAllowed()) {
LOG.debug(String.format("request %s match policy %s", request, result.getPolicyId()));
return true;
} else {
LOG.debug(String.format(
"Permission denied: user [%s] does not have privilege for [%s] command on [%s]",
result.getAccessRequest().getUser(), accessType.name(),
result.getAccessRequest().getResource().getAsString()));
return false;
}
return checkRequestResult(request, result, accessType.name());
}
public String getFilterExpr(UserIdentity currentUser, HiveAccessType accessType,
@ -147,7 +122,7 @@ public class RangerHiveAccessController implements CatalogAccessController {
result.getMaskTypeDef(), result.getMaskedValue()));
}
public HiveAccessType convertToAccessType(PrivPredicate predicate) {
private HiveAccessType convertToAccessType(PrivPredicate predicate) {
if (predicate == PrivPredicate.SHOW) {
return HiveAccessType.USE;
} else if (predicate == PrivPredicate.SELECT) {
@ -167,6 +142,14 @@ public class RangerHiveAccessController implements CatalogAccessController {
}
}
@Override
public boolean checkGlobalPriv(UserIdentity currentUser, PrivPredicate wanted) {
// hive ranger plugin does not support global privilege
// use internal access controller to check
return Env.getCurrentEnv().getAccessManager().getAccessControllerOrDefault(
InternalCatalog.INTERNAL_CATALOG_NAME).checkGlobalPriv(currentUser, wanted);
}
@Override
public boolean checkCtlPriv(UserIdentity currentUser, String ctl, PrivPredicate wanted) {
return true;
@ -198,4 +181,27 @@ public class RangerHiveAccessController implements CatalogAccessController {
checkPrivileges(currentUser, convertToAccessType(wanted), resources);
}
@Override
public boolean checkResourcePriv(UserIdentity currentUser, String resourceName, PrivPredicate wanted) {
return false;
}
@Override
public boolean checkWorkloadGroupPriv(UserIdentity currentUser, String workloadGroupName, PrivPredicate wanted) {
return false;
}
// For test only
public static void main(String[] args) {
Map<String, String> properties = Maps.newHashMap();
properties.put("ranger.service.name", "hive");
RangerHiveAccessController ac = new RangerHiveAccessController(properties);
UserIdentity user = new UserIdentity("user1", "127.0.0.1");
user.setIsAnalyzed();
boolean res = ac.checkDbPriv(user, "hive", "tpcds_bin_partitioned_orc_1", PrivPredicate.SHOW);
System.out.println("res: " + res);
res = ac.checkTblPriv(user, "internal", "tpch1", "customer", PrivPredicate.SELECT);
System.out.println("res: " + res);
}
}

View File

@ -15,7 +15,7 @@
// specific language governing permissions and limitations
// under the License.
package org.apache.doris.catalog.authorizer;
package org.apache.doris.catalog.authorizer.ranger.hive;
import org.apache.doris.mysql.privilege.AccessControllerFactory;
import org.apache.doris.mysql.privilege.CatalogAccessController;

View File

@ -15,7 +15,7 @@
// specific language governing permissions and limitations
// under the License.
package org.apache.doris.catalog.authorizer;
package org.apache.doris.catalog.authorizer.ranger.hive;
import org.apache.commons.lang3.StringUtils;
import org.apache.hadoop.conf.Configuration;

View File

@ -15,7 +15,7 @@
// specific language governing permissions and limitations
// under the License.
package org.apache.doris.catalog.authorizer;
package org.apache.doris.catalog.authorizer.ranger.hive;
import lombok.extern.slf4j.Slf4j;

View File

@ -15,7 +15,7 @@
// specific language governing permissions and limitations
// under the License.
package org.apache.doris.catalog.authorizer;
package org.apache.doris.catalog.authorizer.ranger.hive;
import java.util.Map;

View File

@ -15,7 +15,7 @@
// specific language governing permissions and limitations
// under the License.
package org.apache.doris.catalog.authorizer;
package org.apache.doris.catalog.authorizer.ranger.hive;
import org.apache.ranger.plugin.service.RangerBasePlugin;

View File

@ -15,7 +15,7 @@
// specific language governing permissions and limitations
// under the License.
package org.apache.doris.catalog.authorizer;
package org.apache.doris.catalog.authorizer.ranger.hive;
import org.apache.ranger.plugin.policyengine.RangerAccessResourceImpl;

View File

@ -17,7 +17,6 @@
package org.apache.doris.httpv2.controller;
import org.apache.doris.analysis.CompoundPredicate;
import org.apache.doris.analysis.UserIdentity;
import org.apache.doris.catalog.Env;
import org.apache.doris.cluster.ClusterNamespace;
@ -27,9 +26,7 @@ import org.apache.doris.common.util.NetUtils;
import org.apache.doris.httpv2.HttpAuthManager;
import org.apache.doris.httpv2.HttpAuthManager.SessionValue;
import org.apache.doris.httpv2.exception.UnauthorizedException;
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.qe.ConnectContext;
import org.apache.doris.service.FrontendOptions;
@ -71,8 +68,7 @@ public class BaseController {
UserIdentity currentUser = checkPassword(authInfo);
if (checkAuth) {
checkGlobalAuth(currentUser, PrivPredicate.of(PrivBitSet.of(Privilege.ADMIN_PRIV,
Privilege.NODE_PRIV), CompoundPredicate.Operator.OR));
checkGlobalAuth(currentUser, PrivPredicate.ADMIN);
}
SessionValue value = new SessionValue();
@ -129,8 +125,7 @@ public class BaseController {
}
if (checkAuth && !Env.getCurrentEnv().getAccessManager().checkGlobalPriv(sessionValue.currentUser,
PrivPredicate.of(PrivBitSet.of(Privilege.ADMIN_PRIV,
Privilege.NODE_PRIV), CompoundPredicate.Operator.OR))) {
PrivPredicate.ADMIN)) {
// need to check auth and check auth failed
return null;
}

View File

@ -21,11 +21,12 @@ 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.catalog.authorizer.ranger.doris.RangerDorisAccessController;
import org.apache.doris.common.Config;
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 com.google.common.base.Preconditions;
@ -47,14 +48,18 @@ import java.util.Set;
public class AccessControllerManager {
private static final Logger LOG = LogManager.getLogger(AccessControllerManager.class);
private SystemAccessController sysAccessController;
private CatalogAccessController internalAccessController;
private Auth auth;
private CatalogAccessController defaultAccessController;
private Map<String, CatalogAccessController> ctlToCtlAccessController = Maps.newConcurrentMap();
public AccessControllerManager(Auth auth) {
sysAccessController = new SystemAccessController(auth);
internalAccessController = new InternalCatalogAccessController(auth);
ctlToCtlAccessController.put(InternalCatalog.INTERNAL_CATALOG_NAME, internalAccessController);
this.auth = auth;
if (Config.access_controller_type.equalsIgnoreCase("ranger-doris")) {
defaultAccessController = new RangerDorisAccessController("doris");
} else {
defaultAccessController = new InternalAccessController(auth);
}
ctlToCtlAccessController.put(InternalCatalog.INTERNAL_CATALOG_NAME, defaultAccessController);
}
public CatalogAccessController getAccessControllerOrDefault(String ctl) {
@ -68,7 +73,7 @@ public class AccessControllerManager {
return ctlToCtlAccessController.get(ctl);
}
return internalAccessController;
return defaultAccessController;
}
private synchronized void lazyLoadCtlAccessController(ExternalCatalog catalog) {
@ -77,11 +82,10 @@ public class AccessControllerManager {
}
catalog.initAccessController(false);
if (!ctlToCtlAccessController.containsKey(catalog.getName())) {
ctlToCtlAccessController.put(catalog.getName(), internalAccessController);
ctlToCtlAccessController.put(catalog.getName(), defaultAccessController);
}
}
public boolean checkIfAccessControllerExist(String ctl) {
return ctlToCtlAccessController.containsKey(ctl);
}
@ -112,7 +116,7 @@ public class AccessControllerManager {
}
public Auth getAuth() {
return sysAccessController.getAuth();
return this.auth;
}
// ==== Global ====
@ -121,7 +125,7 @@ public class AccessControllerManager {
}
public boolean checkGlobalPriv(UserIdentity currentUser, PrivPredicate wanted) {
return sysAccessController.checkGlobalPriv(currentUser, wanted);
return defaultAccessController.checkGlobalPriv(currentUser, wanted);
}
// ==== Catalog ====
@ -130,11 +134,10 @@ public class AccessControllerManager {
}
public boolean checkCtlPriv(UserIdentity currentUser, String ctl, PrivPredicate wanted) {
boolean hasGlobal = sysAccessController.checkGlobalPriv(currentUser, wanted);
// for checking catalog priv, always use InternalCatalogAccessController.
// because catalog priv is only saved in InternalCatalogAccessController.
return getAccessControllerOrDefault(InternalCatalog.INTERNAL_CATALOG_NAME).checkCtlPriv(hasGlobal, currentUser,
ctl, wanted);
boolean hasGlobal = checkGlobalPriv(currentUser, wanted);
// for checking catalog priv, always use InternalAccessController.
// because catalog priv is only saved in InternalAccessController.
return defaultAccessController.checkCtlPriv(hasGlobal, currentUser, ctl, wanted);
}
// ==== Database ====
@ -151,7 +154,7 @@ public class AccessControllerManager {
}
public boolean checkDbPriv(UserIdentity currentUser, String ctl, String db, PrivPredicate wanted) {
boolean hasGlobal = sysAccessController.checkGlobalPriv(currentUser, wanted);
boolean hasGlobal = checkGlobalPriv(currentUser, wanted);
return getAccessControllerOrDefault(ctl).checkDbPriv(hasGlobal, currentUser, ctl, db, wanted);
}
@ -178,7 +181,7 @@ public class AccessControllerManager {
}
public boolean checkTblPriv(UserIdentity currentUser, String ctl, String db, String tbl, PrivPredicate wanted) {
boolean hasGlobal = sysAccessController.checkGlobalPriv(currentUser, wanted);
boolean hasGlobal = checkGlobalPriv(currentUser, wanted);
return getAccessControllerOrDefault(ctl).checkTblPriv(hasGlobal, currentUser, ctl, db, tbl, wanted);
}
@ -186,7 +189,7 @@ public class AccessControllerManager {
public void checkColumnsPriv(UserIdentity currentUser, String
ctl, HashMultimap<TableName, String> tableToColsMap,
PrivPredicate wanted) throws UserException {
boolean hasGlobal = sysAccessController.checkGlobalPriv(currentUser, wanted);
boolean hasGlobal = checkGlobalPriv(currentUser, wanted);
CatalogAccessController accessController = getAccessControllerOrDefault(ctl);
for (TableName tableName : tableToColsMap.keySet()) {
accessController.checkColsPriv(hasGlobal, currentUser, ctl,
@ -198,7 +201,7 @@ public class AccessControllerManager {
public void checkColumnsPriv(UserIdentity currentUser, String
ctl, String qualifiedDb, String tbl, Set<String> cols,
PrivPredicate wanted) throws UserException {
boolean hasGlobal = sysAccessController.checkGlobalPriv(currentUser, wanted);
boolean hasGlobal = checkGlobalPriv(currentUser, wanted);
CatalogAccessController accessController = getAccessControllerOrDefault(ctl);
accessController.checkColsPriv(hasGlobal, currentUser, ctl, qualifiedDb,
tbl, cols, wanted);
@ -216,7 +219,7 @@ public class AccessControllerManager {
}
public boolean checkResourcePriv(UserIdentity currentUser, String resourceName, PrivPredicate wanted) {
return sysAccessController.checkResourcePriv(currentUser, resourceName, wanted);
return defaultAccessController.checkResourcePriv(currentUser, resourceName, wanted);
}
public boolean checkWorkloadGroupPriv(ConnectContext ctx, String workloadGroupName, PrivPredicate wanted) {
@ -224,7 +227,7 @@ public class AccessControllerManager {
}
public boolean checkWorkloadGroupPriv(UserIdentity currentUser, String workloadGroupName, PrivPredicate wanted) {
return sysAccessController.checkWorkloadGroupPriv(currentUser, workloadGroupName, wanted);
return defaultAccessController.checkWorkloadGroupPriv(currentUser, workloadGroupName, wanted);
}
// ==== Other ====
@ -245,12 +248,4 @@ public class AccessControllerManager {
}
return true;
}
/*
* Check if current user has certain privilege.
* This method will check the given privilege levels
*/
public boolean checkHasPriv(ConnectContext ctx, PrivPredicate priv, PrivLevel... levels) {
return sysAccessController.checkHasPriv(ctx, priv, levels);
}
}

View File

@ -29,6 +29,10 @@ public interface CatalogAccessController {
return hasGlobal || res;
}
// ==== Global ====
boolean checkGlobalPriv(UserIdentity currentUser, PrivPredicate wanted);
// ==== Catalog ====
boolean checkCtlPriv(UserIdentity currentUser, String ctl, PrivPredicate wanted);
// ==== Database ====
@ -61,6 +65,12 @@ public interface CatalogAccessController {
}
}
// ==== Resource ====
boolean checkResourcePriv(UserIdentity currentUser, String resourceName, PrivPredicate wanted);
// ==== Workload Group ====
boolean checkWorkloadGroupPriv(UserIdentity currentUser, String workloadGroupName, PrivPredicate wanted);
void checkColsPriv(UserIdentity currentUser, String ctl, String db, String tbl,
Set<String> cols, PrivPredicate wanted) throws AuthorizationException;
}

View File

@ -22,13 +22,18 @@ import org.apache.doris.common.AuthorizationException;
import java.util.Set;
public class InternalCatalogAccessController implements CatalogAccessController {
public class InternalAccessController implements CatalogAccessController {
private Auth auth;
public InternalCatalogAccessController(Auth auth) {
public InternalAccessController(Auth auth) {
this.auth = auth;
}
@Override
public boolean checkGlobalPriv(UserIdentity currentUser, PrivPredicate wanted) {
return auth.checkGlobalPriv(currentUser, wanted);
}
@Override
public boolean checkCtlPriv(UserIdentity currentUser, String ctl, PrivPredicate wanted) {
return auth.checkCtlPriv(currentUser, ctl, wanted);
@ -49,4 +54,14 @@ public class InternalCatalogAccessController implements CatalogAccessController
PrivPredicate wanted) throws AuthorizationException {
auth.checkColsPriv(currentUser, ctl, db, tbl, cols, wanted);
}
@Override
public boolean checkResourcePriv(UserIdentity currentUser, String resourceName, PrivPredicate wanted) {
return auth.checkResourcePriv(currentUser, resourceName, wanted);
}
@Override
public boolean checkWorkloadGroupPriv(UserIdentity currentUser, String workloadGroupName, PrivPredicate wanted) {
return auth.checkWorkloadGroupPriv(currentUser, workloadGroupName, wanted);
}
}

View File

@ -61,22 +61,35 @@ public class PrivPredicate {
// alter
public static final PrivPredicate ALTER = PrivPredicate.of(PrivBitSet.of(Privilege.ADMIN_PRIV,
Privilege.ALTER_PRIV),
Privilege.ALTER_PRIV),
Operator.OR);
// create
public static final PrivPredicate CREATE = PrivPredicate.of(PrivBitSet.of(Privilege.ADMIN_PRIV,
Privilege.CREATE_PRIV),
Privilege.CREATE_PRIV),
Operator.OR);
// alter create
public static final PrivPredicate ALTER_CREATE = PrivPredicate.of(PrivBitSet.of(Privilege.ADMIN_PRIV,
Privilege.ALTER_PRIV,
Privilege.CREATE_PRIV),
Operator.OR);
// alter create drop
public static final PrivPredicate ALTER_CREATE_DROP = PrivPredicate.of(PrivBitSet.of(Privilege.ADMIN_PRIV,
Privilege.ALTER_PRIV,
Privilege.CREATE_PRIV,
Privilege.DROP_PRIV),
Operator.OR);
// drop
public static final PrivPredicate DROP = PrivPredicate.of(PrivBitSet.of(Privilege.ADMIN_PRIV,
Privilege.DROP_PRIV),
Privilege.DROP_PRIV),
Operator.OR);
// select
public static final PrivPredicate SELECT = PrivPredicate.of(PrivBitSet.of(Privilege.ADMIN_PRIV,
Privilege.SELECT_PRIV),
Privilege.SELECT_PRIV),
Operator.OR);
// operator
@ -107,7 +120,7 @@ public class PrivPredicate {
this.op = op;
}
public static PrivPredicate of(PrivBitSet privs, Operator op) {
private static PrivPredicate of(PrivBitSet privs, Operator op) {
final PrivPredicate predicate = new PrivPredicate(privs, op);
return predicate;
}

View File

@ -1,54 +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.mysql.privilege;
import org.apache.doris.analysis.UserIdentity;
import org.apache.doris.mysql.privilege.Auth.PrivLevel;
import org.apache.doris.qe.ConnectContext;
public class SystemAccessController {
private Auth auth;
public SystemAccessController(Auth auth) {
this.auth = auth;
}
public Auth getAuth() {
return auth;
}
public boolean checkGlobalPriv(UserIdentity currentUser, PrivPredicate wanted) {
return auth.checkGlobalPriv(currentUser, wanted);
}
public boolean checkResourcePriv(UserIdentity currentUser, String resourceName, PrivPredicate wanted) {
return auth.checkResourcePriv(currentUser, resourceName, wanted);
}
public boolean checkWorkloadGroupPriv(UserIdentity currentUser, String workloadGroupName, PrivPredicate wanted) {
return auth.checkWorkloadGroupPriv(currentUser, workloadGroupName, wanted);
}
/*
* Check if current user has certain privilege.
* This method will check the given privilege levels
*/
public boolean checkHasPriv(ConnectContext ctx, PrivPredicate priv, PrivLevel... levels) {
return auth.checkHasPriv(ctx, priv, levels);
}
}

View File

@ -1915,10 +1915,16 @@ public class ShowExecutor {
}
// Handle show resources
private void handleShowResources() {
private void handleShowResources() throws AnalysisException {
ShowResourcesStmt showStmt = (ShowResourcesStmt) stmt;
PatternMatcher matcher = null;
if (showStmt.getPattern() != null) {
matcher = PatternMatcherWrapper.createMysqlPattern(showStmt.getPattern(),
CaseSensibility.RESOURCE.getCaseSensibility());
}
List<List<Comparable>> resourcesInfos = Env.getCurrentEnv().getResourceMgr()
.getResourcesInfo(showStmt.getNameValue(), showStmt.isAccurateMatch(), showStmt.getTypeSet());
.getResourcesInfo(matcher, showStmt.getNameValue(), showStmt.isAccurateMatch(), showStmt.getTypeSet());
// order the result of List<LoadInfo> by orderByPairs in show stmt
List<OrderByPair> orderByPairs = showStmt.getOrderByPairs();
@ -1959,10 +1965,14 @@ public class ShowExecutor {
resultSet = new ShowResultSet(showStmt.getMetaData(), rows);
}
private void handleShowWorkloadGroups() {
private void handleShowWorkloadGroups() throws AnalysisException {
ShowWorkloadGroupsStmt showStmt = (ShowWorkloadGroupsStmt) stmt;
List<List<String>> workloadGroupsInfos = Env.getCurrentEnv().getWorkloadGroupMgr().getResourcesInfo();
PatternMatcher matcher = null;
if (showStmt.getPattern() != null) {
matcher = PatternMatcherWrapper.createMysqlPattern(showStmt.getPattern(),
CaseSensibility.WORKLOAD_GROUP.getCaseSensibility());
}
List<List<String>> workloadGroupsInfos = Env.getCurrentEnv().getWorkloadGroupMgr().getResourcesInfo(matcher);
resultSet = new ShowResultSet(showStmt.getMetaData(), workloadGroupsInfos);
}

View File

@ -28,6 +28,7 @@ import org.apache.doris.common.DdlException;
import org.apache.doris.common.ErrorCode;
import org.apache.doris.common.ErrorReport;
import org.apache.doris.common.Pair;
import org.apache.doris.common.PatternMatcher;
import org.apache.doris.common.UserException;
import org.apache.doris.common.io.Text;
import org.apache.doris.common.io.Writable;
@ -55,6 +56,7 @@ import java.io.DataOutput;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@ -413,13 +415,20 @@ public class WorkloadGroupMgr implements Writable, GsonPostProcessable {
}
}
public List<List<String>> getResourcesInfo() {
public List<List<String>> getResourcesInfo(PatternMatcher matcher) {
UserIdentity currentUserIdentity = ConnectContext.get().getCurrentUserIdentity();
return procNode.fetchResult(currentUserIdentity).getRows();
List<List<String>> rows = procNode.fetchResult(currentUserIdentity).getRows();
for (Iterator<List<String>> it = rows.iterator(); it.hasNext(); ) {
List<String> row = it.next();
if (matcher != null && !matcher.match(row.get(1))) {
it.remove();
}
}
return rows;
}
public List<List<String>> getResourcesInfo(TUserIdentity tcurrentUserIdentity) {
UserIdentity currentUserIdentity = UserIdentity.fromThrift(tcurrentUserIdentity);
public List<List<String>> getResourcesInfo(TUserIdentity tCurrentUserIdentity) {
UserIdentity currentUserIdentity = UserIdentity.fromThrift(tCurrentUserIdentity);
return procNode.fetchResult(currentUserIdentity).getRows();
}