pref: 暂存 客户端连接方式

pull/9129/head
ibuler 2022-11-28 22:58:43 +08:00
parent 742cac1e90
commit f6bdc7f81c
7 changed files with 96 additions and 38 deletions

View File

@ -11,6 +11,7 @@ from rest_framework.decorators import action
from rest_framework.exceptions import PermissionDenied
from rest_framework.request import Request
from rest_framework.response import Response
from rest_framework.serializers import ValidationError
from common.drf.api import JMSModelViewSet
from common.http import is_true
@ -18,6 +19,7 @@ from common.utils import random_string
from orgs.mixins.api import RootOrgViewMixin
from perms.models import ActionChoices
from terminal.models import EndpointRule
from terminal.const import NativeClient
from ..models import ConnectionToken
from ..serializers import (
ConnectionTokenSerializer, ConnectionTokenSecretSerializer,
@ -128,19 +130,20 @@ class RDPFileClientProtocolURLMixin:
return true_value if is_true(os.getenv(env_key, env_default)) else false_value
def get_client_protocol_data(self, token: ConnectionToken):
protocol = token.protocol
username = token.user.username
rdp_config = ssh_token = ''
if protocol == 'rdp':
filename, rdp_config = self.get_rdp_file_info(token)
elif protocol == 'ssh':
connect_method = token.connect_method
if connect_method == NativeClient.ssh:
filename, ssh_token = self.get_ssh_token(token)
elif connect_method == NativeClient.mstsc:
filename, rdp_config = self.get_rdp_file_info(token)
else:
raise ValueError('Protocol not support: {}'.format(protocol))
raise ValueError('Protocol not support: {}'.format(connect_method))
return {
"filename": filename,
"protocol": protocol,
"protocol": token.protocol,
"username": username,
"token": ssh_token,
"config": rdp_config
@ -234,14 +237,25 @@ class ConnectionTokenViewSet(ExtraActionApiMixin, RootOrgViewMixin, JMSModelView
rbac_perm = 'authentication.view_connectiontokensecret'
if not request.user.has_perm(rbac_perm):
raise PermissionDenied('Not allow to view secret')
token_id = request.data.get('token') or ''
token_id = request.data.get('id') or ''
token = get_object_or_404(ConnectionToken, pk=token_id)
if token.is_expired:
raise ValidationError({'id': 'Token is expired'})
token.is_valid()
serializer = self.get_serializer(instance=token)
expire_now = request.data.get('expire_now', True)
if expire_now:
token.expire()
return Response(serializer.data, status=status.HTTP_200_OK)
def get_queryset(self):
return ConnectionToken.objects.filter(user=self.request.user)
queryset = ConnectionToken.objects\
.filter(user=self.request.user)\
.filter(date_expired__lt=timezone.now())
return queryset
def get_user(self, serializer):
return self.request.user
@ -299,7 +313,7 @@ class SuperConnectionTokenViewSet(ConnectionTokenViewSet):
def renewal(self, request, *args, **kwargs):
from common.utils.timezone import as_current_tz
token_id = request.data.get('token') or ''
token_id = request.data.get('id') or ''
token = get_object_or_404(ConnectionToken, pk=token_id)
date_expired = as_current_tz(token.date_expired)
if token.is_expired:

View File

@ -26,20 +26,20 @@ class Migration(migrations.Migration):
old_name='username',
new_name='input_username',
),
migrations.AddField(
model_name='connectiontoken',
name='input_secret',
field=common.db.fields.EncryptCharField(default='', max_length=128, verbose_name='Input Secret'),
),
migrations.AlterField(
model_name='connectiontoken',
name='account_name',
field=models.CharField(max_length=128, verbose_name='Account name'),
),
migrations.AlterField(
model_name='connectiontoken',
name='input_secret',
field=common.db.fields.EncryptCharField(blank=True, default='', max_length=128, verbose_name='Input Secret'),
),
migrations.AlterField(
model_name='connectiontoken',
name='input_username',
field=models.CharField(default='', max_length=128, verbose_name='Input Username'),
field=models.CharField(blank=True, default='', max_length=128, verbose_name='Input Username'),
),
migrations.AlterField(
model_name='connectiontoken',

View File

@ -0,0 +1,20 @@
# Generated by Django 3.2.14 on 2022-11-28 13:48
import common.db.fields
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('authentication', '0016_auto_20221125_2240'),
]
operations = [
migrations.AddField(
model_name='connectiontoken',
name='connect_method',
field=models.CharField(default='web_ui', max_length=32, verbose_name='Connect method'),
preserve_default=False,
),
]

View File

@ -34,6 +34,7 @@ class ConnectionToken(OrgModelMixin, JMSBaseModel):
protocol = models.CharField(
choices=Protocol.choices, max_length=16, default=Protocol.ssh, verbose_name=_("Protocol")
)
connect_method = models.CharField(max_length=32, verbose_name=_("Connect method"))
user_display = models.CharField(max_length=128, default='', verbose_name=_("User display"))
asset_display = models.CharField(max_length=128, default='', verbose_name=_("Asset display"))
date_expired = models.DateTimeField(

View File

@ -109,16 +109,10 @@ class ConnectionTokenGatewaySerializer(serializers.ModelSerializer):
class Meta:
model = Asset
fields = ['id', 'address', 'port', 'username', 'password', 'private_key']
class ConnectionTokenDomainSerializer(serializers.ModelSerializer):
""" Domain """
gateways = ConnectionTokenGatewaySerializer(many=True, read_only=True)
class Meta:
model = Domain
fields = ['id', 'name', 'gateways']
fields = [
'id', 'address', 'port', 'username',
'password', 'private_key'
]
class ConnectionTokenCmdFilterRuleSerializer(serializers.ModelSerializer):
@ -143,6 +137,7 @@ class ConnectionTokenPlatform(PlatformSerializer):
class ConnectionTokenSecretSerializer(OrgResourceModelSerializerMixin):
expire_now = serializers.BooleanField(label=_('Expired now'), default=True)
user = ConnectionTokenUserSerializer(read_only=True)
asset = ConnectionTokenAssetSerializer(read_only=True)
platform = ConnectionTokenPlatform(read_only=True)
@ -155,7 +150,10 @@ class ConnectionTokenSecretSerializer(OrgResourceModelSerializerMixin):
class Meta:
model = ConnectionToken
fields = [
'id', 'value', 'user', 'asset', 'account',
'protocol', 'domain', 'gateway',
'actions', 'expire_at', 'platform',
'id', 'value', 'user', 'asset', 'platform', 'account',
'protocol', 'gateway', 'actions', 'expire_at', 'expire_now',
]
extra_kwargs = {
'value': {'read_only': True},
'expire_now': {'write_only': True},
}

View File

@ -0,0 +1,21 @@
# Generated by Django 3.2.14 on 2022-11-28 13:48
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('ops', '0035_jobexecution_org_id'),
]
operations = [
migrations.AlterModelOptions(
name='job',
options={'ordering': ['date_created']},
),
migrations.AlterModelOptions(
name='jobexecution',
options={'ordering': ['-date_created']},
),
]

View File

@ -96,17 +96,21 @@ class NativeClient(TextChoices):
@classmethod
def get_launch_command(cls, name, os='windows'):
commands = {
'ssh': 'ssh {username}@{hostname} -p {port}',
'putty': 'putty -ssh {username}@{hostname} -P {port}',
'xshell': '-url ssh://root:passwd@192.168.10.100',
'mysql': 'mysql -h {hostname} -P {port} -u {username} -p',
'psql': {
'default': 'psql -h {hostname} -p {port} -U {username} -W',
'windows': 'psql /h {hostname} /p {port} /U {username} -W',
cls.ssh: 'ssh {token.id}@{endpoint.ip} -p {endpoint.port}',
cls.putty: 'putty-ssh {token.id}@{endpoint.ip} -P {endpoint.port}',
cls.xshell: 'xshell -url ssh://{token.id}:{token.value}@{endpoint.ip}:{endpoint.port}',
# 'mysql': 'mysql -h {hostname} -P {port} -u {username} -p',
# 'psql': {
# 'default': 'psql -h {hostname} -p {port} -U {username} -W',
# 'windows': 'psql /h {hostname} /p {port} /U {username} -W',
# },
# 'sqlplus': 'sqlplus {username}/{password}@{hostname}:{port}',
# 'redis': 'redis-cli -h {hostname} -p {port} -a {password}',
cls.mstsc: {
'command': "$open_file$",
'file': {
}
},
'sqlplus': 'sqlplus {username}/{password}@{hostname}:{port}',
'redis': 'redis-cli -h {hostname} -p {port} -a {password}',
'mstsc': 'mstsc /v:{hostname}:{port}',
}
command = commands.get(name)
if isinstance(command, dict):