[improvement](account) support to account management sql (#8849)
Add [IF EXISTS] support to following statements: - CREATE [IF NOT EXISTS] USER - CREATE [IF NOT EXISTS] ROLE - DROP [IF EXISTS] USER - DROP [IF EXISTS] ROLE
This commit is contained in:
@ -1310,9 +1310,9 @@ create_stmt ::=
|
||||
{:
|
||||
RESULT = new CreateRepositoryStmt(isReadOnly, repoName, storage);
|
||||
:}
|
||||
| KW_CREATE KW_ROLE ident:role
|
||||
| KW_CREATE KW_ROLE opt_if_not_exists:ifNotExists ident:role
|
||||
{:
|
||||
RESULT = new CreateRoleStmt(role);
|
||||
RESULT = new CreateRoleStmt(ifNotExists, role);
|
||||
:}
|
||||
| KW_CREATE KW_FILE STRING_LITERAL:fileName opt_db:db KW_PROPERTIES LPAREN key_value_map:properties RPAREN
|
||||
{:
|
||||
@ -2010,9 +2010,9 @@ drop_stmt ::=
|
||||
RESULT = new DropTableStmt(ifExists, name, force);
|
||||
:}
|
||||
/* User */
|
||||
| KW_DROP KW_USER user_identity:userId
|
||||
| KW_DROP KW_USER opt_if_exists:ifExists user_identity:userId
|
||||
{:
|
||||
RESULT = new DropUserStmt(userId);
|
||||
RESULT = new DropUserStmt(ifExists, userId);
|
||||
:}
|
||||
/* View */
|
||||
| KW_DROP KW_VIEW opt_if_exists:ifExists table_name:name
|
||||
@ -2023,9 +2023,9 @@ drop_stmt ::=
|
||||
{:
|
||||
RESULT = new DropRepositoryStmt(repoName);
|
||||
:}
|
||||
| KW_DROP KW_ROLE ident:role
|
||||
| KW_DROP KW_ROLE opt_if_exists:ifExists ident:role
|
||||
{:
|
||||
RESULT = new DropRoleStmt(role);
|
||||
RESULT = new DropRoleStmt(ifExists, role);
|
||||
:}
|
||||
| KW_DROP KW_FILE STRING_LITERAL:fileName opt_db:dbName KW_PROPERTIES LPAREN key_value_map:properties RPAREN
|
||||
{:
|
||||
|
||||
@ -28,12 +28,22 @@ import org.apache.doris.qe.ConnectContext;
|
||||
|
||||
public class CreateRoleStmt extends DdlStmt {
|
||||
|
||||
private boolean ifNotExists;
|
||||
private String role;
|
||||
|
||||
public CreateRoleStmt(String role) {
|
||||
this.role = role;
|
||||
}
|
||||
|
||||
public CreateRoleStmt(boolean ifNotExists, String role) {
|
||||
this.ifNotExists = ifNotExists;
|
||||
this.role = role;
|
||||
}
|
||||
|
||||
public boolean isSetIfNotExists() {
|
||||
return ifNotExists;
|
||||
}
|
||||
|
||||
public String getQualifiedRole() {
|
||||
return role;
|
||||
}
|
||||
|
||||
@ -28,12 +28,22 @@ import org.apache.doris.qe.ConnectContext;
|
||||
|
||||
public class DropRoleStmt extends DdlStmt {
|
||||
|
||||
private boolean ifExists;
|
||||
private String role;
|
||||
|
||||
public DropRoleStmt(String role) {
|
||||
this.role = role;
|
||||
}
|
||||
|
||||
public DropRoleStmt(boolean ifExists, String role) {
|
||||
this.ifExists = ifExists;
|
||||
this.role = role;
|
||||
}
|
||||
|
||||
public boolean isSetIfExists() {
|
||||
return ifExists;
|
||||
}
|
||||
|
||||
public String getQualifiedRole() {
|
||||
return role;
|
||||
}
|
||||
|
||||
@ -29,12 +29,23 @@ import org.apache.doris.qe.ConnectContext;
|
||||
// drop user cmy <==> drop user cmy@'%'
|
||||
// drop user cmy@'192.168.1.%'
|
||||
public class DropUserStmt extends DdlStmt {
|
||||
|
||||
private boolean ifExists;
|
||||
private UserIdentity userIdent;
|
||||
|
||||
public DropUserStmt(UserIdentity userIdent) {
|
||||
this.userIdent = userIdent;
|
||||
}
|
||||
|
||||
public DropUserStmt(boolean ifExists, UserIdentity userIdent) {
|
||||
this.ifExists = ifExists;
|
||||
this.userIdent = userIdent;
|
||||
}
|
||||
|
||||
public boolean isSetIfExists() {
|
||||
return ifExists;
|
||||
}
|
||||
|
||||
public UserIdentity getUserIdentity() {
|
||||
return userIdent;
|
||||
}
|
||||
|
||||
@ -6096,7 +6096,7 @@ public class Catalog {
|
||||
idToDb.remove(infoSchemaDb.getId());
|
||||
}
|
||||
|
||||
public void replayDropCluster(ClusterInfo info) {
|
||||
public void replayDropCluster(ClusterInfo info) throws DdlException {
|
||||
tryLock(true);
|
||||
try {
|
||||
unprotectDropCluster(info, true/* is replay */);
|
||||
|
||||
@ -554,12 +554,12 @@ public class PaloAuth implements Writable {
|
||||
|
||||
// create user
|
||||
public void createUser(CreateUserStmt stmt) throws DdlException {
|
||||
createUserInternal(stmt.getUserIdent(), stmt.getQualifiedRole(), stmt.getPassword(), false);
|
||||
createUserInternal(stmt.getUserIdent(), stmt.getQualifiedRole(), stmt.getPassword(), stmt.isIfNotExist(), false);
|
||||
}
|
||||
|
||||
public void replayCreateUser(PrivInfo privInfo) {
|
||||
try {
|
||||
createUserInternal(privInfo.getUserIdent(), privInfo.getRole(), privInfo.getPasswd(), true);
|
||||
createUserInternal(privInfo.getUserIdent(), privInfo.getRole(), privInfo.getPasswd(), false, true);
|
||||
} catch (DdlException e) {
|
||||
LOG.error("should not happen", e);
|
||||
}
|
||||
@ -568,12 +568,12 @@ public class PaloAuth implements Writable {
|
||||
/*
|
||||
* Do following steps:
|
||||
* 1. Check does specified role exist. If not, throw exception.
|
||||
* 2. Check does user already exist. If yes, throw exception.
|
||||
* 2. Check does user already exist. If yes && ignoreIfExists, just return. Otherwise, throw exception.
|
||||
* 3. set password for specified user.
|
||||
* 4. grant privs of role to user, if role is specified.
|
||||
*/
|
||||
private void createUserInternal(UserIdentity userIdent, String roleName, byte[] password,
|
||||
boolean isReplay) throws DdlException {
|
||||
boolean ignoreIfExists, boolean isReplay) throws DdlException {
|
||||
writeLock();
|
||||
try {
|
||||
// 1. check if role exist
|
||||
@ -584,9 +584,13 @@ public class PaloAuth implements Writable {
|
||||
throw new DdlException("Role: " + roleName + " does not exist");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 2. check if user already exist
|
||||
if (userPrivTable.doesUserExist(userIdent)) {
|
||||
if (ignoreIfExists) {
|
||||
LOG.debug("user exists, ignored to create user: {}, is replay: {}", userIdent, isReplay);
|
||||
return;
|
||||
}
|
||||
throw new DdlException("User " + userIdent + " already exist");
|
||||
}
|
||||
|
||||
@ -646,22 +650,33 @@ public class PaloAuth implements Writable {
|
||||
|
||||
// drop user
|
||||
public void dropUser(DropUserStmt stmt) throws DdlException {
|
||||
dropUserInternal(stmt.getUserIdentity(), false);
|
||||
dropUserInternal(stmt.getUserIdentity(), stmt.isSetIfExists(), false);
|
||||
}
|
||||
|
||||
public void replayDropUser(UserIdentity userIdent) {
|
||||
dropUserInternal(userIdent, true);
|
||||
public void replayDropUser(UserIdentity userIdent) throws DdlException {
|
||||
dropUserInternal(userIdent, false, true);
|
||||
}
|
||||
|
||||
public void replayOldDropUser(String userName) {
|
||||
public void replayOldDropUser(String userName) throws DdlException {
|
||||
UserIdentity userIdentity = new UserIdentity(userName, "%");
|
||||
userIdentity.setIsAnalyzed();
|
||||
dropUserInternal(userIdentity, true /* is replay */);
|
||||
dropUserInternal(userIdentity, false /* ignore if non exists */, true /* is replay */);
|
||||
}
|
||||
|
||||
private void dropUserInternal(UserIdentity userIdent, boolean isReplay) {
|
||||
private void dropUserInternal(UserIdentity userIdent, boolean ignoreIfNonExists, boolean isReplay) throws DdlException {
|
||||
writeLock();
|
||||
try {
|
||||
// check if user exists
|
||||
if (!doesUserExist(userIdent)) {
|
||||
if (ignoreIfNonExists) {
|
||||
LOG.info("user non exists, ignored to drop user: {}, is replay: {}",
|
||||
userIdent.getQualifiedUser(), isReplay);
|
||||
return;
|
||||
}
|
||||
throw new DdlException(String.format("User `%s`@`%s` does not exist.",
|
||||
userIdent.getQualifiedUser(), userIdent.getHost()));
|
||||
}
|
||||
|
||||
// we don't check if user exists
|
||||
userPrivTable.dropUser(userIdent);
|
||||
dbPrivTable.dropUser(userIdent);
|
||||
@ -1047,21 +1062,26 @@ public class PaloAuth implements Writable {
|
||||
|
||||
// create role
|
||||
public void createRole(CreateRoleStmt stmt) throws DdlException {
|
||||
createRoleInternal(stmt.getQualifiedRole(), false);
|
||||
createRoleInternal(stmt.getQualifiedRole(), stmt.isSetIfNotExists(), false);
|
||||
}
|
||||
|
||||
public void replayCreateRole(PrivInfo info) {
|
||||
try {
|
||||
createRoleInternal(info.getRole(), true);
|
||||
createRoleInternal(info.getRole(), false, true);
|
||||
} catch (DdlException e) {
|
||||
LOG.error("should not happened", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void createRoleInternal(String role, boolean isReplay) throws DdlException {
|
||||
private void createRoleInternal(String role, boolean ignoreIfExists, boolean isReplay) throws DdlException {
|
||||
PaloRole emptyPrivsRole = new PaloRole(role);
|
||||
writeLock();
|
||||
try {
|
||||
if (ignoreIfExists && roleManager.getRole(role) != null) {
|
||||
LOG.info("role exists, ignored to create role: {}, is replay: {}", role, isReplay);
|
||||
return;
|
||||
}
|
||||
|
||||
roleManager.addRole(emptyPrivsRole, true /* err on exist */);
|
||||
|
||||
if (!isReplay) {
|
||||
@ -1076,20 +1096,25 @@ public class PaloAuth implements Writable {
|
||||
|
||||
// drop role
|
||||
public void dropRole(DropRoleStmt stmt) throws DdlException {
|
||||
dropRoleInternal(stmt.getQualifiedRole(), false);
|
||||
dropRoleInternal(stmt.getQualifiedRole(), stmt.isSetIfExists(), false);
|
||||
}
|
||||
|
||||
public void replayDropRole(PrivInfo info) {
|
||||
try {
|
||||
dropRoleInternal(info.getRole(), true);
|
||||
dropRoleInternal(info.getRole(), false, true);
|
||||
} catch (DdlException e) {
|
||||
LOG.error("should not happened", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void dropRoleInternal(String role, boolean isReplay) throws DdlException {
|
||||
private void dropRoleInternal(String role, boolean ignoreIfNonExists, boolean isReplay) throws DdlException {
|
||||
writeLock();
|
||||
try {
|
||||
if (ignoreIfNonExists && roleManager.getRole(role) == null) {
|
||||
LOG.info("role non exists, ignored to drop role: {}, is replay: {}", role, isReplay);
|
||||
return;
|
||||
}
|
||||
|
||||
roleManager.dropRole(role, true /* err on non exist */);
|
||||
|
||||
if (!isReplay) {
|
||||
@ -1429,13 +1454,13 @@ public class PaloAuth implements Writable {
|
||||
}
|
||||
}
|
||||
|
||||
public void dropUserOfCluster(String clusterName, boolean isReplay) {
|
||||
public void dropUserOfCluster(String clusterName, boolean isReplay) throws DdlException {
|
||||
writeLock();
|
||||
try {
|
||||
Set<UserIdentity> allUserIdents = getAllUserIdents(true);
|
||||
for (UserIdentity userIdent : allUserIdents) {
|
||||
if (userIdent.getQualifiedUser().startsWith(clusterName)) {
|
||||
dropUserInternal(userIdent, isReplay);
|
||||
dropUserInternal(userIdent, false, isReplay);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
@ -1478,10 +1503,10 @@ public class PaloAuth implements Writable {
|
||||
try {
|
||||
UserIdentity rootUser = new UserIdentity(ROOT_USER, "%");
|
||||
rootUser.setIsAnalyzed();
|
||||
createUserInternal(rootUser, PaloRole.OPERATOR_ROLE, new byte[0], true /* is replay */);
|
||||
createUserInternal(rootUser, PaloRole.OPERATOR_ROLE, new byte[0], false /* ignore if exists */, true /* is replay */);
|
||||
UserIdentity adminUser = new UserIdentity(ADMIN_USER, "%");
|
||||
adminUser.setIsAnalyzed();
|
||||
createUserInternal(adminUser, PaloRole.ADMIN_ROLE, new byte[0], true /* is replay */);
|
||||
createUserInternal(adminUser, PaloRole.ADMIN_ROLE, new byte[0], false /* ignore if exists */, true /* is replay */);
|
||||
} catch (DdlException e) {
|
||||
LOG.error("should not happened", e);
|
||||
}
|
||||
|
||||
@ -161,6 +161,43 @@ public class AuthTest {
|
||||
Assert.fail();
|
||||
}
|
||||
|
||||
// 1.1 create cmy@% again with IF NOT EXISTS
|
||||
userIdentity = new UserIdentity("cmy", "%");
|
||||
userDesc = new UserDesc(userIdentity, "54321", true);
|
||||
createUserStmt = new CreateUserStmt(true, userDesc, null);
|
||||
try {
|
||||
createUserStmt.analyze(analyzer);
|
||||
} catch (UserException e) {
|
||||
e.printStackTrace();
|
||||
Assert.fail();
|
||||
}
|
||||
|
||||
try {
|
||||
auth.createUser(createUserStmt);
|
||||
} catch (DdlException e) {
|
||||
Assert.fail();
|
||||
}
|
||||
|
||||
// 1.2 create cmy@% again without IF NOT EXISTS
|
||||
userIdentity = new UserIdentity("cmy", "%");
|
||||
userDesc = new UserDesc(userIdentity, "54321", true);
|
||||
createUserStmt = new CreateUserStmt(false, userDesc, null);
|
||||
try {
|
||||
createUserStmt.analyze(analyzer);
|
||||
} catch (UserException e) {
|
||||
e.printStackTrace();
|
||||
Assert.fail();
|
||||
}
|
||||
|
||||
boolean hasException = false;
|
||||
try {
|
||||
auth.createUser(createUserStmt);
|
||||
} catch (DdlException e) {
|
||||
e.printStackTrace();
|
||||
hasException = true;
|
||||
}
|
||||
Assert.assertTrue(hasException);
|
||||
|
||||
// 2. check if cmy from specified ip can access to palo
|
||||
List<UserIdentity> currentUser = Lists.newArrayList();
|
||||
Assert.assertTrue(auth.checkPlainPassword(SystemInfoService.DEFAULT_CLUSTER + ":cmy", "192.168.0.1", "12345",
|
||||
@ -205,7 +242,7 @@ public class AuthTest {
|
||||
Assert.fail();
|
||||
}
|
||||
|
||||
boolean hasException = false;
|
||||
hasException = false;
|
||||
try {
|
||||
auth.createUser(createUserStmt);
|
||||
} catch (DdlException e) {
|
||||
@ -769,6 +806,40 @@ public class AuthTest {
|
||||
Assert.fail();
|
||||
}
|
||||
|
||||
// 24.1 create role again with IF NOT EXISTS
|
||||
roleStmt = new CreateRoleStmt(true, "role1");
|
||||
try {
|
||||
roleStmt.analyze(analyzer);
|
||||
} catch (UserException e1) {
|
||||
e1.printStackTrace();
|
||||
Assert.fail();
|
||||
}
|
||||
|
||||
try {
|
||||
auth.createRole(roleStmt);
|
||||
} catch (DdlException e1) {
|
||||
e1.printStackTrace();
|
||||
Assert.fail();
|
||||
}
|
||||
|
||||
// 24.2 create role again without IF NOT EXISTS
|
||||
roleStmt = new CreateRoleStmt(false, "role1");
|
||||
try {
|
||||
roleStmt.analyze(analyzer);
|
||||
} catch (UserException e1) {
|
||||
e1.printStackTrace();
|
||||
Assert.fail();
|
||||
}
|
||||
|
||||
hasException = false;
|
||||
try {
|
||||
auth.createRole(roleStmt);
|
||||
} catch (DdlException e1) {
|
||||
e1.printStackTrace();
|
||||
hasException = true;
|
||||
}
|
||||
Assert.assertTrue(hasException);
|
||||
|
||||
// 25. grant auth to non exist role, will create this new role
|
||||
privileges = Lists.newArrayList(AccessPrivilege.DROP_PRIV, AccessPrivilege.SELECT_PRIV);
|
||||
grantStmt = new GrantStmt(null, "role2", new TablePattern("*", "*"), privileges);
|
||||
@ -917,6 +988,40 @@ public class AuthTest {
|
||||
Assert.assertFalse(auth.checkDbPriv(currentUser2.get(0), SystemInfoService.DEFAULT_CLUSTER + ":db4",
|
||||
PrivPredicate.DROP));
|
||||
|
||||
// 31.1 drop role again with IF EXISTS
|
||||
dropRoleStmt = new DropRoleStmt(true, "role1");
|
||||
try {
|
||||
dropRoleStmt.analyze(analyzer);
|
||||
} catch (UserException e) {
|
||||
e.printStackTrace();
|
||||
Assert.fail();
|
||||
}
|
||||
|
||||
try {
|
||||
auth.dropRole(dropRoleStmt);
|
||||
} catch (DdlException e) {
|
||||
e.printStackTrace();
|
||||
Assert.fail();
|
||||
}
|
||||
|
||||
// 31.2 drop role again without IF EXISTS
|
||||
dropRoleStmt = new DropRoleStmt(false, "role1");
|
||||
try {
|
||||
dropRoleStmt.analyze(analyzer);
|
||||
} catch (UserException e) {
|
||||
e.printStackTrace();
|
||||
Assert.fail();
|
||||
}
|
||||
|
||||
hasException = false;
|
||||
try {
|
||||
auth.dropRole(dropRoleStmt);
|
||||
} catch (DdlException e) {
|
||||
e.printStackTrace();
|
||||
hasException = true;
|
||||
}
|
||||
Assert.assertTrue(hasException);
|
||||
|
||||
// 32. drop user cmy@"%"
|
||||
DropUserStmt dropUserStmt = new DropUserStmt(new UserIdentity("cmy", "%"));
|
||||
try {
|
||||
@ -936,6 +1041,39 @@ public class AuthTest {
|
||||
Assert.assertTrue(auth.checkPlainPassword(SystemInfoService.DEFAULT_CLUSTER + ":zhangsan", "192.168.0.1",
|
||||
"12345", null));
|
||||
|
||||
// 32.1 drop user cmy@"%" again with IF EXISTS
|
||||
dropUserStmt = new DropUserStmt(true, new UserIdentity("cmy", "%"));
|
||||
try {
|
||||
dropUserStmt.analyze(analyzer);
|
||||
} catch (UserException e) {
|
||||
e.printStackTrace();
|
||||
Assert.fail();
|
||||
}
|
||||
|
||||
try {
|
||||
auth.dropUser(dropUserStmt);
|
||||
} catch (DdlException e) {
|
||||
Assert.fail();
|
||||
}
|
||||
|
||||
// 32.2 drop user cmy@"%" again without IF EXISTS
|
||||
dropUserStmt = new DropUserStmt(false, new UserIdentity("cmy", "%"));
|
||||
try {
|
||||
dropUserStmt.analyze(analyzer);
|
||||
} catch (UserException e) {
|
||||
e.printStackTrace();
|
||||
Assert.fail();
|
||||
}
|
||||
|
||||
hasException = false;
|
||||
try {
|
||||
auth.dropUser(dropUserStmt);
|
||||
} catch (DdlException e) {
|
||||
e.printStackTrace();
|
||||
hasException = true;
|
||||
}
|
||||
Assert.assertTrue(hasException);
|
||||
|
||||
// 33. drop user zhangsan@"192.%"
|
||||
dropUserStmt = new DropUserStmt(new UserIdentity("zhangsan", "192.%"));
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user