diff --git a/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4 b/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4 index 359be7ed0f1dd7..d41da2cc76f517 100644 --- a/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4 +++ b/fe/fe-core/src/main/antlr4/org/apache/doris/nereids/DorisParser.g4 @@ -1148,7 +1148,7 @@ userIdentify ; grantUserIdentify - : userIdentify (IDENTIFIED BY PASSWORD? STRING_LITERAL)? + : userIdentify (IDENTIFIED BY PASSWORD? pwd=STRING_LITERAL)? ; explain diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilderForEncryption.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilderForEncryption.java index 466939214df4bd..1356124590396a 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilderForEncryption.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/parser/LogicalPlanBuilderForEncryption.java @@ -18,6 +18,7 @@ package org.apache.doris.nereids.parser; import org.apache.doris.analysis.BrokerDesc; +import org.apache.doris.analysis.UserDesc; import org.apache.doris.common.Pair; import org.apache.doris.common.util.DatasourcePrintableMap; import org.apache.doris.nereids.DorisParser; @@ -85,6 +86,15 @@ public SetVarOp visitSetPassword(DorisParser.SetPasswordContext ctx) { return super.visitSetPassword(ctx); } + // grant user identity clause + @Override + public UserDesc visitGrantUserIdentify(DorisParser.GrantUserIdentifyContext ctx) { + if (ctx.pwd != null) { + encryptPassword(ctx.pwd.getStartIndex(), ctx.pwd.getStopIndex()); + } + return super.visitGrantUserIdentify(ctx); + } + // set ldap password clause @Override public SetVarOp visitSetLdapAdminPassword(DorisParser.SetLdapAdminPasswordContext ctx) { diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/AlterUserCommand.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/AlterUserCommand.java index e1bde5ac549f70..39765e7cc63e19 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/AlterUserCommand.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/commands/AlterUserCommand.java @@ -29,7 +29,7 @@ /** * AlterUserCommand */ -public class AlterUserCommand extends AlterCommand { +public class AlterUserCommand extends AlterCommand implements NeedAuditEncryption { private final AlterUserInfo alterUserInfo; @@ -57,4 +57,9 @@ public void validate() throws UserException { public StmtType stmtType() { return StmtType.ALTER; } + + @Override + public boolean needAuditEncryption() { + return true; + } } diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/parser/EncryptSQLTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/parser/EncryptSQLTest.java index b766b1a6e809c3..5ccb3ca9400524 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/nereids/parser/EncryptSQLTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/parser/EncryptSQLTest.java @@ -443,6 +443,68 @@ public void testEncryption() throws Exception { } } + @Test + public void testCreateUserPasswordMasking() throws Exception { + ctx.setDatabase("test"); + try (MockedConstruction ignored = Mockito.mockConstruction(StmtExecutor.class, + Mockito.withSettings().defaultAnswer(Mockito.CALLS_REAL_METHODS), + (mock, context) -> { + Mockito.doReturn(false).when(mock).isForwardToMaster(); + Profile profile = new Profile(false, 0, 0); + Deencapsulation.setField(mock, "profile", profile); + Mockito.doReturn(profile).when(mock).getProfile(); + Mockito.doReturn(ctx).when(mock).getContext(); + Mockito.doNothing().when(mock).execute(); + Deencapsulation.setField(mock, "context", ctx); + if (context.arguments().size() >= 2 + && context.arguments().get(1) instanceof StatementBase) { + Deencapsulation.setField(mock, "parsedStmt", + context.arguments().get(1)); + } + if (ctx.getStatementContext() == null) { + ctx.setStatementContext(new StatementContext()); + } + })) { + ctx.setEnv(env); + ctx.setCurrentUserIdentity(UserIdentity.ROOT); + // testing for https://github.com/apache/doris/issues/62140 + String sql = "CREATE USER 'test_user62140'@'%' IDENTIFIED BY '123456'"; + String res = "CREATE USER 'test_user62140'@'%' IDENTIFIED BY '*XXX'"; + parseAndCheck(sql, res); + } + } + + @Test + public void testAlterUserPasswordMasking() throws Exception { + ctx.setDatabase("test"); + try (MockedConstruction ignored = Mockito.mockConstruction(StmtExecutor.class, + Mockito.withSettings().defaultAnswer(Mockito.CALLS_REAL_METHODS), + (mock, context) -> { + Mockito.doReturn(false).when(mock).isForwardToMaster(); + Profile profile = new Profile(false, 0, 0); + Deencapsulation.setField(mock, "profile", profile); + Mockito.doReturn(profile).when(mock).getProfile(); + Mockito.doReturn(ctx).when(mock).getContext(); + Mockito.doNothing().when(mock).execute(); + Deencapsulation.setField(mock, "context", ctx); + if (context.arguments().size() >= 2 + && context.arguments().get(1) instanceof StatementBase) { + Deencapsulation.setField(mock, "parsedStmt", + context.arguments().get(1)); + } + if (ctx.getStatementContext() == null) { + ctx.setStatementContext(new StatementContext()); + } + })) { + ctx.setEnv(env); + ctx.setCurrentUserIdentity(UserIdentity.ROOT); + // testing for https://github.com/apache/doris/issues/62140 + String sql = "ALTER USER 'test_user62140'@'%' IDENTIFIED BY '123456'"; + String res = "ALTER USER 'test_user62140'@'%' IDENTIFIED BY '*XXX'"; + parseAndCheck(sql, res); + } + } + private void parseAndCheck(String sql, String expected) throws Exception { processor.executeQuery(sql); AuditEvent event = auditEvents.get(auditEvents.size() - 1);