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

Reply via email to