pref: 后端返回 connect types

pull/9115/head
ibuler 2022-11-17 20:48:50 +08:00
parent 4591b03e17
commit 04ee7ee0e7
6 changed files with 180 additions and 83 deletions

View File

@ -2,13 +2,11 @@ from django.shortcuts import get_object_or_404
from django.utils.translation import ugettext_lazy as _
from rest_framework import status
from rest_framework.decorators import action
from rest_framework.generics import ListAPIView
from rest_framework.request import Request
from rest_framework.response import Response
from assets.models import Asset
from common.drf.api import JMSBulkModelViewSet
from common.permissions import IsValidUser
from common.permissions import IsValidUserOrConnectionToken
from orgs.utils import tmp_to_root_org
from terminal import serializers
@ -98,15 +96,3 @@ class EndpointRuleViewSet(JMSBulkModelViewSet):
search_fields = filterset_fields
serializer_class = serializers.EndpointRuleSerializer
queryset = EndpointRule.objects.all()
class ConnectMethodListApi(ListAPIView):
permission_classes = (IsValidUser,)
# serializer_class = serializers.ProtocolConnectMethodsSerializer
def get_queryset(self):
protocol = self.request.query_params.get('protocol')
if not protocol:
return []
return Protocol.objects.filter(name=protocol)

View File

@ -1,26 +1,24 @@
# -*- coding: utf-8 -*-
#
import logging
import uuid
from django.core.cache import cache
from rest_framework import generics
from rest_framework.views import APIView, Response
from rest_framework import status
from django.conf import settings
from django.utils.translation import gettext_lazy as _
from rest_framework import generics
from rest_framework import status
from rest_framework.views import APIView, Response
from common.exceptions import JMSException
from common.drf.api import JMSBulkModelViewSet
from common.utils import get_object_or_none, get_request_ip
from common.exceptions import JMSException
from common.permissions import IsValidUser
from common.permissions import WithBootstrapToken
from terminal.models import Terminal
from terminal import serializers
from terminal import exceptions
from terminal.const import TerminalType
from terminal.models import Terminal
__all__ = [
'TerminalViewSet', 'TerminalConfig',
'TerminalRegistrationApi',
'TerminalViewSet', 'TerminalConfig',
'TerminalRegistrationApi', 'ConnectMethodListApi'
]
logger = logging.getLogger(__file__)
@ -72,3 +70,22 @@ class TerminalRegistrationApi(generics.CreateAPIView):
data = {"error": "service account registration disabled"}
return Response(data=data, status=status.HTTP_400_BAD_REQUEST)
return super().create(request, *args, **kwargs)
class ConnectMethodListApi(generics.ListAPIView):
serializer_class = serializers.ConnectMethodSerializer
permission_classes = [IsValidUser]
def get_queryset(self):
user_agent = self.request.META['HTTP_USER_AGENT'].lower()
if 'macintosh' in user_agent:
os = 'macos'
elif 'windows' in user_agent:
os = 'windows'
else:
os = 'linux'
return TerminalType.get_protocols_connect_methods(os)
def list(self, request, *args, **kwargs):
queryset = self.get_queryset()
return Response(queryset)

View File

@ -1,5 +1,6 @@
# -*- coding: utf-8 -*-
#
from collections import defaultdict
from django.db.models import TextChoices
from django.utils.translation import ugettext_lazy as _
@ -43,24 +44,12 @@ class ComponentLoad(TextChoices):
return set(dict(cls.choices).keys())
class TerminalType(TextChoices):
koko = 'koko', 'KoKo'
guacamole = 'guacamole', 'Guacamole'
omnidb = 'omnidb', 'OmniDB'
xrdp = 'xrdp', 'Xrdp'
lion = 'lion', 'Lion'
core = 'core', 'Core'
celery = 'celery', 'Celery'
magnus = 'magnus', 'Magnus'
razor = 'razor', 'Razor'
tinker = 'tinker', 'Tinker'
@classmethod
def types(cls):
return set(dict(cls.choices).keys())
class HttpMethod(TextChoices):
web_gui = 'web_gui', 'Web GUI'
web_cli = 'web_cli', 'Web CLI'
class NativeClient:
class NativeClient(TextChoices):
# Koko
ssh = 'ssh', 'ssh'
putty = 'putty', 'PuTTY'
@ -71,15 +60,42 @@ class NativeClient:
psql = 'psql', 'psql'
sqlplus = 'sqlplus', 'sqlplus'
redis = 'redis-cli', 'redis-cli'
mongodb = 'mongo', 'mongo'
# Razor
mstsc = 'mstsc', 'Remote Desktop'
@classmethod
def get_native_clients(cls, p, os='windows'):
def get_native_clients(cls):
clients = {
''
Protocol.ssh: {
'default': [cls.ssh],
'windows': [cls.putty],
},
Protocol.rdp: [cls.mstsc],
Protocol.mysql: [cls.mysql],
Protocol.oracle: [cls.sqlplus],
Protocol.postgresql: [cls.psql],
Protocol.redis: [cls.redis],
Protocol.mongodb: [cls.mongodb],
}
return clients
@classmethod
def get_native_methods(cls, os='windows'):
clients_map = cls.get_native_clients()
methods = defaultdict(list)
for protocol, _clients in clients_map.items():
if isinstance(_clients, dict):
_clients = _clients.get(os, _clients['default'])
for client in _clients:
methods[protocol].append({
'value': client.value,
'label': client.label,
'type': 'native',
})
return methods
@classmethod
def get_launch_command(cls, name, os='windows'):
@ -104,33 +120,113 @@ class NativeClient:
class RemoteAppMethod:
@classmethod
def get_remote_app_methods(cls, protocol):
def get_remote_app_methods(cls):
from .models import Applet
applets = Applet.objects.filter(protocol=protocol)
return applets
applets = Applet.objects.all()
methods = defaultdict(list)
for applet in applets:
for protocol in applet.protocols:
methods[protocol].append({
'value': applet.name,
'label': applet.display_name,
'icon': applet.icon,
'type': 'remote_app',
})
return methods
class ConnectMethod(TextChoices):
web_cli = 'web_cli', _('Web CLI')
web_gui = 'web_gui', _('Web GUI')
native_client = 'native_client', _('Native Client')
remote_app = 'remote_app', _('Remote App')
class TerminalType(TextChoices):
koko = 'koko', 'KoKo'
guacamole = 'guacamole', 'Guacamole'
omnidb = 'omnidb', 'OmniDB'
xrdp = 'xrdp', 'Xrdp'
lion = 'lion', 'Lion'
core = 'core', 'Core'
celery = 'celery', 'Celery'
magnus = 'magnus', 'Magnus'
razor = 'razor', 'Razor'
tinker = 'tinker', 'Tinker'
@classmethod
def methods(cls):
def types(cls):
return set(dict(cls.choices).keys())
@classmethod
def protocols(cls):
return {
Protocol.ssh: [cls.web_cli, cls.native_client],
Protocol.rdp: ([cls.web_gui], [cls.native_client]),
Protocol.vnc: [cls.web_gui],
Protocol.telnet: [cls.web_cli, cls.native_client],
Protocol.mysql: [cls.web_cli, cls.web_gui, cls.native_client],
Protocol.sqlserver: [cls.web_cli, cls.web_gui],
Protocol.oracle: [cls.web_cli, cls.web_gui],
Protocol.postgresql: [cls.web_cli, cls.web_gui],
Protocol.redis: [cls.web_cli, cls.web_gui, cls.native_client],
Protocol.mongodb: [cls.web_cli, cls.web_gui],
Protocol.k8s: [cls.web_cli],
Protocol.http: [],
cls.koko: {
'http_method': HttpMethod.web_cli,
'listen': [Protocol.ssh, Protocol.http],
'support': [
Protocol.ssh, Protocol.telnet,
Protocol.mysql, Protocol.postgresql,
Protocol.oracle, Protocol.sqlserver,
Protocol.mariadb, Protocol.redis,
Protocol.mongodb,
],
'match': 'm2m'
},
cls.omnidb: {
'http_method': HttpMethod.web_gui,
'listen': [Protocol.http],
'support': [
Protocol.mysql, Protocol.postgresql, Protocol.oracle,
Protocol.sqlserver, Protocol.mariadb
],
'match': 'm2m'
},
cls.lion: {
'http_method': HttpMethod.web_gui,
'listen': [Protocol.http],
'support': [Protocol.rdp, Protocol.vnc],
'match': 'm2m'
},
cls.magnus: {
'listen': [],
'support': [
Protocol.mysql, Protocol.postgresql, Protocol.oracle,
Protocol.mariadb
],
'match': 'map'
},
cls.razor: {
'listen': [Protocol.rdp],
'support': [Protocol.rdp],
'match': 'map'
}
}
@classmethod
def get_protocols_connect_methods(cls, os):
methods = defaultdict(list)
native_methods = NativeClient.get_native_methods(os)
remote_app_methods = RemoteAppMethod.get_remote_app_methods()
for component, component_protocol in cls.protocols().items():
component_methods = defaultdict(list)
support = component_protocol['support']
for protocol in support:
if component_protocol['match'] == 'map':
listen = [protocol]
else:
listen = component_protocol['listen']
for listen_protocol in listen:
if listen_protocol == Protocol.http:
web_protocol = component_protocol['http_method']
component_methods[protocol.value].append({
'value': web_protocol.value,
'label': web_protocol.label,
'type': 'web',
})
# Native method
component_methods[protocol.value].extend(native_methods[listen_protocol])
component_methods[protocol.value].extend(remote_app_methods[listen_protocol])
for protocol, _methods in component_methods.items():
for method in _methods:
method['component'] = component.value
methods[protocol].extend(_methods)
return methods

View File

@ -1,19 +1,16 @@
import uuid
import time
import uuid
from django.utils import timezone
from django.db import models
from django.core.cache import cache
from django.utils.translation import ugettext_lazy as _
from django.conf import settings
from django.db import models
from django.utils.translation import ugettext_lazy as _
from common.utils import get_logger, lazyproperty
from users.models import User
from orgs.utils import tmp_to_root_org
from terminal.const import TerminalType as TypeChoices, ComponentLoad as StatusChoice
from terminal.const import TerminalType as TypeChoices
from users.models import User
from ..session import Session
logger = get_logger(__file__)
@ -87,7 +84,8 @@ class Terminal(StorageMixin, TerminalStatusMixin, models.Model):
remote_addr = models.CharField(max_length=128, blank=True, verbose_name=_('Remote Address'))
command_storage = models.CharField(max_length=128, verbose_name=_("Command storage"), default='default')
replay_storage = models.CharField(max_length=128, verbose_name=_("Replay storage"), default='default')
user = models.OneToOneField(User, related_name='terminal', verbose_name='Application User', null=True, on_delete=models.CASCADE)
user = models.OneToOneField(User, related_name='terminal', verbose_name='Application User', null=True,
on_delete=models.CASCADE)
is_deleted = models.BooleanField(default=False)
date_created = models.DateTimeField(auto_now_add=True)
comment = models.TextField(blank=True, verbose_name=_('Comment'))
@ -160,4 +158,3 @@ class Terminal(StorageMixin, TerminalStatusMixin, models.Model):
permissions = (
('view_terminalconfig', _('Can view terminal config')),
)

View File

@ -136,4 +136,6 @@ class TerminalRegistrationSerializer(serializers.ModelSerializer):
class ConnectMethodSerializer(serializers.Serializer):
name = serializers.CharField(max_length=128)
value = serializers.CharField(max_length=128)
label = serializers.CharField(max_length=128)
group = serializers.CharField(max_length=128)

View File

@ -31,7 +31,6 @@ router.register(r'applet-hosts', api.AppletHostViewSet, 'applet-host')
router.register(r'applet-publications', api.AppletPublicationViewSet, 'applet-publication')
router.register(r'applet-host-deployments', api.AppletHostDeploymentViewSet, 'applet-host-deployment')
urlpatterns = [
path('my-sessions/', api.MySessionAPIView.as_view(), name='my-session'),
path('terminal-registrations/', api.TerminalRegistrationApi.as_view(), name='terminal-registration'),
@ -44,10 +43,13 @@ urlpatterns = [
path('tasks/kill-session-for-ticket/', api.KillSessionForTicketAPI.as_view(), name='kill-session-for-ticket'),
path('terminals/config/', api.TerminalConfig.as_view(), name='terminal-config'),
path('commands/insecure-command/', api.InsecureCommandAlertAPI.as_view(), name="command-alert"),
path('replay-storages/<uuid:pk>/test-connective/', api.ReplayStorageTestConnectiveApi.as_view(), name='replay-storage-test-connective'),
path('command-storages/<uuid:pk>/test-connective/', api.CommandStorageTestConnectiveApi.as_view(), name='command-storage-test-connective'),
path('replay-storages/<uuid:pk>/test-connective/', api.ReplayStorageTestConnectiveApi.as_view(),
name='replay-storage-test-connective'),
path('command-storages/<uuid:pk>/test-connective/', api.CommandStorageTestConnectiveApi.as_view(),
name='command-storage-test-connective'),
# components
path('components/metrics/', api.ComponentsMetricsAPIView.as_view(), name='components-metrics'),
path('components/connect-methods/', api.ConnectMethodListApi.as_view(), name='connect-methods'),
]
old_version_urlpatterns = [
@ -55,6 +57,3 @@ old_version_urlpatterns = [
]
urlpatterns += router.urls + old_version_urlpatterns