forked from Github-Mirrors/canaille
Implements admin token deletion
This commit is contained in:
parent
3ac7a8013f
commit
3359b51d9b
4 changed files with 126 additions and 39 deletions
|
@ -1,9 +1,15 @@
|
||||||
|
import datetime
|
||||||
|
|
||||||
from canaille.flaskutils import permissions_needed
|
from canaille.flaskutils import permissions_needed
|
||||||
from canaille.models import User
|
from canaille.models import User
|
||||||
from canaille.oidc.models import Client
|
from canaille.oidc.models import Client
|
||||||
from canaille.oidc.models import Token
|
from canaille.oidc.models import Token
|
||||||
from flask import abort
|
from flask import abort
|
||||||
from flask import Blueprint
|
from flask import Blueprint
|
||||||
|
from flask import flash
|
||||||
|
from flask import redirect
|
||||||
|
from flask import url_for
|
||||||
|
from flask_babel import gettext as _
|
||||||
from flask_themer import render_template
|
from flask_themer import render_template
|
||||||
|
|
||||||
|
|
||||||
|
@ -40,3 +46,18 @@ def view(user, token_id):
|
||||||
token_audience=token_audience,
|
token_audience=token_audience,
|
||||||
menuitem="admin",
|
menuitem="admin",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@bp.route("/<token_id>/revoke", methods=["GET", "POST"])
|
||||||
|
@permissions_needed("manage_oidc")
|
||||||
|
def revoke(user, token_id):
|
||||||
|
token = Token.get(token_id=token_id)
|
||||||
|
|
||||||
|
if not token:
|
||||||
|
abort(404)
|
||||||
|
|
||||||
|
token.revokation_date = datetime.datetime.now()
|
||||||
|
token.save()
|
||||||
|
flash(_("The token has successfully been revoked."), "success")
|
||||||
|
|
||||||
|
return redirect(url_for("oidc.tokens.view", token_id=token_id))
|
||||||
|
|
|
@ -2,13 +2,30 @@
|
||||||
{% import 'fomanticui.html' as sui %}
|
{% import 'fomanticui.html' as sui %}
|
||||||
|
|
||||||
{% block script %}
|
{% block script %}
|
||||||
|
<script src="/static/js/confirm.js"></script>
|
||||||
<script src="/static/js/copy.js"></script>
|
<script src="/static/js/copy.js"></script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
|
<div id="modal-delete" class="ui basic modal">
|
||||||
|
<div class="ui icon header">
|
||||||
|
<i class="trash icon"></i>
|
||||||
|
{% trans %}Token deletion{% endtrans %}
|
||||||
|
</div>
|
||||||
|
<div class="content">
|
||||||
|
<p>
|
||||||
|
{{ _("Are you sure you want to revoke this token? This action is unrevokable.") }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="actions">
|
||||||
|
<div class="ui inverted cancel button">{% trans %}Cancel{% endtrans %}</div>
|
||||||
|
<div class="ui inverted red approve button">{% trans %}Delete{% endtrans %}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="loginform">
|
<div class="loginform">
|
||||||
<h3 class="ui top attached header">
|
<h3 class="ui top attached header">
|
||||||
{% trans %}View a token{% endtrans %}
|
{% trans %}Token details{% endtrans %}
|
||||||
</h3>
|
</h3>
|
||||||
|
|
||||||
<div class="ui attached clearing segment">
|
<div class="ui attached clearing segment">
|
||||||
|
@ -59,7 +76,18 @@
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ _("Revokation date") }}</td>
|
<td>{{ _("Revokation date") }}</td>
|
||||||
<td>{% if token.revokation_date %}{{ token.revokation_date }}{% endif %}</td>
|
<td>
|
||||||
|
{% if token.revokation_date %}
|
||||||
|
{{ token.revokation_date }}
|
||||||
|
{% else %}
|
||||||
|
<a href="{{ url_for("oidc.tokens.revoke", token_id=token.token_id) }}" class="ui negative right floated button confirm" name="action" value="delete" id="delete">
|
||||||
|
{% trans %}Revoke token{% endtrans %}
|
||||||
|
</a>
|
||||||
|
<p>
|
||||||
|
{% trans %}This token has not been revoked{% endtrans %}
|
||||||
|
</p>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>{{ _("Lifetime") }}</td>
|
<td>{{ _("Lifetime") }}</td>
|
||||||
|
|
|
@ -8,7 +8,7 @@ msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PROJECT VERSION\n"
|
"Project-Id-Version: PROJECT VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||||
"POT-Creation-Date: 2023-01-22 13:42+0100\n"
|
"POT-Creation-Date: 2023-02-04 18:36+0100\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
|
@ -18,7 +18,7 @@ msgstr ""
|
||||||
"Generated-By: Babel 2.11.0\n"
|
"Generated-By: Babel 2.11.0\n"
|
||||||
|
|
||||||
#: canaille/account.py:103 canaille/account.py:128
|
#: canaille/account.py:103 canaille/account.py:128
|
||||||
#: canaille/oidc/endpoints.py:81
|
#: canaille/oidc/endpoints.py:82
|
||||||
msgid "Login failed, please check your information"
|
msgid "Login failed, please check your information"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@ msgid ""
|
||||||
"should receive it within a few minutes."
|
"should receive it within a few minutes."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/account.py:176 canaille/account.py:426
|
#: canaille/account.py:176 canaille/account.py:423
|
||||||
msgid "Could not send the password initialization email"
|
msgid "Could not send the password initialization email"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -76,65 +76,65 @@ msgstr ""
|
||||||
msgid "You account has been created successfuly."
|
msgid "You account has been created successfuly."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/account.py:393
|
#: canaille/account.py:390
|
||||||
msgid "User account creation succeed."
|
msgid "User account creation succeed."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/account.py:420
|
#: canaille/account.py:417
|
||||||
msgid ""
|
msgid ""
|
||||||
"A password initialization link has been sent at the user email address. "
|
"A password initialization link has been sent at the user email address. "
|
||||||
"It should be received within a few minutes."
|
"It should be received within a few minutes."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/account.py:437
|
#: canaille/account.py:434
|
||||||
msgid ""
|
msgid ""
|
||||||
"A password reset link has been sent at the user email address. It should "
|
"A password reset link has been sent at the user email address. It should "
|
||||||
"be received within a few minutes."
|
"be received within a few minutes."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/account.py:443
|
#: canaille/account.py:440
|
||||||
msgid "Could not send the password reset email"
|
msgid "Could not send the password reset email"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/account.py:477
|
#: canaille/account.py:474
|
||||||
msgid "Profile edition failed."
|
msgid "Profile edition failed."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/account.py:513
|
#: canaille/account.py:508
|
||||||
msgid "Profile updated successfuly."
|
msgid "Profile updated successfuly."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/account.py:536
|
#: canaille/account.py:531
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "The user %(user)s has been sucessfuly deleted"
|
msgid "The user %(user)s has been sucessfuly deleted"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/account.py:566
|
#: canaille/account.py:561
|
||||||
msgid "Could not send the password reset link."
|
msgid "Could not send the password reset link."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/account.py:570
|
#: canaille/account.py:565
|
||||||
msgid ""
|
msgid ""
|
||||||
"A password reset link has been sent at your email address. You should "
|
"A password reset link has been sent at your email address. You should "
|
||||||
"receive it within a few minutes."
|
"receive it within a few minutes."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/account.py:581
|
#: canaille/account.py:576
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"The user '%(user)s' does not have permissions to update their password. "
|
"The user '%(user)s' does not have permissions to update their password. "
|
||||||
"We cannot send a password reset email."
|
"We cannot send a password reset email."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/account.py:596
|
#: canaille/account.py:591
|
||||||
msgid "We encountered an issue while we sent the password recovery email."
|
msgid "We encountered an issue while we sent the password recovery email."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/account.py:615
|
#: canaille/account.py:610
|
||||||
msgid "The password reset link that brought you here was invalid."
|
msgid "The password reset link that brought you here was invalid."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/account.py:624
|
#: canaille/account.py:619
|
||||||
msgid "Your password has been updated successfuly"
|
msgid "Your password has been updated successfuly"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -396,19 +396,19 @@ msgstr ""
|
||||||
msgid "The access has been revoked"
|
msgid "The access has been revoked"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/oidc/endpoints.py:129
|
#: canaille/oidc/endpoints.py:130
|
||||||
msgid "You have been successfully logged out."
|
msgid "You have been successfully logged out."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/oidc/endpoints.py:327
|
#: canaille/oidc/endpoints.py:329
|
||||||
msgid "You have been disconnected"
|
msgid "You have been disconnected"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/oidc/endpoints.py:335
|
#: canaille/oidc/endpoints.py:337
|
||||||
msgid "An error happened during the logout"
|
msgid "An error happened during the logout"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/oidc/endpoints.py:347
|
#: canaille/oidc/endpoints.py:349
|
||||||
msgid "You have not been disconnected"
|
msgid "You have not been disconnected"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -432,7 +432,7 @@ msgstr ""
|
||||||
msgid "Grant types"
|
msgid "Grant types"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/oidc/forms.py:54 canaille/templates/oidc/admin/token_view.html:33
|
#: canaille/oidc/forms.py:54 canaille/templates/oidc/admin/token_view.html:54
|
||||||
msgid "Scope"
|
msgid "Scope"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -480,12 +480,16 @@ msgstr ""
|
||||||
msgid "Pre-consent"
|
msgid "Pre-consent"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: canaille/oidc/tokens.py:61
|
||||||
|
msgid "The token has successfully been revoked."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/oidc/utils.py:6
|
#: canaille/oidc/utils.py:6
|
||||||
msgid "Personnal information about yourself, such as your name or your gender."
|
msgid "Info about yourself, such as your name."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/oidc/utils.py:8
|
#: canaille/oidc/utils.py:8
|
||||||
msgid "Your email address."
|
msgid "Your e-mail address."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/oidc/utils.py:9
|
#: canaille/oidc/utils.py:9
|
||||||
|
@ -497,11 +501,11 @@ msgid "Your phone number."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/oidc/utils.py:11
|
#: canaille/oidc/utils.py:11
|
||||||
msgid "Groups you are belonging to"
|
msgid "Groups you belong to."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/about.html:12 canaille/themes/default/base.html:106
|
#: canaille/templates/about.html:12 canaille/themes/default/base.html:106
|
||||||
msgid "About canaille"
|
msgid "About Canaille"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/about.html:14
|
#: canaille/templates/about.html:14
|
||||||
|
@ -623,12 +627,14 @@ msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/group.html:30
|
#: canaille/templates/group.html:30
|
||||||
#: canaille/templates/oidc/admin/client_edit.html:18
|
#: canaille/templates/oidc/admin/client_edit.html:18
|
||||||
|
#: canaille/templates/oidc/admin/token_view.html:21
|
||||||
#: canaille/templates/profile.html:41
|
#: canaille/templates/profile.html:41
|
||||||
msgid "Cancel"
|
msgid "Cancel"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/group.html:31
|
#: canaille/templates/group.html:31
|
||||||
#: canaille/templates/oidc/admin/client_edit.html:19
|
#: canaille/templates/oidc/admin/client_edit.html:19
|
||||||
|
#: canaille/templates/oidc/admin/token_view.html:22
|
||||||
#: canaille/templates/profile.html:42
|
#: canaille/templates/profile.html:42
|
||||||
msgid "Delete"
|
msgid "Delete"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -723,6 +729,8 @@ msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/invite.html:58
|
#: canaille/templates/invite.html:58
|
||||||
|
#: canaille/templates/oidc/admin/token_view.html:104
|
||||||
|
#: canaille/templates/oidc/admin/token_view.html:114
|
||||||
msgid "Copy"
|
msgid "Copy"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -1039,13 +1047,13 @@ msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/oidc/admin/authorization_list.html:19
|
#: canaille/templates/oidc/admin/authorization_list.html:19
|
||||||
#: canaille/templates/oidc/admin/token_list.html:19
|
#: canaille/templates/oidc/admin/token_list.html:19
|
||||||
#: canaille/templates/oidc/admin/token_view.html:17
|
#: canaille/templates/oidc/admin/token_view.html:38
|
||||||
msgid "Client"
|
msgid "Client"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/oidc/admin/authorization_list.html:20
|
#: canaille/templates/oidc/admin/authorization_list.html:20
|
||||||
#: canaille/templates/oidc/admin/token_list.html:20
|
#: canaille/templates/oidc/admin/token_list.html:20
|
||||||
#: canaille/templates/oidc/admin/token_view.html:25
|
#: canaille/templates/oidc/admin/token_view.html:46
|
||||||
msgid "Subject"
|
msgid "Subject"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -1113,35 +1121,51 @@ msgstr ""
|
||||||
msgid "Token"
|
msgid "Token"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/oidc/admin/token_view.html:7
|
#: canaille/templates/oidc/admin/token_view.html:13
|
||||||
msgid "View a token"
|
msgid "Token deletion"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/oidc/admin/token_view.html:13
|
#: canaille/templates/oidc/admin/token_view.html:17
|
||||||
|
msgid "Are you sure you want to revoke this token? This action is unrevokable."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: canaille/templates/oidc/admin/token_view.html:28
|
||||||
|
msgid "Token details"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: canaille/templates/oidc/admin/token_view.html:34
|
||||||
msgid "Issue date"
|
msgid "Issue date"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/oidc/admin/token_view.html:43
|
#: canaille/templates/oidc/admin/token_view.html:64
|
||||||
msgid "Audience"
|
msgid "Audience"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/oidc/admin/token_view.html:57
|
#: canaille/templates/oidc/admin/token_view.html:78
|
||||||
msgid "Revokation date"
|
msgid "Revokation date"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/oidc/admin/token_view.html:61
|
#: canaille/templates/oidc/admin/token_view.html:84
|
||||||
|
msgid "Revoke token"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: canaille/templates/oidc/admin/token_view.html:86
|
||||||
|
msgid "This token has not been revoked"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: canaille/templates/oidc/admin/token_view.html:91
|
||||||
msgid "Lifetime"
|
msgid "Lifetime"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/oidc/admin/token_view.html:65
|
#: canaille/templates/oidc/admin/token_view.html:95
|
||||||
msgid "Token type"
|
msgid "Token type"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/oidc/admin/token_view.html:69
|
#: canaille/templates/oidc/admin/token_view.html:99
|
||||||
msgid "Access token"
|
msgid "Access token"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/oidc/admin/token_view.html:74
|
#: canaille/templates/oidc/admin/token_view.html:109
|
||||||
msgid "Refresh token"
|
msgid "Refresh token"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -1152,7 +1176,7 @@ msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/oidc/user/authorize.html:32
|
#: canaille/templates/oidc/user/authorize.html:32
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "You are logged id as: %(name)s"
|
msgid "You are logged in as %(name)s"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: canaille/templates/oidc/user/authorize.html:39
|
#: canaille/templates/oidc/user/authorize.html:39
|
||||||
|
|
|
@ -18,3 +18,17 @@ def test_token_view(testclient, token, logged_admin):
|
||||||
|
|
||||||
def test_token_not_found(testclient, logged_admin):
|
def test_token_not_found(testclient, logged_admin):
|
||||||
res = testclient.get("/admin/token/" + "yolo", status=404)
|
res = testclient.get("/admin/token/" + "yolo", status=404)
|
||||||
|
|
||||||
|
|
||||||
|
def test_revoke_token(testclient, token, logged_admin):
|
||||||
|
assert not token.revoked
|
||||||
|
|
||||||
|
res = testclient.get(f"/admin/token/{token.token_id}/revoke")
|
||||||
|
assert ("success", "The token has successfully been revoked.") in res.flashes
|
||||||
|
|
||||||
|
token.reload()
|
||||||
|
assert token.revoked
|
||||||
|
|
||||||
|
|
||||||
|
def test_revoke_invalid_token(testclient, logged_admin):
|
||||||
|
testclient.get(f"/admin/token/invalid/revoke", status=404)
|
||||||
|
|
Loading…
Reference in a new issue