[feature-wip](multi-catalog)(resubmit) add catalog level privileges (#10345)

This commit is contained in:
Ashin Gau
2022-06-23 14:10:11 +08:00
committed by GitHub
parent f466668d48
commit 6a54fc2fe5
31 changed files with 754 additions and 311 deletions

View File

@ -1365,10 +1365,13 @@ public class Analyzer {
* is already fully qualified, returns tableName.
*/
public TableName getFqTableName(TableName tableName) {
if (tableName.isFullyQualified()) {
return tableName;
if (Strings.isNullOrEmpty(tableName.getCtl())) {
tableName.setCtl(getDefaultCatalog());
}
return new TableName(getDefaultDb(), tableName.getTbl());
if (Strings.isNullOrEmpty(tableName.getDb())) {
tableName.setDb(getDefaultDb());
}
return tableName;
}
public TupleId getTupleId(SlotId slotId) {
@ -1935,6 +1938,10 @@ public class Analyzer {
return globalState.context.getConnectionId();
}
public String getDefaultCatalog() {
return globalState.context.getDefaultCatalog();
}
public String getDefaultDb() {
return globalState.context.getDatabase();
}

View File

@ -107,7 +107,7 @@ public class GrantStmt extends DdlStmt {
}
if (tblPattern != null) {
tblPattern.analyze(analyzer.getClusterName());
tblPattern.analyze(analyzer);
} else {
// TODO(wyb): spark-load
if (!Config.enable_spark_load) {
@ -148,7 +148,7 @@ public class GrantStmt extends DdlStmt {
// Rule 1
if (tblPattern.getPrivLevel() != PrivLevel.GLOBAL && (privileges.contains(PaloPrivilege.ADMIN_PRIV)
|| privileges.contains(PaloPrivilege.NODE_PRIV))) {
throw new AnalysisException("ADMIN_PRIV and NODE_PRIV can only be granted on *.*");
throw new AnalysisException("ADMIN_PRIV and NODE_PRIV can only be granted on *.*.*");
}
// Rule 2

View File

@ -97,7 +97,7 @@ public class RevokeStmt extends DdlStmt {
}
if (tblPattern != null) {
tblPattern.analyze(analyzer.getClusterName());
tblPattern.analyze(analyzer);
} else {
// TODO(wyb): spark-load
if (!Config.enable_spark_load) {

View File

@ -36,6 +36,7 @@ public class ShowRolesStmt extends ShowStmt {
builder.addColumn(new Column("Name", ScalarType.createVarchar(100)));
builder.addColumn(new Column("Users", ScalarType.createVarchar(100)));
builder.addColumn(new Column("GlobalPrivs", ScalarType.createVarchar(300)));
builder.addColumn(new Column("CatalogPrivs", ScalarType.createVarchar(300)));
builder.addColumn(new Column("DatabasePrivs", ScalarType.createVarchar(300)));
builder.addColumn(new Column("TablePrivs", ScalarType.createVarchar(300)));
builder.addColumn(new Column("ResourcePrivs", ScalarType.createVarchar(300)));

View File

@ -25,32 +25,57 @@ import org.apache.doris.cluster.ClusterNamespace;
import org.apache.doris.common.AnalysisException;
import org.apache.doris.common.ErrorCode;
import org.apache.doris.common.ErrorReport;
import org.apache.doris.common.FeMetaVersion;
import org.apache.doris.common.io.Text;
import org.apache.doris.common.io.Writable;
import org.apache.doris.datasource.InternalDataSource;
import org.apache.doris.persist.gson.GsonUtils;
import com.google.common.base.Strings;
import com.google.gson.annotations.SerializedName;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class TableName implements Writable {
@SerializedName(value = "ctl")
private String ctl;
@SerializedName(value = "tbl")
private String tbl;
@SerializedName(value = "db")
private String db;
public TableName() {
}
public TableName(String db, String tbl) {
public TableName(String ctl, String db, String tbl) {
if (Catalog.isStoredTableNamesLowerCase() && !Strings.isNullOrEmpty(tbl)) {
tbl = tbl.toLowerCase();
}
this.ctl = ctl;
this.db = db;
this.tbl = tbl;
}
/**
* Initialize catalog in analyze.
*/
public TableName(String db, String tbl) {
this(null, db, tbl);
}
public void analyze(Analyzer analyzer) throws AnalysisException {
if (Strings.isNullOrEmpty(ctl)) {
ctl = analyzer.getDefaultCatalog();
if (Strings.isNullOrEmpty(ctl)) {
ctl = InternalDataSource.INTERNAL_DS_NAME;
}
}
if (Strings.isNullOrEmpty(db)) {
db = analyzer.getDefaultDb();
if (Strings.isNullOrEmpty(db)) {
@ -68,6 +93,14 @@ public class TableName implements Writable {
}
}
public String getCtl() {
return ctl;
}
public void setCtl(String ctl) {
this.ctl = ctl;
}
public String getDb() {
return db;
}
@ -85,33 +118,30 @@ public class TableName implements Writable {
}
/**
* Returns true if this name has a non-empty database field and a non-empty
* table name.
* Returns true if this name has a non-empty catalog and a non-empty database field
* and a non-empty table name.
*/
public boolean isFullyQualified() {
return db != null && !db.isEmpty() && !tbl.isEmpty();
return Stream.of(ctl, db, tbl).noneMatch(Strings::isNullOrEmpty);
}
public String getNoClusterString() {
if (db == null) {
return tbl;
} else {
String dbName = ClusterNamespace.getNameFromFullName(db);
if (dbName == null) {
return db + "." + tbl;
} else {
return dbName + "." + tbl;
}
}
return Stream.of(ctl, ClusterNamespace.getNameFromFullName(db), tbl)
.filter(Objects::nonNull)
.collect(Collectors.joining("."));
}
@Override
public String toString() {
if (db == null) {
return tbl;
} else {
return db + "." + tbl;
StringBuilder stringBuilder = new StringBuilder();
if (ctl != null && !ctl.equals(InternalDataSource.INTERNAL_DS_NAME)) {
stringBuilder.append(ctl).append(".");
}
if (db != null) {
stringBuilder.append(db).append(".");
}
stringBuilder.append(tbl);
return stringBuilder.toString();
}
@Override
@ -127,6 +157,9 @@ public class TableName implements Writable {
public String toSql() {
StringBuilder stringBuilder = new StringBuilder();
if (ctl != null && !ctl.equals(InternalDataSource.INTERNAL_DS_NAME)) {
stringBuilder.append("`").append(ctl).append("`.");
}
if (db != null) {
stringBuilder.append("`").append(db).append("`.");
}
@ -136,17 +169,24 @@ public class TableName implements Writable {
@Override
public void write(DataOutput out) throws IOException {
Text.writeString(out, db);
Text.writeString(out, tbl);
String json = GsonUtils.GSON.toJson(this);
Text.writeString(out, json);
}
public void readFields(DataInput in) throws IOException {
db = Text.readString(in);
tbl = Text.readString(in);
if (Catalog.getCurrentCatalogJournalVersion() >= FeMetaVersion.VERSION_111) {
TableName fromJson = GsonUtils.GSON.fromJson(Text.readString(in), TableName.class);
ctl = fromJson.ctl;
db = fromJson.db;
tbl = fromJson.tbl;
} else {
ctl = InternalDataSource.INTERNAL_DS_NAME;
db = Text.readString(in);
tbl = Text.readString(in);
}
}
public TableName cloneWithoutAnalyze() {
TableName tableName = new TableName(this.db, this.tbl);
return tableName;
return new TableName(this.ctl, this.db, this.tbl);
}
}

View File

@ -17,33 +17,46 @@
package org.apache.doris.analysis;
import org.apache.doris.catalog.Catalog;
import org.apache.doris.cluster.ClusterNamespace;
import org.apache.doris.common.AnalysisException;
import org.apache.doris.common.FeMetaVersion;
import org.apache.doris.common.FeNameFormat;
import org.apache.doris.common.io.Text;
import org.apache.doris.common.io.Writable;
import org.apache.doris.datasource.InternalDataSource;
import org.apache.doris.mysql.privilege.PaloAuth.PrivLevel;
import org.apache.doris.persist.gson.GsonUtils;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import com.google.gson.annotations.SerializedName;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.Stream;
// only the following 3 formats are allowed
// db.tbl
// *.*
// db.*
/**
* Three-segment-format: catalog.database.table. If the lower segment is specific,
* the higher segment can't be a wildcard. The following examples are not allowed:
* "ctl1.*.table1", "*.*.table2", "*.db1.*", ...
*/
public class TablePattern implements Writable {
@SerializedName(value = "ctl")
private String ctl;
@SerializedName(value = "db")
private String db;
@SerializedName(value = "tbl")
private String tbl;
boolean isAnalyzed = false;
public static TablePattern ALL;
static {
ALL = new TablePattern("*", "*");
ALL = new TablePattern("*", "*", "*");
try {
ALL.analyze("");
} catch (AnalysisException e) {
@ -54,11 +67,23 @@ public class TablePattern implements Writable {
private TablePattern() {
}
public TablePattern(String db, String tbl) {
public TablePattern(String ctl, String db, String tbl) {
this.ctl = Strings.isNullOrEmpty(ctl) ? "*" : ctl;
this.db = Strings.isNullOrEmpty(db) ? "*" : db;
this.tbl = Strings.isNullOrEmpty(tbl) ? "*" : tbl;
}
public TablePattern(String db, String tbl) {
this.ctl = null;
this.db = Strings.isNullOrEmpty(db) ? "*" : db;
this.tbl = Strings.isNullOrEmpty(tbl) ? "*" : tbl;
}
public String getQualifiedCtl() {
Preconditions.checkState(isAnalyzed);
return ctl;
}
public String getQualifiedDb() {
Preconditions.checkState(isAnalyzed);
return db;
@ -70,23 +95,39 @@ public class TablePattern implements Writable {
public PrivLevel getPrivLevel() {
Preconditions.checkState(isAnalyzed);
if (db.equals("*")) {
if (ctl.equals("*")) {
return PrivLevel.GLOBAL;
} else if (!tbl.equals("*")) {
return PrivLevel.TABLE;
} else {
} else if (db.equals("*")) {
return PrivLevel.CATALOG;
} else if (tbl.equals("*")) {
return PrivLevel.DATABASE;
} else {
return PrivLevel.TABLE;
}
}
public void analyze(String clusterName) throws AnalysisException {
public void analyze(Analyzer analyzer) throws AnalysisException {
if (ctl == null) {
analyze(analyzer.getDefaultCatalog(), analyzer.getClusterName());
} else {
analyze(analyzer.getClusterName());
}
}
private void analyze(String catalogName, String clusterName) throws AnalysisException {
if (isAnalyzed) {
return;
}
if (db.equals("*") && !tbl.equals("*")) {
this.ctl = Strings.isNullOrEmpty(catalogName) ? InternalDataSource.INTERNAL_DS_NAME : catalogName;
if ((!tbl.equals("*") && (db.equals("*") || ctl.equals("*")))
|| (!db.equals("*") && ctl.equals("*"))) {
throw new AnalysisException("Do not support format: " + toString());
}
if (!ctl.equals("*")) {
FeNameFormat.checkCatalogName(ctl);
}
if (!db.equals("*")) {
FeNameFormat.checkDbName(db);
db = ClusterNamespace.getFullName(clusterName, db);
@ -98,9 +139,21 @@ public class TablePattern implements Writable {
isAnalyzed = true;
}
public void analyze(String clusterName) throws AnalysisException {
analyze(ctl, clusterName);
}
public static TablePattern read(DataInput in) throws IOException {
TablePattern tablePattern = new TablePattern();
tablePattern.readFields(in);
TablePattern tablePattern;
if (Catalog.getCurrentCatalogJournalVersion() >= FeMetaVersion.VERSION_111) {
tablePattern = GsonUtils.GSON.fromJson(Text.readString(in), TablePattern.class);
} else {
String ctl = InternalDataSource.INTERNAL_DS_NAME;
String db = Text.readString(in);
String tbl = Text.readString(in);
tablePattern = new TablePattern(ctl, db, tbl);
}
tablePattern.isAnalyzed = true;
return tablePattern;
}
@ -110,34 +163,25 @@ public class TablePattern implements Writable {
return false;
}
TablePattern other = (TablePattern) obj;
return db.equals(other.getQualifiedDb()) && tbl.equals(other.getTbl());
return ctl.equals(other.getQualifiedCtl()) && db.equals(other.getQualifiedDb()) && tbl.equals(other.getTbl());
}
@Override
public int hashCode() {
int result = 17;
result = 31 * result + db.hashCode();
result = 31 * result + tbl.hashCode();
return result;
return Stream.of(ctl, db, tbl).filter(Objects::nonNull)
.map(String::hashCode)
.reduce(17, (acc, h) -> 31 * acc + h);
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(db).append(".").append(tbl);
return sb.toString();
return Stream.of(ctl, db, tbl).filter(Objects::nonNull).collect(Collectors.joining("."));
}
@Override
public void write(DataOutput out) throws IOException {
Preconditions.checkState(isAnalyzed);
Text.writeString(out, db);
Text.writeString(out, tbl);
}
public void readFields(DataInput in) throws IOException {
db = Text.readString(in);
tbl = Text.readString(in);
isAnalyzed = true;
String json = GsonUtils.GSON.toJson(this);
Text.writeString(out, json);
}
}

View File

@ -22,6 +22,7 @@ package org.apache.doris.common;
**/
public enum CaseSensibility {
CLUSTER(true),
CATALOG(true),
DATABASE(true),
TABLE(true),
ROLLUP(true),

View File

@ -1686,7 +1686,7 @@ public enum ErrorCode {
+ "Use `SHOW PARTITIONS FROM %s` to see the currently partitions of this table. "),
ERROR_SQL_AND_LIMITATIONS_SET_IN_ONE_RULE(5084, new byte[]{'4', '2', '0', '0', '0'},
"sql/sqlHash and partition_num/tablet_num/cardinality cannot be set in one rule."),
;
ERR_WRONG_CATALOG_NAME(5085, new byte[]{'4', '2', '0', '0', '0'}, "Incorrect catalog name '%s'");
// This is error code
private final int code;

View File

@ -18,6 +18,7 @@
package org.apache.doris.common;
import org.apache.doris.alter.SchemaChangeHandler;
import org.apache.doris.datasource.InternalDataSource;
import org.apache.doris.mysql.privilege.PaloRole;
import org.apache.doris.system.SystemInfoService;
@ -42,6 +43,13 @@ public class FeNameFormat {
}
}
public static void checkCatalogName(String catalogName) throws AnalysisException {
if (!InternalDataSource.INTERNAL_DS_NAME.equals(catalogName)
&& (Strings.isNullOrEmpty(catalogName) || !catalogName.matches(COMMON_NAME_REGEX))) {
ErrorReport.reportAnalysisException(ErrorCode.ERR_WRONG_CATALOG_NAME, catalogName);
}
}
public static void checkDbName(String dbName) throws AnalysisException {
if (Strings.isNullOrEmpty(dbName) || !dbName.matches(COMMON_NAME_REGEX)) {
ErrorReport.reportAnalysisException(ErrorCode.ERR_WRONG_DB_NAME, dbName);

View File

@ -31,8 +31,8 @@ import com.google.common.collect.ImmutableList;
*/
public class AuthProcDir implements ProcDirInterface {
public static final ImmutableList<String> TITLE_NAMES = new ImmutableList.Builder<String>()
.add("UserIdentity").add("Password").add("GlobalPrivs").add("DatabasePrivs")
.add("TablePrivs").add("ResourcePrivs").build();
.add("UserIdentity").add("Password").add("GlobalPrivs").add("CatalogPrivs")
.add("DatabasePrivs").add("TablePrivs").add("ResourcePrivs").build();
private PaloAuth auth;

View File

@ -0,0 +1,143 @@
// 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.catalog.Catalog;
import org.apache.doris.common.AnalysisException;
import org.apache.doris.common.CaseSensibility;
import org.apache.doris.common.FeMetaVersion;
import org.apache.doris.common.PatternMatcher;
import org.apache.doris.common.io.Text;
import org.apache.doris.datasource.InternalDataSource;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
public class CatalogPrivEntry extends PrivEntry {
protected static final String ANY_CTL = "*";
protected PatternMatcher ctlPattern;
protected String origCtl;
protected boolean isAnyCtl;
protected CatalogPrivEntry() {
}
protected CatalogPrivEntry(PatternMatcher userPattern, String user,
PatternMatcher hostPattern, String origHost,
PatternMatcher ctlPattern, String origCtl,
boolean isDomain, PrivBitSet privSet) {
super(hostPattern, origHost, userPattern, user, isDomain, privSet);
this.ctlPattern = ctlPattern;
this.origCtl = origCtl;
if (origCtl.equals(ANY_CTL)) {
isAnyCtl = true;
}
}
public static CatalogPrivEntry create(String user, String host, String ctl, boolean isDomain, PrivBitSet privs)
throws AnalysisException {
PatternMatcher hostPattern = PatternMatcher.createMysqlPattern(host, CaseSensibility.HOST.getCaseSensibility());
PatternMatcher ctlPattern = createCtlPatternMatcher(ctl);
PatternMatcher userPattern = PatternMatcher.createFlatPattern(user, CaseSensibility.USER.getCaseSensibility());
if (privs.containsNodePriv() || privs.containsResourcePriv()) {
throw new AnalysisException("Datasource privilege can not contains node or resource privileges: " + privs);
}
return new CatalogPrivEntry(userPattern, user, hostPattern, host, ctlPattern, ctl, isDomain, privs);
}
private static PatternMatcher createCtlPatternMatcher(String ctl) throws AnalysisException {
boolean ctlCaseSensibility = CaseSensibility.CATALOG.getCaseSensibility();
return PatternMatcher.createFlatPattern(ctl, ctlCaseSensibility, ctl.equals(ANY_CTL));
}
public PatternMatcher getCtlPattern() {
return ctlPattern;
}
public String getOrigCtl() {
return origCtl;
}
public boolean isAnyCtl() {
return isAnyCtl;
}
@Override
public int compareTo(PrivEntry other) {
if (!(other instanceof CatalogPrivEntry)) {
throw new ClassCastException("cannot cast " + other.getClass().toString() + " to " + this.getClass());
}
CatalogPrivEntry otherEntry = (CatalogPrivEntry) other;
return compareAssist(origUser, otherEntry.origUser,
origHost, otherEntry.origHost,
origCtl, otherEntry.origCtl);
}
@Override
public boolean keyMatch(PrivEntry other) {
if (!(other instanceof CatalogPrivEntry)) {
return false;
}
CatalogPrivEntry otherEntry = (CatalogPrivEntry) other;
return origUser.equals(otherEntry.origUser) && origHost.equals(otherEntry.origHost)
&& origCtl.equals(otherEntry.origCtl) && isDomain == otherEntry.isDomain;
}
@Override
public String toString() {
return String.format("catalog privilege. user: %s, host: %s, ctl: %s, priv: %s, set by resolver: %b",
origUser, origHost, origCtl, privSet.toString(), isSetByDomainResolver);
}
@Override
public void write(DataOutput out) throws IOException {
if (!isClassNameWrote) {
String className = CatalogPrivEntry.class.getCanonicalName();
Text.writeString(out, className);
isClassNameWrote = true;
}
super.write(out);
Text.writeString(out, origCtl);
isClassNameWrote = false;
}
public void readFields(DataInput in) throws IOException {
super.readFields(in);
if (Catalog.getCurrentCatalogJournalVersion() >= FeMetaVersion.VERSION_111) {
origCtl = Text.readString(in);
} else {
origCtl = InternalDataSource.INTERNAL_DS_NAME;
}
try {
ctlPattern = createCtlPatternMatcher(origCtl);
} catch (AnalysisException e) {
throw new IOException(e);
}
isAnyCtl = origCtl.equals(ANY_CTL);
}
}

View File

@ -0,0 +1,73 @@
// 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.common.io.Text;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.DataOutput;
import java.io.IOException;
/*
* CatalogPrivTable saves all catalog level privs
*/
public class CatalogPrivTable extends PrivTable {
private static final Logger LOG = LogManager.getLogger(CatalogPrivTable.class);
/*
* Return first priv which match the user@host on ctl.* The returned priv will be
* saved in 'savedPrivs'.
*/
public void getPrivs(UserIdentity currentUser, String ctl, PrivBitSet savedPrivs) {
CatalogPrivEntry matchedEntry = null;
for (PrivEntry entry : entries) {
CatalogPrivEntry dsPrivEntry = (CatalogPrivEntry) entry;
if (!dsPrivEntry.match(currentUser, true)) {
continue;
}
// check catalog
if (!dsPrivEntry.isAnyCtl() && !dsPrivEntry.getCtlPattern().match(ctl)) {
continue;
}
matchedEntry = dsPrivEntry;
break;
}
if (matchedEntry == null) {
return;
}
savedPrivs.or(matchedEntry.getPrivSet());
}
@Override
public void write(DataOutput out) throws IOException {
if (!isClassNameWrote) {
String className = CatalogPrivTable.class.getCanonicalName();
Text.writeString(out, className);
isClassNameWrote = true;
}
super.write(out);
}
}

View File

@ -28,7 +28,7 @@ import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
public class DbPrivEntry extends PrivEntry {
public class DbPrivEntry extends CatalogPrivEntry {
protected static final String ANY_DB = "*";
protected PatternMatcher dbPattern;
@ -38,9 +38,12 @@ public class DbPrivEntry extends PrivEntry {
protected DbPrivEntry() {
}
protected DbPrivEntry(PatternMatcher hostPattern, String origHost, PatternMatcher dbPattern, String origDb,
PatternMatcher userPattern, String user, boolean isDomain, PrivBitSet privSet) {
super(hostPattern, origHost, userPattern, user, isDomain, privSet);
protected DbPrivEntry(PatternMatcher userPattern, String user,
PatternMatcher hostPattern, String origHost,
PatternMatcher ctlPattern, String origCtl,
PatternMatcher dbPattern, String origDb,
boolean isDomain, PrivBitSet privSet) {
super(userPattern, user, hostPattern, origHost, ctlPattern, origCtl, isDomain, privSet);
this.dbPattern = dbPattern;
this.origDb = origDb;
if (origDb.equals(ANY_DB)) {
@ -48,10 +51,15 @@ public class DbPrivEntry extends PrivEntry {
}
}
public static DbPrivEntry create(String host, String db, String user, boolean isDomain, PrivBitSet privs)
throws AnalysisException {
public static DbPrivEntry create(
String user, String host,
String ctl, String db,
boolean isDomain, PrivBitSet privs) throws AnalysisException {
PatternMatcher hostPattern = PatternMatcher.createMysqlPattern(host, CaseSensibility.HOST.getCaseSensibility());
PatternMatcher ctlPattern = PatternMatcher.createFlatPattern(
ctl, CaseSensibility.CATALOG.getCaseSensibility(), ctl.equals(ANY_CTL));
PatternMatcher dbPattern = createDbPatternMatcher(db);
PatternMatcher userPattern = PatternMatcher.createFlatPattern(user, CaseSensibility.USER.getCaseSensibility());
@ -60,7 +68,7 @@ public class DbPrivEntry extends PrivEntry {
throw new AnalysisException("Db privilege can not contains global or resource privileges: " + privs);
}
return new DbPrivEntry(hostPattern, host, dbPattern, db, userPattern, user, isDomain, privs);
return new DbPrivEntry(userPattern, user, hostPattern, host, ctlPattern, ctl, dbPattern, db, isDomain, privs);
}
private static PatternMatcher createDbPatternMatcher(String db) throws AnalysisException {
@ -92,17 +100,10 @@ public class DbPrivEntry extends PrivEntry {
}
DbPrivEntry otherEntry = (DbPrivEntry) other;
int res = origHost.compareTo(otherEntry.origHost);
if (res != 0) {
return -res;
}
res = origDb.compareTo(otherEntry.origDb);
if (res != 0) {
return -res;
}
return -origUser.compareTo(otherEntry.origUser);
return compareAssist(origUser, otherEntry.origUser,
origHost, otherEntry.origHost,
origCtl, otherEntry.origCtl,
origDb, otherEntry.origDb);
}
@Override
@ -112,20 +113,15 @@ public class DbPrivEntry extends PrivEntry {
}
DbPrivEntry otherEntry = (DbPrivEntry) other;
if (origHost.equals(otherEntry.origHost) && origUser.equals(otherEntry.origUser)
&& origDb.equals(otherEntry.origDb) && isDomain == otherEntry.isDomain) {
return true;
}
return false;
return origUser.equals(otherEntry.origUser) && origHost.equals(otherEntry.origHost)
&& origCtl.equals(otherEntry.origCtl) && origDb.equals(otherEntry.origDb)
&& isDomain == otherEntry.isDomain;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("db priv. host: ").append(origHost).append(", db: ").append(origDb);
sb.append(", user: ").append(origUser);
sb.append(", priv: ").append(privSet).append(", set by resolver: ").append(isSetByDomainResolver);
return sb.toString();
return String.format("database privilege. user: %s, host: %s, ctl: %s, db: %s, priv: %s, set by resolver: %b",
origUser, origHost, origCtl, origDb, privSet.toString(), isSetByDomainResolver);
}
@Override

View File

@ -34,10 +34,10 @@ public class DbPrivTable extends PrivTable {
private static final Logger LOG = LogManager.getLogger(DbPrivTable.class);
/*
* Return first priv which match the user@host on db.* The returned priv will be
* Return first priv which match the user@host on ctl.db.* The returned priv will be
* saved in 'savedPrivs'.
*/
public void getPrivs(UserIdentity currentUser, String db, PrivBitSet savedPrivs) {
public void getPrivs(UserIdentity currentUser, String ctl, String db, PrivBitSet savedPrivs) {
DbPrivEntry matchedEntry = null;
for (PrivEntry entry : entries) {
DbPrivEntry dbPrivEntry = (DbPrivEntry) entry;
@ -46,6 +46,11 @@ public class DbPrivTable extends PrivTable {
continue;
}
// check catalog
if (!dbPrivEntry.isAnyCtl() && !dbPrivEntry.getCtlPattern().match(ctl)) {
continue;
}
// check db
if (!dbPrivEntry.isAnyDb() && !dbPrivEntry.getDbPattern().match(db)) {
continue;
@ -61,28 +66,6 @@ public class DbPrivTable extends PrivTable {
savedPrivs.or(matchedEntry.getPrivSet());
}
/*
* Check if user@host has specified privilege on any database
*/
public boolean hasPriv(String host, String user, PrivPredicate wanted) {
for (PrivEntry entry : entries) {
DbPrivEntry dbPrivEntry = (DbPrivEntry) entry;
// check host
if (!dbPrivEntry.isAnyHost() && !dbPrivEntry.getHostPattern().match(host)) {
continue;
}
// check user
if (!dbPrivEntry.isAnyUser() && !dbPrivEntry.getUserPattern().match(user)) {
continue;
}
// check priv
if (dbPrivEntry.privSet.satisfy(wanted)) {
return true;
}
}
return false;
}
public boolean hasClusterPriv(ConnectContext ctx, String clusterName) {
for (PrivEntry entry : entries) {
DbPrivEntry dbPrivEntry = (DbPrivEntry) entry;

View File

@ -27,6 +27,7 @@ import org.apache.doris.analysis.RevokeStmt;
import org.apache.doris.analysis.SetLdapPassVar;
import org.apache.doris.analysis.SetPassVar;
import org.apache.doris.analysis.SetUserPropertyStmt;
import org.apache.doris.analysis.TableName;
import org.apache.doris.analysis.TablePattern;
import org.apache.doris.analysis.UserIdentity;
import org.apache.doris.catalog.AuthorizationInfo;
@ -42,6 +43,7 @@ import org.apache.doris.common.LdapConfig;
import org.apache.doris.common.Pair;
import org.apache.doris.common.UserException;
import org.apache.doris.common.io.Writable;
import org.apache.doris.datasource.InternalDataSource;
import org.apache.doris.ldap.LdapPrivsChecker;
import org.apache.doris.load.DppConfig;
import org.apache.doris.persist.LdapInfo;
@ -53,6 +55,7 @@ import org.apache.doris.thrift.TPrivilegeStatus;
import com.google.common.base.Joiner;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import org.apache.logging.log4j.LogManager;
@ -65,6 +68,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.stream.Collectors;
public class PaloAuth implements Writable {
private static final Logger LOG = LogManager.getLogger(PaloAuth.class);
@ -75,8 +79,10 @@ public class PaloAuth implements Writable {
public static final String ADMIN_USER = "admin";
// unknown user does not have any privilege, this is just to be compatible with old version.
public static final String UNKNOWN_USER = "unknown";
private static final String DEFAULT_CATALOG = InternalDataSource.INTERNAL_DS_NAME;
private UserPrivTable userPrivTable = new UserPrivTable();
private CatalogPrivTable catalogPrivTable = new CatalogPrivTable();
private DbPrivTable dbPrivTable = new DbPrivTable();
private TablePrivTable tablePrivTable = new TablePrivTable();
private ResourcePrivTable resourcePrivTable = new ResourcePrivTable();
@ -105,7 +111,7 @@ public class PaloAuth implements Writable {
}
public enum PrivLevel {
GLOBAL, DATABASE, TABLE, RESOURCE
GLOBAL, CATALOG, DATABASE, TABLE, RESOURCE
}
public PaloAuth() {
@ -165,12 +171,39 @@ public class PaloAuth implements Writable {
false /* not delete entry if priv is empty, because global priv entry has password */);
}
private void grantDbPrivs(UserIdentity userIdentity, String db, boolean errOnExist, boolean errOnNonExist,
PrivBitSet privs) throws DdlException {
private void grantCatalogPrivs(UserIdentity userIdentity, String ctl,
boolean errOnExist, boolean errOnNonExist, PrivBitSet privs) throws DdlException {
CatalogPrivEntry entry;
try {
entry = CatalogPrivEntry.create(userIdentity.getQualifiedUser(), userIdentity.getHost(),
ctl, userIdentity.isDomain(), privs);
entry.setSetByDomainResolver(false);
} catch (AnalysisException e) {
throw new DdlException(e.getMessage());
}
catalogPrivTable.addEntry(entry, errOnExist, errOnNonExist);
}
private void revokeCatalogPrivs(UserIdentity userIdentity, String ctl,
PrivBitSet privs, boolean errOnNonExist) throws DdlException {
CatalogPrivEntry entry;
try {
entry = CatalogPrivEntry.create(userIdentity.getQualifiedUser(), userIdentity.getHost(),
ctl, userIdentity.isDomain(), privs);
entry.setSetByDomainResolver(false);
} catch (AnalysisException e) {
throw new DdlException(e.getMessage());
}
catalogPrivTable.revoke(entry, errOnNonExist, true /* delete entry when empty */);
}
private void grantDbPrivs(UserIdentity userIdentity, String ctl, String db,
boolean errOnExist, boolean errOnNonExist, PrivBitSet privs) throws DdlException {
DbPrivEntry entry;
try {
entry = DbPrivEntry.create(userIdentity.getHost(), db, userIdentity.getQualifiedUser(),
userIdentity.isDomain(), privs);
entry = DbPrivEntry.create(userIdentity.getQualifiedUser(), userIdentity.getHost(),
ctl, db, userIdentity.isDomain(), privs);
entry.setSetByDomainResolver(false);
} catch (AnalysisException e) {
throw new DdlException(e.getMessage());
@ -178,12 +211,12 @@ public class PaloAuth implements Writable {
dbPrivTable.addEntry(entry, errOnExist, errOnNonExist);
}
private void revokeDbPrivs(UserIdentity userIdentity, String db, PrivBitSet privs, boolean errOnNonExist)
throws DdlException {
private void revokeDbPrivs(UserIdentity userIdentity, String ctl, String db,
PrivBitSet privs, boolean errOnNonExist) throws DdlException {
DbPrivEntry entry;
try {
entry = DbPrivEntry.create(userIdentity.getHost(), db, userIdentity.getQualifiedUser(),
userIdentity.isDomain(), privs);
entry = DbPrivEntry.create(userIdentity.getQualifiedUser(), userIdentity.getHost(),
ctl, db, userIdentity.isDomain(), privs);
entry.setSetByDomainResolver(false);
} catch (AnalysisException e) {
throw new DdlException(e.getMessage());
@ -192,12 +225,12 @@ public class PaloAuth implements Writable {
dbPrivTable.revoke(entry, errOnNonExist, true /* delete entry when empty */);
}
private void grantTblPrivs(UserIdentity userIdentity, String db, String tbl, boolean errOnExist,
boolean errOnNonExist, PrivBitSet privs) throws DdlException {
private void grantTblPrivs(UserIdentity userIdentity, String ctl, String db, String tbl,
boolean errOnExist, boolean errOnNonExist, PrivBitSet privs) throws DdlException {
TablePrivEntry entry;
try {
entry = TablePrivEntry.create(userIdentity.getHost(), db, userIdentity.getQualifiedUser(), tbl,
userIdentity.isDomain(), privs);
entry = TablePrivEntry.create(userIdentity.getQualifiedUser(), userIdentity.getHost(),
ctl, db, tbl, userIdentity.isDomain(), privs);
entry.setSetByDomainResolver(false);
} catch (AnalysisException e) {
throw new DdlException(e.getMessage());
@ -205,12 +238,12 @@ public class PaloAuth implements Writable {
tablePrivTable.addEntry(entry, errOnExist, errOnNonExist);
}
private void revokeTblPrivs(UserIdentity userIdentity, String db, String tbl, PrivBitSet privs,
boolean errOnNonExist) throws DdlException {
private void revokeTblPrivs(UserIdentity userIdentity, String ctl, String db, String tbl,
PrivBitSet privs, boolean errOnNonExist) throws DdlException {
TablePrivEntry entry;
try {
entry = TablePrivEntry.create(userIdentity.getHost(), db, userIdentity.getQualifiedUser(), tbl,
userIdentity.isDomain(), privs);
entry = TablePrivEntry.create(userIdentity.getQualifiedUser(), userIdentity.getHost(),
ctl, db, tbl, userIdentity.isDomain(), privs);
entry.setSetByDomainResolver(false);
} catch (AnalysisException e) {
throw new DdlException(e.getMessage());
@ -324,11 +357,15 @@ public class PaloAuth implements Writable {
return checkDbPriv(ctx.getCurrentUserIdentity(), qualifiedDb, wanted);
}
public boolean checkDbPriv(UserIdentity currentUser, String db, PrivPredicate wanted) {
return checkDbPriv(currentUser, DEFAULT_CATALOG, db, wanted);
}
/*
* Check if 'user'@'host' on 'db' has 'wanted' priv.
* If the given db is null, which means it will no check if database name is matched.
*/
public boolean checkDbPriv(UserIdentity currentUser, String db, PrivPredicate wanted) {
public boolean checkDbPriv(UserIdentity currentUser, String ctl, String db, PrivPredicate wanted) {
if (!Config.enable_auth_check) {
return true;
}
@ -340,12 +377,13 @@ public class PaloAuth implements Writable {
PrivBitSet savedPrivs = PrivBitSet.of();
if (checkGlobalInternal(currentUser, wanted, savedPrivs)
|| checkDbInternal(currentUser, db, wanted, savedPrivs)) {
|| checkCatalogInternal(currentUser, ctl, wanted, savedPrivs)
|| checkDbInternal(currentUser, ctl, db, wanted, savedPrivs)) {
return true;
}
// if user has any privs of table in this db, and the wanted priv is SHOW, return true
if (db != null && wanted == PrivPredicate.SHOW && checkTblWithDb(currentUser, db)) {
if (ctl != null && db != null && wanted == PrivPredicate.SHOW && checkTblWithDb(currentUser, ctl, db)) {
return true;
}
@ -358,21 +396,31 @@ public class PaloAuth implements Writable {
* So we have to check if user has any privs of tables in this database.
* if so, the database should be visible to this user.
*/
private boolean checkTblWithDb(UserIdentity currentUser, String db) {
private boolean checkTblWithDb(UserIdentity currentUser, String ctl, String db) {
readLock();
try {
return (isLdapAuthEnabled() && LdapPrivsChecker.hasPrivsOfDb(currentUser, db))
|| tablePrivTable.hasPrivsOfDb(currentUser, db);
|| tablePrivTable.hasPrivsOfDb(currentUser, ctl, db);
} finally {
readUnlock();
}
}
public boolean checkTblPriv(ConnectContext ctx, String qualifiedDb, String tbl, PrivPredicate wanted) {
return checkTblPriv(ctx.getCurrentUserIdentity(), qualifiedDb, tbl, wanted);
public boolean checkTblPriv(ConnectContext ctx, String qualifiedCtl,
String qualifiedDb, String tbl, PrivPredicate wanted) {
return checkTblPriv(ctx.getCurrentUserIdentity(), qualifiedCtl, qualifiedDb, tbl, wanted);
}
public boolean checkTblPriv(UserIdentity currentUser, String db, String tbl, PrivPredicate wanted) {
public boolean checkTblPriv(ConnectContext ctx, String qualifiedDb, String tbl, PrivPredicate wanted) {
return checkTblPriv(ctx, DEFAULT_CATALOG, qualifiedDb, tbl, wanted);
}
public boolean checkTblPriv(ConnectContext ctx, TableName tableName, PrivPredicate wanted) {
Preconditions.checkState(tableName.isFullyQualified());
return checkTblPriv(ctx, tableName.getCtl(), tableName.getDb(), wanted);
}
public boolean checkTblPriv(UserIdentity currentUser, String ctl, String db, String tbl, PrivPredicate wanted) {
if (!Config.enable_auth_check) {
return true;
}
@ -383,8 +431,9 @@ public class PaloAuth implements Writable {
PrivBitSet savedPrivs = PrivBitSet.of();
if (checkGlobalInternal(currentUser, wanted, savedPrivs)
|| checkDbInternal(currentUser, db, wanted, savedPrivs)
|| checkTblInternal(currentUser, db, tbl, wanted, savedPrivs)) {
|| checkCatalogInternal(currentUser, ctl, wanted, savedPrivs)
|| checkDbInternal(currentUser, ctl, db, wanted, savedPrivs)
|| checkTblInternal(currentUser, ctl, db, tbl, wanted, savedPrivs)) {
return true;
}
@ -392,6 +441,10 @@ public class PaloAuth implements Writable {
return false;
}
public boolean checkTblPriv(UserIdentity currentUser, String db, String tbl, PrivPredicate wanted) {
return checkTblPriv(currentUser, DEFAULT_CATALOG, db, tbl, wanted);
}
public boolean checkResourcePriv(ConnectContext ctx, String resourceName, PrivPredicate wanted) {
return checkResourcePriv(ctx.getCurrentUserIdentity(), resourceName, wanted);
}
@ -485,15 +538,12 @@ public class PaloAuth implements Writable {
}
}
private boolean checkDbInternal(UserIdentity currentUser, String db, PrivPredicate wanted,
PrivBitSet savedPrivs) {
if (isLdapAuthEnabled() && LdapPrivsChecker.hasDbPrivFromLdap(currentUser, db, wanted)) {
return true;
}
private boolean checkCatalogInternal(UserIdentity currentUser, String ctl,
PrivPredicate wanted, PrivBitSet savedPrivs) {
// TODO(gaoxin): check privileges by ldap.
readLock();
try {
dbPrivTable.getPrivs(currentUser, db, savedPrivs);
catalogPrivTable.getPrivs(currentUser, ctl, savedPrivs);
if (PaloPrivilege.satisfy(savedPrivs, wanted)) {
return true;
}
@ -503,7 +553,25 @@ public class PaloAuth implements Writable {
return false;
}
private boolean checkTblInternal(UserIdentity currentUser, String db, String tbl,
private boolean checkDbInternal(UserIdentity currentUser, String ctl, String db, PrivPredicate wanted,
PrivBitSet savedPrivs) {
if (isLdapAuthEnabled() && LdapPrivsChecker.hasDbPrivFromLdap(currentUser, db, wanted)) {
return true;
}
readLock();
try {
dbPrivTable.getPrivs(currentUser, ctl, db, savedPrivs);
if (PaloPrivilege.satisfy(savedPrivs, wanted)) {
return true;
}
} finally {
readUnlock();
}
return false;
}
private boolean checkTblInternal(UserIdentity currentUser, String ctl, String db, String tbl,
PrivPredicate wanted, PrivBitSet savedPrivs) {
if (isLdapAuthEnabled() && LdapPrivsChecker.hasTblPrivFromLdap(currentUser, db, tbl, wanted)) {
return true;
@ -511,7 +579,7 @@ public class PaloAuth implements Writable {
readLock();
try {
tablePrivTable.getPrivs(currentUser, db, tbl, savedPrivs);
tablePrivTable.getPrivs(currentUser, ctl, db, tbl, savedPrivs);
if (PaloPrivilege.satisfy(savedPrivs, wanted)) {
return true;
}
@ -607,7 +675,7 @@ public class PaloAuth implements Writable {
if (!userIdent.getQualifiedUser().equals(ROOT_USER) && !userIdent.getQualifiedUser().equals(ADMIN_USER)) {
// grant read privs to database information_schema
TablePattern tblPattern = new TablePattern(InfoSchemaDb.DATABASE_NAME, "*");
TablePattern tblPattern = new TablePattern(DEFAULT_CATALOG, InfoSchemaDb.DATABASE_NAME, "*");
try {
tblPattern.analyze(ClusterNamespace.getClusterNameFromFullName(userIdent.getQualifiedUser()));
} catch (AnalysisException e) {
@ -681,6 +749,7 @@ public class PaloAuth implements Writable {
// we don't check if user exists
userPrivTable.dropUser(userIdent);
catalogPrivTable.dropUser(userIdent);
dbPrivTable.dropUser(userIdent);
tablePrivTable.dropUser(userIdent);
resourcePrivTable.dropUser(userIdent);
@ -815,14 +884,22 @@ public class PaloAuth implements Writable {
errOnNonExist,
privs);
break;
case CATALOG:
grantCatalogPrivs(userIdent, tblPattern.getQualifiedCtl(),
false /* err on exist */,
false /* err on non exist */,
privs);
break;
case DATABASE:
grantDbPrivs(userIdent, tblPattern.getQualifiedDb(),
grantDbPrivs(userIdent, tblPattern.getQualifiedCtl(),
tblPattern.getQualifiedDb(),
false /* err on exist */,
false /* err on non exist */,
privs);
break;
case TABLE:
grantTblPrivs(userIdent, tblPattern.getQualifiedDb(),
grantTblPrivs(userIdent, tblPattern.getQualifiedCtl(),
tblPattern.getQualifiedDb(),
tblPattern.getTbl(),
false /* err on exist */,
false /* err on non exist */,
@ -971,12 +1048,16 @@ public class PaloAuth implements Writable {
case GLOBAL:
revokeGlobalPrivs(userIdent, privs, errOnNonExist);
break;
case CATALOG:
revokeCatalogPrivs(userIdent, tblPattern.getQualifiedCtl(), privs, errOnNonExist);
break;
case DATABASE:
revokeDbPrivs(userIdent, tblPattern.getQualifiedDb(), privs, errOnNonExist);
revokeDbPrivs(userIdent, tblPattern.getQualifiedCtl(),
tblPattern.getQualifiedDb(), privs, errOnNonExist);
break;
case TABLE:
revokeTblPrivs(userIdent, tblPattern.getQualifiedDb(), tblPattern.getTbl(), privs,
errOnNonExist);
revokeTblPrivs(userIdent, tblPattern.getQualifiedCtl(), tblPattern.getQualifiedDb(),
tblPattern.getTbl(), privs, errOnNonExist);
break;
default:
Preconditions.checkNotNull(null, tblPattern.getPrivLevel());
@ -1311,6 +1392,17 @@ public class PaloAuth implements Writable {
}
}
// catalog
String ctlPrivs = catalogPrivTable.entries.stream()
.filter(entry -> entry.match(userIdent, true))
.map(entry -> String.format("%s: %s (%b)",
((CatalogPrivEntry) entry).getOrigCtl(), entry.privSet, entry.isSetByDomainResolver()))
.collect(Collectors.joining("; "));
if (Strings.isNullOrEmpty(ctlPrivs)) {
ctlPrivs = FeConstants.null_string;
}
userAuthInfo.add(ctlPrivs);
// db
List<String> dbPrivs = Lists.newArrayList();
Set<String> addedDbs = Sets.newHashSet();
@ -1326,16 +1418,16 @@ public class PaloAuth implements Writable {
PrivBitSet savedPrivs = dEntry.getPrivSet().copy();
savedPrivs.or(LdapPrivsChecker.getDbPrivFromLdap(userIdent, dEntry.getOrigDb()));
addedDbs.add(dEntry.getOrigDb());
dbPrivs.add(dEntry.getOrigDb() + ": " + savedPrivs.toString()
+ " (" + entry.isSetByDomainResolver() + ")");
dbPrivs.add(String.format("%s.%s: %s (%b)", dEntry.getOrigCtl(), dEntry.getOrigDb(),
savedPrivs, dEntry.isSetByDomainResolver()));
}
// Add privs from ldap groups that have not been added in Doris.
if (LdapPrivsChecker.hasLdapPrivs(userIdent)) {
Map<TablePattern, PrivBitSet> ldapDbPrivs = LdapPrivsChecker.getLdapAllDbPrivs(userIdent);
for (Map.Entry<TablePattern, PrivBitSet> entry : ldapDbPrivs.entrySet()) {
if (!addedDbs.contains(entry.getKey().getQualifiedDb())) {
dbPrivs.add(entry.getKey().getQualifiedDb() + ": "
+ entry.getValue().toString() + " (" + false + ")");
dbPrivs.add(String.format("%s.%s: %s (%b)", entry.getKey().getQualifiedCtl(),
entry.getKey().getQualifiedDb(), entry.getValue(), false));
}
}
}
@ -1361,17 +1453,15 @@ public class PaloAuth implements Writable {
PrivBitSet savedPrivs = tEntry.getPrivSet().copy();
savedPrivs.or(LdapPrivsChecker.getTblPrivFromLdap(userIdent, tEntry.getOrigDb(), tEntry.getOrigTbl()));
addedtbls.add(tEntry.getOrigDb().concat(".").concat(tEntry.getOrigTbl()));
tblPrivs.add(tEntry.getOrigDb() + "." + tEntry.getOrigTbl() + ": "
+ savedPrivs.toString()
+ " (" + entry.isSetByDomainResolver() + ")");
tblPrivs.add(String.format("%s.%s.%s: %s (%b)", tEntry.getOrigCtl(), tEntry.getOrigDb(),
tEntry.getOrigTbl(), savedPrivs, tEntry.isSetByDomainResolver()));
}
// Add privs from ldap groups that have not been added in Doris.
if (LdapPrivsChecker.hasLdapPrivs(userIdent)) {
Map<TablePattern, PrivBitSet> ldapTblPrivs = LdapPrivsChecker.getLdapAllTblPrivs(userIdent);
for (Map.Entry<TablePattern, PrivBitSet> entry : ldapTblPrivs.entrySet()) {
if (!addedtbls.contains(entry.getKey().getQualifiedDb().concat(".").concat(entry.getKey().getTbl()))) {
tblPrivs.add(entry.getKey().getQualifiedDb().concat(".").concat(entry.getKey().getTbl())
.concat(": ").concat(entry.getValue().toString()).concat(" (false)"));
tblPrivs.add(String.format("%s: %s (%b)", entry.getKey(), entry.getValue(), false));
}
}
}
@ -1662,6 +1752,7 @@ public class PaloAuth implements Writable {
// role manager must be first, because role should be exist before any user
roleManager.write(out);
userPrivTable.write(out);
catalogPrivTable.write(out);
dbPrivTable.write(out);
tablePrivTable.write(out);
resourcePrivTable.write(out);
@ -1672,6 +1763,13 @@ public class PaloAuth implements Writable {
public void readFields(DataInput in) throws IOException {
roleManager = RoleManager.read(in);
userPrivTable = (UserPrivTable) PrivTable.read(in);
if (Catalog.getCurrentCatalogJournalVersion() >= FeMetaVersion.VERSION_111) {
catalogPrivTable = (CatalogPrivTable) PrivTable.read(in);
} else {
catalogPrivTable = userPrivTable.degradeToInternalCatalogPriv();
LOG.info("Load PaloAuth from meta version < {}, degrade UserPrivTable to CatalogPrivTable",
FeMetaVersion.VERSION_111);
}
dbPrivTable = (DbPrivTable) PrivTable.read(in);
tablePrivTable = (TablePrivTable) PrivTable.read(in);
resourcePrivTable = (ResourcePrivTable) PrivTable.read(in);

View File

@ -24,6 +24,7 @@ import org.apache.doris.common.PatternMatcher;
import org.apache.doris.common.io.Text;
import org.apache.doris.common.io.Writable;
import com.google.common.base.Preconditions;
import org.apache.commons.lang.NotImplementedException;
import java.io.DataInput;
@ -253,4 +254,19 @@ public abstract class PrivEntry implements Comparable<PrivEntry>, Writable {
public int compareTo(PrivEntry o) {
throw new NotImplementedException();
}
/**
* Help derived classes compare in the order of 'user', 'host', 'catalog', 'db', 'ctl'.
* Compare strings[i] with strings[i+1] successively, return if the comparison value is not 0 in current loop.
*/
protected static int compareAssist(String... strings) {
Preconditions.checkState(strings.length % 2 == 0);
for (int i = 0; i < strings.length; i += 2) {
int res = strings[i].compareTo(strings[i + 1]);
if (res != 0) {
return res;
}
}
return 0;
}
}

View File

@ -45,6 +45,27 @@ public abstract class PrivTable implements Writable {
// see PrivEntry for more detail
protected boolean isClassNameWrote = false;
/*
* Check if user@host has specified privilege
*/
public boolean hasPriv(String host, String user, PrivPredicate wanted) {
for (PrivEntry entry : entries) {
// check host
if (!entry.isAnyHost() && !entry.getHostPattern().match(host)) {
continue;
}
// check user
if (!entry.isAnyUser() && !entry.getUserPattern().match(user)) {
continue;
}
// check priv
if (entry.privSet.satisfy(wanted)) {
return true;
}
}
return false;
}
/*
* Add an entry to priv table.
* If entry already exists and errOnExist is false, we try to reset or merge the new priv entry with existing one.

View File

@ -26,6 +26,7 @@ import org.apache.doris.common.io.Writable;
import org.apache.doris.mysql.privilege.PaloAuth.PrivLevel;
import com.google.common.base.Joiner;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
@ -34,6 +35,9 @@ import java.io.DataOutput;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class RoleManager implements Writable {
private Map<String, PaloRole> roles = Maps.newHashMap();
@ -132,60 +136,26 @@ public class RoleManager implements Writable {
info.add(role.getRoleName());
info.add(Joiner.on(", ").join(role.getUsers()));
// global
boolean hasGlobal = false;
for (Map.Entry<TablePattern, PrivBitSet> entry : role.getTblPatternToPrivs().entrySet()) {
if (entry.getKey().getPrivLevel() == PrivLevel.GLOBAL) {
hasGlobal = true;
info.add(entry.getValue().toString());
// global priv should only has one
break;
}
}
if (!hasGlobal) {
info.add(FeConstants.null_string);
}
// db
List<String> tmp = Lists.newArrayList();
for (Map.Entry<TablePattern, PrivBitSet> entry : role.getTblPatternToPrivs().entrySet()) {
if (entry.getKey().getPrivLevel() == PrivLevel.DATABASE) {
tmp.add(entry.getKey().toString() + ": " + entry.getValue().toString());
}
}
if (tmp.isEmpty()) {
info.add(FeConstants.null_string);
} else {
info.add(Joiner.on("; ").join(tmp));
}
// tbl
tmp.clear();
for (Map.Entry<TablePattern, PrivBitSet> entry : role.getTblPatternToPrivs().entrySet()) {
if (entry.getKey().getPrivLevel() == PrivLevel.TABLE) {
tmp.add(entry.getKey().toString() + ": " + entry.getValue().toString());
}
}
if (tmp.isEmpty()) {
info.add(FeConstants.null_string);
} else {
info.add(Joiner.on("; ").join(tmp));
}
// resource
tmp.clear();
for (Map.Entry<ResourcePattern, PrivBitSet> entry : role.getResourcePatternToPrivs().entrySet()) {
if (entry.getKey().getPrivLevel() == PrivLevel.RESOURCE) {
tmp.add(entry.getKey().toString() + ": " + entry.getValue().toString());
}
}
if (tmp.isEmpty()) {
info.add(FeConstants.null_string);
} else {
info.add(Joiner.on("; ").join(tmp));
}
Map<PrivLevel, String> infoMap = role.getTblPatternToPrivs().entrySet().stream()
.collect(Collectors.groupingBy(entry -> entry.getKey().getPrivLevel())).entrySet().stream()
.collect(Collectors.toMap(Entry::getKey, entry -> {
if (entry.getKey() == PrivLevel.GLOBAL) {
return entry.getValue().stream().findFirst().map(priv -> priv.getValue().toString())
.orElse(FeConstants.null_string);
} else {
return entry.getValue().stream()
.map(priv -> priv.getKey() + ": " + priv.getValue())
.collect(Collectors.joining("; "));
}
}));
Stream.of(PrivLevel.GLOBAL, PrivLevel.CATALOG, PrivLevel.DATABASE, PrivLevel.TABLE, PrivLevel.RESOURCE)
.forEach(level -> {
String infoItem = infoMap.get(level);
if (Strings.isNullOrEmpty(infoItem)) {
infoItem = FeConstants.null_string;
}
info.add(infoItem);
});
results.add(info);
}
}

View File

@ -36,10 +36,13 @@ public class TablePrivEntry extends DbPrivEntry {
protected TablePrivEntry() {
}
private TablePrivEntry(PatternMatcher hostPattern, String origHost, PatternMatcher dbPattern, String origDb,
PatternMatcher userPattern, String user, PatternMatcher tblPattern, String origTbl,
boolean isDomain, PrivBitSet privSet) {
super(hostPattern, origHost, dbPattern, origDb, userPattern, user, isDomain, privSet);
private TablePrivEntry(PatternMatcher userPattern, String user,
PatternMatcher hostPattern, String origHost,
PatternMatcher ctlPattern, String origCtl,
PatternMatcher dbPattern, String origDb,
PatternMatcher tblPattern, String origTbl,
boolean isDomain, PrivBitSet privSet) {
super(userPattern, user, hostPattern, origHost, ctlPattern, origCtl, dbPattern, origDb, isDomain, privSet);
this.tblPattern = tblPattern;
this.origTbl = origTbl;
if (origTbl.equals(ANY_TBL)) {
@ -47,12 +50,15 @@ public class TablePrivEntry extends DbPrivEntry {
}
}
public static TablePrivEntry create(String host, String db, String user, String tbl, boolean isDomain,
PrivBitSet privs) throws AnalysisException {
public static TablePrivEntry create(String user, String host,
String ctl, String db, String tbl,
boolean isDomain, PrivBitSet privs) throws AnalysisException {
PatternMatcher hostPattern = PatternMatcher.createMysqlPattern(host, CaseSensibility.HOST.getCaseSensibility());
PatternMatcher dbPattern = PatternMatcher.createFlatPattern(
db, CaseSensibility.DATABASE.getCaseSensibility(), db.equals(ANY_DB));
PatternMatcher userPattern = PatternMatcher.createFlatPattern(user, CaseSensibility.USER.getCaseSensibility());
PatternMatcher ctlPattern = PatternMatcher.createFlatPattern(
ctl, CaseSensibility.CATALOG.getCaseSensibility(), ctl.equals(ANY_CTL));
PatternMatcher tblPattern = PatternMatcher.createFlatPattern(
tbl, CaseSensibility.TABLE.getCaseSensibility(), tbl.equals(ANY_TBL));
@ -61,8 +67,8 @@ public class TablePrivEntry extends DbPrivEntry {
throw new AnalysisException("Table privilege can not contains global or resource privileges: " + privs);
}
return new TablePrivEntry(hostPattern, host, dbPattern, db,
userPattern, user, tblPattern, tbl, isDomain, privs);
return new TablePrivEntry(userPattern, user, hostPattern, host,
ctlPattern, ctl, dbPattern, db, tblPattern, tbl, isDomain, privs);
}
public PatternMatcher getTblPattern() {
@ -84,22 +90,11 @@ public class TablePrivEntry extends DbPrivEntry {
}
TablePrivEntry otherEntry = (TablePrivEntry) other;
int res = origHost.compareTo(otherEntry.origHost);
if (res != 0) {
return -res;
}
res = origDb.compareTo(otherEntry.origDb);
if (res != 0) {
return -res;
}
res = origUser.compareTo(otherEntry.origUser);
if (res != 0) {
return -res;
}
return -origTbl.compareTo(otherEntry.origTbl);
return compareAssist(origUser, otherEntry.origUser,
origHost, otherEntry.origHost,
origCtl, otherEntry.origCtl,
origDb, otherEntry.origDb,
origTbl, otherEntry.origTbl);
}
@Override
@ -109,21 +104,16 @@ public class TablePrivEntry extends DbPrivEntry {
}
TablePrivEntry otherEntry = (TablePrivEntry) other;
if (origHost.equals(otherEntry.origHost) && origUser.equals(otherEntry.origUser)
&& origDb.equals(otherEntry.origDb) && origTbl.equals(otherEntry.origTbl)
&& isDomain == otherEntry.isDomain) {
return true;
}
return false;
return origUser.equals(otherEntry.origUser) && origHost.equals(otherEntry.origHost)
&& origCtl.equals(otherEntry.origCtl) && origDb.equals(otherEntry.origDb)
&& origTbl.equals(otherEntry.origTbl) && isDomain == otherEntry.isDomain;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("db priv. host: ").append(origHost).append(", db: ").append(origDb);
sb.append(", user: ").append(origUser).append(", tbl: ").append(origTbl);
sb.append(", priv: ").append(privSet).append(", set by resolver: ").append(isSetByDomainResolver);
return sb.toString();
return String.format("table privilege. user: %s, host: %s, "
+ "ctl: %s, db: %s, tbl: %s, priv: %s, set by resolver: %b",
origUser, origHost, origCtl, origDb, origTbl, privSet.toString(), isSetByDomainResolver);
}
@Override

View File

@ -32,10 +32,10 @@ import java.io.IOException;
public class TablePrivTable extends PrivTable {
/*
* Return first priv which match the user@host on db.tbl The returned priv will
* Return first priv which match the user@host on ctl.db.tbl The returned priv will
* be saved in 'savedPrivs'.
*/
public void getPrivs(UserIdentity currentUser, String db, String tbl, PrivBitSet savedPrivs) {
public void getPrivs(UserIdentity currentUser, String ctl, String db, String tbl, PrivBitSet savedPrivs) {
TablePrivEntry matchedEntry = null;
for (PrivEntry entry : entries) {
TablePrivEntry tblPrivEntry = (TablePrivEntry) entry;
@ -43,6 +43,11 @@ public class TablePrivTable extends PrivTable {
continue;
}
// check catalog
if (!tblPrivEntry.isAnyCtl() && !tblPrivEntry.getCtlPattern().match(ctl)) {
continue;
}
// check db
Preconditions.checkState(!tblPrivEntry.isAnyDb());
if (!tblPrivEntry.getDbPattern().match(db)) {
@ -64,29 +69,7 @@ public class TablePrivTable extends PrivTable {
savedPrivs.or(matchedEntry.getPrivSet());
}
/*
* Check if user@host has specified privilege on any table
*/
public boolean hasPriv(String host, String user, PrivPredicate wanted) {
for (PrivEntry entry : entries) {
TablePrivEntry tblPrivEntry = (TablePrivEntry) entry;
// check host
if (!tblPrivEntry.isAnyHost() && !tblPrivEntry.getHostPattern().match(host)) {
continue;
}
// check user
if (!tblPrivEntry.isAnyUser() && !tblPrivEntry.getUserPattern().match(user)) {
continue;
}
// check priv
if (tblPrivEntry.privSet.satisfy(wanted)) {
return true;
}
}
return false;
}
public boolean hasPrivsOfDb(UserIdentity currentUser, String db) {
public boolean hasPrivsOfDb(UserIdentity currentUser, String ctl, String db) {
for (PrivEntry entry : entries) {
TablePrivEntry tblPrivEntry = (TablePrivEntry) entry;
@ -94,6 +77,12 @@ public class TablePrivTable extends PrivTable {
continue;
}
// check catalog
Preconditions.checkState(!tblPrivEntry.isAnyCtl());
if (!tblPrivEntry.getCtlPattern().match(ctl)) {
continue;
}
// check db
Preconditions.checkState(!tblPrivEntry.isAnyDb());
if (!tblPrivEntry.getDbPattern().match(db)) {

View File

@ -20,6 +20,7 @@ package org.apache.doris.mysql.privilege;
import org.apache.doris.analysis.UserIdentity;
import org.apache.doris.common.DdlException;
import org.apache.doris.common.io.Text;
import org.apache.doris.datasource.InternalDataSource;
import org.apache.doris.mysql.MysqlPassword;
import org.apache.logging.log4j.LogManager;
@ -27,6 +28,7 @@ import org.apache.logging.log4j.Logger;
import java.io.DataOutput;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
/*
@ -57,27 +59,6 @@ public class UserPrivTable extends PrivTable {
savedPrivs.or(matchedEntry.getPrivSet());
}
/*
* Check if user@host has specified privilege
*/
public boolean hasPriv(String host, String user, PrivPredicate wanted) {
for (PrivEntry entry : entries) {
GlobalPrivEntry globalPrivEntry = (GlobalPrivEntry) entry;
// check host
if (!globalPrivEntry.isAnyHost() && !globalPrivEntry.getHostPattern().match(host)) {
continue;
}
// check user
if (!globalPrivEntry.isAnyUser() && !globalPrivEntry.getUserPattern().match(user)) {
continue;
}
if (globalPrivEntry.getPrivSet().satisfy(wanted)) {
return true;
}
}
return false;
}
// validate the connection by host, user and password.
// return true if this connection is valid, and 'savedPrivs' save all global privs got from user table.
// if currentUser is not null, save the current user identity
@ -196,4 +177,33 @@ public class UserPrivTable extends PrivTable {
super.write(out);
}
/**
* When replay UserPrivTable from journal whose FeMetaVersion < VERSION_111, the global-level privileges should
* degrade to internal-catalog-level privileges.
*/
public CatalogPrivTable degradeToInternalCatalogPriv() throws IOException {
CatalogPrivTable catalogPrivTable = new CatalogPrivTable();
List<PrivEntry> degradedEntries = new LinkedList<>();
for (PrivEntry privEntry : entries) {
GlobalPrivEntry globalPrivEntry = (GlobalPrivEntry) privEntry;
if (!globalPrivEntry.match(UserIdentity.ROOT, true)
&& !globalPrivEntry.match(UserIdentity.ADMIN, true)
&& !globalPrivEntry.privSet.isEmpty()) {
try {
CatalogPrivEntry entry = CatalogPrivEntry.create(globalPrivEntry.origUser, globalPrivEntry.origHost,
InternalDataSource.INTERNAL_DS_NAME, globalPrivEntry.isDomain, globalPrivEntry.privSet);
entry.setSetByDomainResolver(false);
catalogPrivTable.addEntry(entry, false, false);
degradedEntries.add(globalPrivEntry);
} catch (Exception e) {
throw new IOException(e.getMessage());
}
}
}
for (PrivEntry degraded : degradedEntries) {
dropEntry(degraded);
}
return catalogPrivTable;
}
}

View File

@ -23,6 +23,7 @@ import org.apache.doris.catalog.Database;
import org.apache.doris.cluster.ClusterNamespace;
import org.apache.doris.common.UserException;
import org.apache.doris.common.util.DebugUtil;
import org.apache.doris.datasource.InternalDataSource;
import org.apache.doris.datasource.SessionContext;
import org.apache.doris.mysql.MysqlCapability;
import org.apache.doris.mysql.MysqlChannel;
@ -108,6 +109,7 @@ public class ConnectContext {
// Catalog: put catalog here is convenient for unit test,
// because catalog is singleton, hard to mock
protected Catalog catalog;
protected String defaultCatalog = InternalDataSource.INTERNAL_DS_NAME;
protected boolean isSend;
protected AuditEventBuilder auditEventBuilder = new AuditEventBuilder();
@ -290,6 +292,7 @@ public class ConnectContext {
public void setCatalog(Catalog catalog) {
this.catalog = catalog;
defaultCatalog = catalog.getInternalDataSource().getName();
}
public Catalog getCatalog() {
@ -410,6 +413,14 @@ public class ConnectContext {
return serverCapability;
}
public String getDefaultCatalog() {
return defaultCatalog;
}
public void changeDefaultCatalog(String catalogName) {
defaultCatalog = catalogName;
}
public String getDatabase() {
return currentDb;
}

View File

@ -33,6 +33,7 @@ import org.apache.doris.catalog.SinglePartitionInfo;
import org.apache.doris.common.AnalysisException;
import org.apache.doris.common.DdlException;
import org.apache.doris.common.jmockit.Deencapsulation;
import org.apache.doris.datasource.InternalDataSource;
import org.apache.doris.load.Load;
import org.apache.doris.mysql.privilege.PaloAuth;
import org.apache.doris.mysql.privilege.PrivPredicate;
@ -319,6 +320,10 @@ public class AccessTestUtil {
Analyzer analyzer = new Analyzer(fetchAdminCatalog(), new ConnectContext(null));
new Expectations(analyzer) {
{
analyzer.getDefaultCatalog();
minTimes = 0;
result = InternalDataSource.INTERNAL_DS_NAME;
analyzer.getDefaultDb();
minTimes = 0;
result = withCluster ? prefix + "testDb" : "testDb";
@ -351,6 +356,10 @@ public class AccessTestUtil {
Analyzer analyzer = new Analyzer(fetchBlockCatalog(), new ConnectContext(null));
new Expectations(analyzer) {
{
analyzer.getDefaultCatalog();
minTimes = 0;
result = InternalDataSource.INTERNAL_DS_NAME;
analyzer.getDefaultDb();
minTimes = 0;
result = "testCluster:testDb";
@ -371,6 +380,10 @@ public class AccessTestUtil {
Analyzer analyzer = new Analyzer(fetchBlockCatalog(), new ConnectContext(null));
new Expectations(analyzer) {
{
analyzer.getDefaultCatalog();
minTimes = 0;
result = InternalDataSource.INTERNAL_DS_NAME;
analyzer.getDefaultDb();
minTimes = 0;
result = "";
@ -479,6 +492,10 @@ public class AccessTestUtil {
Analyzer analyzer = new Analyzer(catalog, new ConnectContext(null));
new Expectations(analyzer) {
{
analyzer.getDefaultCatalog();
minTimes = 0;
result = InternalDataSource.INTERNAL_DS_NAME;
analyzer.getDefaultDb();
minTimes = 0;
result = "testDb";

View File

@ -19,6 +19,7 @@ package org.apache.doris.analysis;
import org.apache.doris.common.AnalysisException;
import org.apache.doris.common.UserException;
import org.apache.doris.datasource.InternalDataSource;
import org.apache.doris.mysql.privilege.MockedAuth;
import org.apache.doris.mysql.privilege.PaloAuth;
import org.apache.doris.qe.ConnectContext;
@ -49,6 +50,10 @@ public class DropTableStmtTest {
new Expectations() {
{
noDbAnalyzer.getDefaultCatalog();
minTimes = 0;
result = InternalDataSource.INTERNAL_DS_NAME;
noDbAnalyzer.getDefaultDb();
minTimes = 0;
result = "";

View File

@ -19,6 +19,8 @@ package org.apache.doris.analysis;
import org.apache.doris.catalog.Type;
import org.apache.doris.common.AnalysisException;
import org.apache.doris.common.FeMetaVersion;
import org.apache.doris.meta.MetaContext;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
@ -49,6 +51,10 @@ public class VirtualSlotRefTest {
@Before
public void setUp() throws IOException, AnalysisException {
Analyzer analyzerBase = AccessTestUtil.fetchTableAnalyzer();
// read objects from file
MetaContext metaContext = new MetaContext();
metaContext.setMetaVersion(FeMetaVersion.VERSION_CURRENT);
metaContext.setThreadLocalInfo();
analyzer = new Analyzer(analyzerBase.getCatalog(), analyzerBase.getContext());
String[] cols = {"k1", "k2", "k3"};
slots = new ArrayList<>();

View File

@ -22,6 +22,7 @@ import org.apache.doris.analysis.TablePattern;
import org.apache.doris.analysis.UserIdentity;
import org.apache.doris.common.AnalysisException;
import org.apache.doris.common.LdapConfig;
import org.apache.doris.datasource.InternalDataSource;
import org.apache.doris.mysql.privilege.PaloPrivilege;
import org.apache.doris.mysql.privilege.PaloRole;
import org.apache.doris.mysql.privilege.PrivBitSet;
@ -38,6 +39,7 @@ import java.util.Map;
public class LdapPrivsCheckerTest {
private static final String CLUSTER = "default_cluster";
private static final String INTERNAL = InternalDataSource.INTERNAL_DS_NAME;
private static final String DB = "palodb";
private static final String TABLE_DB = "tabledb";
private static final String TABLE1 = "table1";
@ -63,13 +65,13 @@ public class LdapPrivsCheckerTest {
PaloRole role = new PaloRole("");
Map<TablePattern, PrivBitSet> tblPatternToPrivs = role.getTblPatternToPrivs();
TablePattern global = new TablePattern("*", "*");
TablePattern global = new TablePattern("*", "*", "*");
tblPatternToPrivs.put(global, PrivBitSet.of(PaloPrivilege.SELECT_PRIV, PaloPrivilege.CREATE_PRIV));
TablePattern db = new TablePattern(DB, "*");
TablePattern db = new TablePattern(INTERNAL, DB, "*");
tblPatternToPrivs.put(db, PrivBitSet.of(PaloPrivilege.SELECT_PRIV, PaloPrivilege.LOAD_PRIV));
TablePattern tbl1 = new TablePattern(TABLE_DB, TABLE1);
TablePattern tbl1 = new TablePattern(INTERNAL, TABLE_DB, TABLE1);
tblPatternToPrivs.put(tbl1, PrivBitSet.of(PaloPrivilege.SELECT_PRIV, PaloPrivilege.ALTER_PRIV));
TablePattern tbl2 = new TablePattern(TABLE_DB, TABLE2);
TablePattern tbl2 = new TablePattern(INTERNAL, TABLE_DB, TABLE2);
tblPatternToPrivs.put(tbl2, PrivBitSet.of(PaloPrivilege.SELECT_PRIV, PaloPrivilege.DROP_PRIV));
Map<ResourcePattern, PrivBitSet> resourcePatternToPrivs = role.getResourcePatternToPrivs();

View File

@ -23,6 +23,7 @@ import org.apache.doris.catalog.Database;
import org.apache.doris.cluster.ClusterNamespace;
import org.apache.doris.common.DdlException;
import org.apache.doris.common.LdapConfig;
import org.apache.doris.datasource.InternalDataSource;
import org.apache.doris.ldap.LdapAuthenticate;
import org.apache.doris.ldap.LdapClient;
import org.apache.doris.mysql.privilege.PaloAuth;
@ -82,6 +83,10 @@ public class MysqlProtoTest {
}
};
catalog.getInternalDataSource();
minTimes = 0;
result = new InternalDataSource();
catalog.getDbNullable(anyString);
minTimes = 0;
result = new Database();

View File

@ -35,6 +35,7 @@ import org.apache.doris.common.AnalysisException;
import org.apache.doris.common.Config;
import org.apache.doris.common.DdlException;
import org.apache.doris.common.UserException;
import org.apache.doris.datasource.InternalDataSource;
import org.apache.doris.persist.EditLog;
import org.apache.doris.persist.PrivInfo;
import org.apache.doris.qe.ConnectContext;
@ -102,6 +103,10 @@ public class AuthTest {
minTimes = 0;
result = SystemInfoService.DEFAULT_CLUSTER;
analyzer.getDefaultCatalog();
minTimes = 0;
result = InternalDataSource.INTERNAL_DS_NAME;
Catalog.getCurrentCatalog();
minTimes = 0;
result = catalog;
@ -1242,7 +1247,7 @@ public class AuthTest {
}
};
Assert.assertFalse(auth.checkGlobalPriv(ctx, PrivPredicate.OPERATOR));
grantStmt = new GrantStmt(opUser, null, new TablePattern("*", "*"), privileges);
grantStmt = new GrantStmt(opUser, null, new TablePattern("*", "*", "*"), privileges);
// first, use op_user itself to grant node_priv, which is not allowed
try {
new Expectations() {

View File

@ -26,7 +26,7 @@ public class PrivEntryTest {
@Test
public void testNameWithUnderscores() throws Exception {
TablePrivEntry tablePrivEntry = TablePrivEntry.create(
"127.%", "db_db1", "user1", "tbl_tbl1", false,
"user1", "127.%", "__internal", "db_db1", "tbl_tbl1", false,
PrivBitSet.of(PaloPrivilege.SELECT_PRIV, PaloPrivilege.DROP_PRIV));
// pattern match
Assert.assertFalse(tablePrivEntry.getDbPattern().match("db-db1"));
@ -38,11 +38,11 @@ public class PrivEntryTest {
userIdentity.setIsAnalyzed();
PrivBitSet privs1 = PrivBitSet.of();
tablePrivTable.getPrivs(userIdentity, "db#db1", "tbl#tbl1", privs1);
tablePrivTable.getPrivs(userIdentity, "##internal", "db#db1", "tbl#tbl1", privs1);
Assert.assertFalse(PaloPrivilege.satisfy(privs1, PrivPredicate.DROP));
PrivBitSet privs2 = PrivBitSet.of();
tablePrivTable.getPrivs(userIdentity, "db_db1", "tbl_tbl1", privs2);
tablePrivTable.getPrivs(userIdentity, "__internal", "db_db1", "tbl_tbl1", privs2);
Assert.assertTrue(PaloPrivilege.satisfy(privs2, PrivPredicate.DROP));
}
}

View File

@ -66,7 +66,7 @@ public class PolicyTest extends TestWithFeService {
CreateUserStmt createUserStmt = new CreateUserStmt(new UserDesc(user));
Catalog.getCurrentCatalog().getAuth().createUser(createUserStmt);
List<AccessPrivilege> privileges = Lists.newArrayList(AccessPrivilege.ADMIN_PRIV);
TablePattern tablePattern = new TablePattern("*", "*");
TablePattern tablePattern = new TablePattern("*", "*", "*");
tablePattern.analyze(SystemInfoService.DEFAULT_CLUSTER);
GrantStmt grantStmt = new GrantStmt(user, null, tablePattern, privileges);
Catalog.getCurrentCatalog().getAuth().grant(grantStmt);