This is an automated email from the ASF dual-hosted git repository.

yongzao 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 18964f41cda Patch for AUDIT privilege authentication on table model 
(#16563)
18964f41cda is described below

commit 18964f41cdad8398ef8d10e36da36d88c90014f2
Author: Yongzao <[email protected]>
AuthorDate: Sun Oct 12 21:05:49 2025 +0800

    Patch for AUDIT privilege authentication on table model (#16563)
---
 .../iotdb/db/it/audit/IoTDBAuditLogBasicIT.java    | 22 +++-----
 .../org/apache/iotdb/db/audit/DNAuditLogger.java   | 66 +++++++++++-----------
 .../relational/security/ITableAuthCheckerImpl.java | 39 ++++++-------
 .../security/TreeAccessCheckVisitor.java           |  2 +-
 4 files changed, 62 insertions(+), 67 deletions(-)

diff --git 
a/integration-test/src/test/java/org/apache/iotdb/db/it/audit/IoTDBAuditLogBasicIT.java
 
b/integration-test/src/test/java/org/apache/iotdb/db/it/audit/IoTDBAuditLogBasicIT.java
index e423b511da4..ba5a9676ea3 100644
--- 
a/integration-test/src/test/java/org/apache/iotdb/db/it/audit/IoTDBAuditLogBasicIT.java
+++ 
b/integration-test/src/test/java/org/apache/iotdb/db/it/audit/IoTDBAuditLogBasicIT.java
@@ -56,9 +56,9 @@ import java.util.stream.Stream;
 @Category({LocalStandaloneIT.class})
 public class IoTDBAuditLogBasicIT {
 
-  private static final long ENSURE_AUDIT_LOG_SLEEP_IN_MS = 250;
+  public static final long ENSURE_AUDIT_LOG_SLEEP_IN_MS = 250;
 
-  private static final List<String> AUDIT_TABLE_COLUMNS =
+  public static final List<String> AUDIT_TABLE_COLUMNS =
       Arrays.asList(
           AbstractAuditLogger.AUDIT_LOG_NODE_ID,
           AbstractAuditLogger.AUDIT_LOG_USER_ID,
@@ -73,18 +73,18 @@ public class IoTDBAuditLogBasicIT {
           AbstractAuditLogger.AUDIT_LOG_SQL_STRING,
           AbstractAuditLogger.AUDIT_LOG_LOG);
 
-  private static final List<String> AUDIT_TABLE_DATA_TYPES =
+  public static final List<String> AUDIT_TABLE_DATA_TYPES =
       Arrays.asList(
           "STRING", "STRING", "STRING", "STRING", "STRING", "STRING", 
"STRING", "STRING", "BOOLEAN",
           "STRING", "STRING", "STRING");
 
-  private static final List<String> AUDIT_TABLE_CATEGORIES =
+  public static final List<String> AUDIT_TABLE_CATEGORIES =
       Arrays.asList(
           "TAG", "TAG", "FIELD", "FIELD", "FIELD", "FIELD", "FIELD", "FIELD", 
"FIELD", "FIELD",
           "FIELD", "FIELD");
 
-  private static final boolean ENABLE_AUDIT_LOG = true;
-  private static final String AUDITABLE_OPERATION_TYPE =
+  public static final boolean ENABLE_AUDIT_LOG = true;
+  public static final String AUDITABLE_OPERATION_TYPE =
       new StringJoiner(",")
           .add(AuditLogOperation.DDL.toString())
           .add(AuditLogOperation.DML.toString())
@@ -92,9 +92,9 @@ public class IoTDBAuditLogBasicIT {
           .add(AuditLogOperation.CONTROL.toString())
           .toString();
 
-  private static final String AUDITABLE_OPERATION_LEVEL = 
PrivilegeLevel.GLOBAL.toString();
+  public static final String AUDITABLE_OPERATION_LEVEL = 
PrivilegeLevel.GLOBAL.toString();
 
-  private static final String AUDITABLE_OPERATION_RESULT = "SUCCESS,FAIL";
+  public static final String AUDITABLE_OPERATION_RESULT = "SUCCESS,FAIL";
 
   @Before
   public void setUp() throws SQLException, InterruptedException {
@@ -135,7 +135,7 @@ public class IoTDBAuditLogBasicIT {
     EnvFactory.getEnv().cleanClusterEnvironment();
   }
 
-  private static void closeConnectionCompletely(Connection connection) throws 
InterruptedException {
+  public static void closeConnectionCompletely(Connection connection) throws 
InterruptedException {
     // Ensure the session conns in test env are closed completely,
     // in order to generate logout audit log
     // TODO: Optimize this func after the close func of connection is optimized
@@ -2378,7 +2378,6 @@ public class IoTDBAuditLogBasicIT {
     Statement statement = connection.createStatement();
     for (String sql : TREE_MODEL_AUDIT_SQLS_USER_ROOT) {
       statement.execute(sql);
-      TimeUnit.MILLISECONDS.sleep(ENSURE_AUDIT_LOG_SLEEP_IN_MS);
     }
     closeConnectionCompletely(connection);
     connection =
@@ -2386,7 +2385,6 @@ public class IoTDBAuditLogBasicIT {
     statement = connection.createStatement();
     for (String sql : TREE_MODEL_AUDIT_SQLS_USER_USER1) {
       statement.execute(sql);
-      TimeUnit.MILLISECONDS.sleep(ENSURE_AUDIT_LOG_SLEEP_IN_MS);
     }
     closeConnectionCompletely(connection);
     connection =
@@ -2395,7 +2393,6 @@ public class IoTDBAuditLogBasicIT {
     for (String sql : TREE_MODEL_AUDIT_SQLS_USER_USER2) {
       try {
         statement.execute(sql);
-        TimeUnit.MILLISECONDS.sleep(ENSURE_AUDIT_LOG_SLEEP_IN_MS);
       } catch (SQLException e) {
         // Ignore, only record audit log
       }
@@ -2405,7 +2402,6 @@ public class IoTDBAuditLogBasicIT {
     statement = connection.createStatement();
     for (String sql : TREE_MODEL_AUDIT_SQLS_USER_ROOT_FINAL) {
       statement.execute(sql);
-      TimeUnit.MILLISECONDS.sleep(ENSURE_AUDIT_LOG_SLEEP_IN_MS);
     }
     ResultSet resultSet =
         statement.executeQuery("SELECT * FROM root.__audit.log.** ORDER BY 
TIME ALIGN BY DEVICE");
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/audit/DNAuditLogger.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/audit/DNAuditLogger.java
index a8a5280b444..713d79f77d9 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/audit/DNAuditLogger.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/audit/DNAuditLogger.java
@@ -86,9 +86,10 @@ public class DNAuditLogger extends AbstractAuditLogger {
   public static final String PREFIX_PASSWORD_HISTORY = 
"root.__audit.password_history";
   private static final Logger logger = 
LoggerFactory.getLogger(DNAuditLogger.class);
 
-  // TODO: @zhujt20 Optimize the following stupid retry
+  // TODO: @zhujt20 Optimize the following stupid intervals
   private static final int INSERT_RETRY_COUNT = 5;
   private static final int INSERT_RETRY_INTERVAL_MS = 2000;
+  private static final int INSERT_INTERVAL_MS = 50;
 
   private static final IoTDBConfig config = 
IoTDBDescriptor.getInstance().getConfig();
 
@@ -354,49 +355,46 @@ public class DNAuditLogger extends AbstractAuditLogger {
   }
 
   @Override
-  public void log(IAuditEntity auditLogFields, Supplier<String> log) {
+  public synchronized void log(IAuditEntity auditLogFields, Supplier<String> 
log) {
     if (!IS_AUDIT_LOG_ENABLED) {
       return;
     }
-    createViewIfNecessary();
-    if (noNeedInsertAuditLog(auditLogFields)) {
-      return;
-    }
-    long userId = auditLogFields.getUserId();
-    String user = String.valueOf(userId);
-    if (userId == -1) {
-      user = "none";
-    }
-    String dataNodeId = String.valueOf(config.getDataNodeId());
-    InsertRowStatement statement;
     try {
-      statement =
+      createViewIfNecessary();
+      if (noNeedInsertAuditLog(auditLogFields)) {
+        return;
+      }
+      long userId = auditLogFields.getUserId();
+      String user = String.valueOf(userId);
+      if (userId == -1) {
+        user = "none";
+      }
+      String dataNodeId = String.valueOf(config.getDataNodeId());
+      InsertRowStatement statement =
           generateInsertStatement(
               auditLogFields,
               log.get(),
               DEVICE_PATH_CACHE.getPartialPath(String.format(AUDIT_LOG_DEVICE, 
dataNodeId, user)));
-    } catch (IllegalPathException e) {
-      logger.error("Failed to log audit events because ", e);
-      return;
-    }
-    for (int retry = 0; retry < INSERT_RETRY_COUNT; retry++) {
-      ExecutionResult insertResult =
-          coordinator.executeForTreeModel(
-              statement,
-              SESSION_MANAGER.requestQueryId(),
-              sessionInfo,
-              "",
-              ClusterPartitionFetcher.getInstance(),
-              SCHEMA_FETCHER);
-      if (insertResult.status.getCode() == 
TSStatusCode.SUCCESS_STATUS.getStatusCode()) {
-        return;
-      }
-      try {
+      for (int retry = 0; retry < INSERT_RETRY_COUNT; retry++) {
+        ExecutionResult insertResult =
+            coordinator.executeForTreeModel(
+                statement,
+                SESSION_MANAGER.requestQueryId(),
+                sessionInfo,
+                "",
+                ClusterPartitionFetcher.getInstance(),
+                SCHEMA_FETCHER);
+        if (insertResult.status.getCode() == 
TSStatusCode.SUCCESS_STATUS.getStatusCode()) {
+          TimeUnit.MILLISECONDS.sleep(INSERT_INTERVAL_MS);
+          return;
+        }
         TimeUnit.MILLISECONDS.sleep(INSERT_RETRY_INTERVAL_MS);
-      } catch (InterruptedException e) {
-        Thread.currentThread().interrupt();
-        logger.error("Audit log insertion retry sleep was interrupted", e);
       }
+    } catch (InterruptedException e) {
+      Thread.currentThread().interrupt();
+      logger.warn("[AUDIT] Audit log insertion retry sleep was interrupted 
because", e);
+    } catch (Exception e) {
+      logger.warn("[AUDIT] Failed to log audit events because", e);
     }
     AuditEventType type = auditLogFields.getAuditEventType();
     if (isLoginEvent(type)) {
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/ITableAuthCheckerImpl.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/ITableAuthCheckerImpl.java
index 29fc704d85f..d1f60445295 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/ITableAuthCheckerImpl.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/ITableAuthCheckerImpl.java
@@ -66,23 +66,19 @@ public class ITableAuthCheckerImpl implements 
ITableAuthChecker {
     }
 
     if (TABLE_MODEL_AUDIT_DATABASE.equalsIgnoreCase(databaseName)) {
-      if (AuthorityChecker.checkSystemPermission(userName, 
PrivilegeType.AUDIT)) {
-        recordAuditLog(
-            auditEntity
-                .setAuditLogOperation(AuditLogOperation.QUERY)
-                .setPrivilegeType(PrivilegeType.READ_SCHEMA)
-                .setResult(true),
-            () -> databaseName);
+      // The audit database only requires audit privilege
+      boolean hasAuditPrivilege =
+          AuthorityChecker.checkSystemPermission(userName, 
PrivilegeType.AUDIT);
+      recordAuditLog(
+          auditEntity
+              .setAuditLogOperation(AuditLogOperation.QUERY)
+              .setPrivilegeType(PrivilegeType.AUDIT)
+              .setResult(hasAuditPrivilege),
+          () -> databaseName);
+      if (hasAuditPrivilege) {
         return;
-      } else {
-        recordAuditLog(
-            auditEntity
-                .setAuditLogOperation(AuditLogOperation.QUERY)
-                .setPrivilegeType(PrivilegeType.READ_SCHEMA)
-                .setResult(false),
-            () -> databaseName);
-        throw new AccessDeniedException("DATABASE " + databaseName);
       }
+      throw new AccessDeniedException("DATABASE " + databaseName);
     }
 
     if (AuthorityChecker.checkSystemPermission(userName, 
PrivilegeType.SYSTEM)) {
@@ -341,14 +337,19 @@ public class ITableAuthCheckerImpl implements 
ITableAuthChecker {
     }
 
     String databaseName = tableName.getDatabaseName();
-    if (TABLE_MODEL_AUDIT_DATABASE.equalsIgnoreCase(databaseName)
-        && !AuthorityChecker.checkSystemPermission(userName, 
PrivilegeType.AUDIT)) {
+    if (TABLE_MODEL_AUDIT_DATABASE.equalsIgnoreCase(databaseName)) {
+      // The audit table only requires audit privilege
+      boolean hasAuditPrivilege =
+          AuthorityChecker.checkSystemPermission(userName, 
PrivilegeType.AUDIT);
       recordAuditLog(
           auditEntity
               .setAuditLogOperation(AuditLogOperation.QUERY)
-              .setPrivilegeType(PrivilegeType.READ_SCHEMA)
-              .setResult(false),
+              .setPrivilegeType(PrivilegeType.AUDIT)
+              .setResult(hasAuditPrivilege),
           tableName::getObjectName);
+      if (hasAuditPrivilege) {
+        return;
+      }
       throw new AccessDeniedException("TABLE " + tableName);
     }
 
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/TreeAccessCheckVisitor.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/TreeAccessCheckVisitor.java
index 4ffa2c9a5f9..287b2942ccb 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/TreeAccessCheckVisitor.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/TreeAccessCheckVisitor.java
@@ -1900,7 +1900,7 @@ public class TreeAccessCheckVisitor extends 
StatementVisitor<TSStatus, TreeAcces
     return AuthorityChecker.getTSStatus(false, "Only the admin user can 
perform this operation");
   }
 
-  private static void recordObjectAuthenticationAuditLog(
+  protected static void recordObjectAuthenticationAuditLog(
       IAuditEntity auditEntity, Supplier<String> auditObject) {
     AUDIT_LOGGER.log(
         auditEntity.setAuditEventType(AuditEventType.OBJECT_AUTHENTICATION),

Reply via email to