[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:
@ -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);
|
||||
}
|
||||
|
||||
@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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(),
|
||||
|
||||
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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("/", ".")));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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,
|
||||
@ -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;
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
@ -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;
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user