mirror of https://github.com/jumpserver/jumpserver
				
				
				
			Merge pull request #9147 from jumpserver/pr@v3@fix_withdraw_acl_unfinished
fix: 删除掉连接方式控制半成品代码pull/9151/head
						commit
						21f91358cf
					
				| 
						 | 
				
			
			@ -1,52 +0,0 @@
 | 
			
		|||
from rest_framework.views import APIView
 | 
			
		||||
from rest_framework import status
 | 
			
		||||
from django.http.response import JsonResponse
 | 
			
		||||
from django.utils.translation import ugettext_lazy as _
 | 
			
		||||
 | 
			
		||||
from common.drf.api import JMSBulkModelViewSet
 | 
			
		||||
from common.const.choices import ConnectMethodChoices
 | 
			
		||||
from ..models import ConnectACL
 | 
			
		||||
from .. import serializers
 | 
			
		||||
 | 
			
		||||
__all__ = ['ConnectACLViewSet', 'ConnectMethodsAPI', 'ConnectMethodPermissionsAPI']
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ConnectACLViewSet(JMSBulkModelViewSet):
 | 
			
		||||
    queryset = ConnectACL.objects.all()
 | 
			
		||||
    filterset_fields = ('name', )
 | 
			
		||||
    search_fields = ('name',)
 | 
			
		||||
    serializer_class = serializers.ConnectACLSerializer
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ConnectMethodsAPI(APIView):
 | 
			
		||||
    rbac_perms = {
 | 
			
		||||
        'GET': 'acls.view_connnectacl',
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def get(request, *args, **kwargs):
 | 
			
		||||
        data = []
 | 
			
		||||
        for m in ConnectMethodChoices.choices:
 | 
			
		||||
            data.append({'label': m[1], 'value': m[0]})
 | 
			
		||||
        return JsonResponse(data, safe=False)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ConnectMethodPermissionsAPI(APIView):
 | 
			
		||||
    rbac_perms = {
 | 
			
		||||
        'GET': 'acls.view_connnectacl',
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def get(request, *args, **kwargs):
 | 
			
		||||
        login_type = request.query_params.get('login_type')
 | 
			
		||||
        if not login_type:
 | 
			
		||||
            rules = ConnectACL().all_rules(request.user)
 | 
			
		||||
            return JsonResponse({'rules': rules})
 | 
			
		||||
 | 
			
		||||
        acl = ConnectACL.match(request.user, login_type)
 | 
			
		||||
        if acl:
 | 
			
		||||
            err = _('The current user is not allowed to login in this way')
 | 
			
		||||
            return JsonResponse({'error': err})
 | 
			
		||||
        else:
 | 
			
		||||
            return JsonResponse({'msg': 'ok'})
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1,120 +0,0 @@
 | 
			
		|||
from django.db import models
 | 
			
		||||
from django.core.cache import cache
 | 
			
		||||
from django.utils.translation import ugettext_lazy as _
 | 
			
		||||
 | 
			
		||||
from common.utils.connection import get_redis_client
 | 
			
		||||
from common.const.choices import ConnectMethodChoices
 | 
			
		||||
from orgs.mixins.models import OrgManager, OrgModelMixin
 | 
			
		||||
from .base import BaseACL, BaseACLQuerySet
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ACLManager(OrgManager):
 | 
			
		||||
 | 
			
		||||
    def valid(self):
 | 
			
		||||
        return self.get_queryset().valid()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ConnectACL(BaseACL, OrgModelMixin):
 | 
			
		||||
    ConnectACLUserCacheKey = 'CONNECT_ACL_USER_{}'
 | 
			
		||||
    ConnectACLUserCacheTTL = 600
 | 
			
		||||
 | 
			
		||||
    class ActionChoices(models.TextChoices):
 | 
			
		||||
        reject = 'reject', _('Reject')
 | 
			
		||||
 | 
			
		||||
    # 用户
 | 
			
		||||
    users = models.ManyToManyField(
 | 
			
		||||
        'users.User', related_name='connect_acls', blank=True,
 | 
			
		||||
        verbose_name=_("User")
 | 
			
		||||
    )
 | 
			
		||||
    user_groups = models.ManyToManyField(
 | 
			
		||||
        'users.UserGroup', related_name='connect_acls', blank=True,
 | 
			
		||||
        verbose_name=_("User group"),
 | 
			
		||||
    )
 | 
			
		||||
    rules = models.JSONField(default=list, verbose_name=_('Rule'))
 | 
			
		||||
    # 动作
 | 
			
		||||
    action = models.CharField(
 | 
			
		||||
        max_length=64, verbose_name=_('Action'),
 | 
			
		||||
        choices=ActionChoices.choices, default=ActionChoices.reject
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    objects = ACLManager.from_queryset(BaseACLQuerySet)()
 | 
			
		||||
 | 
			
		||||
    class Meta:
 | 
			
		||||
        ordering = ('priority', '-date_updated', 'name')
 | 
			
		||||
        verbose_name = _('Connect acl')
 | 
			
		||||
 | 
			
		||||
    def __str__(self):
 | 
			
		||||
        return self.name
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def rules_display(self):
 | 
			
		||||
        return ', '.join(
 | 
			
		||||
            [ConnectMethodChoices.get_label(i) for i in self.rules]
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
    def is_action(self, action):
 | 
			
		||||
        return self.action == action
 | 
			
		||||
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def match(user, connect_type):
 | 
			
		||||
        if not user:
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
        user_acls = user.connect_acls.all().valid().distinct()
 | 
			
		||||
        for acl in user_acls:
 | 
			
		||||
            if connect_type in acl.rules:
 | 
			
		||||
                return acl
 | 
			
		||||
 | 
			
		||||
        for user_group in user.groups.all():
 | 
			
		||||
            acls = user_group.connect_acls.all().valid().distinct()
 | 
			
		||||
            for acl in acls:
 | 
			
		||||
                if connect_type in acl.rules:
 | 
			
		||||
                    return acl
 | 
			
		||||
 | 
			
		||||
    def _get_all_rules_from_cache(self, user):
 | 
			
		||||
        find = False
 | 
			
		||||
        cache_key = self.ConnectACLUserCacheKey.format(user.id)
 | 
			
		||||
        rules = cache.get(cache_key)
 | 
			
		||||
        if rules is not None:
 | 
			
		||||
            find = True
 | 
			
		||||
        return rules, find
 | 
			
		||||
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def _get_all_rules_from_db(user):
 | 
			
		||||
        connect_rules = set()
 | 
			
		||||
        user_acls = user.connect_acls.all().valid()
 | 
			
		||||
        user_acl_rules = user_acls.values_list('id', 'rules')
 | 
			
		||||
        for r_id, rule in user_acl_rules:
 | 
			
		||||
            connect_rules.update(rule)
 | 
			
		||||
 | 
			
		||||
        for ug in user.groups.all():
 | 
			
		||||
            user_group_acls = ug.connect_acls.all().valid()
 | 
			
		||||
            user_group_rules = user_group_acls.values_list('id', 'rules')
 | 
			
		||||
            for r_id, rule in user_group_rules:
 | 
			
		||||
                connect_rules.update(rule)
 | 
			
		||||
        return list(connect_rules)
 | 
			
		||||
 | 
			
		||||
    def set_all_rules_to_cache(self, key, rules):
 | 
			
		||||
        cache.set(key, rules, self.ConnectACLUserCacheTTL)
 | 
			
		||||
 | 
			
		||||
    def all_rules(self, user):
 | 
			
		||||
        rules, find = self._get_all_rules_from_cache(user)
 | 
			
		||||
        if not find:
 | 
			
		||||
            rules = self._get_all_rules_from_db(user)
 | 
			
		||||
            self.set_all_rules_to_cache(
 | 
			
		||||
                self.ConnectACLUserCacheKey.format(user.id), rules
 | 
			
		||||
            )
 | 
			
		||||
        return rules
 | 
			
		||||
 | 
			
		||||
    def clear_rules_cache(self):
 | 
			
		||||
        cache.delete_pattern(
 | 
			
		||||
            self.ConnectACLUserCacheKey.format('*')
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
    def save(self, *args, **kwargs):
 | 
			
		||||
        self.clear_rules_cache()
 | 
			
		||||
        return super().save(*args, **kwargs)
 | 
			
		||||
 | 
			
		||||
    def delete(self, using=None, keep_parents=False):
 | 
			
		||||
        self.clear_rules_cache()
 | 
			
		||||
        return super().delete(using=using, keep_parents=keep_parents)
 | 
			
		||||
| 
						 | 
				
			
			@ -1,36 +0,0 @@
 | 
			
		|||
from django.utils.translation import ugettext as _
 | 
			
		||||
from rest_framework import serializers
 | 
			
		||||
 | 
			
		||||
from common.drf.serializers import BulkModelSerializer
 | 
			
		||||
from common.const.choices import ConnectMethodChoices
 | 
			
		||||
from ..models import ConnectACL
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
__all__ = ['ConnectACLSerializer', ]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ConnectACLSerializer(BulkModelSerializer):
 | 
			
		||||
    action_display = serializers.ReadOnlyField(source='get_action_display', label=_('Action'))
 | 
			
		||||
 | 
			
		||||
    class Meta:
 | 
			
		||||
        model = ConnectACL
 | 
			
		||||
        fields_mini = ['id', 'name']
 | 
			
		||||
        fields_small = fields_mini + [
 | 
			
		||||
            'priority', 'rules', 'rules_display', 'action', 'action_display', 'is_active',
 | 
			
		||||
            'date_created', 'date_updated', 'comment', 'created_by'
 | 
			
		||||
        ]
 | 
			
		||||
        fields_m2m = ['users', 'user_groups']
 | 
			
		||||
        fields = fields_small + fields_m2m
 | 
			
		||||
        extra_kwargs = {
 | 
			
		||||
            'priority': {'default': 50},
 | 
			
		||||
            'is_active': {'default': True}
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def validate_rules(rules):
 | 
			
		||||
        for r in rules:
 | 
			
		||||
            label = ConnectMethodChoices.get_label(r)
 | 
			
		||||
            if not label:
 | 
			
		||||
                error = _('Invalid connection method: {}').format(r)
 | 
			
		||||
                raise serializers.ValidationError(error)
 | 
			
		||||
        return rules
 | 
			
		||||
		Loading…
	
		Reference in New Issue