mirror of
https://github.com/jumpserver/jumpserver.git
synced 2025-07-04 10:36:37 +00:00
perf: 修改 connection token
This commit is contained in:
parent
6d5be66b5e
commit
779161d79a
@ -6,6 +6,7 @@ import urllib.parse
|
|||||||
|
|
||||||
from django.http import HttpResponse
|
from django.http import HttpResponse
|
||||||
from django.shortcuts import get_object_or_404
|
from django.shortcuts import get_object_or_404
|
||||||
|
from django.utils import timezone
|
||||||
from rest_framework import status
|
from rest_framework import status
|
||||||
from rest_framework.decorators import action
|
from rest_framework.decorators import action
|
||||||
from rest_framework.exceptions import PermissionDenied
|
from rest_framework.exceptions import PermissionDenied
|
||||||
@ -15,6 +16,7 @@ from rest_framework.response import Response
|
|||||||
from common.drf.api import JMSModelViewSet
|
from common.drf.api import JMSModelViewSet
|
||||||
from common.http import is_true
|
from common.http import is_true
|
||||||
from orgs.mixins.api import RootOrgViewMixin
|
from orgs.mixins.api import RootOrgViewMixin
|
||||||
|
from orgs.utils import tmp_to_root_org
|
||||||
from perms.models import ActionChoices
|
from perms.models import ActionChoices
|
||||||
from terminal.models import EndpointRule
|
from terminal.models import EndpointRule
|
||||||
from ..models import ConnectionToken
|
from ..models import ConnectionToken
|
||||||
@ -257,6 +259,10 @@ class ConnectionTokenViewSet(ExtraActionApiMixin, RootOrgViewMixin, JMSModelView
|
|||||||
'get_client_protocol_url': 'authentication.add_connectiontoken',
|
'get_client_protocol_url': 'authentication.add_connectiontoken',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def dispatch(self, request, *args, **kwargs):
|
||||||
|
with tmp_to_root_org():
|
||||||
|
return super().dispatch(request, *args, **kwargs)
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
return ConnectionToken.objects.filter(user=self.request.user)
|
return ConnectionToken.objects.filter(user=self.request.user)
|
||||||
|
|
||||||
@ -264,22 +270,36 @@ class ConnectionTokenViewSet(ExtraActionApiMixin, RootOrgViewMixin, JMSModelView
|
|||||||
return self.request.user
|
return self.request.user
|
||||||
|
|
||||||
def perform_create(self, serializer):
|
def perform_create(self, serializer):
|
||||||
user = self.get_user(serializer)
|
self.validate_serializer(serializer)
|
||||||
asset = serializer.validated_data.get('asset')
|
return super().perform_create(serializer)
|
||||||
account_username = serializer.validated_data.get('account_username')
|
|
||||||
self.validate_asset_permission(user, asset, account_username)
|
|
||||||
return super(ConnectionTokenViewSet, self).perform_create(serializer)
|
|
||||||
|
|
||||||
@staticmethod
|
def validate_serializer(self, serializer):
|
||||||
def validate_asset_permission(user, asset, account_username):
|
|
||||||
from perms.utils.account import PermAccountUtil
|
from perms.utils.account import PermAccountUtil
|
||||||
actions, expire_at = PermAccountUtil().validate_permission(user, asset, account_username)
|
|
||||||
if not actions:
|
data = serializer.validated_data
|
||||||
error = 'No actions'
|
user = self.get_user(serializer)
|
||||||
raise PermissionDenied(error)
|
asset = data.get('asset')
|
||||||
if expire_at < time.time():
|
login = data.get('login')
|
||||||
error = 'Expired'
|
data['org_id'] = asset.org_id
|
||||||
raise PermissionDenied(error)
|
data['user'] = user
|
||||||
|
|
||||||
|
util = PermAccountUtil()
|
||||||
|
permed_account = util.validate_permission(user, asset, login)
|
||||||
|
|
||||||
|
if not permed_account or not permed_account.actions:
|
||||||
|
msg = 'user `{}` not has asset `{}` permission for login `{}`'.format(
|
||||||
|
user, asset, login
|
||||||
|
)
|
||||||
|
raise PermissionDenied(msg)
|
||||||
|
|
||||||
|
if permed_account.date_expired < timezone.now():
|
||||||
|
raise PermissionDenied('Expired')
|
||||||
|
|
||||||
|
if permed_account.has_secret:
|
||||||
|
serializer.validated_data['secret'] = ''
|
||||||
|
if permed_account.username != '@INPUT':
|
||||||
|
serializer.validated_data['username'] = ''
|
||||||
|
return permed_account
|
||||||
|
|
||||||
|
|
||||||
class SuperConnectionTokenViewSet(ConnectionTokenViewSet):
|
class SuperConnectionTokenViewSet(ConnectionTokenViewSet):
|
||||||
|
@ -16,7 +16,7 @@ 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_username = connection_token.system_user.username
|
connection_token.account = connection_token.system_user.username
|
||||||
updated.append(connection_token)
|
updated.append(connection_token)
|
||||||
connection_token_model.objects.bulk_update(updated, ['account_username'])
|
connection_token_model.objects.bulk_update(updated, ['account_username'])
|
||||||
|
|
||||||
|
29
apps/authentication/migrations/0014_auto_20221122_2152.py
Normal file
29
apps/authentication/migrations/0014_auto_20221122_2152.py
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
# Generated by Django 3.2.14 on 2022-11-22 13:52
|
||||||
|
|
||||||
|
import common.db.fields
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('authentication', '0013_connectiontoken_protocol'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RenameField(
|
||||||
|
model_name='connectiontoken',
|
||||||
|
old_name='account_username',
|
||||||
|
new_name='login'
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='connectiontoken',
|
||||||
|
name='username',
|
||||||
|
field=models.CharField(default='', max_length=128, verbose_name='Username'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='connectiontoken',
|
||||||
|
name='secret',
|
||||||
|
field=common.db.fields.EncryptCharField(default='', max_length=128, verbose_name='Secret'),
|
||||||
|
),
|
||||||
|
]
|
@ -2,13 +2,15 @@ import time
|
|||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from django.conf import settings
|
|
||||||
from orgs.mixins.models import OrgModelMixin
|
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from common.utils import lazyproperty
|
from django.conf import settings
|
||||||
|
from rest_framework.exceptions import PermissionDenied
|
||||||
|
|
||||||
|
from orgs.mixins.models import OrgModelMixin
|
||||||
|
from common.utils import lazyproperty, pretty_string
|
||||||
from common.utils.timezone import as_current_tz
|
from common.utils.timezone import as_current_tz
|
||||||
from common.db.models import JMSBaseModel
|
from common.db.models import JMSBaseModel
|
||||||
|
from common.db.fields import EncryptCharField
|
||||||
from assets.const import Protocol
|
from assets.const import Protocol
|
||||||
|
|
||||||
|
|
||||||
@ -25,13 +27,14 @@ 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'),
|
||||||
)
|
)
|
||||||
|
login = models.CharField(max_length=128, verbose_name=_("Login account"))
|
||||||
|
username = models.CharField(max_length=128, default='', verbose_name=_("Username"))
|
||||||
|
secret = EncryptCharField(max_length=64, default='', verbose_name=_("Secret"))
|
||||||
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"))
|
user_display = models.CharField(max_length=128, default='', verbose_name=_("User display"))
|
||||||
asset_display = models.CharField(max_length=128, default='', verbose_name=_("Asset 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"))
|
|
||||||
date_expired = models.DateTimeField(
|
date_expired = models.DateTimeField(
|
||||||
default=date_expired_default, verbose_name=_("Date expired")
|
default=date_expired_default, verbose_name=_("Date expired")
|
||||||
)
|
)
|
||||||
@ -59,9 +62,10 @@ class ConnectionToken(OrgModelMixin, JMSBaseModel):
|
|||||||
seconds = 0
|
seconds = 0
|
||||||
return int(seconds)
|
return int(seconds)
|
||||||
|
|
||||||
@classmethod
|
def save(self, *args, **kwargs):
|
||||||
def get_default_date_expired(cls):
|
self.asset_display = pretty_string(self.asset, max_length=128)
|
||||||
return date_expired_default()
|
self.user_display = pretty_string(self.user, max_length=128)
|
||||||
|
return super().save(*args, **kwargs)
|
||||||
|
|
||||||
def expire(self):
|
def expire(self):
|
||||||
self.date_expired = timezone.now()
|
self.date_expired = timezone.now()
|
||||||
@ -69,7 +73,7 @@ class ConnectionToken(OrgModelMixin, JMSBaseModel):
|
|||||||
|
|
||||||
def renewal(self):
|
def renewal(self):
|
||||||
""" 续期 Token,将来支持用户自定义创建 token 后,续期策略要修改 """
|
""" 续期 Token,将来支持用户自定义创建 token 后,续期策略要修改 """
|
||||||
self.date_expired = self.get_default_date_expired()
|
self.date_expired = date_expired_default()
|
||||||
self.save()
|
self.save()
|
||||||
|
|
||||||
# actions 和 expired_at 在 check_valid() 中赋值
|
# actions 和 expired_at 在 check_valid() 中赋值
|
||||||
@ -89,28 +93,52 @@ class ConnectionToken(OrgModelMixin, JMSBaseModel):
|
|||||||
is_valid = False
|
is_valid = False
|
||||||
error = _('No asset or inactive asset')
|
error = _('No asset or inactive asset')
|
||||||
return is_valid, error
|
return is_valid, error
|
||||||
if not self.account_username:
|
if not self.login:
|
||||||
is_valid = False
|
is_valid = False
|
||||||
error = _('No account')
|
error = _('No account')
|
||||||
return is_valid, error
|
return is_valid, error
|
||||||
actions, expire_at = PermAccountUtil().validate_permission(
|
|
||||||
self.user, self.asset, self.account_username
|
permed_account = PermAccountUtil().validate_permission(
|
||||||
|
self.user, self.asset, self.login
|
||||||
)
|
)
|
||||||
if not actions or expire_at < time.time():
|
if not permed_account or not permed_account.actions:
|
||||||
is_valid = False
|
msg = 'user `{}` not has asset `{}` permission for login `{}`'.format(
|
||||||
error = _('User has no permission to access asset or permission expired')
|
self.user, self.asset, self.login
|
||||||
return is_valid, error
|
)
|
||||||
self.actions = actions
|
raise PermissionDenied(msg)
|
||||||
self.expire_at = expire_at
|
|
||||||
|
if permed_account.date_expired < timezone.now():
|
||||||
|
raise PermissionDenied('Expired')
|
||||||
|
|
||||||
is_valid, error = True, ''
|
is_valid, error = True, ''
|
||||||
return is_valid, error
|
return is_valid, error
|
||||||
|
|
||||||
@lazyproperty
|
@lazyproperty
|
||||||
def account(self):
|
def platform(self):
|
||||||
|
return self.asset.platform
|
||||||
|
|
||||||
|
@lazyproperty
|
||||||
|
def accounts(self):
|
||||||
if not self.asset:
|
if not self.asset:
|
||||||
return None
|
return None
|
||||||
account = self.asset.accounts.filter(username=self.account_username).first()
|
|
||||||
return account
|
data = []
|
||||||
|
if self.login == '@INPUT':
|
||||||
|
data.append({
|
||||||
|
'name': self.login,
|
||||||
|
'username': self.username,
|
||||||
|
'secret_type': 'password',
|
||||||
|
'secret': self.secret
|
||||||
|
})
|
||||||
|
else:
|
||||||
|
accounts = self.asset.accounts.filter(username=self.login)
|
||||||
|
for account in accounts:
|
||||||
|
data.append({
|
||||||
|
'username': account.uesrname,
|
||||||
|
'secret_type': account.secret_type,
|
||||||
|
'secret': account.secret if account.secret else self.secret
|
||||||
|
})
|
||||||
|
return data
|
||||||
|
|
||||||
@lazyproperty
|
@lazyproperty
|
||||||
def domain(self):
|
def domain(self):
|
||||||
|
@ -2,9 +2,8 @@ from django.utils.translation import ugettext_lazy as _
|
|||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
from assets.models import Asset, Gateway, Domain, CommandFilterRule, Account, Platform
|
from assets.models import Asset, Gateway, Domain, CommandFilterRule, Account, Platform
|
||||||
|
from assets.serializers import PlatformSerializer
|
||||||
from authentication.models import ConnectionToken
|
from authentication.models import ConnectionToken
|
||||||
from common.utils import pretty_string
|
|
||||||
from common.utils.random import random_string
|
|
||||||
from orgs.mixins.serializers import OrgResourceModelSerializerMixin
|
from orgs.mixins.serializers import OrgResourceModelSerializerMixin
|
||||||
from perms.serializers.permission import ActionChoicesField
|
from perms.serializers.permission import ActionChoicesField
|
||||||
from users.models import User
|
from users.models import User
|
||||||
@ -16,6 +15,8 @@ __all__ = [
|
|||||||
|
|
||||||
|
|
||||||
class ConnectionTokenSerializer(OrgResourceModelSerializerMixin):
|
class ConnectionTokenSerializer(OrgResourceModelSerializerMixin):
|
||||||
|
username = serializers.CharField(max_length=128, label=_("Input username"),
|
||||||
|
allow_null=True, allow_blank=True)
|
||||||
is_valid = serializers.BooleanField(read_only=True, label=_('Validity'))
|
is_valid = serializers.BooleanField(read_only=True, label=_('Validity'))
|
||||||
expire_time = serializers.IntegerField(read_only=True, label=_('Expired time'))
|
expire_time = serializers.IntegerField(read_only=True, label=_('Expired time'))
|
||||||
|
|
||||||
@ -23,9 +24,10 @@ class ConnectionTokenSerializer(OrgResourceModelSerializerMixin):
|
|||||||
model = ConnectionToken
|
model = ConnectionToken
|
||||||
fields_mini = ['id']
|
fields_mini = ['id']
|
||||||
fields_small = fields_mini + [
|
fields_small = fields_mini + [
|
||||||
'secret', 'account_username', 'date_expired',
|
'protocol', 'login', 'secret', 'username',
|
||||||
'date_created', 'date_updated',
|
'date_expired', 'date_created',
|
||||||
'created_by', 'updated_by', 'org_id', 'org_name',
|
'date_updated', 'created_by',
|
||||||
|
'updated_by', 'org_id', 'org_name',
|
||||||
]
|
]
|
||||||
fields_fk = [
|
fields_fk = [
|
||||||
'user', 'asset',
|
'user', 'asset',
|
||||||
@ -45,32 +47,6 @@ class ConnectionTokenSerializer(OrgResourceModelSerializerMixin):
|
|||||||
def get_user(self, attrs):
|
def get_user(self, attrs):
|
||||||
return self.get_request_user()
|
return self.get_request_user()
|
||||||
|
|
||||||
def validate(self, attrs):
|
|
||||||
fields_attrs = self.construct_internal_fields_attrs(attrs)
|
|
||||||
attrs.update(fields_attrs)
|
|
||||||
return attrs
|
|
||||||
|
|
||||||
def construct_internal_fields_attrs(self, attrs):
|
|
||||||
asset = attrs.get('asset') or ''
|
|
||||||
asset_display = pretty_string(str(asset), max_length=128)
|
|
||||||
user = self.get_user(attrs)
|
|
||||||
user_display = pretty_string(str(user), max_length=128)
|
|
||||||
secret = attrs.get('secret') or random_string(16)
|
|
||||||
date_expired = attrs.get('date_expired') or ConnectionToken.get_default_date_expired()
|
|
||||||
org_id = asset.org_id
|
|
||||||
if not isinstance(asset, Asset):
|
|
||||||
error = ''
|
|
||||||
raise serializers.ValidationError(error)
|
|
||||||
attrs = {
|
|
||||||
'user': user,
|
|
||||||
'secret': secret,
|
|
||||||
'user_display': user_display,
|
|
||||||
'asset_display': asset_display,
|
|
||||||
'date_expired': date_expired,
|
|
||||||
'org_id': org_id,
|
|
||||||
}
|
|
||||||
return attrs
|
|
||||||
|
|
||||||
|
|
||||||
class ConnectionTokenDisplaySerializer(ConnectionTokenSerializer):
|
class ConnectionTokenDisplaySerializer(ConnectionTokenSerializer):
|
||||||
class Meta(ConnectionTokenSerializer.Meta):
|
class Meta(ConnectionTokenSerializer.Meta):
|
||||||
@ -122,7 +98,7 @@ class ConnectionTokenAccountSerializer(serializers.ModelSerializer):
|
|||||||
class Meta:
|
class Meta:
|
||||||
model = Account
|
model = Account
|
||||||
fields = [
|
fields = [
|
||||||
'id', 'name', 'username', 'secret_type', 'secret', 'version'
|
'username', 'secret_type', 'secret',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@ -154,26 +130,31 @@ class ConnectionTokenCmdFilterRuleSerializer(serializers.ModelSerializer):
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class ConnectionTokenPlatform(serializers.ModelSerializer):
|
class ConnectionTokenPlatform(PlatformSerializer):
|
||||||
class Meta:
|
class Meta(PlatformSerializer.Meta):
|
||||||
model = Platform
|
model = Platform
|
||||||
fields = ['id', 'name', 'org_id']
|
|
||||||
|
def get_field_names(self, declared_fields, info):
|
||||||
|
names = super().get_field_names(declared_fields, info)
|
||||||
|
names = [n for n in names if n not in ['automation']]
|
||||||
|
return names
|
||||||
|
|
||||||
|
|
||||||
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)
|
||||||
platform = ConnectionTokenPlatform(read_only=True)
|
platform = ConnectionTokenPlatform(read_only=True)
|
||||||
account = ConnectionTokenAccountSerializer(read_only=True)
|
accounts = ConnectionTokenAccountSerializer(read_only=True, many=True)
|
||||||
gateway = ConnectionTokenGatewaySerializer(read_only=True)
|
gateway = ConnectionTokenGatewaySerializer(read_only=True)
|
||||||
cmd_filter_rules = ConnectionTokenCmdFilterRuleSerializer(many=True)
|
# cmd_filter_rules = ConnectionTokenCmdFilterRuleSerializer(many=True)
|
||||||
actions = ActionChoicesField()
|
actions = ActionChoicesField()
|
||||||
expire_at = serializers.IntegerField()
|
expire_at = serializers.IntegerField()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ConnectionToken
|
model = ConnectionToken
|
||||||
fields = [
|
fields = [
|
||||||
'id', 'secret', 'user', 'asset', 'account_username',
|
'id', 'secret', 'user', 'asset', 'login',
|
||||||
'account', 'protocol', 'domain', 'gateway',
|
'accounts', 'protocol', 'domain', 'gateway',
|
||||||
'cmd_filter_rules', 'actions', 'expire_at',
|
'actions', 'expire_at',
|
||||||
|
'platform',
|
||||||
]
|
]
|
||||||
|
@ -344,7 +344,7 @@ def get_file_by_arch(dir, filename):
|
|||||||
return file_path
|
return file_path
|
||||||
|
|
||||||
|
|
||||||
def pretty_string(data: str, max_length=128, ellipsis_str='...'):
|
def pretty_string(data, max_length=128, ellipsis_str='...'):
|
||||||
"""
|
"""
|
||||||
params:
|
params:
|
||||||
data: abcdefgh
|
data: abcdefgh
|
||||||
@ -353,6 +353,7 @@ def pretty_string(data: str, max_length=128, ellipsis_str='...'):
|
|||||||
return:
|
return:
|
||||||
ab...gh
|
ab...gh
|
||||||
"""
|
"""
|
||||||
|
data = str(data)
|
||||||
if len(data) < max_length:
|
if len(data) < max_length:
|
||||||
return data
|
return data
|
||||||
remain_length = max_length - len(ellipsis_str)
|
remain_length = max_length - len(ellipsis_str)
|
||||||
|
3
apps/common/utils/geoip/GeoLite2-City.mmdb
Normal file
3
apps/common/utils/geoip/GeoLite2-City.mmdb
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:860b4d38beff81667c64da41c026a7dd28c3c93a28ae61fefaa7c26875f35638
|
||||||
|
size 73906864
|
@ -6,7 +6,7 @@ from django.utils.translation import ugettext_lazy as _
|
|||||||
|
|
||||||
default_interface = dict((
|
default_interface = dict((
|
||||||
('logo_logout', static('img/logo.png')),
|
('logo_logout', static('img/logo.png')),
|
||||||
('logo_index', static('img/logo_text.png')),
|
('logo_index', static('img/logo_text_white.png')),
|
||||||
('login_image', static('img/login_image.jpg')),
|
('login_image', static('img/login_image.jpg')),
|
||||||
('favicon', static('img/facio.ico')),
|
('favicon', static('img/facio.ico')),
|
||||||
('login_title', _('JumpServer Open Source Bastion Host')),
|
('login_title', _('JumpServer Open Source Bastion Host')),
|
||||||
|
5
apps/perms/api/perm_token.py
Normal file
5
apps/perms/api/perm_token.py
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
from rest_framework.viewsets import ModelViewSet
|
||||||
|
|
||||||
|
|
||||||
|
class PermTokenViewSet(ModelViewSet):
|
||||||
|
pass
|
@ -17,10 +17,8 @@ class PermAccountUtil(AssetPermissionUtil):
|
|||||||
"""
|
"""
|
||||||
permed_accounts = self.get_permed_accounts_for_user(user, asset)
|
permed_accounts = self.get_permed_accounts_for_user(user, asset)
|
||||||
accounts_mapper = {account.username: account for account in permed_accounts}
|
accounts_mapper = {account.username: account for account in permed_accounts}
|
||||||
|
|
||||||
account = accounts_mapper.get(account_username)
|
account = accounts_mapper.get(account_username)
|
||||||
actions, date_expired = (account.actions, account.date_expired) if account else (False, None)
|
return account
|
||||||
return actions, date_expired
|
|
||||||
|
|
||||||
def get_permed_accounts_for_user(self, user, asset):
|
def get_permed_accounts_for_user(self, user, asset):
|
||||||
""" 获取授权给用户某个资产的账号 """
|
""" 获取授权给用户某个资产的账号 """
|
||||||
|
48
apps/tickets/migrations/0024_auto_20221121_1800.py
Normal file
48
apps/tickets/migrations/0024_auto_20221121_1800.py
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
# Generated by Django 3.2.14 on 2022-11-21 10:00
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('tickets', '0023_alter_applyassetticket_apply_actions'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='approvalrule',
|
||||||
|
name='strategy',
|
||||||
|
field=models.CharField(choices=[('org_admin', 'Org admin'), ('custom_user', 'Custom user'), ('super_admin', 'Super admin'), ('super_org_admin', 'Super admin and org admin')], default='super_admin', max_length=64, verbose_name='Approve strategy'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='ticket',
|
||||||
|
name='state',
|
||||||
|
field=models.CharField(choices=[('pending', 'Open'), ('closed', 'Cancel'), ('reopen', 'Reopen'), ('approved', 'Approved'), ('rejected', 'Rejected')], default='pending', max_length=16, verbose_name='State'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='ticket',
|
||||||
|
name='type',
|
||||||
|
field=models.CharField(choices=[('general', 'General'), ('apply_asset', 'Apply for asset'), ('login_confirm', 'Login confirm'), ('command_confirm', 'Command confirm'), ('login_asset_confirm', 'Login asset confirm')], default='general', max_length=64, verbose_name='Type'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='ticketassignee',
|
||||||
|
name='state',
|
||||||
|
field=models.CharField(choices=[('pending', 'Open'), ('closed', 'Cancel'), ('reopen', 'Reopen'), ('approved', 'Approved'), ('rejected', 'Rejected')], default='pending', max_length=64),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='ticketflow',
|
||||||
|
name='type',
|
||||||
|
field=models.CharField(choices=[('general', 'General'), ('apply_asset', 'Apply for asset'), ('login_confirm', 'Login confirm'), ('command_confirm', 'Command confirm'), ('login_asset_confirm', 'Login asset confirm')], default='general', max_length=64, verbose_name='Type'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='ticketstep',
|
||||||
|
name='state',
|
||||||
|
field=models.CharField(choices=[('pending', 'Pending'), ('closed', 'Closed'), ('reopen', 'Reopen'), ('approved', 'Approved'), ('rejected', 'Rejected')], default='pending', max_length=64, verbose_name='State'),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='ticketstep',
|
||||||
|
name='status',
|
||||||
|
field=models.CharField(choices=[('active', 'Active'), ('closed', 'Closed'), ('pending', 'Pending')], default='pending', max_length=16),
|
||||||
|
),
|
||||||
|
]
|
Loading…
Reference in New Issue
Block a user