Unverified Commit eafef9fc authored by BaiJiangJie's avatar BaiJiangJie Committed by GitHub

Dev (#2785)

* [Update]优化用户页面的资产标签过滤功能 (#2781)

* [Update] 优化用户页面的资产标签下拉框选项

* [Update]增加用户页面的过滤资产标签功能

* [Update]优化用户页面的资产标签过滤

* [Update]优化用户页面的资产标签过滤代码

* [Update] 优化用户页面的资产标签过滤

* [Update] 优化用户API,创建用户添加组织关系 (#2776)

* [Update] 优化前端高度显示css (#2749)

* [Update] 修改授权树显示策略 (#2784)

* [Update] 修改授权树显示策略

* [Update] 是否允许用户执行批量命令

* [Update] 优化授权节点构建

* [Update] 修改节点大小判断

* [Update] 修改节点大小判断
parent e5185ebd
......@@ -40,8 +40,10 @@ class Node(OrgModelMixin):
return self.key == other.key
def __gt__(self, other):
if self.is_root():
if self.is_root() and not other.is_root():
return True
elif not self.is_root() and other.is_root():
return False
self_key = [int(k) for k in self.key.split(':')]
other_key = [int(k) for k in other.key.split(':')]
self_parent_key = self_key[:-1]
......@@ -49,6 +51,10 @@ class Node(OrgModelMixin):
if self_parent_key == other_parent_key:
return self.name > other.name
if len(self_parent_key) < len(other_parent_key):
return True
elif len(self_parent_key) > len(other_parent_key):
return False
return self_key > other_key
def __lt__(self, other):
......
......@@ -153,7 +153,11 @@ function initTree() {
$(document).ready(function () {
initTree();
initTable();
})
}).on('click', '.labels li', function () {
var val = $(this).text();
$("#user_assets_table_filter input").val(val);
asset_table.search(val).draw();
})
.on('click', '.asset_detail', function() {
var data = asset_table.ajax.json();
var asset_id = this.getAttribute("asset-id");
......
......@@ -79,6 +79,7 @@ class UserAssetListView(LoginRequiredMixin, TemplateView):
def get_context_data(self, **kwargs):
context = {
'action': _('My assets'),
'labels': Label.objects.all().order_by('name'),
'system_users': SystemUser.objects.all(),
}
kwargs.update(context)
......
......@@ -15,7 +15,8 @@ def jumpserver_processor(request):
'FAVICON_URL': static('img/facio.ico'),
'JMS_TITLE': 'Jumpserver',
'VERSION': settings.VERSION,
'COPYRIGHT': 'FIT2CLOUD 飞致云' + ' © 2014-2019'
'COPYRIGHT': 'FIT2CLOUD 飞致云' + ' © 2014-2019',
'SECURITY_COMMAND_EXECUTION': settings.SECURITY_COMMAND_EXECUTION,
}
return context
......
......@@ -546,6 +546,7 @@ TERMINAL_REPLAY_STORAGE = {
SECURITY_MFA_AUTH = False
SECURITY_COMMAND_EXECUTION = True
SECURITY_LOGIN_LIMIT_COUNT = 7
SECURITY_LOGIN_LIMIT_TIME = 30 # Unit: minute
SECURITY_MAX_IDLE_TIME = 30 # Unit: minute
......
This diff is collapsed.
......@@ -2,6 +2,7 @@
#
from rest_framework import viewsets
from django.db import transaction
from django.conf import settings
from common.permissions import IsValidUser
from ..models import CommandExecution
......@@ -18,6 +19,11 @@ class CommandExecutionViewSet(viewsets.ModelViewSet):
user_id=str(self.request.user.id)
)
def check_permissions(self, request):
if not settings.SECURITY_COMMAND_EXECUTION:
return self.permission_denied(request, "Command execution disabled")
return super().check_permissions(request)
def perform_create(self, serializer):
instance = serializer.save()
instance.user = self.request.user
......
......@@ -14,6 +14,7 @@ class AssetsFilterMixin(object):
def filter_queryset(self, queryset):
queryset = self.search_assets(queryset)
queryset = self.filter_labels(queryset)
queryset = self.sort_assets(queryset)
return queryset
......@@ -40,6 +41,31 @@ class AssetsFilterMixin(object):
queryset = sort_assets(queryset, order_by=order_by, reverse=reverse)
return queryset
def filter_labels(self, queryset):
from assets.models import Label
query_keys = self.request.query_params.keys()
all_label_keys = Label.objects.values_list('name', flat=True)
valid_keys = set(all_label_keys) & set(query_keys)
labels_query = {}
for key in valid_keys:
labels_query[key] = self.request.query_params.get(key)
if not labels_query:
return queryset
labels = set()
for k, v in labels_query.items():
label = Label.objects.filter(name=k, value=v).first()
if not label:
continue
labels.add(label)
_queryset = []
for asset in queryset:
_labels = set(asset.labels.all()) & set(labels)
if _labels and len(_labels) == len(set(labels)):
_queryset.append(asset)
return _queryset
class RemoteAppFilterMixin(object):
"""
......
......@@ -37,9 +37,21 @@ class GenerateTree:
def add_asset(self, asset, system_users):
nodes = asset.nodes.all()
self.add_nodes(nodes)
in_nodes = False
for node in nodes:
if node not in self.nodes:
continue
self.nodes[node][asset].update(system_users)
in_nodes = True
if not in_nodes:
all_nodes = self.nodes.keys()
# 如果没有授权节点,就放到默认的根节点下
if not all_nodes:
root_node = Node.root()
self.add_node(root_node)
else:
root_node = max(all_nodes)
self.nodes[root_node][asset].update(system_users)
def get_nodes(self):
for node in self.nodes:
......@@ -50,6 +62,7 @@ class GenerateTree:
node.assets_amount = len(assets)
return self.nodes
# 添加节点时,追溯到根节点
def add_node(self, node):
if node in self.nodes:
return
......@@ -62,9 +75,11 @@ class GenerateTree:
self.add_node(n)
break
# 添加树节点
def add_nodes(self, nodes):
for node in nodes:
self.add_node(node)
self.add_nodes(node.get_all_children(with_self=False))
def get_user_permissions(user, include_group=True):
......@@ -123,6 +138,7 @@ class AssetPermissionUtil:
self._assets = None
self._filter_id = 'None' # 当通过filter更改 permission是标记
self.cache_policy = cache_policy
self.tree = GenerateTree()
@classmethod
def is_not_using_cache(cls, cache_policy):
......@@ -181,6 +197,7 @@ class AssetPermissionUtil:
permissions = self.permissions.prefetch_related('nodes', 'system_users')
for perm in permissions:
actions = perm.actions.all()
self.tree.add_nodes(perm.nodes.all())
for node in perm.nodes.all():
system_users = perm.system_users.all()
system_users = self._structured_system_user(system_users, actions)
......@@ -275,10 +292,9 @@ class AssetPermissionUtil:
:return:
"""
assets = self.get_assets_without_cache()
tree = GenerateTree()
for asset, system_users in assets.items():
tree.add_asset(asset, system_users)
return tree.get_nodes()
self.tree.add_asset(asset, system_users)
return self.tree.get_nodes()
def get_nodes_with_assets_from_cache(self):
cached = cache.get(self.node_key)
......
......@@ -180,6 +180,11 @@ class SecuritySettingForm(BaseForm):
'authentication (valid for all users, including administrators)'
)
)
# Execute commands for user
SECURITY_COMMAND_EXECUTION = forms.BooleanField(
required=False, label=_("Batch execute commands"),
help_text=_("Allow user batch execute commands")
)
# limit login count
SECURITY_LOGIN_LIMIT_COUNT = forms.IntegerField(
min_value=3, max_value=99999,
......
......@@ -8118,7 +8118,7 @@ body.md-skin {
#page-wrapper {
position: inherit;
margin: 0 0 0 220px;
min-height: 1200px;
/*min-height: 1200px;*/
}
.navbar-static-side {
z-index: 2001;
......
......@@ -16,11 +16,13 @@
</li>
</ul>
</li>
{% if SECURITY_COMMAND_EXECUTION %}
<li id="ops">
<a href="{% url 'ops:command-execution-start' %}">
<i class="fa fa-terminal" style="width: 14px"></i> <span class="nav-label">{% trans 'Command execution' %}</span><span class="label label-info pull-right"></span>
</a>
</li>
{% endif %}
<li id="users">
<a href="{% url 'users:user-profile' %}">
<i class="fa fa-user" style="width: 14px"></i> <span class="nav-label">{% trans 'Profile' %}</span><span class="label label-info pull-right"></span>
......
......@@ -48,6 +48,9 @@ class UserViewSet(IDInCacheFilterMixin, BulkModelViewSet):
def perform_create(self, serializer):
users = serializer.save()
for user in users:
if current_org and current_org.is_real():
user.orgs.add(current_org.id)
self.send_created_signal(users)
def get_queryset(self):
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment