aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFrederick Muriuki Muriithi2024-07-19 10:23:28 -0500
committerFrederick Muriuki Muriithi2024-07-31 09:30:24 -0500
commit6b18e1f0b05222d84fd0b06a8e5c2780df6958d5 (patch)
tree4806d860eaf68e2624b70b1f08dbba3eaf91c0f4
parentc56dc39193909062d25e3270d9ab0ec3467a47ee (diff)
downloadgn-auth-6b18e1f0b05222d84fd0b06a8e5c2780df6958d5.tar.gz
Enable registration of a public-jwks-uri for every client
-rw-r--r--gn_auth/auth/authorisation/users/admin/views.py113
-rw-r--r--gn_auth/templates/admin/register-client.html10
-rw-r--r--gn_auth/templates/admin/view-oauth2-client.html70
3 files changed, 29 insertions, 164 deletions
diff --git a/gn_auth/auth/authorisation/users/admin/views.py b/gn_auth/auth/authorisation/users/admin/views.py
index 0ab69e9..85aeb50 100644
--- a/gn_auth/auth/authorisation/users/admin/views.py
+++ b/gn_auth/auth/authorisation/users/admin/views.py
@@ -3,14 +3,12 @@ import uuid
import json
import random
import string
-from pathlib import Path
from typing import Optional
from functools import partial
from dataclasses import asdict
from urllib.parse import urlparse
from datetime import datetime, timezone, timedelta
-from authlib.jose import KeySet, JsonWebKey
from email_validator import validate_email, EmailNotValidError
from flask import (
flash,
@@ -178,6 +176,9 @@ def check_register_client_form(form):
"scope[]",
"You need to select at least one scope option."),)
+ if not uri_valid(form.get("client_jwk_uri", "")):
+ errors = errors + ("The provided client's public JWKs URI is invalid.",)
+
errors = tuple(item for item in errors if item is not None)
if bool(errors):
raise RegisterClientError(errors)
@@ -225,7 +226,8 @@ def register_client():
"default_redirect_uri": default_redirect_uri,
"redirect_uris": [default_redirect_uri] + form.get("other_redirect_uri", "").split(),
"response_type": __response_types__(tuple(grant_types)),
- "scope": form.getlist("scope[]")
+ "scope": form.getlist("scope[]"),
+ "public-jwks-uri": form.get("client_jwk_uri", "")
},
user = with_db_connection(partial(
user_by_id, user_id=uuid.UUID(form["user"])))
@@ -262,108 +264,6 @@ def view_client(client_id: uuid.UUID):
scope=app.config["OAUTH2_SCOPE"],
granttypes=_FORM_GRANT_TYPES_)
-@admin.route("/register-client-public-key", methods=["POST"])
-@is_admin
-def register_client_public_key():
- """Register a client's SSL key"""
- form = request.form
- admin_dashboard_uri = redirect(url_for("oauth2.admin.dashboard"))
- view_client_uri = redirect(url_for("oauth2.admin.view_client",
- client_id=form["client_id"]))
- if not bool(form.get("client_id")):
- flash("No client selected.", "alert-danger")
- return admin_dashboard_uri
-
- try:
- _client = with_db_connection(partial(
- oauth2_client, client_id=uuid.UUID(form["client_id"])))
- if _client.is_nothing():
- raise ValueError("No such client.")
- _client = _client.value
- except ValueError:
- flash("Invalid client ID provided.", "alert-danger")
- return admin_dashboard_uri
- try:
- _key = JsonWebKey.import_key(form["client_ssl_key"].strip())
- except ValueError:
- flash("Invalid key provided!", "alert-danger")
- return view_client_uri
-
- keypath = Path(app.config["CLIENTS_SSL_PUBLIC_KEYS_DIR"]).joinpath(
- f"{_key.thumbprint()}.pem")
- if not keypath.exists():
- with open(keypath, mode="w", encoding="utf8") as _kpth:
- _kpth.write(form["client_ssl_key"])
-
- with_db_connection(partial(save_client, the_client=OAuth2Client(
- client_id=_client.client_id,
- client_secret=_client.client_secret,
- client_id_issued_at=_client.client_id_issued_at,
- client_secret_expires_at=_client.client_secret_expires_at,
- client_metadata={
- **_client.client_metadata,
- "public_keys": list(set(
- _client.client_metadata.get("public_keys", []) +
- [str(keypath)]))},
- user=_client.user)))
- flash("Client key successfully registered.", "alert-success")
- return view_client_uri
-
-
-@admin.route("/delete-client-public-key", methods=["POST"])
-@is_admin
-def delete_client_public_key():
- """Delete a client's SSL key"""
- form = request.form
- admin_dashboard_uri = redirect(url_for("oauth2.admin.dashboard"))
- view_client_uri = redirect(url_for("oauth2.admin.view_client",
- client_id=form["client_id"]))
- if not bool(form.get("client_id")):
- flash("No client selected.", "alert-danger")
- return admin_dashboard_uri
-
- try:
- _client = with_db_connection(partial(
- oauth2_client, client_id=uuid.UUID(form["client_id"])))
- if _client.is_nothing():
- raise ValueError("No such client.")
- _client = _client.value
- except ValueError:
- flash("Invalid client ID provided.", "alert-danger")
- return admin_dashboard_uri
-
- if form.get("ssl_key", None) is None:
- flash("The key must be provided.", "alert-danger")
- return view_client_uri
-
- try:
- def find_by_kid(keyset: KeySet, kid: str) -> JsonWebKey:
- for key in keyset.keys:
- if key.thumbprint() == kid:
- return key
- raise ValueError('Invalid JSON Web Key Set')
- _key = find_by_kid(_client.jwks, form.get("ssl_key"))
- except ValueError:
- flash("Could not delete: No such public key.", "alert-danger")
- return view_client_uri
-
- _keys = (_key for _key in _client.jwks.keys
- if _key.thumbprint() != form["ssl_key"])
- _keysdir = Path(app.config["CLIENTS_SSL_PUBLIC_KEYS_DIR"])
- with_db_connection(partial(save_client, the_client=OAuth2Client(
- client_id=_client.client_id,
- client_secret=_client.client_secret,
- client_id_issued_at=_client.client_id_issued_at,
- client_secret_expires_at=_client.client_secret_expires_at,
- client_metadata={
- **_client.client_metadata,
- "public_keys": list(set(
- _keysdir.joinpath(f"{_key.thumbprint()}.pem")
- for _key in _keys))},
- user=_client.user)))
- flash("Key deleted.", "alert-success")
- return view_client_uri
-
@admin.route("/edit-client", methods=["POST"])
@is_admin
@@ -391,7 +291,8 @@ def edit_client():
[form["redirect_uri"]] +
form["other_redirect_uris"].split("\r\n"))),
"grant_types": form.getlist("grants[]"),
- "scope": form.getlist("scope[]")
+ "scope": form.getlist("scope[]"),
+ "public-jwks-uri": form.get("client_jwk_uri", "")
}
with_db_connection(partial(save_client, the_client=OAuth2Client(
the_client.client_id,
diff --git a/gn_auth/templates/admin/register-client.html b/gn_auth/templates/admin/register-client.html
index 5e24148..bfe56f8 100644
--- a/gn_auth/templates/admin/register-client.html
+++ b/gn_auth/templates/admin/register-client.html
@@ -84,6 +84,16 @@
</select>
</div>
+ <legend>Other metadata</legend>
+ <div class="form-group">
+ <label class="form-group" for="txt-client-jwk-uri">
+ Client's Public JWKs</label>
+ <input type="text"
+ id="txt-client-jwk-uri"
+ name="client_jwk_uri"
+ class="form-control" />
+ </div>
+
<input type="submit" value="register client" class="btn btn-primary" />
</form>
{%endblock%}
diff --git a/gn_auth/templates/admin/view-oauth2-client.html b/gn_auth/templates/admin/view-oauth2-client.html
index 6da8291..c250ee3 100644
--- a/gn_auth/templates/admin/view-oauth2-client.html
+++ b/gn_auth/templates/admin/view-oauth2-client.html
@@ -73,68 +73,22 @@
{%endif%} />
{{granttype.name}}
</label>
-
- <input type="submit" class="btn btn-primary" value="update client" />
-</form>
-
-<hr />
-<h2>Signing/Verification SSL Keys</h2>
-<table>
- <caption>Registered Public Keys</caption>
- <thead>
- <tr>
- <th>JWK Thumbprint</th>
- <th>Actions</th>
- </tr>
- </thead>
-
- <tbody>
- {%for sslkey in client.jwks.keys:%}
- <tr>
- <td>{{sslkey.thumbprint()}}</td>
- <td>
- <form method="POST"
- action="{{url_for('oauth2.admin.delete_client_public_key')}}">
- <input type="hidden"
- name="client_id"
- value="{{client.client_id}}" />
- <input type="hidden"
- name="ssl_key"
- value="{{sslkey.thumbprint()}}" />
- <input type="submit"
- class="btn btn-danger"
- value="delete key" />
- </form>
- </td>
- </tr>
- {%else%}
- <tr>
- <td class="alert-warning"
- colspan="2">
- There are no registered SSL keys for this client.
- </td>
- </tr>
</div>
{%endfor%}
- </tbody>
-</table>
-<form id="frm-client-add-ssl-key"
- method="POST"
- action="{{url_for('oauth2.admin.register_client_public_key')}}">
- <legend>Register new SSL key</legend>
- <input type="hidden" name="client_id" value="{{client.client_id}}" />
- <fieldset>
- <label for="txt-area-client-ssl-key">Client's Public Key</label>
- <textarea id="txt-area-client-ssl-key"
- name="client_ssl_key"
- required="required"
- class="form-control"
- rows="10"></textarea>
- </fieldset>
</div>
- <br />
- <input type="submit" class="btn btn-primary" value="register key" />
+ <legend>Other metadata</legend>
+ <div class="form-group">
+ <label class="form-group" for="txt-client-jwk-uri">
+ Client's Public JWKs</label>
+ <input type="text"
+ id="txt-client-jwk-uri"
+ name="client_jwk_uri"
+ class="form-control"
+ value="{{client.client_metadata.get('public-jwks-uri', '')}}" />
+ </div>
+
+ <input type="submit" class="btn btn-primary" value="update client" />
</form>
{%endif%}