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