From 9b2620751539e9613bc7835fdf70c5d517a81807 Mon Sep 17 00:00:00 2001
From: Yohann D'ANELLO <ynerant@crans.org>
Date: Thu, 17 Jun 2021 20:56:59 +0200
Subject: [PATCH] Rework templates for OAuth2

Signed-off-by: Yohann D'ANELLO <ynerant@crans.org>
---
 .../templates/member/manage_auth_tokens.html  | 112 ++++++++++++++----
 .../templates/permission/scopes.html          |   8 +-
 apps/permission/views.py                      |   2 +-
 locale/fr/LC_MESSAGES/django.po               |  73 ++++++++++--
 .../oauth2_provider/application_detail.html   |  10 +-
 .../oauth2_provider/application_list.html     |   7 ++
 .../templates/oauth2_provider/authorize.html  |  10 +-
 7 files changed, 183 insertions(+), 39 deletions(-)

diff --git a/apps/member/templates/member/manage_auth_tokens.html b/apps/member/templates/member/manage_auth_tokens.html
index 014686f1..0f6a64ec 100644
--- a/apps/member/templates/member/manage_auth_tokens.html
+++ b/apps/member/templates/member/manage_auth_tokens.html
@@ -5,32 +5,98 @@ SPDX-License-Identifier: GPL-3.0-or-later
 {% load i18n %}
 
 {% block content %}
-<div class="alert alert-info">
-    <h4>À quoi sert un jeton d'authentification ?</h4>
+<div class="row mt-4">
+    <div class="col-xl-6">
+        <div class="card">
+            <div class="card-header text-center">
+                <h3>{% trans "Token authentication" %}</h3>
+            </div>
+            <div class="card-body">
+                <div class="alert alert-info">
+                    <h4>À quoi sert un jeton d'authentification ?</h4>
 
-    Un jeton vous permet de vous connecter à <a href="/api/">l'API de la Note Kfet</a>.<br />
-    Il suffit pour cela d'ajouter en en-tête de vos requêtes <code>Authorization: Token &lt;TOKEN&gt;</code>
-    pour pouvoir vous identifier.<br /><br />
+                    Un jeton vous permet de vous connecter à <a href="/api/">l'API de la Note Kfet</a> via votre propre compte
+                    depuis un client externe.<br />
+                    Il suffit pour cela d'ajouter en en-tête de vos requêtes <code>Authorization: Token &lt;TOKEN&gt;</code>
+                    pour pouvoir vous identifier.<br /><br />
 
-    Une documentation de l'API arrivera ultérieurement.
-</div>
+                    La documentation de l'API est disponible ici :
+                    <a href="/doc/api/">{{ request.scheme }}://{{ request.get_host }}/doc/api/</a>.
+                </div>
 
-<div class="alert alert-info">
-    <strong>{%trans  'Token' %} :</strong>
-    {% if 'show' in request.GET %}
-    {{ token.key }} (<a href="?">cacher</a>)
-    {% else %}
-    <em>caché</em> (<a href="?show">montrer</a>)
-    {% endif %}
-    <br />
-    <strong>{%trans  'Created' %} :</strong> {{ token.created }}
-</div>
+                <div class="alert alert-info">
+                    <strong>{%trans  'Token' %} :</strong>
+                    {% if 'show' in request.GET %}
+                    {{ token.key }} (<a href="?">cacher</a>)
+                    {% else %}
+                    <em>caché</em> (<a href="?show">montrer</a>)
+                    {% endif %}
+                    <br />
+                    <strong>{%trans  'Created' %} :</strong> {{ token.created }}
+                </div>
 
-<div class="alert alert-warning">
-    <strong>Attention :</strong> regénérer le jeton va révoquer tout accès autorisé à l'API via ce jeton !
-</div>
+                <div class="alert alert-warning">
+                    <strong>{% trans "Warning" %} :</strong> regénérer le jeton va révoquer tout accès autorisé à l'API via ce jeton !
+                </div>
+            </div>
+            <div class="card-footer text-center">
+                <a href="?regenerate">
+                    <button class="btn btn-primary">{% trans 'Regenerate token' %}</button>
+                </a>
+            </div>
+        </div>
+    </div>
+
+    <div class="col-xl-6">
+        <div class="card">
+            <div class="card-header text-center">
+                <h3>{% trans "OAuth2 authentication" %}</h3>
+            </div>
+            <div class="card-header">
+                <div class="alert alert-info">
+                    <p>
+                        La Note Kfet implémente également le protocole <a href="https://oauth.net/2/">OAuth2</a>, afin de
+                        permettre à des applications tierces d'interagir avec la Note en récoltant des informations
+                        (de connexion par exemple) voir en permettant des modifications à distance, par exemple lorsqu'il
+                        s'agit d'avoir un site marchand sur lequel faire des transactions via la Note Kfet.
+                    </p>
 
-<a href="?regenerate">
-    <button class="btn btn-primary">{% trans 'Regenerate token' %}</button>
-</a>
+                    <p>
+                        L'usage de ce protocole est recommandé pour tout usage non personnel, car permet de mieux cibler
+                        les droits dont on a besoin, en restreignant leur usage par jeton généré.
+                    </p>
+
+                    <p>
+                        La documentation vis-à-vis de l'usage de ce protocole est disponible ici :
+                        <a href="/doc/external_services/oauth2/">{{ request.scheme }}://{{ request.get_host }}/doc/external_services/oauth2/</a>.
+                    </p>
+                </div>
+
+                Liste des URL à communiquer à votre application :
+
+                <ul>
+                    <li>
+                        {% trans "Authorization:" %}
+                        <a href="{% url 'oauth2_provider:authorize' %}">{{ request.scheme }}://{{ request.get_host }}{% url 'oauth2_provider:authorize' %}</a>
+                    </li>
+                    <li>
+                        {% trans "Token:" %}
+                        <a href="{% url 'oauth2_provider:authorize' %}">{{ request.scheme }}://{{ request.get_host }}{% url 'oauth2_provider:token' %}</a>
+                    </li>
+                    <li>
+                        {% trans "Revoke Token:" %}
+                        <a href="{% url 'oauth2_provider:authorize' %}">{{ request.scheme }}://{{ request.get_host }}{% url 'oauth2_provider:revoke-token' %}</a>
+                    </li>
+                    <li>
+                        {% trans "Introspect Token:" %}
+                        <a href="{% url 'oauth2_provider:authorize' %}">{{ request.scheme }}://{{ request.get_host }}{% url 'oauth2_provider:introspect' %}</a>
+                    </li>
+                </ul>
+            </div>
+            <div class="card-footer text-center">
+                <a class="btn btn-primary" href="{% url 'oauth2_provider:list' %}">{% trans "Show my applications" %}</a>
+            </div>
+        </div>
+    </div>
+</div>
 {% endblock %}
\ No newline at end of file
diff --git a/apps/permission/templates/permission/scopes.html b/apps/permission/templates/permission/scopes.html
index 26a5feda..31a4395e 100644
--- a/apps/permission/templates/permission/scopes.html
+++ b/apps/permission/templates/permission/scopes.html
@@ -57,16 +57,16 @@
                     let scope = ""
                     for (let element of elements) {
                         if (element.checked) {
-                            scope += element.value + "%20"
+                            scope += element.value + " "
                         }
                     }
 
-                    scope = scope.substr(0, scope.length - 3)
+                    scope = scope.substr(0, scope.length - 1)
 
                     document.getElementById("url-{{ app.name.lower }}").innerHTML = 'Scopes : ' + scope
-                        + '<br><a href="{% url 'oauth2_provider:authorize' %}?client_id={{ app.client_id }}&response_type=code&scope='+ scope
+                        + '<br><a href="{% url 'oauth2_provider:authorize' %}?client_id={{ app.client_id }}&response_type=code&scope='+ scope.replaceAll(' ', '%20')
                         + '" target="_blank">{{ request.scheme }}://{{ request.get_host }}{% url 'oauth2_provider:authorize' %}?client_id={{ app.client_id }}&response_type=code&scope='
-                        + scope + '</a>'
+                        + scope.replaceAll(' ', '%20') + '</a>'
                 }
             }
         {% endfor %}
diff --git a/apps/permission/views.py b/apps/permission/views.py
index 9bee5295..8f498478 100644
--- a/apps/permission/views.py
+++ b/apps/permission/views.py
@@ -157,7 +157,7 @@ class ScopesView(LoginRequiredMixin, TemplateView):
         scopes = PermissionScopes()
         context["scopes"] = {}
         all_scopes = scopes.get_all_scopes()
-        for app in Application.objects.filter(Q(user=self.request.user) | Q(client_type='public')).all():
+        for app in Application.objects.filter(user=self.request.user).all():
             available_scopes = scopes.get_available_scopes(app)
             context["scopes"][app] = OrderedDict()
             items = [(k, v) for (k, v) in all_scopes.items() if k in available_scopes]
diff --git a/locale/fr/LC_MESSAGES/django.po b/locale/fr/LC_MESSAGES/django.po
index 3a6f2d3a..241b9853 100644
--- a/locale/fr/LC_MESSAGES/django.po
+++ b/locale/fr/LC_MESSAGES/django.po
@@ -1053,18 +1053,50 @@ msgstr "Changer le mot de passe"
 msgid "API token"
 msgstr "Accès API"
 
-#: apps/member/templates/member/manage_auth_tokens.html:19
+#: apps/member/templates/member/manage_auth_tokens.html:12
+msgid "Token authentication"
+msgstr "Authentification par jeton"
+
+#: apps/member/templates/member/manage_auth_tokens.html:28
 msgid "Token"
 msgstr "Jeton"
 
-#: apps/member/templates/member/manage_auth_tokens.html:26
+#: apps/member/templates/member/manage_auth_tokens.html:35
 msgid "Created"
 msgstr "Créé le"
 
-#: apps/member/templates/member/manage_auth_tokens.html:34
+#: apps/member/templates/member/manage_auth_tokens.html:39
+msgid "Warning"
+msgstr "Attention"
+
+#: apps/member/templates/member/manage_auth_tokens.html:44
 msgid "Regenerate token"
 msgstr "Regénérer le jeton"
 
+#: apps/member/templates/member/manage_auth_tokens.html:53
+msgid "OAuth2 authentication"
+msgstr "Authentification OAuth2"
+
+#: apps/member/templates/member/manage_auth_tokens.html:79
+msgid "Authorization:"
+msgstr "Autorisation :"
+
+#: apps/member/templates/member/manage_auth_tokens.html:83
+msgid "Token:"
+msgstr "Jeton :"
+
+#: apps/member/templates/member/manage_auth_tokens.html:87
+msgid "Revoke Token:"
+msgstr "Révoquer le jeton :"
+
+#: apps/member/templates/member/manage_auth_tokens.html:91
+msgid "Introspect Token:"
+msgstr "Introspection :"
+
+#: apps/member/templates/member/manage_auth_tokens.html:97
+msgid "Show my applications"
+msgstr "Voir mes applications"
+
 #: apps/member/templates/member/picture_update.html:35
 msgid "Nevermind"
 msgstr "Annuler"
@@ -1482,7 +1514,7 @@ msgstr "Pas de motif spécifié"
 #: apps/wei/tables.py:74 apps/wei/tables.py:114
 #: apps/wei/templates/wei/weiregistration_confirm_delete.html:31
 #: note_kfet/templates/oauth2_provider/application_confirm_delete.html:18
-#: note_kfet/templates/oauth2_provider/application_detail.html:31
+#: note_kfet/templates/oauth2_provider/application_detail.html:39
 #: note_kfet/templates/oauth2_provider/authorized-token-delete.html:12
 msgid "Delete"
 msgstr "Supprimer"
@@ -1493,7 +1525,7 @@ msgstr "Supprimer"
 #: apps/wei/templates/wei/bus_detail.html:20
 #: apps/wei/templates/wei/busteam_detail.html:20
 #: apps/wei/templates/wei/busteam_detail.html:40
-#: note_kfet/templates/oauth2_provider/application_detail.html:30
+#: note_kfet/templates/oauth2_provider/application_detail.html:38
 msgid "Edit"
 msgstr "Éditer"
 
@@ -1808,17 +1840,17 @@ msgid "Available scopes"
 msgstr "Scopes disponibles"
 
 #: apps/permission/templates/permission/scopes.html:42
-#: note_kfet/templates/oauth2_provider/application_list.html:18
+#: note_kfet/templates/oauth2_provider/application_list.html:24
 msgid "No applications defined"
 msgstr "Pas d'application définie"
 
 #: apps/permission/templates/permission/scopes.html:43
-#: note_kfet/templates/oauth2_provider/application_list.html:19
+#: note_kfet/templates/oauth2_provider/application_list.html:25
 msgid "Click here"
 msgstr "Cliquez ici"
 
 #: apps/permission/templates/permission/scopes.html:43
-#: note_kfet/templates/oauth2_provider/application_list.html:19
+#: note_kfet/templates/oauth2_provider/application_list.html:25
 msgid "if you want to register a new one"
 msgstr "si vous voulez en enregistrer une nouvelle"
 
@@ -3180,6 +3212,17 @@ msgid "Redirect Uris"
 msgstr "URIs de redirection"
 
 #: note_kfet/templates/oauth2_provider/application_detail.html:29
+#, python-format
+msgid ""
+"You can go <a href=\"%(scopes_url)s\">here</a> to generate authorization "
+"link templates and convert permissions to scope numbers with the permissions "
+"that you want to grant for your application."
+msgstr ""
+"Vous pouvez aller <a href=\"%(scopes_url)s\"ici</a> pour générer des modèles "
+"de liens d'autorisation et convertir des permissions en identifiants de "
+"scopes avec les permissions que vous souhaitez attribuer à votre application."
+
+#: note_kfet/templates/oauth2_provider/application_detail.html:37
 #: note_kfet/templates/oauth2_provider/application_form.html:23
 msgid "Go Back"
 msgstr "Retour en arrière"
@@ -3192,10 +3235,22 @@ msgstr "Modifier l'application"
 msgid "Your applications"
 msgstr "Vos applications"
 
-#: note_kfet/templates/oauth2_provider/application_list.html:24
+#: note_kfet/templates/oauth2_provider/application_list.html:11
+msgid ""
+"You can find on this page the list of the applications that you already "
+"registered."
+msgstr ""
+"Vous pouvez trouver sur cette page la liste des applications que vous avez "
+"déjà enregistrées."
+
+#: note_kfet/templates/oauth2_provider/application_list.html:30
 msgid "New Application"
 msgstr "Nouvelle application"
 
+#: note_kfet/templates/oauth2_provider/application_list.html:31
+msgid "Authorized Tokens"
+msgstr "Jetons autorisés"
+
 #: note_kfet/templates/oauth2_provider/application_registration_form.html:5
 msgid "Register a new application"
 msgstr "Enregistrer une nouvelle application"
diff --git a/note_kfet/templates/oauth2_provider/application_detail.html b/note_kfet/templates/oauth2_provider/application_detail.html
index 183ac9b8..5d3cc008 100644
--- a/note_kfet/templates/oauth2_provider/application_detail.html
+++ b/note_kfet/templates/oauth2_provider/application_detail.html
@@ -12,7 +12,7 @@
                 <dd class="col-xl-6"><input class="form-control" type="text" value="{{ application.client_id }}" readonly></dd>
 
                 <dt class="col-xl-6">{% trans "Client secret" %}</dt>
-                <dd class="col-xl-6"><input class="form-control" type="text" value="{{ application.client_secret }}" readonly></dd>
+                <dd class="col-xl-6"><input class="form-control" type="text" value="****************************************************************" readonly></dd>
 
                 <dt class="col-xl-6">{% trans "Client type" %}</dt>
                 <dd class="col-xl-6">{{ application.client_type }}</dd>
@@ -24,6 +24,14 @@
                 <dd class="col-xl-6"><textarea class="form-control" readonly>{{ application.redirect_uris }}</textarea></dd>
             </dl>
 
+            <div class="alert alert-info">
+                {% url 'permission:scopes' as scopes_url %}
+                {% blocktrans trimmed %}
+                    You can go <a href="{{ scopes_url }}">here</a> to generate authorization link templates and convert
+                    permissions to scope numbers with the permissions that you want to grant for your application.
+                {% endblocktrans %}
+            </div>
+
         </div>
         <div class="card-footer text-center">
             <a class="btn btn-secondary" href="{% url "oauth2_provider:list" %}">{% trans "Go Back" %}</a>
diff --git a/note_kfet/templates/oauth2_provider/application_list.html b/note_kfet/templates/oauth2_provider/application_list.html
index 1c17879c..0238b345 100644
--- a/note_kfet/templates/oauth2_provider/application_list.html
+++ b/note_kfet/templates/oauth2_provider/application_list.html
@@ -7,6 +7,12 @@
             <h3>{% trans "Your applications" %}</h3>
         </div>
         <div class="card-body">
+            <div class="alert alert-info">
+                {% blocktrans trimmed %}
+                    You can find on this page the list of the applications that you already registered.
+                {% endblocktrans %}
+            </div>
+
             {% if applications %}
                 <ul>
                     {% for application in applications %}
@@ -22,6 +28,7 @@
         </div>
         <div class="card-footer text-center">
             <a class="btn btn-success" href="{% url "oauth2_provider:register" %}">{% trans "New Application" %}</a>
+            <a class="btn btn-secondary" href="{% url "oauth2_provider:authorized-token-list" %}">{% trans "Authorized Tokens" %}</a>
         </div>
     </div>
 {% endblock content %}
diff --git a/note_kfet/templates/oauth2_provider/authorize.html b/note_kfet/templates/oauth2_provider/authorize.html
index 16c9f3b6..b6cbb836 100644
--- a/note_kfet/templates/oauth2_provider/authorize.html
+++ b/note_kfet/templates/oauth2_provider/authorize.html
@@ -38,4 +38,12 @@
             </div>
         {% endif %}
     </div>
-{% endblock %}
\ No newline at end of file
+{% endblock %}
+
+{% block extrajavascript %}
+    <script>
+        {# Small hack to have the remove the allow checkbox and replace it with the button #}
+        {# Django oauth toolkit does simply not render the wdiget since it is not hidden, and create directly the button #}
+        document.getElementById('div_id_allow').parentElement.remove()
+    </script>
+{% endblock %}
-- 
GitLab