mirror of https://github.com/jumpserver/jumpserver
commit
787be3ff7a
|
@ -4,9 +4,38 @@ from rest_framework import serializers
|
||||||
from rest_framework_bulk.serializers import BulkListSerializer
|
from rest_framework_bulk.serializers import BulkListSerializer
|
||||||
|
|
||||||
from common.mixins import BulkSerializerMixin
|
from common.mixins import BulkSerializerMixin
|
||||||
from ..models import Asset
|
from ..models import Asset, Node
|
||||||
from .system_user import AssetSystemUserSerializer
|
from .system_user import AssetSystemUserSerializer
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
'AssetSerializer', 'AssetGrantedSerializer', 'MyAssetGrantedSerializer',
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class NodeTMPSerializer(serializers.ModelSerializer):
|
||||||
|
parent = serializers.SerializerMethodField()
|
||||||
|
assets_amount = serializers.SerializerMethodField()
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = Node
|
||||||
|
fields = ['id', 'key', 'value', 'parent', 'assets_amount',
|
||||||
|
'is_asset']
|
||||||
|
list_serializer_class = BulkListSerializer
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_parent(obj):
|
||||||
|
return obj.parent.id
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_assets_amount(obj):
|
||||||
|
return obj.get_all_assets().count()
|
||||||
|
|
||||||
|
def get_fields(self):
|
||||||
|
fields = super().get_fields()
|
||||||
|
field = fields["key"]
|
||||||
|
field.required = False
|
||||||
|
return fields
|
||||||
|
|
||||||
|
|
||||||
class AssetSerializer(BulkSerializerMixin, serializers.ModelSerializer):
|
class AssetSerializer(BulkSerializerMixin, serializers.ModelSerializer):
|
||||||
"""
|
"""
|
||||||
|
@ -33,12 +62,13 @@ class AssetGrantedSerializer(serializers.ModelSerializer):
|
||||||
"""
|
"""
|
||||||
system_users_granted = AssetSystemUserSerializer(many=True, read_only=True)
|
system_users_granted = AssetSystemUserSerializer(many=True, read_only=True)
|
||||||
system_users_join = serializers.SerializerMethodField()
|
system_users_join = serializers.SerializerMethodField()
|
||||||
|
nodes = NodeTMPSerializer(many=True, read_only=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Asset
|
model = Asset
|
||||||
fields = (
|
fields = (
|
||||||
"id", "hostname", "ip", "port", "system_users_granted",
|
"id", "hostname", "ip", "port", "system_users_granted",
|
||||||
"is_active", "system_users_join", "os", 'domain',
|
"is_active", "system_users_join", "os", 'domain', "nodes",
|
||||||
"platform", "comment"
|
"platform", "comment"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,12 @@ from ..models import Asset, Node
|
||||||
from .asset import AssetGrantedSerializer
|
from .asset import AssetGrantedSerializer
|
||||||
|
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
'NodeSerializer', "NodeGrantedSerializer", "NodeAddChildrenSerializer",
|
||||||
|
"NodeAssetsSerializer",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
class NodeGrantedSerializer(BulkSerializerMixin, serializers.ModelSerializer):
|
class NodeGrantedSerializer(BulkSerializerMixin, serializers.ModelSerializer):
|
||||||
"""
|
"""
|
||||||
授权资产组
|
授权资产组
|
||||||
|
|
|
@ -182,6 +182,11 @@ class SessionViewSet(viewsets.ModelViewSet):
|
||||||
self.queryset = terminal.session_set.all()
|
self.queryset = terminal.session_set.all()
|
||||||
return self.queryset
|
return self.queryset
|
||||||
|
|
||||||
|
def perform_create(self, serializer):
|
||||||
|
if self.request.user.terminal:
|
||||||
|
serializer.validated_data["terminal"] = self.request.user.terminal
|
||||||
|
return super().perform_create(serializer)
|
||||||
|
|
||||||
|
|
||||||
class TaskViewSet(BulkModelViewSet):
|
class TaskViewSet(BulkModelViewSet):
|
||||||
queryset = Task.objects.all()
|
queryset = Task.objects.all()
|
||||||
|
@ -299,6 +304,57 @@ class SessionReplayViewSet(viewsets.ViewSet):
|
||||||
return HttpResponseNotFound()
|
return HttpResponseNotFound()
|
||||||
|
|
||||||
|
|
||||||
|
class SessionReplayV2ViewSet(viewsets.ViewSet):
|
||||||
|
serializer_class = ReplaySerializer
|
||||||
|
permission_classes = (IsSuperUserOrAppUser,)
|
||||||
|
session = None
|
||||||
|
|
||||||
|
def gen_session_path(self):
|
||||||
|
date = self.session.date_start.strftime('%Y-%m-%d')
|
||||||
|
replay = {
|
||||||
|
"id": self.session.id,
|
||||||
|
# "width": 100,
|
||||||
|
# "heith": 100
|
||||||
|
}
|
||||||
|
if self.session.protocol == "ssh":
|
||||||
|
replay['type'] = "json"
|
||||||
|
replay['path'] = os.path.join(date, str(self.session.id) + '.gz')
|
||||||
|
return replay
|
||||||
|
elif self.session.protocol == "rdp":
|
||||||
|
replay['type'] = "mp4"
|
||||||
|
replay['path'] = os.path.join(date, str(self.session.id) + '.mp4')
|
||||||
|
return replay
|
||||||
|
else:
|
||||||
|
return replay
|
||||||
|
|
||||||
|
def retrieve(self, request, *args, **kwargs):
|
||||||
|
session_id = kwargs.get('pk')
|
||||||
|
self.session = get_object_or_404(Session, id=session_id)
|
||||||
|
replay = self.gen_session_path()
|
||||||
|
|
||||||
|
if replay.get("path", "") == "":
|
||||||
|
return HttpResponseNotFound()
|
||||||
|
|
||||||
|
if default_storage.exists(replay["path"]):
|
||||||
|
replay["src"] = default_storage.url(replay["path"])
|
||||||
|
return Response(replay)
|
||||||
|
else:
|
||||||
|
configs = settings.TERMINAL_REPLAY_STORAGE.items()
|
||||||
|
if not configs:
|
||||||
|
return HttpResponseNotFound()
|
||||||
|
|
||||||
|
for name, config in configs:
|
||||||
|
client = jms_storage.init(config)
|
||||||
|
|
||||||
|
target_path = default_storage.base_location + '/' + replay["path"]
|
||||||
|
|
||||||
|
if client and client.has_file(replay["path"]) and \
|
||||||
|
client.download_file(replay["path"], target_path):
|
||||||
|
replay["src"] = default_storage.url(replay["path"])
|
||||||
|
return Response(replay)
|
||||||
|
return HttpResponseNotFound()
|
||||||
|
|
||||||
|
|
||||||
class TerminalConfig(APIView):
|
class TerminalConfig(APIView):
|
||||||
permission_classes = (IsAppUser,)
|
permission_classes = (IsAppUser,)
|
||||||
|
|
||||||
|
|
|
@ -117,6 +117,10 @@ class Session(models.Model):
|
||||||
('ST', 'SSH Terminal'),
|
('ST', 'SSH Terminal'),
|
||||||
('WT', 'Web Terminal'),
|
('WT', 'Web Terminal'),
|
||||||
)
|
)
|
||||||
|
PROTOCOL_CHOICES = (
|
||||||
|
('ssh', 'ssh'),
|
||||||
|
('rdp', 'rdp')
|
||||||
|
)
|
||||||
|
|
||||||
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
|
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
|
||||||
user = models.CharField(max_length=128, verbose_name=_("User"))
|
user = models.CharField(max_length=128, verbose_name=_("User"))
|
||||||
|
@ -128,8 +132,9 @@ class Session(models.Model):
|
||||||
has_replay = models.BooleanField(default=False, verbose_name=_("Replay"))
|
has_replay = models.BooleanField(default=False, verbose_name=_("Replay"))
|
||||||
has_command = models.BooleanField(default=False, verbose_name=_("Command"))
|
has_command = models.BooleanField(default=False, verbose_name=_("Command"))
|
||||||
terminal = models.ForeignKey(Terminal, null=True, on_delete=models.SET_NULL)
|
terminal = models.ForeignKey(Terminal, null=True, on_delete=models.SET_NULL)
|
||||||
|
protocol = models.CharField(choices=PROTOCOL_CHOICES, default='ssh', max_length=8)
|
||||||
date_last_active = models.DateTimeField(verbose_name=_("Date last active"), default=timezone.now)
|
date_last_active = models.DateTimeField(verbose_name=_("Date last active"), default=timezone.now)
|
||||||
date_start = models.DateTimeField(verbose_name=_("Date start"), db_index=True)
|
date_start = models.DateTimeField(verbose_name=_("Date start"), db_index=True, default=timezone.now)
|
||||||
date_end = models.DateTimeField(verbose_name=_("Date end"), null=True)
|
date_end = models.DateTimeField(verbose_name=_("Date end"), null=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
|
@ -72,7 +72,7 @@
|
||||||
<th class="text-center">{% trans 'Asset' %}</th>
|
<th class="text-center">{% trans 'Asset' %}</th>
|
||||||
<th class="text-center">{% trans 'System user' %}</th>
|
<th class="text-center">{% trans 'System user' %}</th>
|
||||||
<th class="text-center">{% trans 'Remote addr' %}</th>
|
<th class="text-center">{% trans 'Remote addr' %}</th>
|
||||||
<th class="text-center">{% trans 'Terminal' %}</th>
|
<th class="text-center">{% trans 'Protocol' %}</th>
|
||||||
<th class="text-center">{% trans 'Command' %}</th>
|
<th class="text-center">{% trans 'Command' %}</th>
|
||||||
<th class="text-center">{% trans 'Date start' %}</th>
|
<th class="text-center">{% trans 'Date start' %}</th>
|
||||||
{# <th class="text-center">{% trans 'Date last active' %}</th>#}
|
{# <th class="text-center">{% trans 'Date last active' %}</th>#}
|
||||||
|
@ -91,7 +91,7 @@
|
||||||
<td class="text-center">{{ session.asset }}</td>
|
<td class="text-center">{{ session.asset }}</td>
|
||||||
<td class="text-center">{{ session.system_user }}</td>
|
<td class="text-center">{{ session.system_user }}</td>
|
||||||
<td class="text-center">{{ session.remote_addr|default:"" }}</td>
|
<td class="text-center">{{ session.remote_addr|default:"" }}</td>
|
||||||
<td class="text-center">{{ session.terminal.name }}</td>
|
<td class="text-center">{{ session.protocol }}</td>
|
||||||
<td class="text-center">{{ session.id | get_session_command_amount }}</td>
|
<td class="text-center">{{ session.id | get_session_command_amount }}</td>
|
||||||
|
|
||||||
<td class="text-center">{{ session.date_start }}</td>
|
<td class="text-center">{{ session.date_start }}</td>
|
||||||
|
|
|
@ -23,8 +23,13 @@ urlpatterns = [
|
||||||
api.SessionReplayViewSet.as_view({'get': 'retrieve', 'post': 'create'}),
|
api.SessionReplayViewSet.as_view({'get': 'retrieve', 'post': 'create'}),
|
||||||
name='session-replay'),
|
name='session-replay'),
|
||||||
url(r'^v1/tasks/kill-session/', api.KillSessionAPI.as_view(), name='kill-session'),
|
url(r'^v1/tasks/kill-session/', api.KillSessionAPI.as_view(), name='kill-session'),
|
||||||
url(r'^v1/terminal/(?P<terminal>[a-zA-Z0-9\-]{36})/access-key', api.TerminalTokenApi.as_view(), name='terminal-access-key'),
|
url(r'^v1/terminal/(?P<terminal>[a-zA-Z0-9\-]{36})/access-key', api.TerminalTokenApi.as_view(),
|
||||||
|
name='terminal-access-key'),
|
||||||
url(r'^v1/terminal/config', api.TerminalConfig.as_view(), name='terminal-config'),
|
url(r'^v1/terminal/config', api.TerminalConfig.as_view(), name='terminal-config'),
|
||||||
|
# v2: get session's replay
|
||||||
|
url(r'^v2/sessions/(?P<pk>[0-9a-zA-Z\-]{36})/replay/$',
|
||||||
|
api.SessionReplayV2ViewSet.as_view({'get': 'retrieve'}),
|
||||||
|
name='session-replay-v2'),
|
||||||
]
|
]
|
||||||
|
|
||||||
urlpatterns += router.urls
|
urlpatterns += router.urls
|
||||||
|
|
|
@ -38,7 +38,7 @@ class CommandListView(DatetimeSearchMixin, AdminUserRequiredMixin, ListView):
|
||||||
if self.system_user:
|
if self.system_user:
|
||||||
filter_kwargs['system_user'] = self.system_user
|
filter_kwargs['system_user'] = self.system_user
|
||||||
if self.command:
|
if self.command:
|
||||||
filter_kwargs['input__contains'] = self.command
|
filter_kwargs['input'] = self.command
|
||||||
queryset = common_storage.filter(**filter_kwargs)
|
queryset = common_storage.filter(**filter_kwargs)
|
||||||
return queryset
|
return queryset
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue