Repository: TencentBlueKing/bk-user

Issue:
[logging] ldap login增加日志/debug日志
https://github.com/TencentBlueKing/bk-user/blob/development/src/api/bkuser_core/categories/plugins/ldap/login.py

问题: 目前出现登录不进去的场景, 没有足够的信息用于排查问题

-----

另外, 这个跟用户的配置关系很大


Discussion:
此时, 需要打印登录的用户名? 以及, `猜测`是否带了域? 相当于, 显式告诉用户问题在哪里

TODO: use `info`, not `debug`
做不到, 因为domain目前没有在login展示 => 应该在login展示domain来解决这个问题? 

Resolving patch:
diff --git a/src/api/bkuser_core/common/error_codes.py b/src/api/bkuser_core/common/error_codes.py
--- a/src/api/bkuser_core/common/error_codes.py
+++ b/src/api/bkuser_core/common/error_codes.py
@@ -115,6 +115,8 @@ def __getattr__(self, code_name):
         ErrorCode("CATEGORY_NOT_ENABLED", _("用户目录未启用"), 3210019),
         ErrorCode("ERROR_FORMAT", _("传入参数错误"), 3210020),
         ErrorCode("SHOULD_CHANGE_INITIAL_PASSWORD", _("平台分配的初始密码未修改"), 3210021),
+        ErrorCode("USER_IS_DELETED", _("账号已被删除，请联系管理员"), 3210022),
+        ErrorCode("CATEGORY_PLUGIN_LOAD_FAIL", _("目录登录插件加载失败"), 3210023),
         # 用户相关
         ErrorCode("PASSWORD_DUPLICATED", _("新密码不能与最近{max_password_history}次密码相同")),
         ErrorCode("EMAIL_NOT_PROVIDED", _("该用户没有提供邮箱，发送邮件失败")),
diff --git a/src/api/bkuser_core/profiles/v2/views.py b/src/api/bkuser_core/profiles/v2/views.py
--- a/src/api/bkuser_core/profiles/v2/views.py
+++ b/src/api/bkuser_core/profiles/v2/views.py
@@ -557,6 +557,7 @@ def login(self, request):
         password = serializer.validated_data.get("password")
         domain = serializer.validated_data.get("domain", None)
 
+        logger.debug("do login check, username<%s>, domain=<%s>", username, domain)
         # 无指定 domain 时, 选择默认域
         if not domain:
             category = ProfileCategory.objects.get_default()
@@ -569,6 +570,14 @@ def login(self, request):
             if category.inactive:
                 raise error_codes.CATEGORY_NOT_ENABLED
 
+        logger.debug(
+            "do login check, will check in category<%s-%s-%s>", category.type, category.display_name, category.id
+        )
+
+        message_detail = (
+            f"username={username}, domain={domain} in category<{category.type}-{category.display_name}-{category.id}>"
+        )
+
         # 这里不检查具体的用户名格式，只判断是否能够获取到对应用户
         try:
             profile = Profile.objects.get(
@@ -576,9 +585,14 @@ def login(self, request):
                 domain=category.domain,
             )
         except Profile.DoesNotExist:
+            logger.info("login check, can't find the %s", message_detail)
+            # NOTE: 这里不能使用 USER_DOES_NOT_EXIST, 安全问题
             raise error_codes.PASSWORD_ERROR
         except MultipleObjectsReturned:
+            logger.info("login check, find multiple profiles via %s", message_detail)
+            # NOTE: 安全原因, 不能返回账户状态
             raise error_codes.PASSWORD_ERROR
+            # raise error_codes.USER_EXIST_MANY
 
         time_aware_now = now()
         config_loader = ConfigProvider(category_id=category.id)
@@ -596,7 +610,13 @@ def login(self, request):
                     request=request,
                     params={"is_success": False, "reason": LogInFailReason.DISABLED_USER.value},
                 )
+                logger.info("login check, profile<%s> of %s is disabled or deleted", profile.username, message_detail)
                 raise error_codes.PASSWORD_ERROR
+                # NOTE: 安全原因, 不能返回账户状态
+                # if profile.status == ProfileStatus.DISABLED.value:
+                #     raise error_codes.USER_IS_DISABLED
+                # else:
+                #     raise error_codes.USER_IS_DELETED
             elif profile.status == ProfileStatus.LOCKED.value:
                 create_profile_log(
                     profile=profile,
@@ -604,7 +624,10 @@ def login(self, request):
                     request=request,
                     params={"is_success": False, "reason": LogInFailReason.LOCKED_USER.value},
                 )
+                logger.info("login check, profile<%s> of %s is locked", profile.username, message_detail)
                 raise error_codes.PASSWORD_ERROR
+                # NOTE: 安全原因, 不能返回账户状态
+                # raise error_codes.USER_IS_LOCKED
 
             # 获取密码配置
             auto_unlock_seconds = int(config_loader["auto_unlock_seconds"])
@@ -625,18 +648,25 @@ def login(self, request):
 
                     logger.info(f"用户<{profile}> 登录失败错误过多，已被锁定，请 {retry_after_wait}s 后再试")
                     # 当密码输入错误时，不暴露不同的信息，避免用户名爆破
+                    logger.info(
+                        "login check, profile<%s> of %s entered wrong password too many times",
+                        profile.username,
+                        message_detail,
+                    )
+                    # NOTE: 安全原因, 不能返回账户状态
                     raise error_codes.PASSWORD_ERROR
 
         try:
             login_class = get_plugin_by_category(category).login_handler_cls
         except Exception:
             logger.exception(
-                "category<%s-%s-%s> load login handler failed",
+                "login check, category<%s-%s-%s> load login handler failed",
                 category.type,
                 category.display_name,
                 category.id,
             )
-            raise error_codes.PASSWORD_ERROR
+            # NOTE: 代码异常, 可以返回加载失败
+            raise error_codes.CATEGORY_PLUGIN_LOAD_FAIL
 
         try:
             login_class().check(profile, password)
@@ -647,7 +677,8 @@ def login(self, request):
                 request=request,
                 params={"is_success": False, "reason": LogInFailReason.BAD_PASSWORD.value},
             )
-            logger.exception("check profile<%s> failed", profile.username)
+            logger.exception("login check, check profile<%s> of %s failed", profile.username, message_detail)
+            # NOTE: 这里不能使用其他错误, 一律是 PASSWORD_ERROR, 安全问题
             raise error_codes.PASSWORD_ERROR
 
         self._check_password_status(request, profile, config_loader, time_aware_now)
diff --git a/src/login/bklogin/backends/bk.py b/src/login/bklogin/backends/bk.py
--- a/src/login/bklogin/backends/bk.py
+++ b/src/login/bklogin/backends/bk.py
@@ -73,6 +73,8 @@ def authenticate(self, request, username=None, password=None, **kwargs):
         else:
             domain = ""
 
+        logger.debug("parse the domain from username, result: username=%s, domain=%s", username, domain)
+
         # 调用用户管理接口进行验证
         ok, code, message, extra_values = usermgr_api.authenticate(
             username, password, language=kwargs.get("language"), domain=domain


Test patch: