mirror of https://github.com/jumpserver/jumpserver
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
121 lines
3.7 KiB
121 lines
3.7 KiB
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)
|