mirror of https://github.com/jumpserver/jumpserver
perf: AKSK添加访问IP控制
parent
bc54685a31
commit
dc841650cf
|
@ -8,7 +8,7 @@ from django.utils.translation import gettext as _
|
|||
from rest_framework import authentication, exceptions
|
||||
|
||||
from common.auth import signature
|
||||
from common.utils import get_object_or_none
|
||||
from common.utils import get_object_or_none, get_request_ip_or_data, contains_ip
|
||||
from ..models import AccessKey, PrivateToken
|
||||
|
||||
|
||||
|
@ -122,3 +122,14 @@ class SignatureAuthentication(signature.SignatureAuthentication):
|
|||
return user, secret
|
||||
except (AccessKey.DoesNotExist, exceptions.ValidationError):
|
||||
return None, None
|
||||
|
||||
def is_ip_allow(self, key_id, request):
|
||||
try:
|
||||
ak = AccessKey.objects.get(id=key_id)
|
||||
ip_group = ak.ip_group
|
||||
ip = get_request_ip_or_data(request)
|
||||
if not contains_ip(ip, ip_group):
|
||||
return False
|
||||
return True
|
||||
except (AccessKey.DoesNotExist, exceptions.ValidationError):
|
||||
return False
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
# Generated by Django 4.1.10 on 2023-10-31 05:37
|
||||
|
||||
import authentication.models.access_key
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('authentication', '0023_auto_20231010_1101'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='accesskey',
|
||||
name='ip_group',
|
||||
field=models.JSONField(default=authentication.models.access_key.defatult_ip_group, verbose_name='IP group'),
|
||||
),
|
||||
]
|
|
@ -12,9 +12,14 @@ def default_secret():
|
|||
return random_string(36)
|
||||
|
||||
|
||||
def defatult_ip_group():
|
||||
return ["*"]
|
||||
|
||||
|
||||
class AccessKey(models.Model):
|
||||
id = models.UUIDField(verbose_name='AccessKeyID', primary_key=True, default=uuid.uuid4, editable=False)
|
||||
secret = models.CharField(verbose_name='AccessKeySecret', default=default_secret, max_length=36)
|
||||
ip_group = models.JSONField(default=defatult_ip_group, verbose_name=_('IP group'))
|
||||
user = models.ForeignKey(settings.AUTH_USER_MODEL, verbose_name='User',
|
||||
on_delete=common.db.models.CASCADE_SIGNAL_SKIP, related_name='access_keys')
|
||||
is_active = models.BooleanField(default=True, verbose_name=_('Active'))
|
||||
|
|
|
@ -4,6 +4,7 @@ from django.utils import timezone
|
|||
from django.utils.translation import gettext_lazy as _
|
||||
from rest_framework import serializers
|
||||
|
||||
from acls.serializers.rules import ip_group_child_validator, ip_group_help_text
|
||||
from common.utils import get_object_or_none, random_string
|
||||
from users.models import User
|
||||
from users.serializers import UserProfileSerializer
|
||||
|
@ -17,9 +18,14 @@ __all__ = [
|
|||
|
||||
|
||||
class AccessKeySerializer(serializers.ModelSerializer):
|
||||
ip_group = serializers.ListField(
|
||||
default=['*'], label=_('AccessIP'), help_text=ip_group_help_text,
|
||||
child=serializers.CharField(max_length=1024, validators=[ip_group_child_validator])
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = AccessKey
|
||||
fields = ['id', 'is_active', 'date_created', 'date_last_used']
|
||||
fields = ['id', 'is_active', 'date_created', 'date_last_used'] + ['ip_group']
|
||||
read_only_fields = ['id', 'date_created', 'date_last_used']
|
||||
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ Reusing failure exceptions serves several purposes:
|
|||
|
||||
"""
|
||||
FAILED = exceptions.AuthenticationFailed('Invalid signature.')
|
||||
IP_NOT_ALLOW = exceptions.AuthenticationFailed('Ip is not in access ip list.')
|
||||
|
||||
|
||||
class SignatureAuthentication(authentication.BaseAuthentication):
|
||||
|
@ -43,6 +44,9 @@ class SignatureAuthentication(authentication.BaseAuthentication):
|
|||
"""Returns a tuple (User, secret) or (None, None)."""
|
||||
raise NotImplementedError()
|
||||
|
||||
def is_ip_allow(self, key_id, request):
|
||||
raise NotImplementedError()
|
||||
|
||||
def authenticate_header(self, request):
|
||||
"""
|
||||
DRF sends this for unauthenticated responses if we're the primary
|
||||
|
@ -50,7 +54,7 @@ class SignatureAuthentication(authentication.BaseAuthentication):
|
|||
"""
|
||||
h = " ".join(self.required_headers)
|
||||
return 'Signature realm="%s",headers="%s"' % (
|
||||
self.www_authenticate_realm, h)
|
||||
self.www_authenticate_realm, h)
|
||||
|
||||
def authenticate(self, request):
|
||||
"""
|
||||
|
@ -78,15 +82,19 @@ class SignatureAuthentication(authentication.BaseAuthentication):
|
|||
if len({"keyid", "algorithm", "signature"} - set(fields.keys())) > 0:
|
||||
raise FAILED
|
||||
|
||||
key_id = fields["keyid"]
|
||||
# Fetch the secret associated with the keyid
|
||||
user, secret = self.fetch_user_data(
|
||||
fields["keyid"],
|
||||
key_id,
|
||||
algorithm=fields["algorithm"]
|
||||
)
|
||||
|
||||
if not (user and secret):
|
||||
raise FAILED
|
||||
|
||||
if not self.is_ip_allow(key_id, request):
|
||||
raise IP_NOT_ALLOW
|
||||
|
||||
# Gather all request headers and translate them as stated in the Django docs:
|
||||
# https://docs.djangoproject.com/en/1.6/ref/request-response/#django.http.HttpRequest.META
|
||||
headers = {}
|
||||
|
|
|
@ -8,7 +8,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2023-10-30 11:28+0800\n"
|
||||
"POT-Creation-Date: 2023-10-31 14:04+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"
|
||||
|
@ -41,7 +41,7 @@ msgstr "パスワード"
|
|||
msgid "SSH key"
|
||||
msgstr "SSH キー"
|
||||
|
||||
#: accounts/const/account.py:8 authentication/models/access_key.py:37
|
||||
#: accounts/const/account.py:8 authentication/models/access_key.py:42
|
||||
msgid "Access key"
|
||||
msgstr "アクセスキー"
|
||||
|
||||
|
@ -843,7 +843,7 @@ msgstr "关联平台,可以配置推送参数,如果不关联,则使用默
|
|||
#: assets/models/group.py:20 common/db/models.py:36 ops/models/adhoc.py:26
|
||||
#: ops/models/job.py:145 ops/models/playbook.py:31 rbac/models/role.py:37
|
||||
#: settings/models.py:37 terminal/models/applet/applet.py:45
|
||||
#: terminal/models/applet/applet.py:321 terminal/models/applet/host.py:143
|
||||
#: terminal/models/applet/applet.py:317 terminal/models/applet/host.py:143
|
||||
#: terminal/models/component/endpoint.py:24
|
||||
#: terminal/models/component/endpoint.py:104
|
||||
#: terminal/models/session/session.py:46 tickets/models/comment.py:32
|
||||
|
@ -1014,7 +1014,7 @@ msgstr "1-100、低い値は最初に一致します"
|
|||
msgid "Reviewers"
|
||||
msgstr "レビュー担当者"
|
||||
|
||||
#: acls/models/base.py:43 authentication/models/access_key.py:20
|
||||
#: acls/models/base.py:43 authentication/models/access_key.py:25
|
||||
#: authentication/models/connection_token.py:53
|
||||
#: authentication/templates/authentication/_access_key_modal.html:32
|
||||
#: perms/models/asset_permission.py:81 terminal/models/session/sharing.py:29
|
||||
|
@ -1712,7 +1712,7 @@ msgstr "アセットの自動化タスク"
|
|||
|
||||
#: assets/models/automations/base.py:113 audits/models.py:207
|
||||
#: audits/serializers.py:51 ops/models/base.py:49 ops/models/job.py:220
|
||||
#: terminal/models/applet/applet.py:320 terminal/models/applet/host.py:140
|
||||
#: terminal/models/applet/applet.py:316 terminal/models/applet/host.py:140
|
||||
#: terminal/models/component/status.py:30 terminal/serializers/applet.py:18
|
||||
#: terminal/serializers/applet_host.py:124 tickets/models/ticket/general.py:283
|
||||
#: tickets/serializers/super_ticket.py:13
|
||||
|
@ -2653,7 +2653,7 @@ msgid "Added on"
|
|||
msgstr "に追加"
|
||||
|
||||
#: authentication/backends/passkey/models.py:14
|
||||
#: authentication/models/access_key.py:21
|
||||
#: authentication/models/access_key.py:26
|
||||
#: authentication/models/private_token.py:8
|
||||
msgid "Date last used"
|
||||
msgstr "最後に使用した日付"
|
||||
|
@ -2956,6 +2956,11 @@ msgstr "MFAタイプ ({}) が有効になっていない"
|
|||
msgid "Please change your password"
|
||||
msgstr "パスワードを変更してください"
|
||||
|
||||
#: authentication/models/access_key.py:22
|
||||
#: terminal/models/component/endpoint.py:95
|
||||
msgid "IP group"
|
||||
msgstr "IP グループ"
|
||||
|
||||
#: authentication/models/connection_token.py:38
|
||||
#: terminal/serializers/storage.py:113
|
||||
msgid "Account name"
|
||||
|
@ -3108,7 +3113,13 @@ msgstr "メール"
|
|||
msgid "The {} cannot be empty"
|
||||
msgstr "{} 空にしてはならない"
|
||||
|
||||
#: authentication/serializers/token.py:86 perms/serializers/permission.py:37
|
||||
#: authentication/serializers/token.py:23
|
||||
#, fuzzy
|
||||
#| msgid "Access key"
|
||||
msgid "AccessIP"
|
||||
msgstr "アクセスキー"
|
||||
|
||||
#: authentication/serializers/token.py:93 perms/serializers/permission.py:37
|
||||
#: perms/serializers/permission.py:59 users/serializers/user.py:98
|
||||
#: users/serializers/user.py:168
|
||||
msgid "Is valid"
|
||||
|
@ -4615,7 +4626,7 @@ msgid "My assets"
|
|||
msgstr "私の資産"
|
||||
|
||||
#: rbac/tree.py:56 terminal/models/applet/applet.py:52
|
||||
#: terminal/models/applet/applet.py:317 terminal/models/applet/host.py:30
|
||||
#: terminal/models/applet/applet.py:313 terminal/models/applet/host.py:30
|
||||
#: terminal/serializers/applet.py:15
|
||||
msgid "Applet"
|
||||
msgstr "リモートアプリケーション"
|
||||
|
@ -6346,7 +6357,7 @@ msgstr "カスタムプラットフォームのみをサポート"
|
|||
msgid "Missing type in platform.yml"
|
||||
msgstr "platform.ymlにタイプがありません"
|
||||
|
||||
#: terminal/models/applet/applet.py:319 terminal/models/applet/host.py:36
|
||||
#: terminal/models/applet/applet.py:315 terminal/models/applet/host.py:36
|
||||
#: terminal/models/applet/host.py:138
|
||||
msgid "Hosting"
|
||||
msgstr "ホスト マシン"
|
||||
|
@ -6425,10 +6436,6 @@ msgstr "Redis ポート"
|
|||
msgid "Endpoint"
|
||||
msgstr "エンドポイント"
|
||||
|
||||
#: terminal/models/component/endpoint.py:95
|
||||
msgid "IP group"
|
||||
msgstr "IP グループ"
|
||||
|
||||
#: terminal/models/component/endpoint.py:108
|
||||
msgid "Endpoint rule"
|
||||
msgstr "エンドポイントルール"
|
||||
|
@ -6732,7 +6739,10 @@ msgid ""
|
|||
"Connect to the host using the same account first. For security reasons, "
|
||||
"please set the configuration item CACHE_LOGIN_PASSWORD_ENABLED=true and "
|
||||
"restart the service to enable it."
|
||||
msgstr "同じアカウントを使用してホストに接続します。セキュリティ上の理由から、構成項目 CACHE_LOGIN_PASSWORD_ENABLED=true を設定してサービスを再起動して有効にしてください。"
|
||||
msgstr ""
|
||||
"同じアカウントを使用してホストに接続します。セキュリティ上の理由から、構成項"
|
||||
"目 CACHE_LOGIN_PASSWORD_ENABLED=true を設定してサービスを再起動して有効にして"
|
||||
"ください。"
|
||||
|
||||
#: terminal/serializers/command.py:19
|
||||
msgid "Session ID"
|
||||
|
|
|
@ -7,7 +7,7 @@ msgid ""
|
|||
msgstr ""
|
||||
"Project-Id-Version: JumpServer 0.3.3\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2023-10-30 11:28+0800\n"
|
||||
"POT-Creation-Date: 2023-10-31 14:04+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"
|
||||
|
@ -40,7 +40,7 @@ msgstr "密码"
|
|||
msgid "SSH key"
|
||||
msgstr "SSH 密钥"
|
||||
|
||||
#: accounts/const/account.py:8 authentication/models/access_key.py:37
|
||||
#: accounts/const/account.py:8 authentication/models/access_key.py:42
|
||||
msgid "Access key"
|
||||
msgstr "Access key"
|
||||
|
||||
|
@ -841,7 +841,7 @@ msgstr "关联平台,可配置推送参数,如果不关联,将使用默认
|
|||
#: assets/models/group.py:20 common/db/models.py:36 ops/models/adhoc.py:26
|
||||
#: ops/models/job.py:145 ops/models/playbook.py:31 rbac/models/role.py:37
|
||||
#: settings/models.py:37 terminal/models/applet/applet.py:45
|
||||
#: terminal/models/applet/applet.py:321 terminal/models/applet/host.py:143
|
||||
#: terminal/models/applet/applet.py:317 terminal/models/applet/host.py:143
|
||||
#: terminal/models/component/endpoint.py:24
|
||||
#: terminal/models/component/endpoint.py:104
|
||||
#: terminal/models/session/session.py:46 tickets/models/comment.py:32
|
||||
|
@ -1011,7 +1011,7 @@ msgstr "优先级可选范围为 1-100 (数值越小越优先)"
|
|||
msgid "Reviewers"
|
||||
msgstr "审批人"
|
||||
|
||||
#: acls/models/base.py:43 authentication/models/access_key.py:20
|
||||
#: acls/models/base.py:43 authentication/models/access_key.py:25
|
||||
#: authentication/models/connection_token.py:53
|
||||
#: authentication/templates/authentication/_access_key_modal.html:32
|
||||
#: perms/models/asset_permission.py:81 terminal/models/session/sharing.py:29
|
||||
|
@ -1705,7 +1705,7 @@ msgstr "资产自动化任务"
|
|||
|
||||
#: assets/models/automations/base.py:113 audits/models.py:207
|
||||
#: audits/serializers.py:51 ops/models/base.py:49 ops/models/job.py:220
|
||||
#: terminal/models/applet/applet.py:320 terminal/models/applet/host.py:140
|
||||
#: terminal/models/applet/applet.py:316 terminal/models/applet/host.py:140
|
||||
#: terminal/models/component/status.py:30 terminal/serializers/applet.py:18
|
||||
#: terminal/serializers/applet_host.py:124 tickets/models/ticket/general.py:283
|
||||
#: tickets/serializers/super_ticket.py:13
|
||||
|
@ -2632,7 +2632,7 @@ msgid "Added on"
|
|||
msgstr "附加"
|
||||
|
||||
#: authentication/backends/passkey/models.py:14
|
||||
#: authentication/models/access_key.py:21
|
||||
#: authentication/models/access_key.py:26
|
||||
#: authentication/models/private_token.py:8
|
||||
msgid "Date last used"
|
||||
msgstr "最后使用日期"
|
||||
|
@ -2925,6 +2925,11 @@ msgstr "该 MFA ({}) 方式没有启用"
|
|||
msgid "Please change your password"
|
||||
msgstr "请修改密码"
|
||||
|
||||
#: authentication/models/access_key.py:22
|
||||
#: terminal/models/component/endpoint.py:95
|
||||
msgid "IP group"
|
||||
msgstr "IPグループ"
|
||||
|
||||
#: authentication/models/connection_token.py:38
|
||||
#: terminal/serializers/storage.py:113
|
||||
msgid "Account name"
|
||||
|
@ -3077,7 +3082,13 @@ msgstr "邮箱"
|
|||
msgid "The {} cannot be empty"
|
||||
msgstr "{} 不能为空"
|
||||
|
||||
#: authentication/serializers/token.py:86 perms/serializers/permission.py:37
|
||||
#: authentication/serializers/token.py:23
|
||||
#, fuzzy
|
||||
#| msgid "Access key"
|
||||
msgid "AccessIP"
|
||||
msgstr "アクセスIP"
|
||||
|
||||
#: authentication/serializers/token.py:93 perms/serializers/permission.py:37
|
||||
#: perms/serializers/permission.py:59 users/serializers/user.py:98
|
||||
#: users/serializers/user.py:168
|
||||
msgid "Is valid"
|
||||
|
@ -4563,7 +4574,7 @@ msgid "My assets"
|
|||
msgstr "我的资产"
|
||||
|
||||
#: rbac/tree.py:56 terminal/models/applet/applet.py:52
|
||||
#: terminal/models/applet/applet.py:317 terminal/models/applet/host.py:30
|
||||
#: terminal/models/applet/applet.py:313 terminal/models/applet/host.py:30
|
||||
#: terminal/serializers/applet.py:15
|
||||
msgid "Applet"
|
||||
msgstr "远程应用"
|
||||
|
@ -6256,7 +6267,7 @@ msgstr "只支持自定义平台"
|
|||
msgid "Missing type in platform.yml"
|
||||
msgstr "在 platform.yml 中缺少类型"
|
||||
|
||||
#: terminal/models/applet/applet.py:319 terminal/models/applet/host.py:36
|
||||
#: terminal/models/applet/applet.py:315 terminal/models/applet/host.py:36
|
||||
#: terminal/models/applet/host.py:138
|
||||
msgid "Hosting"
|
||||
msgstr "宿主机"
|
||||
|
@ -6333,10 +6344,6 @@ msgstr "Redis 端口"
|
|||
msgid "Endpoint"
|
||||
msgstr "端点"
|
||||
|
||||
#: terminal/models/component/endpoint.py:95
|
||||
msgid "IP group"
|
||||
msgstr "IP 组"
|
||||
|
||||
#: terminal/models/component/endpoint.py:108
|
||||
msgid "Endpoint rule"
|
||||
msgstr "端点规则"
|
||||
|
@ -6637,7 +6644,9 @@ msgid ""
|
|||
"Connect to the host using the same account first. For security reasons, "
|
||||
"please set the configuration item CACHE_LOGIN_PASSWORD_ENABLED=true and "
|
||||
"restart the service to enable it."
|
||||
msgstr "优先使用同名账号连接发布机。为了安全,需配置文件中开启配置 CACHE_LOGIN_PASSWORD_ENABLED=true, 修改后重启服务"
|
||||
msgstr ""
|
||||
"优先使用同名账号连接发布机。为了安全,需配置文件中开启配置 "
|
||||
"CACHE_LOGIN_PASSWORD_ENABLED=true, 修改后重启服务"
|
||||
|
||||
#: terminal/serializers/command.py:19
|
||||
msgid "Session ID"
|
||||
|
|
Loading…
Reference in New Issue