Skip to content

Commit

Permalink
feat: added operation audit for data source and users (#1987)
Browse files Browse the repository at this point in the history
  • Loading branch information
rolin999 authored Nov 28, 2024
1 parent b92a9b6 commit 0c5a689
Show file tree
Hide file tree
Showing 8 changed files with 868 additions and 94 deletions.
94 changes: 23 additions & 71 deletions src/bk-user/bkuser/apis/web/data_source/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,6 @@
LocalDataSourceImportInputSLZ,
)
from bkuser.apis.web.mixins import CurrentUserTenantMixin
from bkuser.apps.audit.constants import ObjectTypeEnum, OperationEnum
from bkuser.apps.audit.recorder import add_audit_record
from bkuser.apps.data_source.constants import DataSourceTypeEnum
from bkuser.apps.data_source.models import (
DataSource,
Expand All @@ -70,6 +68,7 @@
from bkuser.apps.sync.managers import DataSourceSyncManager
from bkuser.apps.sync.models import DataSourceSyncTask, TenantSyncTask
from bkuser.apps.tenant.models import TenantDepartment, TenantUser
from bkuser.biz.auditor import DataSourceAuditor
from bkuser.biz.data_source import DataSourceHandler
from bkuser.biz.exporters import DataSourceUserExporter
from bkuser.biz.tenant import TenantUserHandler
Expand Down Expand Up @@ -186,19 +185,10 @@ def post(self, request, *args, **kwargs):
updater=current_user,
)

# 审计记录
add_audit_record(
operator=current_user,
tenant_id=current_tenant_id,
operation=OperationEnum.CREATE_DATA_SOURCE,
object_type=ObjectTypeEnum.DATA_SOURCE,
object_id=ds.id,
extras={
"plugin_config": ds.plugin_config,
"field_mapping": ds.field_mapping,
"sync_config": ds.sync_config,
},
)
# 【审计】创建数据源审计对象并记录
auditor = DataSourceAuditor(request.user.username, current_tenant_id, ds)
# 【审计】将审计记录保存至数据库
auditor.record_create()

return Response(
DataSourceCreateOutputSLZ(instance={"id": ds.id}).data,
Expand Down Expand Up @@ -252,12 +242,9 @@ def put(self, request, *args, **kwargs):
slz.is_valid(raise_exception=True)
data = slz.validated_data

# 【审计】记录变更前数据
data_before = {
"plugin_config": data_source.plugin_config,
"field_mapping": data_source.field_mapping,
"sync_config": data_source.sync_config,
}
# 【审计】创建数据源审计对象,并记录变更前数据
auditor = DataSourceAuditor(request.user.username, data_source.owner_tenant_id, data_source)
auditor.pre_record_data_before()

with transaction.atomic():
data_source.field_mapping = data["field_mapping"]
Expand All @@ -267,15 +254,8 @@ def put(self, request, *args, **kwargs):
# 由于需要替换敏感信息,因此需要独立调用 set_plugin_cfg 方法
data_source.set_plugin_cfg(data["plugin_config"])

# 审计记录
add_audit_record(
operator=data_source.updater,
tenant_id=data_source.owner_tenant_id,
operation=OperationEnum.MODIFY_DATA_SOURCE,
object_type=ObjectTypeEnum.DATA_SOURCE,
object_id=data_source.id,
extras={"data_before": data_before},
)
# 【审计】将审计记录保存至数据库
auditor.record_update(data_source)

return Response(status=status.HTTP_204_NO_CONTENT)

Expand Down Expand Up @@ -308,14 +288,9 @@ def delete(self, request, *args, **kwargs):
# 待删除的认证源
waiting_delete_idps = Idp.objects.filter(**idp_filters)

# 【审计】记录变更前数据,数据删除后便无法获取
idps_before_delete = list(
waiting_delete_idps.values("id", "name", "status", "plugin_config", "data_source_match_rules")
)
data_source_id = data_source.id
plugin_config = data_source.plugin_config
field_mapping = data_source.field_mapping
sync_config = data_source.sync_config
# 【审计】创建数据源审计对象,并记录变更前数据
auditor = DataSourceAuditor(request.user.username, data_source.owner_tenant_id, data_source)
auditor.pre_record_data_before(list(waiting_delete_idps))

with transaction.atomic():
# 删除认证源敏感信息
Expand All @@ -334,21 +309,8 @@ def delete(self, request, *args, **kwargs):
# 删除数据源 & 关联资源数据
DataSourceHandler.delete_data_source_and_related_resources(data_source)

# 审计记录
add_audit_record(
operator=request.user.username,
tenant_id=self.get_current_tenant_id(),
operation=OperationEnum.DELETE_DATA_SOURCE,
object_type=ObjectTypeEnum.DATA_SOURCE,
object_id=data_source_id,
extras={
"is_delete_idp": is_delete_idp,
"plugin_config": plugin_config,
"field_mapping": field_mapping,
"sync_config": sync_config,
"idps_before_delete": idps_before_delete,
},
)
# 【审计】将审计记录保存至数据库
auditor.record_delete()

return Response(status=status.HTTP_204_NO_CONTENT)

Expand Down Expand Up @@ -543,15 +505,10 @@ def post(self, request, *args, **kwargs):
logger.exception("本地数据源 %s 导入失败", data_source.id)
raise error_codes.DATA_SOURCE_IMPORT_FAILED.f(str(e))

# 审计记录
add_audit_record(
operator=task.operator,
tenant_id=data_source.owner_tenant_id,
operation=OperationEnum.SYNC_DATA_SOURCE,
object_type=ObjectTypeEnum.DATA_SOURCE,
object_id=data_source.id,
extras={"overwrite": options.overwrite, "incremental": options.incremental, "trigger": options.trigger},
)
# 【审计】创建数据源审计对象并记录
auditor = DataSourceAuditor(request.user.username, data_source.owner_tenant_id, data_source)
# 【审计】将审计记录保存至数据库
auditor.record_sync(options)

return Response(
DataSourceImportOrSyncOutputSLZ(
Expand Down Expand Up @@ -596,15 +553,10 @@ def post(self, request, *args, **kwargs):
logger.exception("创建下发数据源 %s 同步任务失败", data_source.id)
raise error_codes.DATA_SOURCE_SYNC_TASK_CREATE_FAILED.f(str(e))

# 审计记录
add_audit_record(
operator=task.operator,
tenant_id=data_source.owner_tenant_id,
operation=OperationEnum.SYNC_DATA_SOURCE,
object_type=ObjectTypeEnum.DATA_SOURCE,
object_id=data_source.id,
extras={"overwrite": options.overwrite, "incremental": options.incremental, "trigger": options.trigger},
)
# 【审计】创建数据源审计对象并记录
auditor = DataSourceAuditor(request.user.username, data_source.owner_tenant_id, data_source)
# 【审计】将审计记录保存至数据库
auditor.record_sync(options)

return Response(
DataSourceImportOrSyncOutputSLZ(
Expand Down
50 changes: 50 additions & 0 deletions src/bk-user/bkuser/apis/web/organization/views/relations.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,12 @@
TenantDeptUserRelationBatchUpdateInputSLZ,
)
from bkuser.apis.web.organization.views.mixins import CurrentUserTenantDataSourceMixin
from bkuser.apps.audit.constants import OperationEnum
from bkuser.apps.data_source.models import DataSourceDepartmentUserRelation
from bkuser.apps.permission.constants import PermAction
from bkuser.apps.permission.permissions import perm_class
from bkuser.apps.tenant.models import TenantDepartment, TenantUser
from bkuser.biz.auditor import TenantUserDepartmentRelationsAuditor


class TenantDeptUserRelationBatchCreateApi(CurrentUserTenantDataSourceMixin, generics.CreateAPIView):
Expand Down Expand Up @@ -66,6 +68,15 @@ def post(self, request, *args, **kwargs):
id__in=data["user_ids"],
).values_list("data_source_user_id", flat=True)

# 【审计】创建审计对象并记录变更前的数据
auditor = TenantUserDepartmentRelationsAuditor(
request.user.username,
cur_tenant_id,
data_source_user_ids,
OperationEnum.CREATE_USER_DEPARTMENT,
)
auditor.pre_record_data_before()

# 复制操作:为数据源部门 & 用户添加关联边,但是不会影响存量的关联边
relations = [
DataSourceDepartmentUserRelation(user_id=user_id, department_id=dept_id, data_source=data_source)
Expand All @@ -74,6 +85,9 @@ def post(self, request, *args, **kwargs):
# 由于复制操作不会影响存量的关联边,所以需要忽略冲突,避免出现用户复选的情况
DataSourceDepartmentUserRelation.objects.bulk_create(relations, ignore_conflicts=True)

# 【审计】将审计记录保存至数据库
auditor.record(extras={"department_ids": list(data_source_dept_ids)})

return Response(status=status.HTTP_204_NO_CONTENT)


Expand Down Expand Up @@ -107,6 +121,15 @@ def put(self, request, *args, **kwargs):
id__in=data["user_ids"],
).values_list("data_source_user_id", flat=True)

# 【审计】创建审计对象并记录变更前的数据
auditor = TenantUserDepartmentRelationsAuditor(
request.user.username,
cur_tenant_id,
data_source_user_ids,
OperationEnum.MODIFY_USER_DEPARTMENT,
)
auditor.pre_record_data_before()

# 移动操作:为数据源部门 & 用户添加关联边,但是会删除这批用户所有的存量关联边
with transaction.atomic():
# 先删除
Expand All @@ -118,6 +141,9 @@ def put(self, request, *args, **kwargs):
]
DataSourceDepartmentUserRelation.objects.bulk_create(relations)

# 【审计】将审计记录保存至数据库
auditor.record(extras={"department_ids": list(data_source_dept_ids)})

return Response(status=status.HTTP_204_NO_CONTENT)

@swagger_auto_schema(
Expand Down Expand Up @@ -147,6 +173,15 @@ def patch(self, request, *args, **kwargs):
id__in=data["user_ids"],
).values_list("data_source_user_id", flat=True)

# 【审计】创建审计对象
auditor = TenantUserDepartmentRelationsAuditor(
request.user.username,
cur_tenant_id,
data_source_user_ids,
OperationEnum.MODIFY_USER_DEPARTMENT,
)
auditor.pre_record_data_before()

# 移动操作:为数据源部门 & 用户添加关联边,但是会删除这批用户在当前部门的存量关联边
with transaction.atomic():
# 先删除(仅限于指定部门)
Expand All @@ -160,6 +195,9 @@ def patch(self, request, *args, **kwargs):
]
DataSourceDepartmentUserRelation.objects.bulk_create(relations, ignore_conflicts=True)

# 【审计】将审计记录保存至数据库
auditor.record(extras={"department_id": source_data_source_dept.id})

return Response(status=status.HTTP_204_NO_CONTENT)


Expand Down Expand Up @@ -191,8 +229,20 @@ def delete(self, request, *args, **kwargs):
id__in=data["user_ids"],
).values_list("data_source_user_id", flat=True)

# 【审计】创建审计对象
auditor = TenantUserDepartmentRelationsAuditor(
request.user.username,
cur_tenant_id,
data_source_user_ids,
OperationEnum.DELETE_USER_DEPARTMENT,
)
auditor.pre_record_data_before()

DataSourceDepartmentUserRelation.objects.filter(
user_id__in=data_source_user_ids, department=source_data_source_dept
).delete()

# 【审计】将审计记录保存至数据库
auditor.record(extras={"department_id": source_data_source_dept.id})

return Response(status=status.HTTP_204_NO_CONTENT)
Loading

0 comments on commit 0c5a689

Please sign in to comment.