perf: Admin connection token

pull/14431/head
feng 2024-11-12 10:26:34 +08:00 committed by feng626
parent 0b9887d18f
commit 914110b64c
6 changed files with 92 additions and 13 deletions

View File

@ -15,17 +15,17 @@ class Migration(migrations.Migration):
name="risk", name="risk",
field=models.CharField( field=models.CharField(
choices=[ choices=[
("zombie", "Long time no login"), ('zombie', 'Long time no login'),
("ghost", "Not managed"), ('ghost', 'Not managed'),
("long_time_password", "Long time no change"), ('long_time_password', 'Long time no change'),
("weak_password", "Weak password"), ('weak_password', 'Weak password'),
("group_changed", "Group change"), ('password_error', 'Password error'),
("sudo_changed", "Sudo changed"), ('password_expired', 'Password expired'),
("account_deleted", "Account delete"), ('group_changed', 'Group change'),
("password_expired", "Password expired"), ('sudo_changed', 'Sudo changed'),
("no_admin_account", "No admin account"), ('account_deleted', 'Account delete'),
("password_error", "Password error"), ('no_admin_account', 'No admin account'),
("others", "Others"), ('others', 'Others')
], ],
max_length=128, max_length=128,
verbose_name="Risk", verbose_name="Risk",

View File

@ -29,14 +29,14 @@ from terminal.models import EndpointRule, Endpoint
from users.const import FileNameConflictResolution from users.const import FileNameConflictResolution
from users.const import RDPSmartSize, RDPColorQuality from users.const import RDPSmartSize, RDPColorQuality
from users.models import Preference from users.models import Preference
from ..models import ConnectionToken, date_expired_default from ..models import ConnectionToken, AdminConnectionToken, date_expired_default
from ..serializers import ( from ..serializers import (
ConnectionTokenSerializer, ConnectionTokenSecretSerializer, ConnectionTokenSerializer, ConnectionTokenSecretSerializer,
SuperConnectionTokenSerializer, ConnectTokenAppletOptionSerializer, SuperConnectionTokenSerializer, ConnectTokenAppletOptionSerializer,
ConnectionTokenReusableSerializer, ConnectTokenVirtualAppOptionSerializer ConnectionTokenReusableSerializer, ConnectTokenVirtualAppOptionSerializer
) )
__all__ = ['ConnectionTokenViewSet', 'SuperConnectionTokenViewSet'] __all__ = ['ConnectionTokenViewSet', 'SuperConnectionTokenViewSet', 'AdminConnectionTokenViewSet']
logger = get_logger(__name__) logger = get_logger(__name__)
@ -558,3 +558,14 @@ class SuperConnectionTokenViewSet(ConnectionTokenViewSet):
else: else:
logger.error('Release applet account error: {}'.format(lock_key)) logger.error('Release applet account error: {}'.format(lock_key))
return Response({'error': 'not found or expired'}, status=400) return Response({'error': 'not found or expired'}, status=400)
class AdminConnectionTokenViewSet(SuperConnectionTokenViewSet):
def check_permissions(self, request):
user = request.user
if not user.is_superuser:
self.permission_denied(request)
def get_queryset(self):
return AdminConnectionToken.objects.all()

View File

@ -37,3 +37,9 @@ class MFAType(TextChoices):
SMS = MFASms.name, MFASms.display_name SMS = MFASms.name, MFASms.display_name
Radius = MFARadius.name, MFARadius.display_name Radius = MFARadius.name, MFARadius.display_name
Custom = MFACustom.name, MFACustom.display_name Custom = MFACustom.name, MFACustom.display_name
class ConnectionTokenType(TextChoices):
ADMIN = 'admin', 'Admin'
SUPER = 'super', 'Super'
USER = 'user', 'User'

View File

@ -0,0 +1,30 @@
# Generated by Django 4.1.13 on 2024-11-11 11:04
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('authentication', '0003_sshkey'),
]
operations = [
migrations.AddField(
model_name='connectiontoken',
name='type',
field=models.CharField(choices=[('admin', 'Admin'), ('super', 'Super'), ('user', 'User')], default='user', max_length=16, verbose_name='Type'),
),
migrations.CreateModel(
name='AdminConnectionToken',
fields=[
],
options={
'verbose_name': 'Admin connection token',
'proxy': True,
'indexes': [],
'constraints': [],
},
bases=('authentication.connectiontoken',),
),
]

View File

@ -12,6 +12,7 @@ from rest_framework.exceptions import PermissionDenied
from accounts.models import VirtualAccount from accounts.models import VirtualAccount
from assets.const import Protocol from assets.const import Protocol
from assets.const.host import GATEWAY_NAME from assets.const.host import GATEWAY_NAME
from authentication.const import ConnectionTokenType
from common.db.fields import EncryptTextField from common.db.fields import EncryptTextField
from common.exceptions import JMSException from common.exceptions import JMSException
from common.utils import lazyproperty, pretty_string, bulk_get from common.utils import lazyproperty, pretty_string, bulk_get
@ -26,6 +27,8 @@ def date_expired_default():
class ConnectionToken(JMSOrgBaseModel): class ConnectionToken(JMSOrgBaseModel):
_type = ConnectionTokenType.USER
value = models.CharField(max_length=64, default='', verbose_name=_("Value")) value = models.CharField(max_length=64, default='', verbose_name=_("Value"))
user = models.ForeignKey( user = models.ForeignKey(
'users.User', on_delete=models.SET_NULL, null=True, blank=True, 'users.User', on_delete=models.SET_NULL, null=True, blank=True,
@ -52,6 +55,11 @@ class ConnectionToken(JMSOrgBaseModel):
) )
is_active = models.BooleanField(default=True, verbose_name=_("Active")) is_active = models.BooleanField(default=True, verbose_name=_("Active"))
type = models.CharField(
max_length=16, choices=ConnectionTokenType.choices,
default=ConnectionTokenType.USER, verbose_name=_('Type')
)
class Meta: class Meta:
ordering = ('-date_expired',) ordering = ('-date_expired',)
permissions = [ permissions = [
@ -60,6 +68,10 @@ class ConnectionToken(JMSOrgBaseModel):
] ]
verbose_name = _('Connection token') verbose_name = _('Connection token')
def save(self, *args, **kwargs):
self.type = self._meta.model._type
return super().save(*args, **kwargs)
@property @property
def is_expired(self): def is_expired(self):
return self.date_expired < timezone.now() return self.date_expired < timezone.now()
@ -268,9 +280,28 @@ class ConnectionToken(JMSOrgBaseModel):
class SuperConnectionToken(ConnectionToken): class SuperConnectionToken(ConnectionToken):
_type = ConnectionTokenType.SUPER
class Meta: class Meta:
proxy = True proxy = True
permissions = [ permissions = [
('view_superconnectiontokensecret', _('Can view super connection token secret')) ('view_superconnectiontokensecret', _('Can view super connection token secret'))
] ]
verbose_name = _("Super connection token") verbose_name = _("Super connection token")
class AdminConnectionTokenManager(models.Manager):
def get_queryset(self):
queryset = super().get_queryset()
queryset = queryset.filter(type=ConnectionTokenType.ADMIN)
return queryset
class AdminConnectionToken(ConnectionToken):
_type = ConnectionTokenType.ADMIN
objects = AdminConnectionTokenManager()
class Meta:
proxy = True
verbose_name = _("Admin connection token")

View File

@ -13,6 +13,7 @@ router.register('sso', api.SSOViewSet, 'sso')
router.register('temp-tokens', api.TempTokenViewSet, 'temp-token') router.register('temp-tokens', api.TempTokenViewSet, 'temp-token')
router.register('connection-token', api.ConnectionTokenViewSet, 'connection-token') router.register('connection-token', api.ConnectionTokenViewSet, 'connection-token')
router.register('super-connection-token', api.SuperConnectionTokenViewSet, 'super-connection-token') router.register('super-connection-token', api.SuperConnectionTokenViewSet, 'super-connection-token')
router.register('admin-connection-token', api.AdminConnectionTokenViewSet, 'admin-connection-token')
router.register('confirm', api.UserConfirmationViewSet, 'confirm') router.register('confirm', api.UserConfirmationViewSet, 'confirm')
router.register('ssh-key', api.SSHkeyViewSet, 'ssh-key') router.register('ssh-key', api.SSHkeyViewSet, 'ssh-key')