[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:
Jiading Guo
2022-04-08 09:08:08 +08:00
committed by GitHub
parent 0b98d78664
commit 318feb01f3
11 changed files with 256 additions and 62 deletions

View File

@ -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
{:

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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 */);

View File

@ -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);
}

View File

@ -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 {