forked from shaba/openuds
Merge remote-tracking branch 'origin/v3.6'
This commit is contained in:
commit
2908b99435
@ -31,7 +31,7 @@ Author: Adolfo Gómez, dkmaster at dkmon dot com
|
||||
"""
|
||||
import typing
|
||||
|
||||
from uds.models import Log, getSqlDatetime
|
||||
from uds import models
|
||||
from uds.core.util.log import (
|
||||
REST,
|
||||
OWNER_TYPE_AUDIT,
|
||||
@ -40,31 +40,68 @@ from uds.core.util.log import (
|
||||
WARNING,
|
||||
ERROR,
|
||||
CRITICAL,
|
||||
# These are legacy support until full removal
|
||||
WARN,
|
||||
FATAL,
|
||||
)
|
||||
|
||||
|
||||
if typing.TYPE_CHECKING:
|
||||
from .handlers import Handler
|
||||
|
||||
# This structct allows us to perform the following:
|
||||
# If path has ".../providers/[uuid]/..." we will replace uuid with "provider nanme" sourrounded by []
|
||||
# If path has ".../services/[uuid]/..." we will replace uuid with "service name" sourrounded by []
|
||||
# If path has ".../users/[uuid]/..." we will replace uuid with "user name" sourrounded by []
|
||||
# If path has ".../groups/[uuid]/..." we will replace uuid with "group name" sourrounded by []
|
||||
UUID_REPLACER = (
|
||||
('providers', models.Provider),
|
||||
('services', models.Service),
|
||||
('users', models.User),
|
||||
('groups', models.Group),
|
||||
)
|
||||
|
||||
def log_operation(handler: typing.Optional['Handler'], response_code: int, level: int = INFO):
|
||||
|
||||
def replacePath(path: str) -> str:
|
||||
"""Replaces uuids in path with names
|
||||
All paths are in the form .../type/uuid/...
|
||||
"""
|
||||
for type, model in UUID_REPLACER:
|
||||
if f'/{type}/' in path:
|
||||
try:
|
||||
uuid = path.split(f'/{type}/')[1].split('/')[0]
|
||||
name = model.objects.get(uuid=uuid).name # type: ignore
|
||||
path = path.replace(uuid, f'[{name}]')
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
return path
|
||||
|
||||
|
||||
def log_operation(
|
||||
handler: typing.Optional['Handler'], response_code: int, level: int = INFO
|
||||
):
|
||||
"""
|
||||
Logs a request
|
||||
"""
|
||||
if not handler:
|
||||
return # Nothing to log
|
||||
|
||||
path = handler._request.path
|
||||
|
||||
# If a common request, and no error, we don't log it because it's useless and a waste of resources
|
||||
if response_code < 400 and any(
|
||||
x in path for x in ('overview', 'tableinfo', 'gui', 'types', 'system')
|
||||
):
|
||||
return
|
||||
|
||||
path = replacePath(path)
|
||||
|
||||
username = handler._request.user.pretty_name if handler._request.user else 'Unknown'
|
||||
# Global log is used without owner nor type
|
||||
Log.objects.create(
|
||||
models.Log.objects.create(
|
||||
owner_id=0,
|
||||
owner_type=OWNER_TYPE_AUDIT,
|
||||
created=getSqlDatetime(),
|
||||
created=models.getSqlDatetime(),
|
||||
level=level,
|
||||
source=REST,
|
||||
data=f'{username}: [{handler._request.method}/{response_code}] {handler._request.path}'[
|
||||
data=f'{handler._request.ip} {username}: [{handler._request.method}/{response_code}] {path}'[
|
||||
:255
|
||||
],
|
||||
)
|
||||
|
@ -163,7 +163,7 @@ class gui:
|
||||
# Helper to convert an item to a dict
|
||||
def choiceFromValue(val: typing.Union[str, typing.Dict[str, str]]) -> typing.Dict[str, str]:
|
||||
if isinstance(val, str):
|
||||
return {'id': val, 'name': val}
|
||||
return {'id': val, 'text': val}
|
||||
# Return a deepcopy
|
||||
return copy.deepcopy(val)
|
||||
|
||||
|
@ -227,6 +227,7 @@ class SMSMFA(mfas.MFA):
|
||||
cls.networks.setValues([
|
||||
gui.choiceItem(v.uuid, v.name)
|
||||
for v in models.Network.objects.all().order_by('name')
|
||||
if v.uuid
|
||||
])
|
||||
|
||||
def composeSmsUrl(self, userId: str, userName: str, code: str, phone: str) -> str:
|
||||
|
@ -80,7 +80,7 @@ class ListReportAuditCSV(ListReport):
|
||||
def genData(self) -> typing.Generator[typing.Tuple, None, None]:
|
||||
# Xtract user method, response_code and request from data
|
||||
# the format is "user: [method/response_code] request"
|
||||
rx = re.compile(r'(?P<user>[^:]*): \[(?P<method>[^/]*)/(?P<response_code>[^\]]*)\] (?P<request>.*)')
|
||||
rx = re.compile(r'(?P<ip>[^ ]*) (?P<user>[^:]*): \[(?P<method>[^/]*)/(?P<response_code>[^\]]*)\] (?P<request>.*)')
|
||||
|
||||
start = self.startDate.datetime().replace(hour=0, minute=0, second=0, microsecond=0)
|
||||
end = self.endDate.datetime().replace(hour=23, minute=59, second=59, microsecond=999999)
|
||||
@ -91,10 +91,6 @@ class ListReportAuditCSV(ListReport):
|
||||
m = rx.match(i.data)
|
||||
|
||||
if m is not None:
|
||||
# Skip fields with 200 and one of this words on the request
|
||||
# overview, tableinfo, gui, types, system
|
||||
if m.group('response_code') == '200' and any(x in m.group('request') for x in ('overview', 'tableinfo', 'gui', 'types', 'system')):
|
||||
continue
|
||||
# Convert response code to an string if 200, else, to an error
|
||||
response_code = {
|
||||
'200': 'OK',
|
||||
@ -105,10 +101,11 @@ class ListReportAuditCSV(ListReport):
|
||||
'405': 'Method Not Allowed',
|
||||
'500': 'Internal Server Error',
|
||||
'501': 'Not Implemented',
|
||||
}.get(m.group('response_code'), 'CODE: ' + m.group('response_code'))
|
||||
}.get(m.group('response_code'), 'Code: ' + m.group('response_code'))
|
||||
yield (
|
||||
i.created,
|
||||
i.level_str,
|
||||
m.group('ip'),
|
||||
m.group('user'),
|
||||
m.group('method'),
|
||||
response_code,
|
||||
@ -120,7 +117,7 @@ class ListReportAuditCSV(ListReport):
|
||||
writer = csv.writer(output)
|
||||
|
||||
writer.writerow(
|
||||
[ugettext('Date'), ugettext('Level'), ugettext('User'), ugettext('Method'), ugettext('Response code'), ugettext('Request')]
|
||||
[ugettext('Date'), ugettext('Level'), ugettext('IP'), ugettext('User'), ugettext('Method'), ugettext('Response code'), ugettext('Request')]
|
||||
)
|
||||
|
||||
for l in self.genData():
|
||||
|
33
server/src/uds/templates/uds/reports/lists/audit.html
Normal file
33
server/src/uds/templates/uds/reports/lists/audit.html
Normal file
@ -0,0 +1,33 @@
|
||||
{% load l10n i18n %}
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Users Report</title>
|
||||
<meta name="author" content="UDS">
|
||||
<meta name="description" content="List of UDS audit logs">
|
||||
<meta name="keywords" content="uds,report,audit,log,list">
|
||||
<meta name="generator" content="UDS Reporting">
|
||||
</head>
|
||||
<body>
|
||||
<table style="width: 100%; font-size: 0.8em;">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width: 25%">{% trans 'Date' %}</th>
|
||||
<th style="width: 15%">{% trans 'Level' %}</th>
|
||||
<th style="width: 60%">{% trans 'Message' %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for log in logs %}
|
||||
<tr>
|
||||
<td>{{ log.date }}</td>
|
||||
<td>{{ log.level }}</td>
|
||||
<td>{{ log.message }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<!-- <p style="page-break-before: always">
|
||||
This is a new page
|
||||
</p> -->
|
||||
</body>
|
||||
</html>
|
Loading…
Reference in New Issue
Block a user