Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
l y
Jumpserver
Commits
12a86d72
Unverified
Commit
12a86d72
authored
4 years ago
by
Jiangjie.Bai
Committed by
GitHub
4 years ago
Browse files
Options
Download
Plain Diff
Merge pull request #4611 from jumpserver/dev
Dev
parents
a0085c4e
269eea88
Changes
20
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
Dockerfile
+1
-1
Dockerfile
README.md
+6
-0
README.md
apps/audits/tasks.py
+2
-2
apps/audits/tasks.py
apps/authentication/signals_handlers.py
+16
-0
apps/authentication/signals_handlers.py
apps/common/fields/model.py
+10
-2
apps/common/fields/model.py
apps/common/tasks.py
+1
-1
apps/common/tasks.py
apps/common/utils/crypto.py
+63
-3
apps/common/utils/crypto.py
apps/jumpserver/conf.py
+2
-1
apps/jumpserver/conf.py
apps/jumpserver/settings/custom.py
+3
-0
apps/jumpserver/settings/custom.py
apps/locale/zh/LC_MESSAGES/django.mo
+0
-0
apps/locale/zh/LC_MESSAGES/django.mo
apps/locale/zh/LC_MESSAGES/django.po
+134
-115
apps/locale/zh/LC_MESSAGES/django.po
apps/settings/api.py
+6
-4
apps/settings/api.py
apps/settings/tasks/ldap.py
+2
-5
apps/settings/tasks/ldap.py
apps/tickets/migrations/0004_ticket_comment.py
+18
-0
apps/tickets/migrations/0004_ticket_comment.py
apps/tickets/models/ticket.py
+1
-0
apps/tickets/models/ticket.py
apps/tickets/serializers/request_asset_perm.py
+1
-1
apps/tickets/serializers/request_asset_perm.py
apps/users/api/user.py
+1
-3
apps/users/api/user.py
apps/users/models/user.py
+0
-6
apps/users/models/user.py
apps/users/serializers/user.py
+0
-3
apps/users/serializers/user.py
config_example.yml
+4
-1
config_example.yml
with
271 additions
and
148 deletions
+271
-148
Dockerfile
+
1
-
1
View file @
12a86d72
...
...
@@ -21,7 +21,7 @@ RUN useradd jumpserver
RUN
yum
-y
install
epel-release
&&
\
echo
-e
"[mysql]
\n
name=mysql
\n
baseurl=
${
MYSQL_MIRROR
}
\n
gpgcheck=0
\n
enabled=1"
>
/etc/yum.repos.d/mysql.repo
RUN
yum
-y
install
$(
cat
requirements/rpm_requirements.txt
)
RUN
pip
install
--upgrade
pip setuptools wheel
-i
${
PIP_MIRROR
}
&&
\
RUN
pip
install
--upgrade
pip
setuptools
==
49.6.0
wheel
-i
${
PIP_MIRROR
}
&&
\
pip config
set
global.index-url
${
PIP_MIRROR
}
RUN
pip
install
-r
requirements/requirements.txt
||
pip
install
-r
requirements/requirements.txt
...
...
This diff is collapsed.
Click to expand it.
README.md
+
6
-
0
View file @
12a86d72
...
...
@@ -206,6 +206,12 @@ v2.1.0 是 v2.0.0 之后的功能版本。
-
[
完整文档
](
https://docs.jumpserver.org
)
-
[
演示视频
](
https://jumpserver.oss-cn-hangzhou.aliyuncs.com/jms-media/%E3%80%90%E6%BC%94%E7%A4%BA%E8%A7%86%E9%A2%91%E3%80%91Jumpserver%20%E5%A0%A1%E5%9E%92%E6%9C%BA%20V1.5.0%20%E6%BC%94%E7%A4%BA%E8%A7%86%E9%A2%91%20-%20final.mp4
)
## 组件项目
-
[
Lina
](
https://github.com/jumpserver/lina
)
JumpServer Web UI 项目
-
[
Luna
](
https://github.com/jumpserver/luna
)
JumpServer Web Terminal 项目
-
[
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/
)
## JumpServer 企业版
-
[
申请企业版试用
](
https://jinshuju.net/f/kyOYpi
)
> 注:企业版支持离线安装,申请通过后会提供高速下载链接。
...
...
This diff is collapsed.
Click to expand it.
apps/audits/tasks.py
+
2
-
2
View file @
12a86d72
...
...
@@ -16,7 +16,7 @@ def clean_login_log_period():
try
:
days
=
int
(
settings
.
LOGIN_LOG_KEEP_DAYS
)
except
ValueError
:
days
=
9
0
days
=
9
999
expired_day
=
now
-
datetime
.
timedelta
(
days
=
days
)
UserLoginLog
.
objects
.
filter
(
datetime__lt
=
expired_day
).
delete
()
...
...
@@ -28,6 +28,6 @@ def clean_operation_log_period():
try
:
days
=
int
(
settings
.
LOGIN_LOG_KEEP_DAYS
)
except
ValueError
:
days
=
9
0
days
=
9
999
expired_day
=
now
-
datetime
.
timedelta
(
days
=
days
)
OperateLog
.
objects
.
filter
(
datetime__lt
=
expired_day
).
delete
()
This diff is collapsed.
Click to expand it.
apps/authentication/signals_handlers.py
+
16
-
0
View file @
12a86d72
from
importlib
import
import_module
from
django.conf
import
settings
from
django.contrib.auth
import
user_logged_in
from
django.core.cache
import
cache
from
django.dispatch
import
receiver
from
jms_oidc_rp.signals
import
openid_user_login_failed
,
openid_user_login_success
...
...
@@ -5,6 +10,17 @@ from jms_oidc_rp.signals import openid_user_login_failed, openid_user_login_succ
from
.signals
import
post_auth_success
,
post_auth_failed
@
receiver
(
user_logged_in
)
def
on_user_auth_login_success
(
sender
,
user
,
request
,
**
kwargs
):
if
settings
.
USER_LOGIN_SINGLE_MACHINE_ENABLED
:
user_id
=
'single_machine_login_'
+
str
(
user
.
id
)
session_key
=
cache
.
get
(
user_id
)
if
session_key
and
session_key
!=
request
.
session
.
session_key
:
session
=
import_module
(
settings
.
SESSION_ENGINE
).
SessionStore
(
session_key
)
session
.
delete
()
cache
.
set
(
user_id
,
request
.
session
.
session_key
,
None
)
@
receiver
(
openid_user_login_success
)
def
on_oidc_user_login_success
(
sender
,
request
,
user
,
**
kwargs
):
post_auth_success
.
send
(
sender
,
user
=
user
,
request
=
request
)
...
...
This diff is collapsed.
Click to expand it.
apps/common/fields/model.py
+
10
-
2
View file @
12a86d72
...
...
@@ -5,7 +5,7 @@ from django.db import models
from
django.utils.translation
import
ugettext_lazy
as
_
from
django.utils.encoding
import
force_text
from
..utils
import
signer
,
aes_crypto
from
..utils
import
signer
,
aes_crypto
,
aes_ecb_crypto
__all__
=
[
...
...
@@ -117,9 +117,17 @@ class EncryptMixin:
return
signer
.
unsign
(
value
)
or
''
def
decrypt_from_aes
(
self
,
value
):
"""
先尝试使用GCM模式解密,如果解不开,再尝试使用原来的ECB模式解密
"""
try
:
return
aes_crypto
.
decrypt
(
value
)
except
(
TypeError
,
ValueError
):
except
ValueError
:
pass
try
:
return
aes_ecb_crypto
.
decrypt
(
value
)
except
(
TypeError
,
ValueError
,
UnicodeDecodeError
):
pass
def
from_db_value
(
self
,
value
,
expression
,
connection
,
context
):
...
...
This diff is collapsed.
Click to expand it.
apps/common/tasks.py
+
1
-
1
View file @
12a86d72
...
...
@@ -24,7 +24,7 @@ def send_mail_async(*args, **kwargs):
"""
if
len
(
args
)
==
3
:
args
=
list
(
args
)
args
[
0
]
=
settings
.
EMAIL_SUBJECT_PREFIX
+
args
[
0
]
args
[
0
]
=
(
settings
.
EMAIL_SUBJECT_PREFIX
or
''
)
+
args
[
0
]
email_from
=
settings
.
EMAIL_FROM
or
settings
.
EMAIL_HOST_USER
args
.
insert
(
2
,
email_from
)
args
=
tuple
(
args
)
...
...
This diff is collapsed.
Click to expand it.
apps/common/utils/crypto.py
+
63
-
3
View file @
12a86d72
import
base64
from
Crypto.Cipher
import
AES
from
Crypto.Util.Padding
import
pad
from
Crypto.Random
import
get_random_bytes
from
django.conf
import
settings
...
...
@@ -44,11 +46,69 @@ class AESCrypto:
return
str
(
aes
.
decrypt
(
base64
.
decodebytes
(
bytes
(
text
,
encoding
=
'utf8'
))).
rstrip
(
b
'
\0
'
).
decode
(
"utf8"
))
# 解密
def
get_aes_crypto
(
key
=
None
):
class
AESCryptoGCM
:
"""
使用AES GCM模式
"""
def
__init__
(
self
,
key
):
self
.
key
=
self
.
process_key
(
key
)
@
staticmethod
def
process_key
(
key
):
"""
返回32 bytes 的key
"""
if
not
isinstance
(
key
,
bytes
):
key
=
bytes
(
key
,
encoding
=
'utf-8'
)
if
len
(
key
)
>=
32
:
return
key
[:
32
]
return
pad
(
key
,
32
)
def
encrypt
(
self
,
text
):
"""
加密text,并将 header, nonce, tag (3*16 bytes, base64后变为 3*24 bytes)
附在密文前。解密时要用到。
"""
header
=
get_random_bytes
(
16
)
cipher
=
AES
.
new
(
self
.
key
,
AES
.
MODE_GCM
)
cipher
.
update
(
header
)
ciphertext
,
tag
=
cipher
.
encrypt_and_digest
(
bytes
(
text
,
encoding
=
'utf-8'
))
result
=
[]
for
byte_data
in
(
header
,
cipher
.
nonce
,
tag
,
ciphertext
):
result
.
append
(
base64
.
b64encode
(
byte_data
).
decode
(
'utf-8'
))
return
''
.
join
(
result
)
def
decrypt
(
self
,
text
):
"""
提取header, nonce, tag并解密text。
"""
metadata
=
text
[:
72
]
header
=
base64
.
b64decode
(
metadata
[:
24
])
nonce
=
base64
.
b64decode
(
metadata
[
24
:
48
])
tag
=
base64
.
b64decode
(
metadata
[
48
:])
ciphertext
=
base64
.
b64decode
(
text
[
72
:])
cipher
=
AES
.
new
(
self
.
key
,
AES
.
MODE_GCM
,
nonce
=
nonce
)
cipher
.
update
(
header
)
plain_text_bytes
=
cipher
.
decrypt_and_verify
(
ciphertext
,
tag
)
return
plain_text_bytes
.
decode
(
'utf-8'
)
def
get_aes_crypto
(
key
=
None
,
mode
=
'GCM'
):
if
key
is
None
:
key
=
settings
.
SECRET_KEY
a
=
AESCrypto
(
key
)
if
mode
==
'ECB'
:
a
=
AESCrypto
(
key
)
elif
mode
==
'GCM'
:
a
=
AESCryptoGCM
(
key
)
return
a
aes_crypto
=
get_aes_crypto
()
aes_ecb_crypto
=
get_aes_crypto
(
mode
=
'ECB'
)
aes_crypto
=
get_aes_crypto
(
mode
=
'GCM'
)
This diff is collapsed.
Click to expand it.
apps/jumpserver/conf.py
+
2
-
1
View file @
12a86d72
...
...
@@ -266,7 +266,8 @@ class Config(dict):
'ORG_CHANGE_TO_URL'
:
''
,
'LANGUAGE_CODE'
:
'zh'
,
'TIME_ZONE'
:
'Asia/Shanghai'
,
'CHANGE_AUTH_PLAN_SECURE_MODE_ENABLED'
:
True
'CHANGE_AUTH_PLAN_SECURE_MODE_ENABLED'
:
True
,
'USER_LOGIN_SINGLE_MACHINE_ENABLED'
:
False
}
def
compatible_auth_openid_of_key
(
self
):
...
...
This diff is collapsed.
Click to expand it.
apps/jumpserver/settings/custom.py
+
3
-
0
View file @
12a86d72
...
...
@@ -70,6 +70,9 @@ FLOWER_URL = CONFIG.FLOWER_URL
# Enable internal period task
PERIOD_TASK_ENABLED
=
CONFIG
.
PERIOD_TASK_ENABLED
# only allow single machine login with the same account
USER_LOGIN_SINGLE_MACHINE_ENABLED
=
CONFIG
.
USER_LOGIN_SINGLE_MACHINE_ENABLED
# Email custom content
EMAIL_SUBJECT_PREFIX
=
DYNAMIC
.
EMAIL_SUBJECT_PREFIX
EMAIL_SUFFIX
=
DYNAMIC
.
EMAIL_SUFFIX
...
...
This diff is collapsed.
Click to expand it.
apps/locale/zh/LC_MESSAGES/django.mo
+
0
-
0
View file @
12a86d72
No preview for this file type
This diff is collapsed.
Click to expand it.
apps/locale/zh/LC_MESSAGES/django.po
+
134
-
115
View file @
12a86d72
This diff is collapsed.
Click to expand it.
apps/settings/api.py
+
6
-
4
View file @
12a86d72
...
...
@@ -2,6 +2,7 @@
#
import
json
import
threading
from
collections.abc
import
Iterable
from
smtplib
import
SMTPSenderRefused
from
rest_framework
import
generics
...
...
@@ -15,7 +16,7 @@ from .utils import (
LDAPServerUtil
,
LDAPCacheUtil
,
LDAPImportUtil
,
LDAPSyncUtil
,
LDAP_USE_CACHE_FLAGS
,
LDAPTestUtil
,
ObjectDict
)
from
.tasks
import
sync_ldap_user
_task
from
.tasks
import
sync_ldap_user
from
common.permissions
import
IsOrgAdmin
,
IsSuperUser
from
common.utils
import
get_logger
from
.serializers
import
(
...
...
@@ -204,8 +205,9 @@ class LDAPUserListApi(generics.ListAPIView):
if
sync_util
.
task_no_start
:
# 任务外部设置 task running 状态
sync_util
.
set_task_status
(
sync_util
.
TASK_STATUS_IS_RUNNING
)
task
=
sync_ldap_user_task
.
delay
()
data
=
{
'msg'
:
'Cache no data, sync task {} started.'
.
format
(
task
.
id
)}
t
=
threading
.
Thread
(
target
=
sync_ldap_user
)
t
.
start
()
data
=
{
'msg'
:
'Sync start.'
}
return
Response
(
data
=
data
,
status
=
409
)
# 同步任务正在执行
if
sync_util
.
task_is_running
:
...
...
@@ -214,7 +216,7 @@ class LDAPUserListApi(generics.ListAPIView):
# 同步任务执行结束
if
sync_util
.
task_is_over
:
msg
=
sync_util
.
get_task_error_msg
()
data
=
{
'error'
:
'Synchronization
task report
error: {}'
.
format
(
msg
)}
data
=
{
'error'
:
'Synchronization error: {}'
.
format
(
msg
)}
return
Response
(
data
=
data
,
status
=
400
)
return
super
().
list
(
request
,
*
args
,
**
kwargs
)
...
...
This diff is collapsed.
Click to expand it.
apps/settings/tasks/ldap.py
+
2
-
5
View file @
12a86d72
# coding: utf-8
#
from
celery
import
shared_task
from
common.utils
import
get_logger
from
..utils
import
LDAPSyncUtil
__all__
=
[
'sync_ldap_user
_task
'
]
__all__
=
[
'sync_ldap_user'
]
logger
=
get_logger
(
__file__
)
@
shared_task
def
sync_ldap_user_task
():
def
sync_ldap_user
():
LDAPSyncUtil
().
perform_sync
()
This diff is collapsed.
Click to expand it.
apps/tickets/migrations/0004_ticket_comment.py
0 → 100644
+
18
-
0
View file @
12a86d72
# Generated by Django 2.2.13 on 2020-09-07 11:10
from
django.db
import
migrations
,
models
class
Migration
(
migrations
.
Migration
):
dependencies
=
[
(
'tickets'
,
'0003_auto_20200804_1551'
),
]
operations
=
[
migrations
.
AddField
(
model_name
=
'ticket'
,
name
=
'comment'
,
field
=
models
.
TextField
(
blank
=
True
,
default
=
''
,
max_length
=
128
,
verbose_name
=
'Comment'
),
),
]
This diff is collapsed.
Click to expand it.
apps/tickets/models/ticket.py
+
1
-
0
View file @
12a86d72
...
...
@@ -40,6 +40,7 @@ class Ticket(OrgModelMixin, CommonModelMixin):
type
=
models
.
CharField
(
max_length
=
16
,
choices
=
TYPE
.
choices
,
default
=
TYPE
.
GENERAL
,
verbose_name
=
_
(
"Type"
))
status
=
models
.
CharField
(
choices
=
STATUS
.
choices
,
max_length
=
16
,
default
=
'open'
)
action
=
models
.
CharField
(
choices
=
ACTION
.
choices
,
max_length
=
16
,
default
=
''
,
blank
=
True
)
comment
=
models
.
TextField
(
max_length
=
128
,
default
=
''
,
blank
=
True
,
verbose_name
=
_
(
'Comment'
))
origin_objects
=
models
.
Manager
()
...
...
This diff is collapsed.
Click to expand it.
apps/tickets/serializers/request_asset_perm.py
+
1
-
1
View file @
12a86d72
...
...
@@ -46,7 +46,7 @@ class RequestAssetPermTicketSerializer(serializers.ModelSerializer):
'status'
,
'action'
,
'date_created'
,
'date_updated'
,
'system_user_waitlist_url'
,
'type'
,
'type_display'
,
'action_display'
,
'ips'
,
'confirmed_assets'
,
'date_start'
,
'date_expired'
,
'confirmed_system_user'
,
'hostname'
,
'assets_waitlist_url'
,
'system_user'
,
'org_id'
,
'actions'
'assets_waitlist_url'
,
'system_user'
,
'org_id'
,
'actions'
,
'comment'
]
m2m_fields
=
[
'user'
,
'user_display'
,
'assignees'
,
'assignees_display'
,
...
...
This diff is collapsed.
Click to expand it.
apps/users/api/user.py
+
1
-
3
View file @
12a86d72
...
...
@@ -44,9 +44,7 @@ class UserViewSet(CommonApiMixin, UserQuerysetMixin, BulkModelViewSet):
def
get_queryset
(
self
):
return
super
().
get_queryset
().
annotate
(
gc_m2m_org_members__role
=
GroupConcat
(
'm2m_org_members__role'
),
gc_groups__name
=
GroupConcat
(
'groups__name'
),
gc_groups
=
GroupConcat
(
'groups__id'
,
output_field
=
CharField
())
)
).
prefetch_related
(
'groups'
)
def
send_created_signal
(
self
,
users
):
if
not
isinstance
(
users
,
list
):
...
...
This diff is collapsed.
Click to expand it.
apps/users/models/user.py
+
0
-
6
View file @
12a86d72
...
...
@@ -560,12 +560,6 @@ class User(AuthMixin, TokenMixin, RoleMixin, MFAMixin, AbstractUser):
@
property
def
groups_display
(
self
):
if
hasattr
(
self
,
'gc_groups__name'
):
names
=
self
.
gc_groups__name
if
isinstance
(
names
,
str
):
return
' '
.
join
(
set
(
self
.
gc_groups__name
.
split
(
','
)))
else
:
return
''
return
' '
.
join
([
group
.
name
for
group
in
self
.
groups
.
all
()])
@
property
...
...
This diff is collapsed.
Click to expand it.
apps/users/serializers/user.py
+
0
-
3
View file @
12a86d72
...
...
@@ -44,9 +44,6 @@ class UserSerializer(CommonBulkSerializerMixin, serializers.ModelSerializer):
label
=
_
(
'Password strategy'
),
write_only
=
True
)
mfa_level_display
=
serializers
.
ReadOnlyField
(
source
=
'get_mfa_level_display'
)
groups
=
GroupConcatedPrimaryKeyRelatedField
(
label
=
_
(
'User group'
),
many
=
True
,
queryset
=
UserGroup
.
objects
.
all
(),
required
=
False
)
login_blocked
=
serializers
.
SerializerMethodField
()
can_update
=
serializers
.
SerializerMethodField
()
can_delete
=
serializers
.
SerializerMethodField
()
...
...
This diff is collapsed.
Click to expand it.
config_example.yml
+
4
-
1
View file @
12a86d72
...
...
@@ -116,7 +116,10 @@ REDIS_PORT: 6379
# Perm show single asset to ungrouped node
# 是否把未授权节点资产放入到 未分组 节点中
# PERM_SINGLE_ASSET_TO_UNGROUP_NODE: false
# PERM_SINGLE_ASSET_TO_UNGROUP_NODE: False
#
# 同一账号仅允许在一台设备登录
# USER_LOGIN_SINGLE_MACHINE_ENABLED: False
#
# 启用定时任务
# PERIOD_TASK_ENABLE: True
...
...
This diff is collapsed.
Click to expand it.
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment