mirror of https://github.com/jumpserver/jumpserver
Stash
parent
8f699fa366
commit
ae690050e7
|
@ -50,19 +50,14 @@ class AssetSystemUserSerializer(serializers.ModelSerializer):
|
||||||
"""
|
"""
|
||||||
查看授权的资产系统用户的数据结构,这个和AssetSerializer不同,字段少
|
查看授权的资产系统用户的数据结构,这个和AssetSerializer不同,字段少
|
||||||
"""
|
"""
|
||||||
actions = serializers.SerializerMethodField()
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = SystemUser
|
model = SystemUser
|
||||||
fields = (
|
fields = (
|
||||||
'id', 'name', 'username', 'priority',
|
'id', 'name', 'username', 'priority',
|
||||||
'protocol', 'comment', 'login_mode', 'actions',
|
'protocol', 'comment', 'login_mode',
|
||||||
)
|
)
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def get_actions(obj):
|
|
||||||
return [action.name for action in obj.actions]
|
|
||||||
|
|
||||||
|
|
||||||
class SystemUserSimpleSerializer(serializers.ModelSerializer):
|
class SystemUserSimpleSerializer(serializers.ModelSerializer):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -54,17 +54,19 @@ class NodeUtil:
|
||||||
def sorted_by(node):
|
def sorted_by(node):
|
||||||
return [int(i) for i in node.key.split(':')]
|
return [int(i) for i in node.key.split(':')]
|
||||||
|
|
||||||
def get_all_nodes(self):
|
def get_queryset(self):
|
||||||
all_nodes = Node.objects.all()
|
all_nodes = Node.objects.all()
|
||||||
if self.with_assets_amount:
|
if self.with_assets_amount:
|
||||||
now = time.time()
|
|
||||||
all_nodes = all_nodes.prefetch_related(
|
all_nodes = all_nodes.prefetch_related(
|
||||||
Prefetch('assets', queryset=Asset.objects.all().only('id'))
|
Prefetch('assets', queryset=Asset.objects.all().only('id'))
|
||||||
)
|
)
|
||||||
all_nodes = list(all_nodes)
|
all_nodes = list(all_nodes)
|
||||||
for node in all_nodes:
|
for node in all_nodes:
|
||||||
node._assets = set(node.assets.all())
|
node._assets = set(node.assets.all())
|
||||||
all_nodes = sorted(all_nodes, key=self.sorted_by)
|
return all_nodes
|
||||||
|
|
||||||
|
def get_all_nodes(self):
|
||||||
|
all_nodes = sorted(self.get_queryset(), key=self.sorted_by)
|
||||||
|
|
||||||
guarder = Node(key='', value='Guarder')
|
guarder = Node(key='', value='Guarder')
|
||||||
guarder._assets = []
|
guarder._assets = []
|
||||||
|
@ -119,11 +121,11 @@ class NodeUtil:
|
||||||
def get_nodes_by_queryset(self, queryset):
|
def get_nodes_by_queryset(self, queryset):
|
||||||
nodes = []
|
nodes = []
|
||||||
for n in queryset:
|
for n in queryset:
|
||||||
node = self._nodes.get(n.key)
|
node = self.get_node_by_key(n.key)
|
||||||
if not node:
|
if not node:
|
||||||
continue
|
continue
|
||||||
nodes.append(nodes)
|
nodes.append(node)
|
||||||
return [self]
|
return nodes
|
||||||
|
|
||||||
def get_node_by_key(self, key):
|
def get_node_by_key(self, key):
|
||||||
return self._nodes.get(key)
|
return self._nodes.get(key)
|
||||||
|
@ -156,11 +158,17 @@ class NodeUtil:
|
||||||
tree_nodes.add(node)
|
tree_nodes.add(node)
|
||||||
if with_children:
|
if with_children:
|
||||||
tree_nodes.update(node._children)
|
tree_nodes.update(node._children)
|
||||||
for n in tree_nodes:
|
|
||||||
delattr(n, '_children')
|
|
||||||
delattr(n, '_parents')
|
|
||||||
return list(tree_nodes)
|
return list(tree_nodes)
|
||||||
|
|
||||||
|
def get_nodes_parents(self, nodes, with_self=True):
|
||||||
|
parents = set()
|
||||||
|
for n in nodes:
|
||||||
|
node = self.get_node_by_key(n.key)
|
||||||
|
parents.update(set(node._parents))
|
||||||
|
if with_self:
|
||||||
|
parents.add(node)
|
||||||
|
return parents
|
||||||
|
|
||||||
|
|
||||||
def test_node_tree():
|
def test_node_tree():
|
||||||
tree = NodeUtil()
|
tree = NodeUtil()
|
||||||
|
|
|
@ -35,7 +35,8 @@ class AssetPermissionViewSet(viewsets.ModelViewSet):
|
||||||
permission_classes = (IsOrgAdmin,)
|
permission_classes = (IsOrgAdmin,)
|
||||||
|
|
||||||
def get_serializer_class(self):
|
def get_serializer_class(self):
|
||||||
if self.action in ("list", 'retrieve'):
|
if self.action in ("list", 'retrieve') and \
|
||||||
|
self.request.query_params.get("display"):
|
||||||
return serializers.AssetPermissionListSerializer
|
return serializers.AssetPermissionListSerializer
|
||||||
return self.serializer_class
|
return self.serializer_class
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
#
|
#
|
||||||
|
import time
|
||||||
from hashlib import md5
|
from hashlib import md5
|
||||||
from django.core.cache import cache
|
from django.core.cache import cache
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
@ -261,14 +261,19 @@ class UserGrantedNodesWithAssetsAsTreeApi(UserPermissionCacheMixin, ListAPIView)
|
||||||
nodes = util.get_nodes_with_assets()
|
nodes = util.get_nodes_with_assets()
|
||||||
print("22222222222222")
|
print("22222222222222")
|
||||||
for node, assets in nodes.items():
|
for node, assets in nodes.items():
|
||||||
|
now = time.time()
|
||||||
|
print("Parse to node")
|
||||||
data = parse_node_to_tree_node(node)
|
data = parse_node_to_tree_node(node)
|
||||||
|
print("parse to node end, using: {0:.2f}".format(time.time() - now))
|
||||||
queryset.append(data)
|
queryset.append(data)
|
||||||
if not self.show_assets:
|
if not self.show_assets:
|
||||||
continue
|
continue
|
||||||
for asset, system_users in assets.items():
|
for asset, system_users in assets.items():
|
||||||
|
now1 = time.time()
|
||||||
|
print("parse to asset")
|
||||||
data = parse_asset_to_tree_node(node, asset, system_users)
|
data = parse_asset_to_tree_node(node, asset, system_users)
|
||||||
|
print("parse to asset end, using: {0:.2f}".format(time.time()-now1))
|
||||||
queryset.append(data)
|
queryset.append(data)
|
||||||
queryset = sorted(queryset)
|
|
||||||
return queryset
|
return queryset
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -74,13 +74,13 @@ class AssetPermissionForm(OrgModelForm):
|
||||||
'system_users': forms.SelectMultiple(
|
'system_users': forms.SelectMultiple(
|
||||||
attrs={'class': 'select2', 'data-placeholder': _('System user')}
|
attrs={'class': 'select2', 'data-placeholder': _('System user')}
|
||||||
),
|
),
|
||||||
'action': forms.CheckboxSelectMultiple()
|
'actions': forms.CheckboxSelectMultiple()
|
||||||
}
|
}
|
||||||
labels = {
|
labels = {
|
||||||
'nodes': _("Node"),
|
'nodes': _("Node"),
|
||||||
}
|
}
|
||||||
help_texts = {
|
help_texts = {
|
||||||
'action': _('Tips: The RDP protocol does not support separate '
|
'actions': _('Tips: The RDP protocol does not support separate '
|
||||||
'controls for uploading or downloading files')
|
'controls for uploading or downloading files')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,7 @@ class Migration(migrations.Migration):
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='assetpermission',
|
model_name='assetpermission',
|
||||||
name='action',
|
name='action',
|
||||||
field=models.IntegerField(choices=[(255, 'All'), (1, 'Connect'), (2, 'Upload file'), (5, 'Upload download'), (4, 'Download file')], default=255, verbose_name='Action'),
|
field=models.IntegerField(choices=[(255, 'All'), (1, 'Connect'), (2, 'Upload file'), (4, 'Download file'), (6, 'Upload download')], default=255, verbose_name='Actions'),
|
||||||
),
|
),
|
||||||
migrations.RunPython(migrate_old_actions),
|
migrations.RunPython(migrate_old_actions),
|
||||||
]
|
]
|
||||||
|
|
|
@ -14,4 +14,9 @@ class Migration(migrations.Migration):
|
||||||
model_name='assetpermission',
|
model_name='assetpermission',
|
||||||
name='actions',
|
name='actions',
|
||||||
),
|
),
|
||||||
|
migrations.RenameField(
|
||||||
|
model_name='assetpermission',
|
||||||
|
old_name='action',
|
||||||
|
new_name='actions',
|
||||||
|
),
|
||||||
]
|
]
|
||||||
|
|
|
@ -39,39 +39,46 @@ class ActionFlag:
|
||||||
UPLOAD = 0b00000010
|
UPLOAD = 0b00000010
|
||||||
DOWNLOAD = 0b00000100
|
DOWNLOAD = 0b00000100
|
||||||
UPDOWNLOAD = UPLOAD | DOWNLOAD
|
UPDOWNLOAD = UPLOAD | DOWNLOAD
|
||||||
CONNECT_UPLOADOWN = CONNECT | UPDOWNLOAD
|
|
||||||
ALL = 0b11111111
|
ALL = 0b11111111
|
||||||
NAME_MAP = {
|
|
||||||
"connect": CONNECT,
|
|
||||||
"upload": UPLOAD,
|
|
||||||
"download": DOWNLOAD,
|
|
||||||
"updownload": UPDOWNLOAD,
|
|
||||||
"all": ALL,
|
|
||||||
}
|
|
||||||
|
|
||||||
CHOICES = (
|
DB_CHOICES = (
|
||||||
(ALL, _('All')),
|
(ALL, _('All')),
|
||||||
(CONNECT, _('Connect')),
|
(CONNECT, _('Connect')),
|
||||||
(UPDOWNLOAD, _("Upload download")),
|
|
||||||
(UPLOAD, _('Upload file')),
|
(UPLOAD, _('Upload file')),
|
||||||
(DOWNLOAD, _('Download file')),
|
(DOWNLOAD, _('Download file')),
|
||||||
|
(UPDOWNLOAD, _("Upload download")),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
NAME_MAP = {
|
||||||
|
ALL: "all",
|
||||||
|
CONNECT: "connect",
|
||||||
|
UPLOAD: "upload_file",
|
||||||
|
DOWNLOAD: "download_file",
|
||||||
|
UPDOWNLOAD: "updownload",
|
||||||
|
}
|
||||||
|
|
||||||
|
NAME_MAP_REVERSE = dict({v: k for k, v in NAME_MAP.items()})
|
||||||
|
CHOICES = []
|
||||||
|
for i, j in DB_CHOICES:
|
||||||
|
CHOICES.append((NAME_MAP[i], j))
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def value_to_choices(cls, value):
|
def value_to_choices(cls, value):
|
||||||
value = int(value)
|
value = int(value)
|
||||||
if value == cls.ALL:
|
choices = [cls.NAME_MAP[i] for i, j in cls.DB_CHOICES if value & i == i]
|
||||||
return [cls.ALL]
|
return choices
|
||||||
elif value == cls.UPDOWNLOAD:
|
|
||||||
return [cls.UPDOWNLOAD]
|
|
||||||
elif value == cls.CONNECT_UPLOADOWN:
|
|
||||||
return [cls.CONNECT, cls.UPDOWNLOAD]
|
|
||||||
else:
|
|
||||||
return [i for i in dict(cls.CHOICES) if i == i & int(value)]
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def choices_to_value(cls, value):
|
def choices_to_value(cls, value):
|
||||||
return reduce(lambda x, y: int(x) | int(y), value)
|
def to_choices(x, y):
|
||||||
|
x = cls.NAME_MAP_REVERSE.get(x, 0)
|
||||||
|
y = cls.NAME_MAP_REVERSE.get(y, 0)
|
||||||
|
return x | y
|
||||||
|
return reduce(to_choices, value)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def choices(cls):
|
||||||
|
return [(cls.NAME_MAP[i], j) for i, j in cls.DB_CHOICES]
|
||||||
|
|
||||||
|
|
||||||
class AssetPermission(BasePermission):
|
class AssetPermission(BasePermission):
|
||||||
|
@ -79,7 +86,7 @@ class AssetPermission(BasePermission):
|
||||||
nodes = models.ManyToManyField('assets.Node', related_name='granted_by_permissions', blank=True, verbose_name=_("Nodes"))
|
nodes = models.ManyToManyField('assets.Node', related_name='granted_by_permissions', blank=True, verbose_name=_("Nodes"))
|
||||||
system_users = models.ManyToManyField('assets.SystemUser', related_name='granted_by_permissions', verbose_name=_("System user"))
|
system_users = models.ManyToManyField('assets.SystemUser', related_name='granted_by_permissions', verbose_name=_("System user"))
|
||||||
# actions = models.ManyToManyField(Action, related_name='permissions', blank=True, verbose_name=_('Action'))
|
# actions = models.ManyToManyField(Action, related_name='permissions', blank=True, verbose_name=_('Action'))
|
||||||
action = models.IntegerField(choices=ActionFlag.CHOICES, default=ActionFlag.ALL, verbose_name=_("Action"))
|
actions = models.IntegerField(choices=ActionFlag.DB_CHOICES, default=ActionFlag.ALL, verbose_name=_("Actions"))
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
unique_together = [('org_id', 'name')]
|
unique_together = [('org_id', 'name')]
|
||||||
|
|
|
@ -38,7 +38,7 @@ class ActionDisplayField(ActionField):
|
||||||
|
|
||||||
|
|
||||||
class AssetPermissionCreateUpdateSerializer(BulkOrgResourceModelSerializer):
|
class AssetPermissionCreateUpdateSerializer(BulkOrgResourceModelSerializer):
|
||||||
action = ActionField()
|
actions = ActionField()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = AssetPermission
|
model = AssetPermission
|
||||||
|
@ -51,7 +51,7 @@ class AssetPermissionListSerializer(BulkOrgResourceModelSerializer):
|
||||||
assets = StringManyToManyField(many=True, read_only=True)
|
assets = StringManyToManyField(many=True, read_only=True)
|
||||||
nodes = StringManyToManyField(many=True, read_only=True)
|
nodes = StringManyToManyField(many=True, read_only=True)
|
||||||
system_users = StringManyToManyField(many=True, read_only=True)
|
system_users = StringManyToManyField(many=True, read_only=True)
|
||||||
action = ActionDisplayField()
|
actions = ActionDisplayField()
|
||||||
is_valid = serializers.BooleanField()
|
is_valid = serializers.BooleanField()
|
||||||
is_expired = serializers.BooleanField()
|
is_expired = serializers.BooleanField()
|
||||||
|
|
||||||
|
|
|
@ -122,8 +122,8 @@ function format(d) {
|
||||||
if (d.system_users.length > 0) {
|
if (d.system_users.length > 0) {
|
||||||
data += makeLabel(["{% trans 'System user' %}", d.system_users.join(", ")])
|
data += makeLabel(["{% trans 'System user' %}", d.system_users.join(", ")])
|
||||||
}
|
}
|
||||||
if (d.action.length > 0) {
|
if (d.actions.length > 0) {
|
||||||
data += makeLabel(["{% trans 'Action' %}", d.action.join(", ")])
|
data += makeLabel(["{% trans 'Action' %}", d.actions.join(", ")])
|
||||||
}
|
}
|
||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
|
@ -180,7 +180,7 @@ function initTable() {
|
||||||
$(td).html(update_btn + del_btn);
|
$(td).html(update_btn + del_btn);
|
||||||
}}
|
}}
|
||||||
],
|
],
|
||||||
ajax_url: '{% url "api-perms:asset-permission-list" %}',
|
ajax_url: '{% url "api-perms:asset-permission-list" %}?display=1',
|
||||||
columns: [
|
columns: [
|
||||||
{data: "id"}, {data: "name"}, {data: "users"},
|
{data: "id"}, {data: "name"}, {data: "users"},
|
||||||
{data: "user_groups"}, {data: "assets"},
|
{data: "user_groups"}, {data: "assets"},
|
||||||
|
|
|
@ -17,8 +17,8 @@ from orgs.utils import set_to_root_org
|
||||||
from common.utils import get_logger
|
from common.utils import get_logger
|
||||||
from common.tree import TreeNode
|
from common.tree import TreeNode
|
||||||
from .. import const
|
from .. import const
|
||||||
from ..models import AssetPermission, Action
|
from ..models import AssetPermission, Action, ActionFlag
|
||||||
from ..hands import Node
|
from ..hands import Node, Asset
|
||||||
from assets.utils import NodeUtil
|
from assets.utils import NodeUtil
|
||||||
|
|
||||||
logger = get_logger(__file__)
|
logger = get_logger(__file__)
|
||||||
|
@ -31,17 +31,57 @@ __all__ = [
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class TreeNodeCounter(NodeUtil):
|
||||||
|
def __init__(self, nodes):
|
||||||
|
self.__nodes = nodes
|
||||||
|
super().__init__(with_assets_amount=True)
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
return self.__nodes
|
||||||
|
|
||||||
|
|
||||||
|
def timeit(func):
|
||||||
|
def wrapper(*args, **kwargs):
|
||||||
|
logger.debug("Start call: {}".format(func.__name__))
|
||||||
|
now = time.time()
|
||||||
|
result = func(*args, **kwargs)
|
||||||
|
using = time.time() - now
|
||||||
|
logger.debug("Call {} end, using: {:.2}s".format(func.__name__, using))
|
||||||
|
return result
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
class GenerateTree:
|
class GenerateTree:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
"""
|
"""
|
||||||
nodes: {"node_instance": {
|
nodes = {
|
||||||
"asset_instance": set("system_user")
|
"<node1>": {
|
||||||
|
"system_users": {
|
||||||
|
"system_user": action,
|
||||||
|
"system_user2": action,
|
||||||
|
},
|
||||||
|
"assets": set([<asset_instance>]),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assets = {
|
||||||
|
"<asset_instance2>": {
|
||||||
|
"system_user": action,
|
||||||
|
"system_user2": action,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
self.node_util = NodeUtil()
|
self._node_util = None
|
||||||
self.nodes = defaultdict(dict)
|
self.nodes = defaultdict(lambda: {"system_users": defaultdict(int), "assets": set(), "assets_amount": 0})
|
||||||
|
self.assets = defaultdict(lambda: defaultdict(int))
|
||||||
self._root_node = None
|
self._root_node = None
|
||||||
self._ungroup_node = None
|
self._ungroup_node = None
|
||||||
|
self._nodes_with_assets = None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def node_util(self):
|
||||||
|
if not self._node_util:
|
||||||
|
self._node_util = NodeUtil()
|
||||||
|
return self._node_util
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def root_node(self):
|
def root_node(self):
|
||||||
|
@ -66,35 +106,79 @@ class GenerateTree:
|
||||||
node_key = '0:0'
|
node_key = '0:0'
|
||||||
node_value = _("Default")
|
node_value = _("Default")
|
||||||
node = Node(id=node_id, key=node_key, value=node_value)
|
node = Node(id=node_id, key=node_key, value=node_value)
|
||||||
self.add_node(node)
|
self.add_node(node, {})
|
||||||
self._ungroup_node = node
|
self._ungroup_node = node
|
||||||
return node
|
return node
|
||||||
|
|
||||||
def add_asset(self, asset, system_users):
|
@timeit
|
||||||
|
def add_assets_without_system_users(self, assets):
|
||||||
|
for asset in assets:
|
||||||
|
self.add_asset(asset, {})
|
||||||
|
|
||||||
|
@timeit
|
||||||
|
def add_assets(self, assets):
|
||||||
|
for asset, system_users in assets.items():
|
||||||
|
self.add_asset(asset, system_users)
|
||||||
|
|
||||||
|
@timeit
|
||||||
|
def add_asset(self, asset, system_users=None):
|
||||||
nodes = asset.nodes.all()
|
nodes = asset.nodes.all()
|
||||||
for node in nodes:
|
nodes = self.node_util.get_nodes_by_queryset(nodes)
|
||||||
if node in self.nodes:
|
if not system_users:
|
||||||
self.nodes[node][asset].update(system_users)
|
system_users = defaultdict(int)
|
||||||
else:
|
else:
|
||||||
self.nodes[self.ungrouped_node][asset].update(system_users)
|
system_users = {k: v for k, v in system_users.items()}
|
||||||
|
_system_users = self.assets[asset]
|
||||||
|
for system_user, action in _system_users.items():
|
||||||
|
system_users[system_user] |= action
|
||||||
|
|
||||||
def get_nodes(self):
|
# 获取父节点们
|
||||||
for node in self.nodes:
|
parents = self.node_util.get_nodes_parents(nodes, with_self=True)
|
||||||
assets = set(self.nodes.get(node).keys())
|
for node in parents:
|
||||||
for n in self.nodes.keys():
|
_system_users = self.nodes[node]["system_users"]
|
||||||
if n.key.startswith(node.key + ':'):
|
self.nodes[node]["assets_amount"] += 1
|
||||||
assets.update(set(self.nodes[n].keys()))
|
for system_user, action in _system_users.items():
|
||||||
node.assets_amount = len(assets)
|
system_users[system_user] |= action
|
||||||
return self.nodes
|
|
||||||
|
|
||||||
def add_node(self, node):
|
# 过滤系统用户的协议
|
||||||
self.nodes[node] = defaultdict(set)
|
system_users = {s: v for s, v in system_users.items() if asset.has_protocol(s.protocol)}
|
||||||
|
self.assets[asset] = system_users
|
||||||
|
|
||||||
|
in_nodes = set(self.nodes.keys()) & set(nodes)
|
||||||
|
if not in_nodes:
|
||||||
|
self.nodes[self.ungrouped_node]["assets_amount"] += 1
|
||||||
|
self.nodes[self.ungrouped_node]["assets"].add(system_users)
|
||||||
|
return
|
||||||
|
|
||||||
|
for node in in_nodes:
|
||||||
|
self.nodes[node]["assets"].add(asset)
|
||||||
|
|
||||||
|
def add_node(self, node, system_users=None):
|
||||||
|
if not system_users:
|
||||||
|
system_users = defaultdict(int)
|
||||||
|
self.nodes[node]["system_users"] = system_users
|
||||||
|
|
||||||
# 添加树节点
|
# 添加树节点
|
||||||
|
@timeit
|
||||||
def add_nodes(self, nodes):
|
def add_nodes(self, nodes):
|
||||||
need_nodes = self.node_util.get_family(nodes, with_children=True)
|
_nodes = nodes.keys()
|
||||||
for node in need_nodes:
|
family = self.node_util.get_family(_nodes, with_children=True)
|
||||||
self.add_node(node)
|
for node in family:
|
||||||
|
self.add_node(node, nodes.get(node, {}))
|
||||||
|
|
||||||
|
def get_assets(self):
|
||||||
|
return dict(self.assets)
|
||||||
|
|
||||||
|
@timeit
|
||||||
|
def get_nodes_with_assets(self):
|
||||||
|
if self._nodes_with_assets:
|
||||||
|
return self._nodes_with_assets
|
||||||
|
nodes = {}
|
||||||
|
for node, values in self.nodes.items():
|
||||||
|
node._assets_amount = values["assets_amount"]
|
||||||
|
nodes[node] = {asset: self.assets.get(asset, {}) for asset in values["assets"]}
|
||||||
|
self._nodes_with_assets = nodes
|
||||||
|
return dict(nodes)
|
||||||
|
|
||||||
|
|
||||||
def get_user_permissions(user, include_group=True):
|
def get_user_permissions(user, include_group=True):
|
||||||
|
@ -131,17 +215,6 @@ def get_system_user_permissions(system_user):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def timeit(func):
|
|
||||||
def wrapper(*args, **kwargs):
|
|
||||||
logger.debug("Start call: {}".format(func.__name__))
|
|
||||||
now = time.time()
|
|
||||||
result = func(*args, **kwargs)
|
|
||||||
using = time.time() - now
|
|
||||||
logger.debug("Call {} end, using: {:.2}".format(func.__name__, using))
|
|
||||||
return result
|
|
||||||
return wrapper
|
|
||||||
|
|
||||||
|
|
||||||
class AssetPermissionCacheMixin:
|
class AssetPermissionCacheMixin:
|
||||||
CACHE_KEY_PREFIX = '_ASSET_PERM_CACHE_'
|
CACHE_KEY_PREFIX = '_ASSET_PERM_CACHE_'
|
||||||
CACHE_META_KEY_PREFIX = '_ASSET_PERM_META_KEY_'
|
CACHE_META_KEY_PREFIX = '_ASSET_PERM_META_KEY_'
|
||||||
|
@ -216,6 +289,16 @@ class AssetPermissionCacheMixin:
|
||||||
cached = cache.get(self.system_key)
|
cached = cache.get(self.system_key)
|
||||||
return cached
|
return cached
|
||||||
|
|
||||||
|
def get_assets(self):
|
||||||
|
if self._is_not_using_cache():
|
||||||
|
return self.get_assets_from_cache()
|
||||||
|
elif self._is_refresh_cache():
|
||||||
|
self.expire_cache()
|
||||||
|
return self.get_assets_from_cache()
|
||||||
|
else:
|
||||||
|
self.expire_cache()
|
||||||
|
return self.get_assets_without_cache()
|
||||||
|
|
||||||
def get_system_users(self):
|
def get_system_users(self):
|
||||||
if self._is_using_cache():
|
if self._is_using_cache():
|
||||||
return self.get_system_user_from_cache()
|
return self.get_system_user_from_cache()
|
||||||
|
@ -282,57 +365,6 @@ class AssetPermissionCacheMixin:
|
||||||
cache.delete_pattern(key)
|
cache.delete_pattern(key)
|
||||||
|
|
||||||
|
|
||||||
class FlatPermissionQueryset(set):
|
|
||||||
def add_many(self, assets_or_nodes, system_users, action, rtp="asset"):
|
|
||||||
print("Add many: {}-{}-{}".format(len(assets_or_nodes), len(system_users), action))
|
|
||||||
if not any([assets_or_nodes, system_users, action]):
|
|
||||||
return
|
|
||||||
|
|
||||||
iterable = itertools.product(assets_or_nodes, system_users, [action])
|
|
||||||
for source, sysuser, action in iterable:
|
|
||||||
permission = FlatPermission(source, sysuser, action, rtp=rtp)
|
|
||||||
print("ADDDDDDDDDDDDDDDd")
|
|
||||||
self.add(permission)
|
|
||||||
|
|
||||||
def group_by_resource(self):
|
|
||||||
resources = defaultdict(lambda: defaultdict(int))
|
|
||||||
for i in self:
|
|
||||||
resources[i.resource][i.system_user] |= i.action
|
|
||||||
return resources
|
|
||||||
|
|
||||||
|
|
||||||
class FlatPermission:
|
|
||||||
def __init__(self, assets_or_node, system_user, action, rtp="asset"):
|
|
||||||
self.id = "{}_{}_{}".format(assets_or_node.id, system_user.id, action)
|
|
||||||
self.resource = assets_or_node
|
|
||||||
self.resource_type = rtp
|
|
||||||
self.system_user = system_user
|
|
||||||
self.action = action
|
|
||||||
|
|
||||||
def __eq__(self, other):
|
|
||||||
if self.id == other.id:
|
|
||||||
return True
|
|
||||||
# 资产不同
|
|
||||||
if self.resource_type == "asset" and self.id != other.id:
|
|
||||||
return False
|
|
||||||
# 不是子节点
|
|
||||||
elif self.resource_type == "node" and not other.resource.key.startswith(self.resource.key):
|
|
||||||
return False
|
|
||||||
# 系统用户优先级大于后者,则相同
|
|
||||||
if self.system_user.priority > self.system_user.priority:
|
|
||||||
return True
|
|
||||||
# 如果系统用户不同,则不同
|
|
||||||
elif self.system_user != other.system_user:
|
|
||||||
return False
|
|
||||||
# 如果action为与后的结果则相同
|
|
||||||
if self.action == self.action | other.action:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
def __hash__(self):
|
|
||||||
return hash(self.id)
|
|
||||||
|
|
||||||
|
|
||||||
class AssetPermissionUtil(AssetPermissionCacheMixin):
|
class AssetPermissionUtil(AssetPermissionCacheMixin):
|
||||||
get_permissions_map = {
|
get_permissions_map = {
|
||||||
"User": get_user_permissions,
|
"User": get_user_permissions,
|
||||||
|
@ -353,6 +385,7 @@ class AssetPermissionUtil(AssetPermissionCacheMixin):
|
||||||
self.tree = GenerateTree()
|
self.tree = GenerateTree()
|
||||||
self.change_org_if_need()
|
self.change_org_if_need()
|
||||||
self.nodes = None
|
self.nodes = None
|
||||||
|
self._nodes = None
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def change_org_if_need():
|
def change_org_if_need():
|
||||||
|
@ -380,29 +413,32 @@ class AssetPermissionUtil(AssetPermissionCacheMixin):
|
||||||
返回用户/组授权规则直接关联的节点
|
返回用户/组授权规则直接关联的节点
|
||||||
:return: {node1: {system_user1: {'actions': set()},}}
|
:return: {node1: {system_user1: {'actions': set()},}}
|
||||||
"""
|
"""
|
||||||
queryset = FlatPermissionQueryset()
|
nodes = defaultdict(lambda: defaultdict(int))
|
||||||
for perm in self.permissions:
|
for perm in self.permissions:
|
||||||
actions = perm.action
|
actions = [perm.actions]
|
||||||
system_users = perm.system_users.all()
|
system_users = perm.system_users.all()
|
||||||
nodes = perm.nodes.all()
|
_nodes = perm.nodes.all()
|
||||||
queryset.add_many(nodes, system_users, actions, rtp="nodes")
|
for node, system_user, action in itertools.product(_nodes, system_users, actions):
|
||||||
print(queryset)
|
nodes[node][system_user] |= action
|
||||||
return queryset.group_by_resource()
|
self.tree.add_nodes(nodes)
|
||||||
|
return nodes
|
||||||
|
|
||||||
@timeit
|
@timeit
|
||||||
def get_assets_direct(self):
|
def get_assets_direct(self):
|
||||||
"""
|
"""
|
||||||
返回用户授权规则直接关联的资产
|
返回用户授权规则直接关联的资产
|
||||||
:return: {asset1: {system_user1: {'actions': set()},}}
|
:return: {asset1: {system_user1: 1,}}
|
||||||
"""
|
"""
|
||||||
queryset = FlatPermissionQueryset()
|
assets = defaultdict(lambda: defaultdict(int))
|
||||||
for perm in self.permissions:
|
for perm in self.permissions:
|
||||||
action = perm.action
|
actions = [perm.actions]
|
||||||
assets = perm.assets.all()
|
_assets = perm.assets.all().prefetch_related('nodes', 'protocols')
|
||||||
system_users = perm.system_users.all()
|
system_users = perm.system_users.all()
|
||||||
queryset.add_many(assets, system_users, action, rtp="assets")
|
iterable = itertools.product(_assets, system_users, actions)
|
||||||
print(queryset)
|
for asset, system_user, action in iterable:
|
||||||
return queryset.group_by_resource()
|
assets[asset][system_user] |= action
|
||||||
|
self.tree.add_assets(assets)
|
||||||
|
return assets
|
||||||
|
|
||||||
@timeit
|
@timeit
|
||||||
def get_assets_without_cache(self):
|
def get_assets_without_cache(self):
|
||||||
|
@ -411,24 +447,34 @@ class AssetPermissionUtil(AssetPermissionCacheMixin):
|
||||||
"""
|
"""
|
||||||
if self._assets:
|
if self._assets:
|
||||||
return self._assets
|
return self._assets
|
||||||
assets = self.get_assets_direct()
|
|
||||||
nodes = self.get_nodes_direct()
|
nodes = self.get_nodes_direct()
|
||||||
print("++++++++++++++++++++++")
|
pattern = set()
|
||||||
print(assets)
|
for node in nodes:
|
||||||
print("---------------------")
|
pattern.add(r'^{0}$|^{0}:'.format(node.key))
|
||||||
print(nodes)
|
pattern = '|'.join(list(pattern))
|
||||||
|
now = time.time()
|
||||||
|
print("Get node assets start")
|
||||||
|
if pattern:
|
||||||
|
assets = Asset.objects.filter(nodes__key__regex=pattern)\
|
||||||
|
.prefetch_related('nodes', "protocols").only('id', 'hostname', 'ip').distinct()
|
||||||
|
else:
|
||||||
|
assets = []
|
||||||
|
assets = list(assets)
|
||||||
|
print("Get node assets end, using: {}".format(time.time() - now))
|
||||||
|
self.tree.add_assets_without_system_users(assets)
|
||||||
|
assets = self.tree.get_assets()
|
||||||
|
self._assets = assets
|
||||||
|
return assets
|
||||||
|
|
||||||
@timeit
|
@timeit
|
||||||
def get_nodes_with_assets_without_cache(self):
|
def get_nodes_with_assets_without_cache(self):
|
||||||
"""
|
"""
|
||||||
返回节点并且包含资产
|
返回节点并且包含资产
|
||||||
{"node": {"assets": set("system_user")}}
|
{"node": {"asset": {"system_user": 1})}}
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
assets = self.get_assets_without_cache()
|
self.get_assets_without_cache()
|
||||||
for asset, system_users in assets.items():
|
return self.tree.get_nodes_with_assets()
|
||||||
self.tree.add_asset(asset, system_users)
|
|
||||||
return self.tree.get_nodes()
|
|
||||||
|
|
||||||
def get_system_user_without_cache(self):
|
def get_system_user_without_cache(self):
|
||||||
system_users = set()
|
system_users = set()
|
||||||
|
@ -460,9 +506,7 @@ def sort_assets(assets, order_by='hostname', reverse=False):
|
||||||
|
|
||||||
|
|
||||||
def parse_node_to_tree_node(node):
|
def parse_node_to_tree_node(node):
|
||||||
from .. import serializers
|
|
||||||
name = '{} ({})'.format(node.value, node.assets_amount)
|
name = '{} ({})'.format(node.value, node.assets_amount)
|
||||||
node_serializer = serializers.GrantedNodeSerializer(node)
|
|
||||||
data = {
|
data = {
|
||||||
'id': node.key,
|
'id': node.key,
|
||||||
'name': name,
|
'name': name,
|
||||||
|
@ -471,7 +515,11 @@ def parse_node_to_tree_node(node):
|
||||||
'isParent': True,
|
'isParent': True,
|
||||||
'open': node.is_root(),
|
'open': node.is_root(),
|
||||||
'meta': {
|
'meta': {
|
||||||
'node': node_serializer.data,
|
'node': {
|
||||||
|
"id": node.id,
|
||||||
|
"key": node.key,
|
||||||
|
"value": node.value,
|
||||||
|
},
|
||||||
'type': 'node'
|
'type': 'node'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -480,23 +528,21 @@ def parse_node_to_tree_node(node):
|
||||||
|
|
||||||
|
|
||||||
def parse_asset_to_tree_node(node, asset, system_users):
|
def parse_asset_to_tree_node(node, asset, system_users):
|
||||||
system_users_protocol_matched = [s for s in system_users if asset.has_protocol(s.protocol)]
|
|
||||||
icon_skin = 'file'
|
icon_skin = 'file'
|
||||||
if asset.platform.lower() == 'windows':
|
if asset.platform.lower() == 'windows':
|
||||||
icon_skin = 'windows'
|
icon_skin = 'windows'
|
||||||
elif asset.platform.lower() == 'linux':
|
elif asset.platform.lower() == 'linux':
|
||||||
icon_skin = 'linux'
|
icon_skin = 'linux'
|
||||||
system_users = []
|
_system_users = []
|
||||||
for system_user in system_users_protocol_matched:
|
for system_user, action in system_users.items():
|
||||||
system_users.append({
|
_system_users.append({
|
||||||
'id': system_user.id,
|
'id': system_user.id,
|
||||||
'name': system_user.name,
|
'name': system_user.name,
|
||||||
'username': system_user.username,
|
'username': system_user.username,
|
||||||
'protocol': system_user.protocol,
|
'protocol': system_user.protocol,
|
||||||
'priority': system_user.priority,
|
'priority': system_user.priority,
|
||||||
'login_mode': system_user.login_mode,
|
'login_mode': system_user.login_mode,
|
||||||
'actions': [action.name for action in system_user.actions],
|
'actions': [ActionFlag.value_to_choices(action)],
|
||||||
'comment': system_user.comment,
|
|
||||||
})
|
})
|
||||||
data = {
|
data = {
|
||||||
'id': str(asset.id),
|
'id': str(asset.id),
|
||||||
|
@ -507,7 +553,7 @@ def parse_asset_to_tree_node(node, asset, system_users):
|
||||||
'open': False,
|
'open': False,
|
||||||
'iconSkin': icon_skin,
|
'iconSkin': icon_skin,
|
||||||
'meta': {
|
'meta': {
|
||||||
'system_users': system_users,
|
'system_users': _system_users,
|
||||||
'type': 'asset',
|
'type': 'asset',
|
||||||
'asset': {
|
'asset': {
|
||||||
'id': asset.id,
|
'id': asset.id,
|
||||||
|
|
|
@ -1,36 +0,0 @@
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
#
|
|
||||||
from django.test import TestCase
|
|
||||||
|
|
||||||
from assets.models import Node, SystemUser
|
|
||||||
from .asset_permission import FlatPermission
|
|
||||||
from ..models import ActionFlag
|
|
||||||
|
|
||||||
|
|
||||||
class TestFlatPermissionEqual(TestCase):
|
|
||||||
def setUp(self):
|
|
||||||
node1 = Node(value="parent", key="1:1")
|
|
||||||
node2 = Node(value="child", key="1:1:1")
|
|
||||||
|
|
||||||
system_user1 = SystemUser(username="name1", name="name1", priority=20)
|
|
||||||
system_user2 = SystemUser(username="name2", name="name2", priority=10)
|
|
||||||
|
|
||||||
action1 = ActionFlag.ALL
|
|
||||||
action2 = ActionFlag.CONNECT
|
|
||||||
action3 = ActionFlag.UPDOWNLOAD
|
|
||||||
|
|
||||||
perm1 = FlatPermission(node1, system_user1, action1)
|
|
||||||
perm2 = FlatPermission(node2, system_user1, action1)
|
|
||||||
perm3 = FlatPermission(node2, system_user2, action1)
|
|
||||||
|
|
||||||
self.groups = (
|
|
||||||
(perm1, perm2, True),
|
|
||||||
(perm1, perm3, True),
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_equal(self):
|
|
||||||
for k, k2, wanted in self.groups:
|
|
||||||
if (k == k2) != wanted:
|
|
||||||
print("Not equal {} {}", k, k2)
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue