Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v2.3.6 #620

Merged
merged 29 commits into from
Sep 3, 2022
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
9dfeca3
feature: 本地目录导入用户,新增根据密码初始化设置,是否发送密码邮件
neronkl Jul 28, 2022
8824f3a
ci(pre-commit): update ip check
nannan00 Aug 3, 2022
c4cd875
feat(deploy): support listen to ipv6
nannan00 Aug 3, 2022
acd8242
ci(pre-commit): update check name
nannan00 Aug 3, 2022
ea7d21f
feat(chart): update version
nannan00 Aug 3, 2022
4f28c8a
Merge pull request #602 from nannan00/ft_ipv6
nannan00 Aug 4, 2022
80f9480
feat(helm chart): update app version 1.0.1 (#604)
nannan00 Aug 8, 2022
386e1ee
Merge pull request #597 from neronkl/import_and_send_2
nannan00 Aug 8, 2022
891cb75
chore(django): from 3.2.13 to 3.2.15 (#612)
wklken Aug 12, 2022
06c6165
Ft account expiration (#537)
wklken Aug 18, 2022
208ce27
Merge branch 'master' into develop
wklken Aug 18, 2022
95a1a22
style(lints): fix lints (#621)
wklken Aug 18, 2022
e549ccb
fix(iam): api viewset iam settings (#614) (#615)
wklken Aug 18, 2022
9dcf4fa
test(unittest): fix unittest fail after add permission check
wklken Aug 18, 2022
0764373
Merge pull request #622 from wklken/fix_2.3.6_pr
wklken Aug 18, 2022
0292d7c
chore(version): to v2.3.6-alpha.2
wklken Aug 19, 2022
f909581
Merge pull request #624 from wklken/fix_2.3.6_pr
wklken Aug 19, 2022
de3ef4b
fix(api/profiles): /api/v2/profiles fetch last_login_time cause huge …
wklken Aug 23, 2022
97242ec
fix: 升级vue版本 (#634)
yuri0528 Aug 24, 2022
d2d2603
fix: 枚举字段展示问题
Aug 24, 2022
f4e7a02
feat(otel): update settings (#636)
wklken Aug 25, 2022
0366476
fix(lints): fix flake8 (#639)
wklken Aug 25, 2022
bebe531
fix(version_log): bugfix, load fail (#642)
wklken Aug 25, 2022
408e200
fix: 重置按钮失效
Aug 26, 2022
42d9550
chore(version): to v2.3.6-beta.3 (#647)
wklken Aug 29, 2022
bdbbac1
bugfix(saas/organization): search check got None (#651)
wklken Aug 31, 2022
9ddebe1
feat(apigateway): generate sdk (#653)
wklken Sep 1, 2022
b278f0d
fix(dynamic_fields/permission): disable the `list` permission check (…
wklken Sep 1, 2022
eeabd05
bugfix(profiles): iam filter error with department._bk_iam_path_ (#656)
wklken Sep 2, 2022
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
6 changes: 3 additions & 3 deletions deploy/helm/bk-user/Chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,13 @@ dependencies:
condition: redis.enabled

- name: api
version: "1.0.0"
version: "1.0.1"
condition: api.enabled

- name: login
version: "1.0.0"
version: "1.0.1"
condition: login.enabled

- name: saas
version: "1.0.0"
version: "1.0.1"
condition: saas.enabled
2 changes: 2 additions & 0 deletions src/api/bkuser_core/audit/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ class LogInFailReason(AutoLowerEnum):
TOO_MANY_FAILURE = auto()
LOCKED_USER = auto()
DISABLED_USER = auto()
EXPIRED_USER = auto()
SHOULD_CHANGE_INITIAL_PASSWORD = auto()

_choices_labels = (
Expand All @@ -29,6 +30,7 @@ class LogInFailReason(AutoLowerEnum):
(TOO_MANY_FAILURE, "密码错误次数过多"),
(LOCKED_USER, "用户已锁定"),
(DISABLED_USER, "用户已删除"),
(EXPIRED_USER, "用户账号已过期"),
(SHOULD_CHANGE_INITIAL_PASSWORD, "需要修改初始密码"),
)

Expand Down
23 changes: 23 additions & 0 deletions src/api/bkuser_core/audit/migrations/0005_auto_20220526_1048.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Generated by Django 3.2.5 on 2022-05-26 02:48

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('audit', '0004_auto_20211021_1852'),
]

operations = [
migrations.AlterField(
model_name='generallog',
name='status',
field=models.CharField(choices=[('succeed', '成功'), ('failed', '失败')], max_length=16, verbose_name='状态'),
),
migrations.AlterField(
model_name='login',
name='reason',
field=models.CharField(blank=True, choices=[('bad_password', '密码错误'), ('expired_password', '密码过期'), ('too_many_failure', '密码错误次数过多'), ('locked_user', '用户已锁定'), ('disabled_user', '用户已删除'), ('expired_user', '用户账号已过期'), ('should_change_initial_password', '需要修改初始密码')], max_length=32, null=True, verbose_name='登陆失败原因'),
),
]
2 changes: 2 additions & 0 deletions src/api/bkuser_core/bkiam/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,8 @@ def get_id_name_pair(cls, resource_type: "ResourceType") -> tuple:
cls.CATEGORY: ("id", "display_name"),
cls.FIELD: ("id", "display_name"),
cls.PROFILE: ("id", "username"),
# FIXME: not sure
cls.SYNCTASK: ("id", "id"),
}
return _map[resource_type]

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
specific language governing permissions and limitations under the License.
"""
import logging
import traceback

from django.core.management.base import BaseCommand

Expand Down Expand Up @@ -44,4 +45,5 @@ def handle(self, *args, **options):
try:
make_periodic_sync_task(int(category_id), operator, interval)
except Exception: # pylint: disable=broad-except
self.stdout.write(traceback.format_exc())
self.stdout.write(f"Failed to add sync task for category {category_id}")
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
specific language governing permissions and limitations under the License.
"""
import logging
import traceback
import uuid

from django.core.management.base import BaseCommand
Expand Down Expand Up @@ -42,10 +43,12 @@ def handle(self, *args, **options):
raw_data_file=excel_file,
)
except Exception: # pylint: disable=broad-except
self.stdout.write(traceback.format_exc())
logger.exception("can not find category by type<%s>", category_type)
return

try:
adapter_sync(ProfileCategory.objects.filter(type=category_type)[0].pk, task_id=task_id)
except Exception: # pylint: disable=broad-except
self.stdout.write(traceback.format_exc())
logger.exception("can not find category by type<%s>", category_type)
2 changes: 1 addition & 1 deletion src/api/bkuser_core/categories/plugins/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ def try_to_add_profile_department_relation(self, profile: Profile, department: D
profile=profile, department_id__in=exempt_department_ids
).exists()
):
logger.debug(
logger.info(
"profile<%s> is in the exempted department<%s>, skip",
profile,
department,
Expand Down
21 changes: 15 additions & 6 deletions src/api/bkuser_core/categories/plugins/custom/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def _get_code(self, raw_key: Union[str, int]) -> str:
# 添加 category_id ,code 可以在多目录中唯一
code = f"{self.category.pk}-{str(raw_key)}"
sha = hashlib.sha256(force_bytes(code)).hexdigest()
logger.debug("transform code to sha: %s -> %s", code, sha)
logger.info("transform code to sha: %s -> %s", code, sha)
return sha


Expand Down Expand Up @@ -156,7 +156,7 @@ def _load_base_info(self):
validate_username(value=info.username)
except ValidationError as e:
self.context.add_record(step=SyncStep.USERS, success=False, username=info.username, error=str(e))
logger.warning("username<%s:%s> does not meet format", info.code, info.username)
logger.warning("username<%s:%s> does not meet format, will skip", info.code, info.username)
continue

# 1. 先更新 profile 本身
Expand All @@ -165,6 +165,7 @@ def _load_base_info(self):
if info.extras:
# note: the priority of extras from origin api is higher than `code=info.code`
extras.update(info.extras)

profile_params = {
"category_id": self.category.pk,
"domain": self.category.domain,
Expand Down Expand Up @@ -209,7 +210,9 @@ def _load_base_info(self):
department=dep_id,
error=_("部门不存在"),
)
logger.warning("the department<%s> of profile<%s:%s> is missing", dep_id, info.code, info.username)
logger.warning(
"the department<%s> of profile<%s:%s> is missing, will skip", dep_id, info.code, info.username
)
continue

self.try_add_relation(
Expand All @@ -231,15 +234,19 @@ def _load_leader_info(self):
self.context.add_record(
step=SyncStep.USERS_RELATIONSHIP, success=False, username=info.username, error=_("用户信息不存在")
)
logger.warning("profile<%s:%s> not exists, will not be synced, skip", info.code, info.username)
logger.warning(
"profile<%s:%s> not exists, the profile leaders will not be synced, will skip",
info.code,
info.username,
)
continue

for leader_id in info.leaders:
if leader_id == profile.code:
self.context.add_record(
step=SyncStep.USERS_RELATIONSHIP, success=False, username=info.username, error=_("无法设置自己为上级")
)
logger.warning("profile<%s:%s> can not regard self as leader, skip", info.code, info.username)
logger.warning("profile<%s:%s> can not regard self as leader, will skip", info.code, info.username)
continue

leader = self.db_sync_manager.magic_get(self._get_code(leader_id), CustomProfileMeta)
Expand All @@ -250,7 +257,9 @@ def _load_leader_info(self):
username=info.username,
error=_("上级【{username}】不存在").format(username=leader_id),
)
logger.warning("the leader<%s> of profile<%s:%s> is missing", leader_id, info.code, info.username)
logger.warning(
"the leader<%s> of profile<%s:%s> is missing, will skip", leader_id, info.code, info.username
)
continue

self.try_add_relation(
Expand Down
2 changes: 2 additions & 0 deletions src/api/bkuser_core/categories/plugins/ldap/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,5 @@
category_type="ldap",
settings_path=os.path.dirname(__file__) / Path("settings.yaml"),
).register()

# NOTE: 策略-每一次排查, 都简化复杂度, 加相关的日志等, 为未来的排查降低成本
6 changes: 3 additions & 3 deletions src/api/bkuser_core/categories/plugins/ldap/adaptor.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,19 +49,19 @@ def get_value(
if dynamic_field:
ldap_field_name = field_name
if ldap_field_name not in self.dynamic_fields_mapping.values():
logger.info("no config[%s] in configs of dynamic_fields_mapping", field_name)
logger.warning("no config[%s] in configs of dynamic_fields_mapping", field_name)
return ""

else:
# 从目录配置中获取 字段名
ldap_field_name = self.config_loader.get(field_name)
if not ldap_field_name:
logger.info("no config[%s] in configs of category", field_name)
logger.warning("no config[%s] in configs of category", field_name)
return ""

# 1. 通过字段名,获取具体值
if ldap_field_name not in user_meta or not user_meta[ldap_field_name]:
logger.info("field[%s] is missing in raw attributes of user data from ldap", field_name)
logger.warning("field[%s] is missing in raw attributes of user data from ldap", field_name)
return ""

# 2. 类似 memberOf 字段,将会返回原始列表
Expand Down
1 change: 1 addition & 0 deletions src/api/bkuser_core/categories/plugins/ldap/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ def search(
)

if not result and not self.con.result["result"] == 0 and not self.con.last_error:
logger.error("failed to search %s from %s, last_error: %s", search_filter, start_root, self.con.last_error)
raise local_exceptions.SearchFailed

return self.con.response
Expand Down
9 changes: 8 additions & 1 deletion src/api/bkuser_core/categories/plugins/ldap/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ def update_or_create_sync_tasks(instance: "Setting", operator: str):
@receiver(post_category_delete)
def delete_sync_tasks(sender, instance: "ProfileCategory", **kwargs):
if instance.type not in [CategoryType.LDAP.value, CategoryType.MAD.value]:
logger.warning(
"category<%s> is %s, not a ldap or mad category, skip delete sync tasks", instance.id, instance.type
)
return

logger.info("going to delete periodic task for Category<%s>, the category type is %s", instance.id, instance.type)
Expand All @@ -81,14 +84,18 @@ def delete_sync_tasks(sender, instance: "ProfileCategory", **kwargs):
@receiver(post_setting_create)
def update_sync_tasks(sender, instance: "Setting", operator: str, **kwargs):
if instance.category.type not in [CategoryType.LDAP.value, CategoryType.MAD.value]:
logger.warning(
"category<%s> is %s, not a ldap or mad category, skip update sync tasks", instance.id, instance.type
)
return

# 针对 pull_cycle 配置更新同步任务
logger.info("going to update periodic task for Category<%s>, the category type is %s", instance.id, instance.type)
update_or_create_sync_tasks(instance, operator)


@receiver(post_dynamic_field_delete)
def update_dynamic_field_mapping(sender, instance: "DynamicFieldInfo", **kwargs):
"""尝试刷新自定义字段映射配置"""
delete_dynamic_filed(dynamic_field=instance.name)
logger.info("going to delete <%s> from dynamic_field_mapping", instance.name)
delete_dynamic_filed(dynamic_field=instance.name)
4 changes: 2 additions & 2 deletions src/api/bkuser_core/categories/plugins/ldap/helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ def _load_base_info(self):
username=info.username,
error=str(e),
)
logger.warning("username<%s> does not meet format", info.username)
logger.warning("username<%s> does not meet format, will skip", info.username)
continue

# 1. 先更新 profile 本身
Expand Down Expand Up @@ -201,7 +201,7 @@ def _load_base_info(self):
error=_("部门不存在"),
)
logger.warning(
"the department<%s> of profile<%s> is missing",
"the department<%s> of profile<%s> is missing, will skip",
department_key,
info.username,
)
Expand Down
14 changes: 14 additions & 0 deletions src/api/bkuser_core/categories/plugins/ldap/login.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,17 @@
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.
"""
import logging

from django.utils.encoding import force_str

from bkuser_core.categories.plugins.ldap.adaptor import ProfileFieldMapper
from bkuser_core.categories.plugins.ldap.client import LDAPClient
from bkuser_core.categories.plugins.ldap.exceptions import FetchUserMetaInfoFailed
from bkuser_core.user_settings.loader import ConfigProvider

logger = logging.getLogger(__name__)


class LoginHandler:
@staticmethod
Expand All @@ -31,13 +35,22 @@ def check(self, profile, password):
client = LDAPClient(config_loader)
field_fetcher = ProfileFieldMapper(config_loader)

logger.debug(
"going to search users, object_class: %s, attributes: %s",
config_loader["user_class"],
field_fetcher.get_user_attributes(),
)
users = client.search(
object_class=config_loader["user_class"],
attributes=field_fetcher.get_user_attributes(),
)
logger.debug("search results users: %s", users)

# NOTE: 1. 如果用户反馈登录一直不成功, 怎么排查? 2.target_dn可能被后面命中的覆盖?
target_dn = None
for user in users:
if not user.get("raw_attributes"):
logger.debug("user %s has no raw_attributes, skip", user)
continue

if self.fetch_username(field_fetcher, user) == profile.username:
Expand All @@ -47,4 +60,5 @@ def check(self, profile, password):
raise FetchUserMetaInfoFailed("获取用户基本信息失败")

# 检验
logger.debug("going to check user, dn: %s", target_dn)
client.check(username=target_dn, password=password)
23 changes: 18 additions & 5 deletions src/api/bkuser_core/categories/plugins/ldap/syncer.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,14 +79,22 @@ def _fetch_data(
else:
groups = []
except Exception as e:
logger.exception("failed to get groups from remote server")
logger.exception(
"failed to get groups from remote server. basic_pull_node: %s, user_group_filter: %s",
basic_pull_node,
user_group_filter,
)
error_detail = f" ({type(e).__module__}.{type(e).__name__}: {str(e)})"
raise FetchDataFromRemoteFailed(_("无法获取用户组,请检查配置") + error_detail)

try:
departments = self.client.search(start_root=basic_pull_node, object_class=organization_class)
except Exception as e:
logger.exception("failed to get departments from remote server")
logger.exception(
"failed to get departments from remote server. basic_pull_node: %s, organization_class: %s",
basic_pull_node,
organization_class,
)
error_detail = f" ({type(e).__module__}.{type(e).__name__}: {str(e)})"
raise FetchDataFromRemoteFailed(_("无法获取组织部门,请检查配置") + error_detail)

Expand All @@ -97,7 +105,12 @@ def _fetch_data(
attributes=attributes or [],
)
except Exception as e:
logger.exception("failed to get users from remote server")
logger.exception(
"failed to get users from remote server. basic_pull_node: %s, user_filter: %s, attributes: %s",
basic_pull_node,
user_filter,
attributes,
)
error_detail = f" ({type(e).__module__}.{type(e).__name__}: {str(e)})"
raise FetchDataFromRemoteFailed(_("无法获取用户数据, 请检查配置") + error_detail)

Expand All @@ -122,7 +135,7 @@ def fetch_profiles(self, restrict_types: List[str]):
profiles = []
for user in users:
if not user.get("dn"):
logger.info("no dn field, skipping for %s", user)
logger.warning("no dn field, skipping for profile: %s", user)
continue

profiles.append(
Expand All @@ -141,7 +154,7 @@ def fetch_departments(self, restrict_types: List[str]):
results = []
for is_group, dept_meta in chain.from_iterable(iter([product([False], departments), product([True], groups)])):
if not dept_meta.get("dn"):
logger.info("no dn field, skipping for %s", dept_meta)
logger.warning("no dn field, skipping for %s:%s", ("group" if is_group else "department"), dept_meta)
continue
results.append(
department_adapter(
Expand Down
1 change: 1 addition & 0 deletions src/api/bkuser_core/categories/plugins/local/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
@receiver(post_category_create)
def make_local_default_settings(sender, instance: "ProfileCategory", **kwargs):
if instance.type not in [CategoryType.LOCAL.value]:
logger.info("category<%s> is not local, skip make_local_default_settings", instance.id)
return

logger.info("going to make default settings for Category<%s>", instance.id)
Expand Down
Loading