diff --git a/apps/applications/api/account.py b/apps/applications/api/account.py index def6292c1..1c9449fb3 100644 --- a/apps/applications/api/account.py +++ b/apps/applications/api/account.py @@ -54,6 +54,6 @@ class ApplicationAccountSecretViewSet(ApplicationAccountViewSet): permission_classes = [RBACPermission, NeedMFAVerify] http_method_names = ['get', 'options'] rbac_perms = { - 'retrieve': 'view_applicationaccountsecret', - 'list': 'view_applicationaccountsecret', + 'retrieve': 'applications.view_applicationaccountsecret', + 'list': 'applications.view_applicationaccountsecret', } diff --git a/apps/applications/const.py b/apps/applications/const.py index 79a76b593..23cf409c9 100644 --- a/apps/applications/const.py +++ b/apps/applications/const.py @@ -1,10 +1,10 @@ # coding: utf-8 # -from django.db.models import TextChoices +from django.db import models from django.utils.translation import ugettext_lazy as _ -class AppCategory(TextChoices): +class AppCategory(models.TextChoices): db = 'db', _('Database') remote_app = 'remote_app', _('Remote app') cloud = 'cloud', 'Cloud' @@ -14,7 +14,7 @@ class AppCategory(TextChoices): return dict(cls.choices).get(category, '') -class AppType(TextChoices): +class AppType(models.TextChoices): # db category mysql = 'mysql', 'MySQL' redis = 'redis', 'Redis' diff --git a/apps/assets/models/asset.py b/apps/assets/models/asset.py index e2de48aa6..905b70aa5 100644 --- a/apps/assets/models/asset.py +++ b/apps/assets/models/asset.py @@ -8,7 +8,6 @@ from functools import reduce from collections import OrderedDict from django.db import models -from common.db.models import TextChoices from django.utils.translation import ugettext_lazy as _ from rest_framework.exceptions import ValidationError @@ -59,7 +58,7 @@ class AssetQuerySet(models.QuerySet): class ProtocolsMixin: protocols = '' - class Protocol(TextChoices): + class Protocol(models.TextChoices): ssh = 'ssh', 'SSH' rdp = 'rdp', 'RDP' telnet = 'telnet', 'Telnet' diff --git a/apps/assets/models/domain.py b/apps/assets/models/domain.py index 7fcb02c3c..2d6e8a1bc 100644 --- a/apps/assets/models/domain.py +++ b/apps/assets/models/domain.py @@ -7,7 +7,6 @@ import random from django.core.cache import cache import paramiko from django.db import models -from django.db.models import TextChoices from django.utils.translation import ugettext_lazy as _ from common.utils import get_logger @@ -55,7 +54,7 @@ class Gateway(BaseUser): UNCONNECTIVE_SILENCE_PERIOD_KEY_TMPL = 'asset_unconnective_gateway_silence_period_{}' UNCONNECTIVE_SILENCE_PERIOD_BEGIN_VALUE = 60 * 5 - class Protocol(TextChoices): + class Protocol(models.TextChoices): ssh = 'ssh', 'SSH' ip = models.CharField(max_length=128, verbose_name=_('IP'), db_index=True) diff --git a/apps/assets/models/user.py b/apps/assets/models/user.py index d22f4ea10..428723a11 100644 --- a/apps/assets/models/user.py +++ b/apps/assets/models/user.py @@ -5,13 +5,11 @@ import logging from django.db import models -from django.db.models import Q from django.utils.translation import ugettext_lazy as _ from django.core.validators import MinValueValidator, MaxValueValidator from django.core.cache import cache from common.utils import signer, get_object_or_none -from common.db.models import TextChoices from .base import BaseUser from .asset import Asset from .authbook import AuthBook @@ -24,7 +22,7 @@ logger = logging.getLogger(__name__) class ProtocolMixin: protocol: str - class Protocol(TextChoices): + class Protocol(models.TextChoices): ssh = 'ssh', 'SSH' rdp = 'rdp', 'RDP' telnet = 'telnet', 'Telnet' @@ -217,7 +215,7 @@ class SystemUser(ProtocolMixin, AuthMixin, BaseUser): (LOGIN_MANUAL, _('Manually input')) ) - class Type(TextChoices): + class Type(models.TextChoices): common = 'common', _('Common user') admin = 'admin', _('Admin user') diff --git a/apps/jumpserver/settings/base.py b/apps/jumpserver/settings/base.py index e0c1b5628..936c99980 100644 --- a/apps/jumpserver/settings/base.py +++ b/apps/jumpserver/settings/base.py @@ -1,4 +1,10 @@ import os +import platform + +if platform.system() == 'Darwin' and platform.machine() == 'arm64': + import pymysql + pymysql.version_info = (1, 4, 2, "final", 0) + pymysql.install_as_MySQLdb() from django.urls import reverse_lazy @@ -68,10 +74,9 @@ INSTALLED_APPS = [ 'django.contrib.messages', 'django.contrib.staticfiles', 'django.forms', - 'simple_history', + 'simple_history', # 这个要放到最后,别特么瞎改顺序 ] - MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', @@ -92,7 +97,6 @@ MIDDLEWARE = [ 'simple_history.middleware.HistoryRequestMiddleware', ] - ROOT_URLCONF = 'jumpserver.urls' TEMPLATES = [ @@ -158,13 +162,14 @@ DATABASES = { 'OPTIONS': DB_OPTIONS } } + + DB_CA_PATH = os.path.join(PROJECT_DIR, 'data', 'certs', 'db_ca.pem') if CONFIG.DB_ENGINE.lower() == 'mysql': DB_OPTIONS['init_command'] = "SET sql_mode='STRICT_TRANS_TABLES'" if os.path.isfile(DB_CA_PATH): DB_OPTIONS['ssl'] = {'ca': DB_CA_PATH} - # Password validation # https://docs.djangoproject.com/en/1.10/ref/settings/#auth-password-validators # @@ -234,7 +239,6 @@ EMAIL_RECIPIENT = CONFIG.EMAIL_RECIPIENT EMAIL_USE_SSL = CONFIG.EMAIL_USE_SSL EMAIL_USE_TLS = CONFIG.EMAIL_USE_TLS - # Custom User Auth model AUTH_USER_MODEL = 'users.User' diff --git a/apps/notifications/api/notifications.py b/apps/notifications/api/notifications.py index 8271c2a10..225b8a065 100644 --- a/apps/notifications/api/notifications.py +++ b/apps/notifications/api/notifications.py @@ -19,14 +19,15 @@ __all__ = ( class BackendListView(APIView): + permission_classes = [IsValidUser] + def get(self, request): data = [ { 'name': backend, 'name_display': backend.label } - for backend in BACKEND.choices - if backend.is_enable + for backend in BACKEND if backend.is_enable ] return Response(data=data) @@ -91,7 +92,6 @@ class UserMsgSubscriptionViewSet(ListModelMixin, return queryset - def get_all_test_messages(request): import textwrap from ..notifications import Message @@ -128,5 +128,3 @@ def get_all_test_messages(request):
""").format(msg_cls.__name__, msg_text) return HttpResponse(html_data + text_data) - - diff --git a/apps/ops/views.py b/apps/ops/views.py index 91e753514..fee4a0b9f 100644 --- a/apps/ops/views.py +++ b/apps/ops/views.py @@ -13,7 +13,7 @@ class CeleryTaskLogView(PermissionsMixin, TemplateView): template_name = 'ops/celery_task_log.html' permission_classes = [RBACPermission] rbac_perms = { - 'GET': 'view_tasklog' + 'GET': 'ops.view_tasklog' } def get_context_data(self, **kwargs): diff --git a/apps/perms/api/application/user_permission/common.py b/apps/perms/api/application/user_permission/common.py index e5787c004..650a403cb 100644 --- a/apps/perms/api/application/user_permission/common.py +++ b/apps/perms/api/application/user_permission/common.py @@ -56,7 +56,7 @@ class MyGrantedApplicationSystemUsersApi(RoleUserMixin, GrantedApplicationSystem @method_decorator(tmp_to_root_org(), name='get') class ValidateUserApplicationPermissionApi(APIView): rbac_perms = { - 'GET': 'view_applicationpermission' + 'GET': 'ops.view_applicationpermission' } def get(self, request, *args, **kwargs): diff --git a/apps/perms/api/asset/user_group_permission.py b/apps/perms/api/asset/user_group_permission.py index 5be59efe2..60471432b 100644 --- a/apps/perms/api/asset/user_group_permission.py +++ b/apps/perms/api/asset/user_group_permission.py @@ -123,7 +123,7 @@ class UserGroupGrantedNodeAssetsApi(ListAPIView): class UserGroupGrantedNodesApi(ListAPIView): serializer_class = serializers.NodeGrantedSerializer rbac_perms = { - 'list': 'view_userassets' + 'list': 'perms.view_userassets' } def get_queryset(self): @@ -137,7 +137,7 @@ class UserGroupGrantedNodesApi(ListAPIView): class UserGroupGrantedNodeChildrenAsTreeApi(SerializeToTreeNodeMixin, ListAPIView): rbac_perms = { - 'list': 'view_userassets' + 'list': 'perms.view_userassets' } def get_children_nodes(self, parent_key): diff --git a/apps/perms/models/asset_permission.py b/apps/perms/models/asset_permission.py index 596164461..dbe836afb 100644 --- a/apps/perms/models/asset_permission.py +++ b/apps/perms/models/asset_permission.py @@ -1,9 +1,8 @@ import logging from django.utils.translation import ugettext_lazy as _ -from django.db.models import F +from django.db.models import F, TextChoices -from common.db.models import TextChoices from orgs.mixins.models import OrgModelMixin from common.db import models from common.utils import lazyproperty diff --git a/apps/rbac/apps.py b/apps/rbac/apps.py index f9cc34f88..f22c7cf0a 100644 --- a/apps/rbac/apps.py +++ b/apps/rbac/apps.py @@ -5,3 +5,7 @@ from django.utils.translation import ugettext_lazy as _ class RBACConfig(AppConfig): name = 'rbac' verbose_name = _('RBAC') + + def ready(self): + from . import signal_handlers + super().ready() diff --git a/apps/rbac/builtin.py b/apps/rbac/builtin.py index 63b9b661a..71f7d0bc4 100644 --- a/apps/rbac/builtin.py +++ b/apps/rbac/builtin.py @@ -64,11 +64,11 @@ class PredefineRole: } return defaults - def get_or_create_role(self): + def update_or_create_role(self): from rbac.models import Role defaults = self._get_defaults() permissions = defaults.pop('permissions', []) - role, created = Role.objects.get_or_create(defaults, id=self.id) + role, created = Role.objects.update_or_create(defaults, id=self.id) role.permissions.set(permissions) return role, created @@ -125,10 +125,10 @@ class BuiltinRole: return mapper[name].get_role() @classmethod - def sync_to_db(cls): + def sync_to_db(cls, show_msg=False): roles = cls.get_roles() for pre_role in roles.values(): - role, created = pre_role.get_or_create_role() - print("Create builtin Role: {} - {}".format(role.name, created)) - + role, created = pre_role.update_or_create_role() + if show_msg: + print("Update builtin Role: {} - {}".format(role.name, created)) diff --git a/apps/rbac/migrations/0003_auto_20211130_1037.py b/apps/rbac/migrations/0003_auto_20211130_1037.py index 5cd8a3b00..b72b56876 100644 --- a/apps/rbac/migrations/0003_auto_20211130_1037.py +++ b/apps/rbac/migrations/0003_auto_20211130_1037.py @@ -5,7 +5,7 @@ from rbac.builtin import BuiltinRole def create_builtin_roles(apps, schema_editor): - BuiltinRole.sync_to_db() + BuiltinRole.sync_to_db(show_msg=True) class Migration(migrations.Migration): diff --git a/apps/rbac/models/permission.py b/apps/rbac/models/permission.py index e51c46fb8..0ba84f315 100644 --- a/apps/rbac/models/permission.py +++ b/apps/rbac/models/permission.py @@ -1,7 +1,5 @@ -import uuid from typing import Callable -from django.db import models from django.db.models import F, Count, Q from django.apps import apps from django.utils.translation import ugettext_lazy as _, ugettext diff --git a/apps/rbac/models/role.py b/apps/rbac/models/role.py index bcfa37595..9d539ba13 100644 --- a/apps/rbac/models/role.py +++ b/apps/rbac/models/role.py @@ -49,10 +49,10 @@ class Role(JMSModel): return '%s(%s)' % (self.name, self.get_scope_display()) def is_system_admin(self): - return self.id == self.BuiltinRole.system_admin.id and self.builtin + return str(self.id) == self.BuiltinRole.system_admin.id and self.builtin def is_org_admin(self): - return self.id == self.BuiltinRole.org_admin.id and self.builtin + return str(self.id) == self.BuiltinRole.org_admin.id and self.builtin def is_admin(self): yes = self.is_system_admin() or self.is_org_admin() diff --git a/apps/rbac/signal_handlers.py b/apps/rbac/signal_handlers.py new file mode 100644 index 000000000..316c38211 --- /dev/null +++ b/apps/rbac/signal_handlers.py @@ -0,0 +1,14 @@ +from django.dispatch import receiver +from django.db.models.signals import post_migrate +from django.apps import apps + +from .builtin import BuiltinRole + + +@receiver(post_migrate) +def after_migrate_update_builtin_role_permissions(sender, app_config, **kwargs): + # 最后一个 app migrations 后执行, 更新内置角色的权限 + last_app = list(apps.get_app_configs())[-1] + if app_config.name == last_app.name: + print("After migration, update builtin role permissions") + BuiltinRole.sync_to_db() diff --git a/apps/terminal/api/terminal.py b/apps/terminal/api/terminal.py index ed7cf16bf..f3fa8f5d0 100644 --- a/apps/terminal/api/terminal.py +++ b/apps/terminal/api/terminal.py @@ -85,7 +85,7 @@ class TerminalViewSet(JMSBulkModelViewSet): class TerminalConfig(APIView): rbac_perms = { - 'GET': 'view_terminalconfig' + 'GET': 'terminal.view_terminalconfig' } def get(self, request): diff --git a/apps/terminal/models/session.py b/apps/terminal/models/session.py index 483c50540..c5064beea 100644 --- a/apps/terminal/models/session.py +++ b/apps/terminal/models/session.py @@ -13,7 +13,7 @@ from django.core.cache import cache from assets.models import Asset from users.models import User from orgs.mixins.models import OrgModelMixin -from common.db.models import TextChoices +from django.db.models import TextChoices from ..backends import get_multi_command_storage diff --git a/apps/users/models/user.py b/apps/users/models/user.py index 3d3b45096..4fcf460fb 100644 --- a/apps/users/models/user.py +++ b/apps/users/models/user.py @@ -21,7 +21,7 @@ from orgs.utils import current_org from orgs.models import Organization from common.utils import date_expired_default, get_logger, lazyproperty, random_string from common import fields -from common.db.models import TextChoices +from django.db.models import TextChoices from ..signals import post_user_change_password, post_user_leave_org, pre_user_leave_org __all__ = ['User', 'UserPasswordHistory'] diff --git a/requirements/requirements.txt b/requirements/requirements.txt index 480e19dac..07c0eb688 100644 --- a/requirements/requirements.txt +++ b/requirements/requirements.txt @@ -12,7 +12,7 @@ chardet==3.0.4 configparser==3.5.0 coreapi==2.3.3 coreschema==0.0.4 -cryptography==3.3.2 +cryptography==36.0.1 decorator==4.1.2 Django==3.1.13 django-auth-ldap==2.2.0 @@ -52,8 +52,8 @@ passlib==1.7.1 Pillow==8.3.2 pyasn1==0.4.8 pycparser==2.19 -pycryptodome==3.10.1 -pycryptodomex==3.10.1 +pycryptodome==3.12.0 +pycryptodomex==3.12.0 pyotp==2.2.6 PyNaCl==1.2.1 python-dateutil==2.8.2