This is an automated email from the ASF dual-hosted git repository. yongzao pushed a commit to branch trigger-audit-log-v1 in repository https://gitbox.apache.org/repos/asf/iotdb.git
commit 42a35ed0d8f144ce91b7dd092b7e282cd2610b2e Author: Yongzao <[email protected]> AuthorDate: Sat Sep 20 13:04:09 2025 +0800 wait 4 MPP reconstruct --- .../org/apache/iotdb/db/auth/AuthorityChecker.java | 3 + .../db/queryengine/common/MPPQueryContext.java | 54 +++- .../plan/relational/security/AccessControl.java | 60 ++-- .../relational/security/AccessControlImpl.java | 119 ++++---- .../relational/security/AllowAllAccessControl.java | 84 +++--- .../relational/security/ITableAuthChecker.java | 48 +++- .../relational/security/ITableAuthCheckerImpl.java | 313 ++++++++++++++++++--- .../relational/security/TableModelPrivilege.java | 23 ++ .../apache/iotdb/commons/audit/AuditEventType.java | 2 +- .../apache/iotdb/commons/audit/AuditLogFields.java | 7 +- .../apache/iotdb/commons/audit/IAuditEntity.java | 34 +++ .../iotdb/commons/auth/entity/PrivilegeType.java | 35 +++ 12 files changed, 617 insertions(+), 165 deletions(-) diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/auth/AuthorityChecker.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/auth/AuthorityChecker.java index b67987159b7..fbd2d5aac82 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/auth/AuthorityChecker.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/auth/AuthorityChecker.java @@ -69,8 +69,11 @@ import static org.apache.iotdb.commons.schema.column.ColumnHeaderConstant.LIST_U // It checks permission in local. DCL statement will send to configNode. public class AuthorityChecker { + public static int SUPER_USER_ID = 0; public static String SUPER_USER = CommonDescriptor.getInstance().getConfig().getAdminName(); + public static String ANY_SCOPE = "any"; + public static final TSStatus SUCCEED = RpcUtils.SUCCESS_STATUS; public static final String ONLY_ADMIN_ALLOWED = diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/common/MPPQueryContext.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/common/MPPQueryContext.java index 9d71f9147ac..28c18ad619b 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/common/MPPQueryContext.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/common/MPPQueryContext.java @@ -21,6 +21,11 @@ package org.apache.iotdb.db.queryengine.common; import org.apache.iotdb.common.rpc.thrift.TEndPoint; import org.apache.iotdb.common.rpc.thrift.TRegionReplicaSet; +import org.apache.iotdb.commons.audit.AuditEventType; +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.utils.TestOnly; import org.apache.iotdb.db.queryengine.plan.analyze.Analysis; import org.apache.iotdb.db.queryengine.plan.analyze.PredicateUtils; import org.apache.iotdb.db.queryengine.plan.analyze.QueryType; @@ -43,7 +48,7 @@ import java.util.function.LongConsumer; * This class is used to record the context of a query including QueryId, query statement, session * info and so on. */ -public class MPPQueryContext { +public class MPPQueryContext implements IAuditEntity { private String sql; private final QueryId queryId; @@ -103,6 +108,7 @@ public class MPPQueryContext { new NotThreadSafeMemoryReservationManager(queryId, this.getClass().getName()); } + @TestOnly public MPPQueryContext( String sql, QueryId queryId, @@ -426,4 +432,50 @@ public class MPPQueryContext { public void setUserQuery(boolean userQuery) { this.userQuery = userQuery; } + + @Override + public int getUserId() { + return session.getUserId(); + } + + @Override + public String getUsername() { + return session.getUserName(); + } + + @Override + public String getCliHostname() { + return session.getCliHostname; + } + + @Override + public AuditEventType getAuditEventType() { + return null; + } + + @Override + public AuditLogOperation getAuditLogOperation() { + return null; + } + + @Override + public PrivilegeType getPrivilegeType() { + // The privilege type will be given ultimately. + return null; + } + + @Override + public boolean getResult() { + return false; + } + + @Override + public String getDatabase() { + return session.getDatabaseName().orElse(null); + } + + @Override + public String getSqlString() { + return sql; + } } 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 6af1a8d7c31..460d7e994fa 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.IAuditEntity; import org.apache.iotdb.commons.auth.entity.PrivilegeType; import org.apache.iotdb.commons.exception.auth.AccessDeniedException; import org.apache.iotdb.commons.path.PartialPath; @@ -40,129 +41,152 @@ public interface AccessControl { * * @param userName name of user * @param databaseName without `root.` prefix, like db + * @param auditEntity records necessary info for audit log * @throws AccessDeniedException if not allowed */ - void checkCanCreateDatabase(String userName, String databaseName); + void checkCanCreateDatabase(String userName, String databaseName, IAuditEntity auditEntity); /** * Check if user is allowed to drop the specified database. * * @param userName name of user * @param databaseName without `root.` prefix, like db + * @param auditEntity records necessary info for audit log * @throws AccessDeniedException if not allowed */ - void checkCanDropDatabase(String userName, String databaseName); + void checkCanDropDatabase(String userName, String databaseName, IAuditEntity auditEntity); /** * Check if user is allowed to alter the specified database. * * @param userName name of user * @param databaseName without `root.` prefix, like db + * @param auditEntity records necessary info for audit log * @throws AccessDeniedException if not allowed */ - void checkCanAlterDatabase(String userName, String databaseName); + void checkCanAlterDatabase(String userName, String databaseName, IAuditEntity auditEntity); /** * Check if user is allowed to show or use the specified database. * * @param userName name of user * @param databaseName without `root.` prefix, like db + * @param auditEntity records necessary info for audit log * @throws AccessDeniedException if not allowed */ - void checkCanShowOrUseDatabase(final String userName, final String databaseName); + void checkCanShowOrUseDatabase( + final String userName, final String databaseName, IAuditEntity auditEntity); /** * Check if user is allowed to create the specified table. * * @param userName name of user * @param tableName qualified name of table without `root.` prefix, like db.table1 + * @param auditEntity records necessary info for audit log * @throws AccessDeniedException if not allowed */ - void checkCanCreateTable(String userName, QualifiedObjectName tableName); + void checkCanCreateTable( + String userName, QualifiedObjectName tableName, IAuditEntity auditEntity); /** * Check if user is allowed to create the specified table. * * @param userName name of user * @param tableName qualified name of table without `root.` prefix, like db.table1 + * @param auditEntity records necessary info for audit log * @throws AccessDeniedException if not allowed */ - void checkCanDropTable(String userName, QualifiedObjectName tableName); + void checkCanDropTable(String userName, QualifiedObjectName tableName, IAuditEntity auditEntity); /** * Check if user is allowed to alter the specified table. * * @param userName name of user * @param tableName qualified name of table without `root.` prefix, like db.table1 + * @param auditEntity records necessary info for audit log * @throws AccessDeniedException if not allowed */ - void checkCanAlterTable(String userName, QualifiedObjectName tableName); + void checkCanAlterTable(String userName, QualifiedObjectName tableName, IAuditEntity auditEntity); /** * Check if user is allowed to insert into the specified table. * * @param userName name of user * @param tableName qualified name of table without `root.` prefix, like db.table1 + * @param auditEntity records necessary info for audit log * @throws AccessDeniedException if not allowed */ - void checkCanInsertIntoTable(String userName, QualifiedObjectName tableName); + void checkCanInsertIntoTable( + String userName, QualifiedObjectName tableName, IAuditEntity auditEntity); /** * Check if user is allowed to select from the specified table. * * @param userName name of user * @param tableName qualified name of table without `root.` prefix, like db.table1 + * @param auditEntity records necessary info for audit log * @throws AccessDeniedException if not allowed */ - void checkCanSelectFromTable(String userName, QualifiedObjectName tableName); + void checkCanSelectFromTable( + String userName, QualifiedObjectName tableName, IAuditEntity auditEntity); /** * Check if user is allowed to extract certain data from pipe. * * @param userName name of user * @param databaseName the databaseName + * @param auditEntity records necessary info for audit log * @throws AccessDeniedException if not allowed */ - void checkCanSelectFromDatabase4Pipe(final String userName, final String databaseName); + void checkCanSelectFromDatabase4Pipe( + final String userName, final String databaseName, IAuditEntity auditEntity); // This does not throw exception for performance issues - boolean checkCanSelectFromTable4Pipe(final String userName, final QualifiedObjectName tableName); + boolean checkCanSelectFromTable4Pipe( + final String userName, final QualifiedObjectName tableName, IAuditEntity auditEntity); /** * Check if user is allowed to delete from the specified table. * * @param userName name of user * @param tableName qualified name of table without `root.` prefix, like db.table1 + * @param auditEntity records necessary info for audit log * @throws AccessDeniedException if not allowed */ - void checkCanDeleteFromTable(String userName, QualifiedObjectName tableName); + void checkCanDeleteFromTable( + String userName, QualifiedObjectName tableName, IAuditEntity auditEntity); /** * Check if user is allowed to show or describe the specified table. * * @param userName name of user * @param tableName qualified name of table without `root.` prefix, like db.table1 + * @param auditEntity records necessary info for audit log * @throws AccessDeniedException if not allowed */ - void checkCanShowOrDescTable(String userName, QualifiedObjectName tableName); + void checkCanShowOrDescTable( + String userName, QualifiedObjectName tableName, IAuditEntity auditEntity); /** * Check if user is allowed to create view under the specific tree path. * * @param userName name of user * @param path the tree path scope the view can select from + * @param auditEntity records necessary info for audit log * @throws AccessDeniedException if not allowed */ - void checkCanCreateViewFromTreePath(final String userName, final PartialPath path); + void checkCanCreateViewFromTreePath( + final String userName, final PartialPath path, IAuditEntity auditEntity); /** * Check if user can run relational author statement. * * @param userName name of user + * @param auditEntity records necessary info for audit log * @throws AccessDeniedException if not allowed */ void checkUserCanRunRelationalAuthorStatement( - String userName, RelationalAuthorStatement statement); + String userName, RelationalAuthorStatement statement, IAuditEntity auditEntity); /** * Check if user is admin user @@ -176,9 +200,10 @@ public interface AccessControl { * Check if user has global SYSTEM privilege * * @param userName name of user + * @param auditEntity records necessary info for audit log * @throws AccessDeniedException if not allowed */ - void checkUserGlobalSysPrivilege(String userName); + void checkUserGlobalSysPrivilege(String userName, IAuditEntity auditEntity); /** * Check if user has sepecified global privilege @@ -189,7 +214,8 @@ public interface AccessControl { */ boolean hasGlobalPrivilege(String userName, PrivilegeType privilegeType); - void checkMissingPrivileges(String username, Collection<PrivilegeType> privilegeTypes); + void checkMissingPrivileges( + String username, Collection<PrivilegeType> privilegeTypes, IAuditEntity auditEntity); // ====================================== TREE ============================================= 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 b90b854d259..f0c172c250c 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 @@ -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.IAuditEntity; import org.apache.iotdb.commons.auth.entity.PrivilegeType; import org.apache.iotdb.commons.exception.IllegalPathException; import org.apache.iotdb.commons.exception.auth.AccessDeniedException; @@ -70,115 +71,132 @@ public class AccessControlImpl implements AccessControl { } @Override - public void checkCanCreateDatabase(String userName, String databaseName) { + public void checkCanCreateDatabase( + String userName, String databaseName, IAuditEntity auditEntity) { InformationSchemaUtils.checkDBNameInWrite(databaseName); - authChecker.checkDatabasePrivilege(userName, databaseName, TableModelPrivilege.CREATE); + authChecker.checkDatabasePrivilege( + userName, databaseName, TableModelPrivilege.CREATE, auditEntity); } @Override - public void checkCanDropDatabase(String userName, String databaseName) { + public void checkCanDropDatabase(String userName, String databaseName, IAuditEntity auditEntity) { InformationSchemaUtils.checkDBNameInWrite(databaseName); - authChecker.checkDatabasePrivilege(userName, databaseName, TableModelPrivilege.DROP); + authChecker.checkDatabasePrivilege( + userName, databaseName, TableModelPrivilege.DROP, auditEntity); } @Override - public void checkCanAlterDatabase(String userName, String databaseName) { + public void checkCanAlterDatabase( + String userName, String databaseName, IAuditEntity auditEntity) { InformationSchemaUtils.checkDBNameInWrite(databaseName); - authChecker.checkDatabasePrivilege(userName, databaseName, TableModelPrivilege.ALTER); + authChecker.checkDatabasePrivilege( + userName, databaseName, TableModelPrivilege.ALTER, auditEntity); } @Override - public void checkCanShowOrUseDatabase(String userName, String databaseName) { - authChecker.checkDatabaseVisibility(userName, databaseName); + public void checkCanShowOrUseDatabase( + String userName, String databaseName, IAuditEntity auditEntity) { + authChecker.checkDatabaseVisibility(userName, databaseName, auditEntity); } @Override - public void checkCanCreateTable(String userName, QualifiedObjectName tableName) { + public void checkCanCreateTable( + String userName, QualifiedObjectName tableName, IAuditEntity auditEntity) { InformationSchemaUtils.checkDBNameInWrite(tableName.getDatabaseName()); checkAuditDatabase(tableName.getDatabaseName()); if (hasGlobalPrivilege(userName, PrivilegeType.SYSTEM)) { return; } - authChecker.checkTablePrivilege(userName, tableName, TableModelPrivilege.CREATE); + authChecker.checkTablePrivilege(userName, tableName, TableModelPrivilege.CREATE, auditEntity); } @Override - public void checkCanDropTable(String userName, QualifiedObjectName tableName) { + public void checkCanDropTable( + String userName, QualifiedObjectName tableName, IAuditEntity auditEntity) { InformationSchemaUtils.checkDBNameInWrite(tableName.getDatabaseName()); checkAuditDatabase(tableName.getDatabaseName()); if (hasGlobalPrivilege(userName, PrivilegeType.SYSTEM)) { return; } - authChecker.checkTablePrivilege(userName, tableName, TableModelPrivilege.DROP); + authChecker.checkTablePrivilege(userName, tableName, TableModelPrivilege.DROP, auditEntity); } @Override - public void checkCanAlterTable(String userName, QualifiedObjectName tableName) { + public void checkCanAlterTable( + String userName, QualifiedObjectName tableName, IAuditEntity auditEntity) { InformationSchemaUtils.checkDBNameInWrite(tableName.getDatabaseName()); checkAuditDatabase(tableName.getDatabaseName()); if (hasGlobalPrivilege(userName, PrivilegeType.SYSTEM)) { return; } - authChecker.checkTablePrivilege(userName, tableName, TableModelPrivilege.ALTER); + authChecker.checkTablePrivilege(userName, tableName, TableModelPrivilege.ALTER, auditEntity); } @Override - public void checkCanInsertIntoTable(String userName, QualifiedObjectName tableName) { + public void checkCanInsertIntoTable( + String userName, QualifiedObjectName tableName, IAuditEntity auditEntity) { InformationSchemaUtils.checkDBNameInWrite(tableName.getDatabaseName()); checkAuditDatabase(tableName.getDatabaseName()); - authChecker.checkTablePrivilege(userName, tableName, TableModelPrivilege.INSERT); + authChecker.checkTablePrivilege(userName, tableName, TableModelPrivilege.INSERT, auditEntity); } @Override - public void checkCanSelectFromTable(String userName, QualifiedObjectName tableName) { + public void checkCanSelectFromTable( + String userName, QualifiedObjectName tableName, IAuditEntity auditEntity) { if (tableName.getDatabaseName().equals(InformationSchema.INFORMATION_DATABASE)) { return; } if (TABLE_MODEL_AUDIT_DATABASE.equalsIgnoreCase(tableName.getDatabaseName())) { - checkCanSelectAuditTable(userName); + checkCanSelectAuditTable(userName, auditEntity); } else { - authChecker.checkTablePrivilege(userName, tableName, TableModelPrivilege.SELECT); + authChecker.checkTablePrivilege(userName, tableName, TableModelPrivilege.SELECT, auditEntity); } } @Override - public void checkCanSelectFromDatabase4Pipe(final String userName, final String databaseName) { + public void checkCanSelectFromDatabase4Pipe( + final String userName, final String databaseName, IAuditEntity auditEntity) { if (Objects.isNull(userName)) { throw new AccessDeniedException("User not exists"); } - authChecker.checkDatabasePrivilege(userName, databaseName, TableModelPrivilege.SELECT); + authChecker.checkDatabasePrivilege( + userName, databaseName, TableModelPrivilege.SELECT, auditEntity); } @Override public boolean checkCanSelectFromTable4Pipe( - final String userName, final QualifiedObjectName tableName) { - return Objects.nonNull(userName) && authChecker.checkTablePrivilege4Pipe(userName, tableName); + final String userName, final QualifiedObjectName tableName, IAuditEntity auditEntity) { + return Objects.nonNull(userName) + && authChecker.checkTablePrivilege4Pipe(userName, tableName, auditEntity); } @Override - public void checkCanDeleteFromTable(String userName, QualifiedObjectName tableName) { + public void checkCanDeleteFromTable( + String userName, QualifiedObjectName tableName, IAuditEntity auditEntity) { InformationSchemaUtils.checkDBNameInWrite(tableName.getDatabaseName()); checkAuditDatabase(tableName.getDatabaseName()); - authChecker.checkTablePrivilege(userName, tableName, TableModelPrivilege.DELETE); + authChecker.checkTablePrivilege(userName, tableName, TableModelPrivilege.DELETE, auditEntity); } @Override - public void checkCanShowOrDescTable(String userName, QualifiedObjectName tableName) { + public void checkCanShowOrDescTable( + String userName, QualifiedObjectName tableName, IAuditEntity auditEntity) { // Information_schema is visible to any user if (tableName.getDatabaseName().equals(InformationSchema.INFORMATION_DATABASE)) { return; } - authChecker.checkTableVisibility(userName, tableName); + authChecker.checkTableVisibility(userName, tableName, auditEntity); } @Override - public void checkCanCreateViewFromTreePath(final String userName, final PartialPath path) { + public void checkCanCreateViewFromTreePath( + final String userName, final PartialPath path, IAuditEntity auditEntity) { if (AuthorityChecker.SUPER_USER.equals(userName)) { return; } if (includeByAuditTreeDB(path)) { - checkCanSelectAuditTable(userName); + checkCanSelectAuditTable(userName, auditEntity); } TSStatus status = @@ -202,20 +220,20 @@ public class AccessControlImpl implements AccessControl { @Override public void checkUserCanRunRelationalAuthorStatement( - String userName, RelationalAuthorStatement statement) { + String userName, RelationalAuthorStatement statement, IAuditEntity auditEntity) { AuthorRType type = statement.getAuthorType(); switch (type) { case CREATE_USER: if (AuthorityChecker.SUPER_USER.equals(userName)) { return; } - authChecker.checkGlobalPrivilege(userName, TableModelPrivilege.MANAGE_USER); + authChecker.checkGlobalPrivilege(userName, TableModelPrivilege.MANAGE_USER, auditEntity); return; case DROP_USER: if (AuthorityChecker.SUPER_USER.equals(userName)) { return; } - authChecker.checkGlobalPrivilege(userName, TableModelPrivilege.MANAGE_USER); + authChecker.checkGlobalPrivilege(userName, TableModelPrivilege.MANAGE_USER, auditEntity); return; case UPDATE_USER: case LIST_USER_PRIV: @@ -223,7 +241,7 @@ public class AccessControlImpl implements AccessControl { || statement.getUserName().equals(userName)) { return; } - authChecker.checkGlobalPrivilege(userName, TableModelPrivilege.MANAGE_USER); + authChecker.checkGlobalPrivilege(userName, TableModelPrivilege.MANAGE_USER, auditEntity); return; case LIST_USER: if (!hasGlobalPrivilege(userName, PrivilegeType.MANAGE_USER)) { @@ -234,32 +252,32 @@ public class AccessControlImpl implements AccessControl { if (AuthorityChecker.SUPER_USER.equals(userName)) { return; } - authChecker.checkGlobalPrivilege(userName, TableModelPrivilege.MANAGE_ROLE); + authChecker.checkGlobalPrivilege(userName, TableModelPrivilege.MANAGE_ROLE, auditEntity); return; case DROP_ROLE: if (AuthorityChecker.SUPER_USER.equals(userName)) { return; } - authChecker.checkGlobalPrivilege(userName, TableModelPrivilege.MANAGE_ROLE); + authChecker.checkGlobalPrivilege(userName, TableModelPrivilege.MANAGE_ROLE, auditEntity); return; case GRANT_USER_ROLE: if (AuthorityChecker.SUPER_USER.equals(userName)) { return; } - authChecker.checkGlobalPrivilege(userName, TableModelPrivilege.MANAGE_ROLE); + authChecker.checkGlobalPrivilege(userName, TableModelPrivilege.MANAGE_ROLE, auditEntity); return; case REVOKE_USER_ROLE: if (AuthorityChecker.SUPER_USER.equals(userName)) { return; } - authChecker.checkGlobalPrivilege(userName, TableModelPrivilege.MANAGE_ROLE); + authChecker.checkGlobalPrivilege(userName, TableModelPrivilege.MANAGE_ROLE, auditEntity); return; case LIST_ROLE: if (statement.getUserName() != null && !statement.getUserName().equals(userName)) { - authChecker.checkGlobalPrivilege(userName, TableModelPrivilege.MANAGE_ROLE); + authChecker.checkGlobalPrivilege(userName, TableModelPrivilege.MANAGE_ROLE, auditEntity); return; } if (!hasGlobalPrivilege(userName, PrivilegeType.MANAGE_ROLE)) { @@ -273,7 +291,7 @@ public class AccessControlImpl implements AccessControl { if (AuthorityChecker.checkRole(userName, statement.getRoleName())) { return; } - authChecker.checkGlobalPrivilege(userName, TableModelPrivilege.MANAGE_ROLE); + authChecker.checkGlobalPrivilege(userName, TableModelPrivilege.MANAGE_ROLE, auditEntity); return; case GRANT_ROLE_ANY: case GRANT_USER_ANY: @@ -284,7 +302,7 @@ public class AccessControlImpl implements AccessControl { } for (PrivilegeType privilegeType : statement.getPrivilegeTypes()) { authChecker.checkAnyScopePrivilegeGrantOption( - userName, TableModelPrivilege.getTableModelType(privilegeType)); + userName, TableModelPrivilege.getTableModelType(privilegeType), auditEntity); } return; case GRANT_ROLE_ALL: @@ -297,10 +315,10 @@ public class AccessControlImpl implements AccessControl { for (TableModelPrivilege privilege : TableModelPrivilege.values()) { PrivilegeType privilegeType = privilege.getPrivilegeType(); if (privilegeType.isRelationalPrivilege()) { - authChecker.checkAnyScopePrivilegeGrantOption(userName, privilege); + authChecker.checkAnyScopePrivilegeGrantOption(userName, privilege, auditEntity); } if (privilegeType.forRelationalSys()) { - authChecker.checkGlobalPrivilegeGrantOption(userName, privilege); + authChecker.checkGlobalPrivilegeGrantOption(userName, privilege, auditEntity); } } return; @@ -315,7 +333,8 @@ public class AccessControlImpl implements AccessControl { authChecker.checkDatabasePrivilegeGrantOption( userName, statement.getDatabase(), - TableModelPrivilege.getTableModelType(privilegeType)); + TableModelPrivilege.getTableModelType(privilegeType), + auditEntity); } return; case GRANT_USER_TB: @@ -329,7 +348,8 @@ public class AccessControlImpl implements AccessControl { authChecker.checkTablePrivilegeGrantOption( userName, new QualifiedObjectName(statement.getDatabase(), statement.getTableName()), - TableModelPrivilege.getTableModelType(privilegeType)); + TableModelPrivilege.getTableModelType(privilegeType), + auditEntity); } return; @@ -342,7 +362,7 @@ public class AccessControlImpl implements AccessControl { } for (PrivilegeType privilegeType : statement.getPrivilegeTypes()) { authChecker.checkGlobalPrivilegeGrantOption( - userName, TableModelPrivilege.getTableModelType(privilegeType)); + userName, TableModelPrivilege.getTableModelType(privilegeType), auditEntity); } break; default: @@ -358,9 +378,9 @@ public class AccessControlImpl implements AccessControl { } @Override - public void checkUserGlobalSysPrivilege(String userName) { + public void checkUserGlobalSysPrivilege(String userName, IAuditEntity auditEntity) { if (!AuthorityChecker.SUPER_USER.equals(userName)) { - authChecker.checkGlobalPrivilege(userName, TableModelPrivilege.SYSTEM); + authChecker.checkGlobalPrivilege(userName, TableModelPrivilege.SYSTEM, auditEntity); } } @@ -371,11 +391,12 @@ public class AccessControlImpl implements AccessControl { } @Override - public void checkMissingPrivileges(String username, Collection<PrivilegeType> privilegeTypes) { + public void checkMissingPrivileges( + String username, Collection<PrivilegeType> privilegeTypes, IAuditEntity auditEntity) { if (AuthorityChecker.SUPER_USER.equals(username)) { return; } - authChecker.checkGlobalPrivileges(username, privilegeTypes); + authChecker.checkGlobalPrivileges(username, privilegeTypes, auditEntity); } @Override 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 ab359966fcb..9349cc3dd88 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.IAuditEntity; import org.apache.iotdb.commons.auth.entity.PrivilegeType; import org.apache.iotdb.commons.path.PartialPath; import org.apache.iotdb.db.queryengine.plan.relational.metadata.QualifiedObjectName; @@ -34,80 +35,66 @@ import static org.apache.iotdb.db.auth.AuthorityChecker.SUCCEED; public class AllowAllAccessControl implements AccessControl { @Override - public void checkCanCreateDatabase(String userName, String databaseName) { - // allow anything - } + public void checkCanCreateDatabase( + String userName, String databaseName, IAuditEntity auditEntity) {} @Override - public void checkCanDropDatabase(String userName, String databaseName) { - // allow anything - } + public void checkCanDropDatabase( + String userName, String databaseName, IAuditEntity auditEntity) {} @Override - public void checkCanAlterDatabase(String userName, String databaseName) { - // allow anything - } + public void checkCanAlterDatabase( + String userName, String databaseName, IAuditEntity auditEntity) {} @Override - public void checkCanShowOrUseDatabase(String userName, String databaseName) { - // allow anything - } + public void checkCanShowOrUseDatabase( + String userName, String databaseName, IAuditEntity auditEntity) {} @Override - public void checkCanCreateTable(String userName, QualifiedObjectName tableName) { - // allow anything - } + public void checkCanCreateTable( + String userName, QualifiedObjectName tableName, IAuditEntity auditEntity) {} @Override - public void checkCanDropTable(String userName, QualifiedObjectName tableName) { - // allow anything - } + public void checkCanDropTable( + String userName, QualifiedObjectName tableName, IAuditEntity auditEntity) {} @Override - public void checkCanAlterTable(String userName, QualifiedObjectName tableName) { - // allow anything - } + public void checkCanAlterTable( + String userName, QualifiedObjectName tableName, IAuditEntity auditEntity) {} @Override - public void checkCanInsertIntoTable(String userName, QualifiedObjectName tableName) { - // allow anything - } + public void checkCanInsertIntoTable( + String userName, QualifiedObjectName tableName, IAuditEntity auditEntity) {} @Override - public void checkCanSelectFromTable(String userName, QualifiedObjectName tableName) { - // allow anything - } + public void checkCanSelectFromTable( + String userName, QualifiedObjectName tableName, IAuditEntity auditEntity) {} @Override - public void checkCanSelectFromDatabase4Pipe(String userName, String databaseName) { - // allow anything - } + public void checkCanSelectFromDatabase4Pipe( + String userName, String databaseName, IAuditEntity auditEntity) {} @Override - public boolean checkCanSelectFromTable4Pipe(String userName, QualifiedObjectName tableName) { - return true; + public boolean checkCanSelectFromTable4Pipe( + String userName, QualifiedObjectName tableName, IAuditEntity auditEntity) { + return false; } @Override - public void checkCanDeleteFromTable(String userName, QualifiedObjectName tableName) { - // allow anything - } + public void checkCanDeleteFromTable( + String userName, QualifiedObjectName tableName, IAuditEntity auditEntity) {} @Override - public void checkCanShowOrDescTable(String userName, QualifiedObjectName tableName) { - // allow anything - } + public void checkCanShowOrDescTable( + String userName, QualifiedObjectName tableName, IAuditEntity auditEntity) {} @Override - public void checkCanCreateViewFromTreePath(String userName, PartialPath path) { - // allow anything - } + public void checkCanCreateViewFromTreePath( + String userName, PartialPath path, IAuditEntity auditEntity) {} @Override public void checkUserCanRunRelationalAuthorStatement( - String userName, RelationalAuthorStatement statement) { - // allow anything - } + String userName, RelationalAuthorStatement statement, IAuditEntity auditEntity) {} @Override public void checkUserIsAdmin(String userName) { @@ -115,9 +102,7 @@ public class AllowAllAccessControl implements AccessControl { } @Override - public void checkUserGlobalSysPrivilege(String userName) { - // allow anything - } + public void checkUserGlobalSysPrivilege(String userName, IAuditEntity auditEntity) {} @Override public boolean hasGlobalPrivilege(String userName, PrivilegeType privilegeType) { @@ -125,9 +110,8 @@ public class AllowAllAccessControl implements AccessControl { } @Override - public void checkMissingPrivileges(String username, Collection<PrivilegeType> privilegeTypes) { - // allow anything - } + public void checkMissingPrivileges( + String username, Collection<PrivilegeType> privilegeTypes, IAuditEntity auditEntity) {} @Override public TSStatus checkPermissionBeforeProcess(Statement statement, String userName) { 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 e377fa85fde..e666196ebd8 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,6 +19,7 @@ package org.apache.iotdb.db.queryengine.plan.relational.security; +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.db.queryengine.plan.relational.metadata.QualifiedObjectName; @@ -33,9 +34,10 @@ public interface ITableAuthChecker { * * @param userName name of user * @param databaseName without `root.` prefix, like db + * @param auditEntity records necessary info for audit log * @throws AccessDeniedException if not allowed */ - void checkDatabaseVisibility(String userName, String databaseName); + void checkDatabaseVisibility(String userName, String databaseName, IAuditEntity auditEntity); /** * Check if user has specified privilege on the specified database or bigger scope (like ANY). @@ -43,12 +45,20 @@ public interface ITableAuthChecker { * @param userName name of user * @param databaseName without `root.` prefix, like db * @param privilege specified privilege to be checked + * @param auditEntity records necessary info for audit log * @throws AccessDeniedException if not allowed */ - void checkDatabasePrivilege(String userName, String databaseName, TableModelPrivilege privilege); + void checkDatabasePrivilege( + String userName, + String databaseName, + TableModelPrivilege privilege, + IAuditEntity auditEntity); void checkDatabasePrivilegeGrantOption( - String userName, String databaseName, TableModelPrivilege privilege); + String userName, + String databaseName, + TableModelPrivilege privilege, + IAuditEntity auditEntity); /** * Check if user has specified privilege on the specified table or bigger scope (like database or @@ -57,45 +67,61 @@ public interface ITableAuthChecker { * @param userName name of user * @param tableName qualified name of table without `root.` prefix, like db.table1 * @param privilege specified privilege to be checked + * @param auditEntity records necessary info for audit log * @throws AccessDeniedException if not allowed */ void checkTablePrivilege( - String userName, QualifiedObjectName tableName, TableModelPrivilege privilege); + String userName, + QualifiedObjectName tableName, + TableModelPrivilege privilege, + IAuditEntity auditEntity); void checkTablePrivilegeGrantOption( - String userName, QualifiedObjectName tableName, TableModelPrivilege privilege); + String userName, + QualifiedObjectName tableName, + TableModelPrivilege privilege, + IAuditEntity auditEntity); // This does not throw exception for performance issue. - boolean checkTablePrivilege4Pipe(final String userName, final QualifiedObjectName tableName); + boolean checkTablePrivilege4Pipe( + final String userName, final QualifiedObjectName tableName, IAuditEntity auditEntity); /** * Check if user has any privilege on the specified table or bigger scope (like database or ANY). * * @param userName name of user * @param tableName qualified name of table without `root.` prefix, like db.table1 + * @param auditEntity records necessary info for audit log * @throws AccessDeniedException if not allowed */ - void checkTableVisibility(String userName, QualifiedObjectName tableName); + void checkTableVisibility( + String userName, QualifiedObjectName tableName, IAuditEntity auditEntity); /** * Check if user has the specified global privilege * * @param userName name of user * @param privilege specified global privilege to be checked + * @param auditEntity records necessary info for audit log * @throws AccessDeniedException if not allowed */ - void checkGlobalPrivilege(String userName, TableModelPrivilege privilege); + void checkGlobalPrivilege( + String userName, TableModelPrivilege privilege, IAuditEntity auditEntity); - void checkGlobalPrivileges(String username, Collection<PrivilegeType> privileges); + void checkGlobalPrivileges( + String username, Collection<PrivilegeType> privileges, IAuditEntity auditEntity); /** * Check if user has the specified global privilege * * @param userName name of user * @param privilege specified global privilege to be checked + * @param auditEntity records necessary info for audit log * @throws AccessDeniedException if not allowed */ - void checkGlobalPrivilegeGrantOption(String userName, TableModelPrivilege privilege); + void checkGlobalPrivilegeGrantOption( + String userName, TableModelPrivilege privilege, IAuditEntity auditEntity); - void checkAnyScopePrivilegeGrantOption(String userName, TableModelPrivilege privilege); + void checkAnyScopePrivilegeGrantOption( + String userName, TableModelPrivilege privilege, 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 9a553207f43..07c092ff6c2 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 @@ -19,9 +19,14 @@ package org.apache.iotdb.db.queryengine.plan.relational.security; import org.apache.iotdb.common.rpc.thrift.TSStatus; +import org.apache.iotdb.commons.audit.AuditEventType; +import org.apache.iotdb.commons.audit.AuditLogFields; +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.schema.table.InformationSchema; +import org.apache.iotdb.db.audit.DNAuditLogger; import org.apache.iotdb.db.auth.AuthorityChecker; import org.apache.iotdb.db.queryengine.plan.relational.metadata.QualifiedObjectName; import org.apache.iotdb.rpc.TSStatusCode; @@ -32,42 +37,105 @@ import static org.apache.iotdb.commons.schema.table.Audit.TABLE_MODEL_AUDIT_DATA public class ITableAuthCheckerImpl implements ITableAuthChecker { + private static final DNAuditLogger AUDIT_LOGGER = DNAuditLogger.getInstance(); + + private static final String OBJECT_AUTHENTICATION_AUDIT_STR = + "User %s (ID=%d) requests authority on object %s with result %s"; + @Override - public void checkDatabaseVisibility(String userName, String databaseName) { + public void checkDatabaseVisibility( + String userName, String databaseName, IAuditEntity auditEntity) { if (AuthorityChecker.SUPER_USER.equals(userName)) { + recordAuditLog( + auditEntity + .setAuditLogOperation(AuditLogOperation.QUERY) + .setPrivilegeType(PrivilegeType.READ_SCHEMA) + .setResult(true), + databaseName); return; } // Information_schema is visible to any user if (databaseName.equals(InformationSchema.INFORMATION_DATABASE)) { + recordAuditLog( + auditEntity + .setAuditLogOperation(AuditLogOperation.QUERY) + .setPrivilegeType(PrivilegeType.READ_SCHEMA) + .setResult(true), + databaseName); return; } 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); return; } else { + recordAuditLog( + auditEntity + .setAuditLogOperation(AuditLogOperation.QUERY) + .setPrivilegeType(PrivilegeType.READ_SCHEMA) + .setResult(false), + databaseName); throw new AccessDeniedException("DATABASE " + databaseName); } } if (AuthorityChecker.checkSystemPermission(userName, PrivilegeType.SYSTEM)) { + recordAuditLog( + auditEntity + .setAuditLogOperation(AuditLogOperation.QUERY) + .setPrivilegeType(PrivilegeType.READ_SCHEMA) + .setResult(true), + databaseName); return; } if (!AuthorityChecker.checkDBVisible(userName, databaseName)) { + recordAuditLog( + auditEntity + .setAuditLogOperation(AuditLogOperation.QUERY) + .setPrivilegeType(PrivilegeType.READ_SCHEMA) + .setResult(false), + databaseName); throw new AccessDeniedException("DATABASE " + databaseName); } + recordAuditLog( + auditEntity + .setAuditLogOperation(AuditLogOperation.QUERY) + .setPrivilegeType(PrivilegeType.READ_SCHEMA) + .setResult(true), + databaseName); } @Override public void checkDatabasePrivilege( - String userName, String databaseName, TableModelPrivilege privilege) { - checkAuditDatabase(userName, privilege, databaseName); + String userName, + String databaseName, + TableModelPrivilege privilege, + IAuditEntity auditEntity) { + checkAuditDatabase(userName, privilege, databaseName, auditEntity); if (AuthorityChecker.SUPER_USER.equals(userName)) { + recordAuditLog( + auditEntity + .setAuditLogOperation(privilege.getAuditLogOperation()) + .setPrivilegeType(privilege.getPrivilegeType()) + .setResult(true), + databaseName); return; } if (AuthorityChecker.checkSystemPermission(userName, PrivilegeType.SYSTEM)) { + recordAuditLog( + auditEntity + .setAuditLogOperation(privilege.getAuditLogOperation()) + .setPrivilegeType(privilege.getPrivilegeType()) + .setResult(true), + databaseName); return; } @@ -77,36 +145,81 @@ public class ITableAuthCheckerImpl implements ITableAuthChecker { userName, databaseName, privilege.getPrivilegeType()), privilege.getPrivilegeType(), databaseName); - if (result.getCode() != TSStatusCode.SUCCESS_STATUS.getStatusCode()) { - throw new AccessDeniedException(result.getMessage()); - } + recordAuditLogViaAuthenticationResult(databaseName, privilege, auditEntity, result); } private static void checkAuditDatabase( - String userName, TableModelPrivilege privilege, String databaseName) { + String userName, + TableModelPrivilege privilege, + String databaseName, + IAuditEntity auditEntity) { if (TABLE_MODEL_AUDIT_DATABASE.equalsIgnoreCase(databaseName)) { if (privilege == TableModelPrivilege.SELECT) { - checkCanSelectAuditTable(userName); + checkCanSelectAuditTable(userName, auditEntity); } else { + recordAuditLog( + auditEntity + .setAuditLogOperation(privilege.getAuditLogOperation()) + .setPrivilegeType(privilege.getPrivilegeType()) + .setResult(false), + databaseName); throw new AccessDeniedException( String.format("The database '%s' is read-only.", TABLE_MODEL_AUDIT_DATABASE)); } } } - public static void checkCanSelectAuditTable(String userName) { + public static void checkCanSelectAuditTable(String userName, IAuditEntity auditEntity) { if (!AuthorityChecker.SUPER_USER.equals(userName) && !AuthorityChecker.checkSystemPermission(userName, PrivilegeType.AUDIT)) { + recordAuditLog( + auditEntity + .setAuditLogOperation(AuditLogOperation.QUERY) + .setPrivilegeType(PrivilegeType.SELECT) + .setResult(false), + TABLE_MODEL_AUDIT_DATABASE); + AUDIT_LOGGER.log( + new AuditLogFields( + userName, + auditEntity.getUserId(), + auditEntity.getCliHostname(), + AuditEventType.OBJECT_AUTHENTICATION, + AuditLogOperation.QUERY, + PrivilegeType.SELECT, + false, + TABLE_MODEL_AUDIT_DATABASE, + auditEntity.getSqlString()), + String.format( + OBJECT_AUTHENTICATION_AUDIT_STR, + userName, + auditEntity.getUserId(), + TABLE_MODEL_AUDIT_DATABASE, + false)); throw new AccessDeniedException( String.format( "The database '%s' can only be queried by AUDIT admin.", TABLE_MODEL_AUDIT_DATABASE)); } + recordAuditLog( + auditEntity + .setAuditLogOperation(AuditLogOperation.QUERY) + .setPrivilegeType(PrivilegeType.SELECT) + .setResult(true), + TABLE_MODEL_AUDIT_DATABASE); } @Override public void checkDatabasePrivilegeGrantOption( - String userName, String databaseName, TableModelPrivilege privilege) { + String userName, + String databaseName, + TableModelPrivilege privilege, + IAuditEntity auditEntity) { if (AuthorityChecker.SUPER_USER.equals(userName)) { + recordAuditLog( + auditEntity + .setAuditLogOperation(privilege.getAuditLogOperation()) + .setPrivilegeType(privilege.getPrivilegeType()) + .setResult(true), + databaseName); return; } TSStatus result = @@ -115,15 +228,23 @@ public class ITableAuthCheckerImpl implements ITableAuthChecker { userName, databaseName, privilege.getPrivilegeType()), privilege.getPrivilegeType(), databaseName); - if (result.getCode() != TSStatusCode.SUCCESS_STATUS.getStatusCode()) { - throw new AccessDeniedException(result.getMessage()); - } + recordAuditLogViaAuthenticationResult(databaseName, privilege, auditEntity, result); } @Override public void checkTablePrivilege( - String userName, QualifiedObjectName tableName, TableModelPrivilege privilege) { + String userName, + QualifiedObjectName tableName, + TableModelPrivilege privilege, + IAuditEntity auditEntity) { if (AuthorityChecker.SUPER_USER.equals(userName)) { + recordAuditLog( + auditEntity + .setDatabase(tableName.getDatabaseName()) + .setAuditLogOperation(privilege.getAuditLogOperation()) + .setPrivilegeType(privilege.getPrivilegeType()) + .setResult(true), + tableName.getObjectName()); return; } TSStatus result = @@ -136,15 +257,24 @@ public class ITableAuthCheckerImpl implements ITableAuthChecker { privilege.getPrivilegeType(), tableName.getDatabaseName(), tableName.getObjectName()); - if (result.getCode() != TSStatusCode.SUCCESS_STATUS.getStatusCode()) { - throw new AccessDeniedException(result.getMessage()); - } + recordAuditLogViaAuthenticationResult( + tableName.getObjectName(), privilege, auditEntity, result); } @Override public void checkTablePrivilegeGrantOption( - String userName, QualifiedObjectName tableName, TableModelPrivilege privilege) { + String userName, + QualifiedObjectName tableName, + TableModelPrivilege privilege, + IAuditEntity auditEntity) { if (AuthorityChecker.SUPER_USER.equals(userName)) { + recordAuditLog( + auditEntity + .setDatabase(tableName.getDatabaseName()) + .setAuditLogOperation(privilege.getAuditLogOperation()) + .setPrivilegeType(privilege.getPrivilegeType()) + .setResult(true), + tableName.getObjectName()); return; } TSStatus result = @@ -157,15 +287,14 @@ public class ITableAuthCheckerImpl implements ITableAuthChecker { privilege.getPrivilegeType(), tableName.getDatabaseName(), tableName.getObjectName()); - if (result.getCode() != TSStatusCode.SUCCESS_STATUS.getStatusCode()) { - throw new AccessDeniedException(result.getMessage()); - } + recordAuditLogViaAuthenticationResult( + tableName.getObjectName(), privilege, auditEntity, result); } @Override public boolean checkTablePrivilege4Pipe( - final String userName, final QualifiedObjectName tableName) { - return AuthorityChecker.SUPER_USER.equals(userName) + final String userName, final QualifiedObjectName tableName, IAuditEntity auditEntity) { + if (AuthorityChecker.SUPER_USER.equals(userName) || AuthorityChecker.getTSStatus( AuthorityChecker.checkTablePermission( userName, @@ -176,47 +305,107 @@ public class ITableAuthCheckerImpl implements ITableAuthChecker { tableName.getDatabaseName(), tableName.getObjectName()) .getCode() - == TSStatusCode.SUCCESS_STATUS.getStatusCode(); + == TSStatusCode.SUCCESS_STATUS.getStatusCode()) { + recordAuditLog( + auditEntity + .setDatabase(tableName.getDatabaseName()) + .setAuditLogOperation(AuditLogOperation.CONTROL) + .setPrivilegeType(PrivilegeType.SYSTEM) + .setResult(true), + tableName.getObjectName()); + return true; + } + recordAuditLog( + auditEntity + .setDatabase(tableName.getDatabaseName()) + .setAuditLogOperation(AuditLogOperation.CONTROL) + .setPrivilegeType(PrivilegeType.SYSTEM) + .setResult(false), + tableName.getObjectName()); + return false; } @Override - public void checkTableVisibility(String userName, QualifiedObjectName tableName) { + public void checkTableVisibility( + String userName, QualifiedObjectName tableName, IAuditEntity auditEntity) { if (AuthorityChecker.SUPER_USER.equals(userName)) { + recordAuditLog( + auditEntity + .setDatabase(tableName.getDatabaseName()) + .setAuditLogOperation(AuditLogOperation.QUERY) + .setPrivilegeType(PrivilegeType.READ_SCHEMA) + .setResult(true), + tableName.getObjectName()); return; } String databaseName = tableName.getDatabaseName(); if (TABLE_MODEL_AUDIT_DATABASE.equalsIgnoreCase(databaseName) && !AuthorityChecker.checkSystemPermission(userName, PrivilegeType.AUDIT)) { + recordAuditLog( + auditEntity + .setDatabase(tableName.getDatabaseName()) + .setAuditLogOperation(AuditLogOperation.QUERY) + .setPrivilegeType(PrivilegeType.READ_SCHEMA) + .setResult(false), + tableName.getObjectName()); throw new AccessDeniedException("TABLE " + tableName); } if (AuthorityChecker.checkSystemPermission(userName, PrivilegeType.SYSTEM)) { + recordAuditLog( + auditEntity + .setDatabase(tableName.getDatabaseName()) + .setAuditLogOperation(AuditLogOperation.QUERY) + .setPrivilegeType(PrivilegeType.READ_SCHEMA) + .setResult(true), + tableName.getObjectName()); return; } if (!AuthorityChecker.checkTableVisible( userName, tableName.getDatabaseName(), tableName.getObjectName())) { + recordAuditLog( + auditEntity + .setDatabase(tableName.getDatabaseName()) + .setAuditLogOperation(AuditLogOperation.QUERY) + .setPrivilegeType(PrivilegeType.READ_SCHEMA) + .setResult(false), + tableName.getObjectName()); throw new AccessDeniedException("TABLE " + tableName); } } @Override - public void checkGlobalPrivilege(String userName, TableModelPrivilege privilege) { + public void checkGlobalPrivilege( + String userName, TableModelPrivilege privilege, IAuditEntity auditEntity) { if (AuthorityChecker.SUPER_USER.equals(userName)) { + recordAuditLog( + auditEntity + .setAuditLogOperation(privilege.getAuditLogOperation()) + .setPrivilegeType(privilege.getPrivilegeType()) + .setResult(true), + AuthorityChecker.ANY_SCOPE); return; } TSStatus result = AuthorityChecker.getTSStatus( AuthorityChecker.checkSystemPermission(userName, privilege.getPrivilegeType()), privilege.getPrivilegeType()); - if (result.getCode() != TSStatusCode.SUCCESS_STATUS.getStatusCode()) { - throw new AccessDeniedException(result.getMessage()); - } + recordAuditLogViaAuthenticationResult(userName, privilege, auditEntity, result); } @Override - public void checkGlobalPrivileges(String username, Collection<PrivilegeType> privileges) { + public void checkGlobalPrivileges( + String username, Collection<PrivilegeType> privileges, IAuditEntity auditEntity) { if (AuthorityChecker.SUPER_USER.equals(username)) { + for (PrivilegeType privilege : privileges) { + recordAuditLog( + auditEntity + .setAuditLogOperation(privilege.getAuditLogOperation()) + .setPrivilegeType(privilege) + .setResult(true), + AuthorityChecker.ANY_SCOPE); + } return; } TSStatus result = @@ -228,8 +417,15 @@ public class ITableAuthCheckerImpl implements ITableAuthChecker { } @Override - public void checkGlobalPrivilegeGrantOption(String userName, TableModelPrivilege privilege) { + public void checkGlobalPrivilegeGrantOption( + String userName, TableModelPrivilege privilege, IAuditEntity auditEntity) { if (AuthorityChecker.SUPER_USER.equals(userName)) { + recordAuditLog( + auditEntity + .setAuditLogOperation(privilege.getAuditLogOperation()) + .setPrivilegeType(privilege.getPrivilegeType()) + .setResult(true), + AuthorityChecker.ANY_SCOPE); return; } TSStatus result = @@ -237,14 +433,20 @@ public class ITableAuthCheckerImpl implements ITableAuthChecker { AuthorityChecker.checkSystemPermissionGrantOption( userName, privilege.getPrivilegeType()), privilege.getPrivilegeType()); - if (result.getCode() != TSStatusCode.SUCCESS_STATUS.getStatusCode()) { - throw new AccessDeniedException(result.getMessage()); - } + recordAuditLogViaAuthenticationResult( + AuthorityChecker.ANY_SCOPE, privilege, auditEntity, result); } @Override - public void checkAnyScopePrivilegeGrantOption(String userName, TableModelPrivilege privilege) { + public void checkAnyScopePrivilegeGrantOption( + String userName, TableModelPrivilege privilege, IAuditEntity auditEntity) { if (AuthorityChecker.SUPER_USER.equals(userName)) { + recordAuditLog( + auditEntity + .setAuditLogOperation(privilege.getAuditLogOperation()) + .setPrivilegeType(privilege.getPrivilegeType()) + .setResult(true), + AuthorityChecker.ANY_SCOPE); return; } TSStatus result = @@ -252,8 +454,49 @@ public class ITableAuthCheckerImpl implements ITableAuthChecker { AuthorityChecker.checkAnyScopePermissionGrantOption( userName, privilege.getPrivilegeType()), privilege.getPrivilegeType()); + recordAuditLogViaAuthenticationResult( + AuthorityChecker.ANY_SCOPE, privilege, auditEntity, result); + } + + private void recordAuditLogViaAuthenticationResult( + String auditObject, + TableModelPrivilege privilege, + IAuditEntity auditEntity, + TSStatus result) { if (result.getCode() != TSStatusCode.SUCCESS_STATUS.getStatusCode()) { + recordAuditLog( + auditEntity + .setAuditLogOperation(privilege.getAuditLogOperation()) + .setPrivilegeType(privilege.getPrivilegeType()) + .setResult(false), + auditObject); throw new AccessDeniedException(result.getMessage()); } + recordAuditLog( + auditEntity + .setAuditLogOperation(privilege.getAuditLogOperation()) + .setPrivilegeType(privilege.getPrivilegeType()) + .setResult(true), + auditObject); + } + + private static void recordAuditLog(IAuditEntity auditEntity, String auditObject) { + AUDIT_LOGGER.log( + new AuditLogFields( + auditEntity.getUsername(), + auditEntity.getUserId(), + auditEntity.getCliHostname(), + AuditEventType.OBJECT_AUTHENTICATION, + auditEntity.getAuditLogOperation(), + auditEntity.getPrivilegeType(), + auditEntity.getResult(), + auditEntity.getDatabase(), + auditEntity.getSqlString()), + String.format( + OBJECT_AUTHENTICATION_AUDIT_STR, + auditEntity.getUsername(), + auditEntity.getUserId(), + auditObject, + true)); } } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/TableModelPrivilege.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/TableModelPrivilege.java index 3372d3af75f..d06a08ef026 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/TableModelPrivilege.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/security/TableModelPrivilege.java @@ -19,6 +19,7 @@ package org.apache.iotdb.db.queryengine.plan.relational.security; +import org.apache.iotdb.commons.audit.AuditLogOperation; import org.apache.iotdb.commons.auth.entity.PrivilegeType; public enum TableModelPrivilege { @@ -97,4 +98,26 @@ public enum TableModelPrivilege { throw new IllegalStateException("Unexpected value:" + privilegeType); } } + + public AuditLogOperation getAuditLogOperation() { + switch (this) { + case CREATE: + case DROP: + case ALTER: + return AuditLogOperation.DDL; + case SELECT: + return AuditLogOperation.QUERY; + case INSERT: + case DELETE: + return AuditLogOperation.DML; + case MANAGE_ROLE: + case MANAGE_USER: + case SYSTEM: + case SECURITY: + case AUDIT: + return AuditLogOperation.CONTROL; + default: + throw new IllegalStateException("Unexpected value:" + this); + } + } } diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/audit/AuditEventType.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/audit/AuditEventType.java index 50f2b24be96..81ac94ad4dd 100644 --- a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/audit/AuditEventType.java +++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/audit/AuditEventType.java @@ -25,7 +25,7 @@ public enum AuditEventType { GENERATE_KEY, DESTROY_KEY, EXECUTE_ENCRYPT, - OBJECT_AUTHENTICATION_SUCCESS, + OBJECT_AUTHENTICATION, LBAC_AUTHENTICATION, EXPORT_DATA_WITH_LABEL, IMPORT_DATA_WITH_LABEL, diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/audit/AuditLogFields.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/audit/AuditLogFields.java index f272ae1e24b..2c060911def 100644 --- a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/audit/AuditLogFields.java +++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/audit/AuditLogFields.java @@ -29,7 +29,7 @@ public class AuditLogFields { private final AuditEventType auditType; private final AuditLogOperation operationType; private final PrivilegeType privilegeType; - private final boolean result; + private boolean result; private final String database; private final String sqlString; @@ -82,6 +82,11 @@ public class AuditLogFields { return result; } + public AuditLogFields setResult(boolean result) { + this.result = result; + return this; + } + public String getDatabase() { return database; } diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/audit/IAuditEntity.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/audit/IAuditEntity.java new file mode 100644 index 00000000000..ccba49082a1 --- /dev/null +++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/audit/IAuditEntity.java @@ -0,0 +1,34 @@ +package org.apache.iotdb.commons.audit; + +import org.apache.iotdb.commons.auth.entity.PrivilegeType; + +public interface IAuditEntity { + + int getUserId(); + + String getUsername(); + + String getCliHostname(); + + AuditEventType getAuditEventType(); + + IAuditEntity setAuditEventType(AuditEventType auditEventType); + + AuditLogOperation getAuditLogOperation(); + + IAuditEntity setAuditLogOperation(AuditLogOperation auditLogOperation); + + PrivilegeType getPrivilegeType(); + + IAuditEntity setPrivilegeType(PrivilegeType privilegeType); + + boolean getResult(); + + IAuditEntity setResult(boolean result); + + String getDatabase(); + + IAuditEntity setDatabase(String database); + + String getSqlString(); +} diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/entity/PrivilegeType.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/entity/PrivilegeType.java index 972a6de9ee2..29dc5301a84 100644 --- a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/entity/PrivilegeType.java +++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/auth/entity/PrivilegeType.java @@ -19,6 +19,7 @@ package org.apache.iotdb.commons.auth.entity; +import org.apache.iotdb.commons.audit.AuditLogOperation; import org.apache.iotdb.commons.utils.TestOnly; import java.util.Arrays; @@ -191,4 +192,38 @@ public enum PrivilegeType { public boolean isHided() { return this == AUDIT; } + + public AuditLogOperation getAuditLogOperation() { + switch (this) { + case READ_DATA: + case READ_SCHEMA: + case SELECT: + return AuditLogOperation.QUERY; + case CREATE: + case DROP: + case ALTER: + case MANAGE_DATABASE: + return AuditLogOperation.DDL; + case WRITE_DATA: + case WRITE_SCHEMA: + case INSERT: + case DELETE: + return AuditLogOperation.DML; + case MANAGE_USER: + case MANAGE_ROLE: + case USE_TRIGGER: + case USE_UDF: + case USE_CQ: + case USE_PIPE: + case USE_MODEL: + case EXTEND_TEMPLATE: + case MAINTAIN: + case SYSTEM: + case SECURITY: + case AUDIT: + return AuditLogOperation.CONTROL; + default: + throw new IllegalStateException("Unexpected value:" + this); + } + } }
