Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
gjl2004yn
jumpserver
提交
07634042
J
jumpserver
项目概览
gjl2004yn
/
jumpserver
与 Fork 源项目一致
从无法访问的项目Fork
通知
2
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
J
jumpserver
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
未验证
提交
07634042
编写于
11月 17, 2020
作者:
J
Jiangjie.Bai
提交者:
GitHub
11月 17, 2020
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #5021 from jumpserver/dev
Dev
上级
96d26cc9
31cd441a
变更
17
隐藏空白更改
内联
并排
Showing
17 changed file
with
152 addition
and
23 deletion
+152
-23
README.md
README.md
+55
-1
apps/assets/migrations/0061_auto_20201116_1757.py
apps/assets/migrations/0061_auto_20201116_1757.py
+17
-0
apps/assets/models/base.py
apps/assets/models/base.py
+4
-2
apps/assets/models/node.py
apps/assets/models/node.py
+3
-1
apps/assets/models/user.py
apps/assets/models/user.py
+5
-0
apps/assets/tasks/push_system_user.py
apps/assets/tasks/push_system_user.py
+4
-2
apps/common/utils/crypto.py
apps/common/utils/crypto.py
+1
-1
apps/jumpserver/urls.py
apps/jumpserver/urls.py
+3
-3
apps/ops/ansible/callback.py
apps/ops/ansible/callback.py
+7
-1
apps/ops/ansible/runner.py
apps/ops/ansible/runner.py
+8
-0
apps/ops/inventory.py
apps/ops/inventory.py
+14
-6
apps/ops/models/adhoc.py
apps/ops/models/adhoc.py
+1
-1
apps/ops/models/command.py
apps/ops/models/command.py
+2
-2
apps/templates/_base_only_content.html
apps/templates/_base_only_content.html
+1
-1
apps/templates/_head_css_js.html
apps/templates/_head_css_js.html
+2
-0
apps/terminal/migrations/0029_auto_20201116_1757.py
apps/terminal/migrations/0029_auto_20201116_1757.py
+23
-0
apps/terminal/models.py
apps/terminal/models.py
+2
-2
未找到文件。
README.md
浏览文件 @
07634042
...
...
@@ -25,7 +25,8 @@ JumpServer 采纳分布式架构,支持多机房跨区域部署,支持横向
-
无插件: 仅需浏览器,极致的 Web Terminal 使用体验;
-
多云支持: 一套系统,同时管理不同云上面的资产;
-
云端存储: 审计录像云端存储,永不丢失;
-
多租户: 一套系统,多个子公司和部门同时使用。
-
多租户: 一套系统,多个子公司和部门同时使用;
-
多应用支持: 数据库,Windows远程应用,Kubernetes。
## 版本说明
...
...
@@ -198,6 +199,54 @@ v2.1.0 是 v2.0.0 之后的功能版本。
<td>
文件传输
</td>
<td>
可对文件的上传、下载记录进行审计
</td>
</tr>
<tr>
<td
rowspan=
"20"
>
数据库审计
<br>
Database
</td>
<td
rowspan=
"2"
>
连接方式
</td>
<td>
命令方式
</td>
</tr>
<tr>
<td>
Web UI方式 (X-PACK)
</td>
</tr>
<tr>
<td
rowspan=
"4"
>
支持的数据库
</td>
<td>
MySQL
</td>
</tr>
<tr>
<td>
Oracle (X-PACK)
</td>
</tr>
<tr>
<td>
MariaDB (X-PACK)
</td>
</tr>
<tr>
<td>
PostgreSQL (X-PACK)
</td>
</tr>
<tr>
<td
rowspan=
"6"
>
功能亮点
</td>
<td>
语法高亮
</td>
</tr>
<tr>
<td>
SQL格式化
</td>
</tr>
<tr>
<td>
支持快捷键
</td>
</tr>
<tr>
<td>
支持选中执行
</td>
</tr>
<tr>
<td>
SQL历史查询
</td>
</tr>
<tr>
<td>
支持页面创建 DB, TABLE
</td>
</tr>
<tr>
<td
rowspan=
"2"
>
会话审计
</td>
<td>
命令记录
</td>
</tr>
<tr>
<td>
录像回放
</td>
</tr>
</table>
## 快速开始
...
...
@@ -212,6 +261,11 @@ v2.1.0 是 v2.0.0 之后的功能版本。
-
[
Koko
](
https://github.com/jumpserver/koko
)
JumpServer 字符协议 Connector 项目,替代原来 Python 版本的
[
Coco
](
https://github.com/jumpserver/coco
)
-
[
Guacamole
](
https://github.com/jumpserver/docker-guacamole
)
JumpServer 图形协议 Connector 项目,依赖
[
Apache Guacamole
](
https://guacamole.apache.org/
)
## 致谢
-
[
Apache Guacamole
](
https://guacamole.apache.org/
)
Web页面连接 RDP, SSH, VNC协议设备,JumpServer 图形化连接依赖
-
[
OmniDB
](
https://omnidb.org/
)
Web页面连接使用数据库,JumpServer Web数据库依赖
## JumpServer 企业版
-
[
申请企业版试用
](
https://jinshuju.net/f/kyOYpi
)
> 注:企业版支持离线安装,申请通过后会提供高速下载链接。
...
...
apps/assets/migrations/0061_auto_20201116_1757.py
0 → 100644
浏览文件 @
07634042
# Generated by Django 2.2.13 on 2020-11-16 09:57
from
django.db
import
migrations
class
Migration
(
migrations
.
Migration
):
dependencies
=
[
(
'assets'
,
'0060_node_full_value'
),
]
operations
=
[
migrations
.
AlterModelOptions
(
name
=
'node'
,
options
=
{
'ordering'
:
[
'value'
],
'verbose_name'
:
'Node'
},
),
]
apps/assets/models/base.py
浏览文件 @
07634042
...
...
@@ -158,9 +158,11 @@ class AuthMixin:
if
update_fields
:
self
.
save
(
update_fields
=
update_fields
)
def
has_special_auth
(
self
,
asset
=
None
):
def
has_special_auth
(
self
,
asset
=
None
,
username
=
None
):
from
.authbook
import
AuthBook
queryset
=
AuthBook
.
objects
.
filter
(
username
=
self
.
username
)
if
username
is
None
:
username
=
self
.
username
queryset
=
AuthBook
.
objects
.
filter
(
username
=
username
)
if
asset
:
queryset
=
queryset
.
filter
(
asset
=
asset
)
return
queryset
.
exists
()
...
...
apps/assets/models/node.py
浏览文件 @
07634042
...
...
@@ -210,6 +210,7 @@ class FamilyMixin:
if
not
full_value
:
return
[]
nodes_family
=
full_value
.
split
(
'/'
)
nodes_family
=
[
v
for
v
in
nodes_family
if
v
]
org_root
=
cls
.
org_root
()
if
nodes_family
[
0
]
==
org_root
.
value
:
nodes_family
=
nodes_family
[
1
:]
...
...
@@ -217,6 +218,7 @@ class FamilyMixin:
@
classmethod
def
create_nodes_recurse
(
cls
,
values
,
parent
=
None
):
values
=
[
v
for
v
in
values
if
v
]
if
not
values
:
return
None
if
parent
is
None
:
...
...
@@ -407,7 +409,7 @@ class Node(OrgModelMixin, SomeNodesMixin, FamilyMixin, NodeAssetsMixin):
class
Meta
:
verbose_name
=
_
(
"Node"
)
ordering
=
[
'
key
'
]
ordering
=
[
'
value
'
]
def
__str__
(
self
):
return
self
.
full_value
...
...
apps/assets/models/user.py
浏览文件 @
07634042
...
...
@@ -165,6 +165,11 @@ class SystemUser(BaseUser):
def
is_need_test_asset_connective
(
self
):
return
self
.
protocol
not
in
self
.
application_category_protocols
def
has_special_auth
(
self
,
asset
=
None
,
username
=
None
):
if
username
is
None
and
self
.
username_same_with_user
:
raise
TypeError
(
'System user is dynamic, username should be pass'
)
return
super
().
has_special_auth
(
asset
=
asset
,
username
=
username
)
@
property
def
can_perm_to_asset
(
self
):
return
self
.
protocol
not
in
self
.
application_category_protocols
...
...
apps/assets/tasks/push_system_user.py
浏览文件 @
07634042
...
...
@@ -139,6 +139,7 @@ def get_push_windows_system_user_tasks(system_user, username=None):
tasks
=
[]
if
not
password
:
logger
.
error
(
"Error: no password found"
)
return
tasks
task
=
{
'name'
:
'Add user {}'
.
format
(
username
),
...
...
@@ -214,14 +215,15 @@ def push_system_user_util(system_user, assets, task_name, username=None):
print
(
_
(
"Start push system user for platform: [{}]"
).
format
(
platform
))
print
(
_
(
"Hosts count: {}"
).
format
(
len
(
_hosts
)))
if
not
system_user
.
has_special_auth
():
# 如果没有特殊密码设置,就不需要单独推送某台机器了
if
not
system_user
.
has_special_auth
(
username
=
username
):
logger
.
debug
(
"System user not has special auth"
)
tasks
=
get_push_system_user_tasks
(
system_user
,
platform
,
username
=
username
)
run_task
(
tasks
,
_hosts
)
continue
for
_host
in
_hosts
:
system_user
.
load_asset_special_auth
(
_host
)
system_user
.
load_asset_special_auth
(
_host
,
username
=
username
)
tasks
=
get_push_system_user_tasks
(
system_user
,
platform
,
username
=
username
)
run_task
(
tasks
,
[
_host
])
...
...
apps/common/utils/crypto.py
浏览文件 @
07634042
...
...
@@ -189,7 +189,7 @@ class Crypto:
if
origin_text
:
# 有时不同算法解密不报错,但是返回空字符串
return
origin_text
except
(
TypeError
,
ValueError
,
UnicodeDecodeError
):
except
(
TypeError
,
ValueError
,
UnicodeDecodeError
,
IndexError
):
continue
...
...
apps/jumpserver/urls.py
浏览文件 @
07634042
...
...
@@ -69,9 +69,9 @@ urlpatterns = [
urlpatterns
+=
static
(
settings
.
MEDIA_URL
,
document_root
=
settings
.
MEDIA_ROOT
)
\
+
static
(
settings
.
STATIC_URL
,
document_root
=
settings
.
STATIC_ROOT
)
js_i18n_patterns
=
i18n_patterns
(
path
(
'jsi18n/'
,
JavaScriptCatalog
.
as_view
(),
name
=
'javascript-catalog'
),
)
js_i18n_patterns
=
[
path
(
'
core/
jsi18n/'
,
JavaScriptCatalog
.
as_view
(),
name
=
'javascript-catalog'
),
]
urlpatterns
+=
js_i18n_patterns
handler404
=
'jumpserver.views.handler404'
...
...
apps/ops/ansible/callback.py
浏览文件 @
07634042
...
...
@@ -65,6 +65,8 @@ class AdHocResultCallback(CallbackMixin, CallbackModule, CMDCallBackModule):
"""
Task result Callback
"""
context
=
None
def
clean_result
(
self
,
t
,
host
,
task_name
,
task_result
):
contacted
=
self
.
results_summary
[
"contacted"
]
dark
=
self
.
results_summary
[
"dark"
]
...
...
@@ -133,7 +135,11 @@ class AdHocResultCallback(CallbackMixin, CallbackModule, CMDCallBackModule):
pass
def
set_play_context
(
self
,
context
):
context
.
ssh_args
=
'-C -o ControlMaster=no'
# for k, v in context._attributes.items():
# print("{} ==> {}".format(k, v))
if
self
.
context
and
isinstance
(
self
.
context
,
dict
):
for
k
,
v
in
self
.
context
.
items
():
setattr
(
context
,
k
,
v
)
class
CommandResultCallback
(
AdHocResultCallback
):
...
...
apps/ops/ansible/runner.py
浏览文件 @
07634042
...
...
@@ -182,6 +182,13 @@ class AdHocRunner:
_options
.
update
(
options
)
return
_options
def
set_control_master_if_need
(
self
,
cleaned_tasks
):
modules
=
[
task
.
get
(
'action'
,
{}).
get
(
'module'
)
for
task
in
cleaned_tasks
]
if
{
'ping'
,
'win_ping'
}
&
set
(
modules
):
self
.
results_callback
.
context
=
{
'ssh_args'
:
'-C -o ControlMaster=no'
}
def
run
(
self
,
tasks
,
pattern
,
play_name
=
'Ansible Ad-hoc'
,
gather_facts
=
'no'
):
"""
:param tasks: [{'action': {'module': 'shell', 'args': 'ls'}, ...}, ]
...
...
@@ -193,6 +200,7 @@ class AdHocRunner:
self
.
check_pattern
(
pattern
)
self
.
results_callback
=
self
.
get_result_callback
()
cleaned_tasks
=
self
.
clean_tasks
(
tasks
)
self
.
set_control_master_if_need
(
cleaned_tasks
)
context
.
CLIARGS
=
ImmutableDict
(
self
.
options
)
play_source
=
dict
(
...
...
apps/ops/inventory.py
浏览文件 @
07634042
...
...
@@ -76,7 +76,7 @@ class JMSInventory(JMSBaseInventory):
write you own inventory, construct you inventory,
user_info is obtained from admin_user or asset_user
"""
def
__init__
(
self
,
assets
,
run_as_admin
=
False
,
run_as
=
None
,
become_info
=
None
):
def
__init__
(
self
,
assets
,
run_as_admin
=
False
,
run_as
=
None
,
become_info
=
None
,
system_user
=
None
):
"""
:param assets: assets
:param run_as_admin: True 是否使用管理用户去执行, 每台服务器的管理用户可能不同
...
...
@@ -86,6 +86,7 @@ class JMSInventory(JMSBaseInventory):
self
.
assets
=
assets
self
.
using_admin
=
run_as_admin
self
.
run_as
=
run_as
self
.
system_user
=
system_user
self
.
become_info
=
become_info
host_list
=
[]
...
...
@@ -104,18 +105,25 @@ class JMSInventory(JMSBaseInventory):
def
get_run_user_info
(
self
,
host
):
from
assets.backends
import
AssetUserManager
if
self
.
run_as
is
None
:
if
not
self
.
run_as
and
not
self
.
system_user
:
return
{}
asset_id
=
host
.
get
(
'id'
,
''
)
asset
=
self
.
assets
.
filter
(
id
=
asset_id
).
first
()
if
not
asset
:
logger
.
error
(
'Host not found: '
,
asset_id
)
if
self
.
system_user
:
self
.
system_user
.
load_asset_special_auth
(
asset
=
asset
,
username
=
self
.
run_as
)
return
self
.
system_user
.
_to_secret_json
()
try
:
asset
=
self
.
assets
.
get
(
id
=
host
.
get
(
'id'
))
manager
=
AssetUserManager
()
run_user
=
manager
.
get_latest
(
username
=
self
.
run_as
,
asset
=
asset
)
run_user
=
manager
.
get_latest
(
username
=
self
.
run_as
,
asset
=
asset
,
prefer
=
'system_user'
)
return
run_user
.
_to_secret_json
()
except
Exception
as
e
:
logger
.
error
(
e
,
exc_info
=
True
)
return
{}
else
:
return
run_user
.
_to_secret_json
()
class
JMSCustomInventory
(
JMSBaseInventory
):
...
...
apps/ops/models/adhoc.py
浏览文件 @
07634042
...
...
@@ -184,7 +184,7 @@ class AdHoc(OrgModelMixin):
hid
=
str
(
uuid
.
uuid4
())
execution
=
AdHocExecution
(
id
=
hid
,
adhoc
=
self
,
task
=
self
.
task
,
task_display
=
str
(
self
.
task
),
task_display
=
str
(
self
.
task
)
[:
128
]
,
date_start
=
timezone
.
now
(),
hosts_amount
=
self
.
hosts
.
count
(),
)
...
...
apps/ops/models/command.py
浏览文件 @
07634042
...
...
@@ -37,7 +37,7 @@ class CommandExecution(OrgModelMixin):
username
=
self
.
user
.
username
else
:
username
=
self
.
run_as
.
username
inv
=
JMSInventory
(
self
.
hosts
.
all
(),
run_as
=
username
)
inv
=
JMSInventory
(
self
.
hosts
.
all
(),
run_as
=
username
,
system_user
=
self
.
run_as
)
return
inv
@
lazyproperty
...
...
@@ -78,7 +78,7 @@ class CommandExecution(OrgModelMixin):
runner
=
CommandRunner
(
self
.
inventory
)
try
:
host
=
self
.
hosts
.
first
()
if
host
.
is_windows
():
if
host
and
host
.
is_windows
():
shell
=
'win_shell'
else
:
shell
=
'shell'
...
...
apps/templates/_base_only_content.html
浏览文件 @
07634042
...
...
@@ -11,7 +11,7 @@
{% include '_head_css_js.html' %}
<link
href=
"{% static "
css
/
jumpserver.css
"
%}"
rel=
"stylesheet"
>
<script
src=
"{% url 'javascript-catalog' %}"
></script>
<script
src=
"{% static "
js
/
jumpserver.js
"
%}"
></script>
<style>
.passwordBox
{
...
...
apps/templates/_head_css_js.html
浏览文件 @
07634042
...
...
@@ -13,5 +13,7 @@
<script
src=
"{% static 'js/plugins/sweetalert/sweetalert.min.js' %}"
></script>
<script
src=
"{% static 'js/bootstrap.min.js' %}"
></script>
<script
src=
"{% static 'js/plugins/datatables/datatables.min.js' %}"
></script>
<script
src=
"{% url 'javascript-catalog' %}"
></script>
<link
href=
"{% static 'css/plugins/select2/select2.min.css' %}"
rel=
"stylesheet"
>
apps/terminal/migrations/0029_auto_20201116_1757.py
0 → 100644
浏览文件 @
07634042
# Generated by Django 2.2.13 on 2020-11-16 09:57
from
django.db
import
migrations
,
models
class
Migration
(
migrations
.
Migration
):
dependencies
=
[
(
'terminal'
,
'0028_auto_20201110_1918'
),
]
operations
=
[
migrations
.
AlterField
(
model_name
=
'commandstorage'
,
name
=
'name'
,
field
=
models
.
CharField
(
max_length
=
128
,
unique
=
True
,
verbose_name
=
'Name'
),
),
migrations
.
AlterField
(
model_name
=
'replaystorage'
,
name
=
'name'
,
field
=
models
.
CharField
(
max_length
=
128
,
unique
=
True
,
verbose_name
=
'Name'
),
),
]
apps/terminal/models.py
浏览文件 @
07634042
...
...
@@ -401,7 +401,7 @@ class CommandStorage(CommonModelMixin):
TYPE_DEFAULTS
=
dict
(
const
.
REPLAY_STORAGE_TYPE_CHOICES_DEFAULT
).
keys
()
TYPE_SERVER
=
const
.
COMMAND_STORAGE_TYPE_SERVER
name
=
models
.
CharField
(
max_length
=
32
,
verbose_name
=
_
(
"Name"
),
unique
=
True
)
name
=
models
.
CharField
(
max_length
=
128
,
verbose_name
=
_
(
"Name"
),
unique
=
True
)
type
=
models
.
CharField
(
max_length
=
16
,
choices
=
TYPE_CHOICES
,
verbose_name
=
_
(
'Type'
),
default
=
TYPE_SERVER
...
...
@@ -438,7 +438,7 @@ class ReplayStorage(CommonModelMixin):
TYPE_SERVER
=
const
.
REPLAY_STORAGE_TYPE_SERVER
TYPE_DEFAULTS
=
dict
(
const
.
REPLAY_STORAGE_TYPE_CHOICES_DEFAULT
).
keys
()
name
=
models
.
CharField
(
max_length
=
32
,
verbose_name
=
_
(
"Name"
),
unique
=
True
)
name
=
models
.
CharField
(
max_length
=
128
,
verbose_name
=
_
(
"Name"
),
unique
=
True
)
type
=
models
.
CharField
(
max_length
=
16
,
choices
=
TYPE_CHOICES
,
verbose_name
=
_
(
'Type'
),
default
=
TYPE_SERVER
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录