mirror of https://github.com/jumpserver/jumpserver
perf: remove system user
parent
2948d5af7f
commit
3f47e63080
|
@ -3,7 +3,6 @@ from django.utils.translation import ugettext_lazy as _
|
|||
|
||||
from orgs.mixins.serializers import BulkOrgResourceModelSerializer
|
||||
from orgs.models import Organization
|
||||
from assets.models import SystemUser
|
||||
from assets.const import Protocol
|
||||
from acls import models
|
||||
|
||||
|
@ -60,14 +59,6 @@ class LoginAssetACLSystemUsersSerializer(serializers.Serializer):
|
|||
)
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def validate_protocol_group(protocol_group):
|
||||
unsupported_protocols = set(protocol_group) - set(SystemUser.ASSET_CATEGORY_PROTOCOLS + ['*'])
|
||||
if unsupported_protocols:
|
||||
error = _('Unsupported protocols: {}').format(unsupported_protocols)
|
||||
raise serializers.ValidationError(error)
|
||||
return protocol_group
|
||||
|
||||
|
||||
class LoginAssetACLSerializer(BulkOrgResourceModelSerializer):
|
||||
users = LoginAssetACLUsersSerializer()
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
from django.utils.translation import ugettext_lazy as _
|
||||
from rest_framework import serializers
|
||||
from orgs.utils import tmp_to_root_org
|
||||
from common.utils import get_object_or_none, lazyproperty
|
||||
from users.models import User
|
||||
from assets.models import Asset, SystemUser
|
||||
from assets.models import Asset
|
||||
|
||||
|
||||
__all__ = ['LoginAssetCheckSerializer']
|
||||
|
@ -30,21 +29,21 @@ class LoginAssetCheckSerializer(serializers.Serializer):
|
|||
self.asset = self.validate_object_exist(Asset, asset_id)
|
||||
return asset_id
|
||||
|
||||
def validate_system_user_id(self, system_user_id):
|
||||
self._system_user = self.validate_object_exist(SystemUser, system_user_id)
|
||||
return system_user_id
|
||||
|
||||
def validate_system_user_username(self, system_user_username):
|
||||
system_user_id = self.initial_data.get('system_user_id')
|
||||
system_user = self.validate_object_exist(SystemUser, system_user_id)
|
||||
if self._system_user.login_mode == SystemUser.LOGIN_MANUAL \
|
||||
and not system_user.username \
|
||||
and not system_user.username_same_with_user \
|
||||
and not system_user_username:
|
||||
error = 'Missing parameter: system_user_username'
|
||||
raise serializers.ValidationError(error)
|
||||
self._system_user_username = system_user_username
|
||||
return system_user_username
|
||||
# def validate_system_user_id(self, system_user_id):
|
||||
# self._system_user = self.validate_object_exist(SystemUser, system_user_id)
|
||||
# return system_user_id
|
||||
#
|
||||
# def validate_system_user_username(self, system_user_username):
|
||||
# system_user_id = self.initial_data.get('system_user_id')
|
||||
# system_user = self.validate_object_exist(SystemUser, system_user_id)
|
||||
# if self._system_user.login_mode == SystemUser.LOGIN_MANUAL \
|
||||
# and not system_user.username \
|
||||
# and not system_user.username_same_with_user \
|
||||
# and not system_user_username:
|
||||
# error = 'Missing parameter: system_user_username'
|
||||
# raise serializers.ValidationError(error)
|
||||
# self._system_user_username = system_user_username
|
||||
# return system_user_username
|
||||
|
||||
@staticmethod
|
||||
def validate_object_exist(model, field_id):
|
||||
|
@ -55,16 +54,16 @@ class LoginAssetCheckSerializer(serializers.Serializer):
|
|||
raise serializers.ValidationError(error)
|
||||
return obj
|
||||
|
||||
@lazyproperty
|
||||
def system_user(self):
|
||||
if self._system_user.username_same_with_user:
|
||||
username = self.user.username
|
||||
elif self._system_user.login_mode == SystemUser.LOGIN_MANUAL:
|
||||
username = self._system_user_username
|
||||
else:
|
||||
username = self._system_user.username
|
||||
self._system_user.username = username
|
||||
return self._system_user
|
||||
# @lazyproperty
|
||||
# def system_user(self):
|
||||
# if self._system_user.username_same_with_user:
|
||||
# username = self.user.username
|
||||
# elif self._system_user.login_mode == SystemUser.LOGIN_MANUAL:
|
||||
# username = self._system_user_username
|
||||
# else:
|
||||
# username = self._system_user.username
|
||||
# self._system_user.username = username
|
||||
# return self._system_user
|
||||
|
||||
@lazyproperty
|
||||
def org(self):
|
||||
|
|
|
@ -1,85 +0,0 @@
|
|||
# coding: utf-8
|
||||
#
|
||||
from django.db import models
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
|
||||
class AppCategory(models.TextChoices):
|
||||
db = 'db', _('Database')
|
||||
remote_app = 'remote_app', _('Remote app')
|
||||
cloud = 'cloud', 'Cloud'
|
||||
|
||||
@classmethod
|
||||
def get_label(cls, category):
|
||||
return dict(cls.choices).get(category, '')
|
||||
|
||||
@classmethod
|
||||
def is_xpack(cls, category):
|
||||
return category in ['remote_app']
|
||||
|
||||
|
||||
class AppType(models.TextChoices):
|
||||
# db category
|
||||
mysql = 'mysql', 'MySQL'
|
||||
mariadb = 'mariadb', 'MariaDB'
|
||||
oracle = 'oracle', 'Oracle'
|
||||
pgsql = 'postgresql', 'PostgreSQL'
|
||||
sqlserver = 'sqlserver', 'SQLServer'
|
||||
redis = 'redis', 'Redis'
|
||||
mongodb = 'mongodb', 'MongoDB'
|
||||
|
||||
# remote-app category
|
||||
chrome = 'chrome', 'Chrome'
|
||||
mysql_workbench = 'mysql_workbench', 'MySQL Workbench'
|
||||
vmware_client = 'vmware_client', 'vSphere Client'
|
||||
custom = 'custom', _('Custom')
|
||||
|
||||
# cloud category
|
||||
k8s = 'k8s', 'Kubernetes'
|
||||
|
||||
@classmethod
|
||||
def category_types_mapper(cls):
|
||||
return {
|
||||
AppCategory.db: [
|
||||
cls.mysql, cls.mariadb, cls.oracle, cls.pgsql,
|
||||
cls.sqlserver, cls.redis, cls.mongodb
|
||||
],
|
||||
AppCategory.remote_app: [
|
||||
cls.chrome, cls.mysql_workbench,
|
||||
cls.vmware_client, cls.custom
|
||||
],
|
||||
AppCategory.cloud: [cls.k8s]
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def type_category_mapper(cls):
|
||||
mapper = {}
|
||||
for category, tps in cls.category_types_mapper().items():
|
||||
for tp in tps:
|
||||
mapper[tp] = category
|
||||
return mapper
|
||||
|
||||
@classmethod
|
||||
def get_label(cls, tp):
|
||||
return dict(cls.choices).get(tp, '')
|
||||
|
||||
@classmethod
|
||||
def db_types(cls):
|
||||
return [tp.value for tp in cls.category_types_mapper()[AppCategory.db]]
|
||||
|
||||
@classmethod
|
||||
def remote_app_types(cls):
|
||||
return [tp.value for tp in cls.category_types_mapper()[AppCategory.remote_app]]
|
||||
|
||||
@classmethod
|
||||
def cloud_types(cls):
|
||||
return [tp.value for tp in cls.category_types_mapper()[AppCategory.cloud]]
|
||||
|
||||
@classmethod
|
||||
def is_xpack(cls, tp):
|
||||
tp_category_mapper = cls.type_category_mapper()
|
||||
category = tp_category_mapper[tp]
|
||||
|
||||
if AppCategory.is_xpack(category):
|
||||
return True
|
||||
return tp in ['oracle', 'postgresql', 'sqlserver']
|
|
@ -1,59 +0,0 @@
|
|||
# Generated by Django 3.2.14 on 2022-08-16 08:29
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('tickets', '0019_delete_applyapplicationticket'),
|
||||
('authentication', '0012_auto_20220816_1629'),
|
||||
('applications', '0023_auto_20220816_1021'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterUniqueTogether(
|
||||
name='account',
|
||||
unique_together=None,
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='account',
|
||||
name='app',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='account',
|
||||
name='systemuser',
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='application',
|
||||
unique_together=None,
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='application',
|
||||
name='domain',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='historicalaccount',
|
||||
name='app',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='historicalaccount',
|
||||
name='history_user',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='historicalaccount',
|
||||
name='systemuser',
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name='ApplicationUser',
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name='Account',
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name='Application',
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name='HistoricalAccount',
|
||||
),
|
||||
]
|
|
@ -1,2 +0,0 @@
|
|||
# from .application import *
|
||||
# from .account import *
|
|
@ -1,117 +0,0 @@
|
|||
from django.db import models
|
||||
from simple_history.models import HistoricalRecords
|
||||
from django.db.models import F
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from common.utils import lazyproperty
|
||||
from assets.models.base import BaseAccount
|
||||
from assets.models import SystemUser
|
||||
|
||||
|
||||
class Account(BaseAccount):
|
||||
app = models.ForeignKey(
|
||||
'applications.Application', on_delete=models.CASCADE, null=True, verbose_name=_('Application')
|
||||
)
|
||||
systemuser = models.ForeignKey(
|
||||
'assets.SystemUser', on_delete=models.CASCADE, null=True, verbose_name=_("System user")
|
||||
)
|
||||
version = models.IntegerField(default=1, verbose_name=_('Version'))
|
||||
history = HistoricalRecords()
|
||||
|
||||
auth_attrs = ['username', 'password', 'private_key', 'public_key']
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('Application account')
|
||||
unique_together = [('username', 'app', 'systemuser')]
|
||||
permissions = [
|
||||
('view_applicationaccountsecret', _('Can view application account secret')),
|
||||
('change_appplicationaccountsecret', _('Can change application account secret')),
|
||||
]
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.auth_snapshot = {}
|
||||
|
||||
def get_or_systemuser_attr(self, attr):
|
||||
val = getattr(self, attr, None)
|
||||
if val:
|
||||
return val
|
||||
if self.systemuser:
|
||||
return getattr(self.systemuser, attr, '')
|
||||
return ''
|
||||
|
||||
def load_auth(self):
|
||||
for attr in self.auth_attrs:
|
||||
value = self.get_or_systemuser_attr(attr)
|
||||
self.auth_snapshot[attr] = [getattr(self, attr), value]
|
||||
setattr(self, attr, value)
|
||||
|
||||
def unload_auth(self):
|
||||
if not self.systemuser:
|
||||
return
|
||||
|
||||
for attr, values in self.auth_snapshot.items():
|
||||
origin_value, loaded_value = values
|
||||
current_value = getattr(self, attr, '')
|
||||
if current_value == loaded_value:
|
||||
setattr(self, attr, origin_value)
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
self.unload_auth()
|
||||
instance = super().save(*args, **kwargs)
|
||||
self.load_auth()
|
||||
return instance
|
||||
|
||||
@lazyproperty
|
||||
def category(self):
|
||||
return self.app.category
|
||||
|
||||
@lazyproperty
|
||||
def type(self):
|
||||
return self.app.type
|
||||
|
||||
@lazyproperty
|
||||
def attrs(self):
|
||||
return self.app.attrs
|
||||
|
||||
@lazyproperty
|
||||
def app_display(self):
|
||||
return self.systemuser.name
|
||||
|
||||
@property
|
||||
def username_display(self):
|
||||
return self.get_or_systemuser_attr('username') or ''
|
||||
|
||||
@lazyproperty
|
||||
def systemuser_display(self):
|
||||
if not self.systemuser:
|
||||
return ''
|
||||
return str(self.systemuser)
|
||||
|
||||
@property
|
||||
def smart_name(self):
|
||||
username = self.username_display
|
||||
|
||||
if self.app:
|
||||
app = str(self.app)
|
||||
else:
|
||||
app = '*'
|
||||
return '{}@{}'.format(username, app)
|
||||
|
||||
@classmethod
|
||||
def get_queryset(cls):
|
||||
queryset = cls.objects.all() \
|
||||
.annotate(type=F('app__type')) \
|
||||
.annotate(app_display=F('app__name')) \
|
||||
.annotate(systemuser_display=F('systemuser__name')) \
|
||||
.annotate(category=F('app__category'))
|
||||
return queryset
|
||||
|
||||
def __str__(self):
|
||||
return self.smart_name
|
||||
|
||||
|
||||
class ApplicationUser(SystemUser):
|
||||
class Meta:
|
||||
proxy = True
|
||||
verbose_name = _('Application user')
|
|
@ -1,97 +0,0 @@
|
|||
from django.db import models
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from orgs.mixins.models import OrgModelMixin
|
||||
from common.mixins import CommonModelMixin
|
||||
from common.utils import is_uuid
|
||||
from assets.models import Asset
|
||||
|
||||
from .. import const
|
||||
from .tree import ApplicationTreeNodeMixin
|
||||
|
||||
|
||||
class Application(CommonModelMixin, OrgModelMixin, ApplicationTreeNodeMixin):
|
||||
name = models.CharField(max_length=128, verbose_name=_('Name'))
|
||||
category = models.CharField(
|
||||
max_length=16, choices=const.AppCategory.choices, verbose_name=_('Category')
|
||||
)
|
||||
type = models.CharField(
|
||||
max_length=16, choices=const.AppType.choices, verbose_name=_('Type')
|
||||
)
|
||||
domain = models.ForeignKey(
|
||||
'assets.Domain', null=True, blank=True, related_name='applications',
|
||||
on_delete=models.SET_NULL, verbose_name=_("Domain"),
|
||||
)
|
||||
attrs = models.JSONField(default=dict, verbose_name=_('Attrs'))
|
||||
comment = models.TextField(
|
||||
max_length=128, default='', blank=True, verbose_name=_('Comment')
|
||||
)
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('Application')
|
||||
unique_together = [('org_id', 'name')]
|
||||
ordering = ('name',)
|
||||
permissions = [
|
||||
('match_application', _('Can match application')),
|
||||
]
|
||||
|
||||
def __str__(self):
|
||||
category_display = self.get_category_display()
|
||||
type_display = self.get_type_display()
|
||||
return f'{self.name}({type_display})[{category_display}]'
|
||||
|
||||
@property
|
||||
def category_remote_app(self):
|
||||
return self.category == const.AppCategory.remote_app.value
|
||||
|
||||
@property
|
||||
def category_cloud(self):
|
||||
return self.category == const.AppCategory.cloud.value
|
||||
|
||||
@property
|
||||
def category_db(self):
|
||||
return self.category == const.AppCategory.db.value
|
||||
|
||||
def get_rdp_remote_app_setting(self):
|
||||
from applications.serializers.attrs import get_serializer_class_by_application_type
|
||||
if not self.category_remote_app:
|
||||
raise ValueError(f"Not a remote app application: {self.name}")
|
||||
serializer_class = get_serializer_class_by_application_type(self.type)
|
||||
fields = serializer_class().get_fields()
|
||||
|
||||
parameters = [self.type]
|
||||
for field_name in list(fields.keys()):
|
||||
if field_name in ['asset']:
|
||||
continue
|
||||
value = self.attrs.get(field_name)
|
||||
if not value:
|
||||
continue
|
||||
if field_name == 'path':
|
||||
value = '\"%s\"' % value
|
||||
parameters.append(str(value))
|
||||
|
||||
parameters = ' '.join(parameters)
|
||||
return {
|
||||
'program': '||jmservisor',
|
||||
'working_directory': '',
|
||||
'parameters': parameters
|
||||
}
|
||||
|
||||
def get_remote_app_asset(self, raise_exception=True):
|
||||
asset_id = self.attrs.get('asset')
|
||||
if is_uuid(asset_id):
|
||||
return Asset.objects.filter(id=asset_id).first()
|
||||
if raise_exception:
|
||||
raise ValueError("Remote App not has asset attr")
|
||||
|
||||
def get_target_ip(self):
|
||||
target_ip = ''
|
||||
if self.category_remote_app:
|
||||
asset = self.get_remote_app_asset()
|
||||
target_ip = asset.ip if asset else target_ip
|
||||
elif self.category_cloud:
|
||||
target_ip = self.attrs.get('cluster')
|
||||
elif self.category_db:
|
||||
target_ip = self.attrs.get('host')
|
||||
return target_ip
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
from django.db import models
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from .application import Application
|
||||
|
||||
|
||||
class Database(Application):
|
||||
host = models.CharField(max_length=1024, verbose_name=_('Host'))
|
||||
port = models.IntegerField(verbose_name=_("Port"))
|
||||
database = models.CharField(max_length=1024, blank=True, null=True, verbose_name=_("Database"))
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("Database")
|
|
@ -1,207 +0,0 @@
|
|||
from collections import defaultdict
|
||||
from urllib.parse import urlencode, parse_qsl
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.conf import settings
|
||||
|
||||
from common.tree import TreeNode
|
||||
from .. import const
|
||||
|
||||
|
||||
class ApplicationTreeNodeMixin:
|
||||
id: str
|
||||
name: str
|
||||
type: str
|
||||
category: str
|
||||
attrs: dict
|
||||
|
||||
@staticmethod
|
||||
def create_tree_id(pid, type, v):
|
||||
i = dict(parse_qsl(pid))
|
||||
i[type] = v
|
||||
tree_id = urlencode(i)
|
||||
return tree_id
|
||||
|
||||
@classmethod
|
||||
def create_choice_node(cls, c, id_, pid, tp, opened=False, counts=None,
|
||||
show_empty=True, show_count=True):
|
||||
count = counts.get(c.value, 0)
|
||||
if count == 0 and not show_empty:
|
||||
return None
|
||||
label = c.label
|
||||
if count is not None and show_count:
|
||||
label = '{} ({})'.format(label, count)
|
||||
data = {
|
||||
'id': id_,
|
||||
'name': label,
|
||||
'title': label,
|
||||
'pId': pid,
|
||||
'isParent': bool(count),
|
||||
'open': opened,
|
||||
'iconSkin': '',
|
||||
'meta': {
|
||||
'type': tp,
|
||||
'data': {
|
||||
'name': c.name,
|
||||
'value': c.value
|
||||
}
|
||||
}
|
||||
}
|
||||
return TreeNode(**data)
|
||||
|
||||
@classmethod
|
||||
def create_root_tree_node(cls, queryset, show_count=True):
|
||||
count = queryset.count() if show_count else None
|
||||
root_id = 'applications'
|
||||
root_name = _('Applications')
|
||||
if count is not None and show_count:
|
||||
root_name = '{} ({})'.format(root_name, count)
|
||||
node = TreeNode(**{
|
||||
'id': root_id,
|
||||
'name': root_name,
|
||||
'title': root_name,
|
||||
'pId': '',
|
||||
'isParent': True,
|
||||
'open': True,
|
||||
'iconSkin': '',
|
||||
'meta': {
|
||||
'type': 'applications_root',
|
||||
}
|
||||
})
|
||||
return node
|
||||
|
||||
@classmethod
|
||||
def create_category_tree_nodes(cls, pid, counts=None, show_empty=True, show_count=True):
|
||||
nodes = []
|
||||
categories = const.AppType.category_types_mapper().keys()
|
||||
for category in categories:
|
||||
if not settings.XPACK_ENABLED and const.AppCategory.is_xpack(category):
|
||||
continue
|
||||
i = cls.create_tree_id(pid, 'category', category.value)
|
||||
node = cls.create_choice_node(
|
||||
category, i, pid=pid, tp='category',
|
||||
counts=counts, opened=False, show_empty=show_empty,
|
||||
show_count=show_count
|
||||
)
|
||||
if not node:
|
||||
continue
|
||||
nodes.append(node)
|
||||
return nodes
|
||||
|
||||
@classmethod
|
||||
def create_types_tree_nodes(cls, pid, counts, show_empty=True, show_count=True):
|
||||
nodes = []
|
||||
temp_pid = pid
|
||||
type_category_mapper = const.AppType.type_category_mapper()
|
||||
types = const.AppType.type_category_mapper().keys()
|
||||
|
||||
for tp in types:
|
||||
if not settings.XPACK_ENABLED and const.AppType.is_xpack(tp):
|
||||
continue
|
||||
category = type_category_mapper.get(tp)
|
||||
pid = cls.create_tree_id(pid, 'category', category.value)
|
||||
i = cls.create_tree_id(pid, 'type', tp.value)
|
||||
node = cls.create_choice_node(
|
||||
tp, i, pid, tp='type', counts=counts, opened=False,
|
||||
show_empty=show_empty, show_count=show_count
|
||||
)
|
||||
pid = temp_pid
|
||||
if not node:
|
||||
continue
|
||||
nodes.append(node)
|
||||
return nodes
|
||||
|
||||
@staticmethod
|
||||
def get_tree_node_counts(queryset):
|
||||
counts = defaultdict(int)
|
||||
values = queryset.values_list('type', 'category')
|
||||
for i in values:
|
||||
tp = i[0]
|
||||
category = i[1]
|
||||
counts[tp] += 1
|
||||
counts[category] += 1
|
||||
return counts
|
||||
|
||||
@classmethod
|
||||
def create_category_type_tree_nodes(cls, queryset, pid, show_empty=True, show_count=True):
|
||||
counts = cls.get_tree_node_counts(queryset)
|
||||
tree_nodes = []
|
||||
|
||||
# 类别的节点
|
||||
tree_nodes += cls.create_category_tree_nodes(
|
||||
pid, counts, show_empty=show_empty,
|
||||
show_count=show_count
|
||||
)
|
||||
|
||||
# 类型的节点
|
||||
tree_nodes += cls.create_types_tree_nodes(
|
||||
pid, counts, show_empty=show_empty,
|
||||
show_count=show_count
|
||||
)
|
||||
return tree_nodes
|
||||
|
||||
@classmethod
|
||||
def create_tree_nodes(cls, queryset, root_node=None, show_empty=True, show_count=True):
|
||||
tree_nodes = []
|
||||
|
||||
# 根节点有可能是组织名称
|
||||
if root_node is None:
|
||||
root_node = cls.create_root_tree_node(queryset, show_count=show_count)
|
||||
tree_nodes.append(root_node)
|
||||
|
||||
tree_nodes += cls.create_category_type_tree_nodes(
|
||||
queryset, root_node.id, show_empty=show_empty, show_count=show_count
|
||||
)
|
||||
|
||||
# 应用的节点
|
||||
for app in queryset:
|
||||
if not settings.XPACK_ENABLED and const.AppType.is_xpack(app.type):
|
||||
continue
|
||||
node = app.as_tree_node(root_node.id)
|
||||
tree_nodes.append(node)
|
||||
return tree_nodes
|
||||
|
||||
def create_app_tree_pid(self, root_id):
|
||||
pid = self.create_tree_id(root_id, 'category', self.category)
|
||||
pid = self.create_tree_id(pid, 'type', self.type)
|
||||
return pid
|
||||
|
||||
def as_tree_node(self, pid, k8s_as_tree=False):
|
||||
if self.type == const.AppType.k8s and k8s_as_tree:
|
||||
node = KubernetesTree(pid).as_tree_node(self)
|
||||
else:
|
||||
node = self._as_tree_node(pid)
|
||||
return node
|
||||
|
||||
def _attrs_to_tree(self):
|
||||
if self.category == const.AppCategory.db:
|
||||
return self.attrs
|
||||
return {}
|
||||
|
||||
def _as_tree_node(self, pid):
|
||||
icon_skin_category_mapper = {
|
||||
'remote_app': 'chrome',
|
||||
'db': 'database',
|
||||
'cloud': 'cloud'
|
||||
}
|
||||
icon_skin = icon_skin_category_mapper.get(self.category, 'file')
|
||||
pid = self.create_app_tree_pid(pid)
|
||||
node = TreeNode(**{
|
||||
'id': str(self.id),
|
||||
'name': self.name,
|
||||
'title': self.name,
|
||||
'pId': pid,
|
||||
'isParent': False,
|
||||
'open': False,
|
||||
'iconSkin': icon_skin,
|
||||
'meta': {
|
||||
'type': 'application',
|
||||
'data': {
|
||||
'category': self.category,
|
||||
'type': self.type,
|
||||
'attrs': self._attrs_to_tree()
|
||||
}
|
||||
}
|
||||
})
|
||||
return node
|
||||
|
|
@ -11,19 +11,6 @@ class Migration(migrations.Migration):
|
|||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='AccountTemplate',
|
||||
fields=[
|
||||
('created_by', models.CharField(blank=True, max_length=32, null=True, verbose_name='Created by')),
|
||||
('updated_by', models.CharField(blank=True, max_length=32, null=True, verbose_name='Updated by')),
|
||||
('date_created', models.DateTimeField(auto_now_add=True, null=True, verbose_name='Date created')),
|
||||
('date_updated', models.DateTimeField(auto_now=True, verbose_name='Date updated')),
|
||||
('id', models.UUIDField(default=uuid.uuid4, primary_key=True, serialize=False)),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='account',
|
||||
name='protocol',
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
# Generated by Django 3.2.14 on 2022-08-16 02:22
|
||||
import time
|
||||
from django.db import migrations, models
|
||||
from django.db.models import Count
|
||||
|
||||
|
||||
def migrate_command_filter_to_assets(apps, schema_editor):
|
||||
|
@ -50,9 +51,6 @@ class Migration(migrations.Migration):
|
|||
]
|
||||
|
||||
operations = [
|
||||
migrations.DeleteModel(
|
||||
name='AccountTemplate',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='commandfilter',
|
||||
name='accounts',
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
from .base import *
|
||||
from .platform import *
|
||||
from ._user import *
|
||||
# from ._user import *
|
||||
from .asset import *
|
||||
from .label import Label
|
||||
from .group import *
|
||||
|
@ -12,7 +12,7 @@ from .favorite_asset import *
|
|||
from .account import *
|
||||
from .backup import *
|
||||
# 废弃以下
|
||||
from ._authbook import *
|
||||
# from ._authbook import *
|
||||
from .protocol import *
|
||||
from .cmd_filter import *
|
||||
|
||||
|
|
|
@ -11,24 +11,10 @@ from common.utils import validate_ssh_private_key
|
|||
|
||||
|
||||
__all__ = [
|
||||
'init_model', 'generate_fake', 'private_key_validator',
|
||||
'private_key_validator',
|
||||
]
|
||||
|
||||
|
||||
def init_model():
|
||||
from . import SystemUser, AdminUser, Asset
|
||||
for cls in [SystemUser, AdminUser, Asset]:
|
||||
if hasattr(cls, 'initial'):
|
||||
cls.initial()
|
||||
|
||||
|
||||
def generate_fake():
|
||||
from . import SystemUser, AdminUser, Asset
|
||||
for cls in [SystemUser, AdminUser, Asset]:
|
||||
if hasattr(cls, 'generate_fake'):
|
||||
cls.generate_fake()
|
||||
|
||||
|
||||
def private_key_validator(value):
|
||||
if not validate_ssh_private_key(value):
|
||||
raise ValidationError(
|
||||
|
|
|
@ -16,7 +16,7 @@ from django.utils import translation
|
|||
from rest_framework.renderers import JSONRenderer
|
||||
from rest_framework.request import Request
|
||||
|
||||
from assets.models import Asset, SystemUser
|
||||
from assets.models import Asset
|
||||
from authentication.signals import post_auth_failed, post_auth_success
|
||||
from authentication.utils import check_different_city_login_if_need
|
||||
from jumpserver.utils import current_request
|
||||
|
|
|
@ -13,7 +13,7 @@ from rest_framework.request import Request
|
|||
from common.drf.api import JMSModelViewSet
|
||||
from common.http import is_true
|
||||
from orgs.mixins.api import RootOrgViewMixin
|
||||
from perms.models.base import Action
|
||||
from perms.models import Action
|
||||
from terminal.models import EndpointRule
|
||||
from ..serializers import (
|
||||
ConnectionTokenSerializer, ConnectionTokenSecretSerializer, SuperConnectionTokenSerializer,
|
||||
|
|
|
@ -3,14 +3,14 @@
|
|||
from django.db import migrations, models
|
||||
|
||||
|
||||
def migrate_system_user_to_accounts(apps, schema_editor):
|
||||
connection_token_model = apps.get_model("perms", "ConnectionToken")
|
||||
def migrate_system_user_to_account(apps, schema_editor):
|
||||
connection_token_model = apps.get_model("authentication", "ConnectionToken")
|
||||
count = 0
|
||||
bulk_size = 10000
|
||||
|
||||
while True:
|
||||
connection_tokens = connection_token_model.objects \
|
||||
.prefect_related('system_users')[count:bulk_size]
|
||||
.prefetch_related('system_users')[count:bulk_size]
|
||||
if not connection_tokens:
|
||||
break
|
||||
count += len(connection_tokens)
|
||||
|
@ -45,7 +45,7 @@ class Migration(migrations.Migration):
|
|||
name='account',
|
||||
field=models.CharField(default='', max_length=128, verbose_name='Account'),
|
||||
),
|
||||
migrations.RunPython(migrate_system_user_to_accounts),
|
||||
migrations.RunPython(migrate_system_user_to_account),
|
||||
migrations.RemoveField(
|
||||
model_name='connectiontoken',
|
||||
name='system_user',
|
||||
|
|
|
@ -5,7 +5,7 @@ from orgs.mixins.serializers import OrgResourceModelSerializerMixin
|
|||
from authentication.models import ConnectionToken
|
||||
from common.utils import pretty_string
|
||||
from common.utils.random import random_string
|
||||
from assets.models import Asset, SystemUser, Gateway, Domain, CommandFilterRule
|
||||
from assets.models import Asset, Gateway, Domain, CommandFilterRule
|
||||
from users.models import User
|
||||
from perms.serializers.base import ActionsField
|
||||
|
||||
|
@ -123,15 +123,6 @@ class ConnectionTokenAssetSerializer(serializers.ModelSerializer):
|
|||
fields = ['id', 'name', 'ip', 'protocols', 'org_id']
|
||||
|
||||
|
||||
class ConnectionTokenSystemUserSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = SystemUser
|
||||
fields = [
|
||||
'id', 'name', 'username', 'password', 'private_key',
|
||||
'protocol', 'ad_domain', 'org_id'
|
||||
]
|
||||
|
||||
|
||||
class ConnectionTokenGatewaySerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Gateway
|
||||
|
@ -165,7 +156,7 @@ class ConnectionTokenSecretSerializer(OrgResourceModelSerializerMixin):
|
|||
user = ConnectionTokenUserSerializer(read_only=True)
|
||||
asset = ConnectionTokenAssetSerializer(read_only=True)
|
||||
remote_app = ConnectionTokenRemoteAppSerializer(read_only=True)
|
||||
system_user = ConnectionTokenSystemUserSerializer(read_only=True)
|
||||
account = serializers.CharField(read_only=True)
|
||||
gateway = ConnectionTokenGatewaySerializer(read_only=True)
|
||||
domain = ConnectionTokenDomainSerializer(read_only=True)
|
||||
cmd_filter_rules = ConnectionTokenCmdFilterRuleSerializer(many=True)
|
||||
|
|
|
@ -157,7 +157,6 @@ class AdHoc(OrgModelMixin):
|
|||
hosts = models.ManyToManyField('assets.Asset', verbose_name=_("Host"))
|
||||
run_as_admin = models.BooleanField(default=False, verbose_name=_('Run as admin'))
|
||||
run_as = models.CharField(max_length=64, default='', blank=True, null=True, verbose_name=_('Username'))
|
||||
run_system_user = models.ForeignKey('assets.SystemUser', null=True, on_delete=models.CASCADE)
|
||||
become = EncryptJsonDictCharField(max_length=1024, default='', blank=True, null=True, verbose_name=_("Become"))
|
||||
created_by = models.CharField(max_length=64, default='', blank=True, null=True, verbose_name=_('Create by'))
|
||||
date_created = models.DateTimeField(auto_now_add=True, db_index=True)
|
||||
|
|
|
@ -23,6 +23,7 @@ class CommandExecution(OrgModelMixin):
|
|||
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
|
||||
hosts = models.ManyToManyField('assets.Asset')
|
||||
run_as = models.ForeignKey('assets.SystemUser', on_delete=models.CASCADE)
|
||||
account = models.CharField(max_length=128, verbose_name=_('account'))
|
||||
command = models.TextField(verbose_name=_("Command"))
|
||||
_result = models.TextField(blank=True, null=True, verbose_name=_('Result'))
|
||||
user = models.ForeignKey('users.User', on_delete=models.CASCADE, null=True)
|
||||
|
|
|
@ -14,7 +14,7 @@ from .serializers import (
|
|||
)
|
||||
from users.models import User, UserGroup
|
||||
from assets.models import (
|
||||
Asset, Domain, SystemUser, Label, Node, Gateway,
|
||||
Asset, Domain, Label, Node, Gateway,
|
||||
CommandFilter, CommandFilterRule, GatheredUser
|
||||
)
|
||||
from perms.models import AssetPermission
|
||||
|
@ -27,7 +27,7 @@ logger = get_logger(__file__)
|
|||
|
||||
# 部分 org 相关的 model,需要清空这些数据之后才能删除该组织
|
||||
org_related_models = [
|
||||
User, UserGroup, Asset, Label, Domain, Gateway, Node, SystemUser, Label,
|
||||
User, UserGroup, Asset, Label, Domain, Gateway, Node, Label,
|
||||
CommandFilter, CommandFilterRule, GatheredUser,
|
||||
AssetPermission,
|
||||
]
|
||||
|
|
|
@ -6,7 +6,7 @@ from orgs.utils import current_org, tmp_to_org
|
|||
from common.cache import Cache, IntegerField
|
||||
from common.utils import get_logger
|
||||
from users.models import UserGroup, User
|
||||
from assets.models import Node, SystemUser, Domain, Gateway, Asset
|
||||
from assets.models import Node, Domain, Gateway, Asset
|
||||
from terminal.models import Session
|
||||
from perms.models import AssetPermission
|
||||
|
||||
|
@ -71,12 +71,6 @@ class OrgResourceStatisticsCache(OrgRelatedCache):
|
|||
def get_current_org(self):
|
||||
return self.org
|
||||
|
||||
def compute_admin_users_amount(self):
|
||||
return SystemUser.objects.filter(type=SystemUser.Type.admin).count()
|
||||
|
||||
def compute_system_users_amount(self):
|
||||
return SystemUser.objects.filter(type=SystemUser.Type.common).count()
|
||||
|
||||
def compute_users_amount(self):
|
||||
amount = User.get_org_users(self.org).count()
|
||||
return amount
|
||||
|
|
|
@ -8,7 +8,7 @@ from users.models import UserGroup, User
|
|||
from users.signals import pre_user_leave_org
|
||||
from terminal.models import Session
|
||||
from rbac.models import OrgRoleBinding, SystemRoleBinding, RoleBinding
|
||||
from assets.models import Asset, SystemUser, Domain, Gateway
|
||||
from assets.models import Asset, Domain, Gateway
|
||||
from orgs.caches import OrgResourceStatisticsCache
|
||||
from orgs.utils import current_org
|
||||
from common.utils import get_logger
|
||||
|
@ -77,7 +77,6 @@ class OrgResourceStatisticsRefreshUtil:
|
|||
AssetPermission: ['asset_perms_amount'],
|
||||
Gateway: ['gateways_amount'],
|
||||
Domain: ['domains_amount'],
|
||||
SystemUser: ['system_users_amount', 'admin_users_amount'],
|
||||
Node: ['nodes_amount'],
|
||||
Asset: ['assets_amount'],
|
||||
UserGroup: ['groups_amount'],
|
||||
|
|
|
@ -14,7 +14,6 @@ from orgs.models import Organization
|
|||
from orgs.hands import set_current_org, Node, get_current_org
|
||||
from perms.models import AssetPermission
|
||||
from users.models import UserGroup, User
|
||||
from assets.models import SystemUser
|
||||
from common.const.signals import PRE_REMOVE, POST_REMOVE
|
||||
from common.decorator import on_transaction_commit
|
||||
from common.signals import django_ready
|
||||
|
@ -135,7 +134,7 @@ def _clear_users_from_org(org, users):
|
|||
if not users:
|
||||
return
|
||||
|
||||
models = (AssetPermission, UserGroup, SystemUser)
|
||||
models = (AssetPermission, UserGroup)
|
||||
|
||||
for m in models:
|
||||
_remove_users(m, users, org)
|
||||
|
|
|
@ -2,4 +2,3 @@
|
|||
#
|
||||
|
||||
from .asset import *
|
||||
from .system_user_permission import *
|
||||
|
|
|
@ -8,7 +8,7 @@ from django.utils.decorators import method_decorator
|
|||
from rest_framework.views import APIView, Response
|
||||
from rest_framework import status
|
||||
from rest_framework.generics import (
|
||||
ListAPIView, get_object_or_404, RetrieveAPIView, DestroyAPIView
|
||||
ListAPIView, get_object_or_404, RetrieveAPIView
|
||||
)
|
||||
|
||||
from orgs.utils import tmp_to_root_org
|
||||
|
@ -16,7 +16,7 @@ from perms.utils.asset.permission import get_asset_system_user_ids_with_actions_
|
|||
from common.permissions import IsValidUser
|
||||
from common.utils import get_logger, lazyproperty
|
||||
|
||||
from perms.hands import User, Asset, SystemUser
|
||||
from perms.hands import User, Asset
|
||||
from perms import serializers
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
@ -25,7 +25,6 @@ __all__ = [
|
|||
'UserGrantedAssetSystemUsersForAdminApi',
|
||||
'ValidateUserAssetPermissionApi',
|
||||
'GetUserAssetPermissionActionsApi',
|
||||
'UserAssetPermissionsCacheApi',
|
||||
'MyGrantedAssetSystemUsersApi',
|
||||
]
|
||||
|
||||
|
@ -45,19 +44,18 @@ class GetUserAssetPermissionActionsApi(RetrieveAPIView):
|
|||
|
||||
def get_object(self):
|
||||
asset_id = self.request.query_params.get('asset_id', '')
|
||||
system_id = self.request.query_params.get('system_user_id', '')
|
||||
account = self.request.query_params.get('account', '')
|
||||
|
||||
try:
|
||||
asset_id = uuid.UUID(asset_id)
|
||||
system_id = uuid.UUID(system_id)
|
||||
except ValueError:
|
||||
return Response({'msg': False}, status=403)
|
||||
|
||||
asset = get_object_or_404(Asset, id=asset_id)
|
||||
system_user = get_object_or_404(SystemUser, id=system_id)
|
||||
|
||||
system_users_actions = get_asset_system_user_ids_with_actions_by_user(self.get_user(), asset)
|
||||
actions = system_users_actions.get(system_user.id)
|
||||
# actions = system_users_actions.get(system_user.id)
|
||||
actions = system_users_actions.get(account)
|
||||
return {"actions": actions}
|
||||
|
||||
|
||||
|
@ -70,7 +68,7 @@ class ValidateUserAssetPermissionApi(APIView):
|
|||
def get(self, request, *args, **kwargs):
|
||||
user_id = self.request.query_params.get('user_id', '')
|
||||
asset_id = request.query_params.get('asset_id', '')
|
||||
system_id = request.query_params.get('system_user_id', '')
|
||||
account = request.query_params.get('account', '')
|
||||
action_name = request.query_params.get('action_name', '')
|
||||
|
||||
data = {
|
||||
|
@ -79,14 +77,13 @@ class ValidateUserAssetPermissionApi(APIView):
|
|||
'actions': []
|
||||
}
|
||||
|
||||
if not all((user_id, asset_id, system_id, action_name)):
|
||||
if not all((user_id, asset_id, account, action_name)):
|
||||
return Response(data)
|
||||
|
||||
user = User.objects.get(id=user_id)
|
||||
asset = Asset.objects.valid().get(id=asset_id)
|
||||
system_user = SystemUser.objects.get(id=system_id)
|
||||
|
||||
has_perm, actions, expire_at = validate_permission(user, asset, system_user, action_name)
|
||||
has_perm, actions, expire_at = validate_permission(user, asset, account, action_name)
|
||||
status_code = status.HTTP_200_OK if has_perm else status.HTTP_403_FORBIDDEN
|
||||
data = {
|
||||
'has_permission': has_perm,
|
||||
|
@ -97,8 +94,6 @@ class ValidateUserAssetPermissionApi(APIView):
|
|||
|
||||
|
||||
class UserGrantedAssetSystemUsersForAdminApi(ListAPIView):
|
||||
serializer_class = serializers.AssetSystemUserSerializer
|
||||
only_fields = serializers.AssetSystemUserSerializer.Meta.only_fields
|
||||
rbac_perms = {
|
||||
'list': 'perms.view_userassets'
|
||||
}
|
||||
|
@ -117,13 +112,6 @@ class UserGrantedAssetSystemUsersForAdminApi(ListAPIView):
|
|||
def get_asset_system_user_ids_with_actions(self, asset):
|
||||
return get_asset_system_user_ids_with_actions_by_user(self.user, asset)
|
||||
|
||||
def get_queryset(self):
|
||||
system_user_ids = self.system_users_with_actions.keys()
|
||||
system_users = SystemUser.objects.filter(id__in=system_user_ids) \
|
||||
.only(*self.serializer_class.Meta.only_fields) \
|
||||
.order_by('name')
|
||||
return system_users
|
||||
|
||||
def paginate_queryset(self, queryset):
|
||||
page = super().paginate_queryset(queryset)
|
||||
|
||||
|
@ -148,8 +136,3 @@ class MyGrantedAssetSystemUsersApi(UserGrantedAssetSystemUsersForAdminApi):
|
|||
def user(self):
|
||||
return self.request.user
|
||||
|
||||
|
||||
# TODO 删除
|
||||
class UserAssetPermissionsCacheApi(DestroyAPIView):
|
||||
def destroy(self, request, *args, **kwargs):
|
||||
return Response(status=204)
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
from rest_framework import generics
|
||||
|
||||
from assets.models import SystemUser
|
||||
from common.permissions import IsValidUser
|
||||
from perms.utils.asset.user_permission import get_user_all_asset_perm_ids
|
||||
from .. import serializers
|
||||
|
||||
|
||||
class SystemUserPermission(generics.ListAPIView):
|
||||
permission_classes = (IsValidUser,)
|
||||
serializer_class = serializers.SystemUserSerializer
|
||||
|
||||
def get_queryset(self):
|
||||
user = self.request.user
|
||||
|
||||
asset_perm_ids = get_user_all_asset_perm_ids(user)
|
||||
queryset = SystemUser.objects.filter(
|
||||
granted_by_permissions__id__in=asset_perm_ids
|
||||
).distinct()
|
||||
|
||||
return queryset
|
|
@ -5,7 +5,7 @@ from common.db.models import UnionQuerySet
|
|||
from common.drf.filters import BaseFilterSet
|
||||
from common.utils import get_object_or_none
|
||||
from users.models import User, UserGroup
|
||||
from assets.models import Node, Asset, SystemUser
|
||||
from assets.models import Node, Asset
|
||||
from perms.models import AssetPermission
|
||||
|
||||
|
||||
|
@ -30,7 +30,6 @@ class PermissionBaseFilter(BaseFilterSet):
|
|||
qs = super().qs
|
||||
qs = self.filter_valid(qs)
|
||||
qs = self.filter_user(qs)
|
||||
qs = self.filter_system_user(qs)
|
||||
qs = self.filter_user_group(qs)
|
||||
return qs
|
||||
|
||||
|
@ -74,21 +73,6 @@ class PermissionBaseFilter(BaseFilterSet):
|
|||
).distinct()
|
||||
return queryset
|
||||
|
||||
def filter_system_user(self, queryset):
|
||||
system_user_id = self.get_query_param('system_user_id')
|
||||
system_user_name = self.get_query_param('system_user')
|
||||
|
||||
if system_user_id:
|
||||
system_user = get_object_or_none(SystemUser, pk=system_user_id)
|
||||
elif system_user_name:
|
||||
system_user = get_object_or_none(SystemUser, name=system_user_name)
|
||||
else:
|
||||
return queryset
|
||||
if not system_user:
|
||||
return queryset.none()
|
||||
queryset = queryset.filter(system_users=system_user)
|
||||
return queryset
|
||||
|
||||
def filter_user_group(self, queryset):
|
||||
user_group_id = self.get_query_param('user_group_id')
|
||||
user_group_name = self.get_query_param('user_group')
|
||||
|
|
|
@ -2,12 +2,12 @@
|
|||
#
|
||||
|
||||
from users.models import User, UserGroup
|
||||
from assets.models import Asset, SystemUser, Node, Label, FavoriteAsset
|
||||
from assets.models import Asset, Node, Label, FavoriteAsset
|
||||
from assets.serializers import NodeSerializer
|
||||
|
||||
__all__ = [
|
||||
'User', 'UserGroup',
|
||||
'Asset', 'SystemUser', 'Node', 'Label', 'FavoriteAsset',
|
||||
'Asset', 'Node', 'Label', 'FavoriteAsset',
|
||||
'NodeSerializer',
|
||||
]
|
||||
|
||||
|
|
|
@ -1,8 +1,4 @@
|
|||
# Generated by Django 3.2.14 on 2022-08-16 03:32
|
||||
|
||||
|
||||
|
||||
import time
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
|
|
|
@ -2,5 +2,3 @@
|
|||
#
|
||||
|
||||
from .asset_permission import *
|
||||
# from .application_permission import *
|
||||
from .base import *
|
||||
|
|
|
@ -13,7 +13,9 @@ from common.db.models import BaseCreateUpdateModel, BitOperationChoice, UnionQue
|
|||
|
||||
|
||||
__all__ = [
|
||||
'AssetPermission', 'PermNode', 'UserAssetGrantedTreeNodeRelation',
|
||||
'AssetPermission', 'PermNode',
|
||||
'UserAssetGrantedTreeNodeRelation',
|
||||
'Action'
|
||||
]
|
||||
|
||||
# 使用场景
|
||||
|
|
|
@ -1,160 +0,0 @@
|
|||
# coding: utf-8
|
||||
#
|
||||
|
||||
# TODO: v3 delete 整个文件
|
||||
|
||||
|
||||
import uuid
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.db import models
|
||||
from django.db.models import Q
|
||||
from django.utils import timezone
|
||||
from orgs.mixins.models import OrgModelMixin
|
||||
|
||||
from common.db.models import UnionQuerySet, BitOperationChoice
|
||||
from common.utils import date_expired_default, lazyproperty
|
||||
from orgs.mixins.models import OrgManager
|
||||
|
||||
__all__ = [
|
||||
'BasePermission', 'BasePermissionQuerySet', 'Action'
|
||||
]
|
||||
|
||||
|
||||
class BasePermissionQuerySet(models.QuerySet):
|
||||
def active(self):
|
||||
return self.filter(is_active=True)
|
||||
|
||||
def valid(self):
|
||||
return self.active().filter(date_start__lt=timezone.now()) \
|
||||
.filter(date_expired__gt=timezone.now())
|
||||
|
||||
def inactive(self):
|
||||
return self.filter(is_active=False)
|
||||
|
||||
def invalid(self):
|
||||
now = timezone.now()
|
||||
q = (Q(is_active=False) | Q(date_start__gt=now) | Q(date_expired__lt=now))
|
||||
return self.filter(q)
|
||||
|
||||
|
||||
class BasePermissionManager(OrgManager):
|
||||
def valid(self):
|
||||
return self.get_queryset().valid()
|
||||
|
||||
|
||||
class Action(BitOperationChoice):
|
||||
ALL = 0xff
|
||||
|
||||
CONNECT = 0b1
|
||||
UPLOAD = 0b1 << 1
|
||||
DOWNLOAD = 0b1 << 2
|
||||
CLIPBOARD_COPY = 0b1 << 3
|
||||
CLIPBOARD_PASTE = 0b1 << 4
|
||||
UPDOWNLOAD = UPLOAD | DOWNLOAD
|
||||
CLIPBOARD_COPY_PASTE = CLIPBOARD_COPY | CLIPBOARD_PASTE
|
||||
|
||||
DB_CHOICES = (
|
||||
(ALL, _('All')),
|
||||
(CONNECT, _('Connect')),
|
||||
(UPLOAD, _('Upload file')),
|
||||
(DOWNLOAD, _('Download file')),
|
||||
(UPDOWNLOAD, _("Upload download")),
|
||||
(CLIPBOARD_COPY, _('Clipboard copy')),
|
||||
(CLIPBOARD_PASTE, _('Clipboard paste')),
|
||||
(CLIPBOARD_COPY_PASTE, _('Clipboard copy paste'))
|
||||
)
|
||||
|
||||
NAME_MAP = {
|
||||
ALL: "all",
|
||||
CONNECT: "connect",
|
||||
UPLOAD: "upload_file",
|
||||
DOWNLOAD: "download_file",
|
||||
UPDOWNLOAD: "updownload",
|
||||
CLIPBOARD_COPY: 'clipboard_copy',
|
||||
CLIPBOARD_PASTE: 'clipboard_paste',
|
||||
CLIPBOARD_COPY_PASTE: 'clipboard_copy_paste'
|
||||
}
|
||||
|
||||
NAME_MAP_REVERSE = {v: k for k, v in NAME_MAP.items()}
|
||||
CHOICES = []
|
||||
for i, j in DB_CHOICES:
|
||||
CHOICES.append((NAME_MAP[i], j))
|
||||
|
||||
|
||||
class BasePermission(OrgModelMixin):
|
||||
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
|
||||
name = models.CharField(max_length=128, verbose_name=_('Name'))
|
||||
users = models.ManyToManyField('users.User', blank=True, verbose_name=_("User"), related_name='%(class)ss')
|
||||
user_groups = models.ManyToManyField(
|
||||
'users.UserGroup', blank=True, verbose_name=_("User group"), related_name='%(class)ss')
|
||||
actions = models.IntegerField(choices=Action.DB_CHOICES, default=Action.ALL, verbose_name=_("Actions"))
|
||||
is_active = models.BooleanField(default=True, verbose_name=_('Active'))
|
||||
date_start = models.DateTimeField(default=timezone.now, db_index=True, verbose_name=_("Date start"))
|
||||
date_expired = models.DateTimeField(default=date_expired_default, db_index=True, verbose_name=_('Date expired'))
|
||||
created_by = models.CharField(max_length=128, blank=True, verbose_name=_('Created by'))
|
||||
date_created = models.DateTimeField(auto_now_add=True, verbose_name=_('Date created'))
|
||||
comment = models.TextField(verbose_name=_('Comment'), blank=True)
|
||||
from_ticket = models.BooleanField(default=False, verbose_name=_('From ticket'))
|
||||
|
||||
objects = BasePermissionManager.from_queryset(BasePermissionQuerySet)()
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
@property
|
||||
def id_str(self):
|
||||
return str(self.id)
|
||||
|
||||
@property
|
||||
def is_expired(self):
|
||||
if self.date_expired > timezone.now() > self.date_start:
|
||||
return False
|
||||
return True
|
||||
|
||||
@property
|
||||
def is_valid(self):
|
||||
if not self.is_expired and self.is_active:
|
||||
return True
|
||||
return False
|
||||
|
||||
@property
|
||||
def all_users(self):
|
||||
from users.models import User
|
||||
|
||||
users_query = self._meta.get_field('users').related_query_name()
|
||||
user_groups_query = self._meta.get_field('user_groups').related_query_name()
|
||||
|
||||
users_q = Q(**{
|
||||
f'{users_query}': self
|
||||
})
|
||||
|
||||
user_groups_q = Q(**{
|
||||
f'groups__{user_groups_query}': self
|
||||
})
|
||||
|
||||
return User.objects.filter(users_q | user_groups_q).distinct()
|
||||
|
||||
def get_all_users(self):
|
||||
from users.models import User
|
||||
user_ids = self.users.all().values_list('id', flat=True)
|
||||
group_ids = self.user_groups.all().values_list('id', flat=True)
|
||||
|
||||
user_ids = list(user_ids)
|
||||
group_ids = list(group_ids)
|
||||
|
||||
qs1 = User.objects.filter(id__in=user_ids).distinct()
|
||||
qs2 = User.objects.filter(groups__id__in=group_ids).distinct()
|
||||
|
||||
qs = UnionQuerySet(qs1, qs2)
|
||||
return qs
|
||||
|
||||
@lazyproperty
|
||||
def users_amount(self):
|
||||
return self.users.count()
|
||||
|
||||
@lazyproperty
|
||||
def user_groups_amount(self):
|
||||
return self.user_groups.count()
|
|
@ -2,4 +2,3 @@
|
|||
#
|
||||
from .base import *
|
||||
from .asset import *
|
||||
from .system_user_permission import *
|
||||
|
|
|
@ -5,9 +5,8 @@ from rest_framework import serializers
|
|||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.db.models import Q
|
||||
|
||||
from orgs.mixins.serializers import BulkOrgResourceModelSerializer
|
||||
from perms.models import AssetPermission, Action
|
||||
from assets.models import Asset, Node, SystemUser
|
||||
from assets.models import Asset, Node
|
||||
from users.models import User, UserGroup
|
||||
from ..base import ActionsField, BasePermissionSerializer
|
||||
|
||||
|
|
|
@ -4,35 +4,16 @@
|
|||
from rest_framework import serializers
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from assets.models import Node, SystemUser, Asset, Platform
|
||||
from assets.models import Node, Asset, Platform
|
||||
from perms.serializers.base import ActionsField
|
||||
|
||||
__all__ = [
|
||||
'NodeGrantedSerializer',
|
||||
'AssetGrantedSerializer',
|
||||
'ActionsSerializer', 'AssetSystemUserSerializer',
|
||||
'RemoteAppSystemUserSerializer',
|
||||
'DatabaseAppSystemUserSerializer',
|
||||
'K8sAppSystemUserSerializer',
|
||||
'ActionsSerializer',
|
||||
]
|
||||
|
||||
|
||||
class AssetSystemUserSerializer(serializers.ModelSerializer):
|
||||
"""
|
||||
查看授权的资产系统用户的数据结构,这个和AssetSerializer不同,字段少
|
||||
"""
|
||||
actions = ActionsField(read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = SystemUser
|
||||
only_fields = (
|
||||
'id', 'name', 'username', 'priority', 'protocol', 'login_mode',
|
||||
'sftp_root', 'username_same_with_user', 'su_enabled', 'su_from',
|
||||
)
|
||||
fields = list(only_fields) + ["actions"]
|
||||
read_only_fields = fields
|
||||
|
||||
|
||||
class AssetGrantedSerializer(serializers.ModelSerializer):
|
||||
"""
|
||||
被授权资产的数据结构
|
||||
|
@ -63,34 +44,3 @@ class NodeGrantedSerializer(serializers.ModelSerializer):
|
|||
class ActionsSerializer(serializers.Serializer):
|
||||
actions = ActionsField(read_only=True)
|
||||
|
||||
|
||||
# TODO: 删除
|
||||
class RemoteAppSystemUserSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = SystemUser
|
||||
only_fields = (
|
||||
'id', 'name', 'username', 'priority', 'protocol', 'login_mode',
|
||||
)
|
||||
fields = list(only_fields)
|
||||
read_only_fields = fields
|
||||
|
||||
|
||||
class DatabaseAppSystemUserSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = SystemUser
|
||||
only_fields = (
|
||||
'id', 'name', 'username', 'priority', 'protocol', 'login_mode',
|
||||
)
|
||||
fields = list(only_fields)
|
||||
read_only_fields = fields
|
||||
|
||||
|
||||
class K8sAppSystemUserSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = SystemUser
|
||||
only_fields = (
|
||||
'id', 'name', 'username', 'priority', 'protocol', 'login_mode',
|
||||
)
|
||||
fields = list(only_fields)
|
||||
read_only_fields = fields
|
||||
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
from rest_framework import serializers
|
||||
from ..hands import SystemUser
|
||||
|
||||
__all__ = [
|
||||
'SystemUserSerializer',
|
||||
]
|
||||
|
||||
|
||||
class SystemUserSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = SystemUser
|
||||
fields = [
|
||||
'id', 'name', 'username', 'protocol',
|
||||
'login_mode', 'login_mode_display',
|
||||
'priority', 'username_same_with_user',
|
||||
'auto_push_account', 'cmd_filters', 'sudo', 'shell', 'comment',
|
||||
'sftp_root', 'date_created', 'created_by'
|
||||
]
|
||||
ref_name = 'PermedSystemUserSerializer'
|
|
@ -73,11 +73,6 @@ user_permission_urlpatterns = [
|
|||
# Asset System users
|
||||
path('<uuid:pk>/assets/<uuid:asset_id>/system-users/', api.UserGrantedAssetSystemUsersForAdminApi.as_view(), name='user-asset-system-users'),
|
||||
path('assets/<uuid:asset_id>/system-users/', api.MyGrantedAssetSystemUsersApi.as_view(), name='my-asset-system-users'),
|
||||
|
||||
# TODO 要废弃 Expire user permission cache
|
||||
path('<uuid:pk>/asset-permissions/cache/', api.UserAssetPermissionsCacheApi.as_view(),
|
||||
name='user-asset-permission-cache'),
|
||||
path('asset-permissions/cache/', api.UserAssetPermissionsCacheApi.as_view(), name='my-asset-permission-cache'),
|
||||
]
|
||||
|
||||
user_group_permission_urlpatterns = [
|
||||
|
|
|
@ -5,7 +5,7 @@ from django.db.models import Q
|
|||
|
||||
from common.utils import get_logger
|
||||
from perms.models import AssetPermission, Action
|
||||
from perms.hands import Asset, User, UserGroup, SystemUser, Node
|
||||
from perms.hands import Asset, User, UserGroup, Node
|
||||
from perms.utils.asset.user_permission import get_user_all_asset_perm_ids
|
||||
|
||||
logger = get_logger(__file__)
|
||||
|
@ -83,7 +83,7 @@ def get_asset_system_user_ids_with_actions_by_user(user: User, asset: Asset):
|
|||
return get_asset_system_user_ids_with_actions(asset_perm_ids, asset)
|
||||
|
||||
|
||||
def has_asset_system_permission(user: User, asset: Asset, system_user: SystemUser):
|
||||
def has_asset_system_permission(user: User, asset: Asset, account: str):
|
||||
systemuser_actions_mapper = get_asset_system_user_ids_with_actions_by_user(user, asset)
|
||||
actions = systemuser_actions_mapper.get(system_user.id, 0)
|
||||
if actions:
|
||||
|
|
|
@ -1,34 +0,0 @@
|
|||
from django.db import models
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from .general import Ticket
|
||||
from applications.const import AppCategory, AppType
|
||||
|
||||
__all__ = ['ApplyApplicationTicket']
|
||||
|
||||
|
||||
class ApplyApplicationTicket(Ticket):
|
||||
apply_permission_name = models.CharField(max_length=128, verbose_name=_('Permission name'))
|
||||
# 申请信息
|
||||
apply_category = models.CharField(
|
||||
max_length=16, choices=AppCategory.choices, verbose_name=_('Category')
|
||||
)
|
||||
apply_type = models.CharField(
|
||||
max_length=16, choices=AppType.choices, verbose_name=_('Type')
|
||||
)
|
||||
apply_applications = models.ManyToManyField(
|
||||
'applications.Application', verbose_name=_('Apply applications'),
|
||||
)
|
||||
apply_system_users = models.ManyToManyField(
|
||||
'assets.SystemUser', verbose_name=_('Apply system users'),
|
||||
)
|
||||
apply_date_start = models.DateTimeField(verbose_name=_('Date start'), null=True)
|
||||
apply_date_expired = models.DateTimeField(verbose_name=_('Date expired'), null=True)
|
||||
|
||||
@property
|
||||
def apply_category_display(self):
|
||||
return AppCategory.get_label(self.apply_category)
|
||||
|
||||
@property
|
||||
def apply_type_display(self):
|
||||
return AppType.get_label(self.apply_type)
|
|
@ -17,6 +17,7 @@ class ApplyAssetTicket(Ticket):
|
|||
apply_system_users = models.ManyToManyField(
|
||||
'assets.SystemUser', verbose_name=_('Apply system users')
|
||||
)
|
||||
apply_accounts = models.JSONField(default=list, verbose_name=_('Apply accounts'))
|
||||
apply_actions = models.IntegerField(
|
||||
choices=Action.DB_CHOICES, default=Action.ALL, verbose_name=_('Actions')
|
||||
)
|
||||
|
|
|
@ -14,6 +14,7 @@ class ApplyCommandTicket(Ticket):
|
|||
'assets.SystemUser', on_delete=models.SET_NULL,
|
||||
null=True, verbose_name=_('Run system user')
|
||||
)
|
||||
apply_run_account = models.CharField(max_length=128, verbose_name=_('Run account'))
|
||||
apply_run_command = models.CharField(max_length=4096, verbose_name=_('Run command'))
|
||||
apply_from_session = models.ForeignKey(
|
||||
'terminal.Session', on_delete=models.SET_NULL,
|
||||
|
|
|
@ -19,3 +19,4 @@ class ApplyLoginAssetTicket(Ticket):
|
|||
'assets.SystemUser', on_delete=models.SET_NULL, null=True,
|
||||
verbose_name=_('Login system user'),
|
||||
)
|
||||
apply_login_account = models.CharField(max_length=128, verbose_name=_('Login account'))
|
||||
|
|
|
@ -3,7 +3,6 @@ from django.db.models import Model
|
|||
from django.utils.translation import ugettext as _
|
||||
from rest_framework import serializers
|
||||
|
||||
from assets.models import SystemUser
|
||||
from orgs.utils import tmp_to_org
|
||||
from tickets.models import Ticket
|
||||
|
||||
|
@ -54,7 +53,7 @@ class BaseApplyAssetApplicationSerializer(serializers.Serializer):
|
|||
qs = model.objects.filter(id__in=ids, **kwargs).values_list('id', flat=True)
|
||||
return list(qs)
|
||||
|
||||
def validate_apply_system_users(self, system_users):
|
||||
def validate_apply_account(self, system_users):
|
||||
if self.is_final_approval and not system_users:
|
||||
raise serializers.ValidationError(_('This field is required.'))
|
||||
return self.filter_many_to_many_field(SystemUser, system_users)
|
||||
|
|
|
@ -5,45 +5,6 @@ import forgery_py
|
|||
from .base import FakeDataGenerator
|
||||
|
||||
from assets.models import *
|
||||
from assets.const import Protocol
|
||||
|
||||
|
||||
class AdminUsersGenerator(FakeDataGenerator):
|
||||
resource = 'admin_user'
|
||||
|
||||
def do_generate(self, batch, batch_size):
|
||||
admin_users = []
|
||||
for i in batch:
|
||||
username = forgery_py.internet.user_name(True)
|
||||
password = forgery_py.basic.password()
|
||||
admin_users.append(AdminUser(
|
||||
name=username.title(),
|
||||
username=username,
|
||||
password=password,
|
||||
org_id=self.org.id,
|
||||
created_by='Fake',
|
||||
))
|
||||
AdminUser.objects.bulk_create(admin_users, ignore_conflicts=True)
|
||||
|
||||
|
||||
class SystemUsersGenerator(FakeDataGenerator):
|
||||
def do_generate(self, batch, batch_size):
|
||||
system_users = []
|
||||
protocols = list(dict(Protocol.choices).keys())
|
||||
for i in batch:
|
||||
username = forgery_py.internet.user_name(True)
|
||||
protocol = random.choice(protocols)
|
||||
name = username.title()
|
||||
name = f'{name}-{protocol}'
|
||||
system_users.append(SystemUser(
|
||||
name=name,
|
||||
username=username,
|
||||
password=forgery_py.basic.password(),
|
||||
protocol=protocol,
|
||||
org_id=self.org.id,
|
||||
created_by='Fake',
|
||||
))
|
||||
SystemUser.objects.bulk_create(system_users, ignore_conflicts=True)
|
||||
|
||||
|
||||
class NodesGenerator(FakeDataGenerator):
|
||||
|
@ -62,7 +23,6 @@ class AssetsGenerator(FakeDataGenerator):
|
|||
node_ids: list
|
||||
|
||||
def pre_generate(self):
|
||||
self.admin_user_ids = list(AdminUser.objects.all().values_list('id', flat=True))
|
||||
self.node_ids = list(Node.objects.all().values_list('id', flat=True))
|
||||
|
||||
def set_assets_nodes(self, assets):
|
||||
|
|
|
@ -19,7 +19,6 @@ class AssetPermissionGenerator(FakeDataGenerator):
|
|||
def pre_generate(self):
|
||||
self.node_ids = list(Node.objects.all().values_list('id', flat=True))
|
||||
self.asset_ids = list(Asset.objects.all().values_list('id', flat=True))
|
||||
self.system_user_ids = list(SystemUser.objects.all().values_list('id', flat=True))
|
||||
self.user_ids = list(User.objects.all().values_list('id', flat=True))
|
||||
self.user_group_ids = list(UserGroup.objects.all().values_list('id', flat=True))
|
||||
|
||||
|
|
Loading…
Reference in New Issue