You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@iotdb.apache.org by ji...@apache.org on 2025/09/15 06:41:44 UTC
(iotdb) 01/01: Fix that oldPassword is not recorded during user creation & delete password history after user removal
This is an automated email from the ASF dual-hosted git repository.
jiangtian pushed a commit to branch fix_old_password_in_create
in repository https://gitbox.apache.org/repos/asf/iotdb.git
commit 8b3eacd5d9409bd98df9785a48c9a917699f194e
Author: Tian Jiang <jt...@163.com>
AuthorDate: Mon Sep 15 14:41:28 2025 +0800
Fix that oldPassword is not recorded during user creation & delete password history after user removal
---
.../org/apache/iotdb/db/it/auth/IoTDBAuthIT.java | 28 ++++++++++-
.../iotdb/db/protocol/session/SessionManager.java | 2 +-
.../sql/ast/RelationalAuthorStatement.java | 24 ++++++++--
.../plan/statement/sys/AuthorStatement.java | 24 ++++++++--
.../apache/iotdb/db/utils/DataNodeAuthUtils.java | 54 +++++++++++++++++++++-
5 files changed, 121 insertions(+), 11 deletions(-)
diff --git a/integration-test/src/test/java/org/apache/iotdb/db/it/auth/IoTDBAuthIT.java b/integration-test/src/test/java/org/apache/iotdb/db/it/auth/IoTDBAuthIT.java
index 98467604409..0d963f9e1a4 100644
--- a/integration-test/src/test/java/org/apache/iotdb/db/it/auth/IoTDBAuthIT.java
+++ b/integration-test/src/test/java/org/apache/iotdb/db/it/auth/IoTDBAuthIT.java
@@ -1550,7 +1550,7 @@ public class IoTDBAuthIT {
public void testPasswordHistory() {
try (Connection connection = EnvFactory.getEnv().getConnection();
Statement statement = connection.createStatement()) {
- testPasswordHistoryCreate(statement);
+ testPasswordHistoryCreateAndDrop(statement);
testPasswordHistoryAlter(statement);
} catch (SQLException e) {
e.printStackTrace();
@@ -1558,7 +1558,7 @@ public class IoTDBAuthIT {
}
}
- public void testPasswordHistoryCreate(Statement statement) throws SQLException {
+ public void testPasswordHistoryCreateAndDrop(Statement statement) throws SQLException {
statement.execute("create user userA 'abcdef123456'");
try (ResultSet resultSet =
@@ -1569,9 +1569,33 @@ public class IoTDBAuthIT {
}
assertEquals(AuthUtils.encryptPassword("abcdef123456"), resultSet.getString("Value"));
}
+
+ try (ResultSet resultSet =
+ statement.executeQuery(
+ "select last oldPassword from root.__system.password_history.`_userA`")) {
+ if (!resultSet.next()) {
+ fail("Password history not found");
+ }
+ assertEquals(AuthUtils.encryptPassword("abcdef123456"), resultSet.getString("Value"));
+ }
+
+ statement.execute("drop user userA");
+
+ try (ResultSet resultSet =
+ statement.executeQuery(
+ "select last password from root.__system.password_history.`_userA`")) {
+ assertFalse(resultSet.next());
+ }
+
+ try (ResultSet resultSet =
+ statement.executeQuery(
+ "select last oldPassword from root.__system.password_history.`_userA`")) {
+ assertFalse(resultSet.next());
+ }
}
public void testPasswordHistoryAlter(Statement statement) throws SQLException {
+ statement.execute("create user userA 'abcdef123456'");
statement.execute("alter user userA set password 'abcdef654321'");
try (ResultSet resultSet =
diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/session/SessionManager.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/session/SessionManager.java
index 9fa85a0be76..a5a04e98b27 100644
--- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/session/SessionManager.java
+++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/session/SessionManager.java
@@ -265,7 +265,7 @@ public class SessionManager implements SessionManagerMBean {
username);
long currentTime = CommonDateTimeUtils.currentTime();
TSStatus tsStatus =
- DataNodeAuthUtils.recordPassword(username, password, null, currentTime);
+ DataNodeAuthUtils.recordPasswordHistory(username, password, password, currentTime);
if (tsStatus.getCode() != TSStatusCode.SUCCESS_STATUS.getStatusCode()) {
openSessionResp
.sessionId(-1)
diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/RelationalAuthorStatement.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/RelationalAuthorStatement.java
index 4e2b4597672..a66d6f022c0 100644
--- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/RelationalAuthorStatement.java
+++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/sql/ast/RelationalAuthorStatement.java
@@ -20,6 +20,7 @@ package org.apache.iotdb.db.queryengine.plan.relational.sql.ast;
import org.apache.iotdb.common.rpc.thrift.TSStatus;
import org.apache.iotdb.commons.auth.entity.PrivilegeType;
+import org.apache.iotdb.commons.utils.AuthUtils;
import org.apache.iotdb.commons.utils.CommonDateTimeUtils;
import org.apache.iotdb.db.queryengine.plan.analyze.QueryType;
import org.apache.iotdb.db.queryengine.plan.relational.type.AuthorRType;
@@ -261,14 +262,21 @@ public class RelationalAuthorStatement extends Statement {
return onCreateUserSuccess();
} else if (authorType == AuthorRType.UPDATE_USER) {
return onUpdateUserSuccess();
+ } else if (authorType == AuthorRType.DROP_USER) {
+ return onDropUserSuccess();
}
return null;
}
private TSStatus onCreateUserSuccess() {
+ // the old password is expected to be encrypted during updates, so we also encrypt it here to
+ // keep consistency
TSStatus tsStatus =
- DataNodeAuthUtils.recordPassword(
- userName, password, null, CommonDateTimeUtils.currentTime());
+ DataNodeAuthUtils.recordPasswordHistory(
+ userName,
+ password,
+ AuthUtils.encryptPassword(password),
+ CommonDateTimeUtils.currentTime());
try {
RpcUtils.verifySuccess(tsStatus);
} catch (StatementExecutionException e) {
@@ -279,7 +287,7 @@ public class RelationalAuthorStatement extends Statement {
private TSStatus onUpdateUserSuccess() {
TSStatus tsStatus =
- DataNodeAuthUtils.recordPassword(
+ DataNodeAuthUtils.recordPasswordHistory(
userName, password, oldPassword, CommonDateTimeUtils.currentTime());
try {
RpcUtils.verifySuccess(tsStatus);
@@ -289,6 +297,16 @@ public class RelationalAuthorStatement extends Statement {
return null;
}
+ private TSStatus onDropUserSuccess() {
+ TSStatus tsStatus = DataNodeAuthUtils.deletePasswordHistory(userName);
+ try {
+ RpcUtils.verifySuccess(tsStatus);
+ } catch (StatementExecutionException e) {
+ return new TSStatus(e.getStatusCode()).setMessage(e.getMessage());
+ }
+ return null;
+ }
+
public String getOldPassword() {
return oldPassword;
}
diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/sys/AuthorStatement.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/sys/AuthorStatement.java
index 1cc2b3d499c..e34f289b742 100644
--- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/sys/AuthorStatement.java
+++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/sys/AuthorStatement.java
@@ -22,6 +22,7 @@ package org.apache.iotdb.db.queryengine.plan.statement.sys;
import org.apache.iotdb.common.rpc.thrift.TSStatus;
import org.apache.iotdb.commons.auth.entity.PrivilegeType;
import org.apache.iotdb.commons.path.PartialPath;
+import org.apache.iotdb.commons.utils.AuthUtils;
import org.apache.iotdb.commons.utils.CommonDateTimeUtils;
import org.apache.iotdb.db.auth.AuthorityChecker;
import org.apache.iotdb.db.queryengine.plan.analyze.QueryType;
@@ -360,14 +361,21 @@ public class AuthorStatement extends Statement implements IConfigStatement {
return onCreateUserSuccess();
} else if (authorType == AuthorType.UPDATE_USER) {
return onUpdateUserSuccess();
+ } else if (authorType == AuthorType.DROP_USER) {
+ return onDropUserSuccess();
}
return null;
}
private TSStatus onCreateUserSuccess() {
+ // the old password is expected to be encrypted during updates, so we also encrypt it here to
+ // keep consistency
TSStatus tsStatus =
- DataNodeAuthUtils.recordPassword(
- userName, password, null, CommonDateTimeUtils.currentTime());
+ DataNodeAuthUtils.recordPasswordHistory(
+ userName,
+ password,
+ AuthUtils.encryptPassword(password),
+ CommonDateTimeUtils.currentTime());
try {
RpcUtils.verifySuccess(tsStatus);
} catch (StatementExecutionException e) {
@@ -378,7 +386,7 @@ public class AuthorStatement extends Statement implements IConfigStatement {
private TSStatus onUpdateUserSuccess() {
TSStatus tsStatus =
- DataNodeAuthUtils.recordPassword(
+ DataNodeAuthUtils.recordPasswordHistory(
userName, newPassword, password, CommonDateTimeUtils.currentTime());
try {
RpcUtils.verifySuccess(tsStatus);
@@ -387,4 +395,14 @@ public class AuthorStatement extends Statement implements IConfigStatement {
}
return null;
}
+
+ private TSStatus onDropUserSuccess() {
+ TSStatus tsStatus = DataNodeAuthUtils.deletePasswordHistory(userName);
+ try {
+ RpcUtils.verifySuccess(tsStatus);
+ } catch (StatementExecutionException e) {
+ return new TSStatus(e.getStatusCode()).setMessage(e.getMessage());
+ }
+ return null;
+ }
}
diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/utils/DataNodeAuthUtils.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/utils/DataNodeAuthUtils.java
index 180fb3e3e68..dcc95f366c8 100644
--- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/utils/DataNodeAuthUtils.java
+++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/utils/DataNodeAuthUtils.java
@@ -40,6 +40,7 @@ import org.apache.iotdb.db.queryengine.plan.execution.IQueryExecution;
import org.apache.iotdb.db.queryengine.plan.parser.StatementGenerator;
import org.apache.iotdb.db.queryengine.plan.statement.Statement;
import org.apache.iotdb.db.queryengine.plan.statement.crud.InsertRowStatement;
+import org.apache.iotdb.db.queryengine.plan.statement.metadata.DeleteTimeSeriesStatement;
import org.apache.iotdb.rpc.TSStatusCode;
import org.apache.tsfile.enums.TSDataType;
@@ -50,6 +51,7 @@ import org.slf4j.LoggerFactory;
import java.nio.charset.StandardCharsets;
import java.time.ZoneId;
+import java.util.Arrays;
import java.util.Date;
import java.util.Optional;
@@ -144,13 +146,13 @@ public class DataNodeAuthUtils {
currentTimeMillis);
}
- public static TSStatus recordPassword(
+ public static TSStatus recordPasswordHistory(
String username, String password, String oldPassword, long timeToRecord) {
InsertRowStatement insertRowStatement = new InsertRowStatement();
try {
insertRowStatement.setDevicePath(
new PartialPath(SystemConstant.PREFIX_PASSWORD_HISTORY + ".`_" + username + "`"));
- insertRowStatement.setTime(CommonDateTimeUtils.currentTime());
+ insertRowStatement.setTime(timeToRecord);
insertRowStatement.setMeasurements(new String[] {"password", "oldPassword"});
insertRowStatement.setValues(
new Object[] {
@@ -195,4 +197,52 @@ public class DataNodeAuthUtils {
}
}
}
+
+ public static TSStatus deletePasswordHistory(String username) {
+ DeleteTimeSeriesStatement deleteTimeSeriesStatement = new DeleteTimeSeriesStatement();
+ try {
+ PartialPath devicePath =
+ new PartialPath(SystemConstant.PREFIX_PASSWORD_HISTORY + ".`_" + username + "`");
+ deleteTimeSeriesStatement.setPathPatternList(
+ Arrays.asList(
+ devicePath.concatAsMeasurementPath("password"),
+ devicePath.concatAsMeasurementPath("oldPassword")));
+ } catch (IllegalPathException ignored) {
+ return new TSStatus(TSStatusCode.INTERNAL_SERVER_ERROR.getStatusCode())
+ .setMessage(
+ "Cannot delete password history for "
+ + username
+ + " because the path will be illegal");
+ }
+
+ long queryId = -1;
+ try {
+ SessionInfo sessionInfo =
+ new SessionInfo(0, AuthorityChecker.SUPER_USER, ZoneId.systemDefault());
+
+ queryId = SessionManager.getInstance().requestQueryId();
+ ExecutionResult result =
+ Coordinator.getInstance()
+ .executeForTreeModel(
+ deleteTimeSeriesStatement,
+ queryId,
+ sessionInfo,
+ "",
+ ClusterPartitionFetcher.getInstance(),
+ ClusterSchemaFetcher.getInstance());
+ return result.status;
+ } catch (Exception e) {
+ if (CommonDescriptor.getInstance().getConfig().isMayBypassPasswordCheckInException()) {
+ return StatusUtils.OK;
+ }
+ LOGGER.error("Cannot delete password history for {} because {}", username, e.getMessage());
+ return new TSStatus(TSStatusCode.INTERNAL_SERVER_ERROR.getStatusCode())
+ .setMessage(
+ "The server is not ready for this operation, please check the server log for details");
+ } finally {
+ if (queryId != -1) {
+ Coordinator.getInstance().cleanupQueryExecution(queryId);
+ }
+ }
+ }
}