mirror of
https://github.com/jumpserver/jumpserver.git
synced 2025-12-15 16:42:34 +00:00
Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1bbb5eaf6f | ||
|
|
b5b7cd7693 | ||
|
|
5b35e99866 | ||
|
|
680c174dcf | ||
|
|
68a1388afd | ||
|
|
da47706dda | ||
|
|
922f777fbb | ||
|
|
ca3c56320e | ||
|
|
2ed2c16ff5 | ||
|
|
3069bb5b0c | ||
|
|
b0650b0047 | ||
|
|
7e133bb0c4 | ||
|
|
bd854cfd0f | ||
|
|
f458eff527 | ||
|
|
97b37bfb5d | ||
|
|
4d7ff0828b | ||
|
|
7db3d63e64 |
@@ -55,7 +55,9 @@ class OAuth2AuthCallbackView(View):
|
|||||||
)
|
)
|
||||||
|
|
||||||
logger.debug(log_prompt.format('Redirect'))
|
logger.debug(log_prompt.format('Redirect'))
|
||||||
return HttpResponseRedirect(settings.AUTH_OAUTH2_AUTHENTICATION_FAILURE_REDIRECT_URI)
|
# OAuth2 服务端认证成功, 但是用户被禁用了, 这时候需要调用服务端的logout
|
||||||
|
redirect_url = settings.AUTH_OAUTH2_PROVIDER_END_SESSION_ENDPOINT
|
||||||
|
return HttpResponseRedirect(redirect_url)
|
||||||
|
|
||||||
|
|
||||||
class OAuth2EndSessionView(View):
|
class OAuth2EndSessionView(View):
|
||||||
|
|||||||
@@ -30,7 +30,9 @@ class CeleryBaseService(BaseService):
|
|||||||
'-l', 'INFO',
|
'-l', 'INFO',
|
||||||
'-c', str(self.num),
|
'-c', str(self.num),
|
||||||
'-Q', self.queue,
|
'-Q', self.queue,
|
||||||
'-n', f'{self.queue}@{server_hostname}'
|
'--heartbeat-interval', '10',
|
||||||
|
'-n', f'{self.queue}@{server_hostname}',
|
||||||
|
'--without-mingle',
|
||||||
]
|
]
|
||||||
return cmd
|
return cmd
|
||||||
|
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ class EBCCipher:
|
|||||||
def __padding(val):
|
def __padding(val):
|
||||||
# padding
|
# padding
|
||||||
val = bytes(val)
|
val = bytes(val)
|
||||||
while len(val) % 16 != 0:
|
while len(val) == 0 or len(val) % 16 != 0:
|
||||||
val += b'\0'
|
val += b'\0'
|
||||||
return val
|
return val
|
||||||
|
|
||||||
|
|||||||
@@ -82,7 +82,8 @@ class PiicoSM4EcbCrypto(BaseCrypto):
|
|||||||
return self.cipher.encrypt(self.to_16(data))
|
return self.cipher.encrypt(self.to_16(data))
|
||||||
|
|
||||||
def _decrypt(self, data: bytes) -> bytes:
|
def _decrypt(self, data: bytes) -> bytes:
|
||||||
return self.cipher.decrypt(data)
|
bs = self.cipher.decrypt(data)
|
||||||
|
return bs.rstrip(b'\0')
|
||||||
|
|
||||||
|
|
||||||
class AESCrypto:
|
class AESCrypto:
|
||||||
@@ -232,6 +233,8 @@ class Crypto:
|
|||||||
return self.cryptos[0]
|
return self.cryptos[0]
|
||||||
|
|
||||||
def encrypt(self, text):
|
def encrypt(self, text):
|
||||||
|
if text is None:
|
||||||
|
return text
|
||||||
return self.encryptor.encrypt(text)
|
return self.encryptor.encrypt(text)
|
||||||
|
|
||||||
def decrypt(self, text):
|
def decrypt(self, text):
|
||||||
@@ -241,7 +244,7 @@ class Crypto:
|
|||||||
if origin_text:
|
if origin_text:
|
||||||
# 有时不同算法解密不报错,但是返回空字符串
|
# 有时不同算法解密不报错,但是返回空字符串
|
||||||
return origin_text
|
return origin_text
|
||||||
except (TypeError, ValueError, UnicodeDecodeError, IndexError):
|
except Exception:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -161,6 +161,8 @@ AUTH_OAUTH2_CLIENT_SECRET = CONFIG.AUTH_OAUTH2_CLIENT_SECRET
|
|||||||
AUTH_OAUTH2_CLIENT_ID = CONFIG.AUTH_OAUTH2_CLIENT_ID
|
AUTH_OAUTH2_CLIENT_ID = CONFIG.AUTH_OAUTH2_CLIENT_ID
|
||||||
AUTH_OAUTH2_SCOPE = CONFIG.AUTH_OAUTH2_SCOPE
|
AUTH_OAUTH2_SCOPE = CONFIG.AUTH_OAUTH2_SCOPE
|
||||||
AUTH_OAUTH2_USER_ATTR_MAP = CONFIG.AUTH_OAUTH2_USER_ATTR_MAP
|
AUTH_OAUTH2_USER_ATTR_MAP = CONFIG.AUTH_OAUTH2_USER_ATTR_MAP
|
||||||
|
AUTH_OAUTH2_LOGOUT_COMPLETELY = CONFIG.AUTH_OAUTH2_LOGOUT_COMPLETELY
|
||||||
|
AUTH_OAUTH2_PROVIDER_END_SESSION_ENDPOINT = CONFIG.AUTH_OAUTH2_PROVIDER_END_SESSION_ENDPOINT
|
||||||
AUTH_OAUTH2_AUTH_LOGIN_CALLBACK_URL_NAME = 'authentication:oauth2:login-callback'
|
AUTH_OAUTH2_AUTH_LOGIN_CALLBACK_URL_NAME = 'authentication:oauth2:login-callback'
|
||||||
AUTH_OAUTH2_AUTHENTICATION_REDIRECT_URI = '/'
|
AUTH_OAUTH2_AUTHENTICATION_REDIRECT_URI = '/'
|
||||||
AUTH_OAUTH2_AUTHENTICATION_FAILURE_REDIRECT_URI = '/'
|
AUTH_OAUTH2_AUTHENTICATION_FAILURE_REDIRECT_URI = '/'
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ from .base import (
|
|||||||
)
|
)
|
||||||
from ..const import CONFIG, PROJECT_DIR
|
from ..const import CONFIG, PROJECT_DIR
|
||||||
|
|
||||||
|
|
||||||
REST_FRAMEWORK = {
|
REST_FRAMEWORK = {
|
||||||
# Use Django's standard `django.contrib.auth` permissions,
|
# Use Django's standard `django.contrib.auth` permissions,
|
||||||
# or allow read-only access for unauthenticated users.
|
# or allow read-only access for unauthenticated users.
|
||||||
@@ -64,7 +63,6 @@ SWAGGER_SETTINGS = {
|
|||||||
'DEFAULT_INFO': 'jumpserver.views.swagger.api_info',
|
'DEFAULT_INFO': 'jumpserver.views.swagger.api_info',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
# Captcha settings, more see https://django-simple-captcha.readthedocs.io/en/latest/advanced.html
|
# Captcha settings, more see https://django-simple-captcha.readthedocs.io/en/latest/advanced.html
|
||||||
CAPTCHA_IMAGE_SIZE = (180, 38)
|
CAPTCHA_IMAGE_SIZE = (180, 38)
|
||||||
CAPTCHA_FOREGROUND_COLOR = '#001100'
|
CAPTCHA_FOREGROUND_COLOR = '#001100'
|
||||||
@@ -81,7 +79,6 @@ BOOTSTRAP3 = {
|
|||||||
'required_css_class': 'required',
|
'required_css_class': 'required',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
# Django channels support websocket
|
# Django channels support websocket
|
||||||
if not REDIS_USE_SSL:
|
if not REDIS_USE_SSL:
|
||||||
redis_ssl = None
|
redis_ssl = None
|
||||||
@@ -101,14 +98,13 @@ CHANNEL_LAYERS = {
|
|||||||
'address': (CONFIG.REDIS_HOST, CONFIG.REDIS_PORT),
|
'address': (CONFIG.REDIS_HOST, CONFIG.REDIS_PORT),
|
||||||
'db': CONFIG.REDIS_DB_WS,
|
'db': CONFIG.REDIS_DB_WS,
|
||||||
'password': CONFIG.REDIS_PASSWORD or None,
|
'password': CONFIG.REDIS_PASSWORD or None,
|
||||||
'ssl': redis_ssl
|
'ssl': redis_ssl
|
||||||
}],
|
}],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
ASGI_APPLICATION = 'jumpserver.routing.application'
|
ASGI_APPLICATION = 'jumpserver.routing.application'
|
||||||
|
|
||||||
|
|
||||||
# Dump all celery log to here
|
# Dump all celery log to here
|
||||||
CELERY_LOG_DIR = os.path.join(PROJECT_DIR, 'data', 'celery')
|
CELERY_LOG_DIR = os.path.join(PROJECT_DIR, 'data', 'celery')
|
||||||
|
|
||||||
@@ -131,6 +127,7 @@ CELERY_TASK_EAGER_PROPAGATES = True
|
|||||||
CELERY_WORKER_REDIRECT_STDOUTS = True
|
CELERY_WORKER_REDIRECT_STDOUTS = True
|
||||||
CELERY_WORKER_REDIRECT_STDOUTS_LEVEL = "INFO"
|
CELERY_WORKER_REDIRECT_STDOUTS_LEVEL = "INFO"
|
||||||
CELERY_TASK_SOFT_TIME_LIMIT = 3600
|
CELERY_TASK_SOFT_TIME_LIMIT = 3600
|
||||||
|
CELERY_WORKER_CANCEL_LONG_RUNNING_TASKS_ON_CONNECTION_LOSS = True
|
||||||
|
|
||||||
if REDIS_USE_SSL:
|
if REDIS_USE_SSL:
|
||||||
CELERY_BROKER_USE_SSL = CELERY_REDIS_BACKEND_USE_SSL = {
|
CELERY_BROKER_USE_SSL = CELERY_REDIS_BACKEND_USE_SSL = {
|
||||||
@@ -148,3 +145,7 @@ REDIS_PORT = CONFIG.REDIS_PORT
|
|||||||
REDIS_PASSWORD = CONFIG.REDIS_PASSWORD
|
REDIS_PASSWORD = CONFIG.REDIS_PASSWORD
|
||||||
|
|
||||||
DJANGO_REDIS_SCAN_ITERSIZE = 1000
|
DJANGO_REDIS_SCAN_ITERSIZE = 1000
|
||||||
|
|
||||||
|
# GM DEVICE
|
||||||
|
PIICO_DEVICE_ENABLE = CONFIG.PIICO_DEVICE_ENABLE
|
||||||
|
PIICO_DRIVER_PATH = CONFIG.PIICO_DRIVER_PATH
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
<head>
|
<head>
|
||||||
<title>{% trans 'Task log' %}</title>
|
<title>{% trans 'Task log' %}</title>
|
||||||
<script src="{% static 'js/jquery-3.1.1.min.js' %}"></script>
|
<script src="{% static 'js/jquery-3.6.1.min.js' %}"></script>
|
||||||
<script src="{% static 'js/plugins/xterm/xterm.js' %}"></script>
|
<script src="{% static 'js/plugins/xterm/xterm.js' %}"></script>
|
||||||
<script src="{% static 'js/plugins/xterm/addons/fit/fit.js' %}"></script>
|
<script src="{% static 'js/plugins/xterm/addons/fit/fit.js' %}"></script>
|
||||||
<link rel="stylesheet" href="{% static 'js/plugins/xterm/xterm.css' %}" />
|
<link rel="stylesheet" href="{% static 'js/plugins/xterm/xterm.css' %}" />
|
||||||
|
|||||||
4
apps/static/js/jquery-3.1.1.min.js
vendored
4
apps/static/js/jquery-3.1.1.min.js
vendored
File diff suppressed because one or more lines are too long
2
apps/static/js/jquery-3.6.1.min.js
vendored
Executable file
2
apps/static/js/jquery-3.6.1.min.js
vendored
Executable file
File diff suppressed because one or more lines are too long
@@ -9,7 +9,7 @@
|
|||||||
<link href="{% static 'css/plugins/vaildator/jquery.validator.css' %}" rel="stylesheet">
|
<link href="{% static 'css/plugins/vaildator/jquery.validator.css' %}" rel="stylesheet">
|
||||||
<link href="{% static 'css/plugins/datatables/datatables.min.css' %}" rel="stylesheet">
|
<link href="{% static 'css/plugins/datatables/datatables.min.css' %}" rel="stylesheet">
|
||||||
<!-- scripts -->
|
<!-- scripts -->
|
||||||
<script src="{% static 'js/jquery-3.1.1.min.js' %}"></script>
|
<script src="{% static 'js/jquery-3.6.1.min.js' %}"></script>
|
||||||
<script src="{% static 'js/plugins/sweetalert/sweetalert.min.js' %}"></script>
|
<script src="{% static 'js/plugins/sweetalert/sweetalert.min.js' %}"></script>
|
||||||
<script src="{% static 'js/bootstrap.min.js' %}"></script>
|
<script src="{% static 'js/bootstrap.min.js' %}"></script>
|
||||||
<script src="{% static 'js/plugins/datatables/datatables.min.js' %}"></script>
|
<script src="{% static 'js/plugins/datatables/datatables.min.js' %}"></script>
|
||||||
|
|||||||
@@ -169,6 +169,14 @@ class CommandStore(object):
|
|||||||
return self.es.index(index=self.index, doc_type=self.doc_type, body=data)
|
return self.es.index(index=self.index, doc_type=self.doc_type, body=data)
|
||||||
|
|
||||||
def filter(self, query: dict, from_=None, size=None, sort=None):
|
def filter(self, query: dict, from_=None, size=None, sort=None):
|
||||||
|
try:
|
||||||
|
data = self._filter(query, from_, size, sort)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error('ES filter error: {}'.format(e))
|
||||||
|
data = []
|
||||||
|
return data
|
||||||
|
|
||||||
|
def _filter(self, query: dict, from_=None, size=None, sort=None):
|
||||||
body = self.get_query_body(**query)
|
body = self.get_query_body(**query)
|
||||||
|
|
||||||
data = self.es.search(
|
data = self.es.search(
|
||||||
@@ -184,9 +192,14 @@ class CommandStore(object):
|
|||||||
return Command.from_multi_dict(source_data)
|
return Command.from_multi_dict(source_data)
|
||||||
|
|
||||||
def count(self, **query):
|
def count(self, **query):
|
||||||
body = self.get_query_body(**query)
|
try:
|
||||||
data = self.es.count(index=self.query_index, doc_type=self.doc_type, body=body)
|
body = self.get_query_body(**query)
|
||||||
return data["count"]
|
data = self.es.count(index=self.query_index, doc_type=self.doc_type, body=body)
|
||||||
|
count = data["count"]
|
||||||
|
except Exception as e:
|
||||||
|
logger.error('ES count error: {}'.format(e))
|
||||||
|
count = 0
|
||||||
|
return count
|
||||||
|
|
||||||
def __getattr__(self, item):
|
def __getattr__(self, item):
|
||||||
return getattr(self.es, item)
|
return getattr(self.es, item)
|
||||||
|
|||||||
@@ -117,9 +117,13 @@ class Session(OrgModelMixin):
|
|||||||
def find_ok_relative_path_in_storage(self, storage):
|
def find_ok_relative_path_in_storage(self, storage):
|
||||||
session_paths = self.get_all_possible_relative_path()
|
session_paths = self.get_all_possible_relative_path()
|
||||||
for rel_path in session_paths:
|
for rel_path in session_paths:
|
||||||
if storage.exists(rel_path):
|
# storage 为多个外部存储时, 可能会因部分不可用,
|
||||||
return rel_path
|
# 抛出异常, 影响录像的获取
|
||||||
|
try:
|
||||||
|
if storage.exists(rel_path):
|
||||||
|
return rel_path
|
||||||
|
except:
|
||||||
|
pass
|
||||||
@property
|
@property
|
||||||
def asset_obj(self):
|
def asset_obj(self):
|
||||||
return Asset.objects.get(id=self.asset_id)
|
return Asset.objects.get(id=self.asset_id)
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
from html import escape
|
||||||
|
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
from django.template.loader import render_to_string
|
from django.template.loader import render_to_string
|
||||||
|
|
||||||
@@ -42,7 +44,7 @@ class BaseHandler:
|
|||||||
def _on_step_rejected(self, step):
|
def _on_step_rejected(self, step):
|
||||||
self._send_processed_mail_to_applicant(step)
|
self._send_processed_mail_to_applicant(step)
|
||||||
|
|
||||||
def _on_step_closed(self, step):
|
def _on_step_closed(self):
|
||||||
self._send_processed_mail_to_applicant()
|
self._send_processed_mail_to_applicant()
|
||||||
|
|
||||||
def _send_applied_mail_to_assignees(self, step=None):
|
def _send_applied_mail_to_assignees(self, step=None):
|
||||||
@@ -96,11 +98,19 @@ class BaseHandler:
|
|||||||
approve_info = _('{} {} the ticket').format(user_display, state_display)
|
approve_info = _('{} {} the ticket').format(user_display, state_display)
|
||||||
context = self._diff_prev_approve_context(state)
|
context = self._diff_prev_approve_context(state)
|
||||||
context.update({'approve_info': approve_info})
|
context.update({'approve_info': approve_info})
|
||||||
|
body = self.reject_html_script(
|
||||||
|
render_to_string('tickets/ticket_approve_diff.html', context)
|
||||||
|
)
|
||||||
data = {
|
data = {
|
||||||
'body': render_to_string('tickets/ticket_approve_diff.html', context),
|
'body': body,
|
||||||
'user': user,
|
'user': user,
|
||||||
'user_display': str(user),
|
'user_display': str(user),
|
||||||
'type': 'state',
|
'type': 'state',
|
||||||
'state': state
|
'state': state
|
||||||
}
|
}
|
||||||
return self.ticket.comments.create(**data)
|
return self.ticket.comments.create(**data)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def reject_html_script(unsafe_html):
|
||||||
|
safe_html = escape(unsafe_html)
|
||||||
|
return safe_html
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ class ApplyApplicationSerializer(BaseApplyAssetApplicationSerializer, TicketAppl
|
|||||||
class Meta:
|
class Meta:
|
||||||
model = ApplyApplicationTicket
|
model = ApplyApplicationTicket
|
||||||
writeable_fields = [
|
writeable_fields = [
|
||||||
'id', 'title', 'type', 'apply_category',
|
'id', 'title', 'type', 'apply_category', 'comment',
|
||||||
'apply_type', 'apply_applications', 'apply_system_users',
|
'apply_type', 'apply_applications', 'apply_system_users',
|
||||||
'apply_actions', 'apply_date_start', 'apply_date_expired', 'org_id'
|
'apply_actions', 'apply_date_start', 'apply_date_expired', 'org_id'
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ class ApplyAssetSerializer(BaseApplyAssetApplicationSerializer, TicketApplySeria
|
|||||||
model = ApplyAssetTicket
|
model = ApplyAssetTicket
|
||||||
writeable_fields = [
|
writeable_fields = [
|
||||||
'id', 'title', 'type', 'apply_nodes', 'apply_assets',
|
'id', 'title', 'type', 'apply_nodes', 'apply_assets',
|
||||||
'apply_system_users', 'apply_actions',
|
'apply_system_users', 'apply_actions', 'comment',
|
||||||
'apply_date_start', 'apply_date_expired', 'org_id'
|
'apply_date_start', 'apply_date_expired', 'org_id'
|
||||||
]
|
]
|
||||||
fields = TicketApplySerializer.Meta.fields + \
|
fields = TicketApplySerializer.Meta.fields + \
|
||||||
|
|||||||
@@ -191,7 +191,7 @@ class UserExpirationReminderMsg(UserMessage):
|
|||||||
class ResetSSHKeyMsg(UserMessage):
|
class ResetSSHKeyMsg(UserMessage):
|
||||||
def get_html_msg(self) -> dict:
|
def get_html_msg(self) -> dict:
|
||||||
subject = _('Reset SSH Key')
|
subject = _('Reset SSH Key')
|
||||||
update_url = urljoin(settings.SITE_URL, '/ui/#/users/profile/?activeTab=SSHUpdate')
|
update_url = urljoin(settings.SITE_URL, '/ui/#/profile/setting/?activeTab=SSHUpdate')
|
||||||
context = {
|
context = {
|
||||||
'name': self.user.name,
|
'name': self.user.name,
|
||||||
'url': update_url,
|
'url': update_url,
|
||||||
|
|||||||
@@ -133,6 +133,7 @@ pymssql==2.1.5
|
|||||||
django-mysql==3.9.0
|
django-mysql==3.9.0
|
||||||
django-redis==5.2.0
|
django-redis==5.2.0
|
||||||
python-redis-lock==3.7.0
|
python-redis-lock==3.7.0
|
||||||
|
pyOpenSSL==22.0.0
|
||||||
redis==4.3.3
|
redis==4.3.3
|
||||||
pymongo==4.2.0
|
pymongo==4.2.0
|
||||||
# Debug
|
# Debug
|
||||||
|
|||||||
Reference in New Issue
Block a user