Unverified Commit 3731aa30 authored by Enrico Zini's avatar Enrico Zini
Browse files

More useful views for inspecting identities. Closes: #2

parents 4f809504 d0512a03
...@@ -127,14 +127,19 @@ class VisitPersonMixin(VisitorMixin): ...@@ -127,14 +127,19 @@ class VisitPersonMixin(VisitorMixin):
"key": self.person.lookup_key}) + f"?url={self.request.build_absolute_uri()}", "key": self.person.lookup_key}) + f"?url={self.request.build_absolute_uri()}",
_("Impersonate"), "random")) _("Impersonate"), "random"))
if self.person.is_dd: if self.person.is_dd:
res.append(NavLink(reverse("mia_wat_ping", kwargs={"key": self.person.lookup_key}), _("WAT ping"))) res.append(NavLink(
reverse("mia_wat_ping", kwargs={"key": self.person.lookup_key}), _("WAT ping"), "heartbeat"))
from process.views import Emeritus from process.views import Emeritus
emeritus_link = Emeritus.get_nonauth_url(self.person, self.request) emeritus_link = Emeritus.get_nonauth_url(self.person, self.request)
if emeritus_link: if emeritus_link:
res.append(NavLink(emeritus_link, _("One click emeritus"))) res.append(NavLink(emeritus_link, _("One click emeritus"), "bed"))
if self.person.is_am: if self.person.is_am:
res.append(NavLink( res.append(NavLink(
reverse("person_amprofile", kwargs={"key": self.person.lookup_key}), _("AM Profile"), "gear")) reverse("person_amprofile", kwargs={"key": self.person.lookup_key}), _("AM Profile"), "gear"))
if "view_person_audit_log" in self.visit_perms:
res.append(NavLink(
reverse("signon_identities_person", kwargs={
"key": self.person.lookup_key}), _("Logins"), "sign-in"))
return res return res
def get_visit_perms(self): def get_visit_perms(self):
......
{% load i18n %}
{% for identity in identities %}
<div class="card mt-4">
<div class="card-header">
{% with identity.get_provider as provider %}
{% if identity.profile %}<a href="{{identity.profile}}">{% endif %}
{% if provider.icon %}
<img style="vertical-align: text-top; height: 1em" class="mr-2" src="{{STATIC_URL}}{{provider.icon}}"></img>
{% else %}
<span class="mr-2 fa fa-sign-in"></span>
{% endif %}
{{provider.label}}:
{{identity.fullname}} &lt;{{identity.username}}&gt;
{% endwith %}
{% if identity.profile %}</a>{% endif %}
</div>
<div class="card-body">
<h5 class="card-title">
{% if identity.picture %}
<img class="personpic ml-auto" src="{{identity.picture}}"></img>
{% endif %}
{% trans "Account information" %}
</h5>
<table class="table table-sm">
<tr><th>{% trans "Last used" %}</th><td>{{identity.last_used|date:"Y-m-d"}}</td></tr>
{% if identity.subject %}
<tr><th>{% trans "Subject" %}</th><td>{{identity.subject}}</td></tr>
{% endif %}
{% if identity.fullname %}
<tr><th>{% trans "Full name" %}</th><td>{{identity.fullname}}</td></tr>
{% endif %}
{% if identity.username %}
<tr><th>{% trans "User name" %}</th><td>{{identity.username}}</td></tr>
{% endif %}
</table>
<h5 class="card-title">{% trans "Audit log" %}</h5>
<table class="table table-sm">
<thead>
<tr>
<th>{% trans "Date" %}</th>
<th>{% trans "Author" %}</th>
<th>{% trans "Notes" %}</th>
<th>{% trans "Changes" %}</th>
</tr>
</thead>
<tbody>
{% for e in identity.audit_log.all %}
<tr>
<td>{{e.logdate|date:"Y-m-d H:i:s"}}</td>
<td><a href="{{e.author.get_absolute_url}}">{{e.author}}</a></td>
<td>{{e.notes}}</td>
<td>
<ul>
{% for field, old, new in e.get_changes_list %}
<li>{{field}}: {{old}} → {{new}}</li>
{% endfor %}
</ul>
</td>
</tr>
{% empty %}
<tr><td colspan="4" class="text-center"><i>{% trans "No audit log for this identity" %}</i></td></tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% endfor %}
{% extends "nm2-base.html" %}
{% load nm %}
{% load i18n %}
{% block content %}
<h1>{{person.fullname}} identities</h1>
{% if identities %}
{% include "signon/audit_identities.html" with identities=identities only %}
{% endif %}
{% endblock %}
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
<h1>nm.debian.org login</h1> <h1>nm.debian.org login</h1>
{% if not impersonator %}
{% if not providers_active and not providers_inactive %} {% if not providers_active and not providers_inactive %}
<p class="lead"> <p class="lead">
{% blocktrans %} {% blocktrans %}
...@@ -23,19 +24,21 @@ ...@@ -23,19 +24,21 @@
{% for provider in providers_active %} {% for provider in providers_active %}
<li class="row"> <li class="row">
<div class="btn btn-info btn-lg disabled col-sm-6"> <div class="btn btn-info btn-lg disabled col-sm-6">
{% with provider.get_active_identity as identity %}
{% if provider.icon %} {% if provider.icon %}
<img style="vertical-align: text-top; height: 1em" class="mr-2" src="{{STATIC_URL}}{{provider.icon}}"></img> <img style="vertical-align: text-top; height: 1em" class="mr-2" src="{{STATIC_URL}}{{provider.icon}}"></img>
{% else %} {% else %}
<span class="mr-2 fa fa-sign-in"></span> <span class="mr-2 fa fa-sign-in"></span>
{% endif %} {% endif %}
{% if provider.profile %} {% if identity.profile %}
<a href="{{provider.profile}}">{{provider.label}}</a> <a href="{{identity.profile}}">{{provider.label}}</a>
{% else %} {% else %}
{{provider.label}} {{provider.label}}
{% endif %} {% endif %}
{% if provider.username %} {% if identity.username %}
({{provider.username}}) ({{identity.username}})
{% endif %} {% endif %}
{% endwith %}
</div> </div>
<div class="btn btn-light btn-lg disabled col-sm-6"> <div class="btn btn-light btn-lg disabled col-sm-6">
{% if provider.get_active_identity %} {% if provider.get_active_identity %}
...@@ -79,54 +82,13 @@ ...@@ -79,54 +82,13 @@
</ul> </ul>
{% endif %} {% endif %}
{% endif %} {% endif %}
{% else %}
<p class="lead">{% trans "Current login information not displayed while impersonating." %}</p>
{% endif %}
{% if identities %} {% if identities %}
<h2>Identity audit logs</h2> <h2>{% trans "Identity audit logs" %}</h2>
{% for identity in identities %} {% include "signon/audit_identities.html" with identities=identities only %}
<div class="card mt-4">
<div class="card-header">
{% with identity.get_provider as provider %}
{% if identity.profile %}<a href="{{identity.profile}}">{% endif %}
{% if provider.icon %}
<img style="vertical-align: text-top; height: 1em" class="mr-2" src="{{STATIC_URL}}{{provider.icon}}"></img>
{% else %}
<span class="mr-2 fa fa-sign-in"></span>
{% endif %}
{{provider.label}}:
{{identity.fullname}} &lt;{{identity.username}}&gt;
{% endwith %}
{% if identity.profile %}</a>{% endif %}
</div>
<table id="audit_log" class="table table-sm card-body mb-0">
<thead>
<tr>
<th>{% trans "Date" %}</th>
<th>{% trans "Author" %}</th>
<th>{% trans "Notes" %}</th>
<th>{% trans "Changes" %}</th>
</tr>
</thead>
<tbody>
{% for e in identity.audit_log.all %}
<tr>
<td>{{e.logdate|date:"Y-m-d H:i:s"}}</td>
<td><a href="{{e.author.get_absolute_url}}">{{e.author}}</a></td>
<td>{{e.notes}}</td>
<td>
<ul>
{% for field, old, new in e.get_changes_list %}
<li>{{field}}: {{old}} → {{new}}</li>
{% endfor %}
</ul>
</td>
</tr>
{% empty %}
<tr><td colspan="4" class="text-center"><i>{% trans "No audit log for this identity" %}</i></td></tr>
{% endfor %}
</tbody>
</table>
</div>
{% endfor %}
{% endif %} {% endif %}
{% endblock %} {% endblock %}
...@@ -3,6 +3,8 @@ from . import views ...@@ -3,6 +3,8 @@ from . import views
urlpatterns = [ urlpatterns = [
path('login/', views.Login.as_view(), name='signon_login'), path('login/', views.Login.as_view(), name='signon_login'),
path('identities/', views.Identities.as_view(), name='signon_identities'),
path('identities/<key>/', views.Identities.as_view(), name='signon_identities_person'),
path('logout/', views.Logout.as_view(), name='signon_logout'), path('logout/', views.Logout.as_view(), name='signon_logout'),
path('oidc/callback/<name>/', views.OIDCAuthenticationCallbackView.as_view(), name='signon_oidc_callback'), path('oidc/callback/<name>/', views.OIDCAuthenticationCallbackView.as_view(), name='signon_oidc_callback'),
] ]
...@@ -4,7 +4,7 @@ from django.views.generic import View, TemplateView ...@@ -4,7 +4,7 @@ from django.views.generic import View, TemplateView
from django import http from django import http
from django.shortcuts import redirect from django.shortcuts import redirect
from django.contrib import auth from django.contrib import auth
from backend.mixins import VisitorMixin from backend.mixins import VisitorMixin, VisitPersonMixin
from backend.models import Person from backend.models import Person
from .models import Identity from .models import Identity
from . import providers from . import providers
...@@ -45,6 +45,16 @@ class Logout(View): ...@@ -45,6 +45,16 @@ class Logout(View):
return redirect("home") return redirect("home")
class Identities(VisitPersonMixin, TemplateView):
template_name = "signon/identities.html"
require_visit_perms = "view_person_audit_log"
def get_context_data(self, **kw):
ctx = super().get_context_data(**kw)
ctx["identities"] = self.person.identities.all()
return ctx
class OIDCAuthenticationCallbackView(View): class OIDCAuthenticationCallbackView(View):
def get(self, request, *args, **kw): def get(self, request, *args, **kw):
name = self.kwargs["name"] name = self.kwargs["name"]
......
Supports Markdown
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