Skip to content

Commit 18964f4

Browse files
authored
Patch for AUDIT privilege authentication on table model (apache#16563)
1 parent 558839f commit 18964f4

File tree

4 files changed

+62
-67
lines changed

4 files changed

+62
-67
lines changed

integration-test/src/test/java/org/apache/iotdb/db/it/audit/IoTDBAuditLogBasicIT.java

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,9 @@
5656
@Category({LocalStandaloneIT.class})
5757
public class IoTDBAuditLogBasicIT {
5858

59-
private static final long ENSURE_AUDIT_LOG_SLEEP_IN_MS = 250;
59+
public static final long ENSURE_AUDIT_LOG_SLEEP_IN_MS = 250;
6060

61-
private static final List<String> AUDIT_TABLE_COLUMNS =
61+
public static final List<String> AUDIT_TABLE_COLUMNS =
6262
Arrays.asList(
6363
AbstractAuditLogger.AUDIT_LOG_NODE_ID,
6464
AbstractAuditLogger.AUDIT_LOG_USER_ID,
@@ -73,28 +73,28 @@ public class IoTDBAuditLogBasicIT {
7373
AbstractAuditLogger.AUDIT_LOG_SQL_STRING,
7474
AbstractAuditLogger.AUDIT_LOG_LOG);
7575

76-
private static final List<String> AUDIT_TABLE_DATA_TYPES =
76+
public static final List<String> AUDIT_TABLE_DATA_TYPES =
7777
Arrays.asList(
7878
"STRING", "STRING", "STRING", "STRING", "STRING", "STRING", "STRING", "STRING", "BOOLEAN",
7979
"STRING", "STRING", "STRING");
8080

81-
private static final List<String> AUDIT_TABLE_CATEGORIES =
81+
public static final List<String> AUDIT_TABLE_CATEGORIES =
8282
Arrays.asList(
8383
"TAG", "TAG", "FIELD", "FIELD", "FIELD", "FIELD", "FIELD", "FIELD", "FIELD", "FIELD",
8484
"FIELD", "FIELD");
8585

86-
private static final boolean ENABLE_AUDIT_LOG = true;
87-
private static final String AUDITABLE_OPERATION_TYPE =
86+
public static final boolean ENABLE_AUDIT_LOG = true;
87+
public static final String AUDITABLE_OPERATION_TYPE =
8888
new StringJoiner(",")
8989
.add(AuditLogOperation.DDL.toString())
9090
.add(AuditLogOperation.DML.toString())
9191
.add(AuditLogOperation.QUERY.toString())
9292
.add(AuditLogOperation.CONTROL.toString())
9393
.toString();
9494

95-
private static final String AUDITABLE_OPERATION_LEVEL = PrivilegeLevel.GLOBAL.toString();
95+
public static final String AUDITABLE_OPERATION_LEVEL = PrivilegeLevel.GLOBAL.toString();
9696

97-
private static final String AUDITABLE_OPERATION_RESULT = "SUCCESS,FAIL";
97+
public static final String AUDITABLE_OPERATION_RESULT = "SUCCESS,FAIL";
9898

9999
@Before
100100
public void setUp() throws SQLException, InterruptedException {
@@ -135,7 +135,7 @@ public void tearDown() {
135135
EnvFactory.getEnv().cleanClusterEnvironment();
136136
}
137137

138-
private static void closeConnectionCompletely(Connection connection) throws InterruptedException {
138+
public static void closeConnectionCompletely(Connection connection) throws InterruptedException {
139139
// Ensure the session conns in test env are closed completely,
140140
// in order to generate logout audit log
141141
// TODO: Optimize this func after the close func of connection is optimized
@@ -2378,15 +2378,13 @@ public void basicAuditLogTestForTreeModel() throws SQLException, InterruptedExce
23782378
Statement statement = connection.createStatement();
23792379
for (String sql : TREE_MODEL_AUDIT_SQLS_USER_ROOT) {
23802380
statement.execute(sql);
2381-
TimeUnit.MILLISECONDS.sleep(ENSURE_AUDIT_LOG_SLEEP_IN_MS);
23822381
}
23832382
closeConnectionCompletely(connection);
23842383
connection =
23852384
EnvFactory.getEnv().getConnection("user1", "IoTDB@2025abc", BaseEnv.TREE_SQL_DIALECT);
23862385
statement = connection.createStatement();
23872386
for (String sql : TREE_MODEL_AUDIT_SQLS_USER_USER1) {
23882387
statement.execute(sql);
2389-
TimeUnit.MILLISECONDS.sleep(ENSURE_AUDIT_LOG_SLEEP_IN_MS);
23902388
}
23912389
closeConnectionCompletely(connection);
23922390
connection =
@@ -2395,7 +2393,6 @@ public void basicAuditLogTestForTreeModel() throws SQLException, InterruptedExce
23952393
for (String sql : TREE_MODEL_AUDIT_SQLS_USER_USER2) {
23962394
try {
23972395
statement.execute(sql);
2398-
TimeUnit.MILLISECONDS.sleep(ENSURE_AUDIT_LOG_SLEEP_IN_MS);
23992396
} catch (SQLException e) {
24002397
// Ignore, only record audit log
24012398
}
@@ -2405,7 +2402,6 @@ public void basicAuditLogTestForTreeModel() throws SQLException, InterruptedExce
24052402
statement = connection.createStatement();
24062403
for (String sql : TREE_MODEL_AUDIT_SQLS_USER_ROOT_FINAL) {
24072404
statement.execute(sql);
2408-
TimeUnit.MILLISECONDS.sleep(ENSURE_AUDIT_LOG_SLEEP_IN_MS);
24092405
}
24102406
ResultSet resultSet =
24112407
statement.executeQuery("SELECT * FROM root.__audit.log.** ORDER BY TIME ALIGN BY DEVICE");

iotdb-core/datanode/src/main/java/org/apache/iotdb/db/audit/DNAuditLogger.java

Lines changed: 32 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -86,9 +86,10 @@ public class DNAuditLogger extends AbstractAuditLogger {
8686
public static final String PREFIX_PASSWORD_HISTORY = "root.__audit.password_history";
8787
private static final Logger logger = LoggerFactory.getLogger(DNAuditLogger.class);
8888

89-
// TODO: @zhujt20 Optimize the following stupid retry
89+
// TODO: @zhujt20 Optimize the following stupid intervals
9090
private static final int INSERT_RETRY_COUNT = 5;
9191
private static final int INSERT_RETRY_INTERVAL_MS = 2000;
92+
private static final int INSERT_INTERVAL_MS = 50;
9293

9394
private static final IoTDBConfig config = IoTDBDescriptor.getInstance().getConfig();
9495

@@ -354,49 +355,46 @@ public void createViewIfNecessary() {
354355
}
355356

356357
@Override
357-
public void log(IAuditEntity auditLogFields, Supplier<String> log) {
358+
public synchronized void log(IAuditEntity auditLogFields, Supplier<String> log) {
358359
if (!IS_AUDIT_LOG_ENABLED) {
359360
return;
360361
}
361-
createViewIfNecessary();
362-
if (noNeedInsertAuditLog(auditLogFields)) {
363-
return;
364-
}
365-
long userId = auditLogFields.getUserId();
366-
String user = String.valueOf(userId);
367-
if (userId == -1) {
368-
user = "none";
369-
}
370-
String dataNodeId = String.valueOf(config.getDataNodeId());
371-
InsertRowStatement statement;
372362
try {
373-
statement =
363+
createViewIfNecessary();
364+
if (noNeedInsertAuditLog(auditLogFields)) {
365+
return;
366+
}
367+
long userId = auditLogFields.getUserId();
368+
String user = String.valueOf(userId);
369+
if (userId == -1) {
370+
user = "none";
371+
}
372+
String dataNodeId = String.valueOf(config.getDataNodeId());
373+
InsertRowStatement statement =
374374
generateInsertStatement(
375375
auditLogFields,
376376
log.get(),
377377
DEVICE_PATH_CACHE.getPartialPath(String.format(AUDIT_LOG_DEVICE, dataNodeId, user)));
378-
} catch (IllegalPathException e) {
379-
logger.error("Failed to log audit events because ", e);
380-
return;
381-
}
382-
for (int retry = 0; retry < INSERT_RETRY_COUNT; retry++) {
383-
ExecutionResult insertResult =
384-
coordinator.executeForTreeModel(
385-
statement,
386-
SESSION_MANAGER.requestQueryId(),
387-
sessionInfo,
388-
"",
389-
ClusterPartitionFetcher.getInstance(),
390-
SCHEMA_FETCHER);
391-
if (insertResult.status.getCode() == TSStatusCode.SUCCESS_STATUS.getStatusCode()) {
392-
return;
393-
}
394-
try {
378+
for (int retry = 0; retry < INSERT_RETRY_COUNT; retry++) {
379+
ExecutionResult insertResult =
380+
coordinator.executeForTreeModel(
381+
statement,
382+
SESSION_MANAGER.requestQueryId(),
383+
sessionInfo,
384+
"",
385+
ClusterPartitionFetcher.getInstance(),
386+
SCHEMA_FETCHER);
387+
if (insertResult.status.getCode() == TSStatusCode.SUCCESS_STATUS.getStatusCode()) {
388+
TimeUnit.MILLISECONDS.sleep(INSERT_INTERVAL_MS);
389+
return;
390+
}
395391
TimeUnit.MILLISECONDS.sleep(INSERT_RETRY_INTERVAL_MS);
396-
} catch (InterruptedException e) {
397-
Thread.currentThread().interrupt();
398-
logger.error("Audit log insertion retry sleep was interrupted", e);
399392
}
393+
} catch (InterruptedException e) {
394+
Thread.currentThread().interrupt();
395+
logger.warn("[AUDIT] Audit log insertion retry sleep was interrupted because", e);
396+
} catch (Exception e) {
397+
logger.warn("[AUDIT] Failed to log audit events because", e);
400398
}
401399
AuditEventType type = auditLogFields.getAuditEventType();
402400
if (isLoginEvent(type)) {

iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/ITableAuthCheckerImpl.java

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -66,23 +66,19 @@ public void checkDatabaseVisibility(
6666
}
6767

6868
if (TABLE_MODEL_AUDIT_DATABASE.equalsIgnoreCase(databaseName)) {
69-
if (AuthorityChecker.checkSystemPermission(userName, PrivilegeType.AUDIT)) {
70-
recordAuditLog(
71-
auditEntity
72-
.setAuditLogOperation(AuditLogOperation.QUERY)
73-
.setPrivilegeType(PrivilegeType.READ_SCHEMA)
74-
.setResult(true),
75-
() -> databaseName);
69+
// The audit database only requires audit privilege
70+
boolean hasAuditPrivilege =
71+
AuthorityChecker.checkSystemPermission(userName, PrivilegeType.AUDIT);
72+
recordAuditLog(
73+
auditEntity
74+
.setAuditLogOperation(AuditLogOperation.QUERY)
75+
.setPrivilegeType(PrivilegeType.AUDIT)
76+
.setResult(hasAuditPrivilege),
77+
() -> databaseName);
78+
if (hasAuditPrivilege) {
7679
return;
77-
} else {
78-
recordAuditLog(
79-
auditEntity
80-
.setAuditLogOperation(AuditLogOperation.QUERY)
81-
.setPrivilegeType(PrivilegeType.READ_SCHEMA)
82-
.setResult(false),
83-
() -> databaseName);
84-
throw new AccessDeniedException("DATABASE " + databaseName);
8580
}
81+
throw new AccessDeniedException("DATABASE " + databaseName);
8682
}
8783

8884
if (AuthorityChecker.checkSystemPermission(userName, PrivilegeType.SYSTEM)) {
@@ -341,14 +337,19 @@ public void checkTableVisibility(
341337
}
342338

343339
String databaseName = tableName.getDatabaseName();
344-
if (TABLE_MODEL_AUDIT_DATABASE.equalsIgnoreCase(databaseName)
345-
&& !AuthorityChecker.checkSystemPermission(userName, PrivilegeType.AUDIT)) {
340+
if (TABLE_MODEL_AUDIT_DATABASE.equalsIgnoreCase(databaseName)) {
341+
// The audit table only requires audit privilege
342+
boolean hasAuditPrivilege =
343+
AuthorityChecker.checkSystemPermission(userName, PrivilegeType.AUDIT);
346344
recordAuditLog(
347345
auditEntity
348346
.setAuditLogOperation(AuditLogOperation.QUERY)
349-
.setPrivilegeType(PrivilegeType.READ_SCHEMA)
350-
.setResult(false),
347+
.setPrivilegeType(PrivilegeType.AUDIT)
348+
.setResult(hasAuditPrivilege),
351349
tableName::getObjectName);
350+
if (hasAuditPrivilege) {
351+
return;
352+
}
352353
throw new AccessDeniedException("TABLE " + tableName);
353354
}
354355

iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/TreeAccessCheckVisitor.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1900,7 +1900,7 @@ private TSStatus checkOnlySuperUser(
19001900
return AuthorityChecker.getTSStatus(false, "Only the admin user can perform this operation");
19011901
}
19021902

1903-
private static void recordObjectAuthenticationAuditLog(
1903+
protected static void recordObjectAuthenticationAuditLog(
19041904
IAuditEntity auditEntity, Supplier<String> auditObject) {
19051905
AUDIT_LOGGER.log(
19061906
auditEntity.setAuditEventType(AuditEventType.OBJECT_AUTHENTICATION),

0 commit comments

Comments
 (0)