Skip to content

Commit

Permalink
fix: 审计支持失败记录 TencentBlueKing#71
Browse files Browse the repository at this point in the history
  • Loading branch information
Canway-shiisa committed Sep 29, 2021
1 parent 0086c2a commit 6ea9188
Show file tree
Hide file tree
Showing 11 changed files with 250 additions and 110 deletions.
13 changes: 10 additions & 3 deletions src/api/bkuser_core/audit/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@

RESET_PASSWORD_VAILD_MINUTES = 3 * 60


TOKEN_IS_OK = 0
TOKEN_USED_CODE = 10000
TOKEN_EXPIRED_CODE = 10001
Expand All @@ -23,7 +22,6 @@


class LogInFailReasonEnum(AutoLowerEnum):

BAD_PASSWORD = auto()
EXPIRED_PASSWORD = auto()
TOO_MANY_FAILURE = auto()
Expand All @@ -40,7 +38,6 @@ class LogInFailReasonEnum(AutoLowerEnum):


class OperationEnum(AutoLowerEnum):

CREATE = auto()
UPDATE = auto()
DELETE = auto()
Expand All @@ -61,3 +58,13 @@ class OperationEnum(AutoLowerEnum):
(IMPORT, "导入"),
(RESTORATION, "恢复"),
)


class OperationStatusEnum(AutoLowerEnum):
SUCCESS = auto()
FAILED = auto()

_choices_labels = (
(SUCCESS, "成功"),
(FAILED, "失败"),
)
3 changes: 2 additions & 1 deletion src/api/bkuser_core/audit/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,15 @@

@receiver(post_profile_create)
@receiver(post_profile_update)
def create_audit_log(sender, profile, operator, operation_type, extra_values, **kwargs):
def create_audit_log(sender, profile, operator, operation_type, status, extra_values, **kwargs):
"""Create an audit log"""
request = extra_values["request"]
create_general_log(
operator=operator,
operate_type=operation_type,
operator_obj=profile,
request=request,
status=status,
)

# 当密码信息存在时,我们需要增加一条记录,
Expand Down
3 changes: 2 additions & 1 deletion src/api/bkuser_core/audit/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
from django.db import models
from jsonfield import JSONField

from .constants import LogInFailReasonEnum
from .constants import LogInFailReasonEnum, OperationStatusEnum
from .managers import LogInManager, ResetPasswordManager


Expand Down Expand Up @@ -59,6 +59,7 @@ class Meta:

class GeneralLog(Log):
"""通用操作日志"""
status = models.CharField("状态", max_length=16, choices=OperationStatusEnum.get_choices())


class ApiRequest(Log):
Expand Down
1 change: 1 addition & 0 deletions src/api/bkuser_core/audit/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ class GeneralLogSerializer(CustomFieldsMixin, serializers.Serializer):
extra_value = serializers.JSONField(help_text=_("额外信息"))
operator = serializers.CharField(help_text=_("操作者"))
create_time = serializers.DateTimeField(help_text=_("创建时间"))
status = serializers.CharField(help_text=_("状态"))


class LoginLogSerializer(CustomFieldsMixin, serializers.Serializer):
Expand Down
9 changes: 7 additions & 2 deletions src/api/bkuser_core/audit/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
from django.conf import settings

from . import models
from .constants import OperationEnum
from .constants import OperationEnum, OperationStatusEnum
from .models import GeneralLog, ProfileRelatedLog

if TYPE_CHECKING:
Expand Down Expand Up @@ -45,6 +45,7 @@ def get_client_ip(request: "Request") -> str:
def create_general_log(
operator: str,
operate_type: str,
status: str,
operator_obj: Any,
extra_info: Dict = None,
request=None,
Expand All @@ -60,6 +61,10 @@ def create_general_log(
logger.exception("operate type<%s> unknown", operate_type)
return None

if not OperationStatusEnum.has_value(status):
logger.exception("status <s%> unknown", status)
return None

extra_value = {
"operation": operate_type,
"obj_type": operator_obj.__class__.__name__,
Expand All @@ -77,7 +82,7 @@ def create_general_log(
operator_obj,
operator_obj.__class__.__name__,
)
return GeneralLog.objects.create(operator=operator, extra_value=extra_value)
return GeneralLog.objects.create(operator=operator, extra_value=extra_value, status=status)


def create_profile_log(
Expand Down
105 changes: 102 additions & 3 deletions src/api/bkuser_core/categories/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
import logging
from typing import List

from bkuser_core.audit.constants import OperationEnum
from bkuser_core.audit.constants import OperationEnum, OperationStatusEnum
from bkuser_core.audit.utils import create_general_log
from bkuser_core.bkiam.permissions import IAMAction, IAMHelper, IAMPermissionExtraInfo, need_iam
from bkuser_core.categories.constants import CategoryType, SyncTaskType
Expand Down Expand Up @@ -125,10 +125,9 @@ def create(self, request, *args, **kwargs):
operate_type=OperationEnum.CREATE.value,
operator_obj=instance,
request=request,
status=OperationStatusEnum.SUCCESS.value,
)

return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)

def get_serializer(self, *args, **kwargs):
if self.action in ["create"]:
return CreateCategorySerializer(*args, **kwargs)
Expand All @@ -149,9 +148,25 @@ def update(self, request, *args, **kwargs):

updating_domain = serializer.validated_data.get("domain")
if updating_domain and not updating_domain == instance.domain:
create_general_log(
operator=request.operator,
operate_type=OperationEnum.UPDATE.value,
operator_obj=instance,
request=request,
status=OperationStatusEnum.FAILED.value,
extra_info={"failed_info": f"{error_codes.CANNOT_UPDATE_DOMAIN.message}"},
)
raise error_codes.CANNOT_UPDATE_DOMAIN

if instance.default and any(serializer.validated_data.get(x) is False for x in ["enabled", "status"]):
create_general_log(
operator=request.operator,
operate_type=OperationEnum.UPDATE.value,
operator_obj=instance,
request=request,
status=OperationStatusEnum.FAILED.value,
extra_info={"failed_info": f"{error_codes.CANNOT_DISABLE_DOMAIN.message}"},
)
raise error_codes.CANNOT_DISABLE_DOMAIN

self.perform_update(serializer)
Expand All @@ -166,6 +181,7 @@ def update(self, request, *args, **kwargs):
operate_type=OperationEnum.UPDATE.value,
operator_obj=instance,
request=request,
status=OperationStatusEnum.SUCCESS.value,
)

return Response(serializer.data)
Expand All @@ -176,9 +192,24 @@ def destroy(self, request, *args, **kwargs):
"""
instance = self.get_object()
if instance.default:
create_general_log(
operator=request.operator,
operate_type=OperationEnum.DELETE.value,
operator_obj=instance,
request=request,
status=OperationStatusEnum.FAILED.value,
extra_info={"failed_info": f"{error_codes.CANNOT_DELETE_DEFAULT_CATEGORY.message}"},
)
raise error_codes.CANNOT_DELETE_DEFAULT_CATEGORY

post_category_delete.send(sender=self, category=instance, operator=request.operator)
create_general_log(
operator=request.operator,
operate_type=OperationEnum.DELETE.value,
operator_obj=instance,
request=request,
status=OperationStatusEnum.SUCCESS.value,
)
return super().destroy(request, *args, **kwargs)

@swagger_auto_schema(
Expand Down Expand Up @@ -265,13 +296,30 @@ def sync(self, request, lookup_value):
self.check_object_permissions(request, instance)

if instance.type == CategoryType.LOCAL.value:
create_general_log(
operator=request.operator,
operate_type=OperationEnum.SYNC.value,
operator_obj=instance,
request=request,
status=OperationStatusEnum.FAILED.value,
extra_info={"failed_info": f"{error_codes.LOCAL_CATEGORY_CANNOT_SYNC.message}"}
)
raise error_codes.LOCAL_CATEGORY_CANNOT_SYNC

try:
task_id = SyncTask.objects.register_task(
category=instance, operator=request.operator, type_=SyncTaskType.MANUAL
).id
except ExistsSyncingTaskError as e:
create_general_log(
operator=request.operator,
operate_type=OperationEnum.SYNC.value,
operator_obj=instance,
request=request,
status=OperationStatusEnum.FAILED.value,
extra_info={"failed_info": f"{e}"}
)

raise error_codes.LOAD_DATA_FAILED.f(str(e))

try:
Expand All @@ -280,18 +328,36 @@ def sync(self, request, lookup_value):
)
except FetchDataFromRemoteFailed as e:
logger.exception("failed to sync data")
create_general_log(
operator=request.operator,
operate_type=OperationEnum.SYNC.value,
operator_obj=instance,
request=request,
status=OperationStatusEnum.FAILED.value,
extra_info={"failed_info": f"{e}"}
)

raise error_codes.SYNC_DATA_FAILED.f(f"{e}")
except CoreAPIError:
raise
except Exception:
logger.exception("failed to sync data")
create_general_log(
operator=request.operator,
operate_type=OperationEnum.SYNC.value,
operator_obj=instance,
request=request,
status=OperationStatusEnum.FAILED.value,
extra_info={"failed_info": f"{error_codes.SYNC_DATA_FAILED.message}"}
)
raise error_codes.SYNC_DATA_FAILED

create_general_log(
operator=request.operator,
operate_type=OperationEnum.SYNC.value,
operator_obj=instance,
request=request,
status=OperationStatusEnum.SUCCESS.value,
)
return Response({"task_id": task_id})

Expand All @@ -313,13 +379,29 @@ def import_data_file(self, request, lookup_value):
self.check_object_permissions(request, instance)

if instance.type != CategoryType.LOCAL.value:
create_general_log(
operator=request.operator,
operate_type=OperationEnum.IMPORT.value,
operator_obj=instance,
request=request,
status=OperationStatusEnum.FAILED.value,
extra_info={"failed_info": f"{error_codes.CATEGORY_CANNOT_IMPORT_BY_FILE.message}"}
)
raise error_codes.CATEGORY_CANNOT_IMPORT_BY_FILE

try:
task_id = SyncTask.objects.register_task(
category=instance, operator=request.operator, type_=SyncTaskType.MANUAL
).id
except ExistsSyncingTaskError as e:
create_general_log(
operator=request.operator,
operate_type=OperationEnum.IMPORT.value,
operator_obj=instance,
request=request,
status=OperationStatusEnum.FAILED.value,
extra_info={"failed_info": f"{e}"}
)
raise error_codes.LOAD_DATA_FAILED.f(str(e))

params = {"raw_data_file": serializer.validated_data["raw_data_file"]}
Expand All @@ -328,16 +410,33 @@ def import_data_file(self, request, lookup_value):
adapter_sync(lookup_value, operator=request.operator, task_id=task_id, **params)
except DataFormatError as e:
logger.exception("failed to sync data")
create_general_log(
operator=request.operator,
operate_type=OperationEnum.IMPORT.value,
operator_obj=instance,
request=request,
status=OperationStatusEnum.FAILED.value,
extra_info={"failed_info": f"{e}"}
)
raise error_codes.SYNC_DATA_FAILED.format(str(e), replace=True)
except Exception as e:
logger.exception("failed to sync data")
create_general_log(
operator=request.operator,
operate_type=OperationEnum.IMPORT.value,
operator_obj=instance,
request=request,
status=OperationStatusEnum.FAILED.value,
extra_info={"failed_info": f"{e}"}
)
raise error_codes.SYNC_DATA_FAILED.format(str(e), replace=True)

create_general_log(
operator=request.operator,
operate_type=OperationEnum.IMPORT.value,
operator_obj=instance,
request=request,
status=OperationStatusEnum.SUCCESS.value,
)
return Response()

Expand Down
Loading

0 comments on commit 6ea9188

Please sign in to comment.