Commit a5f97359 authored by ibuler's avatar ibuler

[Update] 更新index view

parent 71a30792
# ~*~ coding: utf-8 ~*~
#
from __future__ import absolute_import, unicode_literals
from rest_framework import generics, viewsets
from rest_framework_bulk import BulkModelViewSet
from audits.backends import command_store, record_store
from audits.backends.command.serializers import CommandLogSerializer
from audits.backends.record.serializers import RecordSerializer
from . import models, serializers
from .hands import IsSuperUserOrAppUser, IsAppUser
class ProxyLogReceiveView(generics.CreateAPIView):
queryset = models.ProxyLog.objects.all()
serializer_class = serializers.ProxyLogSerializer
permission_classes = (IsAppUser,)
def get_serializer(self, *args, **kwargs):
kwargs['data']['terminal'] = self.request.user.terminal.name
return super(ProxyLogReceiveView, self).get_serializer(*args, **kwargs)
class ProxyLogViewSet(viewsets.ModelViewSet):
"""User proxy to backend server need call this api.
params: {
"username": "",
"name": "",
"hostname": "",
"ip": "",
"terminal": "",
"login_type": "",
"system_user": "",
"was_failed": "",
"date_start": ""
}
"""
queryset = models.ProxyLog.objects.all()
serializer_class = serializers.ProxyLogSerializer
permission_classes = (IsSuperUserOrAppUser,)
class CommandLogViewSet(BulkModelViewSet):
"""接受app发送来的command log, 格式如下
{
"proxy_log_id": 23,
"user": "admin",
"asset": "localhost",
"system_user": "web",
"command_no": 1,
"command": "whoami",
"output": "d2hvbWFp", # base64.b64encode(s)
"timestamp": 1485238673.0
}
"""
queryset = command_store.all()
serializer_class = CommandLogSerializer
permission_classes = (IsSuperUserOrAppUser,)
class RecordLogViewSet(BulkModelViewSet):
"""接受app发送来的record log, 格式如下
{
"proxy_log_id": 23,
"output": "d2hvbWFp", # base64.b64encode(s)
"timestamp": 1485238673.0
}
"""
serializer_class = RecordSerializer
permission_classes = (IsSuperUserOrAppUser,)
def get_queryset(self):
filter_kwargs = {}
proxy_log_id = self.request.query_params.get('proxy_log_id')
data_from_ts = self.request.query_params.get('date_from_ts')
if proxy_log_id:
filter_kwargs['proxy_log_id'] = proxy_log_id
if data_from_ts:
filter_kwargs['date_from_ts'] = data_from_ts
if filter_kwargs:
return record_store.filter(**filter_kwargs)
else:
return record_store.all()
from __future__ import unicode_literals
from django.apps import AppConfig
class AuditsConfig(AppConfig):
name = 'audits'
from importlib import import_module
from django.conf import settings
command_engine = import_module(settings.COMMAND_STORE_BACKEND)
command_store = command_engine.CommandStore()
record_engine = import_module(settings.RECORD_STORE_BACKEND)
record_store = record_engine.RecordStore()
from .command.serializers import CommandLogSerializer
# coding: utf-8
import abc
class CommandBase(object):
__metaclass__ = abc.ABCMeta
@abc.abstractmethod
def save(self, proxy_log_id, user, asset, system_user,
command_no, command, output, timestamp):
pass
@abc.abstractmethod
def filter(self, date_from_ts=None, date_to_ts=None, user='',
asset='', system_user='', command='', proxy_log_id=0):
pass
# ~*~ coding: utf-8 ~*~
from .base import CommandBase
from audits.models import CommandLog
class CommandStore(CommandBase):
model = CommandLog
queryset = []
def save(self, proxy_log_id, user, asset, system_user,
command_no, command, output, timestamp):
self.model.objects.create(
proxy_log_id=proxy_log_id, user=user, asset=asset,
system_user=system_user, command_no=command_no,
command=command, output=output, timestamp=timestamp
)
def filter(self, date_from_ts=None, date_to_ts=None, user='',
asset='', system_user='', command='', proxy_log_id=0):
filter_kwargs = {}
if date_from_ts:
filter_kwargs['timestamp__gte'] = date_from_ts
if date_to_ts:
filter_kwargs['timestamp__lte'] = date_to_ts
if user:
filter_kwargs['user'] = user
if asset:
filter_kwargs['asset'] = asset
if system_user:
filter_kwargs['system_user'] = system_user
if command:
filter_kwargs['command__icontains'] = command
if proxy_log_id:
filter_kwargs['proxy_log_id'] = proxy_log_id
if filter_kwargs:
self.queryset = self.model.objects.filter(**filter_kwargs)
return self.queryset
def all(self):
"""返回所有数据"""
return self.model.objects.iterator()
# ~*~ coding: utf-8 ~*~
import base64
from rest_framework import serializers
from audits.models import CommandLog
from audits.backends import command_store
class CommandLogSerializer(serializers.ModelSerializer):
"""使用这个类作为基础Command Log Serializer类, 用来序列化"""
class Meta:
model = CommandLog
fields = '__all__'
def create(self, validated_data):
try:
output = validated_data['output']
validated_data['output'] = base64.b64decode(output)
except IndexError:
pass
return command_store.save(**dict(validated_data))
# coding: utf-8
import abc
class RecordBase(object):
__metaclass__ = abc.ABCMeta
@abc.abstractmethod
def save(self, proxy_log_id, output, timestamp):
pass
@abc.abstractmethod
def filter(self, date_from_ts=None, proxy_log_id=None):
pass
# ~*~ coding: utf-8 ~*~
from .base import RecordBase
from audits.models import RecordLog
class RecordStore(RecordBase):
model = RecordLog
queryset = []
def save(self, proxy_log_id, output, timestamp):
return self.model.objects.create(
proxy_log_id=proxy_log_id, output=output, timestamp=timestamp
)
def filter(self, date_from_ts=None, proxy_log_id=''):
filter_kwargs = {}
if date_from_ts:
filter_kwargs['timestamp__gte'] = date_from_ts
if proxy_log_id:
filter_kwargs['proxy_log_id'] = proxy_log_id
if filter_kwargs:
self.queryset = self.model.objects.filter(**filter_kwargs)
return self.queryset
def all(self):
"""返回所有数据"""
return self.model.objects.all()
# ~*~ coding: utf-8 ~*~
import base64
from rest_framework import serializers
from audits.models import RecordLog
from audits.backends import record_store
class RecordSerializer(serializers.ModelSerializer):
"""使用这个类作为基础Command Log Serializer类, 用来序列化"""
class Meta:
model = RecordLog
fields = '__all__'
def create(self, validated_data):
try:
output = validated_data['output']
validated_data['output'] = base64.b64decode(output)
except IndexError:
pass
return record_store.save(**dict(validated_data))
# ~*~ coding: utf-8 ~*~
#
from users.utils import AdminUserRequiredMixin
from users.models import User
from assets.models import Asset, SystemUser
from users.permissions import IsSuperUserOrAppUser, IsAppUser
from terminal.models import Terminal
# -*- coding: utf-8 -*-
#
from __future__ import unicode_literals
import uuid
from django.db import models
from django.utils.translation import ugettext_lazy as _
class LoginLog(models.Model):
LOGIN_TYPE_CHOICE = (
('W', 'Web'),
('ST', 'SSH Terminal'),
('WT', 'Web Terminal')
)
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
username = models.CharField(max_length=20, verbose_name=_('Username'))
name = models.CharField(max_length=20, blank=True, verbose_name=_('Name'))
login_type = models.CharField(choices=LOGIN_TYPE_CHOICE, max_length=2,
verbose_name=_('Login type'))
login_ip = models.GenericIPAddressField(verbose_name=_('Login ip'))
login_city = models.CharField(max_length=254, blank=True, null=True,
verbose_name=_('Login city'))
user_agent = models.CharField(max_length=254, blank=True, null=True,
verbose_name=_('User agent'))
date_login = models.DateTimeField(auto_now_add=True,
verbose_name=_('Date login'))
class Meta:
db_table = 'login_log'
ordering = ['-date_login', 'username']
class ProxyLog(models.Model):
LOGIN_TYPE_CHOICE = (
('ST', 'SSH Terminal'),
('WT', 'Web Terminal'),
)
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
user = models.CharField(max_length=32, verbose_name=_('User'))
asset = models.CharField(max_length=32, verbose_name=_('Asset'))
system_user = models.CharField(max_length=32, verbose_name=_('System user'))
login_type = models.CharField(
choices=LOGIN_TYPE_CHOICE, max_length=2, blank=True,
null=True, verbose_name=_('Login type'))
terminal = models.CharField(
max_length=32, blank=True, null=True, verbose_name=_('Terminal'))
is_failed = models.BooleanField(
default=False, verbose_name=_('Did connect failed'))
is_finished = models.BooleanField(
default=False, verbose_name=_('Is finished'))
date_start = models.DateTimeField(
auto_created=True, verbose_name=_('Date start'))
date_finished = models.DateTimeField(
null=True, verbose_name=_('Date finished'))
def __unicode__(self):
return '%s-%s-%s' % (self.user, self.asset, self.system_user)
def commands(self):
from audits.backends import command_store
return command_store.filter(proxy_log_id=self.id)
class Meta:
ordering = ['-date_start', 'user']
class CommandLog(models.Model):
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
proxy_log_id = models.IntegerField(db_index=True)
user = models.CharField(max_length=48, db_index=True)
asset = models.CharField(max_length=128, db_index=True)
system_user = models.CharField(max_length=48, db_index=True)
command_no = models.IntegerField()
command = models.TextField(max_length=767, blank=True)
output = models.TextField(blank=True)
timestamp = models.FloatField(db_index=True)
def __unicode__(self):
return '%s: %s' % (self.id, self.command)
class Meta:
ordering = ['command_no', 'command']
class RecordLog(models.Model):
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
proxy_log_id = models.IntegerField(db_index=True)
output = models.TextField(verbose_name=_('Output'))
timestamp = models.FloatField(db_index=True)
def __unicode__(self):
return 'Record: %s' % self.proxy_log_id
class Meta:
ordering = ['timestamp']
# -*- coding: utf-8 -*-
#
from __future__ import absolute_import, unicode_literals
from rest_framework import serializers
from common.utils import timesince
from . import models
class ProxyLogSerializer(serializers.ModelSerializer):
time = serializers.SerializerMethodField()
command_length = serializers.SerializerMethodField()
class Meta:
model = models.ProxyLog
fields = '__all__'
@staticmethod
def get_time(obj):
if not obj.is_finished:
return ''
else:
return timesince(obj.date_start, since=obj.date_finished)
@staticmethod
def get_command_length(obj):
return 2
{% extends '_base_list.html' %}
{% load i18n %}
{% load static %}
{% load common_tags %}
{% block content_left_head %}
<link href="{% static "css/plugins/footable/footable.core.css" %}" rel="stylesheet">
<link href="{% static 'css/plugins/datepicker/datepicker3.css' %}" rel="stylesheet">
<style>
#search_btn {
margin-bottom: 0;
}
</style>
{% endblock %}
{% block table_search %}
<form id="search_form" method="get" action="" class="pull-right form-inline">
<div class="form-group" id="date">
<div class="input-daterange input-group" id="datepicker">
<span class="input-group-addon"><i class="fa fa-calendar"></i></span>
<input type="text" class="input-sm form-control" style="width: 100px;" name="date_from" value="{{ date_from }}">
<span class="input-group-addon">to</span>
<input type="text" class="input-sm form-control" style="width: 100px;" name="date_to" value="{{ date_to }}">
</div>
</div>
<div class="input-group">
<select class="select2 form-control" name="username">
<option value="">{% trans 'User' %}</option>
{% for u in user_list %}
<option value="{{ u.username }}" {% if username == u.username %} selected {% endif %}>{{ u.username }}</option>
{% endfor %}
</select>
</div>
<div class="input-group">
<select class="select2 form-control" name="ip">
<option value="">{% trans 'Asset' %}</option>
{% for a in asset_list %}
<option value="{{ a.ip }}" {% if ip == a.ip %} selected {% endif %}>{{ a.ip }}</option>
{% endfor %}
</select>
</div>
<div class="input-group">
<select class="select2 form-control" name="system_user">
<option value="">{% trans 'System user' %}</option>
{% for s in system_user_list %}
<option value="{{ s.username }}" {% if s.username == system_user %} selected {% endif %}>{{ s.username }}</option>
{% endfor %}
</select>
</div>
<div class="input-group">
<input type="text" class="form-control input-sm" name="command" placeholder="Command" value="{{ command }}">
</div>
<div class="input-group">
<div class="input-group-btn">
<button id='search_btn' type="submit" class="btn btn-sm btn-primary">
搜索
</button>
</div>
</div>
</form>
{% endblock %}
{% block table_container %}
<table class="footable table table-stripped toggle-arrow-tiny" data-page="false">
<thead>
<tr>
<th data-toggle="true">ID</th>
<th>Command</th>
<th>Username</th>
<th>IP</th>
<th>System user</th>
<th>Proxy log</th>
<th>Datetime</th>
<th data-hide="all">Output</th>
</tr>
</thead>
<tbody>
{% for command in command_list %}
<tr>
<td>{{ command.id }}</td>
<td>{{ command.command }}</td>
<td>{{ command.user }}</td>
<td>{{ command.asset }}</td>
<td>{{ command.system_user }}</td>
<td><a href="{% url 'audits:proxy-log-detail' pk=command.proxy_log_id %}">{{ command.proxy_log_id}}</a></td>
<td>{{ command.timestamp|ts_to_date }}</td>
<td><pre style="border: none; background: none">{{ command.output|to_html|safe }}</pre></td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}
{% block custom_foot_js %}
<script src="{% static "js/plugins/footable/footable.all.min.js" %}"></script>
<script src="{% static 'js/plugins/datepicker/bootstrap-datepicker.js' %}"></script>
<script>
$(document).ready(function () {
$('.footable').footable();
$('.select2').select2();
$('#date .input-daterange').datepicker({
dateFormat: 'mm/dd/yy',
keyboardNavigation: false,
forceParse: false,
autoclose: true
});
});
</script>
{% endblock %}
{% extends '_base_list.html' %}
{% load i18n %}
{% load static %}
{% load common_tags %}
{% block content_left_head %}
<link href="{% static 'css/plugins/datepicker/datepicker3.css' %}" rel="stylesheet">
<style>
#search_btn {
margin-bottom: 0;
}
</style>
{% endblock %}
{% block table_search %}
<form id="search_form" method="get" action="" class="pull-right form-inline">
<div class="form-group" id="date">
<div class="input-daterange input-group" id="datepicker">
<span class="input-group-addon"><i class="fa fa-calendar"></i></span>
<input type="text" class="input-sm form-control" style="width: 100px;" name="date_from" value="{{ date_from }}">
<span class="input-group-addon">to</span>
<input type="text" class="input-sm form-control" style="width: 100px;" name="date_to" value="{{ date_to }}">
</div>
</div>
<div class="input-group">
<select class="select2 form-control" name="username">
<option value="">{% trans 'Select user' %}</option>
{% for user in user_list %}
<option value="{{ user.username }}" {% if user.username == username %} selected {% endif %}>{{ user.username }}</option>
{% endfor %}
</select>
</div>
<div class="input-group">
<input type="text" class="form-control input-sm" name="keyword" placeholder="Search" value="{{ keyword }}">
</div>
<div class="input-group">
<div class="input-group-btn">
<button id='search_btn' type="submit" class="btn btn-sm btn-primary">
搜索
</button>
</div>
</div>
</form>
{% endblock %}
{% block table_head %}
<th class="text-center">{% trans 'ID' %}</th>
<th class="text-center">{% trans 'Username' %}</th>
<th class="text-center">{% trans 'Name' %}</th>
<th class="text-center">{% trans 'Type' %}</th>
<th class="text-center">{% trans 'UA' %}</th>
<th class="text-center">{% trans 'IP' %}</th>
<th class="text-center">{% trans 'City' %}</th>
<th class="text-center">{% trans 'Date' %}</th>
{% endblock %}
{% block table_body %}
{% for login_log in login_log_list %}
<tr class="gradeX">
<td class="text-center">
{{ login_log.id }}
{# <a href="{% url 'audits:proxy-log-detail' pk=login_log.id %}">{{ login_log.id }}</a>#}
</td>
<td class="text-center">{{ login_log.username }}</td>
<td class="text-center">{{ login_log.name }}</td>
<td class="text-center">{{ login_log.get_login_type_display }}</td>
{% if login_log.login_type == 'W' %}
<td class="text-center">
<span href="javascript:void(0);" data-toggle="tooltips" title="{{ login_log.user_agent }}">{{ login_log.user_agent | truncatechars:20 }}</span>
</td>
{% else %}
<td class="text-center">{{ login_log.terminal }}</td>
{% endif %}
<td class="text-center">{{ login_log.login_ip }}</td>
<td class="text-center">{{ login_log.login_city }}</td>
<td class="text-center">{{ login_log.date_login }}</td>
</tr>
{% endfor %}
{% endblock %}
{% block custom_foot_js %}
<script src="{% static 'js/plugins/datepicker/bootstrap-datepicker.js' %}"></script>
<script>
$(document).ready(function() {
$('table').DataTable({
"searching": false,
"bInfo" : false,
"paging": false,
"order": []
});
$('#date .input-daterange').datepicker({
dateFormat: 'mm/dd/yy',
keyboardNavigation: false,
forceParse: false,
autoclose: true
});
$('.select2').select2();
})
</script>
{% endblock %}
{% load static %}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="renderer" content="webkit">
{% include '_head_css_js.html' %}
<link href="{% static 'css/bootstrap.min.css' %}" rel="stylesheet">
<link href="{% static "css/plugins/footable/footable.core.css" %}" rel="stylesheet">
<script src="{% static 'js/jquery-2.1.1.js' %}"></script>
<script src="{% static 'js/plugins/sweetalert/sweetalert.min.js' %}"></script>
<script src="{% static 'js/bootstrap.min.js' %}"></script>
</head>
<body>
<div class="wrapper wrapper-content animated fadeInRight">
<div class="tab-content">
<div class="ibox-content">
<input type="text" class="form-control input-sm m-b-xs" id="filter"
placeholder="Search in table">
<table class="footable table table-stripped toggle-arrow-tiny" data-page-size="10" data-filter=#filter>
<thead>
<tr>
<th data-toggle="true">ID</th>
<th>Command</th>
<th data-hide="all">Output</th>
<th>Datetime</th>
</tr>
</thead>
<tbody class="table_body">
{% 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>
<tfoot>
<tr>
<td colspan="5">
<ul class="pagination pull-right"></ul>
</td>
</tr>
</tfoot>
</table>
</div>
</div>
</div>
</body>
<script src="{% static "js/plugins/footable/footable.all.min.js" %}"></script>
<script>
$(document).ready(function () {
$('.footable').footable();
});
</script>
</html>
{% extends 'base.html' %}
{% load static %}
{% load i18n %}
{% load common_tags %}
{% block custom_head_css_js %}
<link href="{% static "css/plugins/footable/footable.core.css" %}" rel="stylesheet">
{% endblock %}
{% block content %}
<div class="wrapper wrapper-content animated fadeInRight">
<div class="row">
<div class="col-sm-12">
<div class="ibox float-e-margins">
<div class="panel-options">
<ul class="nav nav-tabs">
<li class="active">
<a href="#" class="text-center"> {% trans 'Proxy log detail' %} </a>
</li>
</ul>
</div>
<div class="tab-content">
<div class="col-sm-11" style="padding-left: 0;">
<div class="ibox float-e-margins">
<div class="ibox-title">
<span style="float: left">{% trans 'Command log list' %} <b>{{ user_object.name }}</b></span>
<div class="ibox-tools">
<a class="collapse-link">
<i class="fa fa-chevron-up"></i>
</a>
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
<i class="fa fa-wrench"></i>
</a>
<ul class="dropdown-menu dropdown-user">
</ul>
<a class="close-link">
<i class="fa fa-times"></i>
</a>
</div>
</div>
<div class="ibox-content">
<table id="command-log" class="footable table table-stripped toggle-arrow-tiny" data-page-size="10">
<thead>
<tr>
<th data-toggle="true">ID</th>
<th>Command</th>
<th data-hide="all">Output</th>
<th>Datetime</th>
</tr>
</thead>
<tbody>
{% for command in object_list %}
<tr>
<td>{{ command.command_no }}</td>
<td>{{ command.command }}</td>
<td><pre style="border: none;background: none">{{ command.output|to_html|safe}}</pre></td>
<td>{{ command.timestamp|ts_to_date}}</td>
</tr>
{% endfor %}
</tbody>
<tfoot>
<tr>
<td colspan="5">
<ul class="pagination pull-right"></ul>
</td>
</tr>
</tfoot>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{% endblock %}
{% block custom_foot_js %}
<script src="{% static "js/plugins/footable/footable.all.min.js" %}"></script>
<script>
$(document).ready(function () {
$('.footable').footable();
});
</script>
{% endblock %}
{% extends '_base_list.html' %}
{% load i18n %}
{% load static %}
{% block content_left_head %}
<link href="{% static 'css/plugins/datepicker/datepicker3.css' %}" rel="stylesheet">
<style>
#search_btn {
margin-bottom: 0;
}
</style>
{% endblock %}
{% block table_search %}
<form id="search_form" method="get" action="" class="pull-right form-inline">
<div class="form-group" id="date">
<div class="input-daterange input-group" id="datepicker">
<span class="input-group-addon"><i class="fa fa-calendar"></i></span>
<input type="text" class="input-sm form-control" style="width: 100px;" name="date_from" value="{{ date_from }}">
<span class="input-group-addon">to</span>
<input type="text" class="input-sm form-control" style="width: 100px;" name="date_to" value="{{ date_to }}">
</div>
</div>
<div class="input-group">
<select class="select2 form-control" name="username">
<option value="">{% trans 'User' %}</option>
{% for u in user_list %}
<option value="{{ u }}" {% if u == username %} selected {% endif %}>{{ u }}</option>
{% endfor %}
</select>
</div>
<div class="input-group">
<select class="select2 form-control" name="ip">
<option value="">{% trans 'Asset' %}</option>
{% for a in asset_list %}
<option value="{{ a }}" {% if a == ip %} selected {% endif %}>{{ a }}</option>
{% endfor %}
</select>
</div>
<div class="input-group">
<select class="select2 form-control" name="system_user">
<option value="">{% trans 'System user' %}</option>
{% for su in system_user_list %}
<option value="{{ su }}" {% if su == system_user %} selected {% endif %}>{{ su }}</option>
{% endfor %}
</select>
</div>
<div class="input-group">
<input type="text" class="form-control input-sm" name="keyword" placeholder="Keyword" value="{{ keyword }}">
</div>
<div class="input-group">
<div class="input-group-btn">
<button id='search_btn' type="submit" class="btn btn-sm btn-primary">
搜索
</button>
</div>
</div>
</form>
{% endblock %}
{% block table_head %}
<th class="text-center"></th>
<th class="text-center">{% trans 'ID' %}</th>
<th class="text-center">{% trans 'User' %}</th>
<th class="text-center">{% trans 'Asset' %}</th>
<th class="text-center">{% trans 'System user' %}</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 'Finished' %}</th>
<th class="text-center">{% trans 'Play' %}</th>
<th class="text-center">{% trans 'Date start' %}</th>
<th class="text-center">{% trans 'Time' %}</th>
{% endblock %}
{% block table_body %}
{% for proxy_log in proxy_log_list %}
<tr class="gradeX">
<td class="text-center"><input type="checkbox" class="cbx-term" value="{{ proxy_log.id }}"></td>
<td class="text-center">
<a href="{% url 'audits:proxy-log-detail' pk=proxy_log.id %}">{{ proxy_log.id }}</a>
</td>
<td class="text-center">{{ proxy_log.user }}</td>
<td class="text-center">{{ proxy_log.asset }}</td>
<td class="text-center">{{ proxy_log.system_user }}</td>
<td class="text-center">{{ proxy_log.terminal }}</td>
<td class="text-center">{{ proxy_log.commands.all|length}}</td>
<td class="text-center">
{% if proxy_log.is_failed %}
<i class="fa fa-times text-danger"></i>
{% else %}
<i class="fa fa-check text-navy"></i>
{% endif %}
</td>
{% if proxy_log.is_finished %}
<td class="text-center">
<i class="fa fa-check text-navy"></i>
</td>
<td class="text-center">
<a><span class="text-navy"><i class="fa fa-play-circle"></i></span></a>
</td>
{% else %}
<td class="text-center">
<a class="btn-term" value="{{ proxy_log.id }}"><i class="fa fa-times text-danger"></i></a>
</td>
<td class="text-center">
<a><span class="text-danger"><i class="fa fa-eye"></i></span></a>
</td>
{% endif %}
<td class="text-center">{{ proxy_log.date_start }}</td>
<td class="text-center">{{ proxy_log.date_finished|timeuntil:proxy_log.date_start }}</td>
</tr>
{% endfor %}
{% endblock %}
{% block custom_foot_js %}
<script src="{% static 'js/plugins/datepicker/bootstrap-datepicker.js' %}"></script>
<script>
function terminateConnection(data) {
function success() {
window.setTimeout(function () {
window.location.reload()
}, 300)
}
var the_url = "";
APIUpdateAttr({url: the_url, method: 'POST', body: JSON.stringify(data), success: success, success_message: 'Terminate success'});
}
$(document).ready(function() {
$('table').DataTable({
"searching": false,
"paging": false,
"bInfo" : false,
"order": []
});
$('.select2').select2();
$('#date .input-daterange').datepicker({
dateFormat: 'mm/dd/yy',
keyboardNavigation: false,
forceParse: false,
autoclose: true
});
}).on('click', '.btn-term', function () {
var $this = $(this);
var proxy_log_id = $this.attr('value');
var data = {
proxy_log_id: proxy_log_id
};
terminateConnection(data)
}).on('click', '#btn_bulk_update', function () {
var data = [];
$('.cbx-term:checked').each(function () {
data.push({proxy_log_id: $(this).attr('value')})
});
terminateConnection(data)
})
</script>
{% endblock %}
{% extends '_base_list.html' %}
{% load i18n %}
{% load static %}
{% block content_left_head %}
<link href="{% static 'css/plugins/datepicker/datepicker3.css' %}" rel="stylesheet">
<style>
#search_btn {
margin-bottom: 0;
}
</style>
{% endblock %}
{% block table_search %}
<form id="search_form" method="get" action="" class="pull-right form-inline">
<div class="form-group" id="date">
<div class="input-daterange input-group" id="datepicker">
<span class="input-group-addon"><i class="fa fa-calendar"></i></span>
<input type="text" class="input-sm form-control" style="width: 100px;" name="date_from" value="{{ date_from }}">
<span class="input-group-addon">to</span>
<input type="text" class="input-sm form-control" style="width: 100px;" name="date_to" value="{{ date_to }}">
</div>
</div>
<div class="input-group">
<select class="select2 form-control" name="username">
<option value="">{% trans 'User' %}</option>
{% for u in user_list %}
<option value="{{ u }}" {% if u == username %} selected {% endif %}>{{ u }}</option>
{% endfor %}
</select>
</div>
<div class="input-group">
<select class="select2 form-control" name="ip">
<option value="">{% trans 'Asset' %}</option>
{% for a in asset_list %}
<option value="{{ a }}" {% if a == ip %} selected {% endif %}>{{ a }}</option>
{% endfor %}
</select>
</div>
<div class="input-group">
<select class="select2 form-control" name="system_user">
<option value="">{% trans 'System user' %}</option>
{% for su in system_user_list %}
<option value="{{ su }}" {% if su == system_user %} selected {% endif %}>{{ su }}</option>
{% endfor %}
</select>
</div>
<div class="input-group">
<input type="text" class="form-control input-sm" name="keyword" placeholder="Keyword" value="{{ keyword }}">
</div>
<div class="input-group">
<div class="input-group-btn">
<button id='search_btn' type="submit" class="btn btn-sm btn-primary">
搜索
</button>
</div>
</div>
</form>
{% endblock %}
{% block table_head %}
<th class="text-center"></th>
<th class="text-center">{% trans 'ID' %}</th>
<th class="text-center">{% trans 'User' %}</th>
<th class="text-center">{% trans 'Asset' %}</th>
<th class="text-center">{% trans 'System user' %}</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 'Finished' %}</th>
<th class="text-center">{% trans 'Monitor' %}</th>
<th class="text-center">{% trans 'Date start' %}</th>
<th class="text-center">{% trans 'Time' %}</th>
{% endblock %}
{% block table_body %}
{% for proxy_log in proxy_log_list %}
<tr class="gradeX">
<td class="text-center"><input type="checkbox" class="cbx-term" value="{{ proxy_log.id }}"></td>
<td class="text-center">
<a href="{% url 'audits:proxy-log-detail' pk=proxy_log.id %}">{{ proxy_log.id }}</a>
</td>
<td class="text-center">{{ proxy_log.user }}</td>
<td class="text-center">{{ proxy_log.asset }}</td>
<td class="text-center">{{ proxy_log.system_user }}</td>
<td class="text-center">{{ proxy_log.terminal }}</td>
<td class="text-center">{{ proxy_log.commands.all|length}}</td>
<td class="text-center">
{% if proxy_log.is_failed %}
<i class="fa fa-times text-danger"></i>
{% else %}
<i class="fa fa-check text-navy"></i>
{% endif %}
</td>
{% if proxy_log.is_finished %}
<td class="text-center">
<i class="fa fa-check text-navy"></i>
</td>
<td class="text-center">
<a><span class="text-navy"><i class="fa fa-play-circle"></i></span></a>
</td>
{% else %}
<td class="text-center">
<a class="btn-term" value="{{ proxy_log.id }}"><i class="fa fa-times text-danger"></i></a>
</td>
<td class="text-center">
<a><span class="text-danger"><i class="fa fa-eye"></i></span></a>
</td>
{% endif %}
<td class="text-center">{{ proxy_log.date_start }}</td>
<td class="text-center">{{ proxy_log.date_finished|timeuntil:proxy_log.date_start }}</td>
</tr>
{% endfor %}
{% endblock %}
{% block content_bottom_left %}
<div id="actions">
<div class="input-group">
<select class="form-control m-b" style="width: auto" id="slct_bulk_update">
<option value="terminate">{% trans 'Terminate selected' %}</option>
</select>
<div class="input-group-btn pull-left" style="padding-left: 5px;">
<button id='btn_bulk_update' style="height: 32px;" class="btn btn-sm btn-primary">
{% trans 'Submit' %}
</button>
</div>
</div>
</div>
{% endblock %}
{% block custom_foot_js %}
<script src="{% static 'js/plugins/datepicker/bootstrap-datepicker.js' %}"></script>
<script>
function terminateConnection(data) {
function success() {
window.setTimeout(function () {
window.location.reload()
}, 300)
}
var the_url = "";
APIUpdateAttr({url: the_url, method: 'POST', body: JSON.stringify(data), success: success, success_message: 'Terminate success'});
}
$(document).ready(function() {
$('table').DataTable({
"searching": false,
"paging": false,
"bInfo" : false,
"order": []
});
$('.select2').select2();
$('#date .input-daterange').datepicker({
dateFormat: 'mm/dd/yy',
keyboardNavigation: false,
forceParse: false,
autoclose: true
});
}).on('click', '.btn-term', function () {
var $this = $(this);
var proxy_log_id = $this.attr('value');
var data = {
proxy_log_id: proxy_log_id
};
terminateConnection(data)
}).on('click', '#btn_bulk_update', function () {
var data = [];
$('.cbx-term:checked').each(function () {
data.push({proxy_log_id: $(this).attr('value')})
});
terminateConnection(data)
})
</script>
{% endblock %}
from django.test import TestCase
# Create your tests here.
from django.conf.urls import url
from rest_framework import routers
from .. import api
app_name = 'audits'
router = routers.DefaultRouter()
router.register(r'v1/proxy-log', api.ProxyLogViewSet, 'proxy-log')
router.register(r'v1/command-log', api.CommandLogViewSet, 'command-log')
router.register(r'v1/replay-log', api.RecordLogViewSet, 'replay-log')
urlpatterns = [
url(r'^v1/proxy-log/receive/$', api.ProxyLogReceiveView.as_view(),
name='proxy-log-receive'),
]
urlpatterns += router.urls
from django.conf.urls import url
from .. import views
app_name = 'audits'
urlpatterns = [
url(r'^proxy-log-offline/$', views.ProxyLogOfflineListView.as_view(),
name='proxy-log-offline-list'),
url(r'^proxy-log-online/$', views.ProxyLogOnlineListView.as_view(),
name='proxy-log-online-list'),
url(r'^proxy-log/(?P<pk>[0-9a-zA-Z\-]+)/$', views.ProxyLogDetailView.as_view(),
name='proxy-log-detail'),
url(r'^command-log/$', views.CommandLogListView.as_view(),
name='command-log-list'),
url(r'^login-log/$', views.LoginLogListView.as_view(),
name='login-log-list'),
]
# ~*~ coding: utf-8 ~*~
#
from __future__ import unicode_literals
import requests
import ipaddress
from .models import LoginLog
def validate_ip(ip):
try:
ipaddress.ip_address(ip)
return True
except ValueError:
print('valid error')
return False
def write_login_log(username, name='', login_type='',
login_ip='', user_agent=''):
if not (login_ip and validate_ip(login_ip)):
login_ip = '0.0.0.0'
if not name:
name = username
login_city = get_ip_city(login_ip)
LoginLog.objects.create(username=username, name=name, login_type=login_type,
login_ip=login_ip, login_city=login_city, user_agent=user_agent)
def get_ip_city(ip, timeout=10):
# Taobao ip api: http://ip.taobao.com//service/getIpInfo.php?ip=8.8.8.8
# Sina ip api: http://int.dpool.sina.com.cn/iplookup/iplookup.php?ip=8.8.8.8&format=json
url = 'http://int.dpool.sina.com.cn/iplookup/iplookup.php?ip=%s&format=json' % ip
try:
r = requests.get(url, timeout=timeout)
except requests.Timeout:
r = None
city = 'Unknown'
if r and r.status_code == 200:
try:
data = r.json()
if not isinstance(data, int) and data['ret'] == 1:
city = data['country'] + ' ' + data['city']
except ValueError:
pass
return city
This diff is collapsed.
......@@ -3,7 +3,6 @@
from django import template
from django.utils import timezone
from django.utils.html import escape
from audits.backends import command_store
register = template.Library()
......@@ -70,6 +69,6 @@ def to_html(s):
return escape(s).replace('\n', '<br />')
@register.filter
def proxy_log_commands(log_id):
return command_store.filter(proxy_log_id=log_id)
# @register.filter
# def proxy_log_commands(log_id):
# return 1
from __future__ import absolute_import, unicode_literals
from django.shortcuts import render
from django.views.generic import TemplateView
......@@ -9,7 +9,7 @@ from django.shortcuts import HttpResponse
DEMO_MODE = os.environ.get("DEMO_MODE", "")
SAFE_URL = r'^/users/login|^/api/terminal/v1/.*|/api/audits/.*|/api/users/v1/auth/|/api/users/v1/profile/'
SAFE_URL = r'^/users/login|^/api/terminal/v1/.*|/api/terminal/.*|/api/users/v1/auth/|/api/users/v1/profile/'
class TimezoneMiddleware(MiddlewareMixin):
......
......@@ -59,7 +59,7 @@ INSTALLED_APPS = [
'assets.apps.AssetsConfig',
'perms.apps.PermsConfig',
'ops.apps.OpsConfig',
'audits.apps.AuditsConfig',
# 'audits.apps.AuditsConfig',
'common.apps.CommonConfig',
'terminal.apps.ApplicationsConfig',
'rest_framework',
......@@ -364,7 +364,7 @@ CAPTCHA_NOISE_FUNCTIONS = ('captcha.helpers.noise_dots',)
CAPTCHA_TEST_MODE = CONFIG.CAPTCHA_TEST_MODE
COMMAND_STORE_BACKEND = 'terminal.backends.command.db'
RECORD_STORE_BACKEND = 'terminal.backends.replay.db'
REPLAY_STORE_BACKEND = 'terminal.backends.replay.db'
# Django bootstrap3 setting, more see http://django-bootstrap3.readthedocs.io/en/latest/settings.html
......
......@@ -16,7 +16,7 @@ urlpatterns = [
url(r'^users/', include('users.urls.views_urls', namespace='users')),
url(r'^assets/', include('assets.urls.views_urls', namespace='assets')),
url(r'^perms/', include('perms.urls.views_urls', namespace='perms')),
url(r'^audits/', include('audits.urls.views_urls', namespace='audits')),
# url(r'^audits/', include('audits.urls.views_urls', namespace='audits')),
url(r'^terminal/', include('terminal.urls.views_urls', namespace='terminal')),
url(r'^ops/', include('ops.urls.view_urls', namespace='ops')),
......@@ -24,7 +24,7 @@ urlpatterns = [
url(r'^api/users/', include('users.urls.api_urls', namespace='api-users')),
url(r'^api/assets/', include('assets.urls.api_urls', namespace='api-assets')),
url(r'^api/perms/', include('perms.urls.api_urls', namespace='api-perms')),
url(r'^api/audits/', include('audits.urls.api_urls', namespace='api-audits')),
# url(r'^api/audits/', include('audits.urls.api_urls', namespace='api-audits')),
url(r'^api/terminal/', include('terminal.urls.api_urls', namespace='api-terminal')),
url(r'^api/ops/', include('ops.urls.api_urls', namespace='api-ops')),
url(r'^captcha/', include('captcha.urls')),
......
......@@ -6,70 +6,146 @@ from django.shortcuts import redirect
from users.models import User
from assets.models import Asset
from audits.models import ProxyLog
from terminal.models import Session
class IndexView(LoginRequiredMixin, TemplateView):
template_name = 'index.html'
session_week = None
session_month = None
session_month_dates = []
session_month_dates_archive = []
def get(self, request, *args, **kwargs):
if not request.user.is_superuser:
return redirect('assets:user-asset-list')
return super(IndexView, self).get(request, *args, **kwargs)
def get_context_data(self, **kwargs):
seven_days_ago = timezone.now() - timezone.timedelta(days=7)
month_ago = timezone.now() - timezone.timedelta(days=30)
proxy_log_seven_days = ProxyLog.objects.filter(date_start__gt=seven_days_ago, is_failed=False)
proxy_log_month = ProxyLog.objects.filter(date_start__gt=month_ago, is_failed=False)
month_dates = proxy_log_month.dates('date_start', 'day')
month_total_visit = [ProxyLog.objects.filter(date_start__date=d) for d in month_dates]
month_str = [d.strftime('%m-%d') for d in month_dates] or ['0']
month_total_visit_count = [p.count() for p in month_total_visit] or [0]
month_user = [p.values('user').distinct().count() for p in month_total_visit] or [0]
month_asset = [p.values('asset').distinct().count() for p in month_total_visit] or [0]
month_user_active = User.objects.filter(last_login__gt=month_ago).count()
month_user_inactive = User.objects.filter(last_login__lt=month_ago).count()
month_user_disabled = User.objects.filter(is_active=False).count()
month_asset_active = proxy_log_month.values('asset').distinct().count()
month_asset_inactive = Asset.objects.all().count() - month_asset_active
month_asset_disabled = Asset.objects.filter(is_active=False).count()
week_asset_hot_ten = list(proxy_log_seven_days.values('asset').annotate(total=Count('asset')).order_by('-total')[:10])
for p in week_asset_hot_ten:
last_login = ProxyLog.objects.filter(asset=p['asset']).order_by('date_start').last()
p['last'] = last_login
last_login_ten = ProxyLog.objects.all().order_by('-date_start')[:10]
for p in last_login_ten:
@staticmethod
def get_user_count():
return User.objects.filter(role__in=('Admin', 'User')).count()
@staticmethod
def get_asset_count():
return Asset.objects.all().count()
@staticmethod
def get_online_user_count():
return len(set(Session.objects.filter(is_finished=False).values_list('user', flat=True)))
@staticmethod
def get_online_session_count():
return Session.objects.filter(is_finished=False).count()
def get_top5_user_a_week(self):
return self.session_week.values('user').annotate(total=Count('user')).order_by('-total')[:5]
def get_week_login_user_count(self):
return self.session_week.values('user').distinct().count()
def get_week_login_asset_count(self):
return self.session_week.values('asset').distinct().count()
def get_month_day_metrics(self):
month_str = [d.strftime('%m-%d') for d in self.session_month_dates] or ['0']
return month_str
def get_month_login_metrics(self):
return [self.session_month.filter(date_start__date=d).count()
for d in self.session_month_dates]
def get_month_active_user_metrics(self):
if self.session_month_dates_archive:
return [q.values('user').distinct().count()
for q in self.session_month_dates_archive]
else:
return [0]
def get_month_active_asset_metrics(self):
if self.session_month_dates_archive:
return [q.values('asset').distinct().count()
for q in self.session_month_dates_archive]
else:
return [0]
def get_month_active_user_total(self):
return self.session_month.values('user').distinct().count()
def get_month_inactive_user_total(self):
return User.objects.all().count() - self.get_month_active_user_total()
def get_month_active_asset_total(self):
return self.session_month.values('asset').distinct().count()
def get_month_inactive_asset_total(self):
return Asset.objects.all().count() - self.get_month_active_asset_total()
@staticmethod
def get_user_disabled_total():
return User.objects.filter(is_active=False).count()
@staticmethod
def get_asset_disabled_total():
return Asset.objects.filter(is_active=False).count()
def get_week_top10_asset(self):
assets = list(self.session_week.values('asset').annotate(total=Count('asset')).order_by('-total')[:10])
for asset in assets:
last_login = self.session_week.filter(asset=asset["asset"]).order_by('date_start').last()
asset['last'] = last_login
print(asset)
return assets
def get_week_top10_user(self):
users = list(self.session_week.values('user').annotate(
total=Count('asset')).order_by('-total')[:10])
for user in users:
last_login = self.session_week.filter(user=user["user"]).order_by('date_start').last()
user['last'] = last_login
return users
def get_last10_sessions(self):
sessions = self.session_week.order_by('-date_start')[:10]
for session in sessions:
try:
p.avatar_url = User.objects.get(username=p.user).avatar_url()
session.avatar_url = User.objects.get(username=session.user).avatar_url()
except User.DoesNotExist:
p.avatar_url = User.objects.first().avatar_url()
week_user_hot_ten = list(proxy_log_seven_days.values('user').annotate(total=Count('user')).order_by('-total')[:10])
for p in week_user_hot_ten:
last_login = ProxyLog.objects.filter(user=p['user']).order_by('date_start').last()
p['last'] = last_login
session.avatar_url = User.objects.first().avatar_url()
return sessions
def get_context_data(self, **kwargs):
week_ago = timezone.now() - timezone.timedelta(weeks=1)
month_ago = timezone.now() - timezone.timedelta(days=30)
self.session_week = Session.objects.filter(date_start__gt=week_ago)
self.session_month = Session.objects.filter(date_start__gt=month_ago)
self.session_month_dates = self.session_month.dates('date_start', 'day')
self.session_month_dates_archive = [
self.session_month.filter(date_start__date=d)
for d in self.session_month_dates
]
context = {
'assets_count': Asset.objects.count(),
'users_count': User.objects.filter(role__in=('Admin', 'User')).count(),
'online_user_count': ProxyLog.objects.filter(is_finished=False).values('user').distinct().count(),
'online_asset_count': ProxyLog.objects.filter(is_finished=False).values('asset').distinct().count(),
'user_visit_count_weekly': proxy_log_seven_days.values('user').distinct().count(),
'asset_visit_count_weekly': proxy_log_seven_days.count(),
'user_visit_count_top_five': proxy_log_seven_days.values('user').annotate(total=Count('user')).order_by('-total')[:5],
'month_str': month_str,
'month_total_visit_count': month_total_visit_count,
'month_user': month_user,
'mouth_asset': month_asset,
'month_user_active': month_user_active,
'month_user_inactive': month_user_inactive,
'month_user_disabled': month_user_disabled,
'month_asset_active': month_asset_active,
'month_asset_inactive': month_asset_inactive,
'month_asset_disabled': month_asset_disabled,
'week_asset_hot_ten': week_asset_hot_ten,
'last_login_ten': last_login_ten,
'week_user_hot_ten': week_user_hot_ten,
'assets_count': self.get_asset_count(),
'users_count': self.get_user_count(),
'online_user_count': self.get_online_user_count(),
'online_asset_count': self.get_online_session_count(),
'user_visit_count_weekly': self.get_week_login_user_count(),
'asset_visit_count_weekly': self.get_week_login_asset_count(),
'user_visit_count_top_five': self.get_top5_user_a_week(),
'month_str': self.get_month_day_metrics(),
'month_total_visit_count': self.get_month_login_metrics(),
'month_user': self.get_month_active_user_metrics(),
'mouth_asset': self.get_month_active_asset_metrics(),
'month_user_active': self.get_month_active_user_total(),
'month_user_inactive': self.get_month_inactive_user_total(),
'month_user_disabled': self.get_user_disabled_total(),
'month_asset_active': self.get_month_active_asset_total(),
'month_asset_inactive': self.get_month_inactive_asset_total(),
'month_asset_disabled': self.get_asset_disabled_total(),
'week_asset_hot_ten': self.get_week_top10_asset(),
'last_login_ten': self.get_last10_sessions(),
'week_user_hot_ten': self.get_week_top10_user(),
}
kwargs.update(context)
......
......@@ -35,7 +35,7 @@
<h5>在线用户</h5>
</div>
<div class="ibox-content">
<h1 class="no-margins"><a href="{% url 'audits:proxy-log-online-list' %}"> <span id="online_users"></span>{{ online_user_count }}</a></h1>
<h1 class="no-margins"><a href="{% url 'terminal:session-online-list' %}"> <span id="online_users"></span>{{ online_user_count }}</a></h1>
<small>Online user</small>
</div>
</div>
......@@ -45,11 +45,11 @@
<div class="ibox float-e-margins">
<div class="ibox-title">
<span class="label label-danger pull-right">Connected</span>
<h5>已连接服务器</h5>
<h5>在线会话</h5>
</div>
<div class="ibox-content">
<h1 class="no-margins"><a href="{% url 'audits:proxy-log-online-list' %}"> <span id="online_hosts"></span>{{ online_asset_count }}</a></h1>
<small>Connected host</small>
<h1 class="no-margins"><a href="{% url 'terminal:session-online-list' %}"> <span id="online_hosts"></span>{{ online_asset_count }}</a></h1>
<small>Online sessions</small>
</div>
</div>
</div>
......
# -*- coding: utf-8 -*-
#
import base64
from collections import OrderedDict
import copy
import logging
import tarfile
import os
from rest_framework import viewsets, serializers
......@@ -18,7 +16,7 @@ from common.utils import get_object_or_none
from .models import Terminal, Status, Session, Task
from .serializers import TerminalSerializer, StatusSerializer, \
SessionSerializer, TaskSerializer
from .hands import IsSuperUserOrAppUser, IsAppUser, ProxyLog, \
from .hands import IsSuperUserOrAppUser, IsAppUser, \
IsSuperUserOrAppUserOrUserReadonly
from .backends import get_command_store, get_replay_store, SessionCommandSerializer
......@@ -221,7 +219,9 @@ class CommandViewSet(viewsets.ViewSet):
else:
return Response("Save error", status=500)
else:
return Response({"msg": "Not valid: {}".format(serializer.errors)}, status=401)
msg = "Not valid: {}".format(serializer.errors)
logger.error(msg)
return Response({"msg": msg}, status=401)
def list(self, request, *args, **kwargs):
queryset = list(self.command_store.all())
......
......@@ -12,6 +12,6 @@ def get_command_store():
def get_replay_store():
replay_engine = import_module(settings.RECORD_STORE_BACKEND)
replay_store = replay_engine.RecordStore()
replay_engine = import_module(settings.REPLAY_STORE_BACKEND)
replay_store = replay_engine.ReplayStore()
return replay_store
......@@ -2,7 +2,7 @@
import abc
class RecordBase(object):
class ReplayBase(object):
__metaclass__ = abc.ABCMeta
@abc.abstractmethod
......
# ~*~ coding: utf-8 ~*~
from .base import RecordBase
from audits.models import RecordLog
from .base import ReplayBase
class RecordStore(RecordBase):
model = RecordLog
queryset = []
def save(self, proxy_log_id, output, timestamp):
return self.model.objects.create(
proxy_log_id=proxy_log_id, output=output, timestamp=timestamp
)
def filter(self, date_from_ts=None, proxy_log_id=''):
filter_kwargs = {}
if date_from_ts:
filter_kwargs['timestamp__gte'] = date_from_ts
if proxy_log_id:
filter_kwargs['proxy_log_id'] = proxy_log_id
if filter_kwargs:
self.queryset = self.model.objects.filter(**filter_kwargs)
return self.queryset
def all(self):
"""返回所有数据"""
return self.model.objects.all()
class ReplayStore(ReplayBase):
pass
# ~*~ coding: utf-8 ~*~
import base64
from rest_framework import serializers
from audits.models import RecordLog
from audits.backends import record_store
class RecordSerializer(serializers.ModelSerializer):
"""使用这个类作为基础Command Log Serializer类, 用来序列化"""
class Meta:
model = RecordLog
fields = '__all__'
def create(self, validated_data):
try:
output = validated_data['output']
validated_data['output'] = base64.b64decode(output)
except IndexError:
pass
return record_store.save(**dict(validated_data))
......@@ -4,5 +4,4 @@
from users.models import User
from users.permissions import IsSuperUserOrAppUser, IsAppUser, \
IsSuperUserOrAppUserOrUserReadonly
from audits.models import ProxyLog
from users.utils import AdminUserRequiredMixin
\ No newline at end of file
......@@ -13,6 +13,7 @@ ASSETS_CACHE_KEY = "terminal__session__assets"
USERS_CACHE_KEY = "terminal__session__users"
SYSTEM_USER_CACHE_KEY = "terminal__session__system_users"
CACHE_REFRESH_INTERVAL = 10
RUNNING = False
# Todo: 定期清理上报history
......@@ -46,7 +47,16 @@ def set_cache():
def main():
global RUNNING
if RUNNING:
return
threads = []
thread = threading.Thread(target=set_cache)
thread.start()
threads.append(thread)
for t in threads:
t.daemon = True
t.start()
RUNNING = True
main()
......@@ -9,7 +9,7 @@ from rest_framework_bulk import BulkModelViewSet
from django_filters.rest_framework import DjangoFilterBackend
from . import serializers
from .hands import write_login_log_async
from .tasks import write_login_log_async
from .models import User, UserGroup
from .permissions import IsSuperUser, IsValidUser, IsCurrentUserOrReadOnly
from .utils import check_user_valid, generate_token
......
......@@ -10,8 +10,8 @@
:license: GPL v2, see LICENSE for more details.
"""
from terminal.models import Terminal
from audits.tasks import write_login_log_async
from users.models import User
# from terminal.models import Terminal
# from audits.tasks import write_login_log_async
# from users.models import User
# from perms.models import AssetPermission
# from perms.utils import get_user_granted_assets, get_user_granted_asset_groups
......@@ -8,7 +8,7 @@ from django.utils.translation import ugettext_lazy as _
from rest_framework.authtoken.models import Token
from . import User
__all__ = ['AccessKey', 'PrivateToken']
__all__ = ['AccessKey', 'PrivateToken', 'LoginLog']
class AccessKey(models.Model):
......@@ -34,3 +34,22 @@ class PrivateToken(Token):
class Meta:
verbose_name = _('Private Token')
class LoginLog(models.Model):
LOGIN_TYPE_CHOICE = (
('W', 'Web'),
('ST', 'SSH Terminal'),
('WT', 'Web Terminal')
)
id = models.UUIDField(default=uuid.uuid4, primary_key=True)
username = models.CharField(max_length=20, verbose_name=_('Username'))
type = models.CharField(choices=LOGIN_TYPE_CHOICE, max_length=2, verbose_name=_('Login type'))
ip = models.GenericIPAddressField(verbose_name=_('Login ip'))
city = models.CharField(max_length=254, blank=True, null=True, verbose_name=_('Login city'))
user_agent = models.CharField(max_length=254, blank=True, null=True, verbose_name=_('User agent'))
datetime = models.DateTimeField(auto_now_add=True, verbose_name=_('Date login'))
class Meta:
db_table = 'login_log'
ordering = ['-datetime', 'username']
......@@ -24,9 +24,8 @@ class UserGroup(NoDeleteModelMixin):
verbose_name=_('Date created'))
created_by = models.CharField(max_length=100)
def __unicode__(self):
def __str__(self):
return self.name
__str__ = __unicode__
def delete(self, using=None, keep_parents=False):
if self.name != 'Default':
......
#!/usr/bin/env python
# ~*~ coding: utf-8 ~*~
#
# -*- coding: utf-8 -*-
#
from celery import shared_task
from .utils import write_login_log
......
......@@ -5,7 +5,8 @@ import base64
import logging
import uuid
from paramiko.rsakey import RSAKey
import requests
import ipaddress
from django.conf import settings
from django.contrib.auth.mixins import UserPassesTestMixin
from django.contrib.auth import authenticate
......@@ -14,13 +15,7 @@ from django.core.cache import cache
from common.tasks import send_mail_async
from common.utils import reverse, get_object_or_none
from .models import User
# try:
# from io import StringIO
# except ImportError:
# from StringIO import StringIO
from .models import User, LoginLog
logger = logging.getLogger('jumpserver')
......@@ -172,3 +167,40 @@ def generate_token(request, user):
return token
def validate_ip(ip):
try:
ipaddress.ip_address(ip)
return True
except ValueError:
pass
return False
def write_login_log(username, type='', ip='', user_agent=''):
if not (ip and validate_ip(ip)):
ip = '0.0.0.0'
city = get_ip_city(ip)
LoginLog.objects.create(
username=username, type=type,
ip=ip, city=city, user_agent=user_agent
)
def get_ip_city(ip, timeout=10):
# Taobao ip api: http://ip.taobao.com//service/getIpInfo.php?ip=8.8.8.8
# Sina ip api: http://int.dpool.sina.com.cn/iplookup/iplookup.php?ip=8.8.8.8&format=json
url = 'http://int.dpool.sina.com.cn/iplookup/iplookup.php?ip=%s&format=json' % ip
try:
r = requests.get(url, timeout=timeout)
except requests.Timeout:
r = None
city = 'Unknown'
if r and r.status_code == 200:
try:
data = r.json()
if not isinstance(data, int) and data['ret'] == 1:
city = data['country'] + ' ' + data['city']
except ValueError:
pass
return city
......@@ -21,7 +21,7 @@ from django.conf import settings
from common.utils import get_object_or_none
from ..models import User
from ..utils import send_reset_password_mail
from ..hands import write_login_log_async
from ..tasks import write_login_log_async
from .. import forms
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment