Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ public static void closeConnectionCompletely(Connection connection) throws Inter
"DROP DATABASE IF EXISTS test",
"REVOKE SELECT,ALTER,INSERT,DELETE ON TEST.TABLE1 FROM USER user1",
"REVOKE SELECT ON ANY FROM ROLE role1",
"REVOKE ROLE role1 FROM user2",
"DROP USER user1",
"DROP USER user2",
"DROP ROLE role1");
Expand Down Expand Up @@ -634,7 +635,33 @@ public static void closeConnectionCompletely(Connection connection) throws Inter
"true",
"null",
"GRANT ROLE role1 TO user2",
"User root (ID=0) requests authority on object user: user2, role: role1 with result true")),
"User root (ID=0) requests authority on object user: user2, role: role1 with result true"),
Arrays.asList(
"node_1",
"u_0",
"root",
"127.0.0.1",
"MODIFY_SECURITY_FUNCTION",
"CONTROL",
"[SECURITY]",
"GLOBAL",
"true",
"test",
"GRANT ROLE role1 TO user2",
"security function: user-role membership, user: user2, role: role1"),
Arrays.asList(
"node_1",
"u_0",
"root",
"127.0.0.1",
"MODIFY_ROLE_MEMBERSHIP",
"CONTROL",
"[SECURITY]",
"GLOBAL",
"true",
"test",
"GRANT ROLE role1 TO user2",
"user: user2, role: role1")),
// List user/role, the authentication object is null since the root can list all
new AuditLogSet(
Arrays.asList(
Expand Down Expand Up @@ -1192,7 +1219,46 @@ public static void closeConnectionCompletely(Connection connection) throws Inter
"true",
"null",
"REVOKE SELECT ON ANY FROM ROLE role1",
"User root (ID=0) requests authority on object role1 with result true")),
"User root (ID=0) requests authority on object role1 with result true"),
Arrays.asList(
"node_1",
"u_0",
"root",
"127.0.0.1",
"OBJECT_AUTHENTICATION",
"DDL",
"[SECURITY]",
"GLOBAL",
"true",
"null",
"REVOKE ROLE role1 FROM user2",
"User root (ID=0) requests authority on object user: user2, role: role1 with result true"),
Arrays.asList(
"node_1",
"u_0",
"root",
"127.0.0.1",
"MODIFY_SECURITY_FUNCTION",
"CONTROL",
"[SECURITY]",
"GLOBAL",
"true",
"null",
"REVOKE ROLE role1 FROM user2",
"security function: user-role membership, user: user2, role: role1"),
Arrays.asList(
"node_1",
"u_0",
"root",
"127.0.0.1",
"MODIFY_ROLE_MEMBERSHIP",
"CONTROL",
"[SECURITY]",
"GLOBAL",
"true",
"null",
"REVOKE ROLE role1 FROM user2",
"user: user2, role: role1")),
// Drop user, role
new AuditLogSet(
Arrays.asList(
Expand Down Expand Up @@ -1352,6 +1418,7 @@ public void basicAuditLogTestForTableModel() throws SQLException, InterruptedExc
"drop timeseries root.test.d1.*",
"REVOKE READ_DATA, WRITE_DATA ON root.test.** FROM USER user1",
"REVOKE READ ON root.test.** FROM ROLE role1",
"REVOKE ROLE role1 FROM user2",
"DROP USER user1",
"DROP USER user2",
"DROP ROLE role1",
Expand Down Expand Up @@ -1784,6 +1851,30 @@ public void basicAuditLogTestForTableModel() throws SQLException, InterruptedExc
"GRANT ROLE role1 TO user2",
"OBJECT_AUTHENTICATION",
"127.0.0.1",
"root"),
Arrays.asList(
"root.__audit.log.node_1.u_0",
"true",
"GLOBAL",
"[SECURITY]",
"null",
"CONTROL",
"security function: user-role membership, user: user2, role: role1",
"GRANT ROLE role1 TO user2",
"MODIFY_SECURITY_FUNCTION",
"127.0.0.1",
"root"),
Arrays.asList(
"root.__audit.log.node_1.u_0",
"true",
"GLOBAL",
"[SECURITY]",
"null",
"CONTROL",
"user: user2, role: role1",
"GRANT ROLE role1 TO user2",
"MODIFY_ROLE_MEMBERSHIP",
"127.0.0.1",
"root")),
// List user/role, the target object is null since the root can list all,
new AuditLogSet(
Expand Down Expand Up @@ -2318,6 +2409,42 @@ public void basicAuditLogTestForTableModel() throws SQLException, InterruptedExc
"REVOKE READ ON root.test.** FROM ROLE role1",
"OBJECT_AUTHENTICATION",
"127.0.0.1",
"root"),
Arrays.asList(
"root.__audit.log.node_1.u_0",
"true",
"GLOBAL",
"[MANAGE_ROLE]",
"null",
"DDL",
"User root (ID=0) requests authority on object user: user2, role: role1 with result true",
"REVOKE ROLE role1 FROM user2",
"OBJECT_AUTHENTICATION",
"127.0.0.1",
"root"),
Arrays.asList(
"root.__audit.log.node_1.u_0",
"true",
"GLOBAL",
"[SECURITY]",
"null",
"CONTROL",
"security function: user-role membership, user: user2, role: role1",
"REVOKE ROLE role1 FROM user2",
"MODIFY_SECURITY_FUNCTION",
"127.0.0.1",
"root"),
Arrays.asList(
"root.__audit.log.node_1.u_0",
"true",
"GLOBAL",
"[SECURITY]",
"null",
"CONTROL",
"user: user2, role: role1",
"REVOKE ROLE role1 FROM user2",
"MODIFY_ROLE_MEMBERSHIP",
"127.0.0.1",
"root")),
// Drop user/role
new AuditLogSet(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,11 @@ public final class DataNodeMiscMessages {

public static final String CREATE_NEW_REGION_ERROR_FMT = "create new region %s error, exception:%s";
public static final String CREATE_NEW_REGION_SUCCEED_FMT = "create new region %s succeed";
public static final String LOG_USER_ARG_ROLE_ARG_422D48D3 = "user: %s, role: %s";
public static final String
LOG_SECURITY_FUNCTION_USER_ROLE_MEMBERSHIP_USER_ARG_ROLE_ARG_0D500C5D =
"security function: user-role membership, user: %s, role: %s";

private DataNodeMiscMessages() {}

// ---------------------------------------------------------------------------
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,11 @@ public final class DataNodeMiscMessages {

public static final String CREATE_NEW_REGION_ERROR_FMT = "创建新 region %s 错误,异常:%s";
public static final String CREATE_NEW_REGION_SUCCEED_FMT = "创建新 region %s 成功";
public static final String LOG_USER_ARG_ROLE_ARG_422D48D3 = "用户:%s,角色:%s";
public static final String
LOG_SECURITY_FUNCTION_USER_ROLE_MEMBERSHIP_USER_ARG_ROLE_ARG_0D500C5D =
"安全功能:用户角色成员关系,用户:%s,角色:%s";

private DataNodeMiscMessages() {}

// ---------------------------------------------------------------------------
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package org.apache.iotdb.db.audit;

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.auth.entity.PrivilegeType;
import org.apache.iotdb.commons.queryengine.common.SessionInfo;
import org.apache.iotdb.db.i18n.DataNodeMiscMessages;
import org.apache.iotdb.db.queryengine.plan.relational.sql.ast.RelationalAuthorStatement;
import org.apache.iotdb.db.queryengine.plan.relational.type.AuthorRType;
import org.apache.iotdb.db.queryengine.plan.statement.AuthorType;
import org.apache.iotdb.db.queryengine.plan.statement.sys.AuthorStatement;
import org.apache.iotdb.rpc.TSStatusCode;

import java.util.function.Supplier;

/** Tracks one user-role membership statement and logs its successful security changes. */
public class UserRoleModificationAuditContext {

private final DNAuditLogger auditLogger;
private final String sqlString;

private Long userId;
private String username;
private String clientAddress;
private String database;
private String targetUsername;
private String targetRoleName;

public UserRoleModificationAuditContext(String sqlString) {
this(DNAuditLogger.getInstance(), sqlString);
}

UserRoleModificationAuditContext(DNAuditLogger auditLogger, String sqlString) {
this.auditLogger = auditLogger;
this.sqlString = sqlString;
}

public void setSessionInfo(SessionInfo sessionInfo) {
if (sessionInfo == null) {
return;
}
setActor(
sessionInfo.getUserId(),
sessionInfo.getUserName(),
sessionInfo.getCliHostname(),
sessionInfo.getDatabaseName().orElse(null));
}

private void setActor(long userId, String username, String clientAddress, String database) {
this.userId = userId;
this.username = username;
this.clientAddress = clientAddress;
this.database = database;
}

public void track(AuthorStatement statement) {
if (statement.getAuthorType() == AuthorType.GRANT_USER_ROLE
|| statement.getAuthorType() == AuthorType.REVOKE_USER_ROLE) {
targetUsername = statement.getUserName();
targetRoleName = statement.getRoleName();
}
}

public void track(RelationalAuthorStatement statement) {
if (statement.getAuthorType() == AuthorRType.GRANT_USER_ROLE
|| statement.getAuthorType() == AuthorRType.REVOKE_USER_ROLE) {
targetUsername = statement.getUserName();
targetRoleName = statement.getRoleName();
}
}

public void log(TSStatus status) {
if (targetUsername == null || userId == null || !isSuccessful(status)) {
return;
}
logEvent(
AuditEventType.MODIFY_SECURITY_FUNCTION,
() ->
String.format(
DataNodeMiscMessages
.LOG_SECURITY_FUNCTION_USER_ROLE_MEMBERSHIP_USER_ARG_ROLE_ARG_0D500C5D,
targetUsername,
targetRoleName));
logEvent(
AuditEventType.MODIFY_ROLE_MEMBERSHIP,
() ->
String.format(
DataNodeMiscMessages.LOG_USER_ARG_ROLE_ARG_422D48D3,
targetUsername,
targetRoleName));
}

private void logEvent(AuditEventType eventType, Supplier<String> log) {
auditLogger.log(
new AuditLogFields(
userId,
username,
clientAddress,
eventType,
AuditLogOperation.CONTROL,
PrivilegeType.SECURITY,
true,
database,
sqlString),
log);
}

private static boolean isSuccessful(TSStatus status) {
return status != null && status.getCode() == TSStatusCode.SUCCESS_STATUS.getStatusCode();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
import org.apache.iotdb.commons.queryengine.plan.relational.type.InternalTypeManager;
import org.apache.iotdb.commons.queryengine.plan.relational.type.TypeManager;
import org.apache.iotdb.db.audit.DNAuditLogger;
import org.apache.iotdb.db.audit.UserRoleModificationAuditContext;
import org.apache.iotdb.db.auth.AuthorityChecker;
import org.apache.iotdb.db.conf.IoTDBConfig;
import org.apache.iotdb.db.conf.IoTDBDescriptor;
Expand Down Expand Up @@ -157,6 +158,7 @@
import org.apache.iotdb.db.queryengine.plan.statement.IConfigStatement;
import org.apache.iotdb.db.queryengine.plan.statement.Statement;
import org.apache.iotdb.db.queryengine.plan.statement.pipe.PipeEnrichedStatement;
import org.apache.iotdb.db.queryengine.plan.statement.sys.AuthorStatement;
import org.apache.iotdb.db.queryengine.udf.InternalQueryExecutor;
import org.apache.iotdb.db.utils.SetThreadName;

Expand Down Expand Up @@ -415,6 +417,13 @@ public ExecutionResult executeForTreeModel(
} finally {
DNAuditLogger.getInstance()
.logRevokeFailure(statement, session, sql, result == null ? null : result.status);
if (statement instanceof AuthorStatement) {
final UserRoleModificationAuditContext auditContext =
new UserRoleModificationAuditContext(sql);
auditContext.setSessionInfo(session);
auditContext.track((AuthorStatement) statement);
auditContext.log(result == null ? null : result.status);
}
}
}

Expand Down Expand Up @@ -563,6 +572,13 @@ public ExecutionResult executeForTableModel(
} finally {
DNAuditLogger.getInstance()
.logRevokeFailure(statement, session, sql, result == null ? null : result.status);
if (statement instanceof RelationalAuthorStatement) {
final UserRoleModificationAuditContext auditContext =
new UserRoleModificationAuditContext(sql);
auditContext.setSessionInfo(session);
auditContext.track((RelationalAuthorStatement) statement);
auditContext.log(result == null ? null : result.status);
}
}
}

Expand Down
Loading