diff --git a/apps/assets/forms/asset.py b/apps/assets/forms/asset.py index 62f9748be..d83172373 100644 --- a/apps/assets/forms/asset.py +++ b/apps/assets/forms/asset.py @@ -14,6 +14,10 @@ __all__ = [ 'AssetCreateForm', 'AssetUpdateForm', 'AssetBulkUpdateForm', 'ProtocolForm', ] +HELP_TEXTS_ASSET_HOSTNAME = _( + 'Only Numbers、letters、 chinese and characters ( {} ) are allowed' +).format(" ".join(['.', '_', '@'])) + class ProtocolForm(forms.Form): name = forms.ChoiceField( @@ -68,8 +72,7 @@ class AssetCreateForm(OrgModelForm): 'nodes': _("Node"), } help_texts = { - 'hostname': _('Only Numbers, letters, and characters ( {} ) ' - 'are allowed').format(" ".join(['.', '_', '@'])), + 'hostname': HELP_TEXTS_ASSET_HOSTNAME, 'admin_user': _( 'root or other NOPASSWD sudo privilege user existed in asset,' 'If asset is windows or other set any one, more see admin user left menu' @@ -116,8 +119,7 @@ class AssetUpdateForm(OrgModelForm): 'nodes': _("Node"), } help_texts = { - 'hostname': _('Only Numbers, letters, and characters ( {} ) ' - 'are allowed').format(" ".join(['.', '_', '@'])), + 'hostname': HELP_TEXTS_ASSET_HOSTNAME, 'admin_user': _( 'root or other NOPASSWD sudo privilege user existed in asset,' 'If asset is windows or other set any one, more see admin user left menu' diff --git a/apps/assets/models/node.py b/apps/assets/models/node.py index 46e06c63e..d1628be76 100644 --- a/apps/assets/models/node.py +++ b/apps/assets/models/node.py @@ -257,10 +257,6 @@ class NodeAssetsMixin: @lazyproperty def assets_amount(self): - """ - 获取节点下所有资产数量速度太慢,所以需要重写,使用cache等方案 - :return: - """ amount = self.tree().assets_amount(self.key) return amount diff --git a/apps/assets/serializers/asset.py b/apps/assets/serializers/asset.py index f9f099ba8..c53b3057d 100644 --- a/apps/assets/serializers/asset.py +++ b/apps/assets/serializers/asset.py @@ -94,7 +94,7 @@ class AssetSerializer(BulkOrgResourceModelSerializer): @staticmethod def validate_hostname(hostname): - pattern = r"^[\._@a-zA-Z0-9-]+$" + pattern = r"^[\._@\w-]+$" res = re.match(pattern, hostname) if res is None: msg = _("* The hostname contains characters that are not allowed") diff --git a/apps/assets/utils.py b/apps/assets/utils.py index 6e5952ff8..305bcbf36 100644 --- a/apps/assets/utils.py +++ b/apps/assets/utils.py @@ -26,10 +26,6 @@ def get_system_user_by_id(id): class TreeService(Tree): tag_sep = ' / ' - cache_key = '_NODE_FULL_TREE' - cache_time = 3600 - has_empty_node = False - has_ungrouped_node = False def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) @@ -43,13 +39,17 @@ class TreeService(Tree): from orgs.utils import tmp_to_root_org with tmp_to_root_org(): - all_nodes = Node.objects.all() + all_nodes = list(Node.objects.all().values("key", "value")) + all_nodes.sort(key=lambda x: len(x["key"].split(":"))) tree = cls() tree.create_node(tag='', identifier='') for node in all_nodes: + key = node["key"] + value = node["value"] + parent_key = ":".join(key.split(":")[:-1]) tree.create_node( - tag=node.value, identifier=node.key, - parent=node.parent_key, + tag=value, identifier=key, + parent=parent_key, ) tree.init_assets() return tree diff --git a/apps/audits/serializers.py b/apps/audits/serializers.py index 70b69b880..7dcd94d73 100644 --- a/apps/audits/serializers.py +++ b/apps/audits/serializers.py @@ -36,3 +36,4 @@ class SessionAuditSerializer(serializers.ModelSerializer): class Meta: model = Session fields = '__all__' + diff --git a/apps/audits/signals_handler.py b/apps/audits/signals_handler.py index cb87e2b9e..0f201b464 100644 --- a/apps/audits/signals_handler.py +++ b/apps/audits/signals_handler.py @@ -9,7 +9,8 @@ from rest_framework.renderers import JSONRenderer from jumpserver.utils import current_request from common.utils import get_request_ip, get_logger, get_syslogger from users.models import User -from terminal.models import Session +from terminal.models import Session, Command +from terminal.backends.command.serializers import SessionCommandSerializer from . import models from . import serializers @@ -88,6 +89,9 @@ def on_audits_log_create(sender, instance=None, **kwargs): elif sender == Session: category = "host_session_log" serializer = serializers.SessionAuditSerializer + elif sender == Command: + category = "session_command_log" + serializer = SessionCommandSerializer else: return diff --git a/apps/common/utils/common.py b/apps/common/utils/common.py index 667f166b3..f17125435 100644 --- a/apps/common/utils/common.py +++ b/apps/common/utils/common.py @@ -225,4 +225,4 @@ class lazyproperty: else: value = self.func(instance) setattr(instance, self.func.__name__, value) - return value \ No newline at end of file + return value diff --git a/apps/jumpserver/settings.py b/apps/jumpserver/settings.py index dd3fb170f..d726b4bcb 100644 --- a/apps/jumpserver/settings.py +++ b/apps/jumpserver/settings.py @@ -286,7 +286,7 @@ LOGGING = { 'handlers': ['console', 'file'], 'level': "INFO", }, - 'jms_audits': { + 'jms.audits': { 'handlers': ['syslog'], 'level': 'INFO' }, diff --git a/apps/jumpserver/views.py b/apps/jumpserver/views.py index 06eb7feb5..f3365b7ff 100644 --- a/apps/jumpserver/views.py +++ b/apps/jumpserver/views.py @@ -190,7 +190,7 @@ class IndexView(PermissionsMixin, TemplateView): class LunaView(View): def get(self, request): - msg = _("
Luna is a separately deployed program, you need to deploy Luna, coco, configure nginx for url distribution,
" + msg = _("
Luna is a separately deployed program, you need to deploy Luna, koko, configure nginx for url distribution,
" "If you see this page, prove that you are not accessing the nginx listening port. Good luck.") return HttpResponse(msg) diff --git a/apps/locale/zh/LC_MESSAGES/django.mo b/apps/locale/zh/LC_MESSAGES/django.mo index 753a93327..6701de0ac 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 fe241d0fc..5c9d8c4bd 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: 2019-09-24 11:11+0800\n" +"POT-Creation-Date: 2019-09-25 15:11+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: ibuler \n" "Language-Team: Jumpserver team\n" @@ -112,7 +112,7 @@ msgstr "资产" #: applications/templates/applications/remote_app_detail.html:53 #: applications/templates/applications/remote_app_list.html:20 #: applications/templates/applications/user_remote_app_list.html:16 -#: assets/forms/asset.py:20 assets/forms/domain.py:73 assets/forms/user.py:74 +#: assets/forms/asset.py:24 assets/forms/domain.py:73 assets/forms/user.py:74 #: assets/forms/user.py:94 assets/models/base.py:28 assets/models/cluster.py:18 #: assets/models/cmd_filter.py:20 assets/models/domain.py:20 #: assets/models/group.py:20 assets/models/label.py:18 @@ -576,14 +576,18 @@ msgstr "更新节点资产硬件信息: {}" msgid "Test if the assets under the node are connectable: {}" msgstr "测试节点下资产是否可连接: {}" -#: assets/forms/asset.py:24 assets/models/asset.py:140 +#: assets/forms/asset.py:18 +msgid "Only Numbers、letters、 chinese and characters ( {} ) are allowed" +msgstr "只允许包含数字、字母、中文和特殊字符( {} )" + +#: assets/forms/asset.py:28 assets/models/asset.py:140 #: assets/models/domain.py:50 #: assets/templates/assets/domain_gateway_list.html:69 #: settings/templates/settings/replay_storage_create.html:59 msgid "Port" msgstr "端口" -#: assets/forms/asset.py:55 assets/models/asset.py:145 +#: assets/forms/asset.py:59 assets/models/asset.py:145 #: assets/models/user.py:110 assets/templates/assets/asset_detail.html:190 #: assets/templates/assets/asset_detail.html:198 #: assets/templates/assets/system_user_assets.html:83 @@ -594,7 +598,7 @@ msgstr "端口" msgid "Nodes" msgstr "节点" -#: assets/forms/asset.py:58 assets/forms/asset.py:106 +#: assets/forms/asset.py:62 assets/forms/asset.py:109 #: assets/models/asset.py:149 assets/models/cluster.py:19 #: assets/models/user.py:68 assets/templates/assets/asset_detail.html:76 #: templates/_nav.html:44 xpack/plugins/cloud/models.py:161 @@ -603,7 +607,7 @@ msgstr "节点" msgid "Admin user" msgstr "管理用户" -#: assets/forms/asset.py:61 assets/forms/asset.py:109 assets/forms/asset.py:150 +#: assets/forms/asset.py:65 assets/forms/asset.py:112 assets/forms/asset.py:152 #: assets/templates/assets/asset_create.html:48 #: assets/templates/assets/asset_create.html:50 #: assets/templates/assets/asset_list.html:85 @@ -611,7 +615,7 @@ msgstr "管理用户" msgid "Label" msgstr "标签" -#: assets/forms/asset.py:64 assets/forms/asset.py:112 +#: assets/forms/asset.py:68 assets/forms/asset.py:115 #: assets/models/asset.py:144 assets/models/domain.py:26 #: assets/models/domain.py:52 assets/templates/assets/asset_detail.html:80 #: assets/templates/assets/user_asset_list.html:53 @@ -619,8 +623,8 @@ msgstr "标签" msgid "Domain" msgstr "网域" -#: assets/forms/asset.py:68 assets/forms/asset.py:103 assets/forms/asset.py:116 -#: assets/forms/asset.py:153 assets/models/node.py:403 +#: assets/forms/asset.py:72 assets/forms/asset.py:106 assets/forms/asset.py:119 +#: assets/forms/asset.py:155 assets/models/node.py:413 #: assets/templates/assets/asset_create.html:42 #: perms/forms/asset_permission.py:82 perms/forms/asset_permission.py:89 #: perms/templates/perms/asset_permission_list.html:53 @@ -635,11 +639,7 @@ msgstr "网域" msgid "Node" msgstr "节点" -#: assets/forms/asset.py:71 assets/forms/asset.py:119 -msgid "Only Numbers, letters, and characters ( {} ) are allowed" -msgstr "只允许包含数字,字母,特殊字符( {} )" - -#: assets/forms/asset.py:74 assets/forms/asset.py:122 +#: assets/forms/asset.py:77 assets/forms/asset.py:124 msgid "" "root or other NOPASSWD sudo privilege user existed in asset,If asset is " "windows or other set any one, more see admin user left menu" @@ -647,16 +647,16 @@ msgstr "" "root或其他拥有NOPASSWD: ALL权限的用户, 如果是windows或其它硬件可以随意设置一" "个, 更多信息查看左侧 `管理用户` 菜单" -#: assets/forms/asset.py:77 assets/forms/asset.py:125 +#: assets/forms/asset.py:80 assets/forms/asset.py:127 msgid "Windows 2016 RDP protocol is different, If is window 2016, set it" msgstr "Windows 2016的RDP协议与之前不同,如果是请设置" -#: assets/forms/asset.py:78 assets/forms/asset.py:126 +#: assets/forms/asset.py:81 assets/forms/asset.py:128 msgid "" "If your have some network not connect with each other, you can set domain" msgstr "如果有多个的互相隔离的网络,设置资产属于的网域,使用网域网关跳转登录" -#: assets/forms/asset.py:133 assets/forms/asset.py:137 +#: assets/forms/asset.py:135 assets/forms/asset.py:139 #: assets/forms/domain.py:17 assets/forms/label.py:15 #: perms/templates/perms/asset_permission_asset.html:78 #: xpack/plugins/change_auth_plan/forms.py:55 @@ -1107,7 +1107,7 @@ msgstr "默认资产组" msgid "User" msgstr "用户" -#: assets/models/label.py:19 assets/models/node.py:394 +#: assets/models/label.py:19 assets/models/node.py:404 #: assets/templates/assets/label_list.html:15 settings/models.py:30 msgid "Value" msgstr "值" @@ -1116,19 +1116,19 @@ msgstr "值" msgid "Category" msgstr "分类" -#: assets/models/node.py:230 +#: assets/models/node.py:163 msgid "New node" msgstr "新节点" -#: assets/models/node.py:318 +#: assets/models/node.py:328 msgid "ungrouped" msgstr "未分组" -#: assets/models/node.py:320 +#: assets/models/node.py:330 msgid "empty" msgstr "空" -#: assets/models/node.py:393 +#: assets/models/node.py:403 msgid "Key" msgstr "键" @@ -1182,7 +1182,7 @@ msgstr "Shell" msgid "Login mode" msgstr "登录模式" -#: assets/models/user.py:168 assets/templates/assets/user_asset_list.html:52 +#: assets/models/user.py:162 assets/templates/assets/user_asset_list.html:52 #: audits/models.py:20 audits/templates/audits/ftp_log_list.html:52 #: audits/templates/audits/ftp_log_list.html:75 #: perms/forms/asset_permission.py:85 perms/forms/remote_app_permission.py:40 @@ -2733,13 +2733,12 @@ msgstr "仪表盘" #: jumpserver/views.py:193 msgid "" -"
Luna is a separately deployed program, you need to deploy Luna, coco, " +"
Luna is a separately deployed program, you need to deploy Luna, koko, " "configure nginx for url distribution,
If you see this page, " "prove that you are not accessing the nginx listening port. Good luck." msgstr "" -"
Luna是单独部署的一个程序,你需要部署luna,coco,配置nginx做url分发,
如果你看到了这个页面,证明你访问的不是nginx监听的端口,祝你好运" +"
Luna是单独部署的一个程序,你需要部署luna,koko,
如果你看到了" +"这个页面,证明你访问的不是nginx监听的端口,祝你好运
" #: ops/api/celery.py:54 msgid "Waiting task start" @@ -3916,7 +3915,7 @@ msgstr "您确定删除吗?" msgid "Search no entry matched in ou {}" msgstr "在ou:{}中没有匹配条目" -#: settings/utils.py:120 +#: settings/utils.py:122 msgid "The user source is not LDAP" msgstr "用户来源不是LDAP" diff --git a/apps/ops/inventory.py b/apps/ops/inventory.py index 694957b14..ffd7e8619 100644 --- a/apps/ops/inventory.py +++ b/apps/ops/inventory.py @@ -15,7 +15,7 @@ logger = get_logger(__file__) class JMSBaseInventory(BaseInventory): - windows_ssh_default_ssh = settings.WINDOWS_SSH_DEFAULT_SHELL + windows_ssh_default_shell = settings.WINDOWS_SSH_DEFAULT_SHELL def convert_to_ansible(self, asset, run_as_admin=False): info = { @@ -35,7 +35,7 @@ class JMSBaseInventory(BaseInventory): if asset.is_windows(): info["vars"].update({ "ansible_connection": "ssh", - "ansible_shell_type": self.windows_ssh_default_ssh, + "ansible_shell_type": self.windows_ssh_default_shell, }) for label in asset.labels.all(): info["vars"].update({ diff --git a/apps/perms/api/user_permission/mixin.py b/apps/perms/api/user_permission/mixin.py index a25e49251..8d65a884c 100644 --- a/apps/perms/api/user_permission/mixin.py +++ b/apps/perms/api/user_permission/mixin.py @@ -36,7 +36,7 @@ class UserNodeTreeMixin: assets_amount = self.tree.assets_amount(node.key) if assets_amount == 0 and node.key != Node.empty_key: continue - node._assets_amount = assets_amount + node.assets_amount = assets_amount data = ParserNode.parse_node_to_tree_node(node) _queryset.append(data) return _queryset diff --git a/apps/settings/utils.py b/apps/settings/utils.py index 232224dcc..f9fa7ba96 100644 --- a/apps/settings/utils.py +++ b/apps/settings/utils.py @@ -93,6 +93,8 @@ class LDAPUtil: user_item = self._ldap_entry_to_user_item(entry) user = self.get_user_by_username(user_item['username']) user_item['existing'] = bool(user) + if user_item in user_items: + continue user_items.append(user_item) return user_items diff --git a/apps/terminal/api/session.py b/apps/terminal/api/session.py index 5303bbdb2..7071ddd33 100644 --- a/apps/terminal/api/session.py +++ b/apps/terminal/api/session.py @@ -26,7 +26,7 @@ logger = get_logger(__name__) class SessionViewSet(OrgBulkModelViewSet): queryset = Session.objects.all() serializer_class = serializers.SessionSerializer - permission_classes = (IsOrgAdminOrAppUser | IsOrgAuditor, ) + permission_classes = (IsOrgAdminOrAppUser, ) filter_fields = [ "user", "asset", "system_user", "remote_addr", "protocol", "terminal", "is_finished", @@ -53,6 +53,11 @@ class SessionViewSet(OrgBulkModelViewSet): serializer.validated_data["system_user"] = _system_user.name return super().perform_create(serializer) + def get_permissions(self): + if self.request.method.lower() in ['get']: + self.permission_classes = (IsOrgAdminOrAppUser | IsOrgAuditor, ) + return super().get_permissions() + class SessionReplayViewSet(viewsets.ViewSet): serializer_class = serializers.ReplaySerializer diff --git a/apps/terminal/models.py b/apps/terminal/models.py index 8cfd5ef87..f7f2994ed 100644 --- a/apps/terminal/models.py +++ b/apps/terminal/models.py @@ -4,6 +4,7 @@ import os import uuid from django.db import models +from django.db.models.signals import post_save from django.utils.translation import ugettext_lazy as _ from django.utils import timezone from django.conf import settings @@ -267,7 +268,16 @@ class Task(models.Model): db_table = "terminal_task" +class CommandManager(models.Manager): + def bulk_create(self, objs, **kwargs): + resp = super().bulk_create(objs, **kwargs) + for i in objs: + post_save.send(i.__class__, instance=i, created=True) + return resp + + class Command(AbstractSessionCommand): + objects = CommandManager() class Meta: db_table = "terminal_command" diff --git a/apps/terminal/templates/terminal/session_list.html b/apps/terminal/templates/terminal/session_list.html index 6ac9b7bd8..d23d9be02 100644 --- a/apps/terminal/templates/terminal/session_list.html +++ b/apps/terminal/templates/terminal/session_list.html @@ -41,7 +41,7 @@
- {% if type == "online" %} + {% if type == "online" and request.user.can_admin_current_org %}