Compare commits

..

13 Commits

Author SHA1 Message Date
fit2bot
57dfd0fae2 feat: Update v2.28.6 2022-12-22 11:09:53 +08:00
Bai
81dee0c403 perf: 修改方法名称 check_db_port_mapper 2022-12-22 10:43:07 +08:00
老广
105ef791b8 Merge pull request #9230 from jumpserver/pr@v2.28@v2.28_perf_dbportmapper
fix: 修改db_port_mapper策略; 启动时进行check校验;
2022-12-21 18:59:47 +08:00
Bai
a19c0bde60 fix: 修改db_port_mapper策略; 启动时进行check校验; 2022-12-21 18:43:44 +08:00
halo
3996daf4a7 fix: 导入翻译引用 2022-12-16 11:47:39 +08:00
halo
ac235f788e perf: 优化oauth2的服务地址参数拼接 2022-12-16 11:47:39 +08:00
老广
67e334bf43 Merge pull request #9213 from jumpserver/pr@v2.28@perf_fingerprint
fix: 修复非 ssh 协议的系统用户存在错误私钥,引发的解析问题
2022-12-15 15:25:40 +08:00
Eric
f7f9fb1bdf fix: 修复非 ssh 协议的系统用户存在错误私钥,引发的解析问题 2022-12-15 15:17:36 +08:00
Eric
8979228e0b fix: 修复 ssh 私钥推送等问题 2022-12-13 16:21:54 +08:00
吴小白
024beca690 Merge pull request #9200 from jumpserver/pr@v2.28@perf_support_openid_pkce
perf: OpenID支持PKCE方式对接
2022-12-13 16:12:17 +08:00
jiangweidong
5c0359e394 perf: OpenID支持PKCE方式对接 2022-12-13 15:11:21 +08:00
feng
4ce4bde368 fix: ticket xss inject 2022-12-12 17:03:29 +08:00
halo
809bad271a fix: 密钥指纹参数 2022-12-09 13:41:38 +08:00
15 changed files with 221 additions and 126 deletions

2
GITSHA
View File

@@ -1 +1 @@
d3bfc0384977a6910caa7f9e8f12482427842f7d
81dee0c403f17a69eec836ae8cdb1e8e1a9fdd7a

View File

@@ -1,6 +1,5 @@
# -*- coding: utf-8 -*-
#
import io
import os
import uuid
from hashlib import md5
@@ -18,7 +17,9 @@ from common.utils import random_string
from common.utils import (
ssh_key_string_to_obj, ssh_key_gen, get_logger, lazyproperty
)
from common.utils.encode import parse_ssh_public_key_str
from common.utils.encode import (
parse_ssh_public_key_str, parse_ssh_private_key_str
)
from orgs.mixins.models import OrgModelMixin
logger = get_logger(__file__)
@@ -62,16 +63,16 @@ class AuthMixin:
@property
def ssh_key_fingerprint(self):
public_key = None
if self.public_key:
public_key = self.public_key
elif self.private_key:
try:
public_key = parse_ssh_public_key_str(private_key=self.private_key, password=self.password)
public_key = parse_ssh_public_key_str(self.private_key, password=self.password)
except IOError as e:
return str(e)
else:
if not public_key:
return ''
public_key_obj = sshpubkeys.SSHKey(public_key)
fingerprint = public_key_obj.hash_md5()
return fingerprint
@@ -86,24 +87,27 @@ class AuthMixin:
@property
def private_key_file(self):
if not self.private_key_obj:
if not self.private_key:
return None
private_key_str = parse_ssh_private_key_str(self.private_key,
password=self.password)
if not private_key_str:
return None
project_dir = settings.PROJECT_DIR
tmp_dir = os.path.join(project_dir, 'tmp')
key_name = '.' + md5(self.private_key.encode('utf-8')).hexdigest()
key_path = os.path.join(tmp_dir, key_name)
if not os.path.exists(key_path):
self.private_key_obj.write_private_key_file(key_path)
with open(key_path, 'w') as f:
f.write(private_key_str)
os.chmod(key_path, 0o400)
return key_path
def get_private_key(self):
if not self.private_key_obj:
if not self.private_key:
return None
string_io = io.StringIO()
self.private_key_obj.write_private_key(string_io)
private_key = string_io.getvalue()
return private_key
return parse_ssh_private_key_str(self.private_key,
password=self.password)
@property
def public_key_obj(self):

View File

@@ -2,6 +2,7 @@
#
import requests
from django.utils.translation import gettext_lazy as _
from django.contrib.auth import get_user_model
from django.utils.http import urlencode
from django.conf import settings
@@ -90,8 +91,12 @@ class OAuth2Backend(JMSModelBackend):
request, path=reverse(settings.AUTH_OAUTH2_AUTH_LOGIN_CALLBACK_URL_NAME)
)
}
access_token_url = '{url}?{query}'.format(
url=settings.AUTH_OAUTH2_ACCESS_TOKEN_ENDPOINT, query=urlencode(query_dict)
if '?' in settings.AUTH_OAUTH2_ACCESS_TOKEN_ENDPOINT:
separator = '&'
else:
separator = '?'
access_token_url = '{url}{separator}{query}'.format(
url=settings.AUTH_OAUTH2_ACCESS_TOKEN_ENDPOINT, separator=separator, query=urlencode(query_dict)
)
token_method = settings.AUTH_OAUTH2_ACCESS_TOKEN_METHOD.lower()
requests_func = getattr(requests, token_method, requests.get)
@@ -118,8 +123,12 @@ class OAuth2Backend(JMSModelBackend):
}
logger.debug(log_prompt.format('Get userinfo endpoint'))
userinfo_url = '{url}?{query}'.format(
url=settings.AUTH_OAUTH2_PROVIDER_USERINFO_ENDPOINT,
if '?' in settings.AUTH_OAUTH2_PROVIDER_USERINFO_ENDPOINT:
separator = '&'
else:
separator = '?'
userinfo_url = '{url}{separator}{query}'.format(
url=settings.AUTH_OAUTH2_PROVIDER_USERINFO_ENDPOINT, separator=separator,
query=urlencode(query_dict)
)
userinfo_response = requests.get(userinfo_url, headers=headers)

View File

@@ -26,8 +26,13 @@ class OAuth2AuthRequestView(View):
)
}
redirect_url = '{url}?{query}'.format(
if '?' in settings.AUTH_OAUTH2_PROVIDER_AUTHORIZATION_ENDPOINT:
separator = '&'
else:
separator = '?'
redirect_url = '{url}{separator}{query}'.format(
url=settings.AUTH_OAUTH2_PROVIDER_AUTHORIZATION_ENDPOINT,
separator=separator,
query=urlencode(query_dict)
)
logger.debug(log_prompt.format('Redirect login url'))

View File

@@ -88,7 +88,7 @@ class OIDCAuthCodeBackend(OIDCBaseBackend):
"""
@ssl_verification
def authenticate(self, request, nonce=None, **kwargs):
def authenticate(self, request, nonce=None, code_verifier=None, **kwargs):
""" Authenticates users in case of the OpenID Connect Authorization code flow. """
log_prompt = "Process authenticate [OIDCAuthCodeBackend]: {}"
logger.debug(log_prompt.format('start'))
@@ -134,6 +134,8 @@ class OIDCAuthCodeBackend(OIDCBaseBackend):
request, path=reverse(settings.AUTH_OPENID_AUTH_LOGIN_CALLBACK_URL_NAME)
)
}
if settings.AUTH_OPENID_PKCE and code_verifier:
token_payload['code_verifier'] = code_verifier
if settings.AUTH_OPENID_CLIENT_AUTH_METHOD == 'client_secret_post':
token_payload.update({
'client_id': settings.AUTH_OPENID_CLIENT_ID,

View File

@@ -9,7 +9,10 @@
"""
import base64
import hashlib
import time
import secrets
from django.conf import settings
from django.contrib import auth
@@ -38,6 +41,19 @@ class OIDCAuthRequestView(View):
http_method_names = ['get', ]
@staticmethod
def gen_code_verifier(length=128):
# length range 43 ~ 128
return secrets.token_urlsafe(length-32)
@staticmethod
def gen_code_challenge(code_verifier, code_challenge_method):
if code_challenge_method == 'plain':
return code_verifier
h = hashlib.sha256(code_verifier.encode('ascii')).digest()
b = base64.urlsafe_b64encode(h)
return b.decode('ascii')[:-1]
def get(self, request):
""" Processes GET requests. """
@@ -56,6 +72,16 @@ class OIDCAuthRequestView(View):
)
})
if settings.AUTH_OPENID_PKCE:
code_verifier = self.gen_code_verifier()
code_challenge_method = settings.AUTH_OPENID_CODE_CHALLENGE_METHOD or 'S256'
code_challenge = self.gen_code_challenge(code_verifier, code_challenge_method)
authentication_request_params.update({
'code_challenge_method': code_challenge_method,
'code_challenge': code_challenge
})
request.session['oidc_auth_code_verifier'] = code_verifier
# States should be used! They are recommended in order to maintain state between the
# authentication request and the callback.
if settings.AUTH_OPENID_USE_STATE:
@@ -138,8 +164,9 @@ class OIDCAuthCallbackView(View):
# Authenticates the end-user.
next_url = request.session.get('oidc_auth_next_url', None)
code_verifier = request.session.get('oidc_auth_code_verifier', None)
logger.debug(log_prompt.format('Process authenticate'))
user = auth.authenticate(nonce=nonce, request=request)
user = auth.authenticate(nonce=nonce, request=request, code_verifier=code_verifier)
if user and user.is_valid:
logger.debug(log_prompt.format('Login: {}'.format(user)))
auth.login(self.request, user)

View File

@@ -79,7 +79,7 @@ _supported_paramiko_ssh_key_types = (
def ssh_key_string_to_obj(text, password=None):
key = None
for ssh_key_type in _supported_paramiko_ssh_key_types:
if not isinstance(ssh_key_type, paramiko.PKey):
if not issubclass(ssh_key_type, paramiko.PKey):
continue
try:
key = ssh_key_type.from_private_key(StringIO(text), password=password)

View File

@@ -270,6 +270,8 @@ class Config(dict):
'AUTH_OPENID_USER_ATTR_MAP': {
'name': 'name', 'username': 'preferred_username', 'email': 'email'
},
'AUTH_OPENID_PKCE': False,
'AUTH_OPENID_CODE_CHALLENGE_METHOD': 'S256',
# OpenID 新配置参数 (version >= 1.5.9)
'AUTH_OPENID_PROVIDER_ENDPOINT': 'https://oidc.example.com/',

View File

@@ -78,6 +78,8 @@ AUTH_OPENID_SHARE_SESSION = CONFIG.AUTH_OPENID_SHARE_SESSION
AUTH_OPENID_IGNORE_SSL_VERIFICATION = CONFIG.AUTH_OPENID_IGNORE_SSL_VERIFICATION
AUTH_OPENID_ALWAYS_UPDATE_USER = CONFIG.AUTH_OPENID_ALWAYS_UPDATE_USER
AUTH_OPENID_USER_ATTR_MAP = CONFIG.AUTH_OPENID_USER_ATTR_MAP
AUTH_OPENID_PKCE = CONFIG.AUTH_OPENID_PKCE
AUTH_OPENID_CODE_CHALLENGE_METHOD = CONFIG.AUTH_OPENID_CODE_CHALLENGE_METHOD
AUTH_OPENID_AUTH_LOGIN_URL_NAME = 'authentication:openid:login'
AUTH_OPENID_AUTH_LOGIN_CALLBACK_URL_NAME = 'authentication:openid:login-callback'
AUTH_OPENID_AUTH_LOGOUT_URL_NAME = 'authentication:openid:logout'

View File

@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-11-17 17:34+0800\n"
"POT-Creation-Date: 2022-12-13 15:01+0800\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -24,13 +24,13 @@ msgstr "Acls"
#: acls/models/base.py:25 acls/serializers/login_asset_acl.py:47
#: applications/models/application.py:219 assets/models/asset.py:138
#: assets/models/base.py:175 assets/models/cluster.py:18
#: assets/models/base.py:173 assets/models/cluster.py:18
#: assets/models/cmd_filter.py:27 assets/models/domain.py:23
#: assets/models/group.py:20 assets/models/label.py:18 ops/mixin.py:24
#: orgs/models.py:70 perms/models/base.py:83 rbac/models/role.py:29
#: settings/models.py:33 settings/serializers/sms.py:6
#: terminal/models/endpoint.py:14 terminal/models/endpoint.py:87
#: terminal/models/storage.py:27 terminal/models/task.py:16
#: terminal/models/storage.py:26 terminal/models/task.py:16
#: terminal/models/terminal.py:101 users/forms/profile.py:33
#: users/models/group.py:15 users/models/user.py:673
#: xpack/plugins/cloud/models.py:27
@@ -55,14 +55,14 @@ msgstr "アクティブ"
#: acls/models/base.py:32 applications/models/application.py:232
#: assets/models/asset.py:143 assets/models/asset.py:231
#: assets/models/backup.py:54 assets/models/base.py:180
#: assets/models/backup.py:54 assets/models/base.py:178
#: assets/models/cluster.py:29 assets/models/cmd_filter.py:52
#: assets/models/cmd_filter.py:100 assets/models/domain.py:24
#: assets/models/domain.py:65 assets/models/group.py:23
#: assets/models/label.py:23 ops/models/adhoc.py:38 orgs/models.py:73
#: perms/models/base.py:93 rbac/models/role.py:37 settings/models.py:38
#: terminal/models/endpoint.py:22 terminal/models/endpoint.py:97
#: terminal/models/storage.py:30 terminal/models/terminal.py:115
#: terminal/models/storage.py:29 terminal/models/terminal.py:115
#: tickets/models/comment.py:32 tickets/models/ticket/general.py:288
#: users/models/group.py:16 users/models/user.py:712
#: xpack/plugins/change_auth_plan/models/base.py:44
@@ -155,7 +155,7 @@ msgid "Format for comma-delimited string, with * indicating a match all. "
msgstr "コンマ区切り文字列の形式。* はすべて一致することを示します。"
#: acls/serializers/login_acl.py:15 acls/serializers/login_asset_acl.py:17
#: acls/serializers/login_asset_acl.py:51 assets/models/base.py:176
#: acls/serializers/login_asset_acl.py:51 assets/models/base.py:174
#: assets/models/gathered_user.py:15 audits/models.py:139
#: authentication/forms.py:25 authentication/forms.py:27
#: authentication/models.py:260
@@ -310,7 +310,7 @@ msgstr "カテゴリ"
#: assets/models/cmd_filter.py:86 assets/models/user.py:251
#: authentication/models.py:70 perms/models/application_permission.py:24
#: perms/serializers/application/user_permission.py:34
#: terminal/models/storage.py:59 terminal/models/storage.py:145
#: terminal/models/storage.py:58 terminal/models/storage.py:147
#: tickets/models/comment.py:26 tickets/models/flow.py:57
#: tickets/models/ticket/apply_application.py:18
#: tickets/models/ticket/general.py:273
@@ -353,7 +353,7 @@ msgid "Type display"
msgstr "タイプ表示"
#: applications/serializers/application.py:105 assets/models/asset.py:230
#: assets/models/base.py:181 assets/models/cluster.py:26
#: assets/models/base.py:179 assets/models/cluster.py:26
#: assets/models/cmd_filter.py:53 assets/models/domain.py:26
#: assets/models/gathered_user.py:19 assets/models/group.py:22
#: assets/models/label.py:25 assets/serializers/account.py:18
@@ -367,7 +367,7 @@ msgstr "タイプ表示"
msgid "Date created"
msgstr "作成された日付"
#: applications/serializers/application.py:106 assets/models/base.py:182
#: applications/serializers/application.py:106 assets/models/base.py:180
#: assets/models/cmd_filter.py:54 assets/models/gathered_user.py:20
#: assets/serializers/account.py:21 assets/serializers/cmd_filter.py:29
#: assets/serializers/cmd_filter.py:49 common/db/models.py:117
@@ -650,7 +650,7 @@ msgstr "資産番号"
msgid "Labels"
msgstr "ラベル"
#: assets/models/asset.py:229 assets/models/base.py:183
#: assets/models/asset.py:229 assets/models/base.py:181
#: assets/models/cluster.py:28 assets/models/cmd_filter.py:56
#: assets/models/cmd_filter.py:103 assets/models/group.py:21
#: common/db/models.py:114 common/mixins/models.py:49 orgs/models.py:71
@@ -786,32 +786,32 @@ msgstr "成功は"
msgid "Account backup execution"
msgstr "アカウントバックアップの実行"
#: assets/models/base.py:30 assets/tasks/const.py:51 audits/const.py:5
#: assets/models/base.py:28 assets/tasks/const.py:51 audits/const.py:5
#: common/utils/ip/geoip/utils.py:31 common/utils/ip/geoip/utils.py:37
#: common/utils/ip/utils.py:84
msgid "Unknown"
msgstr "不明"
#: assets/models/base.py:31
#: assets/models/base.py:29
msgid "Ok"
msgstr "OK"
#: assets/models/base.py:32 audits/models.py:136
#: assets/models/base.py:30 audits/models.py:136
#: xpack/plugins/change_auth_plan/serializers/app.py:88
#: xpack/plugins/change_auth_plan/serializers/asset.py:199
#: xpack/plugins/cloud/const.py:41
msgid "Failed"
msgstr "失敗しました"
#: assets/models/base.py:38 assets/serializers/domain.py:47
#: assets/models/base.py:36 assets/serializers/domain.py:47
msgid "Connectivity"
msgstr "接続性"
#: assets/models/base.py:40 authentication/models.py:263
#: assets/models/base.py:38 authentication/models.py:263
msgid "Date verified"
msgstr "確認済みの日付"
#: assets/models/base.py:177 assets/serializers/base.py:15
#: assets/models/base.py:175 assets/serializers/base.py:14
#: assets/serializers/base.py:37 assets/serializers/system_user.py:29
#: audits/signal_handlers.py:58 authentication/confirm/password.py:9
#: authentication/forms.py:32
@@ -829,14 +829,14 @@ msgstr "確認済みの日付"
msgid "Password"
msgstr "パスワード"
#: assets/models/base.py:178 assets/serializers/base.py:41
#: assets/models/base.py:176 assets/serializers/base.py:41
#: xpack/plugins/change_auth_plan/models/asset.py:53
#: xpack/plugins/change_auth_plan/models/asset.py:130
#: xpack/plugins/change_auth_plan/models/asset.py:206
msgid "SSH private key"
msgstr "SSH秘密鍵"
#: assets/models/base.py:179 xpack/plugins/change_auth_plan/models/asset.py:56
#: assets/models/base.py:177 xpack/plugins/change_auth_plan/models/asset.py:56
#: xpack/plugins/change_auth_plan/models/asset.py:126
#: xpack/plugins/change_auth_plan/models/asset.py:202
msgid "SSH public key"
@@ -1192,7 +1192,7 @@ msgstr "ssh秘密鍵"
msgid "Key password"
msgstr "キーパスワード"
#: assets/serializers/base.py:58
#: assets/serializers/base.py:58 assets/serializers/utils.py:24
msgid "private key invalid or passphrase error"
msgstr "秘密鍵が無効またはpassphraseエラー"
@@ -1305,15 +1305,15 @@ msgstr "組織名"
msgid "Asset hostname"
msgstr "資産ホスト名"
#: assets/serializers/utils.py:11
#: assets/serializers/utils.py:13
msgid "Password can not contains `{{` "
msgstr "パスワードには '{{' を含まない"
#: assets/serializers/utils.py:14
#: assets/serializers/utils.py:16
msgid "Password can not contains `'` "
msgstr "パスワードには `'` を含まない"
#: assets/serializers/utils.py:16
#: assets/serializers/utils.py:18
msgid "Password can not contains `\"` "
msgstr "パスワードには `\"` を含まない"
@@ -2263,7 +2263,7 @@ msgstr "コードエラー"
#: authentication/templates/authentication/_msg_reset_password_code.html:9
#: authentication/templates/authentication/_msg_rest_password_success.html:2
#: authentication/templates/authentication/_msg_rest_public_key_success.html:2
#: jumpserver/conf.py:413 ops/tasks.py:145 ops/tasks.py:148
#: jumpserver/conf.py:416 ops/tasks.py:145 ops/tasks.py:148
#: perms/templates/perms/_msg_item_permissions_expire.html:3
#: perms/templates/perms/_msg_permed_items_expire.html:3
#: tickets/templates/tickets/approve_check_password.html:33
@@ -2747,11 +2747,11 @@ msgstr "特殊文字を含むべきではない"
msgid "The mobile phone number format is incorrect"
msgstr "携帯電話番号の形式が正しくありません"
#: jumpserver/conf.py:412
#: jumpserver/conf.py:415
msgid "Create account successfully"
msgstr "アカウントを正常に作成"
#: jumpserver/conf.py:414
#: jumpserver/conf.py:417
msgid "Your account has been created successfully"
msgstr "アカウントが正常に作成されました"
@@ -3603,7 +3603,7 @@ msgstr "CAS"
msgid "Enable CAS Auth"
msgstr "CAS 認証の有効化"
#: settings/serializers/auth/cas.py:13 settings/serializers/auth/oidc.py:49
#: settings/serializers/auth/cas.py:13 settings/serializers/auth/oidc.py:54
msgid "Server url"
msgstr "サービス側アドレス"
@@ -3723,11 +3723,11 @@ msgstr "クライアントID"
msgid "Client Secret"
msgstr "クライアント秘密"
#: settings/serializers/auth/oauth2.py:40 settings/serializers/auth/oidc.py:63
#: settings/serializers/auth/oauth2.py:40 settings/serializers/auth/oidc.py:68
msgid "Provider auth endpoint"
msgstr "認証エンドポイントアドレス"
#: settings/serializers/auth/oauth2.py:43 settings/serializers/auth/oidc.py:66
#: settings/serializers/auth/oauth2.py:43 settings/serializers/auth/oidc.py:71
msgid "Provider token endpoint"
msgstr "プロバイダートークンエンドポイント"
@@ -3735,15 +3735,15 @@ msgstr "プロバイダートークンエンドポイント"
msgid "Client authentication method"
msgstr "クライアント認証方式"
#: settings/serializers/auth/oauth2.py:50 settings/serializers/auth/oidc.py:72
#: settings/serializers/auth/oauth2.py:50 settings/serializers/auth/oidc.py:77
msgid "Provider userinfo endpoint"
msgstr "プロバイダーuserinfoエンドポイント"
#: settings/serializers/auth/oauth2.py:53 settings/serializers/auth/oidc.py:75
#: settings/serializers/auth/oauth2.py:53 settings/serializers/auth/oidc.py:80
msgid "Provider end session endpoint"
msgstr "プロバイダーのセッション終了エンドポイント"
#: settings/serializers/auth/oauth2.py:60 settings/serializers/auth/oidc.py:93
#: settings/serializers/auth/oauth2.py:60 settings/serializers/auth/oidc.py:98
#: settings/serializers/auth/saml2.py:35
msgid "Always update user"
msgstr "常にユーザーを更新"
@@ -3772,51 +3772,59 @@ msgstr ""
"ユーザー属性マッピングは、OpenIDのユーザー属性をjumpserverユーザーにマッピン"
"グする方法、username, name,emailはjumpserverのユーザーが必要とする属性です"
#: settings/serializers/auth/oidc.py:46
#: settings/serializers/auth/oidc.py:41
msgid "Enable PKCE"
msgstr "启启PKCE"
#: settings/serializers/auth/oidc.py:43
msgid "Code challenge method"
msgstr "Code暗号化方式です"
#: settings/serializers/auth/oidc.py:51
msgid "Use Keycloak"
msgstr "Keycloakを使用する"
#: settings/serializers/auth/oidc.py:52
#: settings/serializers/auth/oidc.py:57
msgid "Realm name"
msgstr "レルム名"
#: settings/serializers/auth/oidc.py:58
#: settings/serializers/auth/oidc.py:63
msgid "Enable OPENID Auth"
msgstr "OIDC認証の有効化"
#: settings/serializers/auth/oidc.py:60
#: settings/serializers/auth/oidc.py:65
msgid "Provider endpoint"
msgstr "プロバイダーエンドポイント"
#: settings/serializers/auth/oidc.py:69
#: settings/serializers/auth/oidc.py:74
msgid "Provider jwks endpoint"
msgstr "プロバイダーjwksエンドポイント"
#: settings/serializers/auth/oidc.py:78
#: settings/serializers/auth/oidc.py:83
msgid "Provider sign alg"
msgstr "プロビダーサインalg"
#: settings/serializers/auth/oidc.py:81
#: settings/serializers/auth/oidc.py:86
msgid "Provider sign key"
msgstr "プロバイダ署名キー"
#: settings/serializers/auth/oidc.py:83
#: settings/serializers/auth/oidc.py:88
msgid "Scopes"
msgstr "スコープ"
#: settings/serializers/auth/oidc.py:85
#: settings/serializers/auth/oidc.py:90
msgid "Id token max age"
msgstr "IDトークンの最大年齢"
#: settings/serializers/auth/oidc.py:88
#: settings/serializers/auth/oidc.py:93
msgid "Id token include claims"
msgstr "IDトークンにはクレームが含まれます"
#: settings/serializers/auth/oidc.py:90
#: settings/serializers/auth/oidc.py:95
msgid "Use state"
msgstr "使用状態"
#: settings/serializers/auth/oidc.py:91
#: settings/serializers/auth/oidc.py:96
msgid "Use nonce"
msgstr "Nonceを使用"
@@ -5139,15 +5147,15 @@ msgstr "スレッド"
msgid "Boot Time"
msgstr "ブート時間"
#: terminal/models/storage.py:29
#: terminal/models/storage.py:28
msgid "Default storage"
msgstr "デフォルトのストレージ"
#: terminal/models/storage.py:139 terminal/models/terminal.py:109
#: terminal/models/storage.py:141 terminal/models/terminal.py:109
msgid "Command storage"
msgstr "コマンドストレージ"
#: terminal/models/storage.py:199 terminal/models/terminal.py:110
#: terminal/models/storage.py:201 terminal/models/terminal.py:110
msgid "Replay storage"
msgstr "再生ストレージ"
@@ -5444,19 +5452,19 @@ msgstr ""
"チケットのタイトル: {} チケット申請者: {} チケットプロセッサ: {} チケットID: "
"{}"
#: tickets/handlers/base.py:84
#: tickets/handlers/base.py:86
msgid "Change field"
msgstr "フィールドを変更"
#: tickets/handlers/base.py:84
#: tickets/handlers/base.py:86
msgid "Before change"
msgstr "変更前"
#: tickets/handlers/base.py:84
#: tickets/handlers/base.py:86
msgid "After change"
msgstr "変更後"
#: tickets/handlers/base.py:96
#: tickets/handlers/base.py:98
msgid "{} {} the ticket"
msgstr "{} {} チケット"

View File

@@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: JumpServer 0.3.3\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2022-11-17 17:34+0800\n"
"POT-Creation-Date: 2022-12-13 15:00+0800\n"
"PO-Revision-Date: 2021-05-20 10:54+0800\n"
"Last-Translator: ibuler <ibuler@qq.com>\n"
"Language-Team: JumpServer team<ibuler@qq.com>\n"
@@ -23,13 +23,13 @@ msgstr "访问控制"
#: acls/models/base.py:25 acls/serializers/login_asset_acl.py:47
#: applications/models/application.py:219 assets/models/asset.py:138
#: assets/models/base.py:175 assets/models/cluster.py:18
#: assets/models/base.py:173 assets/models/cluster.py:18
#: assets/models/cmd_filter.py:27 assets/models/domain.py:23
#: assets/models/group.py:20 assets/models/label.py:18 ops/mixin.py:24
#: orgs/models.py:70 perms/models/base.py:83 rbac/models/role.py:29
#: settings/models.py:33 settings/serializers/sms.py:6
#: terminal/models/endpoint.py:14 terminal/models/endpoint.py:87
#: terminal/models/storage.py:27 terminal/models/task.py:16
#: terminal/models/storage.py:26 terminal/models/task.py:16
#: terminal/models/terminal.py:101 users/forms/profile.py:33
#: users/models/group.py:15 users/models/user.py:673
#: xpack/plugins/cloud/models.py:27
@@ -54,14 +54,14 @@ msgstr "激活中"
#: acls/models/base.py:32 applications/models/application.py:232
#: assets/models/asset.py:143 assets/models/asset.py:231
#: assets/models/backup.py:54 assets/models/base.py:180
#: assets/models/backup.py:54 assets/models/base.py:178
#: assets/models/cluster.py:29 assets/models/cmd_filter.py:52
#: assets/models/cmd_filter.py:100 assets/models/domain.py:24
#: assets/models/domain.py:65 assets/models/group.py:23
#: assets/models/label.py:23 ops/models/adhoc.py:38 orgs/models.py:73
#: perms/models/base.py:93 rbac/models/role.py:37 settings/models.py:38
#: terminal/models/endpoint.py:22 terminal/models/endpoint.py:97
#: terminal/models/storage.py:30 terminal/models/terminal.py:115
#: terminal/models/storage.py:29 terminal/models/terminal.py:115
#: tickets/models/comment.py:32 tickets/models/ticket/general.py:288
#: users/models/group.py:16 users/models/user.py:712
#: xpack/plugins/change_auth_plan/models/base.py:44
@@ -154,7 +154,7 @@ msgid "Format for comma-delimited string, with * indicating a match all. "
msgstr "格式为逗号分隔的字符串, * 表示匹配所有. "
#: acls/serializers/login_acl.py:15 acls/serializers/login_asset_acl.py:17
#: acls/serializers/login_asset_acl.py:51 assets/models/base.py:176
#: acls/serializers/login_asset_acl.py:51 assets/models/base.py:174
#: assets/models/gathered_user.py:15 audits/models.py:139
#: authentication/forms.py:25 authentication/forms.py:27
#: authentication/models.py:260
@@ -305,7 +305,7 @@ msgstr "类别"
#: assets/models/cmd_filter.py:86 assets/models/user.py:251
#: authentication/models.py:70 perms/models/application_permission.py:24
#: perms/serializers/application/user_permission.py:34
#: terminal/models/storage.py:59 terminal/models/storage.py:145
#: terminal/models/storage.py:58 terminal/models/storage.py:147
#: tickets/models/comment.py:26 tickets/models/flow.py:57
#: tickets/models/ticket/apply_application.py:18
#: tickets/models/ticket/general.py:273
@@ -348,7 +348,7 @@ msgid "Type display"
msgstr "类型名称"
#: applications/serializers/application.py:105 assets/models/asset.py:230
#: assets/models/base.py:181 assets/models/cluster.py:26
#: assets/models/base.py:179 assets/models/cluster.py:26
#: assets/models/cmd_filter.py:53 assets/models/domain.py:26
#: assets/models/gathered_user.py:19 assets/models/group.py:22
#: assets/models/label.py:25 assets/serializers/account.py:18
@@ -362,7 +362,7 @@ msgstr "类型名称"
msgid "Date created"
msgstr "创建日期"
#: applications/serializers/application.py:106 assets/models/base.py:182
#: applications/serializers/application.py:106 assets/models/base.py:180
#: assets/models/cmd_filter.py:54 assets/models/gathered_user.py:20
#: assets/serializers/account.py:21 assets/serializers/cmd_filter.py:29
#: assets/serializers/cmd_filter.py:49 common/db/models.py:117
@@ -643,7 +643,7 @@ msgstr "资产编号"
msgid "Labels"
msgstr "标签管理"
#: assets/models/asset.py:229 assets/models/base.py:183
#: assets/models/asset.py:229 assets/models/base.py:181
#: assets/models/cluster.py:28 assets/models/cmd_filter.py:56
#: assets/models/cmd_filter.py:103 assets/models/group.py:21
#: common/db/models.py:114 common/mixins/models.py:49 orgs/models.py:71
@@ -779,32 +779,32 @@ msgstr "是否成功"
msgid "Account backup execution"
msgstr "账号备份执行"
#: assets/models/base.py:30 assets/tasks/const.py:51 audits/const.py:5
#: assets/models/base.py:28 assets/tasks/const.py:51 audits/const.py:5
#: common/utils/ip/geoip/utils.py:31 common/utils/ip/geoip/utils.py:37
#: common/utils/ip/utils.py:84
msgid "Unknown"
msgstr "未知"
#: assets/models/base.py:31
#: assets/models/base.py:29
msgid "Ok"
msgstr "成功"
#: assets/models/base.py:32 audits/models.py:136
#: assets/models/base.py:30 audits/models.py:136
#: xpack/plugins/change_auth_plan/serializers/app.py:88
#: xpack/plugins/change_auth_plan/serializers/asset.py:199
#: xpack/plugins/cloud/const.py:41
msgid "Failed"
msgstr "失败"
#: assets/models/base.py:38 assets/serializers/domain.py:47
#: assets/models/base.py:36 assets/serializers/domain.py:47
msgid "Connectivity"
msgstr "可连接性"
#: assets/models/base.py:40 authentication/models.py:263
#: assets/models/base.py:38 authentication/models.py:263
msgid "Date verified"
msgstr "校验日期"
#: assets/models/base.py:177 assets/serializers/base.py:15
#: assets/models/base.py:175 assets/serializers/base.py:14
#: assets/serializers/base.py:37 assets/serializers/system_user.py:29
#: audits/signal_handlers.py:58 authentication/confirm/password.py:9
#: authentication/forms.py:32
@@ -822,14 +822,14 @@ msgstr "校验日期"
msgid "Password"
msgstr "密码"
#: assets/models/base.py:178 assets/serializers/base.py:41
#: assets/models/base.py:176 assets/serializers/base.py:41
#: xpack/plugins/change_auth_plan/models/asset.py:53
#: xpack/plugins/change_auth_plan/models/asset.py:130
#: xpack/plugins/change_auth_plan/models/asset.py:206
msgid "SSH private key"
msgstr "SSH密钥"
#: assets/models/base.py:179 xpack/plugins/change_auth_plan/models/asset.py:56
#: assets/models/base.py:177 xpack/plugins/change_auth_plan/models/asset.py:56
#: xpack/plugins/change_auth_plan/models/asset.py:126
#: xpack/plugins/change_auth_plan/models/asset.py:202
msgid "SSH public key"
@@ -1182,7 +1182,7 @@ msgstr "ssh私钥"
msgid "Key password"
msgstr "密钥密码"
#: assets/serializers/base.py:58
#: assets/serializers/base.py:58 assets/serializers/utils.py:24
msgid "private key invalid or passphrase error"
msgstr "密钥不合法或密钥密码错误"
@@ -1295,15 +1295,15 @@ msgstr "组织名称"
msgid "Asset hostname"
msgstr "资产主机名"
#: assets/serializers/utils.py:11
#: assets/serializers/utils.py:13
msgid "Password can not contains `{{` "
msgstr "密码不能包含 `{{` 字符"
#: assets/serializers/utils.py:14
#: assets/serializers/utils.py:16
msgid "Password can not contains `'` "
msgstr "密码不能包含 `'` 字符"
#: assets/serializers/utils.py:16
#: assets/serializers/utils.py:18
msgid "Password can not contains `\"` "
msgstr "密码不能包含 `\"` 字符"
@@ -2233,7 +2233,7 @@ msgstr "代码错误"
#: authentication/templates/authentication/_msg_reset_password_code.html:9
#: authentication/templates/authentication/_msg_rest_password_success.html:2
#: authentication/templates/authentication/_msg_rest_public_key_success.html:2
#: jumpserver/conf.py:413 ops/tasks.py:145 ops/tasks.py:148
#: jumpserver/conf.py:416 ops/tasks.py:145 ops/tasks.py:148
#: perms/templates/perms/_msg_item_permissions_expire.html:3
#: perms/templates/perms/_msg_permed_items_expire.html:3
#: tickets/templates/tickets/approve_check_password.html:33
@@ -2708,11 +2708,11 @@ msgstr "不能包含特殊字符"
msgid "The mobile phone number format is incorrect"
msgstr "手机号格式不正确"
#: jumpserver/conf.py:412
#: jumpserver/conf.py:415
msgid "Create account successfully"
msgstr "创建账号成功"
#: jumpserver/conf.py:414
#: jumpserver/conf.py:417
msgid "Your account has been created successfully"
msgstr "你的账号已创建成功"
@@ -3555,7 +3555,7 @@ msgstr "CAS"
msgid "Enable CAS Auth"
msgstr "启用 CAS 认证"
#: settings/serializers/auth/cas.py:13 settings/serializers/auth/oidc.py:49
#: settings/serializers/auth/cas.py:13 settings/serializers/auth/oidc.py:54
msgid "Server url"
msgstr "服务端地址"
@@ -3675,11 +3675,11 @@ msgstr "客户端 ID"
msgid "Client Secret"
msgstr "客户端密钥"
#: settings/serializers/auth/oauth2.py:40 settings/serializers/auth/oidc.py:63
#: settings/serializers/auth/oauth2.py:40 settings/serializers/auth/oidc.py:68
msgid "Provider auth endpoint"
msgstr "授权端点地址"
#: settings/serializers/auth/oauth2.py:43 settings/serializers/auth/oidc.py:66
#: settings/serializers/auth/oauth2.py:43 settings/serializers/auth/oidc.py:71
msgid "Provider token endpoint"
msgstr "token 端点地址"
@@ -3687,15 +3687,15 @@ msgstr "token 端点地址"
msgid "Client authentication method"
msgstr "客户端认证方式"
#: settings/serializers/auth/oauth2.py:50 settings/serializers/auth/oidc.py:72
#: settings/serializers/auth/oauth2.py:50 settings/serializers/auth/oidc.py:77
msgid "Provider userinfo endpoint"
msgstr "用户信息端点地址"
#: settings/serializers/auth/oauth2.py:53 settings/serializers/auth/oidc.py:75
#: settings/serializers/auth/oauth2.py:53 settings/serializers/auth/oidc.py:80
msgid "Provider end session endpoint"
msgstr "注销会话端点地址"
#: settings/serializers/auth/oauth2.py:60 settings/serializers/auth/oidc.py:93
#: settings/serializers/auth/oauth2.py:60 settings/serializers/auth/oidc.py:98
#: settings/serializers/auth/saml2.py:35
msgid "Always update user"
msgstr "总是更新用户信息"
@@ -3724,51 +3724,59 @@ msgstr ""
"用户属性映射代表怎样将OpenID中用户属性映射到jumpserver用户上username, name,"
"email 是jumpserver的用户需要属性"
#: settings/serializers/auth/oidc.py:46
#: settings/serializers/auth/oidc.py:41
msgid "Enable PKCE"
msgstr "启用 PKCE"
#: settings/serializers/auth/oidc.py:43
msgid "Code challenge method"
msgstr "Code加密方式"
#: settings/serializers/auth/oidc.py:51
msgid "Use Keycloak"
msgstr "使用 Keycloak"
#: settings/serializers/auth/oidc.py:52
#: settings/serializers/auth/oidc.py:57
msgid "Realm name"
msgstr "域"
#: settings/serializers/auth/oidc.py:58
#: settings/serializers/auth/oidc.py:63
msgid "Enable OPENID Auth"
msgstr "启用 OIDC 认证"
#: settings/serializers/auth/oidc.py:60
#: settings/serializers/auth/oidc.py:65
msgid "Provider endpoint"
msgstr "端点地址"
#: settings/serializers/auth/oidc.py:69
#: settings/serializers/auth/oidc.py:74
msgid "Provider jwks endpoint"
msgstr "jwks 端点地址"
#: settings/serializers/auth/oidc.py:78
#: settings/serializers/auth/oidc.py:83
msgid "Provider sign alg"
msgstr "签名算法"
#: settings/serializers/auth/oidc.py:81
#: settings/serializers/auth/oidc.py:86
msgid "Provider sign key"
msgstr "签名 Key"
#: settings/serializers/auth/oidc.py:83
#: settings/serializers/auth/oidc.py:88
msgid "Scopes"
msgstr "连接范围"
#: settings/serializers/auth/oidc.py:85
#: settings/serializers/auth/oidc.py:90
msgid "Id token max age"
msgstr "令牌有效时间"
#: settings/serializers/auth/oidc.py:88
#: settings/serializers/auth/oidc.py:93
msgid "Id token include claims"
msgstr "声明"
#: settings/serializers/auth/oidc.py:90
#: settings/serializers/auth/oidc.py:95
msgid "Use state"
msgstr "使用状态"
#: settings/serializers/auth/oidc.py:91
#: settings/serializers/auth/oidc.py:96
msgid "Use nonce"
msgstr "临时使用"
@@ -5053,15 +5061,15 @@ msgstr "线程数"
msgid "Boot Time"
msgstr "运行时间"
#: terminal/models/storage.py:29
#: terminal/models/storage.py:28
msgid "Default storage"
msgstr "默认存储"
#: terminal/models/storage.py:139 terminal/models/terminal.py:109
#: terminal/models/storage.py:141 terminal/models/terminal.py:109
msgid "Command storage"
msgstr "命令存储"
#: terminal/models/storage.py:199 terminal/models/terminal.py:110
#: terminal/models/storage.py:201 terminal/models/terminal.py:110
msgid "Replay storage"
msgstr "录像存储"
@@ -5351,19 +5359,19 @@ msgid ""
msgstr ""
"通过工单创建, 工单标题: {}, 工单申请人: {}, 工单处理人: {}, 工单 ID: {}"
#: tickets/handlers/base.py:84
#: tickets/handlers/base.py:86
msgid "Change field"
msgstr "变更字段"
#: tickets/handlers/base.py:84
#: tickets/handlers/base.py:86
msgid "Before change"
msgstr "变更前"
#: tickets/handlers/base.py:84
#: tickets/handlers/base.py:86
msgid "After change"
msgstr "变更后"
#: tickets/handlers/base.py:96
#: tickets/handlers/base.py:98
msgid "{} {} the ticket"
msgstr "{} {} 工单"

View File

@@ -38,6 +38,11 @@ class CommonSettingSerializer(serializers.Serializer):
help_text=_('User attr map present how to map OpenID user attr to '
'jumpserver, username,name,email is jumpserver attr')
)
AUTH_OPENID_PKCE = serializers.BooleanField(required=False, label=_('Enable PKCE'))
AUTH_OPENID_CODE_CHALLENGE_METHOD = serializers.ChoiceField(
default='S256', label=_('Code challenge method'),
choices=(('S256', 'HS256'), ('plain', 'Plain'))
)
class KeycloakSettingSerializer(CommonSettingSerializer):

View File

@@ -16,10 +16,10 @@ logger = get_logger(__file__)
@receiver(django_ready)
def init_db_port_mapper(sender, **kwargs):
def check_db_port_mapper(sender, **kwargs):
logger.info('Init db port mapper')
try:
db_port_manager.init()
db_port_manager.check()
except (ProgrammingError,) as e:
pass

View File

@@ -35,9 +35,22 @@ class DBPortManager(object):
def magnus_listen_port_range(self):
return settings.MAGNUS_PORTS
def init(self):
@staticmethod
def fetch_dbs():
with tmp_to_root_org():
db_ids = Application.objects.filter(category=AppCategory.db).values_list('id', flat=True)
dbs = Application.objects.filter(category=AppCategory.db)
return dbs
def check(self):
dbs = self.fetch_dbs()
for db in dbs:
port = self.get_port_by_db(db, raise_exception=False)
if not port:
self.add(db)
def init(self):
dbs = self.fetch_dbs()
db_ids = dbs.values_list('id', flat=True)
db_ids = [str(i) for i in db_ids]
mapper = dict(zip(self.all_available_ports, list(db_ids)))
self.set_mapper(mapper)

View File

@@ -1,3 +1,5 @@
from html import escape
from django.utils.translation import ugettext as _
from django.template.loader import render_to_string
@@ -96,11 +98,19 @@ class BaseHandler:
approve_info = _('{} {} the ticket').format(user_display, state_display)
context = self._diff_prev_approve_context(state)
context.update({'approve_info': approve_info})
body = self.reject_html_script(
render_to_string('tickets/ticket_approve_diff.html', context)
)
data = {
'body': render_to_string('tickets/ticket_approve_diff.html', context),
'body': body,
'user': user,
'user_display': str(user),
'type': 'state',
'state': state
}
return self.ticket.comments.create(**data)
@staticmethod
def reject_html_script(unsafe_html):
safe_html = escape(unsafe_html)
return safe_html