feat: 支持自定义短信认证(文件) (#11784)

* feat: 支持自定义短信认证(文件)

* perf: 翻译

* perf: 还原注释
pull/11797/head
jiangweidong 2023-10-10 18:23:54 +08:00 committed by GitHub
parent 333746e7c4
commit 70f0f55ddb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 193 additions and 84 deletions

View File

@ -10,7 +10,7 @@ logger = get_logger(__file__)
mfa_custom_method = None mfa_custom_method = None
if settings.MFA_CUSTOM: if settings.MFA_CUSTOM:
""" 保证自定义认证方法在服务运行时不能被更改,只在第一次调用时加载一次 """ """ 保证自定义方法在服务运行时不能被更改,只在第一次调用时加载一次 """
try: try:
mfa_custom_method_path = 'data.mfa.main.check_code' mfa_custom_method_path = 'data.mfa.main.check_code'
mfa_custom_method = import_string(mfa_custom_method_path) mfa_custom_method = import_string(mfa_custom_method_path)

View File

@ -30,7 +30,7 @@ class CustomSMS(BaseSMSClient):
code=template_param.get('code'), phone_numbers=phone_numbers_str code=template_param.get('code'), phone_numbers=phone_numbers_str
) )
logger.info(f'Custom sms send: phone_numbers={phone_numbers}param={params}') logger.info(f'Custom sms send: phone_numbers={phone_numbers}, param={params}')
if settings.CUSTOM_SMS_REQUEST_METHOD == 'post': if settings.CUSTOM_SMS_REQUEST_METHOD == 'post':
action = requests.post action = requests.post
kwargs = {'json': params} kwargs = {'json': params}

View File

@ -0,0 +1,50 @@
import os
from collections import OrderedDict
from django.conf import settings
from django.utils.translation import gettext_lazy as _
from django.utils.module_loading import import_string
from common.utils import get_logger
from common.exceptions import JMSException
from jumpserver.settings import get_file_md5
from .base import BaseSMSClient
logger = get_logger(__file__)
custom_sms_method = None
SMS_CUSTOM_FILE_MD5 = settings.SMS_CUSTOM_FILE_MD5
SMS_CUSTOM_FILE_PATH = os.path.join(settings.PROJECT_DIR, 'data', 'sms', 'main.py')
if SMS_CUSTOM_FILE_MD5 == get_file_md5(SMS_CUSTOM_FILE_PATH):
try:
custom_sms_method_path = 'data.sms.main.send_sms'
custom_sms_method = import_string(custom_sms_method_path)
except Exception as e:
logger.warning('Import custom sms method failed: {}, Maybe not enabled'.format(e))
class CustomFileSMS(BaseSMSClient):
@classmethod
def new_from_settings(cls):
return cls()
@staticmethod
def need_pre_check():
return False
def send_sms(self, phone_numbers: list, template_param: OrderedDict, **kwargs):
if not callable(custom_sms_method):
raise JMSException(_('The custom sms file is invalid'))
try:
logger.info(f'Custom file sms send: phone_numbers={phone_numbers}, param={template_param}')
custom_sms_method(phone_numbers, template_param, **kwargs)
except Exception as err:
raise JMSException(_('SMS sending failed[%s]: %s') % (f"{_('Custom type')}({_('File')})", err))
client = CustomFileSMS

View File

@ -17,7 +17,8 @@ class BACKENDS(TextChoices):
TENCENT = 'tencent', _('Tencent cloud') TENCENT = 'tencent', _('Tencent cloud')
HUAWEI = 'huawei', _('Huawei Cloud') HUAWEI = 'huawei', _('Huawei Cloud')
CMPP2 = 'cmpp2', _('CMPP v2.0') CMPP2 = 'cmpp2', _('CMPP v2.0')
Custom = 'custom', _('Custom type') CUSTOM = 'custom', _('Custom type')
CUSTOM_FILE = 'custom_file', f"{_('Custom type')}({_('File')})"
class SMS: class SMS:

View File

@ -67,7 +67,7 @@ class SendAndVerifyCodeUtil(object):
return cache.get(self.key) return cache.get(self.key)
def __generate(self): def __generate(self):
code = random_string(4, lower=False, upper=False) code = random_string(settings.SMS_CODE_LENGTH, lower=False, upper=False)
self.code = code self.code = code
return code return code

View File

@ -247,10 +247,11 @@ class Config(dict):
'AUTH_CUSTOM': False, 'AUTH_CUSTOM': False,
'AUTH_CUSTOM_FILE_MD5': '', 'AUTH_CUSTOM_FILE_MD5': '',
# Custom Config
'MFA_CUSTOM': False, 'MFA_CUSTOM': False,
'MFA_CUSTOM_FILE_MD5': '', 'MFA_CUSTOM_FILE_MD5': '',
'SMS_CUSTOM_FILE_MD5': '',
# 临时密码 # 临时密码
'AUTH_TEMP_TOKEN': False, 'AUTH_TEMP_TOKEN': False,
@ -409,6 +410,7 @@ class Config(dict):
'SMS_ENABLED': False, 'SMS_ENABLED': False,
'SMS_BACKEND': '', 'SMS_BACKEND': '',
'SMS_CODE_LENGTH': 4,
'SMS_TEST_PHONE': '', 'SMS_TEST_PHONE': '',
'ALIBABA_ACCESS_KEY_ID': '', 'ALIBABA_ACCESS_KEY_ID': '',
@ -439,7 +441,7 @@ class Config(dict):
'CMPP2_VERIFY_TEMPLATE_CODE': '{code}', 'CMPP2_VERIFY_TEMPLATE_CODE': '{code}',
'CUSTOM_SMS_URL': '', 'CUSTOM_SMS_URL': '',
'CUSTOM_SMS_API_PARAMS': {'phone_numbers': '{phone_numbers}', 'code': '{code}'}, 'CUSTOM_SMS_API_PARAMS': {'phone_numbers': '{phone_numbers}', 'content': _('The verification code is: {code}')},
'CUSTOM_SMS_REQUEST_METHOD': 'get', 'CUSTOM_SMS_REQUEST_METHOD': 'get',
# Email # Email

View File

@ -259,6 +259,9 @@ if MFA_CUSTOM and MFA_CUSTOM_FILE_MD5 == get_file_md5(MFA_CUSTOM_FILE_PATH):
# 自定义多因子认证模块 # 自定义多因子认证模块
MFA_BACKENDS.append(MFA_BACKEND_CUSTOM) MFA_BACKENDS.append(MFA_BACKEND_CUSTOM)
SMS_CUSTOM_FILE_MD5 = CONFIG.SMS_CUSTOM_FILE_MD5
SMS_CUSTOM_FILE_PATH = os.path.join(PROJECT_DIR, 'data', 'sms', 'main.py')
AUTHENTICATION_BACKENDS_THIRD_PARTY = [ AUTHENTICATION_BACKENDS_THIRD_PARTY = [
AUTH_BACKEND_OIDC_CODE, AUTH_BACKEND_CAS, AUTH_BACKEND_OIDC_CODE, AUTH_BACKEND_CAS,
AUTH_BACKEND_SAML2, AUTH_BACKEND_OAUTH2 AUTH_BACKEND_SAML2, AUTH_BACKEND_OAUTH2

View File

@ -169,6 +169,7 @@ TERMINAL_KOKO_SSH_ENABLED = CONFIG.TERMINAL_KOKO_SSH_ENABLED
# SMS enabled # SMS enabled
SMS_ENABLED = CONFIG.SMS_ENABLED SMS_ENABLED = CONFIG.SMS_ENABLED
SMS_BACKEND = CONFIG.SMS_BACKEND SMS_BACKEND = CONFIG.SMS_BACKEND
SMS_CODE_LENGTH = CONFIG.SMS_CODE_LENGTH
SMS_TEST_PHONE = CONFIG.SMS_TEST_PHONE SMS_TEST_PHONE = CONFIG.SMS_TEST_PHONE
# Alibaba # Alibaba
@ -186,6 +187,11 @@ TENCENT_VERIFY_SIGN_NAME = CONFIG.TENCENT_VERIFY_SIGN_NAME
TENCENT_VERIFY_TEMPLATE_CODE = CONFIG.TENCENT_VERIFY_TEMPLATE_CODE TENCENT_VERIFY_TEMPLATE_CODE = CONFIG.TENCENT_VERIFY_TEMPLATE_CODE
TENCENT_SMS_SIGN_AND_TEMPLATES = CONFIG.TENCENT_SMS_SIGN_AND_TEMPLATES TENCENT_SMS_SIGN_AND_TEMPLATES = CONFIG.TENCENT_SMS_SIGN_AND_TEMPLATES
# CUSTOM_SMS
CUSTOM_SMS_URL = CONFIG.CUSTOM_SMS_URL
CUSTOM_SMS_API_PARAMS = CONFIG.CUSTOM_SMS_API_PARAMS
CUSTOM_SMS_REQUEST_METHOD = CONFIG.CUSTOM_SMS_REQUEST_METHOD
# 公告 # 公告
ANNOUNCEMENT_ENABLED = CONFIG.ANNOUNCEMENT_ENABLED ANNOUNCEMENT_ENABLED = CONFIG.ANNOUNCEMENT_ENABLED
ANNOUNCEMENT = CONFIG.ANNOUNCEMENT ANNOUNCEMENT = CONFIG.ANNOUNCEMENT

View File

@ -81,7 +81,7 @@ msgid "Collected"
msgstr "集めました" msgstr "集めました"
#: accounts/const/account.py:27 accounts/serializers/account/account.py:28 #: accounts/const/account.py:27 accounts/serializers/account/account.py:28
#: settings/serializers/auth/sms.py:75 #: settings/serializers/auth/sms.py:79
msgid "Template" msgid "Template"
msgstr "テンプレート" msgstr "テンプレート"
@ -1325,7 +1325,7 @@ msgid "Script"
msgstr "脚本" msgstr "脚本"
#: assets/const/category.py:10 assets/models/asset/host.py:8 #: assets/const/category.py:10 assets/models/asset/host.py:8
#: settings/serializers/auth/radius.py:16 settings/serializers/auth/sms.py:67 #: settings/serializers/auth/radius.py:16 settings/serializers/auth/sms.py:71
#: settings/serializers/feature.py:47 terminal/models/component/endpoint.py:13 #: settings/serializers/feature.py:47 terminal/models/component/endpoint.py:13
#: terminal/serializers/applet.py:17 #: terminal/serializers/applet.py:17
#: xpack/plugins/cloud/serializers/account_attrs.py:72 #: xpack/plugins/cloud/serializers/account_attrs.py:72
@ -1616,7 +1616,7 @@ msgid "Cloud"
msgstr "クラウド サービス" msgstr "クラウド サービス"
#: assets/models/asset/common.py:92 assets/models/platform.py:16 #: assets/models/asset/common.py:92 assets/models/platform.py:16
#: settings/serializers/auth/radius.py:17 settings/serializers/auth/sms.py:68 #: settings/serializers/auth/radius.py:17 settings/serializers/auth/sms.py:72
#: xpack/plugins/cloud/serializers/account_attrs.py:73 #: xpack/plugins/cloud/serializers/account_attrs.py:73
msgid "Port" msgid "Port"
msgstr "ポート" msgstr "ポート"
@ -1692,7 +1692,7 @@ msgid "Proxy"
msgstr "プロキシー" msgstr "プロキシー"
#: assets/models/automations/base.py:22 ops/models/job.py:223 #: assets/models/automations/base.py:22 ops/models/job.py:223
#: settings/serializers/auth/sms.py:99 #: settings/serializers/auth/sms.py:103
msgid "Parameters" msgid "Parameters"
msgstr "パラメータ" msgstr "パラメータ"
@ -2892,7 +2892,7 @@ msgstr "メッセージ検証コードが無効"
#: authentication/mfa/sms.py:12 authentication/serializers/password_mfa.py:16 #: authentication/mfa/sms.py:12 authentication/serializers/password_mfa.py:16
#: authentication/serializers/password_mfa.py:24 #: authentication/serializers/password_mfa.py:24
#: settings/serializers/auth/sms.py:28 users/forms/profile.py:104 #: settings/serializers/auth/sms.py:32 users/forms/profile.py:104
#: users/forms/profile.py:109 users/templates/users/forgot_password.html:112 #: users/forms/profile.py:109 users/templates/users/forgot_password.html:112
#: users/views/profile/reset.py:98 #: users/views/profile/reset.py:98
msgid "SMS" msgid "SMS"
@ -3164,7 +3164,7 @@ msgstr "コードエラー"
#: authentication/templates/authentication/_msg_reset_password_code.html:9 #: authentication/templates/authentication/_msg_reset_password_code.html:9
#: authentication/templates/authentication/_msg_rest_password_success.html:2 #: authentication/templates/authentication/_msg_rest_password_success.html:2
#: authentication/templates/authentication/_msg_rest_public_key_success.html:2 #: authentication/templates/authentication/_msg_rest_public_key_success.html:2
#: jumpserver/conf.py:447 #: jumpserver/conf.py:449
#: perms/templates/perms/_msg_item_permissions_expire.html:3 #: perms/templates/perms/_msg_item_permissions_expire.html:3
#: perms/templates/perms/_msg_permed_items_expire.html:3 #: perms/templates/perms/_msg_permed_items_expire.html:3
#: tickets/templates/tickets/approve_check_password.html:33 #: tickets/templates/tickets/approve_check_password.html:33
@ -3674,6 +3674,15 @@ msgstr "SP idは6ビット"
msgid "Failed to connect to the CMPP gateway server, err: {}" msgid "Failed to connect to the CMPP gateway server, err: {}"
msgstr "接続ゲートウェイサーバエラー, 非: {}" msgstr "接続ゲートウェイサーバエラー, 非: {}"
#: common/sdk/sms/custom_file.py:41
msgid "The custom sms file is invalid"
msgstr "カスタムショートメッセージファイルが無効です"
#: common/sdk/sms/custom_file.py:47
#, python-format
msgid "SMS sending failed[%s]: %s"
msgstr "ショートメッセージの送信に失敗しました[%s]: %s"
#: common/sdk/sms/endpoint.py:16 #: common/sdk/sms/endpoint.py:16
msgid "Alibaba cloud" msgid "Alibaba cloud"
msgstr "アリ雲" msgstr "アリ雲"
@ -3690,11 +3699,11 @@ msgstr "華為雲"
msgid "CMPP v2.0" msgid "CMPP v2.0"
msgstr "CMPP v2.0" msgstr "CMPP v2.0"
#: common/sdk/sms/endpoint.py:31 #: common/sdk/sms/endpoint.py:32
msgid "SMS provider not support: {}" msgid "SMS provider not support: {}"
msgstr "SMSプロバイダーはサポートしていません: {}" msgstr "SMSプロバイダーはサポートしていません: {}"
#: common/sdk/sms/endpoint.py:53 #: common/sdk/sms/endpoint.py:54
msgid "SMS verification code signature or template invalid" msgid "SMS verification code signature or template invalid"
msgstr "SMS検証コードの署名またはテンプレートが無効" msgstr "SMS検証コードの署名またはテンプレートが無効"
@ -3765,11 +3774,15 @@ msgstr "特殊文字を含むべきではない"
msgid "The mobile phone number format is incorrect" msgid "The mobile phone number format is incorrect"
msgstr "携帯電話番号の形式が正しくありません" msgstr "携帯電話番号の形式が正しくありません"
#: jumpserver/conf.py:446 #: jumpserver/conf.py:444
msgid "The verification code is: {code}"
msgstr "認証コードは: {code}"
#: jumpserver/conf.py:448
msgid "Create account successfully" msgid "Create account successfully"
msgstr "アカウントを正常に作成" msgstr "アカウントを正常に作成"
#: jumpserver/conf.py:448 #: jumpserver/conf.py:450
msgid "Your account has been created successfully" msgid "Your account has been created successfully"
msgstr "アカウントが正常に作成されました" msgstr "アカウントが正常に作成されました"
@ -4596,7 +4609,7 @@ msgid "View permission tree"
msgstr "権限ツリーの表示" msgstr "権限ツリーの表示"
#: settings/api/dingtalk.py:31 settings/api/feishu.py:36 #: settings/api/dingtalk.py:31 settings/api/feishu.py:36
#: settings/api/sms.py:153 settings/api/vault.py:40 settings/api/wecom.py:37 #: settings/api/sms.py:160 settings/api/vault.py:40 settings/api/wecom.py:37
msgid "Test success" msgid "Test success"
msgstr "テストの成功" msgstr "テストの成功"
@ -4624,11 +4637,11 @@ msgstr "Ldapユーザーを取得するにはNone"
msgid "Imported {} users successfully (Organization: {})" msgid "Imported {} users successfully (Organization: {})"
msgstr "{} 人のユーザーを正常にインポートしました (組織: {})" msgstr "{} 人のユーザーを正常にインポートしました (組織: {})"
#: settings/api/sms.py:135 #: settings/api/sms.py:142
msgid "Invalid SMS platform" msgid "Invalid SMS platform"
msgstr "無効なショートメッセージプラットフォーム" msgstr "無効なショートメッセージプラットフォーム"
#: settings/api/sms.py:141 #: settings/api/sms.py:148
msgid "test_phone is required" msgid "test_phone is required"
msgstr "携帯番号をテストこのフィールドは必須です" msgstr "携帯番号をテストこのフィールドは必須です"
@ -5034,54 +5047,58 @@ msgstr "SP プライベートキー"
msgid "SP cert" msgid "SP cert"
msgstr "SP 証明書" msgstr "SP 証明書"
#: settings/serializers/auth/sms.py:16 #: settings/serializers/auth/sms.py:17
msgid "Enable SMS" msgid "Enable SMS"
msgstr "SMSの有効化" msgstr "SMSの有効化"
#: settings/serializers/auth/sms.py:18 #: settings/serializers/auth/sms.py:19
msgid "SMS provider / Protocol" msgid "SMS provider / Protocol"
msgstr "SMSプロバイダ / プロトコル" msgstr "SMSプロバイダ / プロトコル"
#: settings/serializers/auth/sms.py:23 settings/serializers/auth/sms.py:45 #: settings/serializers/auth/sms.py:22
#: settings/serializers/auth/sms.py:53 settings/serializers/auth/sms.py:62 msgid "SMS code length"
#: settings/serializers/auth/sms.py:73 settings/serializers/msg.py:76 msgstr "認証コード長"
#: settings/serializers/auth/sms.py:27 settings/serializers/auth/sms.py:49
#: settings/serializers/auth/sms.py:57 settings/serializers/auth/sms.py:66
#: settings/serializers/auth/sms.py:77 settings/serializers/msg.py:76
msgid "Signature" msgid "Signature"
msgstr "署名" msgstr "署名"
#: settings/serializers/auth/sms.py:24 settings/serializers/auth/sms.py:46 #: settings/serializers/auth/sms.py:28 settings/serializers/auth/sms.py:50
#: settings/serializers/auth/sms.py:54 settings/serializers/auth/sms.py:63 #: settings/serializers/auth/sms.py:58 settings/serializers/auth/sms.py:67
msgid "Template code" msgid "Template code"
msgstr "テンプレートコード" msgstr "テンプレートコード"
#: settings/serializers/auth/sms.py:31 #: settings/serializers/auth/sms.py:35
msgid "Test phone" msgid "Test phone"
msgstr "テスト電話" msgstr "テスト電話"
#: settings/serializers/auth/sms.py:60 #: settings/serializers/auth/sms.py:64
msgid "App Access Address" msgid "App Access Address"
msgstr "アプリケーションアドレス" msgstr "アプリケーションアドレス"
#: settings/serializers/auth/sms.py:61 #: settings/serializers/auth/sms.py:65
msgid "Signature channel number" msgid "Signature channel number"
msgstr "署名チャネル番号" msgstr "署名チャネル番号"
#: settings/serializers/auth/sms.py:69 #: settings/serializers/auth/sms.py:73
msgid "Enterprise code(SP id)" msgid "Enterprise code(SP id)"
msgstr "企業コード(SP id)" msgstr "企業コード(SP id)"
#: settings/serializers/auth/sms.py:70 #: settings/serializers/auth/sms.py:74
msgid "Shared secret(Shared secret)" msgid "Shared secret(Shared secret)"
msgstr "パスワードを共有する(Shared secret)" msgstr "パスワードを共有する(Shared secret)"
#: settings/serializers/auth/sms.py:71 #: settings/serializers/auth/sms.py:75
msgid "Original number(Src id)" msgid "Original number(Src id)"
msgstr "元の番号(Src id)" msgstr "元の番号(Src id)"
#: settings/serializers/auth/sms.py:72 #: settings/serializers/auth/sms.py:76
msgid "Business type(Service id)" msgid "Business type(Service id)"
msgstr "ビジネス・タイプ(Service id)" msgstr "ビジネス・タイプ(Service id)"
#: settings/serializers/auth/sms.py:76 #: settings/serializers/auth/sms.py:80
#, python-brace-format #, python-brace-format
msgid "" msgid ""
"Template need contain {code} and Signature + template length does not exceed " "Template need contain {code} and Signature + template length does not exceed "
@ -5092,24 +5109,24 @@ msgstr ""
"満です。たとえば、認証コードは{code}で、有効期間は5分です。他の人には言わない" "満です。たとえば、認証コードは{code}で、有効期間は5分です。他の人には言わない"
"でください。" "でください。"
#: settings/serializers/auth/sms.py:85 #: settings/serializers/auth/sms.py:89
#, python-brace-format #, python-brace-format
msgid "The template needs to contain {code}" msgid "The template needs to contain {code}"
msgstr "テンプレートには{code}を含める必要があります" msgstr "テンプレートには{code}を含める必要があります"
#: settings/serializers/auth/sms.py:88 #: settings/serializers/auth/sms.py:92
msgid "Signature + Template must not exceed 65 words" msgid "Signature + Template must not exceed 65 words"
msgstr "署名+テンプレートの長さは65文字以内" msgstr "署名+テンプレートの長さは65文字以内"
#: settings/serializers/auth/sms.py:97 #: settings/serializers/auth/sms.py:101
msgid "URL" msgid "URL"
msgstr "URL" msgstr "URL"
#: settings/serializers/auth/sms.py:102 #: settings/serializers/auth/sms.py:106
msgid "Request method" msgid "Request method"
msgstr "請求方法です" msgstr "請求方法です"
#: settings/serializers/auth/sms.py:111 #: settings/serializers/auth/sms.py:117
#, python-format #, python-format
msgid "The value in the parameter must contain %s" msgid "The value in the parameter must contain %s"
msgstr "パラメータの値には必ず %s が含まれます" msgstr "パラメータの値には必ず %s が含まれます"

View File

@ -80,7 +80,7 @@ msgid "Collected"
msgstr "收集" msgstr "收集"
#: accounts/const/account.py:27 accounts/serializers/account/account.py:28 #: accounts/const/account.py:27 accounts/serializers/account/account.py:28
#: settings/serializers/auth/sms.py:75 #: settings/serializers/auth/sms.py:79
msgid "Template" msgid "Template"
msgstr "模板" msgstr "模板"
@ -1317,7 +1317,7 @@ msgid "Script"
msgstr "脚本" msgstr "脚本"
#: assets/const/category.py:10 assets/models/asset/host.py:8 #: assets/const/category.py:10 assets/models/asset/host.py:8
#: settings/serializers/auth/radius.py:16 settings/serializers/auth/sms.py:67 #: settings/serializers/auth/radius.py:16 settings/serializers/auth/sms.py:71
#: settings/serializers/feature.py:47 terminal/models/component/endpoint.py:13 #: settings/serializers/feature.py:47 terminal/models/component/endpoint.py:13
#: terminal/serializers/applet.py:17 #: terminal/serializers/applet.py:17
#: xpack/plugins/cloud/serializers/account_attrs.py:72 #: xpack/plugins/cloud/serializers/account_attrs.py:72
@ -1608,7 +1608,7 @@ msgid "Cloud"
msgstr "云服务" msgstr "云服务"
#: assets/models/asset/common.py:92 assets/models/platform.py:16 #: assets/models/asset/common.py:92 assets/models/platform.py:16
#: settings/serializers/auth/radius.py:17 settings/serializers/auth/sms.py:68 #: settings/serializers/auth/radius.py:17 settings/serializers/auth/sms.py:72
#: xpack/plugins/cloud/serializers/account_attrs.py:73 #: xpack/plugins/cloud/serializers/account_attrs.py:73
msgid "Port" msgid "Port"
msgstr "端口" msgstr "端口"
@ -1684,7 +1684,7 @@ msgid "Proxy"
msgstr "代理" msgstr "代理"
#: assets/models/automations/base.py:22 ops/models/job.py:223 #: assets/models/automations/base.py:22 ops/models/job.py:223
#: settings/serializers/auth/sms.py:99 #: settings/serializers/auth/sms.py:103
msgid "Parameters" msgid "Parameters"
msgstr "参数" msgstr "参数"
@ -2862,7 +2862,7 @@ msgstr "短信验证码校验失败"
#: authentication/mfa/sms.py:12 authentication/serializers/password_mfa.py:16 #: authentication/mfa/sms.py:12 authentication/serializers/password_mfa.py:16
#: authentication/serializers/password_mfa.py:24 #: authentication/serializers/password_mfa.py:24
#: settings/serializers/auth/sms.py:28 users/forms/profile.py:104 #: settings/serializers/auth/sms.py:32 users/forms/profile.py:104
#: users/forms/profile.py:109 users/templates/users/forgot_password.html:112 #: users/forms/profile.py:109 users/templates/users/forgot_password.html:112
#: users/views/profile/reset.py:98 #: users/views/profile/reset.py:98
msgid "SMS" msgid "SMS"
@ -3132,7 +3132,7 @@ msgstr "代码错误"
#: authentication/templates/authentication/_msg_reset_password_code.html:9 #: authentication/templates/authentication/_msg_reset_password_code.html:9
#: authentication/templates/authentication/_msg_rest_password_success.html:2 #: authentication/templates/authentication/_msg_rest_password_success.html:2
#: authentication/templates/authentication/_msg_rest_public_key_success.html:2 #: authentication/templates/authentication/_msg_rest_public_key_success.html:2
#: jumpserver/conf.py:447 #: jumpserver/conf.py:449
#: perms/templates/perms/_msg_item_permissions_expire.html:3 #: perms/templates/perms/_msg_item_permissions_expire.html:3
#: perms/templates/perms/_msg_permed_items_expire.html:3 #: perms/templates/perms/_msg_permed_items_expire.html:3
#: tickets/templates/tickets/approve_check_password.html:33 #: tickets/templates/tickets/approve_check_password.html:33
@ -3628,6 +3628,15 @@ msgstr "SP_id 为6位"
msgid "Failed to connect to the CMPP gateway server, err: {}" msgid "Failed to connect to the CMPP gateway server, err: {}"
msgstr "连接网关服务器错误,错误:{}" msgstr "连接网关服务器错误,错误:{}"
#: common/sdk/sms/custom_file.py:41
msgid "The custom sms file is invalid"
msgstr "自定义短信文件无效"
#: common/sdk/sms/custom_file.py:47
#, python-format
msgid "SMS sending failed[%s]: %s"
msgstr "短信发送失败[%s]: %s"
#: common/sdk/sms/endpoint.py:16 #: common/sdk/sms/endpoint.py:16
msgid "Alibaba cloud" msgid "Alibaba cloud"
msgstr "阿里云" msgstr "阿里云"
@ -3644,11 +3653,11 @@ msgstr "华为云"
msgid "CMPP v2.0" msgid "CMPP v2.0"
msgstr "CMPP v2.0" msgstr "CMPP v2.0"
#: common/sdk/sms/endpoint.py:31 #: common/sdk/sms/endpoint.py:32
msgid "SMS provider not support: {}" msgid "SMS provider not support: {}"
msgstr "短信服务商不支持:{}" msgstr "短信服务商不支持:{}"
#: common/sdk/sms/endpoint.py:53 #: common/sdk/sms/endpoint.py:54
msgid "SMS verification code signature or template invalid" msgid "SMS verification code signature or template invalid"
msgstr "短信验证码签名或模版无效" msgstr "短信验证码签名或模版无效"
@ -3719,11 +3728,15 @@ msgstr "不能包含特殊字符"
msgid "The mobile phone number format is incorrect" msgid "The mobile phone number format is incorrect"
msgstr "手机号格式不正确" msgstr "手机号格式不正确"
#: jumpserver/conf.py:446 #: jumpserver/conf.py:444
msgid "The verification code is: {code}"
msgstr "验证码为: {code}"
#: jumpserver/conf.py:448
msgid "Create account successfully" msgid "Create account successfully"
msgstr "创建账号成功" msgstr "创建账号成功"
#: jumpserver/conf.py:448 #: jumpserver/conf.py:450
msgid "Your account has been created successfully" msgid "Your account has been created successfully"
msgstr "你的账号已创建成功" msgstr "你的账号已创建成功"
@ -4543,7 +4556,7 @@ msgid "View permission tree"
msgstr "查看授权树" msgstr "查看授权树"
#: settings/api/dingtalk.py:31 settings/api/feishu.py:36 #: settings/api/dingtalk.py:31 settings/api/feishu.py:36
#: settings/api/sms.py:153 settings/api/vault.py:40 settings/api/wecom.py:37 #: settings/api/sms.py:160 settings/api/vault.py:40 settings/api/wecom.py:37
msgid "Test success" msgid "Test success"
msgstr "测试成功" msgstr "测试成功"
@ -4571,11 +4584,11 @@ msgstr "获取 LDAP 用户为 None"
msgid "Imported {} users successfully (Organization: {})" msgid "Imported {} users successfully (Organization: {})"
msgstr "成功导入 {} 个用户 ( 组织: {} )" msgstr "成功导入 {} 个用户 ( 组织: {} )"
#: settings/api/sms.py:135 #: settings/api/sms.py:142
msgid "Invalid SMS platform" msgid "Invalid SMS platform"
msgstr "无效的短信平台" msgstr "无效的短信平台"
#: settings/api/sms.py:141 #: settings/api/sms.py:148
msgid "test_phone is required" msgid "test_phone is required"
msgstr "测试手机号 该字段是必填项。" msgstr "测试手机号 该字段是必填项。"
@ -4980,54 +4993,58 @@ msgstr "SP 密钥"
msgid "SP cert" msgid "SP cert"
msgstr "SP 证书" msgstr "SP 证书"
#: settings/serializers/auth/sms.py:16 #: settings/serializers/auth/sms.py:17
msgid "Enable SMS" msgid "Enable SMS"
msgstr "启用 SMS" msgstr "启用 SMS"
#: settings/serializers/auth/sms.py:18 #: settings/serializers/auth/sms.py:19
msgid "SMS provider / Protocol" msgid "SMS provider / Protocol"
msgstr "短信服务商 / 协议" msgstr "短信服务商 / 协议"
#: settings/serializers/auth/sms.py:23 settings/serializers/auth/sms.py:45 #: settings/serializers/auth/sms.py:22
#: settings/serializers/auth/sms.py:53 settings/serializers/auth/sms.py:62 msgid "SMS code length"
#: settings/serializers/auth/sms.py:73 settings/serializers/msg.py:76 msgstr "验证码长度"
#: settings/serializers/auth/sms.py:27 settings/serializers/auth/sms.py:49
#: settings/serializers/auth/sms.py:57 settings/serializers/auth/sms.py:66
#: settings/serializers/auth/sms.py:77 settings/serializers/msg.py:76
msgid "Signature" msgid "Signature"
msgstr "签名" msgstr "签名"
#: settings/serializers/auth/sms.py:24 settings/serializers/auth/sms.py:46 #: settings/serializers/auth/sms.py:28 settings/serializers/auth/sms.py:50
#: settings/serializers/auth/sms.py:54 settings/serializers/auth/sms.py:63 #: settings/serializers/auth/sms.py:58 settings/serializers/auth/sms.py:67
msgid "Template code" msgid "Template code"
msgstr "模板" msgstr "模板"
#: settings/serializers/auth/sms.py:31 #: settings/serializers/auth/sms.py:35
msgid "Test phone" msgid "Test phone"
msgstr "测试手机号" msgstr "测试手机号"
#: settings/serializers/auth/sms.py:60 #: settings/serializers/auth/sms.py:64
msgid "App Access Address" msgid "App Access Address"
msgstr "应用地址" msgstr "应用地址"
#: settings/serializers/auth/sms.py:61 #: settings/serializers/auth/sms.py:65
msgid "Signature channel number" msgid "Signature channel number"
msgstr "签名通道号" msgstr "签名通道号"
#: settings/serializers/auth/sms.py:69 #: settings/serializers/auth/sms.py:73
msgid "Enterprise code(SP id)" msgid "Enterprise code(SP id)"
msgstr "企业代码(SP id)" msgstr "企业代码(SP id)"
#: settings/serializers/auth/sms.py:70 #: settings/serializers/auth/sms.py:74
msgid "Shared secret(Shared secret)" msgid "Shared secret(Shared secret)"
msgstr "共享密码(Shared secret)" msgstr "共享密码(Shared secret)"
#: settings/serializers/auth/sms.py:71 #: settings/serializers/auth/sms.py:75
msgid "Original number(Src id)" msgid "Original number(Src id)"
msgstr "原始号码(Src id)" msgstr "原始号码(Src id)"
#: settings/serializers/auth/sms.py:72 #: settings/serializers/auth/sms.py:76
msgid "Business type(Service id)" msgid "Business type(Service id)"
msgstr "业务类型(Service id)" msgstr "业务类型(Service id)"
#: settings/serializers/auth/sms.py:76 #: settings/serializers/auth/sms.py:80
#, python-brace-format #, python-brace-format
msgid "" msgid ""
"Template need contain {code} and Signature + template length does not exceed " "Template need contain {code} and Signature + template length does not exceed "
@ -5037,24 +5054,24 @@ msgstr ""
"模板需要包含 {code},并且模板+签名长度不能超过67个字。例如, 您的验证码是 " "模板需要包含 {code},并且模板+签名长度不能超过67个字。例如, 您的验证码是 "
"{code}, 有效期为5分钟。请不要泄露给其他人。" "{code}, 有效期为5分钟。请不要泄露给其他人。"
#: settings/serializers/auth/sms.py:85 #: settings/serializers/auth/sms.py:89
#, python-brace-format #, python-brace-format
msgid "The template needs to contain {code}" msgid "The template needs to contain {code}"
msgstr "模板需要包含 {code}" msgstr "模板需要包含 {code}"
#: settings/serializers/auth/sms.py:88 #: settings/serializers/auth/sms.py:92
msgid "Signature + Template must not exceed 65 words" msgid "Signature + Template must not exceed 65 words"
msgstr "模板+签名不能超过65个字" msgstr "模板+签名不能超过65个字"
#: settings/serializers/auth/sms.py:97 #: settings/serializers/auth/sms.py:101
msgid "URL" msgid "URL"
msgstr "URL" msgstr "URL"
#: settings/serializers/auth/sms.py:102 #: settings/serializers/auth/sms.py:106
msgid "Request method" msgid "Request method"
msgstr "请求方式" msgstr "请求方式"
#: settings/serializers/auth/sms.py:111 #: settings/serializers/auth/sms.py:117
#, python-format #, python-format
msgid "The value in the parameter must contain %s" msgid "The value in the parameter must contain %s"
msgstr "参数中的值必须包含 %s" msgstr "参数中的值必须包含 %s"

View File

@ -2,6 +2,7 @@ import importlib
from collections import OrderedDict from collections import OrderedDict
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from django.conf import settings
from rest_framework import status from rest_framework import status
from rest_framework.exceptions import APIException from rest_framework.exceptions import APIException
from rest_framework.generics import ListAPIView, GenericAPIView from rest_framework.generics import ListAPIView, GenericAPIView
@ -28,7 +29,6 @@ class SMSBackendAPI(ListAPIView):
} }
for b in BACKENDS.choices for b in BACKENDS.choices
] ]
return Response(data) return Response(data)
@ -39,11 +39,16 @@ class SMSTestingAPI(GenericAPIView):
'huawei': serializers.HuaweiSMSSettingSerializer, 'huawei': serializers.HuaweiSMSSettingSerializer,
'cmpp2': serializers.CMPP2SMSSettingSerializer, 'cmpp2': serializers.CMPP2SMSSettingSerializer,
'custom': serializers.CustomSMSSettingSerializer, 'custom': serializers.CustomSMSSettingSerializer,
'custom_file': serializers.BaseSMSSettingSerializer,
} }
rbac_perms = { rbac_perms = {
'POST': 'settings.change_sms' 'POST': 'settings.change_sms'
} }
@property
def test_code(self):
return '6' * settings.SMS_CODE_LENGTH
@staticmethod @staticmethod
def get_or_from_setting(key, value=''): def get_or_from_setting(key, value=''):
if not value: if not value:
@ -63,7 +68,7 @@ class SMSTestingAPI(GenericAPIView):
send_sms_params = { send_sms_params = {
'sign_name': data['ALIBABA_VERIFY_SIGN_NAME'], 'sign_name': data['ALIBABA_VERIFY_SIGN_NAME'],
'template_code': data['ALIBABA_VERIFY_TEMPLATE_CODE'], 'template_code': data['ALIBABA_VERIFY_TEMPLATE_CODE'],
'template_param': {'code': '666666'} 'template_param': {'code': self.test_code}
} }
return init_params, send_sms_params return init_params, send_sms_params
@ -78,7 +83,7 @@ class SMSTestingAPI(GenericAPIView):
send_sms_params = { send_sms_params = {
'sign_name': data['TENCENT_VERIFY_SIGN_NAME'], 'sign_name': data['TENCENT_VERIFY_SIGN_NAME'],
'template_code': data['TENCENT_VERIFY_TEMPLATE_CODE'], 'template_code': data['TENCENT_VERIFY_TEMPLATE_CODE'],
'template_param': OrderedDict(code='666666') 'template_param': OrderedDict(code=self.test_code)
} }
return init_params, send_sms_params return init_params, send_sms_params
@ -94,7 +99,7 @@ class SMSTestingAPI(GenericAPIView):
send_sms_params = { send_sms_params = {
'sign_name': data['HUAWEI_VERIFY_SIGN_NAME'], 'sign_name': data['HUAWEI_VERIFY_SIGN_NAME'],
'template_code': data['HUAWEI_VERIFY_TEMPLATE_CODE'], 'template_code': data['HUAWEI_VERIFY_TEMPLATE_CODE'],
'template_param': OrderedDict(code='666666') 'template_param': OrderedDict(code=self.test_code)
} }
return init_params, send_sms_params return init_params, send_sms_params
@ -110,16 +115,18 @@ class SMSTestingAPI(GenericAPIView):
send_sms_params = { send_sms_params = {
'sign_name': data['CMPP2_VERIFY_SIGN_NAME'], 'sign_name': data['CMPP2_VERIFY_SIGN_NAME'],
'template_code': data['CMPP2_VERIFY_TEMPLATE_CODE'], 'template_code': data['CMPP2_VERIFY_TEMPLATE_CODE'],
'template_param': OrderedDict(code='666666') 'template_param': OrderedDict(code=self.test_code)
} }
return init_params, send_sms_params return init_params, send_sms_params
@staticmethod def get_custom_params(self, data):
def get_custom_params(data):
init_params = {} init_params = {}
send_sms_params = {'template_param': OrderedDict(code='666666')} send_sms_params = {'template_param': OrderedDict(code=self.test_code)}
return init_params, send_sms_params return init_params, send_sms_params
def get_custom_file_params(self, data):
return self.get_custom_params(data)
def get_params_by_backend(self, backend, data): def get_params_by_backend(self, backend, data):
""" """
返回两部分参数 返回两部分参数

View File

@ -7,6 +7,7 @@ from common.serializers.fields import EncryptedField, PhoneField
from common.validators import PhoneValidator from common.validators import PhoneValidator
__all__ = [ __all__ = [
'BaseSMSSettingSerializer',
'SMSSettingSerializer', 'AlibabaSMSSettingSerializer', 'TencentSMSSettingSerializer', 'SMSSettingSerializer', 'AlibabaSMSSettingSerializer', 'TencentSMSSettingSerializer',
'HuaweiSMSSettingSerializer', 'CMPP2SMSSettingSerializer', 'CustomSMSSettingSerializer', 'HuaweiSMSSettingSerializer', 'CMPP2SMSSettingSerializer', 'CustomSMSSettingSerializer',
] ]
@ -17,6 +18,9 @@ class SMSSettingSerializer(serializers.Serializer):
SMS_BACKEND = serializers.ChoiceField( SMS_BACKEND = serializers.ChoiceField(
choices=BACKENDS.choices, default=BACKENDS.ALIBABA, label=_('SMS provider / Protocol') choices=BACKENDS.choices, default=BACKENDS.ALIBABA, label=_('SMS provider / Protocol')
) )
SMS_CODE_LENGTH = serializers.IntegerField(
default=4, min_value=4, max_value=16, label=_('SMS code length')
)
class SignTmplPairSerializer(serializers.Serializer): class SignTmplPairSerializer(serializers.Serializer):
@ -102,12 +106,14 @@ class CustomSMSSettingSerializer(BaseSMSSettingSerializer):
default=RequestType.get, choices=RequestType.choices, label=_("Request method") default=RequestType.get, choices=RequestType.choices, label=_("Request method")
) )
@staticmethod def validate(self, attrs):
def validate(attrs):
need_params = {'{phone_numbers}', '{code}'} need_params = {'{phone_numbers}', '{code}'}
params = attrs.get('CUSTOM_SMS_API_PARAMS', {}) params = attrs.get('CUSTOM_SMS_API_PARAMS', {})
if len(set(params.values()) & need_params) != len(need_params): # 这里用逗号分隔是保证需要的参数必须是完整的,不能分开在不同的参数中首位相连
raise serializers.ValidationError( params_string = ','.join(params.values())
for param in need_params:
if param not in params_string:
raise serializers.ValidationError(
_('The value in the parameter must contain %s') % ','.join(need_params) _('The value in the parameter must contain %s') % ','.join(need_params)
) )
return attrs return attrs