This is an automated email from the ASF dual-hosted git repository.
jiangtian pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/iotdb.git
The following commit(s) were added to refs/heads/master by this push:
new d289944750f Fixed lock error messages and default values in
LoginLockManager. Corrected table model unlock syntax. Resolved errors in
security administrator unlock functionality. (#16579)
d289944750f is described below
commit d289944750f72df323e68129fb3346661928b42b
Author: Hongzhi Gao <[email protected]>
AuthorDate: Tue Oct 14 16:55:25 2025 +0800
Fixed lock error messages and default values in LoginLockManager. Corrected
table model unlock syntax. Resolved errors in security administrator unlock
functionality. (#16579)
---
.../iotdb/auth/it/IoTDBLoginLockManagerIT.java | 6 +-
.../consensus/request/ConfigPhysicalPlanType.java | 2 +
.../persistence/auth/AuthorPlanExecutor.java | 4 +
.../persistence/executor/ConfigPlanExecutor.java | 2 +
.../org/apache/iotdb/db/auth/LoginLockManager.java | 25 +++----
.../apache/iotdb/db/auth/LoginLockManagerTest.java | 85 +++++++++-------------
6 files changed, 59 insertions(+), 65 deletions(-)
diff --git
a/integration-test/src/test/java/org/apache/iotdb/auth/it/IoTDBLoginLockManagerIT.java
b/integration-test/src/test/java/org/apache/iotdb/auth/it/IoTDBLoginLockManagerIT.java
index 1fc09e026d5..fa820d4367b 100644
---
a/integration-test/src/test/java/org/apache/iotdb/auth/it/IoTDBLoginLockManagerIT.java
+++
b/integration-test/src/test/java/org/apache/iotdb/auth/it/IoTDBLoginLockManagerIT.java
@@ -101,7 +101,9 @@ public class IoTDBLoginLockManagerIT extends
AbstractScriptIT {
login("test", "wrong", new String[] {authFailedMsg}, 1);
}
// account was locked
- login("test", "test", new String[] {authFailedMsg}, 1);
+ String lockedMsg =
+ "ErrorCan't execute sql because822: Account is blocked due to
consecutive failed logins.";
+ login("test", "test", new String[] {lockedMsg}, 1);
// unlock user-lock manual
session.executeNonQueryStatement("ALTER USER test ACCOUNT UNLOCK");
login("test", "test", new String[] {loginSuccessMsg}, 1);
@@ -111,7 +113,7 @@ public class IoTDBLoginLockManagerIT extends
AbstractScriptIT {
login("test", "wrong", new String[] {authFailedMsg}, 1);
}
// account was locked
- login("test", "test", new String[] {authFailedMsg}, 1);
+ login("test", "test", new String[] {lockedMsg}, 1);
// unlock user-lock manual
session.executeNonQueryStatement("ALTER USER test @ '127.0.0.1' ACCOUNT
UNLOCK");
login("test", "test", new String[] {loginSuccessMsg}, 1);
diff --git
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/ConfigPhysicalPlanType.java
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/ConfigPhysicalPlanType.java
index dee820d825d..77ad500dd2b 100644
---
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/ConfigPhysicalPlanType.java
+++
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/ConfigPhysicalPlanType.java
@@ -135,6 +135,7 @@ public enum ConfigPhysicalPlanType {
CreateUserWithRawPassword((short) 638),
UpdateUserMaxSession((short) 639),
UpdateUserMinSession((short) 640),
+ AccountUnlock((short) 641),
/** Table Author */
RCreateUser((short) 641),
@@ -172,6 +173,7 @@ public enum ConfigPhysicalPlanType {
RListRolePrivilege((short) 672),
RUpdateUserMaxSession((short) 673),
RUpdateUserMinSession((short) 674),
+ RAccountUnlock((short) 675),
/** Function. */
CreateFunction((short) 700),
diff --git
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/auth/AuthorPlanExecutor.java
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/auth/AuthorPlanExecutor.java
index 6eee2481d5b..1056ad735cf 100644
---
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/auth/AuthorPlanExecutor.java
+++
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/auth/AuthorPlanExecutor.java
@@ -146,6 +146,8 @@ public class AuthorPlanExecutor implements
IAuthorPlanExecutor {
case DropRole:
authorizer.deleteRole(roleName);
break;
+ case AccountUnlock:
+ break;
case GrantRole:
for (int permission : permissions) {
PrivilegeType priv = PrivilegeType.values()[permission];
@@ -246,6 +248,8 @@ public class AuthorPlanExecutor implements
IAuthorPlanExecutor {
case RRenameUser:
authorizer.renameUser(userName, newUsername);
break;
+ case RAccountUnlock:
+ break;
case RDropRole:
authorizer.deleteRole(roleName);
break;
diff --git
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/executor/ConfigPlanExecutor.java
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/executor/ConfigPlanExecutor.java
index aa3504ac6d6..d86169e14ef 100644
---
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/executor/ConfigPlanExecutor.java
+++
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/executor/ConfigPlanExecutor.java
@@ -461,6 +461,7 @@ public class ConfigPlanExecutor {
case DropUser:
case DropUserV2:
case DropRole:
+ case AccountUnlock:
case GrantRole:
case GrantUser:
case GrantRoleToUser:
@@ -493,6 +494,7 @@ public class ConfigPlanExecutor {
case RUpdateUserV2:
case RUpdateUserMaxSession:
case RUpdateUserMinSession:
+ case RAccountUnlock:
case RGrantUserRole:
case RGrantRoleAny:
case RGrantUserAny:
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/auth/LoginLockManager.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/auth/LoginLockManager.java
index eaf43d65ca6..05e80cc23cc 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/auth/LoginLockManager.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/auth/LoginLockManager.java
@@ -68,30 +68,27 @@ public class LoginLockManager {
public LoginLockManager(
int failedLoginAttempts, int failedLoginAttemptsPerUser, int
passwordLockTimeMinutes) {
// Set and validate failedLoginAttempts (IP level)
- if (failedLoginAttempts == -1) {
+ if (failedLoginAttempts <= 0) {
this.failedLoginAttempts = -1; // Completely disable IP-level
restrictions
+ LOGGER.info("IP-level login attempts disabled (set to {})",
failedLoginAttempts);
} else {
- this.failedLoginAttempts = failedLoginAttempts >= 1 ?
failedLoginAttempts : 5;
+ this.failedLoginAttempts = failedLoginAttempts;
}
// Set and validate failedLoginAttemptsPerUser (user level)
- if (failedLoginAttemptsPerUser == -1) {
- // If IP-level is enabled, user-level cannot be disabled
- if (this.failedLoginAttempts != -1) {
- this.failedLoginAttemptsPerUser = 1000; // Default user-level value
- LOGGER.error(
- "User-level login attempts cannot be disabled when IP-level is
enabled. "
- + "Setting user-level attempts to default (1000)");
- } else {
- this.failedLoginAttemptsPerUser = -1; // Both are disabled
- }
+ if (failedLoginAttemptsPerUser <= 0) {
+ this.failedLoginAttemptsPerUser = -1; // Disable user-level restrictions
+ LOGGER.info("User-level login attempts disabled (set to {})",
failedLoginAttemptsPerUser);
} else {
- this.failedLoginAttemptsPerUser =
- failedLoginAttemptsPerUser >= 1 ? failedLoginAttemptsPerUser : 1000;
+ this.failedLoginAttemptsPerUser = failedLoginAttemptsPerUser;
}
// Set and validate passwordLockTimeMinutes (default 10, minimum 1)
this.passwordLockTimeMinutes = passwordLockTimeMinutes >= 1 ?
passwordLockTimeMinutes : 10;
+ if (passwordLockTimeMinutes < 1) {
+ LOGGER.warn(
+ "Invalid lock time value ({}), reset to default (10 minutes)",
passwordLockTimeMinutes);
+ }
// Log final effective configuration
LOGGER.info(
diff --git
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/auth/LoginLockManagerTest.java
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/auth/LoginLockManagerTest.java
index 650d88c8690..535ec462496 100644
---
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/auth/LoginLockManagerTest.java
+++
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/auth/LoginLockManagerTest.java
@@ -70,32 +70,42 @@ public class LoginLockManagerTest {
assertEquals(1000, getField(normal, "failedLoginAttemptsPerUser"));
assertEquals(10, getField(normal, "passwordLockTimeMinutes"));
- // 2. Test disabling both IP-level and user-level restrictions
- LoginLockManager disableBoth = new LoginLockManager(-1, -1, 10);
- assertEquals(-1, getField(disableBoth, "failedLoginAttempts"));
- assertEquals(-1, getField(disableBoth, "failedLoginAttemptsPerUser"));
-
- // 3. Test enabling only user-level restriction
- LoginLockManager userOnly = new LoginLockManager(-1, 5, 10);
- assertEquals(-1, getField(userOnly, "failedLoginAttempts"));
- assertEquals(5, getField(userOnly, "failedLoginAttemptsPerUser"));
-
- // 4. Test that enabling IP-level automatically enables user-level with
default value
- LoginLockManager ipEnable = new LoginLockManager(3, -1, 10);
- assertEquals(3, getField(ipEnable, "failedLoginAttempts"));
- assertEquals(1000, getField(ipEnable, "failedLoginAttemptsPerUser"));
-
- // 5. Test invalid IP attempts value falls back to default (5)
- LoginLockManager invalidIp = new LoginLockManager(0, -1, 10);
- assertEquals(5, getField(invalidIp, "failedLoginAttempts"));
-
- // 6. Test invalid user attempts value falls back to default (1000)
- LoginLockManager invalidUser = new LoginLockManager(-1, 0, 10);
- assertEquals(1000, getField(invalidUser, "failedLoginAttemptsPerUser"));
-
- // 7. Test invalid lock time value falls back to default (10 minutes)
- LoginLockManager invalidTime = new LoginLockManager(5, 1000, 0);
- assertEquals(10, getField(invalidTime, "passwordLockTimeMinutes"));
+ // 2. Test disabling both IP-level and user-level restrictions (using -1
or 0)
+ LoginLockManager disableBoth1 = new LoginLockManager(-1, -1, 10);
+ assertEquals(-1, getField(disableBoth1, "failedLoginAttempts"));
+ assertEquals(-1, getField(disableBoth1, "failedLoginAttemptsPerUser"));
+
+ LoginLockManager disableBoth2 = new LoginLockManager(0, 0, 10);
+ assertEquals(-1, getField(disableBoth2, "failedLoginAttempts"));
+ assertEquals(-1, getField(disableBoth2, "failedLoginAttemptsPerUser"));
+
+ // 3. Test mixed scenarios (IP enabled + user disabled, and vice versa)
+ LoginLockManager ipEnabledUserDisabled = new LoginLockManager(3, 0, 10);
+ assertEquals(3, getField(ipEnabledUserDisabled, "failedLoginAttempts"));
+ assertEquals(-1, getField(ipEnabledUserDisabled,
"failedLoginAttemptsPerUser"));
+
+ LoginLockManager ipDisabledUserEnabled = new LoginLockManager(-1, 5, 10);
+ assertEquals(-1, getField(ipDisabledUserEnabled, "failedLoginAttempts"));
+ assertEquals(5, getField(ipDisabledUserEnabled,
"failedLoginAttemptsPerUser"));
+
+ // 4. Test invalid positive values fall back to defaults
+ LoginLockManager invalidIp =
+ new LoginLockManager(-5, 1000, 10); // Negative treated as disable (-1)
+ assertEquals(-1, getField(invalidIp, "failedLoginAttempts"));
+
+ LoginLockManager invalidUser =
+ new LoginLockManager(5, -2, 10); // Negative treated as disable (-1)
+ assertEquals(-1, getField(invalidUser, "failedLoginAttemptsPerUser"));
+
+ // 5. Test lock time validation
+ LoginLockManager zeroLockTime = new LoginLockManager(5, 1000, 0);
+ assertEquals(10, getField(zeroLockTime, "passwordLockTimeMinutes"));
+
+ LoginLockManager negativeLockTime = new LoginLockManager(5, 1000, -5);
+ assertEquals(10, getField(negativeLockTime, "passwordLockTimeMinutes"));
+
+ LoginLockManager customLockTime = new LoginLockManager(5, 1000, 30);
+ assertEquals(30, getField(customLockTime, "passwordLockTimeMinutes"));
}
private int getField(LoginLockManager manager, String fieldName) {
@@ -340,29 +350,6 @@ public class LoginLockManagerTest {
}
// ---------------- Configuration and Invalid Input ----------------
-
- @Test
- public void testInvalidConfigurationDefaults() {
- {
- LoginLockManager invalidConfigManager = new LoginLockManager(-1, 0, -1);
- for (int i = 0; i < 1000; i++) {
- invalidConfigManager.recordFailure(TEST_USER_ID, TEST_IP);
- }
- assertTrue(
- "Should use default config when invalid values provided",
- invalidConfigManager.checkLock(TEST_USER_ID, TEST_IP));
- }
- {
- LoginLockManager invalidConfigManager = new LoginLockManager(-3, 0, -1);
- for (int i = 0; i < 5; i++) {
- invalidConfigManager.recordFailure(TEST_USER_ID, TEST_IP);
- }
- assertTrue(
- "Should use default config when invalid values provided",
- invalidConfigManager.checkLock(TEST_USER_ID, TEST_IP));
- }
- }
-
@Test
public void testNullIpHandling() {
lockManager.recordFailure(TEST_USER_ID, null);