2020-08-17 13:49:48 +00:00
|
|
|
import datetime
|
2021-12-20 22:57:27 +00:00
|
|
|
|
|
|
|
from flask import Blueprint
|
2024-03-15 18:58:06 +00:00
|
|
|
from flask import abort
|
2024-12-06 19:21:14 +00:00
|
|
|
from flask import current_app
|
2021-12-20 22:57:27 +00:00
|
|
|
from flask import flash
|
|
|
|
from flask import redirect
|
|
|
|
from flask import request
|
|
|
|
from flask import url_for
|
2020-08-17 13:49:48 +00:00
|
|
|
from werkzeug.security import gen_salt
|
|
|
|
|
2024-03-15 18:58:06 +00:00
|
|
|
from canaille.app import models
|
|
|
|
from canaille.app.flask import render_htmx_template
|
2024-12-17 13:45:10 +00:00
|
|
|
from canaille.app.flask import user_needed
|
2024-03-15 18:58:06 +00:00
|
|
|
from canaille.app.forms import TableForm
|
|
|
|
from canaille.app.i18n import gettext as _
|
2024-12-22 14:58:45 +00:00
|
|
|
from canaille.app.templating import render_template
|
2024-04-16 20:42:29 +00:00
|
|
|
from canaille.backends import Backend
|
2023-12-25 23:23:47 +00:00
|
|
|
|
2024-03-15 18:58:06 +00:00
|
|
|
from .forms import ClientAddForm
|
2020-08-17 13:49:48 +00:00
|
|
|
|
2022-01-11 18:49:06 +00:00
|
|
|
bp = Blueprint("clients", __name__, url_prefix="/admin/client")
|
2020-08-17 13:49:48 +00:00
|
|
|
|
|
|
|
|
2023-02-25 17:11:19 +00:00
|
|
|
@bp.route("/", methods=["GET", "POST"])
|
2024-12-17 13:45:10 +00:00
|
|
|
@user_needed("manage_oidc")
|
2020-10-29 10:09:31 +00:00
|
|
|
def index(user):
|
2023-04-09 09:37:04 +00:00
|
|
|
table_form = TableForm(models.Client, formdata=request.form)
|
2023-02-25 17:11:19 +00:00
|
|
|
if request.form and request.form.get("page") and not table_form.validate():
|
|
|
|
abort(404)
|
|
|
|
|
2023-03-09 16:41:26 +00:00
|
|
|
return render_htmx_template(
|
2024-12-18 23:16:58 +00:00
|
|
|
"oidc/client_list.html", menuitem="admin", table_form=table_form
|
2022-01-11 18:49:06 +00:00
|
|
|
)
|
2020-08-17 13:49:48 +00:00
|
|
|
|
|
|
|
|
|
|
|
@bp.route("/add", methods=["GET", "POST"])
|
2024-12-17 13:45:10 +00:00
|
|
|
@user_needed("manage_oidc")
|
2020-10-29 10:09:31 +00:00
|
|
|
def add(user):
|
2023-03-29 22:40:25 +00:00
|
|
|
form = ClientAddForm(request.form or None)
|
2020-08-17 13:49:48 +00:00
|
|
|
|
2023-06-22 09:39:50 +00:00
|
|
|
if not request.form or form.form_control():
|
2024-12-18 23:16:58 +00:00
|
|
|
return render_template("oidc/client_add.html", form=form, menuitem="admin")
|
2020-08-17 13:49:48 +00:00
|
|
|
|
|
|
|
if not form.validate():
|
|
|
|
flash(
|
2021-10-13 09:52:02 +00:00
|
|
|
_("The client has not been added. Please check your information."),
|
|
|
|
"error",
|
2020-08-17 13:49:48 +00:00
|
|
|
)
|
2024-12-18 23:16:58 +00:00
|
|
|
return render_template("oidc/client_add.html", form=form, menuitem="admin")
|
2020-08-17 13:49:48 +00:00
|
|
|
|
|
|
|
client_id = gen_salt(24)
|
2023-03-17 23:38:56 +00:00
|
|
|
client_id_issued_at = datetime.datetime.now(datetime.timezone.utc)
|
2023-04-09 09:37:04 +00:00
|
|
|
client = models.Client(
|
2022-01-11 16:57:58 +00:00
|
|
|
client_id=client_id,
|
2022-10-17 15:49:52 +00:00
|
|
|
client_id_issued_at=client_id_issued_at,
|
|
|
|
client_name=form["client_name"].data,
|
2023-06-22 09:39:50 +00:00
|
|
|
contacts=form["contacts"].data,
|
2022-10-17 15:49:52 +00:00
|
|
|
client_uri=form["client_uri"].data,
|
|
|
|
grant_types=form["grant_types"].data,
|
2023-06-22 09:39:50 +00:00
|
|
|
redirect_uris=form["redirect_uris"].data,
|
|
|
|
post_logout_redirect_uris=form["post_logout_redirect_uris"].data,
|
2022-10-17 15:49:52 +00:00
|
|
|
response_types=form["response_types"].data,
|
2022-01-11 16:57:58 +00:00
|
|
|
scope=form["scope"].data.split(" "),
|
|
|
|
token_endpoint_auth_method=form["token_endpoint_auth_method"].data,
|
|
|
|
logo_uri=form["logo_uri"].data,
|
|
|
|
tos_uri=form["tos_uri"].data,
|
|
|
|
policy_uri=form["policy_uri"].data,
|
|
|
|
software_id=form["software_id"].data,
|
|
|
|
software_version=form["software_version"].data,
|
|
|
|
jwk=form["jwk"].data,
|
2022-10-17 15:49:52 +00:00
|
|
|
jwks_uri=form["jwks_uri"].data,
|
2022-01-11 16:57:58 +00:00
|
|
|
preconsent=form["preconsent"].data,
|
2022-10-17 15:49:52 +00:00
|
|
|
client_secret=""
|
2022-01-11 16:57:58 +00:00
|
|
|
if form["token_endpoint_auth_method"].data == "none"
|
2020-08-17 13:49:48 +00:00
|
|
|
else gen_salt(48),
|
|
|
|
)
|
2024-04-16 20:42:29 +00:00
|
|
|
Backend.instance.save(client)
|
2023-03-08 22:53:53 +00:00
|
|
|
client.audience = [client]
|
2024-04-16 20:42:29 +00:00
|
|
|
Backend.instance.save(client)
|
2020-08-17 13:49:48 +00:00
|
|
|
flash(
|
2021-10-13 09:52:02 +00:00
|
|
|
_("The client has been created."),
|
|
|
|
"success",
|
2020-08-17 13:49:48 +00:00
|
|
|
)
|
|
|
|
|
2023-06-29 10:15:12 +00:00
|
|
|
return redirect(url_for("oidc.clients.edit", client=client))
|
2020-08-17 13:49:48 +00:00
|
|
|
|
|
|
|
|
2023-06-29 10:15:12 +00:00
|
|
|
@bp.route("/edit/<client:client>", methods=["GET", "POST"])
|
2024-12-17 13:45:10 +00:00
|
|
|
@user_needed("manage_oidc")
|
2023-06-29 10:15:12 +00:00
|
|
|
def edit(user, client):
|
2023-07-06 16:43:37 +00:00
|
|
|
if request.form.get("action") == "confirm-delete":
|
2024-12-18 23:16:58 +00:00
|
|
|
return render_template("oidc/modals/delete-client.html", client=client)
|
2023-07-06 16:43:37 +00:00
|
|
|
|
2023-06-22 09:39:50 +00:00
|
|
|
if request.form and request.form.get("action") == "delete":
|
2023-06-29 10:15:12 +00:00
|
|
|
return client_delete(client)
|
2023-07-06 16:43:37 +00:00
|
|
|
|
2024-12-06 19:21:14 +00:00
|
|
|
if request.form and request.form.get("action") == "new-token":
|
|
|
|
return client_new_token(client)
|
|
|
|
|
2023-06-29 10:15:12 +00:00
|
|
|
return client_edit(client)
|
2020-11-23 16:32:40 +00:00
|
|
|
|
|
|
|
|
2023-06-29 10:15:12 +00:00
|
|
|
def client_edit(client):
|
2023-05-11 21:08:39 +00:00
|
|
|
data = {attribute: getattr(client, attribute) for attribute in client.attributes}
|
2023-11-24 11:45:41 +00:00
|
|
|
if data["scope"]:
|
|
|
|
data["scope"] = " ".join(data["scope"])
|
2022-01-11 16:57:58 +00:00
|
|
|
data["preconsent"] = client.preconsent
|
2023-03-29 22:40:25 +00:00
|
|
|
form = ClientAddForm(request.form or None, data=data, client=client)
|
2020-08-17 13:49:48 +00:00
|
|
|
|
2023-06-22 09:39:50 +00:00
|
|
|
if not request.form or form.form_control():
|
2020-10-21 10:14:35 +00:00
|
|
|
return render_template(
|
2024-12-18 23:16:58 +00:00
|
|
|
"oidc/client_edit.html", form=form, client=client, menuitem="admin"
|
2020-10-21 10:14:35 +00:00
|
|
|
)
|
2020-08-17 13:49:48 +00:00
|
|
|
|
|
|
|
if not form.validate():
|
|
|
|
flash(
|
2020-10-28 14:49:14 +00:00
|
|
|
_("The client has not been edited. Please check your information."),
|
2020-08-17 13:49:48 +00:00
|
|
|
"error",
|
|
|
|
)
|
2022-11-16 16:50:38 +00:00
|
|
|
return render_template(
|
2024-12-18 23:16:58 +00:00
|
|
|
"oidc/client_edit.html", form=form, client=client, menuitem="admin"
|
2020-08-17 13:49:48 +00:00
|
|
|
)
|
|
|
|
|
2024-04-16 20:42:29 +00:00
|
|
|
Backend.instance.update(
|
2024-04-16 19:57:06 +00:00
|
|
|
client,
|
2022-11-16 16:50:38 +00:00
|
|
|
client_name=form["client_name"].data,
|
2023-06-22 09:39:50 +00:00
|
|
|
contacts=form["contacts"].data,
|
2022-11-16 16:50:38 +00:00
|
|
|
client_uri=form["client_uri"].data,
|
|
|
|
grant_types=form["grant_types"].data,
|
2023-06-22 09:39:50 +00:00
|
|
|
redirect_uris=form["redirect_uris"].data,
|
|
|
|
post_logout_redirect_uris=form["post_logout_redirect_uris"].data,
|
2022-11-16 16:50:38 +00:00
|
|
|
response_types=form["response_types"].data,
|
|
|
|
scope=form["scope"].data.split(" "),
|
|
|
|
token_endpoint_auth_method=form["token_endpoint_auth_method"].data,
|
|
|
|
logo_uri=form["logo_uri"].data,
|
|
|
|
tos_uri=form["tos_uri"].data,
|
|
|
|
policy_uri=form["policy_uri"].data,
|
|
|
|
software_id=form["software_id"].data,
|
|
|
|
software_version=form["software_version"].data,
|
|
|
|
jwk=form["jwk"].data,
|
|
|
|
jwks_uri=form["jwks_uri"].data,
|
2023-11-22 10:30:30 +00:00
|
|
|
audience=form["audience"].data,
|
2022-11-16 16:50:38 +00:00
|
|
|
preconsent=form["preconsent"].data,
|
2020-10-21 10:14:35 +00:00
|
|
|
)
|
2024-04-16 20:42:29 +00:00
|
|
|
Backend.instance.save(client)
|
2022-11-16 16:50:38 +00:00
|
|
|
flash(
|
|
|
|
_("The client has been edited."),
|
|
|
|
"success",
|
|
|
|
)
|
2023-06-29 10:15:12 +00:00
|
|
|
return redirect(url_for("oidc.clients.edit", client=client))
|
2020-11-23 16:32:40 +00:00
|
|
|
|
|
|
|
|
2023-06-29 10:15:12 +00:00
|
|
|
def client_delete(client):
|
2020-11-23 16:32:40 +00:00
|
|
|
flash(
|
2021-10-13 09:52:02 +00:00
|
|
|
_("The client has been deleted."),
|
|
|
|
"success",
|
2020-11-23 16:32:40 +00:00
|
|
|
)
|
2024-04-16 20:42:29 +00:00
|
|
|
Backend.instance.delete(client)
|
2022-01-11 18:49:06 +00:00
|
|
|
return redirect(url_for("oidc.clients.index"))
|
2024-12-06 19:21:14 +00:00
|
|
|
|
|
|
|
|
|
|
|
def client_new_token(client):
|
|
|
|
flash(
|
|
|
|
_(f"A token have been created for the client {client.client_name}"),
|
|
|
|
"success",
|
|
|
|
)
|
|
|
|
now = datetime.datetime.now(datetime.timezone.utc)
|
|
|
|
token = models.Token(
|
|
|
|
token_id=gen_salt(48),
|
|
|
|
type="access_token",
|
|
|
|
access_token=gen_salt(48),
|
|
|
|
issue_date=now,
|
|
|
|
lifetime=current_app.config["CANAILLE_OIDC"]["JWT"]["EXP"],
|
|
|
|
scope=client.scope,
|
|
|
|
client=client,
|
|
|
|
audience=client.audience,
|
|
|
|
)
|
|
|
|
Backend.instance.save(token)
|
|
|
|
return redirect(url_for("oidc.tokens.view", token=token))
|