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

HTHou 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 c6afaf54957 Fix table model set configuration audit logging (#18412)
c6afaf54957 is described below

commit c6afaf549571e8a9900a39197336251b3f03e8d6
Author: libo <[email protected]>
AuthorDate: Thu Aug 6 16:43:55 2026 +0800

    Fix table model set configuration audit logging (#18412)
---
 .../execution/config/TableConfigTaskVisitor.java   |   3 +
 .../relational/security/AccessControlImpl.java     |  22 +++-
 .../relational/security/AccessControlImplTest.java | 119 +++++++++++++++++++++
 3 files changed, 143 insertions(+), 1 deletion(-)

diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/TableConfigTaskVisitor.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/TableConfigTaskVisitor.java
index 5f0ff823972..1ff61937f4b 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/TableConfigTaskVisitor.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/TableConfigTaskVisitor.java
@@ -1074,6 +1074,9 @@ public class TableConfigTaskVisitor implements 
AstVisitor<IConfigTask, MPPQueryC
           setConfigurationStatement.getNeededPrivileges(),
           context);
     } catch (IOException e) {
+      DNAuditLogger.getInstance()
+          .recordObjectAuthenticationAuditLog(
+              
context.setResult(false).setAuditLogOperation(AuditLogOperation.CONTROL), () -> 
"");
       throw new 
AccessDeniedException(DataNodeQueryMessages.FAILED_TO_CHECK_CONFIG_ITEM_PERMISSION);
     }
     setConfigurationStatement.checkSomeParametersKeepConsistentInCluster();
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/AccessControlImpl.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/AccessControlImpl.java
index bc20a7d972f..0db343b44d9 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/AccessControlImpl.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/AccessControlImpl.java
@@ -40,6 +40,7 @@ import org.apache.iotdb.rpc.TSStatusCode;
 
 import org.apache.tsfile.file.metadata.IDeviceID;
 
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
@@ -569,10 +570,29 @@ public class AccessControlImpl implements AccessControl {
   @Override
   public void checkMissingPrivileges(
       String username, Collection<PrivilegeType> privilegeTypes, IAuditEntity 
auditEntity) {
+    List<PrivilegeType> relatedPrivileges = new ArrayList<>(privilegeTypes);
     if (AuthorityChecker.SUPER_USER_ID == auditEntity.getUserId()) {
+      recordMissingPrivilegesAuditLog(auditEntity, relatedPrivileges, true);
       return;
     }
-    authChecker.checkGlobalPrivileges(username, privilegeTypes, auditEntity);
+    try {
+      authChecker.checkGlobalPrivileges(username, privilegeTypes, auditEntity);
+      recordMissingPrivilegesAuditLog(auditEntity, relatedPrivileges, true);
+    } catch (AccessDeniedException e) {
+      recordMissingPrivilegesAuditLog(auditEntity, relatedPrivileges, false);
+      throw e;
+    }
+  }
+
+  private static void recordMissingPrivilegesAuditLog(
+      IAuditEntity auditEntity, List<PrivilegeType> privilegeTypes, boolean 
result) {
+    DNAuditLogger.getInstance()
+        .recordObjectAuthenticationAuditLog(
+            auditEntity
+                .setResult(result)
+                .setAuditLogOperation(AuditLogOperation.CONTROL)
+                .setPrivilegeTypes(privilegeTypes),
+            () -> "");
   }
 
   @Override
diff --git 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/security/AccessControlImplTest.java
 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/security/AccessControlImplTest.java
new file mode 100644
index 00000000000..73e3fe6f6a0
--- /dev/null
+++ 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/security/AccessControlImplTest.java
@@ -0,0 +1,119 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.db.queryengine.plan.relational.security;
+
+import org.apache.iotdb.commons.audit.AuditEventType;
+import org.apache.iotdb.commons.audit.AuditLogOperation;
+import org.apache.iotdb.commons.auth.entity.PrivilegeType;
+import org.apache.iotdb.commons.auth.entity.User;
+import org.apache.iotdb.commons.exception.auth.AccessDeniedException;
+import org.apache.iotdb.db.auth.AuthorityChecker;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.Collections;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyCollection;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+public class AccessControlImplTest {
+
+  private static final List<PrivilegeType> AUDIT_PRIVILEGE =
+      Collections.singletonList(PrivilegeType.AUDIT);
+  private static final long USER_ID = User.INTERNAL_USER_END_ID + 1;
+  private static final String USER_NAME = "user";
+
+  @Before
+  public void setUp() {
+    AuthorityChecker.getAuthorityFetcher().getAuthorCache().invalidAllCache();
+  }
+
+  @After
+  public void tearDown() {
+    AuthorityChecker.getAuthorityFetcher().getAuthorCache().invalidAllCache();
+  }
+
+  @Test
+  public void testSuperUserMissingPrivilegeCheckIsAudited() {
+    ITableAuthChecker authChecker = mock(ITableAuthChecker.class);
+    AccessControlImpl accessControl =
+        new AccessControlImpl(authChecker, new TreeAccessCheckVisitor());
+    TreeAccessCheckContext auditContext =
+        new TreeAccessCheckContext(AuthorityChecker.SUPER_USER_ID, 
AuthorityChecker.SUPER_USER, "");
+
+    accessControl.checkMissingPrivileges(
+        AuthorityChecker.SUPER_USER, AUDIT_PRIVILEGE, auditContext);
+
+    assertAuditContext(auditContext, true);
+    verify(authChecker, never()).checkGlobalPrivileges(anyString(), 
anyCollection(), any());
+  }
+
+  @Test
+  public void testUserWithAuditPrivilegeCheckIsAudited() {
+    User user = new User(USER_NAME, "password", USER_ID);
+    user.grantSysPrivilege(PrivilegeType.AUDIT, false);
+    
AuthorityChecker.getAuthorityFetcher().getAuthorCache().putUserCache(USER_NAME, 
user);
+    AccessControlImpl accessControl =
+        new AccessControlImpl(new ITableAuthCheckerImpl(), new 
TreeAccessCheckVisitor());
+    TreeAccessCheckContext auditContext = new TreeAccessCheckContext(USER_ID, 
USER_NAME, "");
+
+    accessControl.checkMissingPrivileges(USER_NAME, AUDIT_PRIVILEGE, 
auditContext);
+
+    assertAuditContext(auditContext, true);
+  }
+
+  @Test
+  public void testMissingPrivilegeFailureIsAudited() {
+    User user = new User(USER_NAME, "password", USER_ID);
+    
AuthorityChecker.getAuthorityFetcher().getAuthorCache().putUserCache(USER_NAME, 
user);
+    AccessControlImpl accessControl =
+        new AccessControlImpl(new ITableAuthCheckerImpl(), new 
TreeAccessCheckVisitor());
+    TreeAccessCheckContext auditContext = new TreeAccessCheckContext(USER_ID, 
USER_NAME, "");
+
+    assertThrows(
+        AccessDeniedException.class,
+        () -> accessControl.checkMissingPrivileges(USER_NAME, AUDIT_PRIVILEGE, 
auditContext));
+
+    assertAuditContext(auditContext, false);
+  }
+
+  private static void assertAuditContext(
+      TreeAccessCheckContext auditContext, boolean expectedResult) {
+    assertEquals(AuditEventType.OBJECT_AUTHENTICATION, 
auditContext.getAuditEventType());
+    assertEquals(AuditLogOperation.CONTROL, 
auditContext.getAuditLogOperation());
+    assertEquals(AUDIT_PRIVILEGE, auditContext.getPrivilegeTypes());
+    if (expectedResult) {
+      assertTrue(auditContext.getResult());
+    } else {
+      assertFalse(auditContext.getResult());
+    }
+  }
+}

Reply via email to