-
{% trans "More login options" %}
+
+ {% trans "More login options" %}
+
+
diff --git a/apps/authentication/views/login.py b/apps/authentication/views/login.py
index ae32b14ab..3b8f2c60c 100644
--- a/apps/authentication/views/login.py
+++ b/apps/authentication/views/login.py
@@ -10,8 +10,7 @@ from django.contrib.auth import login as auth_login, logout as auth_logout
from django.http import HttpResponse
from django.shortcuts import reverse, redirect
from django.utils.decorators import method_decorator
-from django.db import transaction
-from django.utils.translation import ugettext as _
+from django.utils.translation import ugettext as _, get_language
from django.views.decorators.cache import never_cache
from django.views.decorators.csrf import csrf_protect
from django.views.decorators.debug import sensitive_post_parameters
@@ -181,6 +180,29 @@ class UserLoginView(mixins.AuthMixin, FormView):
]
return [method for method in auth_methods if method['enabled']]
+ @staticmethod
+ def get_support_langs():
+ langs = [
+ {
+ 'title': '中文(简体)',
+ 'code': 'zh-hans'
+ },
+ {
+ 'title': 'English',
+ 'code': 'en'
+ },
+ {
+ 'title': '日本語',
+ 'code': 'ja'
+ }
+ ]
+ return langs
+
+ def get_current_lang(self):
+ langs = self.get_support_langs()
+ matched_lang = filter(lambda x: x['code'] == get_language(), langs)
+ return next(matched_lang, langs[0])
+
@staticmethod
def get_forgot_password_url():
forgot_password_url = reverse('authentication:forgot-password')
@@ -188,14 +210,16 @@ class UserLoginView(mixins.AuthMixin, FormView):
return forgot_password_url
def get_context_data(self, **kwargs):
- context = {
+ context = super().get_context_data(**kwargs)
+ context.update({
'demo_mode': os.environ.get("DEMO_MODE"),
'auth_methods': self.get_support_auth_methods(),
+ 'langs': self.get_support_langs(),
+ 'current_lang': self.get_current_lang(),
'forgot_password_url': self.get_forgot_password_url(),
**self.get_user_mfa_context(self.request.user)
- }
- kwargs.update(context)
- return super().get_context_data(**kwargs)
+ })
+ return context
class UserLoginGuardView(mixins.AuthMixin, RedirectView):
diff --git a/apps/jumpserver/routing.py b/apps/jumpserver/routing.py
index 5deae804e..1d1de2230 100644
--- a/apps/jumpserver/routing.py
+++ b/apps/jumpserver/routing.py
@@ -1,5 +1,6 @@
from channels.auth import AuthMiddlewareStack
from channels.routing import ProtocolTypeRouter, URLRouter
+from django.core.asgi import get_asgi_application
from ops.urls.ws_urls import urlpatterns as ops_urlpatterns
from notifications.urls.ws_urls import urlpatterns as notifications_urlpatterns
@@ -12,4 +13,5 @@ application = ProtocolTypeRouter({
'websocket': AuthMiddlewareStack(
URLRouter(urlpatterns)
),
+ "http": get_asgi_application(),
})
diff --git a/apps/jumpserver/settings/base.py b/apps/jumpserver/settings/base.py
index c1baf2882..2b1bbdf13 100644
--- a/apps/jumpserver/settings/base.py
+++ b/apps/jumpserver/settings/base.py
@@ -11,10 +11,19 @@ from django.urls import reverse_lazy
from .. import const
from ..const import CONFIG
+
+def exist_or_default(path, default):
+ if not os.path.exists(path):
+ path = default
+ return path
+
+
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
VERSION = const.VERSION
BASE_DIR = const.BASE_DIR
PROJECT_DIR = const.PROJECT_DIR
+DATA_DIR = os.path.join(PROJECT_DIR, 'data')
+CERTS_DIR = os.path.join(DATA_DIR, 'certs')
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.10/howto/deployment/checklist/
@@ -148,19 +157,7 @@ SESSION_EXPIRE_AT_BROWSER_CLOSE = True
# 自定义的配置,SESSION_EXPIRE_AT_BROWSER_CLOSE 始终为 True, 下面这个来控制是否强制关闭后过期 cookie
SESSION_EXPIRE_AT_BROWSER_CLOSE_FORCE = CONFIG.SESSION_EXPIRE_AT_BROWSER_CLOSE_FORCE
SESSION_SAVE_EVERY_REQUEST = CONFIG.SESSION_SAVE_EVERY_REQUEST
-SESSION_ENGINE = 'jumpserver.rewriting.session'
-SESSION_REDIS = {
- 'url': '%(protocol)s://:%(password)s@%(host)s:%(port)s/%(db)s' % {
- 'protocol': 'rediss' if CONFIG.REDIS_USE_SSL else 'redis',
- 'password': CONFIG.REDIS_PASSWORD,
- 'host': CONFIG.REDIS_HOST,
- 'port': CONFIG.REDIS_PORT,
- 'db': CONFIG.REDIS_DB_CACHE,
- },
- 'prefix': 'auth_session',
- 'socket_timeout': 1,
- 'retry_on_timeout': False
-}
+SESSION_ENGINE = "django.contrib.sessions.backends.cache"
MESSAGE_STORAGE = 'django.contrib.messages.storage.cookie.CookieStorage'
# Database
@@ -180,7 +177,6 @@ DATABASES = {
}
}
-
DB_CA_PATH = os.path.join(PROJECT_DIR, 'data', 'certs', 'db_ca.pem')
if CONFIG.DB_ENGINE.lower() == 'mysql':
DB_OPTIONS['init_command'] = "SET sql_mode='STRICT_TRANS_TABLES'"
@@ -264,45 +260,40 @@ FILE_UPLOAD_PERMISSIONS = 0o644
FILE_UPLOAD_DIRECTORY_PERMISSIONS = 0o755
# Cache use redis
-REDIS_SSL_KEYFILE = os.path.join(PROJECT_DIR, 'data', 'certs', 'redis_client.key')
-if not os.path.exists(REDIS_SSL_KEYFILE):
- REDIS_SSL_KEYFILE = None
-
-REDIS_SSL_CERTFILE = os.path.join(PROJECT_DIR, 'data', 'certs', 'redis_client.crt')
-if not os.path.exists(REDIS_SSL_CERTFILE):
- REDIS_SSL_CERTFILE = None
-
-REDIS_SSL_CA_CERTS = os.path.join(PROJECT_DIR, 'data', 'certs', 'redis_ca.crt')
-if not os.path.exists(REDIS_SSL_CA_CERTS):
- REDIS_SSL_CA_CERTS = os.path.join(PROJECT_DIR, 'data', 'certs', 'redis_ca.pem')
-
-if not os.path.exists(REDIS_SSL_CA_CERTS):
- REDIS_SSL_CA_CERTS = None
-
+REDIS_SSL_KEYFILE = exist_or_default(os.path.join(CERTS_DIR, 'redis_client.key'), None)
+REDIS_SSL_CERTFILE = exist_or_default(os.path.join(CERTS_DIR, 'redis_client.crt'), None)
+REDIS_SSL_CA_CERTS = exist_or_default(os.path.join(CERTS_DIR, 'redis_ca.pem'), None)
+REDIS_SSL_CA_CERTS = exist_or_default(os.path.join(CERTS_DIR, 'redis_ca.crt'), REDIS_SSL_CA_CERTS)
REDIS_SSL_REQUIRED = CONFIG.REDIS_SSL_REQUIRED or 'none'
+REDIS_LOCATION_NO_DB = '%(protocol)s://:%(password)s@%(host)s:%(port)s/{}' % {
+ 'protocol': 'rediss' if CONFIG.REDIS_USE_SSL else 'redis',
+ 'password': CONFIG.REDIS_PASSWORD,
+ 'host': CONFIG.REDIS_HOST,
+ 'port': CONFIG.REDIS_PORT,
+}
-CACHES = {
- 'default': {
- # 'BACKEND': 'redis_cache.RedisCache',
- 'BACKEND': 'redis_lock.django_cache.RedisCache',
- 'LOCATION': '%(protocol)s://:%(password)s@%(host)s:%(port)s/%(db)s' % {
- 'protocol': 'rediss' if CONFIG.REDIS_USE_SSL else 'redis',
- 'password': CONFIG.REDIS_PASSWORD,
- 'host': CONFIG.REDIS_HOST,
- 'port': CONFIG.REDIS_PORT,
- 'db': CONFIG.REDIS_DB_CACHE,
- },
- 'OPTIONS': {
- "REDIS_CLIENT_KWARGS": {"health_check_interval": 30},
- "CONNECTION_POOL_KWARGS": {
- 'ssl_cert_reqs': REDIS_SSL_REQUIRED,
- "ssl_keyfile": REDIS_SSL_KEYFILE,
- "ssl_certfile": REDIS_SSL_CERTFILE,
- "ssl_ca_certs": REDIS_SSL_CA_CERTS
- } if CONFIG.REDIS_USE_SSL else {}
- }
+REDIS_CACHE_DEFAULT = {
+ 'BACKEND': 'redis_lock.django_cache.RedisCache',
+ 'LOCATION': REDIS_LOCATION_NO_DB.format(CONFIG.REDIS_DB_CACHE),
+ 'OPTIONS': {
+ "REDIS_CLIENT_KWARGS": {"health_check_interval": 30},
+ "CONNECTION_POOL_KWARGS": {
+ 'ssl_cert_reqs': REDIS_SSL_REQUIRED,
+ "ssl_keyfile": REDIS_SSL_KEYFILE,
+ "ssl_certfile": REDIS_SSL_CERTFILE,
+ "ssl_ca_certs": REDIS_SSL_CA_CERTS
+ } if CONFIG.REDIS_USE_SSL else {}
}
}
+REDIS_CACHE_SESSION = dict(REDIS_CACHE_DEFAULT)
+REDIS_CACHE_SESSION['LOCATION'] = REDIS_LOCATION_NO_DB.format(CONFIG.REDIS_DB_SESSION)
+
+CACHES = {
+ 'default': REDIS_CACHE_DEFAULT,
+ 'session': REDIS_CACHE_SESSION
+}
+
+SESSION_CACHE_ALIAS = "session"
FORCE_SCRIPT_NAME = CONFIG.FORCE_SCRIPT_NAME
SESSION_COOKIE_SECURE = CONFIG.SESSION_COOKIE_SECURE
diff --git a/apps/jumpserver/settings/libs.py b/apps/jumpserver/settings/libs.py
index e5a5e90e5..52c0d93b6 100644
--- a/apps/jumpserver/settings/libs.py
+++ b/apps/jumpserver/settings/libs.py
@@ -6,6 +6,7 @@ import ssl
from .base import REDIS_SSL_CA_CERTS, REDIS_SSL_CERTFILE, REDIS_SSL_KEYFILE, REDIS_SSL_REQUIRED
from ..const import CONFIG, PROJECT_DIR
+
REST_FRAMEWORK = {
# Use Django's standard `django.contrib.auth` permissions,
# or allow read-only access for unauthenticated users.
@@ -14,7 +15,6 @@ REST_FRAMEWORK = {
),
'DEFAULT_RENDERER_CLASSES': (
'rest_framework.renderers.JSONRenderer',
- # 'rest_framework.renderers.BrowsableAPIRenderer',
'common.drf.renders.CSVFileRenderer',
'common.drf.renders.ExcelFileRenderer',
@@ -47,9 +47,6 @@ REST_FRAMEWORK = {
'DATETIME_INPUT_FORMATS': ['%Y/%m/%d %H:%M:%S %z', 'iso-8601', '%Y-%m-%d %H:%M:%S %z'],
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination',
'EXCEPTION_HANDLER': 'common.drf.exc_handlers.common_exception_handler',
- # 'PAGE_SIZE': 100,
- # 'MAX_PAGE_SIZE': 5000
-
}
SWAGGER_SETTINGS = {
@@ -67,7 +64,7 @@ SWAGGER_SETTINGS = {
# Captcha settings, more see https://django-simple-captcha.readthedocs.io/en/latest/advanced.html
-CAPTCHA_IMAGE_SIZE = (140, 34)
+CAPTCHA_IMAGE_SIZE = (180, 38)
CAPTCHA_FOREGROUND_COLOR = '#001100'
CAPTCHA_NOISE_FUNCTIONS = ('captcha.helpers.noise_dots',)
CAPTCHA_CHALLENGE_FUNCT = 'captcha.helpers.math_challenge'
@@ -127,18 +124,13 @@ CELERY_RESULT_SERIALIZER = 'pickle'
CELERY_RESULT_BACKEND = CELERY_BROKER_URL
CELERY_ACCEPT_CONTENT = ['json', 'pickle']
CELERY_RESULT_EXPIRES = 600
-# CELERY_WORKER_LOG_FORMAT = '%(asctime)s [%(module)s %(levelname)s] %(message)s'
-# CELERY_WORKER_LOG_FORMAT = '%(message)s'
-# CELERY_WORKER_TASK_LOG_FORMAT = '%(task_id)s %(task_name)s %(message)s'
CELERY_WORKER_TASK_LOG_FORMAT = '%(message)s'
-# CELERY_WORKER_LOG_FORMAT = '%(asctime)s [%(module)s %(levelname)s] %(message)s'
CELERY_WORKER_LOG_FORMAT = '%(message)s'
CELERY_TASK_EAGER_PROPAGATES = True
CELERY_WORKER_REDIRECT_STDOUTS = True
CELERY_WORKER_REDIRECT_STDOUTS_LEVEL = "INFO"
-# CELERY_WORKER_HIJACK_ROOT_LOGGER = True
-# CELERY_WORKER_MAX_TASKS_PER_CHILD = 40
CELERY_TASK_SOFT_TIME_LIMIT = 3600
+
if CONFIG.REDIS_USE_SSL:
CELERY_BROKER_USE_SSL = CELERY_REDIS_BACKEND_USE_SSL = {
'ssl_cert_reqs': REDIS_SSL_REQUIRED,
diff --git a/apps/locale/zh/LC_MESSAGES/django.po b/apps/locale/zh/LC_MESSAGES/django.po
index d0944cb51..37617c5aa 100644
--- a/apps/locale/zh/LC_MESSAGES/django.po
+++ b/apps/locale/zh/LC_MESSAGES/django.po
@@ -2298,7 +2298,7 @@ msgstr "登录"
#: authentication/templates/authentication/login.html:224
msgid "More login options"
-msgstr "更多登录方式"
+msgstr "其他方式登录"
#: authentication/templates/authentication/login_mfa.html:6
msgid "MFA Auth"
diff --git a/apps/notifications/urls/ws_urls.py b/apps/notifications/urls/ws_urls.py
index dfd457e52..69ff5783a 100644
--- a/apps/notifications/urls/ws_urls.py
+++ b/apps/notifications/urls/ws_urls.py
@@ -5,5 +5,5 @@ from .. import ws
app_name = 'notifications'
urlpatterns = [
- path('ws/notifications/site-msg/', ws.SiteMsgWebsocket, name='site-msg-ws'),
-]
\ No newline at end of file
+ path('ws/notifications/site-msg/', ws.SiteMsgWebsocket.as_asgi(), name='site-msg-ws'),
+]
diff --git a/apps/ops/urls/ws_urls.py b/apps/ops/urls/ws_urls.py
index e1d44dd7c..8e9af1636 100644
--- a/apps/ops/urls/ws_urls.py
+++ b/apps/ops/urls/ws_urls.py
@@ -5,5 +5,5 @@ from .. import ws
app_name = 'ops'
urlpatterns = [
- path('ws/ops/tasks/log/', ws.TaskLogWebsocket, name='task-log-ws'),
+ path('ws/ops/tasks/log/', ws.TaskLogWebsocket.as_asgi(), name='task-log-ws'),
]
diff --git a/requirements/requirements.txt b/requirements/requirements.txt
index 1dd12283b..c19bb76e5 100644
--- a/requirements/requirements.txt
+++ b/requirements/requirements.txt
@@ -3,9 +3,9 @@ ansible==2.10.7
asn1crypto==0.24.0
bcrypt==3.1.4
billiard==3.6.4.0
-boto3==1.18.11
-botocore==1.21.11
-celery==5.2.2
+boto3==1.24.12
+botocore==1.27.12
+celery==5.2.7
certifi==2018.1.18
cffi==1.13.2
chardet==3.0.4
@@ -17,117 +17,118 @@ decorator==4.1.2
Django==3.1.14
django-auth-ldap==2.2.0
django-bootstrap3==14.2.0
-django-celery-beat==2.2.1
+django-celery-beat==2.3.0
django-filter==2.4.0
django-formtools==2.2
django-ranged-response==0.2.0
django-rest-swagger==2.2.0
-django-simple-captcha==0.5.13
-django-timezone-field==4.1.0
-djangorestframework==3.12.2
+django-simple-captcha==0.5.17
+django-timezone-field==5.0
+djangorestframework==3.13.1
djangorestframework-bulk==0.2.1
docutils==0.14
ecdsa==0.13.3
enum-compat==0.0.2
ephem==3.7.6.0
-eventlet==0.31.1
+eventlet==0.33.1
future==0.16.0
ForgeryPy3==0.3.1
-greenlet==0.4.14
-gunicorn==19.9.0
+greenlet==1.1.2
+gunicorn==20.1.0
idna==2.6
-itsdangerous==0.24
-itypes==1.1.0
-Jinja2==2.11.3
-jmespath==0.9.3
-kombu==5.2.2
-ldap3==2.4
-MarkupSafe==1.1.1
-mysqlclient==2.0.1
-olefile==0.44
+itsdangerous==1.1.0
+itypes==1.2.0
+Jinja2==3.1.2
+jmespath==1.0.1
+kombu==5.2.4
+ldap3==2.9.1
+MarkupSafe==2.1.1
+mysqlclient==2.1.0
+olefile==0.46
openapi-codec==1.3.2
-paramiko==2.10.1
-passlib==1.7.1
-Pillow==9.0.1
+paramiko==2.11.0
+passlib==1.7.4
+Pillow==9.1.1
pyasn1==0.4.8
-pycparser==2.19
-pycryptodome==3.12.0
-pycryptodomex==3.12.0
-pyotp==2.2.6
+pycparser==2.21
+pycryptodome==3.14.1
+pycryptodomex==3.14.1
+pyotp==2.6.0
PyNaCl==1.5.0
python-dateutil==2.8.2
-pytz==2018.3
+pytz==2022.1
PyYAML==6.0
-redis==4.3.1
-requests==2.25.1
-jms-storage==0.0.42
-s3transfer==0.5.0
-simplejson==3.13.2
-six==1.11.0
-sshpubkeys==3.1.0
-uritemplate==3.0.0
-urllib3==1.26.5
+redis==4.3.3
+requests==2.28.0
+jms-storage==0.0.43
+s3transfer==0.6.0
+simplejson==3.17.6
+six==1.16.0
+sshpubkeys==3.3.1
+uritemplate==4.1.1
+urllib3==1.26.9
vine==5.0.0
drf-yasg==1.20.0
-Werkzeug==0.15.3
-drf-nested-routers==0.91
-aliyun-python-sdk-core-v3==2.9.1
-aliyun-python-sdk-ecs==4.10.1
+Werkzeug==2.1.2
+drf-nested-routers==0.93.4
rest_condition==1.0.3
python-ldap==3.4.0
-tencentcloud-sdk-python==3.0.477
-django-radius==1.4.0
-django-redis-sessions==0.6.1
+django-radius==1.5.0
unicodecsv==0.14.1
-python-daemon==2.2.3
+python-daemon==2.3.0
httpsig==1.3.0
-treelib==1.5.3
+treelib==1.6.1
django-proxy==1.2.1
flower==1.0.0
-channels-redis==3.2.0
-channels==2.4.0
-daphne==2.4.1
-psutil==5.6.6
+channels-redis==3.4.0
+channels==3.0.4
+daphne==3.0.2
+psutil==5.9.1
django-cas-ng==4.0.1
python-cas==1.5.0
ipython
-huaweicloud-sdk-python==1.0.21
-django-redis==4.11.0
+django-redis==5.2.0
python-redis-lock==3.7.0
jumpserver-django-oidc-rp==0.3.7.8
django-mysql==3.9.0
gmssl==3.2.1
-azure-mgmt-compute==4.6.2
-azure-mgmt-network==2.7.0
msrestazure==0.6.4
adal==1.2.5
-openpyxl==3.0.5
-pyexcel==0.6.6
+openpyxl==3.0.10
+pyexcel==0.7.0
pyexcel-xlsx==0.6.0
data-tree==0.0.1
pyvmomi==7.0.1
termcolor==1.1.0
-azure-identity==1.5.0
-azure-mgmt-subscription==1.0.0
-qingcloud-sdk==1.2.12
-django-simple-history==3.0.0
-google-cloud-compute==0.5.0
-PyMySQL==1.0.2
-cx-Oracle==8.2.1
-psycopg2-binary==2.9.1
-alibabacloud_dysmsapi20170525==2.0.2
-geoip2==4.4.0
+django-simple-history==3.1.1
+geoip2==4.5.0
html2text==2020.1.16
-python-novaclient==11.0.1
pyzipper==0.3.5
python3-saml==1.12.0
-python-keystoneclient==4.3.0
-pymssql==2.1.5
kubernetes==21.7.0
websocket-client==1.2.3
numpy==1.22.0
pandas==1.3.5
pyjwkest==1.4.2
jsonfield2==4.0.0.post0
-bce-python-sdk==0.8.64
ipip-ipdb==1.6.1
+# Cloud req
+qingcloud-sdk==1.2.12
+azure-mgmt-subscription==1.0.0
+azure-identity==1.5.0
+azure-mgmt-compute==4.6.2
+azure-mgmt-network==2.7.0
+google-cloud-compute==0.5.0
+alibabacloud_dysmsapi20170525==2.0.2
+python-novaclient==11.0.1
+python-keystoneclient==4.3.0
+bce-python-sdk==0.8.64
+tencentcloud-sdk-python==3.0.477
+aliyun-python-sdk-core-v3==2.9.1
+aliyun-python-sdk-ecs==4.10.1
+huaweicloud-sdk-python==1.0.21
+# DB requirements
+PyMySQL==1.0.2
+cx-Oracle==8.2.1
+psycopg2-binary==2.9.1
+pymssql==2.1.5