mirror of https://github.com/jumpserver/jumpserver
Merge branch 'v3' of github.com:jumpserver/jumpserver into v3
commit
994a484adb
|
@ -16,9 +16,9 @@ def migrate_system_user_to_account(apps, schema_editor):
|
||||||
count += len(connection_tokens)
|
count += len(connection_tokens)
|
||||||
updated = []
|
updated = []
|
||||||
for connection_token in connection_tokens:
|
for connection_token in connection_tokens:
|
||||||
connection_token.account = connection_token.system_user.username
|
connection_token.account_username = connection_token.system_user.username
|
||||||
updated.append(connection_token)
|
updated.append(connection_token)
|
||||||
connection_token_model.objects.bulk_update(updated, ['account'])
|
connection_token_model.objects.bulk_update(updated, ['account_username'])
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
@ -42,7 +42,7 @@ class Migration(migrations.Migration):
|
||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='connectiontoken',
|
model_name='connectiontoken',
|
||||||
name='account',
|
name='account_username',
|
||||||
field=models.CharField(default='', max_length=128, verbose_name='Account'),
|
field=models.CharField(default='', max_length=128, verbose_name='Account'),
|
||||||
),
|
),
|
||||||
migrations.RunPython(migrate_system_user_to_account),
|
migrations.RunPython(migrate_system_user_to_account),
|
||||||
|
|
|
@ -25,12 +25,12 @@ class ConnectionToken(OrgModelMixin, JMSBaseModel):
|
||||||
'assets.Asset', on_delete=models.SET_NULL, null=True, blank=True,
|
'assets.Asset', on_delete=models.SET_NULL, null=True, blank=True,
|
||||||
related_name='connection_tokens', verbose_name=_('Asset'),
|
related_name='connection_tokens', verbose_name=_('Asset'),
|
||||||
)
|
)
|
||||||
user_display = models.CharField(max_length=128, default='', verbose_name=_("User display"))
|
|
||||||
asset_display = models.CharField(max_length=128, default='', verbose_name=_("Asset display"))
|
|
||||||
account = models.CharField(max_length=128, default='', verbose_name=_("Account"))
|
|
||||||
protocol = models.CharField(
|
protocol = models.CharField(
|
||||||
choices=Protocol.choices, max_length=16, default=Protocol.ssh, verbose_name=_("Protocol")
|
choices=Protocol.choices, max_length=16, default=Protocol.ssh, verbose_name=_("Protocol")
|
||||||
)
|
)
|
||||||
|
user_display = models.CharField(max_length=128, default='', verbose_name=_("User display"))
|
||||||
|
asset_display = models.CharField(max_length=128, default='', verbose_name=_("Asset display"))
|
||||||
|
account_username = models.CharField(max_length=128, default='', verbose_name=_("Account"))
|
||||||
secret = models.CharField(max_length=64, default='', verbose_name=_("Secret"))
|
secret = models.CharField(max_length=64, default='', verbose_name=_("Secret"))
|
||||||
date_expired = models.DateTimeField(
|
date_expired = models.DateTimeField(
|
||||||
default=date_expired_default, verbose_name=_("Date expired")
|
default=date_expired_default, verbose_name=_("Date expired")
|
||||||
|
@ -43,6 +43,10 @@ class ConnectionToken(OrgModelMixin, JMSBaseModel):
|
||||||
('view_connectiontokensecret', _('Can view connection token secret'))
|
('view_connectiontokensecret', _('Can view connection token secret'))
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_valid(self):
|
||||||
|
return not self.is_expired
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_expired(self):
|
def is_expired(self):
|
||||||
return self.date_expired < timezone.now()
|
return self.date_expired < timezone.now()
|
||||||
|
@ -55,10 +59,6 @@ class ConnectionToken(OrgModelMixin, JMSBaseModel):
|
||||||
seconds = 0
|
seconds = 0
|
||||||
return int(seconds)
|
return int(seconds)
|
||||||
|
|
||||||
@property
|
|
||||||
def is_valid(self):
|
|
||||||
return not self.is_expired
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_default_date_expired(cls):
|
def get_default_date_expired(cls):
|
||||||
return date_expired_default()
|
return date_expired_default()
|
||||||
|
@ -75,35 +75,28 @@ class ConnectionToken(OrgModelMixin, JMSBaseModel):
|
||||||
# actions 和 expired_at 在 check_valid() 中赋值
|
# actions 和 expired_at 在 check_valid() 中赋值
|
||||||
actions = expire_at = None
|
actions = expire_at = None
|
||||||
|
|
||||||
def check_valid(self):
|
def check_permission(self):
|
||||||
from perms.utils.account import PermAccountUtil
|
from perms.utils.account import PermAccountUtil
|
||||||
if self.is_expired:
|
if self.is_expired:
|
||||||
is_valid = False
|
is_valid = False
|
||||||
error = _('Connection token expired at: {}').format(as_current_tz(self.date_expired))
|
error = _('Connection token expired at: {}').format(as_current_tz(self.date_expired))
|
||||||
return is_valid, error
|
return is_valid, error
|
||||||
if not self.user:
|
if not self.user or not self.user.is_valid:
|
||||||
is_valid = False
|
is_valid = False
|
||||||
error = _('User not exists')
|
error = _('No user or invalid user')
|
||||||
return is_valid, error
|
return is_valid, error
|
||||||
if not self.user.is_valid:
|
if not self.asset or self.asset.is_active:
|
||||||
is_valid = False
|
is_valid = False
|
||||||
error = _('User invalid, disabled or expired')
|
error = _('No asset or inactive asset')
|
||||||
return is_valid, error
|
return is_valid, error
|
||||||
if not self.asset:
|
if not self.account_username:
|
||||||
is_valid = False
|
is_valid = False
|
||||||
error = _('Asset not exists')
|
error = _('No account')
|
||||||
return is_valid, error
|
|
||||||
if not self.asset.is_active:
|
|
||||||
is_valid = False
|
|
||||||
error = _('Asset inactive')
|
|
||||||
return is_valid, error
|
|
||||||
if not self.account:
|
|
||||||
is_valid = False
|
|
||||||
error = _('Account not exists')
|
|
||||||
return is_valid, error
|
return is_valid, error
|
||||||
|
|
||||||
actions, expire_at = PermAccountUtil().validate_permission(
|
account_util = PermAccountUtil()
|
||||||
self.user, self.asset, self.account
|
actions, expire_at = account_util.validate_permission(
|
||||||
|
self.user, self.asset, self.account_username
|
||||||
)
|
)
|
||||||
if not actions or expire_at < time.time():
|
if not actions or expire_at < time.time():
|
||||||
is_valid = False
|
is_valid = False
|
||||||
|
@ -113,6 +106,13 @@ class ConnectionToken(OrgModelMixin, JMSBaseModel):
|
||||||
self.expire_at = expire_at
|
self.expire_at = expire_at
|
||||||
return True, ''
|
return True, ''
|
||||||
|
|
||||||
|
@lazyproperty
|
||||||
|
def account(self):
|
||||||
|
if not self.asset:
|
||||||
|
return None
|
||||||
|
account = self.asset.accounts.filter(username=self.account_username).first()
|
||||||
|
return account
|
||||||
|
|
||||||
@lazyproperty
|
@lazyproperty
|
||||||
def domain(self):
|
def domain(self):
|
||||||
domain = self.asset.domain if self.asset else None
|
domain = self.asset.domain if self.asset else None
|
||||||
|
|
|
@ -5,7 +5,7 @@ from orgs.mixins.serializers import OrgResourceModelSerializerMixin
|
||||||
from authentication.models import ConnectionToken
|
from authentication.models import ConnectionToken
|
||||||
from common.utils import pretty_string
|
from common.utils import pretty_string
|
||||||
from common.utils.random import random_string
|
from common.utils.random import random_string
|
||||||
from assets.models import Asset, Gateway, Domain, CommandFilterRule
|
from assets.models import Asset, Gateway, Domain, CommandFilterRule, Account
|
||||||
from users.models import User
|
from users.models import User
|
||||||
from perms.serializers.permission import ActionsField
|
from perms.serializers.permission import ActionsField
|
||||||
|
|
||||||
|
@ -24,34 +24,33 @@ class ConnectionTokenSerializer(OrgResourceModelSerializerMixin):
|
||||||
model = ConnectionToken
|
model = ConnectionToken
|
||||||
fields_mini = ['id']
|
fields_mini = ['id']
|
||||||
fields_small = fields_mini + [
|
fields_small = fields_mini + [
|
||||||
'secret', 'date_expired', 'date_created', 'date_updated',
|
'secret', 'account_username', 'date_expired',
|
||||||
|
'date_created', 'date_updated',
|
||||||
'created_by', 'updated_by', 'org_id', 'org_name',
|
'created_by', 'updated_by', 'org_id', 'org_name',
|
||||||
]
|
]
|
||||||
fields_fk = [
|
fields_fk = [
|
||||||
'user', 'system_user', 'asset',
|
'user', 'asset',
|
||||||
]
|
]
|
||||||
read_only_fields = [
|
read_only_fields = [
|
||||||
# 普通 Token 不支持指定 user
|
# 普通 Token 不支持指定 user
|
||||||
'user', 'is_valid', 'expire_time',
|
'user', 'is_valid', 'expire_time',
|
||||||
'user_display', 'system_user_display',
|
'user_display', 'asset_display',
|
||||||
'asset_display',
|
|
||||||
]
|
]
|
||||||
fields = fields_small + fields_fk + read_only_fields
|
fields = fields_small + fields_fk + read_only_fields
|
||||||
|
|
||||||
|
def get_request_user(self):
|
||||||
|
request = self.context.get('request')
|
||||||
|
user = request.user if request else None
|
||||||
|
return user
|
||||||
|
|
||||||
|
def get_user(self, attrs):
|
||||||
|
return self.get_request_user()
|
||||||
|
|
||||||
def validate(self, attrs):
|
def validate(self, attrs):
|
||||||
fields_attrs = self.construct_internal_fields_attrs(attrs)
|
fields_attrs = self.construct_internal_fields_attrs(attrs)
|
||||||
attrs.update(fields_attrs)
|
attrs.update(fields_attrs)
|
||||||
return attrs
|
return attrs
|
||||||
|
|
||||||
@property
|
|
||||||
def request_user(self):
|
|
||||||
request = self.context.get('request')
|
|
||||||
if request:
|
|
||||||
return request.user
|
|
||||||
|
|
||||||
def get_user(self, attrs):
|
|
||||||
return self.request_user
|
|
||||||
|
|
||||||
def construct_internal_fields_attrs(self, attrs):
|
def construct_internal_fields_attrs(self, attrs):
|
||||||
asset = attrs.get('asset') or ''
|
asset = attrs.get('asset') or ''
|
||||||
asset_display = pretty_string(str(asset), max_length=128)
|
asset_display = pretty_string(str(asset), max_length=128)
|
||||||
|
@ -63,8 +62,7 @@ class ConnectionTokenSerializer(OrgResourceModelSerializerMixin):
|
||||||
if not isinstance(asset, Asset):
|
if not isinstance(asset, Asset):
|
||||||
error = ''
|
error = ''
|
||||||
raise serializers.ValidationError(error)
|
raise serializers.ValidationError(error)
|
||||||
|
attrs = {
|
||||||
return {
|
|
||||||
'user': user,
|
'user': user,
|
||||||
'secret': secret,
|
'secret': secret,
|
||||||
'user_display': user_display,
|
'user_display': user_display,
|
||||||
|
@ -72,6 +70,7 @@ class ConnectionTokenSerializer(OrgResourceModelSerializerMixin):
|
||||||
'date_expired': date_expired,
|
'date_expired': date_expired,
|
||||||
'org_id': org_id,
|
'org_id': org_id,
|
||||||
}
|
}
|
||||||
|
return attrs
|
||||||
|
|
||||||
|
|
||||||
class ConnectionTokenDisplaySerializer(ConnectionTokenSerializer):
|
class ConnectionTokenDisplaySerializer(ConnectionTokenSerializer):
|
||||||
|
@ -95,7 +94,7 @@ class SuperConnectionTokenSerializer(ConnectionTokenSerializer):
|
||||||
]
|
]
|
||||||
|
|
||||||
def get_user(self, attrs):
|
def get_user(self, attrs):
|
||||||
return attrs.get('user') or self.request_user
|
return attrs.get('user') or self.get_request_user()
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -104,31 +103,37 @@ class SuperConnectionTokenSerializer(ConnectionTokenSerializer):
|
||||||
|
|
||||||
|
|
||||||
class ConnectionTokenUserSerializer(serializers.ModelSerializer):
|
class ConnectionTokenUserSerializer(serializers.ModelSerializer):
|
||||||
|
""" User """
|
||||||
class Meta:
|
class Meta:
|
||||||
model = User
|
model = User
|
||||||
fields = ['id', 'name', 'username', 'email']
|
fields = ['id', 'name', 'username', 'email']
|
||||||
|
|
||||||
|
|
||||||
class ConnectionTokenAssetSerializer(serializers.ModelSerializer):
|
class ConnectionTokenAssetSerializer(serializers.ModelSerializer):
|
||||||
|
""" Asset """
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Asset
|
model = Asset
|
||||||
fields = ['id', 'name', 'ip', 'protocols', 'org_id']
|
fields = ['id', 'name', 'ip', 'protocols', 'org_id']
|
||||||
|
|
||||||
|
|
||||||
|
class ConnectionTokenAccountSerializer(serializers.ModelSerializer):
|
||||||
|
""" Account """
|
||||||
|
class Meta:
|
||||||
|
model = Account
|
||||||
|
fields = [
|
||||||
|
'id', 'name', 'username', 'secret_type', 'secret', 'version'
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
class ConnectionTokenGatewaySerializer(serializers.ModelSerializer):
|
class ConnectionTokenGatewaySerializer(serializers.ModelSerializer):
|
||||||
|
""" Gateway """
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Gateway
|
model = Gateway
|
||||||
fields = ['id', 'ip', 'port', 'username', 'password', 'private_key']
|
fields = ['id', 'ip', 'port', 'username', 'password', 'private_key']
|
||||||
|
|
||||||
|
|
||||||
class ConnectionTokenRemoteAppSerializer(serializers.Serializer):
|
|
||||||
program = serializers.CharField(allow_null=True, allow_blank=True)
|
|
||||||
working_directory = serializers.CharField(allow_null=True, allow_blank=True)
|
|
||||||
parameters = serializers.CharField(allow_null=True, allow_blank=True)
|
|
||||||
|
|
||||||
|
|
||||||
class ConnectionTokenDomainSerializer(serializers.ModelSerializer):
|
class ConnectionTokenDomainSerializer(serializers.ModelSerializer):
|
||||||
|
""" Domain """
|
||||||
gateways = ConnectionTokenGatewaySerializer(many=True, read_only=True)
|
gateways = ConnectionTokenGatewaySerializer(many=True, read_only=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
@ -137,6 +142,7 @@ class ConnectionTokenDomainSerializer(serializers.ModelSerializer):
|
||||||
|
|
||||||
|
|
||||||
class ConnectionTokenCmdFilterRuleSerializer(serializers.ModelSerializer):
|
class ConnectionTokenCmdFilterRuleSerializer(serializers.ModelSerializer):
|
||||||
|
""" Command filter rule """
|
||||||
class Meta:
|
class Meta:
|
||||||
model = CommandFilterRule
|
model = CommandFilterRule
|
||||||
fields = [
|
fields = [
|
||||||
|
@ -148,7 +154,7 @@ class ConnectionTokenCmdFilterRuleSerializer(serializers.ModelSerializer):
|
||||||
class ConnectionTokenSecretSerializer(OrgResourceModelSerializerMixin):
|
class ConnectionTokenSecretSerializer(OrgResourceModelSerializerMixin):
|
||||||
user = ConnectionTokenUserSerializer(read_only=True)
|
user = ConnectionTokenUserSerializer(read_only=True)
|
||||||
asset = ConnectionTokenAssetSerializer(read_only=True)
|
asset = ConnectionTokenAssetSerializer(read_only=True)
|
||||||
remote_app = ConnectionTokenRemoteAppSerializer(read_only=True)
|
account = ConnectionTokenAccountSerializer(read_only=True)
|
||||||
gateway = ConnectionTokenGatewaySerializer(read_only=True)
|
gateway = ConnectionTokenGatewaySerializer(read_only=True)
|
||||||
domain = ConnectionTokenDomainSerializer(read_only=True)
|
domain = ConnectionTokenDomainSerializer(read_only=True)
|
||||||
cmd_filter_rules = ConnectionTokenCmdFilterRuleSerializer(many=True)
|
cmd_filter_rules = ConnectionTokenCmdFilterRuleSerializer(many=True)
|
||||||
|
@ -158,6 +164,8 @@ class ConnectionTokenSecretSerializer(OrgResourceModelSerializerMixin):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ConnectionToken
|
model = ConnectionToken
|
||||||
fields = [
|
fields = [
|
||||||
'id', 'secret', 'type', 'user', 'asset', 'account', 'protocol',
|
'id', 'secret',
|
||||||
'cmd_filter_rules', 'domain', 'gateway', 'actions', 'expired_at',
|
'user', 'asset', 'account_username', 'account', 'protocol',
|
||||||
|
'domain', 'gateway', 'cmd_filter_rules',
|
||||||
|
'actions', 'expired_at',
|
||||||
]
|
]
|
||||||
|
|
Loading…
Reference in New Issue