diff --git a/apps/assets/api/__init__.py b/apps/assets/api/__init__.py index a1a3beee7..1d7dbca00 100644 --- a/apps/assets/api/__init__.py +++ b/apps/assets/api/__init__.py @@ -4,3 +4,4 @@ from .label import * from .system_user import * from .node import * from .domain import * +from .cmd_filter import * diff --git a/apps/assets/api/cmd_filter.py b/apps/assets/api/cmd_filter.py new file mode 100644 index 000000000..f4537cf17 --- /dev/null +++ b/apps/assets/api/cmd_filter.py @@ -0,0 +1,32 @@ +# -*- coding: utf-8 -*- +# + +from rest_framework_bulk import BulkModelViewSet +from django.shortcuts import get_object_or_404 + +from ..hands import IsOrgAdmin +from ..models import CommandFilter, CommandFilterRule +from .. import serializers + + +__all__ = ['CommandFilterViewSet', 'CommandFilterRuleViewSet'] + + +class CommandFilterViewSet(BulkModelViewSet): + permission_classes = (IsOrgAdmin,) + queryset = CommandFilter.objects.all() + serializer_class = serializers.CommandFilterSerializer + + +class CommandFilterRuleViewSet(BulkModelViewSet): + permission_classes = (IsOrgAdmin,) + serializer_class = serializers.CommandFilterRuleSerializer + + def get_queryset(self): + fpk = self.kwargs.get('filter_pk') + if not fpk: + return CommandFilterRule.objects.none() + group = get_object_or_404(CommandFilter, pk=fpk) + return group.rules.all().order_by('priority') + + diff --git a/apps/assets/api/system_user.py b/apps/assets/api/system_user.py index 6022e1b7e..16d475c35 100644 --- a/apps/assets/api/system_user.py +++ b/apps/assets/api/system_user.py @@ -33,7 +33,8 @@ __all__ = [ 'SystemUserViewSet', 'SystemUserAuthInfoApi', 'SystemUserPushApi', 'SystemUserTestConnectiveApi', 'SystemUserAssetsListView', 'SystemUserPushToAssetApi', - 'SystemUserTestAssetConnectabilityApi', + 'SystemUserTestAssetConnectabilityApi', 'SystemUserCommandFilterRuleListApi', + ] @@ -126,4 +127,17 @@ class SystemUserTestAssetConnectabilityApi(generics.RetrieveAPIView): asset_id = self.kwargs.get('aid') asset = get_object_or_404(Asset, id=asset_id) task = test_system_user_connectability_a_asset.delay(system_user, asset) - return Response({"task": task.id}) \ No newline at end of file + return Response({"task": task.id}) + + +class SystemUserCommandFilterRuleListApi(generics.ListAPIView): + permission_classes = (IsOrgAdminOrAppUser,) + + def get_serializer_class(self): + from ..serializers import CommandFilterRuleSerializer + return CommandFilterRuleSerializer + + def get_queryset(self): + pk = self.kwargs.get('pk', None) + system_user = get_object_or_404(SystemUser, pk=pk) + return system_user.cmd_filter_rules diff --git a/apps/assets/forms/__init__.py b/apps/assets/forms/__init__.py index 4eaa40948..a086cb12c 100644 --- a/apps/assets/forms/__init__.py +++ b/apps/assets/forms/__init__.py @@ -4,3 +4,4 @@ from .asset import * from .label import * from .user import * from .domain import * +from .cmd_filter import * diff --git a/apps/assets/forms/cmd_filter.py b/apps/assets/forms/cmd_filter.py new file mode 100644 index 000000000..ebac4fee2 --- /dev/null +++ b/apps/assets/forms/cmd_filter.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +# +from orgs.mixins import OrgModelForm +from ..models import CommandFilter, CommandFilterRule + +__all__ = ['CommandFilterForm', 'CommandFilterRuleForm'] + + +class CommandFilterForm(OrgModelForm): + class Meta: + model = CommandFilter + fields = ['name', 'comment'] + + +class CommandFilterRuleForm(OrgModelForm): + class Meta: + model = CommandFilterRule + fields = [ + 'filter', 'type', 'content', 'priority', 'action', 'comment' + ] diff --git a/apps/assets/forms/user.py b/apps/assets/forms/user.py index de669bce3..740576067 100644 --- a/apps/assets/forms/user.py +++ b/apps/assets/forms/user.py @@ -3,8 +3,9 @@ from django import forms from django.utils.translation import gettext_lazy as _ -from ..models import AdminUser, SystemUser from common.utils import validate_ssh_private_key, ssh_pubkey_gen, get_logger +from orgs.mixins import OrgModelForm +from ..models import AdminUser, SystemUser logger = get_logger(__file__) __all__ = [ @@ -85,7 +86,7 @@ class AdminUserForm(PasswordAndKeyAuthForm): } -class SystemUserForm(PasswordAndKeyAuthForm): +class SystemUserForm(OrgModelForm, PasswordAndKeyAuthForm): # Admin user assets define, let user select, save it in form not in view auto_generate_key = forms.BooleanField(initial=True, required=False) @@ -136,11 +137,14 @@ class SystemUserForm(PasswordAndKeyAuthForm): fields = [ 'name', 'username', 'protocol', 'auto_generate_key', 'password', 'private_key_file', 'auto_push', 'sudo', - 'comment', 'shell', 'priority', 'login_mode', + 'comment', 'shell', 'priority', 'login_mode', 'cmd_filters', ] widgets = { 'name': forms.TextInput(attrs={'placeholder': _('Name')}), 'username': forms.TextInput(attrs={'placeholder': _('Username')}), + 'cmd_filters': forms.SelectMultiple(attrs={ + 'class': 'select2', 'data-placeholder': _('Command filter') + }), } help_texts = { 'name': '* required', diff --git a/apps/assets/models/__init__.py b/apps/assets/models/__init__.py index 35c275b99..4a3b67469 100644 --- a/apps/assets/models/__init__.py +++ b/apps/assets/models/__init__.py @@ -1,11 +1,12 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- # -from .user import AdminUser, SystemUser +from .user import * from .label import Label from .cluster import * from .group import * from .domain import * from .node import * from .asset import * +from .cmd_filter import * from .utils import * diff --git a/apps/assets/models/asset.py b/apps/assets/models/asset.py index b554c5c3a..55fb1723a 100644 --- a/apps/assets/models/asset.py +++ b/apps/assets/models/asset.py @@ -15,7 +15,7 @@ from django.core.cache import cache from ..const import ASSET_ADMIN_CONN_CACHE_KEY from .user import AdminUser, SystemUser -from orgs.mixins import OrgModelMixin,OrgManager +from orgs.mixins import OrgModelMixin, OrgManager __all__ = ['Asset'] logger = logging.getLogger(__name__) diff --git a/apps/assets/models/cmd_filter.py b/apps/assets/models/cmd_filter.py new file mode 100644 index 000000000..b06bed5c6 --- /dev/null +++ b/apps/assets/models/cmd_filter.py @@ -0,0 +1,57 @@ +# -*- coding: utf-8 -*- +# +import uuid + +from django.db import models +from django.core.validators import MinValueValidator, MaxValueValidator +from django.utils.translation import ugettext_lazy as _ + +from orgs.mixins import OrgModelMixin + + +__all__ = [ + 'CommandFilter', 'CommandFilterRule' +] + + +class CommandFilter(OrgModelMixin): + id = models.UUIDField(default=uuid.uuid4, primary_key=True) + name = models.CharField(max_length=64, verbose_name=_("Name")) + is_active = models.BooleanField(default=True, verbose_name=_('Is active')) + comment = models.TextField(blank=True, default='', verbose_name=_("Comment")) + date_created = models.DateTimeField(auto_now_add=True) + date_updated = models.DateTimeField(auto_now=True) + created_by = models.CharField(max_length=128, blank=True, default='', verbose_name=_('Created by')) + + def __str__(self): + return self.name + + +class CommandFilterRule(OrgModelMixin): + TYPE_REGEX = 'regex' + TYPE_COMMAND = 'command' + TYPE_CHOICES = ( + (TYPE_REGEX, _('Regex')), + (TYPE_COMMAND, _('Command')), + ) + + ACTION_DENY = 'deny' + ACTION_ACCEPT = 'accept' + ACTION_CHOICES = ( + (ACTION_DENY, _('Deny')), + (ACTION_ACCEPT, _('Accept')) + ) + + id = models.UUIDField(default=uuid.uuid4, primary_key=True) + filter = models.ForeignKey('CommandFilter', on_delete=models.CASCADE, verbose_name=_("Filter"), related_name='rules') + type = models.CharField(max_length=16, default=TYPE_COMMAND, choices=TYPE_CHOICES, verbose_name=_("Type")) + priority = models.IntegerField(default=50, verbose_name=_("Priority"), validators=[MinValueValidator(1), MaxValueValidator(100)]) + content = models.TextField(max_length=1024, verbose_name=_("Content"), help_text=_("One line one command")) + action = models.CharField(max_length=16, default=ACTION_DENY, choices=ACTION_CHOICES, verbose_name=_("Action")) + comment = models.CharField(max_length=64, blank=True, default='', verbose_name=_("Comment")) + date_created = models.DateTimeField(auto_now_add=True) + date_updated = models.DateTimeField(auto_now=True) + created_by = models.CharField(max_length=128, blank=True, default='', verbose_name=_('Created by')) + + def __str__(self): + return '{} % {}'.format(self.type, self.content) diff --git a/apps/assets/models/user.py b/apps/assets/models/user.py index 646b7204f..338f861ea 100644 --- a/apps/assets/models/user.py +++ b/apps/assets/models/user.py @@ -3,7 +3,6 @@ # import logging -import uuid from django.core.cache import cache from django.db import models @@ -118,6 +117,7 @@ class SystemUser(AssetUser): sudo = models.TextField(default='/bin/whoami', verbose_name=_('Sudo')) shell = models.CharField(max_length=64, default='/bin/bash', verbose_name=_('Shell')) login_mode = models.CharField(choices=LOGIN_MODE_CHOICES, default=AUTO_LOGIN, max_length=10, verbose_name=_('Login mode')) + cmd_filters = models.ManyToManyField('CommandFilter', related_name='system_users', verbose_name=_("Command filter")) cache_key = "__SYSTEM_USER_CACHED_{}" @@ -163,6 +163,14 @@ class SystemUser(AssetUser): def expire_cache(self): cache.delete(self.cache_key.format(self.id)) + @property + def cmd_filter_rules(self): + from .cmd_filter import CommandFilterRule + rules = CommandFilterRule.objects.filter( + filter__in=self.cmd_filters.all() + ).order_by('priority').distinct() + return rules + @classmethod def get_system_user_by_id_or_cached(cls, sid): cached = cache.get(cls.cache_key.format(sid)) diff --git a/apps/assets/serializers/__init__.py b/apps/assets/serializers/__init__.py index 111f070a7..ad4439be3 100644 --- a/apps/assets/serializers/__init__.py +++ b/apps/assets/serializers/__init__.py @@ -7,3 +7,4 @@ from .label import * from .system_user import * from .node import * from .domain import * +from .cmd_filter import * diff --git a/apps/assets/serializers/cmd_filter.py b/apps/assets/serializers/cmd_filter.py new file mode 100644 index 000000000..e49f89bcf --- /dev/null +++ b/apps/assets/serializers/cmd_filter.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +# +from rest_framework import serializers + +from common.fields import ChoiceDisplayField +from ..models import CommandFilter, CommandFilterRule, SystemUser + + +class CommandFilterSerializer(serializers.ModelSerializer): + rules = serializers.PrimaryKeyRelatedField(queryset=CommandFilterRule.objects.all(), many=True) + system_users = serializers.PrimaryKeyRelatedField(queryset=SystemUser.objects.all(), many=True) + + class Meta: + model = CommandFilter + fields = '__all__' + + +class CommandFilterRuleSerializer(serializers.ModelSerializer): + serializer_choice_field = ChoiceDisplayField + + class Meta: + model = CommandFilterRule + fields = '__all__' diff --git a/apps/assets/templates/assets/_system_user.html b/apps/assets/templates/assets/_system_user.html index 4e1bc51a8..a8606820d 100644 --- a/apps/assets/templates/assets/_system_user.html +++ b/apps/assets/templates/assets/_system_user.html @@ -62,6 +62,10 @@ {% endblock %} +
+

{% trans 'Command filter' %}

+ {% bootstrap_field form.cmd_filters layout="horizontal" %} +

{% trans 'Other' %}

{% bootstrap_field form.sudo layout="horizontal" %} {% bootstrap_field form.shell layout="horizontal" %} @@ -101,6 +105,7 @@ var need_change_field_login_mode = [ function protocolChange() { if ($(protocol_id + " option:selected").text() === 'rdp') { $('.auth-fields').removeClass('hidden'); + $('#command-filter-block').addClass('hidden'); $.each(need_change_field, function (index, value) { $(value).closest('.form-group').addClass('hidden') }); diff --git a/apps/assets/templates/assets/admin_user_detail.html b/apps/assets/templates/assets/admin_user_detail.html index 072eb556c..f00e2352a 100644 --- a/apps/assets/templates/assets/admin_user_detail.html +++ b/apps/assets/templates/assets/admin_user_detail.html @@ -90,7 +90,7 @@ diff --git a/apps/assets/templates/assets/cmd_filter_create_update.html b/apps/assets/templates/assets/cmd_filter_create_update.html new file mode 100644 index 000000000..b1f7a57a8 --- /dev/null +++ b/apps/assets/templates/assets/cmd_filter_create_update.html @@ -0,0 +1,20 @@ +{% extends '_base_create_update.html' %} +{% load static %} +{% load bootstrap3 %} +{% load i18n %} + +{% block form %} +
+ {% csrf_token %} + {% bootstrap_field form.name layout="horizontal" %} + {% bootstrap_field form.comment layout="horizontal" %} + +
+
+
+ + +
+
+
+{% endblock %} diff --git a/apps/assets/templates/assets/cmd_filter_detail.html b/apps/assets/templates/assets/cmd_filter_detail.html new file mode 100644 index 000000000..ee68ff2f6 --- /dev/null +++ b/apps/assets/templates/assets/cmd_filter_detail.html @@ -0,0 +1,168 @@ +{% extends 'base.html' %} +{% load static %} +{% load i18n %} + +{% block custom_head_css_js %} + + +{% endblock %} + +{% block content %} +
+
+
+
+ +
+
+
+
+ {{ object.name }} +
+ + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + +
{% trans 'Name' %}:{{ object.name }}
{% trans 'Comment' %}:{{ object.comment }}
{% trans 'Date created' %}:{{ object.date_created }}
{% trans 'Date updated' %}:{{ object.date_updated }}
{% trans 'Created by' %}:{{ object.created_by }}
+
+
+
+ +
+
+
+ {% trans 'System users' %} +
+
+ + + + + + + + + + + {% for system_user in object.system_users.all %} + + + + + {% endfor %} + +
+ +
+ +
{{ system_user }} + +
+
+
+
+
+
+
+
+
+{% endblock %} +{% block custom_foot_js %} + +{% endblock %} diff --git a/apps/assets/templates/assets/cmd_filter_list.html b/apps/assets/templates/assets/cmd_filter_list.html new file mode 100644 index 000000000..4bc33cf02 --- /dev/null +++ b/apps/assets/templates/assets/cmd_filter_list.html @@ -0,0 +1,79 @@ +{% extends '_base_list.html' %} +{% load i18n static %} +{% block table_search %}{% endblock %} +{% block table_container %} +
+ {% trans "Create command filter" %} +
+ + + + + + + + + + + + + +
+ + {% trans 'Name' %}{% trans 'Rules' %}{% trans 'System users' %}{% trans 'Comment' %}{% trans 'Action' %}
+{% endblock %} +{% block content_bottom_left %}{% endblock %} +{% block custom_foot_js %} + +{% endblock %} + + + diff --git a/apps/assets/templates/assets/cmd_filter_rule_create_update.html b/apps/assets/templates/assets/cmd_filter_rule_create_update.html new file mode 100644 index 000000000..bbb02f48c --- /dev/null +++ b/apps/assets/templates/assets/cmd_filter_rule_create_update.html @@ -0,0 +1,57 @@ +{% extends 'base.html' %} +{% load i18n %} +{% load static %} +{% load bootstrap3 %} +{% block custom_head_css_js %} + + +{% endblock %} + +{% block content %} +
+
+
+
+
+
{{ action }}
+ +
+
+
+ {% csrf_token %} + {% if form.non_field_errors %} +
+ {{ form.non_field_errors }} +
+ {% endif %} + {% bootstrap_form form layout="horizontal" %} +
+
+ + +
+
+
+
+
+
+
+
+{% endblock %} + +{% block custom_foot_js %} + +{% endblock %} \ No newline at end of file diff --git a/apps/assets/templates/assets/cmd_filter_rule_list.html b/apps/assets/templates/assets/cmd_filter_rule_list.html new file mode 100644 index 000000000..119b44fd4 --- /dev/null +++ b/apps/assets/templates/assets/cmd_filter_rule_list.html @@ -0,0 +1,115 @@ +{% extends 'base.html' %} +{% load static %} +{% load i18n %} + +{% block custom_head_css_js %} + + +{% endblock %} + +{% block content %} +
+
+
+
+ +
+
+
+
+
+
+ {% trans 'Command filter rule list' %} +
+ + + + + + + + + + +
+
+
+ + + + + + + + + + + + + + + +
+ + {% trans 'Type' %}{% trans 'Content' %}{% trans 'Priority' %}{% trans 'Strategy' %}{% trans 'Comment' %}{% trans 'Action' %}
+
+
+
+
+
+
+
+
+{% endblock %} +{% block content_bottom_left %}{% endblock %} +{% block custom_foot_js %} + +{% endblock %} diff --git a/apps/assets/templates/assets/system_user_detail.html b/apps/assets/templates/assets/system_user_detail.html index 5f16e3941..26e9bbef0 100644 --- a/apps/assets/templates/assets/system_user_detail.html +++ b/apps/assets/templates/assets/system_user_detail.html @@ -156,44 +156,47 @@ -{#
#} -{#
#} -{# {% trans 'Nodes' %}#} -{#
#} -{#
#} -{# #} -{# #} -{# #} -{# #} -{# #} -{# #} -{# #} -{# #} -{# #} -{# #} -{##} -{# {% for node in system_user.nodes.all %}#} -{# #} -{# #} -{# #} -{# #} -{# {% endfor %}#} -{# #} -{#
#} -{# #} -{#
#} -{# #} -{#
{{ node }}#} -{# #} -{#
#} -{#
#} -{#
#} + {% if system_user.protocol != 'rdp' %} +
+
+
+ {% trans 'Command filter' %} +
+
+ + + + + + + + + + + {% for cf in object.cmd_filters.all %} + + + + + {% endfor %} + +
+ +
+ +
{{ cf }} + +
+
+
+
+ {% endif %} @@ -201,27 +204,13 @@ {% endblock %} {% block custom_foot_js %} {% endblock %} diff --git a/apps/assets/urls/api_urls.py b/apps/assets/urls/api_urls.py index bdbbe5f1d..9c6865288 100644 --- a/apps/assets/urls/api_urls.py +++ b/apps/assets/urls/api_urls.py @@ -1,8 +1,11 @@ # coding:utf-8 from django.urls import path -from .. import api +from rest_framework_nested import routers +# from rest_framework.routers import DefaultRouter from rest_framework_bulk.routes import BulkRouter +from .. import api + app_name = 'assets' router = BulkRouter() @@ -13,6 +16,11 @@ router.register(r'labels', api.LabelViewSet, 'label') router.register(r'nodes', api.NodeViewSet, 'node') router.register(r'domain', api.DomainViewSet, 'domain') router.register(r'gateway', api.GatewayViewSet, 'gateway') +router.register(r'cmd-filter', api.CommandFilterViewSet, 'cmd-filter') + +cmd_filter_router = routers.NestedDefaultRouter(router, r'cmd-filter', lookup='filter') +cmd_filter_router.register(r'rules', api.CommandFilterRuleViewSet, 'cmd-filter-rule') + urlpatterns = [ path('assets-bulk/', api.AssetListUpdateApi.as_view(), name='asset-bulk-update'), @@ -42,6 +50,9 @@ urlpatterns = [ path('system-user//connective/', api.SystemUserTestConnectiveApi.as_view(), name='system-user-connective'), + path('system-user//cmd-filter-rules/', + api.SystemUserCommandFilterRuleListApi.as_view(), name='system-user-cmd-filter-rule-list'), + path('nodes//children/', api.NodeChildrenApi.as_view(), name='node-children'), path('nodes/children/', api.NodeChildrenApi.as_view(), name='node-children-2'), @@ -64,5 +75,5 @@ urlpatterns = [ api.GatewayTestConnectionApi.as_view(), name='test-gateway-connective'), ] -urlpatterns += router.urls +urlpatterns += router.urls + cmd_filter_router.urls diff --git a/apps/assets/urls/views_urls.py b/apps/assets/urls/views_urls.py index 9d160bedf..76651cfdb 100644 --- a/apps/assets/urls/views_urls.py +++ b/apps/assets/urls/views_urls.py @@ -49,4 +49,12 @@ urlpatterns = [ path('domain//gateway/create/', views.DomainGatewayCreateView.as_view(), name='domain-gateway-create'), path('domain/gateway//update/', views.DomainGatewayUpdateView.as_view(), name='domain-gateway-update'), + + path('cmd-filter/', views.CommandFilterListView.as_view(), name='cmd-filter-list'), + path('cmd-filter/create/', views.CommandFilterCreateView.as_view(), name='cmd-filter-create'), + path('cmd-filter//update/', views.CommandFilterUpdateView.as_view(), name='cmd-filter-update'), + path('cmd-filter//', views.CommandFilterDetailView.as_view(), name='cmd-filter-detail'), + path('cmd-filter//rule/', views.CommandFilterRuleListView.as_view(), name='cmd-filter-rule-list'), + path('cmd-filter//rule/create/', views.CommandFilterRuleCreateView.as_view(), name='cmd-filter-rule-create'), + path('cmd-filter//rule//update/', views.CommandFilterRuleUpdateView.as_view(), name='cmd-filter-rule-update'), ] diff --git a/apps/assets/views/__init__.py b/apps/assets/views/__init__.py index 5660d2738..04fc6c31c 100644 --- a/apps/assets/views/__init__.py +++ b/apps/assets/views/__init__.py @@ -4,3 +4,4 @@ from .system_user import * from .admin_user import * from .label import * from .domain import * +from .cmd_filter import * diff --git a/apps/assets/views/cmd_filter.py b/apps/assets/views/cmd_filter.py new file mode 100644 index 000000000..56c15885b --- /dev/null +++ b/apps/assets/views/cmd_filter.py @@ -0,0 +1,168 @@ +# -*- coding: utf-8 -*- +# + +from django.views.generic import TemplateView, CreateView, \ + UpdateView, DeleteView, DetailView +from django.views.generic.detail import SingleObjectMixin +from django.utils.translation import ugettext_lazy as _ +from django.urls import reverse_lazy +from django.shortcuts import get_object_or_404, reverse + +from common.permissions import AdminUserRequiredMixin +from common.const import create_success_msg, update_success_msg +from ..models import CommandFilter, CommandFilterRule, SystemUser +from ..forms import CommandFilterForm, CommandFilterRuleForm + + +__all__ = ( + "CommandFilterListView", "CommandFilterCreateView", + "CommandFilterUpdateView", + "CommandFilterRuleListView", "CommandFilterRuleCreateView", + "CommandFilterRuleUpdateView", "CommandFilterDetailView", +) + + +class CommandFilterListView(AdminUserRequiredMixin, TemplateView): + template_name = 'assets/cmd_filter_list.html' + + def get_context_data(self, **kwargs): + context = { + 'app': _('Assets'), + 'action': _('Command filter list'), + } + kwargs.update(context) + return super().get_context_data(**kwargs) + + +class CommandFilterCreateView(AdminUserRequiredMixin, CreateView): + model = CommandFilter + template_name = 'assets/cmd_filter_create_update.html' + form_class = CommandFilterForm + success_url = reverse_lazy('assets:cmd-filter-list') + success_message = create_success_msg + + def get_context_data(self, **kwargs): + context = { + 'app': _('Assets'), + 'action': _('Create command filter'), + } + kwargs.update(context) + return super().get_context_data(**kwargs) + + +class CommandFilterUpdateView(AdminUserRequiredMixin, UpdateView): + model = CommandFilter + template_name = 'assets/cmd_filter_create_update.html' + form_class = CommandFilterForm + success_url = reverse_lazy('assets:cmd-filter-list') + success_message = update_success_msg + + def get_context_data(self, **kwargs): + context = { + 'app': _('Assets'), + 'action': _('Update command filter'), + } + kwargs.update(context) + return super().get_context_data(**kwargs) + + +class CommandFilterDetailView(AdminUserRequiredMixin, DetailView): + model = CommandFilter + template_name = 'assets/cmd_filter_detail.html' + + def get_context_data(self, **kwargs): + system_users_remain = SystemUser.objects\ + .exclude(cmd_filters=self.object)\ + .exclude(protocol='rdp') + context = { + 'app': _('Assets'), + 'action': _('Command filter detail'), + 'system_users_remain': system_users_remain + } + kwargs.update(context) + return super().get_context_data(**kwargs) + + +class CommandFilterRuleListView(AdminUserRequiredMixin, SingleObjectMixin, TemplateView): + template_name = 'assets/cmd_filter_rule_list.html' + model = CommandFilter + object = None + + def get(self, request, *args, **kwargs): + self.object = self.get_object(queryset=self.model.objects.all()) + return super().get(request, *args, **kwargs) + + def get_context_data(self, **kwargs): + context = { + 'app': _('Assets'), + 'action': _('Command filter rule list'), + 'object': self.get_object() + } + kwargs.update(context) + return super().get_context_data(**kwargs) + + +class CommandFilterRuleCreateView(AdminUserRequiredMixin, CreateView): + template_name = 'assets/cmd_filter_rule_create_update.html' + model = CommandFilterRule + form_class = CommandFilterRuleForm + success_message = create_success_msg + cmd_filter = None + + def get_success_url(self): + return reverse('assets:cmd-filter-rule-list', kwargs={ + 'pk': self.cmd_filter.id + }) + + def get_form(self, form_class=None): + form = super().get_form(form_class=form_class) + form['filter'].initial = self.cmd_filter + form['filter'].field.widget.attrs['readonly'] = 1 + return form + + def dispatch(self, request, *args, **kwargs): + filter_pk = self.kwargs.get('filter_pk') + self.cmd_filter = get_object_or_404(CommandFilter, pk=filter_pk) + return super().dispatch(request, *args, **kwargs) + + def get_context_data(self, **kwargs): + context = { + 'app': _('Assets'), + 'action': _('Create command filter rule'), + 'object': self.cmd_filter, + } + kwargs.update(context) + return super().get_context_data(**kwargs) + + +class CommandFilterRuleUpdateView(AdminUserRequiredMixin, UpdateView): + template_name = 'assets/cmd_filter_rule_create_update.html' + model = CommandFilterRule + form_class = CommandFilterRuleForm + success_message = create_success_msg + cmd_filter = None + + def get_success_url(self): + return reverse('assets:cmd-filter-rule-list', kwargs={ + 'pk': self.cmd_filter.id + }) + + def get_form(self, form_class=None): + form = super().get_form(form_class=form_class) + form['filter'].initial = self.cmd_filter + form['filter'].field.widget.attrs['readonly'] = 1 + return form + + def dispatch(self, request, *args, **kwargs): + filter_pk = self.kwargs.get('filter_pk') + self.cmd_filter = get_object_or_404(CommandFilter, pk=filter_pk) + return super().dispatch(request, *args, **kwargs) + + def get_context_data(self, **kwargs): + context = { + 'app': _('Assets'), + 'action': _('Update command filter rule'), + 'object': self.cmd_filter, + } + kwargs.update(context) + return super().get_context_data(**kwargs) \ No newline at end of file diff --git a/apps/assets/views/system_user.py b/apps/assets/views/system_user.py index 7a8bc2bab..c8c6ea6be 100644 --- a/apps/assets/views/system_user.py +++ b/apps/assets/views/system_user.py @@ -9,7 +9,7 @@ from django.views.generic.detail import DetailView from common.const import create_success_msg, update_success_msg from ..forms import SystemUserForm -from ..models import SystemUser, Node +from ..models import SystemUser, Node, CommandFilter from common.permissions import AdminUserRequiredMixin @@ -73,7 +73,7 @@ class SystemUserDetailView(AdminUserRequiredMixin, DetailView): context = { 'app': _('Assets'), 'action': _('System user detail'), - 'nodes_remain': Node.objects.exclude(systemuser=self.object) + 'cmd_filters_remain': CommandFilter.objects.exclude(system_users=self.object) } kwargs.update(context) return super().get_context_data(**kwargs) diff --git a/apps/common/fields.py b/apps/common/fields.py index 8afcdf8d9..cccc265de 100644 --- a/apps/common/fields.py +++ b/apps/common/fields.py @@ -86,3 +86,21 @@ class FormEncryptCharField(FormEncryptMixin, forms.CharField): class FormEncryptDictField(FormEncryptMixin, FormDictField): pass + + +class ChoiceDisplayField(serializers.ChoiceField): + def __init__(self, *args, **kwargs): + super(ChoiceDisplayField, self).__init__(*args, **kwargs) + self.choice_strings_to_display = { + six.text_type(key): value for key, value in self.choices.items() + } + + def to_representation(self, value): + if value is None: + return value + return { + 'value': self.choice_strings_to_values.get(six.text_type(value), + value), + 'display': self.choice_strings_to_display.get(six.text_type(value), + value), + } diff --git a/apps/locale/zh/LC_MESSAGES/django.mo b/apps/locale/zh/LC_MESSAGES/django.mo index 5da9e7a3c..4dcc60c68 100644 Binary files a/apps/locale/zh/LC_MESSAGES/django.mo and b/apps/locale/zh/LC_MESSAGES/django.mo differ diff --git a/apps/locale/zh/LC_MESSAGES/django.po b/apps/locale/zh/LC_MESSAGES/django.po index 938b305e7..7bd6620c1 100644 --- a/apps/locale/zh/LC_MESSAGES/django.po +++ b/apps/locale/zh/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: Jumpserver 0.3.3\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-09-07 12:00+0800\n" +"POT-Creation-Date: 2018-10-10 15:11+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: ibuler \n" "Language-Team: Jumpserver team\n" @@ -33,7 +33,7 @@ msgstr "更新节点资产硬件信息: {}" msgid "Test if the assets under the node are connectable: {}" msgstr "测试节点下资产是否可连接: {}" -#: assets/forms/asset.py:27 assets/models/asset.py:82 assets/models/user.py:113 +#: assets/forms/asset.py:27 assets/models/asset.py:82 assets/models/user.py:112 #: assets/templates/assets/asset_detail.html:183 #: assets/templates/assets/asset_detail.html:191 #: assets/templates/assets/system_user_asset.html:94 perms/models.py:32 @@ -42,7 +42,7 @@ msgstr "节点管理" #: assets/forms/asset.py:30 assets/forms/asset.py:69 assets/forms/asset.py:112 #: assets/forms/asset.py:116 assets/models/asset.py:87 -#: assets/models/cluster.py:19 assets/models/user.py:73 +#: assets/models/cluster.py:19 assets/models/user.py:72 #: assets/templates/assets/asset_detail.html:73 templates/_nav.html:24 #: xpack/plugins/orgs/templates/orgs/org_list.html:18 msgid "Admin user" @@ -129,11 +129,14 @@ msgstr "资产" msgid "Password should not contain special characters" msgstr "不能包含特殊字符" -#: assets/forms/domain.py:59 assets/forms/user.py:79 assets/forms/user.py:142 +#: assets/forms/domain.py:59 assets/forms/user.py:80 assets/forms/user.py:143 #: assets/models/base.py:22 assets/models/cluster.py:18 -#: assets/models/domain.py:18 assets/models/group.py:20 -#: assets/models/label.py:18 assets/templates/assets/admin_user_detail.html:56 +#: assets/models/cmd_filter.py:19 assets/models/domain.py:18 +#: assets/models/group.py:20 assets/models/label.py:18 +#: assets/templates/assets/admin_user_detail.html:56 #: assets/templates/assets/admin_user_list.html:26 +#: assets/templates/assets/cmd_filter_detail.html:61 +#: assets/templates/assets/cmd_filter_list.html:14 #: assets/templates/assets/domain_detail.html:56 #: assets/templates/assets/domain_gateway_list.html:56 #: assets/templates/assets/domain_list.html:25 @@ -162,7 +165,7 @@ msgstr "不能包含特殊字符" msgid "Name" msgstr "名称" -#: assets/forms/domain.py:60 assets/forms/user.py:80 assets/forms/user.py:143 +#: assets/forms/domain.py:60 assets/forms/user.py:81 assets/forms/user.py:144 #: assets/models/base.py:23 assets/templates/assets/admin_user_detail.html:60 #: assets/templates/assets/admin_user_list.html:27 #: assets/templates/assets/domain_gateway_list.html:60 @@ -179,11 +182,11 @@ msgstr "名称" msgid "Username" msgstr "用户名" -#: assets/forms/user.py:24 +#: assets/forms/user.py:25 msgid "Password or private key passphrase" msgstr "密码或密钥密码" -#: assets/forms/user.py:25 assets/models/base.py:24 common/forms.py:104 +#: assets/forms/user.py:26 assets/models/base.py:24 common/forms.py:104 #: users/forms.py:17 users/forms.py:35 users/forms.py:47 #: users/templates/users/login.html:65 #: users/templates/users/reset_password.html:53 @@ -195,33 +198,39 @@ msgstr "密码或密钥密码" msgid "Password" msgstr "密码" -#: assets/forms/user.py:28 users/models/user.py:78 +#: assets/forms/user.py:29 users/models/user.py:78 msgid "Private key" msgstr "ssh私钥" -#: assets/forms/user.py:38 +#: assets/forms/user.py:39 msgid "Invalid private key" msgstr "ssh密钥不合法" -#: assets/forms/user.py:47 +#: assets/forms/user.py:48 msgid "Password and private key file must be input one" msgstr "密码和私钥, 必须输入一个" -#: assets/forms/user.py:128 +#: assets/forms/user.py:129 msgid "* Automatic login mode, must fill in the username." msgstr "自动登录模式,必须填写用户名" -#: assets/forms/user.py:148 +#: assets/forms/user.py:146 assets/models/user.py:120 +#: assets/templates/assets/_system_user.html:66 +#: assets/templates/assets/system_user_detail.html:165 +msgid "Command filter" +msgstr "命令过滤器" + +#: assets/forms/user.py:152 msgid "Auto push system user to asset" msgstr "自动推送系统用户到资产" -#: assets/forms/user.py:149 +#: assets/forms/user.py:153 msgid "" "High level will be using login asset as default, if user was granted more " "than 2 system user" msgstr "高优先级的系统用户将会作为默认登录用户" -#: assets/forms/user.py:151 +#: assets/forms/user.py:155 msgid "" "If you choose manual login mode, you do not need to fill in the username and " "password." @@ -257,7 +266,7 @@ msgid "Hostname" msgstr "主机名" #: assets/models/asset.py:74 assets/models/domain.py:49 -#: assets/models/user.py:116 +#: assets/models/user.py:115 #: assets/templates/assets/domain_gateway_list.html:59 #: assets/templates/assets/system_user_detail.html:70 #: assets/templates/assets/system_user_list.html:31 @@ -271,8 +280,9 @@ msgstr "协议" msgid "Platform" msgstr "系统平台" -#: assets/models/asset.py:83 assets/models/domain.py:52 -#: assets/models/label.py:21 assets/templates/assets/asset_detail.html:105 +#: assets/models/asset.py:83 assets/models/cmd_filter.py:20 +#: assets/models/domain.py:52 assets/models/label.py:21 +#: assets/templates/assets/asset_detail.html:105 #: assets/templates/assets/user_asset_list.html:169 msgid "Is active" msgstr "激活" @@ -349,9 +359,11 @@ msgid "Labels" msgstr "标签管理" #: assets/models/asset.py:126 assets/models/base.py:30 -#: assets/models/cluster.py:28 assets/models/group.py:21 +#: assets/models/cluster.py:28 assets/models/cmd_filter.py:24 +#: assets/models/cmd_filter.py:54 assets/models/group.py:21 #: assets/templates/assets/admin_user_detail.html:68 #: assets/templates/assets/asset_detail.html:117 +#: assets/templates/assets/cmd_filter_detail.html:77 #: assets/templates/assets/domain_detail.html:72 #: assets/templates/assets/system_user_detail.html:100 #: ops/templates/ops/adhoc_detail.html:86 orgs/models.py:15 perms/models.py:37 @@ -363,6 +375,7 @@ msgstr "创建者" #: assets/models/asset.py:129 assets/models/cluster.py:26 #: assets/models/domain.py:21 assets/models/group.py:22 #: assets/models/label.py:24 assets/templates/assets/admin_user_detail.html:64 +#: assets/templates/assets/cmd_filter_detail.html:69 #: assets/templates/assets/domain_detail.html:68 #: assets/templates/assets/system_user_detail.html:96 #: ops/templates/ops/adhoc_detail.html:90 ops/templates/ops/task_detail.html:63 @@ -375,11 +388,15 @@ msgid "Date created" msgstr "创建日期" #: assets/models/asset.py:131 assets/models/base.py:27 -#: assets/models/cluster.py:29 assets/models/domain.py:19 +#: assets/models/cluster.py:29 assets/models/cmd_filter.py:21 +#: assets/models/cmd_filter.py:51 assets/models/domain.py:19 #: assets/models/domain.py:51 assets/models/group.py:23 #: assets/models/label.py:22 assets/templates/assets/admin_user_detail.html:72 #: assets/templates/assets/admin_user_list.html:32 #: assets/templates/assets/asset_detail.html:125 +#: assets/templates/assets/cmd_filter_detail.html:65 +#: assets/templates/assets/cmd_filter_list.html:17 +#: assets/templates/assets/cmd_filter_rule_list.html:62 #: assets/templates/assets/domain_detail.html:76 #: assets/templates/assets/domain_gateway_list.html:61 #: assets/templates/assets/domain_list.html:28 @@ -466,6 +483,77 @@ msgstr "北京电信" msgid "BGP full netcom" msgstr "BGP全网通" +#: assets/models/cmd_filter.py:34 +msgid "Regex" +msgstr "正则表达式" + +#: assets/models/cmd_filter.py:35 terminal/models.py:139 +#: terminal/templates/terminal/command_list.html:55 +#: terminal/templates/terminal/command_list.html:71 +#: terminal/templates/terminal/session_detail.html:48 +#: terminal/templates/terminal/session_list.html:77 +msgid "Command" +msgstr "命令" + +#: assets/models/cmd_filter.py:41 +msgid "Deny" +msgstr "拒绝" + +#: assets/models/cmd_filter.py:42 +#: terminal/templates/terminal/terminal_list.html:76 +msgid "Accept" +msgstr "接受" + +#: assets/models/cmd_filter.py:46 +msgid "Filter" +msgstr "过滤器" + +#: assets/models/cmd_filter.py:47 +#: assets/templates/assets/cmd_filter_rule_list.html:58 +#: audits/templates/audits/login_log_list.html:50 +#: common/templates/common/terminal_setting.html:73 +#: common/templates/common/terminal_setting.html:91 +msgid "Type" +msgstr "类型" + +#: assets/models/cmd_filter.py:48 assets/models/user.py:114 +#: assets/templates/assets/cmd_filter_rule_list.html:60 +msgid "Priority" +msgstr "优先级" + +#: assets/models/cmd_filter.py:49 +#: assets/templates/assets/cmd_filter_rule_list.html:59 +msgid "Content" +msgstr "内容" + +#: assets/models/cmd_filter.py:49 +msgid "One line one command" +msgstr "每行一个命令" + +#: assets/models/cmd_filter.py:50 +#: assets/templates/assets/admin_user_list.html:33 +#: assets/templates/assets/asset_list.html:97 +#: assets/templates/assets/cmd_filter_list.html:18 +#: assets/templates/assets/cmd_filter_rule_list.html:63 +#: assets/templates/assets/domain_gateway_list.html:62 +#: assets/templates/assets/domain_list.html:29 +#: assets/templates/assets/label_list.html:17 +#: assets/templates/assets/system_user_asset.html:53 +#: assets/templates/assets/system_user_list.html:38 audits/models.py:37 +#: audits/templates/audits/operate_log_list.html:41 +#: audits/templates/audits/operate_log_list.html:67 +#: ops/templates/ops/adhoc_history.html:59 ops/templates/ops/task_adhoc.html:64 +#: ops/templates/ops/task_history.html:65 ops/templates/ops/task_list.html:42 +#: perms/templates/perms/asset_permission_list.html:60 +#: terminal/templates/terminal/session_list.html:81 +#: terminal/templates/terminal/terminal_list.html:36 +#: users/templates/users/user_group_list.html:15 +#: users/templates/users/user_list.html:29 +#: xpack/plugins/orgs/templates/orgs/org_list.html:23 +#: xpack/templates/orgs/org_list.html:15 +msgid "Action" +msgstr "动作" + #: assets/models/domain.py:59 assets/templates/assets/domain_detail.html:21 #: assets/templates/assets/domain_detail.html:64 #: assets/templates/assets/domain_gateway_list.html:21 @@ -520,15 +608,15 @@ msgstr "分类" msgid "Key" msgstr "" -#: assets/models/user.py:109 +#: assets/models/user.py:108 msgid "Automatic login" msgstr "自动登录" -#: assets/models/user.py:110 +#: assets/models/user.py:109 msgid "Manually login" msgstr "手动登录" -#: assets/models/user.py:114 +#: assets/models/user.py:113 #: assets/templates/assets/_asset_group_bulk_update_modal.html:11 #: assets/templates/assets/system_user_asset.html:21 #: assets/templates/assets/system_user_detail.html:22 @@ -536,41 +624,40 @@ msgstr "手动登录" #: assets/views/admin_user.py:63 assets/views/admin_user.py:78 #: assets/views/admin_user.py:102 assets/views/asset.py:53 #: assets/views/asset.py:92 assets/views/asset.py:136 assets/views/asset.py:153 -#: assets/views/asset.py:177 assets/views/domain.py:29 -#: assets/views/domain.py:45 assets/views/domain.py:61 -#: assets/views/domain.py:74 assets/views/domain.py:98 -#: assets/views/domain.py:126 assets/views/domain.py:145 -#: assets/views/label.py:26 assets/views/label.py:42 assets/views/label.py:58 -#: assets/views/system_user.py:28 assets/views/system_user.py:44 -#: assets/views/system_user.py:60 assets/views/system_user.py:74 -#: templates/_nav.html:19 +#: assets/views/asset.py:177 assets/views/cmd_filter.py:30 +#: assets/views/cmd_filter.py:46 assets/views/cmd_filter.py:62 +#: assets/views/cmd_filter.py:78 assets/views/cmd_filter.py:97 +#: assets/views/cmd_filter.py:130 assets/views/cmd_filter.py:163 +#: assets/views/domain.py:29 assets/views/domain.py:45 +#: assets/views/domain.py:61 assets/views/domain.py:74 +#: assets/views/domain.py:98 assets/views/domain.py:126 +#: assets/views/domain.py:145 assets/views/label.py:26 assets/views/label.py:42 +#: assets/views/label.py:58 assets/views/system_user.py:28 +#: assets/views/system_user.py:44 assets/views/system_user.py:60 +#: assets/views/system_user.py:74 templates/_nav.html:19 msgid "Assets" msgstr "资产管理" -#: assets/models/user.py:115 -msgid "Priority" -msgstr "优先级" - -#: assets/models/user.py:117 assets/templates/assets/_system_user.html:59 +#: assets/models/user.py:116 assets/templates/assets/_system_user.html:59 #: assets/templates/assets/system_user_detail.html:122 #: assets/templates/assets/system_user_update.html:10 msgid "Auto push" msgstr "自动推送" -#: assets/models/user.py:118 assets/templates/assets/system_user_detail.html:74 +#: assets/models/user.py:117 assets/templates/assets/system_user_detail.html:74 msgid "Sudo" msgstr "Sudo" -#: assets/models/user.py:119 assets/templates/assets/system_user_detail.html:79 +#: assets/models/user.py:118 assets/templates/assets/system_user_detail.html:79 msgid "Shell" msgstr "Shell" -#: assets/models/user.py:120 assets/templates/assets/system_user_detail.html:66 +#: assets/models/user.py:119 assets/templates/assets/system_user_detail.html:66 #: assets/templates/assets/system_user_list.html:32 msgid "Login mode" msgstr "登录模式" -#: assets/models/user.py:181 assets/templates/assets/user_asset_list.html:167 +#: assets/models/user.py:189 assets/templates/assets/user_asset_list.html:167 #: audits/models.py:19 audits/templates/audits/ftp_log_list.html:49 #: audits/templates/audits/ftp_log_list.html:72 perms/forms.py:40 #: perms/models.py:33 perms/models.py:81 @@ -648,6 +735,8 @@ msgid "Select Asset" msgstr "选择资产" #: assets/templates/assets/_asset_group_bulk_update_modal.html:21 +#: assets/templates/assets/cmd_filter_detail.html:89 +#: assets/templates/assets/cmd_filter_list.html:16 #: assets/templates/assets/user_asset_list.html:48 #: users/templates/users/user_granted_asset.html:47 msgid "System users" @@ -708,7 +797,7 @@ msgstr "认证" msgid "Auto generate key" msgstr "自动生成密钥" -#: assets/templates/assets/_system_user.html:65 +#: assets/templates/assets/_system_user.html:69 #: assets/templates/assets/asset_create.html:60 #: assets/templates/assets/asset_update.html:64 #: assets/templates/assets/gateway_create_update.html:53 @@ -717,11 +806,13 @@ msgstr "自动生成密钥" msgid "Other" msgstr "其它" -#: assets/templates/assets/_system_user.html:71 +#: assets/templates/assets/_system_user.html:75 #: assets/templates/assets/admin_user_create_update.html:45 #: assets/templates/assets/asset_bulk_update.html:23 #: assets/templates/assets/asset_create.html:67 #: assets/templates/assets/asset_update.html:71 +#: assets/templates/assets/cmd_filter_create_update.html:15 +#: assets/templates/assets/cmd_filter_rule_create_update.html:40 #: assets/templates/assets/domain_create_update.html:16 #: assets/templates/assets/gateway_create_update.html:58 #: assets/templates/assets/label_create_update.html:18 @@ -743,12 +834,14 @@ msgstr "其它" msgid "Reset" msgstr "重置" -#: assets/templates/assets/_system_user.html:72 +#: assets/templates/assets/_system_user.html:76 #: assets/templates/assets/admin_user_create_update.html:46 #: assets/templates/assets/asset_bulk_update.html:24 #: assets/templates/assets/asset_create.html:68 #: assets/templates/assets/asset_list.html:114 #: assets/templates/assets/asset_update.html:72 +#: assets/templates/assets/cmd_filter_create_update.html:16 +#: assets/templates/assets/cmd_filter_rule_create_update.html:41 #: assets/templates/assets/domain_create_update.html:17 #: assets/templates/assets/gateway_create_update.html:59 #: assets/templates/assets/label_create_update.html:19 @@ -783,6 +876,8 @@ msgstr "关闭" #: assets/templates/assets/admin_user_assets.html:18 #: assets/templates/assets/admin_user_detail.html:18 +#: assets/templates/assets/cmd_filter_detail.html:19 +#: assets/templates/assets/cmd_filter_rule_list.html:19 #: assets/templates/assets/domain_detail.html:18 #: assets/templates/assets/domain_gateway_list.html:18 #: assets/templates/assets/system_user_asset.html:17 @@ -838,6 +933,9 @@ msgstr "测试" #: assets/templates/assets/admin_user_list.html:88 #: assets/templates/assets/asset_detail.html:24 #: assets/templates/assets/asset_list.html:171 +#: assets/templates/assets/cmd_filter_detail.html:29 +#: assets/templates/assets/cmd_filter_list.html:47 +#: assets/templates/assets/cmd_filter_rule_list.html:86 #: assets/templates/assets/domain_detail.html:24 #: assets/templates/assets/domain_detail.html:103 #: assets/templates/assets/domain_gateway_list.html:85 @@ -866,6 +964,9 @@ msgstr "更新" #: assets/templates/assets/admin_user_list.html:89 #: assets/templates/assets/asset_detail.html:28 #: assets/templates/assets/asset_list.html:172 +#: assets/templates/assets/cmd_filter_detail.html:33 +#: assets/templates/assets/cmd_filter_list.html:48 +#: assets/templates/assets/cmd_filter_rule_list.html:87 #: assets/templates/assets/domain_detail.html:28 #: assets/templates/assets/domain_detail.html:104 #: assets/templates/assets/domain_gateway_list.html:86 @@ -900,8 +1001,9 @@ msgstr "选择节点" #: assets/templates/assets/admin_user_detail.html:100 #: assets/templates/assets/asset_detail.html:200 #: assets/templates/assets/asset_list.html:633 +#: assets/templates/assets/cmd_filter_detail.html:106 #: assets/templates/assets/system_user_asset.html:111 -#: assets/templates/assets/system_user_detail.html:330 +#: assets/templates/assets/system_user_detail.html:182 #: assets/templates/assets/system_user_list.html:143 templates/_modal.html:22 #: terminal/templates/terminal/session_detail.html:108 #: users/templates/users/user_detail.html:382 @@ -951,27 +1053,6 @@ msgstr "不可达" msgid "Ratio" msgstr "比例" -#: assets/templates/assets/admin_user_list.html:33 -#: assets/templates/assets/asset_list.html:97 -#: assets/templates/assets/domain_gateway_list.html:62 -#: assets/templates/assets/domain_list.html:29 -#: assets/templates/assets/label_list.html:17 -#: assets/templates/assets/system_user_asset.html:53 -#: assets/templates/assets/system_user_list.html:38 audits/models.py:37 -#: audits/templates/audits/operate_log_list.html:41 -#: audits/templates/audits/operate_log_list.html:67 -#: ops/templates/ops/adhoc_history.html:59 ops/templates/ops/task_adhoc.html:64 -#: ops/templates/ops/task_history.html:65 ops/templates/ops/task_list.html:42 -#: perms/templates/perms/asset_permission_list.html:60 -#: terminal/templates/terminal/session_list.html:81 -#: terminal/templates/terminal/terminal_list.html:36 -#: users/templates/users/user_group_list.html:15 -#: users/templates/users/user_list.html:29 -#: xpack/plugins/orgs/templates/orgs/org_list.html:23 -#: xpack/templates/orgs/org_list.html:15 -msgid "Action" -msgstr "动作" - #: assets/templates/assets/asset_bulk_update.html:8 #: users/templates/users/user_bulk_update.html:8 msgid "Select properties that need to be modified" @@ -1157,7 +1238,6 @@ msgid "This will delete the selected assets !!!" msgstr "删除选择资产" #: assets/templates/assets/asset_list.html:631 -#: assets/templates/assets/system_user_detail.html:328 #: assets/templates/assets/system_user_list.html:141 #: users/templates/users/user_detail.html:380 #: users/templates/users/user_detail.html:406 @@ -1186,6 +1266,37 @@ msgstr "删除失败" msgid "Configuration" msgstr "配置" +#: assets/templates/assets/cmd_filter_detail.html:25 +#: assets/templates/assets/cmd_filter_list.html:15 +#: assets/templates/assets/cmd_filter_rule_list.html:23 +msgid "Rules" +msgstr "规则" + +#: assets/templates/assets/cmd_filter_detail.html:73 +msgid "Date updated" +msgstr "更新日期" + +#: assets/templates/assets/cmd_filter_detail.html:97 +msgid "Binding to system user" +msgstr "绑定到系统用户" + +#: assets/templates/assets/cmd_filter_list.html:6 assets/views/cmd_filter.py:47 +msgid "Create command filter" +msgstr "创建命令过滤器" + +#: assets/templates/assets/cmd_filter_rule_list.html:33 +#: assets/views/cmd_filter.py:98 +msgid "Command filter rule list" +msgstr "命令过滤器列表" + +#: assets/templates/assets/cmd_filter_rule_list.html:50 +msgid "Create rule" +msgstr "创建规则" + +#: assets/templates/assets/cmd_filter_rule_list.html:61 +msgid "Strategy" +msgstr "分类" + #: assets/templates/assets/delete_confirm.html:6 #: perms/templates/perms/delete_confirm.html:6 templates/delete_confirm.html:6 msgid "Confirm delete" @@ -1273,17 +1384,9 @@ msgstr "家目录" msgid "Uid" msgstr "Uid" -#: assets/templates/assets/system_user_detail.html:324 -msgid "Are you sure to remove authentication information for the system user ?" -msgstr "你确定清除该系统用户的认证信息吗 ?" - -#: assets/templates/assets/system_user_detail.html:336 -msgid "Clear auth" -msgstr "清除认证信息" - -#: assets/templates/assets/system_user_detail.html:336 -msgid "success" -msgstr "成功" +#: assets/templates/assets/system_user_detail.html:173 +msgid "Binding command filters" +msgstr "绑定命令过滤器" #: assets/templates/assets/system_user_list.html:10 msgid "" @@ -1369,6 +1472,26 @@ msgstr "更新资产" msgid "already exists" msgstr "已经存在" +#: assets/views/cmd_filter.py:31 +msgid "Command filter list" +msgstr "命令过滤器列表" + +#: assets/views/cmd_filter.py:63 +msgid "Update command filter" +msgstr "更新命令过滤器" + +#: assets/views/cmd_filter.py:79 +msgid "Command filter detail" +msgstr "命令过滤器详情" + +#: assets/views/cmd_filter.py:131 +msgid "Create command filter rule" +msgstr "创建命令过滤器规则" + +#: assets/views/cmd_filter.py:164 +msgid "Update command filter rule" +msgstr "更新命令过滤器规则" + #: assets/views/domain.py:30 templates/_nav.html:23 msgid "Domain list" msgstr "网域列表" @@ -1491,12 +1614,6 @@ msgstr "搜索" msgid "ID" msgstr "ID" -#: audits/templates/audits/login_log_list.html:50 -#: common/templates/common/terminal_setting.html:73 -#: common/templates/common/terminal_setting.html:91 -msgid "Type" -msgstr "类型" - #: audits/templates/audits/login_log_list.html:51 msgid "UA" msgstr "Agent" @@ -1535,19 +1652,19 @@ msgid "Datetime" msgstr "日期" #: audits/views.py:66 audits/views.py:110 audits/views.py:143 -#: templates/_nav.html:67 +#: templates/_nav.html:73 msgid "Audits" msgstr "日志审计" -#: audits/views.py:67 templates/_nav.html:71 +#: audits/views.py:67 templates/_nav.html:77 msgid "FTP log" msgstr "FTP日志" -#: audits/views.py:111 templates/_nav.html:72 +#: audits/views.py:111 templates/_nav.html:78 msgid "Operate log" msgstr "操作日志" -#: audits/views.py:144 templates/_nav.html:73 +#: audits/views.py:144 templates/_nav.html:79 msgid "Password change log" msgstr "改密日志" @@ -1559,7 +1676,7 @@ msgstr "改密日志" msgid "Users" msgstr "用户管理" -#: audits/views.py:184 templates/_nav.html:70 +#: audits/views.py:184 templates/_nav.html:76 msgid "Login log" msgstr "登录日志" @@ -1881,7 +1998,7 @@ msgid "Special char not allowed" msgstr "不能包含特殊字符" #: common/views.py:19 common/views.py:45 common/views.py:71 common/views.py:101 -#: common/views.py:129 templates/_nav.html:100 +#: common/views.py:129 templates/_nav.html:106 msgid "Settings" msgstr "系统设置" @@ -1890,7 +2007,7 @@ msgstr "系统设置" msgid "Update setting successfully, please restart program" msgstr "更新设置成功, 请手动重启程序" -#: jumpserver/views.py:178 +#: jumpserver/views.py:180 msgid "" "
Luna is a separately deployed program, you need to deploy Luna, coco, " "configure nginx for url distribution,
If you see this page, " @@ -1927,7 +2044,7 @@ msgstr "任务" #: ops/models/adhoc.py:157 ops/templates/ops/adhoc_detail.html:57 #: ops/templates/ops/task_adhoc.html:60 msgid "Pattern" -msgstr "" +msgstr "模式" #: ops/models/adhoc.py:158 ops/templates/ops/adhoc_detail.html:61 msgid "Options" @@ -2136,7 +2253,7 @@ msgstr "任务开始: " msgid "Ops" msgstr "作业中心" -#: ops/views.py:37 templates/_nav.html:61 +#: ops/views.py:37 templates/_nav.html:67 msgid "Task list" msgstr "任务列表" @@ -2174,7 +2291,7 @@ msgstr "资产和节点至少选一个" msgid "Date expired" msgstr "失效日期" -#: perms/models.py:45 perms/models.py:92 templates/_nav.html:33 +#: perms/models.py:45 perms/models.py:92 templates/_nav.html:34 msgid "Asset permission" msgstr "资产授权" @@ -2262,7 +2379,7 @@ msgid "Select user groups" msgstr "选择用户组" #: perms/views.py:23 perms/views.py:53 perms/views.py:68 perms/views.py:83 -#: perms/views.py:118 perms/views.py:150 templates/_nav.html:30 +#: perms/views.py:118 perms/views.py:150 templates/_nav.html:31 #: xpack/plugins/orgs/templates/orgs/org_list.html:21 msgid "Perms" msgstr "权限管理" @@ -2365,38 +2482,46 @@ msgstr "" msgid "User list" msgstr "用户列表" -#: templates/_nav.html:39 +#: templates/_nav.html:27 +msgid "Command filters" +msgstr "命令过滤" + +#: templates/_nav.html:40 msgid "Sessions" msgstr "会话管理" -#: templates/_nav.html:42 +#: templates/_nav.html:43 msgid "Session online" msgstr "在线会话" -#: templates/_nav.html:43 +#: templates/_nav.html:44 msgid "Session offline" msgstr "历史会话" -#: templates/_nav.html:44 +#: templates/_nav.html:45 msgid "Commands" msgstr "命令记录" -#: templates/_nav.html:47 templates/_nav_user.html:14 +#: templates/_nav.html:48 templates/_nav_user.html:14 msgid "Web terminal" msgstr "Web终端" -#: templates/_nav.html:51 terminal/views/command.py:50 +#: templates/_nav.html:53 +msgid "File manager" +msgstr "文件管理" + +#: templates/_nav.html:57 terminal/views/command.py:50 #: terminal/views/session.py:75 terminal/views/session.py:93 #: terminal/views/session.py:115 terminal/views/terminal.py:31 #: terminal/views/terminal.py:46 terminal/views/terminal.py:58 msgid "Terminal" msgstr "终端管理" -#: templates/_nav.html:58 +#: templates/_nav.html:64 msgid "Job Center" msgstr "作业中心" -#: templates/_nav.html:88 +#: templates/_nav.html:94 msgid "XPack" msgstr "" @@ -2638,13 +2763,6 @@ msgstr "运行时间" msgid "Replay" msgstr "回放" -#: terminal/models.py:139 terminal/templates/terminal/command_list.html:55 -#: terminal/templates/terminal/command_list.html:71 -#: terminal/templates/terminal/session_detail.html:48 -#: terminal/templates/terminal/session_list.html:77 -msgid "Command" -msgstr "命令" - #: terminal/models.py:142 msgid "Date last active" msgstr "最后活跃日期" @@ -2726,10 +2844,8 @@ msgid "Terminate task send, waiting ..." msgstr "终断任务已发送,请等待" #: terminal/templates/terminal/session_list.html:156 -#, fuzzy -#| msgid "MFA enable success" msgid "Finish session success" -msgstr "MFA 绑定成功" +msgstr "标记会话完成成功" #: terminal/templates/terminal/terminal_detail.html:13 #: terminal/views/terminal.py:59 @@ -2752,10 +2868,6 @@ msgstr "地址" msgid "Alive" msgstr "在线" -#: terminal/templates/terminal/terminal_list.html:76 -msgid "Accept" -msgstr "接受" - #: terminal/templates/terminal/terminal_list.html:78 msgid "Reject" msgstr "拒绝" @@ -2784,36 +2896,36 @@ msgstr "终端列表" msgid "Update terminal" msgstr "更新终端" -#: terminal/views/terminal.py:102 terminal/views/terminal.py:103 +#: terminal/views/terminal.py:105 terminal/views/terminal.py:106 msgid "Redirect to web terminal" msgstr "重定向到web terminal" -#: terminal/views/terminal.py:110 +#: terminal/views/terminal.py:113 msgid "Connect ssh terminal" msgstr "连接ssh终端" -#: terminal/views/terminal.py:111 +#: terminal/views/terminal.py:114 msgid "" "You should use your ssh client tools connect terminal: {}

{}" msgstr "你可以使用ssh客户端工具连接终端" -#: users/api/auth.py:38 users/templates/users/login.html:52 +#: users/api/auth.py:40 users/templates/users/login.html:52 msgid "Log in frequently and try again later" msgstr "登录频繁, 稍后重试" -#: users/api/auth.py:77 +#: users/api/auth.py:79 msgid "Please carry seed value and conduct MFA secondary certification" msgstr "请携带seed值, 进行MFA二次认证" -#: users/api/auth.py:190 +#: users/api/auth.py:192 msgid "Please verify the user name and password first" msgstr "请先进行用户名和密码验证" -#: users/api/auth.py:202 +#: users/api/auth.py:204 msgid "MFA certification failed" msgstr "MFA认证失败" -#: users/api/user.py:134 +#: users/api/user.py:135 msgid "Could not reset self otp, use profile reset instead" msgstr "不能再该页面重置MFA, 请去个人信息页面重置" @@ -3133,7 +3245,7 @@ msgstr "上一步" #: users/templates/users/first_login.html:105 #: users/templates/users/login_otp.html:67 #: users/templates/users/user_otp_authentication.html:26 -#: users/templates/users/user_otp_enable_bind.html:23 +#: users/templates/users/user_otp_enable_bind.html:29 #: users/templates/users/user_otp_enable_install_app.html:26 #: users/templates/users/user_password_authentication.html:21 msgid "Next" @@ -3222,7 +3334,7 @@ msgstr "请打开手机Google Authenticator应用,输入6位动态码" #: users/templates/users/login_otp.html:65 #: users/templates/users/user_otp_authentication.html:23 -#: users/templates/users/user_otp_enable_bind.html:20 +#: users/templates/users/user_otp_enable_bind.html:26 msgid "Six figures" msgstr "6位数字" @@ -3496,7 +3608,7 @@ msgstr "解绑 MFA" msgid "Bind" msgstr "绑定 MFA" -#: users/templates/users/user_otp_enable_bind.html:12 +#: users/templates/users/user_otp_enable_bind.html:14 msgid "" "Use the mobile Google Authenticator application to scan the following qr " "code for a 6-bit verification code" @@ -3737,7 +3849,7 @@ msgstr "用户组授权资产" msgid "Please enable cookies and try again." msgstr "设置你的浏览器支持cookie" -#: users/views/login.py:175 users/views/user.py:524 users/views/user.py:549 +#: users/views/login.py:175 users/views/user.py:526 users/views/user.py:551 msgid "MFA code invalid, or ntp sync server time" msgstr "MFA验证码不正确,或者服务器端时间不对" @@ -3818,19 +3930,19 @@ msgstr "密钥更新" msgid "Password invalid" msgstr "用户名或密码无效" -#: users/views/user.py:579 +#: users/views/user.py:581 msgid "MFA enable success" msgstr "MFA 绑定成功" -#: users/views/user.py:580 +#: users/views/user.py:582 msgid "MFA enable success, return login page" msgstr "MFA 绑定成功,返回到登录页面" -#: users/views/user.py:582 +#: users/views/user.py:584 msgid "MFA disable success" msgstr "MFA 解绑成功" -#: users/views/user.py:583 +#: users/views/user.py:585 msgid "MFA disable success, return login page" msgstr "MFA 解绑成功,返回登录页面" @@ -3882,6 +3994,16 @@ msgstr "创建组织" msgid "Update org" msgstr "更新组织" +#~ msgid "" +#~ "Are you sure to remove authentication information for the system user ?" +#~ msgstr "你确定清除该系统用户的认证信息吗 ?" + +#~ msgid "Clear auth" +#~ msgstr "清除认证信息" + +#~ msgid "success" +#~ msgstr "成功" + #~ msgid "Task has been send, Go to ops task list seen result" #~ msgstr "任务已下发,查看ops任务列表" diff --git a/apps/orgs/views.py b/apps/orgs/views.py index 374f34812..5a363df0a 100644 --- a/apps/orgs/views.py +++ b/apps/orgs/views.py @@ -14,7 +14,8 @@ class SwitchOrgView(DetailView): pk = kwargs.get('pk') self.object = Organization.get_instance(pk) request.session['oid'] = self.object.id.__str__() - return redirect('index') + referer = request.META.get('HTTP_REFERER', reverse('index')) + return redirect(referer) class SwitchToAOrgView(View): diff --git a/apps/templates/_nav.html b/apps/templates/_nav.html index b85e9aebe..5014068dc 100644 --- a/apps/templates/_nav.html +++ b/apps/templates/_nav.html @@ -24,6 +24,7 @@
  • {% trans 'Admin user' %}
  • {% trans 'System user' %}
  • {% trans 'Labels' %}
  • +
  • {% trans 'Command filters' %}
  • @@ -47,6 +48,11 @@ {% trans 'Web terminal' %}
  • +
  • + + {% trans 'File manager' %} + +
  • {% if request.user.is_superuser %}
  • {% trans 'Terminal' %}
  • {% endif %} diff --git a/apps/terminal/urls/views_urls.py b/apps/terminal/urls/views_urls.py index a98a63294..3e144da85 100644 --- a/apps/terminal/urls/views_urls.py +++ b/apps/terminal/urls/views_urls.py @@ -16,6 +16,7 @@ urlpatterns = [ path('terminal//update/', views.TerminalUpdateView.as_view(), name='terminal-update'), path('/accept/', views.TerminalAcceptView.as_view(), name='terminal-accept'), path('web-terminal/', views.WebTerminalView.as_view(), name='web-terminal'), + path('web-sftp/', views.WebSFTPView.as_view(), name='web-sftp'), # Session view path('session-online/', views.SessionOnlineListView.as_view(), name='session-online-list'), diff --git a/apps/terminal/views/terminal.py b/apps/terminal/views/terminal.py index 1adf09513..210bec136 100644 --- a/apps/terminal/views/terminal.py +++ b/apps/terminal/views/terminal.py @@ -16,7 +16,7 @@ from common.permissions import SuperUserRequiredMixin __all__ = [ "TerminalListView", "TerminalUpdateView", "TerminalDetailView", "TerminalDeleteView", "TerminalConnectView", "TerminalAcceptView", - "WebTerminalView", + "WebTerminalView", 'WebSFTPView', ] @@ -124,3 +124,8 @@ class TerminalConnectView(LoginRequiredMixin, SuperUserRequiredMixin, DetailView class WebTerminalView(LoginRequiredMixin, View): def get(self, request, *args, **kwargs): return redirect('/luna/?' + request.GET.urlencode()) + + +class WebSFTPView(LoginRequiredMixin, View): + def get(self, request, *args, **kwargs): + return redirect('/coco/elfinder/sftp/?' + request.GET.urlencode()) diff --git a/requirements/requirements.txt b/requirements/requirements.txt index 7bd31d93e..d1aaf3b1a 100644 --- a/requirements/requirements.txt +++ b/requirements/requirements.txt @@ -71,3 +71,4 @@ urllib3==1.22 vine==1.1.4 drf-yasg==1.9.1 Werkzeug==0.14.1 +drf-nested-routers==0.90.2