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 85711da2091 Fix table function audit operation type (#18351)
85711da2091 is described below
commit 85711da209127293126ba85ee91dbf748058d70d
Author: Haonan <[email protected]>
AuthorDate: Thu Jul 30 10:01:22 2026 +0800
Fix table function audit operation type (#18351)
---
.../execution/config/TableConfigTaskVisitor.java | 4 +-
.../plan/relational/security/AccessControl.java | 13 ++++++
.../relational/security/AccessControlImpl.java | 11 +++++
.../relational/security/AllowAllAccessControl.java | 7 +++
.../relational/security/ITableAuthChecker.java | 13 ++++++
.../relational/security/ITableAuthCheckerImpl.java | 38 +++++++++++++++-
.../pipe/event/PipeTsFileInsertionEventTest.java | 7 +++
.../plan/relational/analyzer/AuthTest.java | 51 ++++++++++++++++++++++
8 files changed, 140 insertions(+), 4 deletions(-)
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 820e4aa4075..3e2eb129dc8 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
@@ -1659,7 +1659,7 @@ public class TableConfigTaskVisitor implements
AstVisitor<IConfigTask, MPPQueryC
@Override
public IConfigTask visitCreateFunction(CreateFunction node, MPPQueryContext
context) {
context.setQueryType(QueryType.OTHER);
- accessControl.checkUserGlobalSysPrivilege(context);
+ accessControl.checkUserGlobalSysPrivilege(context, AuditLogOperation.DDL,
node::getUdfName);
if (node.getUriString().map(ExecutableManager::isUriTrusted).orElse(true))
{
// 1. user specified uri and that uri is trusted
// 2. user doesn't specify uri
@@ -1679,7 +1679,7 @@ public class TableConfigTaskVisitor implements
AstVisitor<IConfigTask, MPPQueryC
@Override
public IConfigTask visitDropFunction(DropFunction node, MPPQueryContext
context) {
context.setQueryType(QueryType.OTHER);
- accessControl.checkUserGlobalSysPrivilege(context);
+ accessControl.checkUserGlobalSysPrivilege(context, AuditLogOperation.DDL,
node::getUdfName);
return new DropFunctionTask(Model.TABLE, node.getUdfName());
}
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/AccessControl.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/AccessControl.java
index 95b1786c734..4ee69aa986c 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/AccessControl.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/AccessControl.java
@@ -20,6 +20,7 @@
package org.apache.iotdb.db.queryengine.plan.relational.security;
import org.apache.iotdb.common.rpc.thrift.TSStatus;
+import org.apache.iotdb.commons.audit.AuditLogOperation;
import org.apache.iotdb.commons.audit.IAuditEntity;
import org.apache.iotdb.commons.auth.entity.PrivilegeType;
import org.apache.iotdb.commons.exception.auth.AccessDeniedException;
@@ -204,6 +205,18 @@ public interface AccessControl {
*/
void checkUserGlobalSysPrivilege(IAuditEntity auditEntity);
+ /**
+ * Check if user has global SYSTEM privilege and record the authentication
audit log with the
+ * specified operation and object.
+ *
+ * @param auditEntity records necessary info for audit log
+ * @param auditLogOperation operation type of the statement being authorized
+ * @param auditObject object affected by the statement
+ * @throws AccessDeniedException if not allowed
+ */
+ void checkUserGlobalSysPrivilege(
+ IAuditEntity auditEntity, AuditLogOperation auditLogOperation,
Supplier<String> auditObject);
+
/**
* Check if user has sepecified global privilege
*
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 1a50f15e9cd..9e7e9871807 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
@@ -546,6 +546,17 @@ public class AccessControlImpl implements AccessControl {
}
}
+ @Override
+ public void checkUserGlobalSysPrivilege(
+ IAuditEntity auditEntity, AuditLogOperation auditLogOperation,
Supplier<String> auditObject) {
+ authChecker.checkGlobalPrivilege(
+ auditEntity.getUsername(),
+ TableModelPrivilege.SYSTEM,
+ auditLogOperation,
+ auditEntity,
+ auditObject);
+ }
+
@Override
public boolean hasGlobalPrivilege(IAuditEntity entity, PrivilegeType
privilegeType) {
return AuthorityChecker.SUPER_USER_ID == entity.getUserId()
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/AllowAllAccessControl.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/AllowAllAccessControl.java
index 4777d01fcc8..890e54db85c 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/AllowAllAccessControl.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/AllowAllAccessControl.java
@@ -20,6 +20,7 @@
package org.apache.iotdb.db.queryengine.plan.relational.security;
import org.apache.iotdb.common.rpc.thrift.TSStatus;
+import org.apache.iotdb.commons.audit.AuditLogOperation;
import org.apache.iotdb.commons.audit.IAuditEntity;
import org.apache.iotdb.commons.auth.entity.PrivilegeType;
import org.apache.iotdb.commons.path.PartialPath;
@@ -106,6 +107,12 @@ public class AllowAllAccessControl implements
AccessControl {
@Override
public void checkUserGlobalSysPrivilege(IAuditEntity auditEntity) {}
+ @Override
+ public void checkUserGlobalSysPrivilege(
+ IAuditEntity auditEntity,
+ AuditLogOperation auditLogOperation,
+ Supplier<String> auditObject) {}
+
@Override
public boolean hasGlobalPrivilege(IAuditEntity entity, PrivilegeType
privilegeType) {
return true;
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/ITableAuthChecker.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/ITableAuthChecker.java
index c3dfa7420bf..c20a2b4228a 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/ITableAuthChecker.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/ITableAuthChecker.java
@@ -19,12 +19,14 @@
package org.apache.iotdb.db.queryengine.plan.relational.security;
+import org.apache.iotdb.commons.audit.AuditLogOperation;
import org.apache.iotdb.commons.audit.IAuditEntity;
import org.apache.iotdb.commons.auth.entity.PrivilegeType;
import org.apache.iotdb.commons.exception.auth.AccessDeniedException;
import
org.apache.iotdb.commons.queryengine.plan.relational.metadata.QualifiedObjectName;
import java.util.Collection;
+import java.util.function.Supplier;
public interface ITableAuthChecker {
@@ -108,6 +110,17 @@ public interface ITableAuthChecker {
void checkGlobalPrivilege(
String userName, TableModelPrivilege privilege, IAuditEntity
auditEntity);
+ /**
+ * Check if user has the specified global privilege and record the
authentication audit log with
+ * the operation and object of the statement being authorized.
+ */
+ void checkGlobalPrivilege(
+ String userName,
+ TableModelPrivilege privilege,
+ AuditLogOperation auditLogOperation,
+ IAuditEntity auditEntity,
+ Supplier<String> auditObject);
+
void checkGlobalPrivileges(
String username, Collection<PrivilegeType> privileges, IAuditEntity
auditEntity);
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 7d10285b2a6..42579f1830d 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
@@ -399,6 +399,30 @@ public class ITableAuthCheckerImpl implements
ITableAuthChecker {
recordAuditLogViaAuthenticationResult(() -> userName, privilege,
auditEntity, result);
}
+ @Override
+ public void checkGlobalPrivilege(
+ String userName,
+ TableModelPrivilege privilege,
+ AuditLogOperation auditLogOperation,
+ IAuditEntity auditEntity,
+ Supplier<String> auditObject) {
+ if (AuthorityChecker.SUPER_USER_ID == auditEntity.getUserId()) {
+ AUDIT_LOGGER.recordObjectAuthenticationAuditLog(
+ auditEntity
+ .setAuditLogOperation(auditLogOperation)
+ .setPrivilegeType(privilege.getPrivilegeType())
+ .setResult(true),
+ auditObject);
+ return;
+ }
+ TSStatus result =
+ AuthorityChecker.getTSStatus(
+ AuthorityChecker.checkSystemPermission(userName,
privilege.getPrivilegeType()),
+ privilege.getPrivilegeType());
+ recordAuditLogViaAuthenticationResult(
+ auditObject, privilege, auditLogOperation, auditEntity, result);
+ }
+
@Override
public void checkGlobalPrivileges(
String username, Collection<PrivilegeType> privileges, IAuditEntity
auditEntity) {
@@ -468,10 +492,20 @@ public class ITableAuthCheckerImpl implements
ITableAuthChecker {
TableModelPrivilege privilege,
IAuditEntity auditEntity,
TSStatus result) {
+ recordAuditLogViaAuthenticationResult(
+ auditObject, privilege, privilege.getAuditLogOperation(), auditEntity,
result);
+ }
+
+ private void recordAuditLogViaAuthenticationResult(
+ Supplier<String> auditObject,
+ TableModelPrivilege privilege,
+ AuditLogOperation auditLogOperation,
+ IAuditEntity auditEntity,
+ TSStatus result) {
if (result.getCode() != TSStatusCode.SUCCESS_STATUS.getStatusCode()) {
AUDIT_LOGGER.recordObjectAuthenticationAuditLog(
auditEntity
- .setAuditLogOperation(privilege.getAuditLogOperation())
+ .setAuditLogOperation(auditLogOperation)
.setPrivilegeType(privilege.getPrivilegeType())
.setResult(false),
auditObject);
@@ -479,7 +513,7 @@ public class ITableAuthCheckerImpl implements
ITableAuthChecker {
}
AUDIT_LOGGER.recordObjectAuthenticationAuditLog(
auditEntity
- .setAuditLogOperation(privilege.getAuditLogOperation())
+ .setAuditLogOperation(auditLogOperation)
.setPrivilegeType(privilege.getPrivilegeType())
.setResult(true),
auditObject);
diff --git
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/pipe/event/PipeTsFileInsertionEventTest.java
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/pipe/event/PipeTsFileInsertionEventTest.java
index 41cbf4358e5..5d5be1dbade 100644
---
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/pipe/event/PipeTsFileInsertionEventTest.java
+++
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/pipe/event/PipeTsFileInsertionEventTest.java
@@ -20,6 +20,7 @@
package org.apache.iotdb.db.pipe.event;
import org.apache.iotdb.common.rpc.thrift.TSStatus;
+import org.apache.iotdb.commons.audit.AuditLogOperation;
import org.apache.iotdb.commons.audit.IAuditEntity;
import org.apache.iotdb.commons.auth.entity.PrivilegeType;
import org.apache.iotdb.commons.conf.IoTDBConstant;
@@ -374,6 +375,12 @@ public class PipeTsFileInsertionEventTest {
@Override
public void checkUserGlobalSysPrivilege(IAuditEntity auditEntity) {}
+ @Override
+ public void checkUserGlobalSysPrivilege(
+ IAuditEntity auditEntity,
+ AuditLogOperation auditLogOperation,
+ Supplier<String> auditObject) {}
+
@Override
public boolean hasGlobalPrivilege(IAuditEntity auditEntity, PrivilegeType
privilegeType) {
return false;
diff --git
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/AuthTest.java
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/AuthTest.java
index e758e499628..9aaada25c83 100644
---
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/AuthTest.java
+++
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/relational/analyzer/AuthTest.java
@@ -19,6 +19,9 @@
package org.apache.iotdb.db.queryengine.plan.relational.analyzer;
+import org.apache.iotdb.commons.audit.AuditLogOperation;
+import org.apache.iotdb.commons.audit.UserEntity;
+import org.apache.iotdb.commons.auth.entity.PrivilegeType;
import org.apache.iotdb.commons.exception.auth.AccessDeniedException;
import org.apache.iotdb.commons.queryengine.common.SessionInfo;
import org.apache.iotdb.commons.queryengine.common.SqlDialect;
@@ -30,6 +33,7 @@ import org.apache.iotdb.db.queryengine.common.MPPQueryContext;
import
org.apache.iotdb.db.queryengine.plan.execution.config.TableConfigTaskVisitor;
import
org.apache.iotdb.db.queryengine.plan.relational.security.AccessControlImpl;
import
org.apache.iotdb.db.queryengine.plan.relational.security.ITableAuthChecker;
+import
org.apache.iotdb.db.queryengine.plan.relational.security.ITableAuthCheckerImpl;
import
org.apache.iotdb.db.queryengine.plan.relational.security.TableModelPrivilege;
import
org.apache.iotdb.db.queryengine.plan.relational.security.TreeAccessCheckVisitor;
import org.apache.iotdb.db.queryengine.plan.relational.sql.parser.SqlParser;
@@ -47,9 +51,13 @@ import static
org.apache.iotdb.db.queryengine.plan.relational.analyzer.TestMetad
import static
org.apache.iotdb.db.queryengine.plan.relational.analyzer.TestUtils.QUERY_ID;
import static
org.apache.iotdb.db.queryengine.plan.relational.analyzer.TestUtils.TEST_MATADATA;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
public class AuthTest {
@@ -206,6 +214,49 @@ public class AuthTest {
}
+ @Test
+ public void testFunctionManagementAuditOperation() {
+ ITableAuthChecker authChecker = Mockito.mock(ITableAuthChecker.class);
+ String functionName = "test_function";
+
+ analyzeConfigTask(
+ String.format(
+ "CREATE FUNCTION %s AS
'org.apache.iotdb.db.query.udf.example.relational.AllSum'",
+ functionName),
+ user1,
+ authChecker);
+ analyzeConfigTask(String.format("DROP FUNCTION %s", functionName), user1,
authChecker);
+
+ verify(authChecker, times(2))
+ .checkGlobalPrivilege(
+ eq(user1),
+ eq(TableModelPrivilege.SYSTEM),
+ eq(AuditLogOperation.DDL),
+ any(),
+ argThat(auditObject -> functionName.equals(auditObject.get())));
+ }
+
+ @Test
+ public void testExplicitGlobalPrivilegeAuditOperation() {
+ ITableAuthCheckerImpl authChecker = new ITableAuthCheckerImpl();
+ UserEntity auditEntity = new UserEntity(0, userRoot, "127.0.0.1");
+
+ authChecker.checkGlobalPrivilege(
+ userRoot,
+ TableModelPrivilege.SYSTEM,
+ AuditLogOperation.DDL,
+ auditEntity,
+ () -> "test_function");
+
+ assertEquals(AuditLogOperation.DDL, auditEntity.getAuditLogOperation());
+ assertEquals(Collections.singletonList(PrivilegeType.SYSTEM),
auditEntity.getPrivilegeTypes());
+ assertTrue(auditEntity.getResult());
+
+ UserEntity defaultAuditEntity = new UserEntity(0, userRoot, "127.0.0.1");
+ authChecker.checkGlobalPrivilege(userRoot, TableModelPrivilege.SYSTEM,
defaultAuditEntity);
+ assertEquals(AuditLogOperation.CONTROL,
defaultAuditEntity.getAuditLogOperation());
+ }
+
private void analyzeSQL(String sql, String userName, ITableAuthChecker
authChecker) {
analyzeSQL(sql, userName, authChecker, null);
}