mirror of https://github.com/jumpserver/jumpserver
commit
91f64eccda
|
@ -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'
|
||||
|
|
|
@ -257,10 +257,6 @@ class NodeAssetsMixin:
|
|||
|
||||
@lazyproperty
|
||||
def assets_amount(self):
|
||||
"""
|
||||
获取节点下所有资产数量速度太慢,所以需要重写,使用cache等方案
|
||||
:return:
|
||||
"""
|
||||
amount = self.tree().assets_amount(self.key)
|
||||
return amount
|
||||
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -36,3 +36,4 @@ class SessionAuditSerializer(serializers.ModelSerializer):
|
|||
class Meta:
|
||||
model = Session
|
||||
fields = '__all__'
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -225,4 +225,4 @@ class lazyproperty:
|
|||
else:
|
||||
value = self.func(instance)
|
||||
setattr(instance, self.func.__name__, value)
|
||||
return value
|
||||
return value
|
||||
|
|
|
@ -286,7 +286,7 @@ LOGGING = {
|
|||
'handlers': ['console', 'file'],
|
||||
'level': "INFO",
|
||||
},
|
||||
'jms_audits': {
|
||||
'jms.audits': {
|
||||
'handlers': ['syslog'],
|
||||
'level': 'INFO'
|
||||
},
|
||||
|
|
|
@ -190,7 +190,7 @@ class IndexView(PermissionsMixin, TemplateView):
|
|||
|
||||
class LunaView(View):
|
||||
def get(self, request):
|
||||
msg = _("<div>Luna is a separately deployed program, you need to deploy Luna, coco, configure nginx for url distribution,</div> "
|
||||
msg = _("<div>Luna is a separately deployed program, you need to deploy Luna, koko, configure nginx for url distribution,</div> "
|
||||
"</div>If you see this page, prove that you are not accessing the nginx listening port. Good luck.</div>")
|
||||
return HttpResponse(msg)
|
||||
|
||||
|
|
Binary file not shown.
|
@ -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 <ibuler@qq.com>\n"
|
||||
"Language-Team: Jumpserver team<ibuler@qq.com>\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 ""
|
||||
"<div>Luna is a separately deployed program, you need to deploy Luna, coco, "
|
||||
"<div>Luna is a separately deployed program, you need to deploy Luna, koko, "
|
||||
"configure nginx for url distribution,</div> </div>If you see this page, "
|
||||
"prove that you are not accessing the nginx listening port. Good luck.</div>"
|
||||
msgstr ""
|
||||
"<div>Luna是单独部署的一个程序,你需要部署luna,coco,配置nginx做url分发, </"
|
||||
"div><div>如果你看到了这个页面,证明你访问的不是nginx监听的端口,祝你好运</"
|
||||
"div>"
|
||||
"<div>Luna是单独部署的一个程序,你需要部署luna,koko, </div><div>如果你看到了"
|
||||
"这个页面,证明你访问的不是nginx监听的端口,祝你好运</div>"
|
||||
|
||||
#: 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"
|
||||
|
||||
|
|
|
@ -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({
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -41,7 +41,7 @@
|
|||
</table>
|
||||
|
||||
<div id="actions" class="hide">
|
||||
{% if type == "online" %}
|
||||
{% if type == "online" and request.user.can_admin_current_org %}
|
||||
<div class="input-group">
|
||||
<select class="form-control m-b" style="width: auto" id="slct_bulk_update">
|
||||
<option value="terminate">{% trans 'Terminate selected' %}</option>
|
||||
|
@ -140,7 +140,7 @@ function initTable() {
|
|||
replayBtn = replayBtn.replace("disabled", "")
|
||||
}
|
||||
var termBtn = '<a class="btn btn-xs btn-danger btn-term" disabled value="sessionID" terminal="terminalID" >{% trans "Terminate" %}</a>';
|
||||
if ("{{ request.user.is_org_admin }}" === "True") {
|
||||
if ("{{ request.user.can_admin_current_org }}" === "True") {
|
||||
termBtn = termBtn.replace("disabled", "")
|
||||
.replace("sessionID", cellData)
|
||||
.replace("terminalID", rowData.terminal)
|
||||
|
|
|
@ -135,4 +135,4 @@ class WebTerminalView(View):
|
|||
|
||||
class WebSFTPView(View):
|
||||
def get(self, request, *args, **kwargs):
|
||||
return redirect('/coco/elfinder/sftp/?' + request.GET.urlencode())
|
||||
return redirect('/koko/elfinder/sftp/?' + request.GET.urlencode())
|
||||
|
|
6
jms
6
jms
|
@ -205,6 +205,10 @@ def parse_service(s):
|
|||
]
|
||||
if s == 'all':
|
||||
return all_services
|
||||
elif s == "web":
|
||||
return ['gunicorn', 'flower']
|
||||
elif s == "task":
|
||||
return ["celery_ansible", "celery_default", "beat"]
|
||||
elif s == 'gunicorn':
|
||||
return ['gunicorn', 'flower']
|
||||
elif s == "celery":
|
||||
|
@ -474,7 +478,7 @@ if __name__ == '__main__':
|
|||
)
|
||||
parser.add_argument(
|
||||
"service", type=str, default="all", nargs="?",
|
||||
choices=("all", "gunicorn", "celery", "beat", "celery,beat", "flower"),
|
||||
choices=("all", "web", "task", "gunicorn", "celery", "beat", "celery,beat", "flower"),
|
||||
help="The service to start",
|
||||
)
|
||||
parser.add_argument('-d', '--daemon', nargs="?", const=1)
|
||||
|
|
Loading…
Reference in New Issue