mirror of https://github.com/jumpserver/jumpserver
Add command list
parent
c2aab50c7b
commit
5d3f9b4a03
|
@ -3,6 +3,7 @@ from __future__ import unicode_literals, absolute_import
|
||||||
|
|
||||||
import functools
|
import functools
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
from django.core import serializers
|
||||||
import logging
|
import logging
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
@ -336,6 +337,9 @@ class Asset(models.Model):
|
||||||
return True, ''
|
return True, ''
|
||||||
return False, warning
|
return False, warning
|
||||||
|
|
||||||
|
def json(self):
|
||||||
|
pass
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
db_table = 'asset'
|
db_table = 'asset'
|
||||||
unique_together = ('ip', 'port')
|
unique_together = ('ip', 'port')
|
||||||
|
|
|
@ -63,7 +63,6 @@ class AssetCreateView(AdminUserRequiredMixin,CreateAssetTagsMiXin,CreateView):
|
||||||
print(form.errors)
|
print(form.errors)
|
||||||
return super(AssetCreateView, self).form_invalid(form)
|
return super(AssetCreateView, self).form_invalid(form)
|
||||||
|
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = {
|
context = {
|
||||||
'app': 'Assets',
|
'app': 'Assets',
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
from __future__ import absolute_import, unicode_literals
|
from __future__ import absolute_import, unicode_literals
|
||||||
from rest_framework import generics
|
from rest_framework import generics
|
||||||
|
from rest_framework.views import APIView, Response
|
||||||
|
|
||||||
from . import models, serializers
|
from . import models, serializers
|
||||||
from .hands import IsSuperUserOrTerminalUser, Terminal
|
from .hands import IsSuperUserOrTerminalUser, Terminal
|
||||||
|
@ -44,7 +45,18 @@ class ProxyLogDetailApi(generics.RetrieveUpdateDestroyAPIView):
|
||||||
permission_classes = (IsSuperUserOrTerminalUser,)
|
permission_classes = (IsSuperUserOrTerminalUser,)
|
||||||
|
|
||||||
|
|
||||||
class CommandLogCreateApi(generics.ListCreateAPIView):
|
class CommandLogListCreateApi(generics.ListCreateAPIView):
|
||||||
queryset = models.CommandLog.objects.all()
|
queryset = models.CommandLog.objects.all()
|
||||||
serializer_class = serializers.CommandLogSerializer
|
serializer_class = serializers.CommandLogSerializer
|
||||||
permission_classes = (IsSuperUserOrTerminalUser,)
|
permission_classes = (IsSuperUserOrTerminalUser,)
|
||||||
|
|
||||||
|
|
||||||
|
# class CommandLogTitleApi(APIView):
|
||||||
|
# def get(self, request):
|
||||||
|
# response = [
|
||||||
|
# {"name": "command_no", "title": "ID", "type": "number"},
|
||||||
|
# {"name": "command", "title": "Title", "visible": True, "filterable": True},
|
||||||
|
# {"name": "datetime", "title": "Datetime", "type"},
|
||||||
|
# {"name": "output", "title": "Output", "filterable": True},
|
||||||
|
# ]
|
||||||
|
#
|
|
@ -2,6 +2,7 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
import base64
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
@ -68,6 +69,10 @@ class CommandLog(models.Model):
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return '%s: %s' % (self.id, self.command)
|
return '%s: %s' % (self.id, self.command)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def output_decode(self):
|
||||||
|
return base64.b64decode(self.output).replace('\n', '<br />')
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
db_table = 'command_log'
|
db_table = 'command_log'
|
||||||
ordering = ['command_no', 'command']
|
ordering = ['command_no', 'command']
|
||||||
|
|
|
@ -3,14 +3,26 @@
|
||||||
from __future__ import absolute_import, unicode_literals
|
from __future__ import absolute_import, unicode_literals
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
|
from common.utils import timesince
|
||||||
from . import models
|
from . import models
|
||||||
|
|
||||||
|
|
||||||
class ProxyLogSerializer(serializers.ModelSerializer):
|
class ProxyLogSerializer(serializers.ModelSerializer):
|
||||||
|
time = serializers.SerializerMethodField()
|
||||||
|
command_length = serializers.SerializerMethodField()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = models.ProxyLog
|
model = models.ProxyLog
|
||||||
fields = ['id', 'name', 'username', 'hostname', 'ip', 'system_user', 'login_type', 'terminal',
|
fields = ['id', 'name', 'username', 'hostname', 'ip', 'system_user', 'login_type', 'terminal',
|
||||||
'log_file', 'was_failed', 'is_finished', 'date_start', 'date_finished', 'get_login_type_display']
|
'log_file', 'was_failed', 'is_finished', 'date_start', 'time', 'command_length']
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_time(obj):
|
||||||
|
return timesince(obj.date_start, since=obj.date_finished)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_command_length(obj):
|
||||||
|
return len(obj.command_log.all())
|
||||||
|
|
||||||
|
|
||||||
class CommandLogSerializer(serializers.ModelSerializer):
|
class CommandLogSerializer(serializers.ModelSerializer):
|
||||||
|
|
|
@ -1,12 +1,10 @@
|
||||||
{% extends 'base.html' %}
|
{% extends 'base.html' %}
|
||||||
{% load common_tags %}
|
{% load common_tags %}
|
||||||
{% load users_tags %}
|
|
||||||
{% load bootstrap %}
|
|
||||||
{% load static %}
|
{% load static %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
{% block custom_head_css_js %}
|
{% block custom_head_css_js %}
|
||||||
<script src="{% static "css/plugins/footable/footable.core.css" %}"></script>
|
<link href="{% static "css/plugins/footable/footable.core.css" %}" rel="stylesheet">
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="wrapper wrapper-content animated fadeInRight">
|
<div class="wrapper wrapper-content animated fadeInRight">
|
||||||
|
@ -40,16 +38,25 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="ibox-content">
|
<div class="ibox-content">
|
||||||
<table class="footable table table-stripped toggle-arrow-tiny command" data-page-size="8">
|
<table id="command-log" class="footable table table-stripped toggle-arrow-tiny" data-page-size="10">
|
||||||
{# <thead>#}
|
<thead>
|
||||||
{# <tr>#}
|
<tr>
|
||||||
{# <th data-toggle="true">No</th>#}
|
<th data-toggle="true">ID</th>
|
||||||
{# <th>Command</th>#}
|
<th>Command</th>
|
||||||
{# <th>Datetime</th>#}
|
<th data-hide="all">Output</th>
|
||||||
{# </tr>#}
|
<th>Datetime</th>
|
||||||
{# </thead>#}
|
</tr>
|
||||||
{# <tbody>#}
|
</thead>
|
||||||
{# </tbody>#}
|
<tbody>
|
||||||
|
{% for command in object_list %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ command.command_no }}</td>
|
||||||
|
<td>{{ command.command }}</td>
|
||||||
|
<td>{{ command.output_decode |safe }}</td>
|
||||||
|
<td>{{ command.datetime }}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -73,31 +80,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="ibox-content">
|
<div class="ibox-content">
|
||||||
<table class="table table-hover">
|
<table class="table2 table-stripped toggle-arrow-tiny" data-page-size="8">
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th class="text-center">{% trans 'Name' %}</th>
|
|
||||||
<th class="text-center">{% trans 'Asset count' %}</th>
|
|
||||||
<th class="text-center">{% trans 'System user' %}</th>
|
|
||||||
<th></th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{% for asset_group, system_users in asset_groups %}
|
|
||||||
<tr class="gradeX">
|
|
||||||
<td class="text-center">
|
|
||||||
<a href="{% url 'assets:asset-group-detail' pk=asset_group.id %}">
|
|
||||||
{{ asset_group.name }}
|
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
<td class="text-center">{{ asset_group.assets.count }}</td>
|
|
||||||
<td class="text-center">{{ system_users|join_attr:"name" }}</td>
|
|
||||||
<td>
|
|
||||||
<button class="btn btn-danger btn-xs btn_delete_user_group {% if not asset_group.is_inherit_from_user_groups %} disabled {% endif %}" type="button" style="float: right;"><i class="fa fa-minus"></i></button>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -110,11 +93,10 @@
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block custom_foot_js %}
|
{% block custom_foot_js %}
|
||||||
|
<script src="{% static "js/plugins/footable/footable.all.min.js" %}"></script>
|
||||||
<script>
|
<script>
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
$('.command').footable({
|
$('.footable').footable();
|
||||||
"rows": $.get({% url 'audits:command-log-create-list-api' %})
|
|
||||||
})
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -27,12 +27,12 @@
|
||||||
<th class="text-center">{% trans 'Username' %}</th>
|
<th class="text-center">{% trans 'Username' %}</th>
|
||||||
<th class="text-center">{% trans 'IP' %}</th>
|
<th class="text-center">{% trans 'IP' %}</th>
|
||||||
<th class="text-center">{% trans 'System user' %}</th>
|
<th class="text-center">{% trans 'System user' %}</th>
|
||||||
<th class="text-center">{% trans 'Login type' %}</th>
|
{# <th class="text-center">{% trans 'Login type' %}</th>#}
|
||||||
{# <th class="text-center">{% trans 'Terminal' %}</th>#}
|
<th class="text-center">{% trans 'Command' %}</th>
|
||||||
<th class="text-center">{% trans 'Success' %}</th>
|
<th class="text-center">{% trans 'Success' %}</th>
|
||||||
<th class="text-center">{% trans 'Finished' %}</th>
|
<th class="text-center">{% trans 'Finished' %}</th>
|
||||||
<th class="text-center">{% trans 'Date start' %}</th>
|
<th class="text-center">{% trans 'Date start' %}</th>
|
||||||
<th class="text-center">{% trans 'Date finished' %}</th>
|
<th class="text-center">{% trans 'Time' %}</th>
|
||||||
<th class="text-center">{% trans 'Action' %}</th>
|
<th class="text-center">{% trans 'Action' %}</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
@ -76,8 +76,8 @@ $(document).ready(function(){
|
||||||
],
|
],
|
||||||
ajax_url: '{% url "audits:proxy-log-list-create-api" %}',
|
ajax_url: '{% url "audits:proxy-log-list-create-api" %}',
|
||||||
columns: [{data: function(){return ""}}, {data: "name" }, {data: "ip"},
|
columns: [{data: function(){return ""}}, {data: "name" }, {data: "ip"},
|
||||||
{data: "system_user"}, {data: "terminal"}, {data: 'was_failed'},
|
{data: "system_user"}, {data: "command_length"}, {data: 'was_failed'},
|
||||||
{data: "is_finished"}, {data: "date_start"}, {data: 'date_finished'}, {data: 'id'}],
|
{data: "is_finished"}, {data: "date_start"}, {data: 'time'}, {data: 'id'}],
|
||||||
op_html: $('#actions').html()
|
op_html: $('#actions').html()
|
||||||
};
|
};
|
||||||
jumpserver.initDataTable(options);
|
jumpserver.initDataTable(options);
|
||||||
|
|
|
@ -15,5 +15,5 @@ urlpatterns = [
|
||||||
urlpatterns += [
|
urlpatterns += [
|
||||||
url(r'^v1/proxy-log/$', api.ProxyLogListCreateApi.as_view(), name='proxy-log-list-create-api'),
|
url(r'^v1/proxy-log/$', api.ProxyLogListCreateApi.as_view(), name='proxy-log-list-create-api'),
|
||||||
url(r'^v1/proxy-log/(?P<pk>\d+)/$', api.ProxyLogDetailApi.as_view(), name='proxy-log-detail-api'),
|
url(r'^v1/proxy-log/(?P<pk>\d+)/$', api.ProxyLogDetailApi.as_view(), name='proxy-log-detail-api'),
|
||||||
url(r'^v1/command-log/$', api.CommandLogCreateApi.as_view(), name='command-log-create-list-api'),
|
url(r'^v1/command-log/$', api.CommandLogListCreateApi.as_view(), name='command-log-create-list-api'),
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,2 +1,5 @@
|
||||||
# ~*~ coding: utf-8 ~*~
|
# ~*~ coding: utf-8 ~*~
|
||||||
#
|
#
|
||||||
|
|
||||||
|
from users.utils import AdminUserRequiredMixin
|
||||||
|
|
||||||
|
|
|
@ -2,10 +2,13 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
from django.views.generic import ListView, UpdateView, DeleteView, DetailView
|
from django.views.generic import ListView, UpdateView, DeleteView, DetailView
|
||||||
|
from django.views.generic.edit import SingleObjectMixin
|
||||||
from django.utils.translation import ugettext as _
|
from django.utils.translation import ugettext as _
|
||||||
from django.urls import reverse_lazy
|
from django.urls import reverse_lazy
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
from .models import ProxyLog, CommandLog
|
from .models import ProxyLog, CommandLog
|
||||||
|
from .utils import AdminUserRequiredMixin
|
||||||
|
|
||||||
|
|
||||||
class ProxyLogListView(ListView):
|
class ProxyLogListView(ListView):
|
||||||
|
@ -18,11 +21,21 @@ class ProxyLogListView(ListView):
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
class ProxyLogDetailView(DetailView):
|
class ProxyLogDetailView(AdminUserRequiredMixin, SingleObjectMixin, ListView):
|
||||||
model = ProxyLog
|
|
||||||
template_name = 'audits/proxy_log_detail.html'
|
template_name = 'audits/proxy_log_detail.html'
|
||||||
|
context_object_name = 'proxy_log'
|
||||||
|
|
||||||
|
def get(self, request, *args, **kwargs):
|
||||||
|
self.object = self.get_object(queryset=ProxyLog.objects.all())
|
||||||
|
return super(ProxyLogDetailView, self).get(request, *args, **kwargs)
|
||||||
|
|
||||||
|
def get_queryset(self):
|
||||||
|
return list(self.object.command_log.all())
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = super(ProxyLogDetailView, self).get_context_data(**kwargs)
|
context = {
|
||||||
context.update({'app': _('Audits'), 'action': _('Proxy log detail')})
|
'app': 'Audits',
|
||||||
|
'action': 'Proxy log detail',
|
||||||
|
}
|
||||||
|
kwargs.update(context)
|
||||||
|
return super(ProxyLogDetailView, self).get_context_data(**kwargs)
|
||||||
|
|
|
@ -6,6 +6,7 @@ from six import string_types
|
||||||
from itertools import chain
|
from itertools import chain
|
||||||
import string
|
import string
|
||||||
import logging
|
import logging
|
||||||
|
import datetime
|
||||||
|
|
||||||
from itsdangerous import Signer, TimedJSONWebSignatureSerializer, JSONWebSignatureSerializer, TimestampSigner, \
|
from itsdangerous import Signer, TimedJSONWebSignatureSerializer, JSONWebSignatureSerializer, TimestampSigner, \
|
||||||
BadSignature, SignatureExpired
|
BadSignature, SignatureExpired
|
||||||
|
@ -133,3 +134,34 @@ def int_seq(seq):
|
||||||
return map(int, seq)
|
return map(int, seq)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return seq
|
return seq
|
||||||
|
|
||||||
|
|
||||||
|
def timesince(dt, since='', default="just now"):
|
||||||
|
"""
|
||||||
|
Returns string representing "time since" e.g.
|
||||||
|
3 days, 5 hours.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if since is '':
|
||||||
|
since = datetime.datetime.utcnow()
|
||||||
|
|
||||||
|
if since is None:
|
||||||
|
return default
|
||||||
|
|
||||||
|
diff = since - dt
|
||||||
|
|
||||||
|
periods = (
|
||||||
|
(diff.days / 365, "year", "years"),
|
||||||
|
(diff.days / 30, "month", "months"),
|
||||||
|
(diff.days / 7, "week", "weeks"),
|
||||||
|
(diff.days, "day", "days"),
|
||||||
|
(diff.seconds / 3600, "hour", "hours"),
|
||||||
|
(diff.seconds / 60, "minute", "minutes"),
|
||||||
|
(diff.seconds, "second", "seconds"),
|
||||||
|
)
|
||||||
|
|
||||||
|
for period, singular, plural in periods:
|
||||||
|
if period:
|
||||||
|
return "%d %s" % (period, singular if period == 1 else plural)
|
||||||
|
return default
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,13 @@ class UserAssetsGrantedApi(APIView):
|
||||||
'hostname': asset.hostname,
|
'hostname': asset.hostname,
|
||||||
'ip': asset.ip,
|
'ip': asset.ip,
|
||||||
'port': asset.port,
|
'port': asset.port,
|
||||||
'system_users': [system_user.name for system_user in system_users],
|
'system_users': [
|
||||||
|
{
|
||||||
|
'id': system_user.id,
|
||||||
|
'name': system_user.name,
|
||||||
|
'username': system_user.username,
|
||||||
|
} for system_user in system_users
|
||||||
|
],
|
||||||
'comment': asset.comment
|
'comment': asset.comment
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.footable {
|
.footable {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
/** SORTING **/
|
/** SORTING **/
|
||||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue