Add auditable superuser mode (#824)

* Remove is_superuser everywhere

* Session handling

* List of sessions, relative timeout

* Absolute timeout

* Optionally pseudo-force audit comments

* Fix failing tests

* Add tests

* Add docs

* Rebsae migration

* Typos

* Fix tests
This commit is contained in:
Raphael Michel
2018-03-28 14:16:58 +02:00
committed by GitHub
parent 558c920181
commit a284e0c2f7
56 changed files with 965 additions and 130 deletions

View File

@@ -151,6 +151,22 @@
</li>
{% endfor %}
{% if request.user.is_staff and not staff_session %}
<li>
<form action="{% url 'control:user.sudo' %}?next={{ request.path|urlencode }}" method="post">
{% csrf_token %}
<button type="submit" class="btn btn-link" id="button-sudo">
<i class="fa fa-id-card"></i> {% trans "Admin mode" %}
</button>
</form>
</li>
{% elif request.user.is_staff and staff_session %}
<li>
<a href="{% url 'control:user.sudo.stop' %}" class="danger">
<i class="fa fa-id-card"></i> {% trans "End admin session" %}
</a>
</li>
{% endif %}
{% if warning_update_available %}
<li>
<a href="{% url 'control:global.update' %}" class="danger">
@@ -191,7 +207,7 @@
{% trans "Dashboard" %}
</a>
</li>
{% if request.user.is_superuser %}
{% if staff_session %}
<li>
<a href="{% url 'control:global.settings' %}"
{% if "global.settings" in url_name %}class="active"{% endif %}>
@@ -219,14 +235,21 @@
{% trans "Order search" %}
</a>
</li>
{% if request.user.is_superuser %}
{% if staff_session %}
<li>
<a href="{% url 'control:users' %}"
{% if "users" in url_name %}class="active"{% endif %}>
{% if "users" in url_name %}class="active"{% endif %}>
<i class="fa fa-user fa-fw"></i>
{% trans "Users" %}
</a>
</li>
<li>
<a href="{% url 'control:user.sudo.list' %}"
{% if "sudo" in url_name %}class="active"{% endif %}>
<i class="fa fa-id-card fa-fw"></i>
{% trans "Admin sessions" %}
</a>
</li>
{% endif %}
{% for nav in nav_global %}
<li>
@@ -260,6 +283,21 @@
</div>
</div>
</nav>
{% if staff_need_to_explain %}
<div class="impersonate-warning">
<span class="fa fa-id-card"></span>
{% blocktrans trimmed %}
Please leave a short comment on what you did in the following admin sessions:
{% endblocktrans %}
<ul>
{% for s in staff_need_to_explain %}
<li>
<a href="{% url "control:user.sudo.edit" id=s.pk %}">#{{ s.pk }}</a>
</li>
{% endfor %}
</ul>
</div>
{% endif %}
{% if request|is_hijacked %}
<div class="impersonate-warning">
<span class="fa fa-user-secret"></span>

View File

@@ -109,7 +109,7 @@
</div>
<div class="col-lg-2 col-sm-6 col-xs-12">
{% if log.user %}
{% if log.user.is_superuser %}
{% if log.user.is_staff %}
<span class="fa fa-id-card fa-danger fa-fw"
data-toggle="tooltip"
title="{% trans "This change was performed by a pretix administrator." %}">

View File

@@ -34,7 +34,7 @@
</div>
<div class="col-lg-2 col-sm-6 col-xs-12">
{% if log.user %}
{% if log.user.is_superuser %}
{% if log.user.is_staff %}
<span class="fa fa-id-card fa-danger fa-fw"
data-toggle="tooltip"
title="{% trans "This change was performed by a pretix administrator." %}">

View File

@@ -23,7 +23,7 @@
<div class="col-sm-4">
{% if plugin.app.compatibility_errors %}
<button class="btn disabled btn-block btn-default" disabled="disabled">{% trans "Incompatible" %}</button>
{% elif plugin.restricted and not request.user.is_superuser %}
{% elif plugin.restricted and not request.user.is_staff %}
<button class="btn disabled btn-block btn-default" disabled="disabled">{% trans "Not available" %}</button>
{% elif plugin.module in plugins_active %}
<button class="btn btn-default btn-block" name="plugin:{{ plugin.module }}" value="disable">{% trans "Disable" %}</button>
@@ -44,7 +44,7 @@
{% endblocktrans %}</p>
{% endif %}
<p>{{ plugin.description }}</p>
{% if plugin.restricted and not request.user.is_superuser %}
{% if plugin.restricted and not request.user.is_staff %}
<div class="alert alert-warning">
{% trans "This plugin needs to be enabled by a system administrator for your event." %}
</div>

View File

@@ -29,7 +29,7 @@
<div class="alert alert-danger">
{% trans "Every event needs to be created as part of an organizer account. Currently, you do not have access to any organizer accounts." %}
</div>
{% if request.user.is_superuser %}
{% if staff_session %}
<a href="{% url "control:organizers.add" %}" class="btn btn-default">
{% trans "Create a new organizer" %}
</a>

View File

@@ -6,7 +6,7 @@
<p class="meta">
<span class="fa fa-clock-o"></span> {{ log.datetime|date:"SHORT_DATETIME_FORMAT" }}
{% if log.user %}
{% if log.user.is_superuser %}
{% if log.user.is_staff %}
<span class="fa fa-id-card fa-danger fa-fw"
data-toggle="tooltip"
title="{% trans "This change was performed by a pretix administrator." %}">

View File

@@ -20,7 +20,7 @@
</button>
</div>
</form>
{% if request.user.is_superuser %}
{% if staff_session %}
<p>
<a href="{% url "control:organizers.add" %}" class="btn btn-default">
<span class="fa fa-plus"></span>

View File

@@ -0,0 +1,47 @@
{% extends "pretixcontrol/base.html" %}
{% load i18n %}
{% load bootstrap3 %}
{% block title %}{% trans "Staff session" %}{% endblock %}
{% block content %}
<h1>{% trans "Session notes" %}</h1>
<form action="" method="post" class="form-horizontal">
{% csrf_token %}
{% bootstrap_form_errors form %}
{% bootstrap_field form.comment layout='horizontal' %}
<div class="form-group submit-group">
<button type="submit" class="btn btn-primary btn-save">
{% trans "Save" %}
</button>
</div>
</form>
<h1>{% trans "Audit log" %}</h1>
<dl class="dl-horizontal">
<dt>{% trans "Start date" %}</dt>
<dd>{{ session.date_start|date:"SHORT_DATETIME_FORMAT" }}</dd>
<dt>{% trans "End date" %}</dt>
<dd>{{ session.date_end|date:"SHORT_DATETIME_FORMAT" }}</dd>
<dt>{% trans "User" %}</dt>
<dd>{{ session.user.email }}</dd>
</dl>
<table class="table table-condensed">
<thead>
<tr>
<th>{% trans "Timestamp" %}</th>
<th>{% trans "Method" %}</th>
<th>{% trans "URL" %}</th>
<th>{% trans "On behalf of" %}</th>
</tr>
</thead>
<tbody>
{% for log in logs %}
<tr>
<td>{{ log.datetime|date:"SHORT_DATETIME_FORMAT" }}</td>
<td>{{ log.method }}</td>
<td>{{ log.url }}</td>
<td>{{ log.impersonating|default:"" }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}

View File

@@ -0,0 +1,58 @@
{% extends "pretixcontrol/base.html" %}
{% load i18n %}
{% load bootstrap3 %}
{% load urlreplace %}
{% block title %}{% trans "Admin sessions" %}{% endblock %}
{% block content %}
<h1>{% trans "Admin sessions" %}</h1>
<table class="table table-condensed table-hover">
<thead>
<tr>
<th>
#
</th>
<th>
{% trans "User" %}
</th>
<th>
{% trans "Start date" %}
</th>
<th>{% trans "End date" %}</th>
<th>{% trans "Comment" %}</th>
<th></th>
</tr>
</thead>
<tbody>
{% for s in sessions %}
<tr>
<td><strong>
<a href="{% url "control:user.sudo.edit" id=s.pk %}">{{ s.pk }}</a>
</strong></td>
<td><strong>
<a href="{% url "control:users.edit" id=s.user.pk %}">{{ s.user.email }}</a>
</strong></td>
<td>
{{ s.date_start|date:"SHORT_DATETIME_FORMAT" }}
</td>
<td>
{% if s.date_end %}
{{ s.date_end|date:"SHORT_DATETIME_FORMAT" }}
{% endif %}
</td>
<td>
{% if s.comment %}
<span class="fa fa-check"></span>
{% else %}
<span class="fa fa-times text-danger"></span>
{% endif %}
</td>
<td class="text-right">
<a href="{% url "control:user.sudo.edit" id=s.id %}" class="btn btn-default btn-sm"><i
class="fa fa-edit"></i></a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% include "pretixcontrol/pagination.html" %}
{% endblock %}

View File

@@ -0,0 +1,22 @@
{% extends "pretixcontrol/base.html" %}
{% load i18n %}
{% load bootstrap3 %}
{% block title %}{% trans "Admin mode" %}{% endblock %}
{% block content %}
<h1>{% trans "Admin mode" %}</h1>
<p>
{% blocktrans trimmed %}
To perform this action, you need to start an administrative session. Everything you do in that session
will be logged and you will later be asked to fill in a comment on what you did in your session for later
reference.
{% endblocktrans %}
</p>
<form action="" method="post" class="form-horizontal">
{% csrf_token %}
<div class="form-group submit-group">
<button type="submit" class="btn btn-primary btn-save">
{% trans "Start session" %}
</button>
</div>
</form>
{% endblock %}

View File

@@ -25,7 +25,7 @@
{% bootstrap_field form.fullname layout='control' %}
{% bootstrap_field form.locale layout='control' %}
{% bootstrap_field form.timezone layout='control' %}
{% bootstrap_field form.is_superuser layout='control' %}
{% bootstrap_field form.is_staff layout='control' %}
</fieldset>
<fieldset>
<legend>{% trans "Log-in settings" %}</legend>

View File

@@ -56,7 +56,7 @@
</strong></td>
<td>{{ u.fullname|default_if_none:"" }}</td>
<td>{% if u.is_active %}<span class="fa fa-check-circle"></span>{% endif %}</td>
<td>{% if u.is_superuser %}<span class="fa fa-check-circle"></span>{% endif %}</td>
<td>{% if u.is_staff %}<span class="fa fa-check-circle"></span>{% endif %}</td>
<td class="text-right">
<a href="{% url "control:users.edit" id=u.id %}" class="btn btn-default btn-sm"><i class="fa fa-edit"></i></a>
</td>