[fix](auth)unified workload and resource permission logic #32907 (#33925)

bp #32907
This commit is contained in:
Mingyu Chen
2024-04-22 11:25:38 +08:00
committed by GitHub
parent 4aee706264
commit 7323487fe1
8 changed files with 82 additions and 66 deletions

View File

@ -22,6 +22,7 @@ import org.apache.doris.common.FeNameFormat;
import org.apache.doris.common.io.Text;
import org.apache.doris.common.io.Writable;
import org.apache.doris.mysql.privilege.Auth.PrivLevel;
import org.apache.doris.persist.gson.GsonPostProcessable;
import org.apache.doris.persist.gson.GsonUtils;
import com.google.common.base.Strings;
@ -34,14 +35,14 @@ import java.io.IOException;
// only the following 2 formats are allowed
// *
// resource
public class ResourcePattern implements Writable {
public class ResourcePattern implements Writable, GsonPostProcessable {
@SerializedName(value = "resourceName")
private String resourceName;
public static ResourcePattern ALL;
static {
ALL = new ResourcePattern("*");
ALL = new ResourcePattern("%");
try {
ALL.analyze();
} catch (AnalysisException e) {
@ -53,7 +54,11 @@ public class ResourcePattern implements Writable {
}
public ResourcePattern(String resourceName) {
this.resourceName = Strings.isNullOrEmpty(resourceName) ? "*" : resourceName;
// To be compatible with previous syntax
if ("*".equals(resourceName)) {
resourceName = "%";
}
this.resourceName = Strings.isNullOrEmpty(resourceName) ? "%" : resourceName;
}
public String getResourceName() {
@ -61,15 +66,11 @@ public class ResourcePattern implements Writable {
}
public PrivLevel getPrivLevel() {
if (resourceName.equals("*")) {
return PrivLevel.GLOBAL;
} else {
return PrivLevel.RESOURCE;
}
return PrivLevel.RESOURCE;
}
public void analyze() throws AnalysisException {
if (!resourceName.equals("*")) {
if (!resourceName.equals("%")) {
FeNameFormat.checkResourceName(resourceName);
}
}
@ -105,4 +106,12 @@ public class ResourcePattern implements Writable {
String json = Text.readString(in);
return GsonUtils.GSON.fromJson(json, ResourcePattern.class);
}
@Override
public void gsonPostProcess() throws IOException {
// // To be compatible with previous syntax
if ("*".equals(resourceName)) {
resourceName = "%";
}
}
}

View File

@ -124,7 +124,7 @@ public class PrivPredicate {
this.op = op;
}
private static PrivPredicate of(PrivBitSet privs, Operator op) {
public static PrivPredicate of(PrivBitSet privs, Operator op) {
final PrivPredicate predicate = new PrivPredicate(privs, op);
return predicate;
}

View File

@ -27,11 +27,8 @@ import java.io.DataInput;
import java.io.IOException;
public class ResourcePrivEntry extends PrivEntry {
protected static final String ANY_RESOURCE = "*";
protected PatternMatcher resourcePattern;
protected String origResource;
protected boolean isAnyResource;
protected ResourcePrivEntry() {
}
@ -41,15 +38,12 @@ public class ResourcePrivEntry extends PrivEntry {
super(privSet);
this.resourcePattern = resourcePattern;
this.origResource = origResource;
if (origResource.equals(ANY_RESOURCE)) {
isAnyResource = true;
}
}
public static ResourcePrivEntry create(String resourceName, PrivBitSet privs)
throws AnalysisException, PatternMatcherException {
PatternMatcher resourcePattern = PatternMatcher.createMysqlPattern(
resourceName.equals(ANY_RESOURCE) ? "%" : resourceName,
resourceName,
CaseSensibility.RESOURCE.getCaseSensibility());
if (privs.containsNodePriv() || privs.containsDbTablePriv()) {
throw new AnalysisException("Resource privilege can not contains node or db table privileges: " + privs);
@ -112,6 +106,5 @@ public class ResourcePrivEntry extends PrivEntry {
} catch (PatternMatcherException e) {
throw new IOException(e);
}
isAnyResource = origResource.equals(ANY_RESOURCE);
}
}

View File

@ -26,26 +26,15 @@ import org.apache.logging.log4j.Logger;
public class ResourcePrivTable extends PrivTable {
private static final Logger LOG = LogManager.getLogger(ResourcePrivTable.class);
/*
* Return first priv which match the user@host on resourceName The returned priv will be
* saved in 'savedPrivs'.
*/
public void getPrivs(String resourceName, PrivBitSet savedPrivs) {
ResourcePrivEntry matchedEntry = null;
// need check all entries, because may have 2 entries match resourceName,
// For example, if the resourceName is g1, there are two entry `%` and `g1` compound requirements
for (PrivEntry entry : entries) {
ResourcePrivEntry resourcePrivEntry = (ResourcePrivEntry) entry;
// check resource
if (!resourcePrivEntry.getResourcePattern().match(resourceName)) {
continue;
if (resourcePrivEntry.getResourcePattern().match(resourceName)) {
savedPrivs.or(resourcePrivEntry.getPrivSet());
}
matchedEntry = resourcePrivEntry;
break;
}
if (matchedEntry == null) {
return;
}
savedPrivs.or(matchedEntry.getPrivSet());
}
}

View File

@ -424,8 +424,8 @@ public class Role implements Writable, GsonPostProcessable {
return true;
}
PrivBitSet savedPrivs = PrivBitSet.of();
// Workload groups do not support global usage_priv, so only global admin_priv and usage_priv are checked.
if (checkGlobalInternal(PrivPredicate.ADMIN, savedPrivs)
// usage priv not in global, but grant_priv may in global
if (checkGlobalInternal(wanted, savedPrivs)
|| checkWorkloadGroupInternal(workloadGroupName, wanted, savedPrivs)) {
return true;
}
@ -522,18 +522,7 @@ public class Role implements Writable, GsonPostProcessable {
if (privs.isEmpty()) {
return;
}
// grant privs to user
switch (resourcePattern.getPrivLevel()) {
case GLOBAL:
grantGlobalPrivs(privs);
break;
case RESOURCE:
grantResourcePrivs(resourcePattern.getResourceName(), privs);
break;
default:
Preconditions.checkNotNull(null, resourcePattern.getPrivLevel());
}
grantResourcePrivs(resourcePattern.getResourceName(), privs);
}
private void grantPrivs(WorkloadGroupPattern workloadGroupPattern, PrivBitSet privs) throws DdlException {

View File

@ -20,20 +20,13 @@ package org.apache.doris.mysql.privilege;
public class WorkloadGroupPrivTable extends PrivTable {
public void getPrivs(String workloadGroupName, PrivBitSet savedPrivs) {
WorkloadGroupPrivEntry matchedEntry = null;
// need check all entries, because may have 2 entries match workloadGroupName,
// For example, if the workloadGroupName is g1, there are two entry `%` and `g1` compound requirements
for (PrivEntry entry : entries) {
WorkloadGroupPrivEntry workloadGroupPrivEntry = (WorkloadGroupPrivEntry) entry;
if (!workloadGroupPrivEntry.getWorkloadGroupPattern().match(workloadGroupName)) {
continue;
if (workloadGroupPrivEntry.getWorkloadGroupPattern().match(workloadGroupName)) {
savedPrivs.or(workloadGroupPrivEntry.getPrivSet());
}
matchedEntry = workloadGroupPrivEntry;
break;
}
if (matchedEntry == null) {
return;
}
savedPrivs.or(matchedEntry.getPrivSet());
}
}