diff --git a/src/bk-user/bkuser/apps/data_source/handlers.py b/src/bk-user/bkuser/apps/data_source/handlers.py index 2e7a89818..74eae308e 100644 --- a/src/bk-user/bkuser/apps/data_source/handlers.py +++ b/src/bk-user/bkuser/apps/data_source/handlers.py @@ -20,4 +20,4 @@ def initial_local_data_source_user_identity_info(sender, data_source: DataSource TODO (su) 数据源更新后,需要检查是否是本地数据源,若是本地数据源且启用账密登录, 则需要对没有账密信息的用户,进行密码的初始化 & 发送通知 """ - pass + ... diff --git a/src/bk-user/bkuser/apps/identity_provider/__init__.py b/src/bk-user/bkuser/apps/idp/__init__.py similarity index 100% rename from src/bk-user/bkuser/apps/identity_provider/__init__.py rename to src/bk-user/bkuser/apps/idp/__init__.py diff --git a/src/bk-user/bkuser/apps/idp/apps.py b/src/bk-user/bkuser/apps/idp/apps.py new file mode 100644 index 000000000..dddd31aad --- /dev/null +++ b/src/bk-user/bkuser/apps/idp/apps.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- +""" +TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-用户管理(Bk-User) available. +Copyright (C) 2017-2021 THL A29 Limited, a Tencent company. All rights reserved. +Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. +You may obtain a copy of the License at http://opensource.org/licenses/MIT +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. +""" +from django.apps import AppConfig + + +class IdpConfig(AppConfig): + default_auto_field = "django.db.models.BigAutoField" + name = "bkuser.apps.idp" diff --git a/src/bk-user/bkuser/apps/idp/constants.py b/src/bk-user/bkuser/apps/idp/constants.py new file mode 100644 index 000000000..8374bcc63 --- /dev/null +++ b/src/bk-user/bkuser/apps/idp/constants.py @@ -0,0 +1,40 @@ +# -*- coding: utf-8 -*- +""" +TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-用户管理(Bk-User) available. +Copyright (C) 2017-2021 THL A29 Limited, a Tencent company. All rights reserved. +Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. +You may obtain a copy of the License at http://opensource.org/licenses/MIT +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. +""" +from blue_krill.data_types.enum import EnumField, StructuredEnum +from django.utils.translation import gettext_lazy as _ + + +class IdpCategory(str, StructuredEnum): + """认证源分类""" + + ENTERPRISE = EnumField("enterprise", label=_("企业")) + SOCIAL = EnumField("social", label=_("社交")) + + +class IdpStatus(str, StructuredEnum): + """认证源状态""" + + ENABLED = EnumField("enabled", label=_("启用")) + DISABLED = EnumField("disabled", label=_("未启用")) + + +class AllowBindScopeObjectType(str, StructuredEnum): + """社会化认证源,允许绑定的范围对象类型""" + + USER = EnumField("user", label=_("用户")) + DEPARTMENT = EnumField("department", label=_("部门")) + DATA_SOURCE = EnumField("data_source", label=_("数据源")) + TENANT = EnumField("tenant", label=_("租户")) + ANY = EnumField("*", label=_("任意")) + + +# 社会化认证源,允许绑定的范围为任意对象ID +ANY_ALLOW_BIND_SCOPE_OBJECT_ID = "*" diff --git a/src/bk-user/bkuser/apps/idp/data_models.py b/src/bk-user/bkuser/apps/idp/data_models.py new file mode 100644 index 000000000..19acc1be9 --- /dev/null +++ b/src/bk-user/bkuser/apps/idp/data_models.py @@ -0,0 +1,33 @@ +# -*- coding: utf-8 -*- +""" +TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-用户管理(Bk-User) available. +Copyright (C) 2017-2021 THL A29 Limited, a Tencent company. All rights reserved. +Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. +You may obtain a copy of the License at http://opensource.org/licenses/MIT +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. +""" +from pydantic import BaseModel + +from .constants import AllowBindScopeObjectType + + +class DataSourceMatchRule(BaseModel): + """认证源与数据源匹配规则""" + + # 认证源原始字段 + source_field: str + # 匹配的数据源 ID + data_source_id: int + # 匹配的数据源字段 + target_field: str + + +class AllowBindScope(BaseModel): + """允许关联社会化认证源的租户组织架构范围""" + + # 范围对象的类型 + type: AllowBindScopeObjectType + # 范围对象的ID + id: str diff --git a/src/bk-user/bkuser/apps/idp/migrations/0001_initial.py b/src/bk-user/bkuser/apps/idp/migrations/0001_initial.py new file mode 100644 index 000000000..bb0a16349 --- /dev/null +++ b/src/bk-user/bkuser/apps/idp/migrations/0001_initial.py @@ -0,0 +1,47 @@ +# Generated by Django 3.2.20 on 2023-09-13 08:36 + +import bkuser.apps.idp.constants +import bkuser.utils.uuid +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='IdpPlugin', + fields=[ + ('category', models.CharField(choices=[('enterprise', '企业'), ('social', '社交')], max_length=32, verbose_name='分类')), + ('id', models.CharField(max_length=128, primary_key=True, serialize=False, verbose_name='认证源插件唯一标识')), + ('name', models.CharField(max_length=128, unique=True, verbose_name='认证源插件名称')), + ('description', models.TextField(blank=True, default='', verbose_name='描述')), + ('logo', models.TextField(blank=True, default='', null=True, verbose_name='Logo')), + ], + ), + migrations.CreateModel( + name='Idp', + fields=[ + ('created_at', models.DateTimeField(auto_now_add=True)), + ('updated_at', models.DateTimeField(auto_now=True)), + ('creator', models.CharField(blank=True, max_length=128, null=True)), + ('updater', models.CharField(blank=True, max_length=128, null=True)), + ('id', models.CharField(default=bkuser.utils.uuid.generate_uuid, max_length=128, primary_key=True, serialize=False, verbose_name='认证源标识')), + ('name', models.CharField(max_length=128, unique=True, verbose_name='认证源名称')), + ('owner_tenant_id', models.CharField(db_index=True, max_length=64, verbose_name='归属租户')), + ('status', models.CharField(choices=[('enabled', '启用'), ('disabled', '未启用')], default=bkuser.apps.idp.constants.IdpStatus['ENABLED'], max_length=32, verbose_name='认证源状态')), + ('plugin_config', models.JSONField(default=dict, verbose_name='插件配置')), + ('data_source_match_rules', models.JSONField(default=list, verbose_name='匹配规则')), + ('allow_bind_scopes', models.JSONField(default=list, verbose_name='允许范围')), + ('plugin', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='idp.idpplugin')), + ], + options={ + 'abstract': False, + }, + ), + ] diff --git a/src/bk-user/bkuser/apps/idp/migrations/__init__.py b/src/bk-user/bkuser/apps/idp/migrations/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/bk-user/bkuser/apps/idp/models.py b/src/bk-user/bkuser/apps/idp/models.py new file mode 100644 index 000000000..270f87140 --- /dev/null +++ b/src/bk-user/bkuser/apps/idp/models.py @@ -0,0 +1,43 @@ +# -*- coding: utf-8 -*- +""" +TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-用户管理(Bk-User) available. +Copyright (C) 2017-2021 THL A29 Limited, a Tencent company. All rights reserved. +Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. +You may obtain a copy of the License at http://opensource.org/licenses/MIT +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. +""" +from django.db import models + +from bkuser.common.models import AuditedModel +from bkuser.utils.uuid import generate_uuid + +from .constants import IdpCategory, IdpStatus + + +class IdpPlugin(models.Model): + """认证源插件""" + + category = models.CharField("分类", max_length=32, choices=IdpCategory.get_choices()) + id = models.CharField("认证源插件唯一标识", primary_key=True, max_length=128) + name = models.CharField("认证源插件名称", max_length=128, unique=True) + description = models.TextField("描述", default="", blank=True) + logo = models.TextField("Logo", null=True, blank=True, default="") + + +class Idp(AuditedModel): + """认证源""" + + # 登录回调场景下,该 ID 是 URL Path 的一部分 + id = models.CharField("认证源标识", primary_key=True, max_length=128, default=generate_uuid) + name = models.CharField("认证源名称", max_length=128, unique=True) + owner_tenant_id = models.CharField("归属租户", max_length=64, db_index=True) + status = models.CharField("认证源状态", max_length=32, choices=IdpStatus.get_choices(), default=IdpStatus.ENABLED) + # Note: 认证源插件被删除的前提是,插件没有被任何认证源使用 + plugin = models.ForeignKey(IdpPlugin, on_delete=models.PROTECT) + plugin_config = models.JSONField("插件配置", default=dict) + # 认证源与数据源的匹配规则 + data_source_match_rules = models.JSONField("匹配规则", default=list) + # 允许关联社会化认证源的租户组织架构范围 + allow_bind_scopes = models.JSONField("允许范围", default=list) diff --git a/src/bk-user/bkuser/apps/natural_user/__init__.py b/src/bk-user/bkuser/apps/natural_user/__init__.py new file mode 100644 index 000000000..1060b7bf4 --- /dev/null +++ b/src/bk-user/bkuser/apps/natural_user/__init__.py @@ -0,0 +1,10 @@ +# -*- coding: utf-8 -*- +""" +TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-用户管理(Bk-User) available. +Copyright (C) 2017-2021 THL A29 Limited, a Tencent company. All rights reserved. +Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. +You may obtain a copy of the License at http://opensource.org/licenses/MIT +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. +""" diff --git a/src/bk-user/bkuser/apps/natural_user/apps.py b/src/bk-user/bkuser/apps/natural_user/apps.py new file mode 100644 index 000000000..ba776bacd --- /dev/null +++ b/src/bk-user/bkuser/apps/natural_user/apps.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- +""" +TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-用户管理(Bk-User) available. +Copyright (C) 2017-2021 THL A29 Limited, a Tencent company. All rights reserved. +Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. +You may obtain a copy of the License at http://opensource.org/licenses/MIT +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. +""" +from django.apps import AppConfig + + +class NaturalUserConfig(AppConfig): + default_auto_field = "django.db.models.BigAutoField" + name = "bkuser.apps.natural_user" diff --git a/src/bk-user/bkuser/apps/natural_user/migrations/0001_initial.py b/src/bk-user/bkuser/apps/natural_user/migrations/0001_initial.py new file mode 100644 index 000000000..f3e42bc89 --- /dev/null +++ b/src/bk-user/bkuser/apps/natural_user/migrations/0001_initial.py @@ -0,0 +1,43 @@ +# Generated by Django 3.2.20 on 2023-09-13 08:37 + +import bkuser.utils.uuid +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('data_source', '0003_auto_20230831_1552'), + ] + + operations = [ + migrations.CreateModel( + name='NaturalUser', + fields=[ + ('created_at', models.DateTimeField(auto_now_add=True)), + ('updated_at', models.DateTimeField(auto_now=True)), + ('id', models.CharField(default=bkuser.utils.uuid.generate_uuid, max_length=128, primary_key=True, serialize=False, verbose_name='自然人标识')), + ('full_name', models.CharField(max_length=128, verbose_name='姓名')), + ], + options={ + 'abstract': False, + }, + ), + migrations.CreateModel( + name='DataSourceUserNaturalUserRelation', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created_at', models.DateTimeField(auto_now_add=True)), + ('updated_at', models.DateTimeField(auto_now=True)), + ('data_source_user', models.ForeignKey(db_constraint=False, on_delete=django.db.models.deletion.CASCADE, to='data_source.datasourceuser')), + ('natural_user', models.ForeignKey(db_constraint=False, on_delete=django.db.models.deletion.DO_NOTHING, to='natural_user.naturaluser')), + ], + options={ + 'ordering': ['id'], + 'unique_together': {('data_source_user', 'natural_user')}, + }, + ), + ] diff --git a/src/bk-user/bkuser/apps/natural_user/migrations/__init__.py b/src/bk-user/bkuser/apps/natural_user/migrations/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/src/bk-user/bkuser/apps/natural_user/models.py b/src/bk-user/bkuser/apps/natural_user/models.py new file mode 100644 index 000000000..e58b2b129 --- /dev/null +++ b/src/bk-user/bkuser/apps/natural_user/models.py @@ -0,0 +1,31 @@ +# -*- coding: utf-8 -*- +""" +TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-用户管理(Bk-User) available. +Copyright (C) 2017-2021 THL A29 Limited, a Tencent company. All rights reserved. +Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. +You may obtain a copy of the License at http://opensource.org/licenses/MIT +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. +""" +from django.db import models + +from bkuser.apps.data_source.models import DataSourceUser +from bkuser.common.models import TimestampedModel +from bkuser.utils.uuid import generate_uuid + + +class NaturalUser(TimestampedModel): + id = models.CharField("自然人标识", primary_key=True, max_length=128, default=generate_uuid) + full_name = models.CharField("姓名", max_length=128) + + +class DataSourceUserNaturalUserRelation(TimestampedModel): + data_source_user = models.ForeignKey(DataSourceUser, on_delete=models.CASCADE, db_constraint=False) + natural_user = models.ForeignKey(NaturalUser, on_delete=models.DO_NOTHING, db_constraint=False) + + class Meta: + ordering = ["id"] + unique_together = [ + ("data_source_user", "natural_user"), + ] diff --git a/src/bk-user/bkuser/apps/tenant/models.py b/src/bk-user/bkuser/apps/tenant/models.py index 6acdbe903..b7114d481 100644 --- a/src/bk-user/bkuser/apps/tenant/models.py +++ b/src/bk-user/bkuser/apps/tenant/models.py @@ -154,3 +154,20 @@ class Meta: # notification_method = models.CharField("通知方式", max_length=32, default="email") # # TODO: 需要考虑不同通知方式,可能无法使用相同模板,或者其他设计方式 # notification_content_template = models.TextField("通知模板", default="") + + +# class TenantUserSocialAccountRelation(TimestampedModel): +# """租户用户与社交账号绑定表""" +# +# tenant_user = models.ForeignKey(TenantUser, on_delete=models.CASCADE, db_constraint=False) +# idp = models.ForeignKey(Idp, on_delete=models.DO_NOTHING, db_constraint=False) +# social_client_id = models.CharField("社交认证源对应的ClientID", max_length=128) +# social_account_id = models.CharField("绑定的社交账号ID", max_length=128) +# +# class Meta: +# unique_together = [ +# ("social_account_id", "tenant_user", "idp", "social_client_id"), +# ] +# index_together = [ +# ("social_account_id", "idp", "social_client_id"), +# ] diff --git a/src/bk-user/bkuser/settings.py b/src/bk-user/bkuser/settings.py index 52f4b4872..6a5222af3 100644 --- a/src/bk-user/bkuser/settings.py +++ b/src/bk-user/bkuser/settings.py @@ -50,6 +50,8 @@ "bkuser.apps.data_source", "bkuser.apps.tenant", "bkuser.apps.sync", + "bkuser.apps.idp", + "bkuser.apps.natural_user", ] MIDDLEWARE = [ diff --git a/src/bk-user/pyproject.toml b/src/bk-user/pyproject.toml index 0f3198a8c..cadd5a6a7 100644 --- a/src/bk-user/pyproject.toml +++ b/src/bk-user/pyproject.toml @@ -82,12 +82,10 @@ ignore_errors = true [tool.ruff] # Enable Pyflakes `E` and `F` codes by default. -select = ["E", "F", "W", "I", "C90", "PL", "RET", "N", "C4", "PT", "PERF", "G", "TRY", "SIM"] +select = ["E", "F", "W", "I", "C90", "PL", "RET", "N", "C4", "PT", "PERF", "G", "TRY", "SIM", "B", "PIE"] # All Rule: https://beta.ruff.rs/docs/rules/ # Add `noqa: E501` manually when necessary until this issue is fixed: https://github.com/astral-sh/ruff/issues/3825 ignore = [ - # Logging statement uses f-string - "G004", # Consider moving this statement to an else block "TRY300", # Use raise from to specify exception cause @@ -101,7 +99,9 @@ ignore = [ # Avoid too many arguments "PLR0913", # Avoid too many return statements - "PLR0911" + "PLR0911", + # raise-without-from-inside-except + "B904" ] # Same as Black. line-length = 119 @@ -162,7 +162,7 @@ name = "Apps Layers contract" type = "layers" layers = [ "bkuser.apps.tenant", - "bkuser.apps.data_source | bkuser.apps.identity_provider", + "bkuser.apps.data_source | bkuser.apps.idp", ] # biz 分层