mirror of https://github.com/jumpserver/jumpserver
fix: rbac 合并 (#7658)
* perf: 修复一些错误权限位 * Pr@fix rbac@fix rbac permissions (#7648) * fix: 确保每次 migrate 执行更新 role permissions * perf: 修改 choices * feat: 兼容apple m1 * perf: 修改 migrations role permissions * perf: pymysql 导入 * perf: admin 判断 * fix: 修复消息订阅权限 Co-authored-by: ibuler <ibuler@qq.com> Co-authored-by: Aaron3S <chenyang@fit2cloud.com> Co-authored-by: feng626 <1304903146@qq.com>pull/7660/head
parent
783c163324
commit
83ff8dbf26
|
@ -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',
|
||||
}
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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')
|
||||
|
||||
|
|
|
@ -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'
|
||||
|
||||
|
|
|
@ -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):
|
|||
<hr />
|
||||
""").format(msg_cls.__name__, msg_text)
|
||||
return HttpResponse(html_data + text_data)
|
||||
|
||||
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
|
@ -85,7 +85,7 @@ class TerminalViewSet(JMSBulkModelViewSet):
|
|||
|
||||
class TerminalConfig(APIView):
|
||||
rbac_perms = {
|
||||
'GET': 'view_terminalconfig'
|
||||
'GET': 'terminal.view_terminalconfig'
|
||||
}
|
||||
|
||||
def get(self, request):
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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']
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue