2020-08-17 13:49:48 +00:00
|
|
|
import datetime
|
|
|
|
import wtforms
|
|
|
|
import wtforms.fields.html5
|
|
|
|
from flask import Blueprint, render_template, request, flash, redirect, url_for
|
|
|
|
from flask_wtf import FlaskForm
|
2020-10-28 14:49:14 +00:00
|
|
|
from flask_babel import lazy_gettext as _
|
2020-08-17 13:49:48 +00:00
|
|
|
from werkzeug.security import gen_salt
|
2020-10-21 12:04:40 +00:00
|
|
|
from canaille.models import Client
|
|
|
|
from canaille.flaskutils import admin_needed
|
2020-08-17 13:49:48 +00:00
|
|
|
|
|
|
|
|
|
|
|
bp = Blueprint(__name__, "clients")
|
|
|
|
|
|
|
|
|
|
|
|
@bp.route("/")
|
2020-08-19 14:20:57 +00:00
|
|
|
@admin_needed()
|
2020-08-17 13:49:48 +00:00
|
|
|
def index():
|
|
|
|
clients = Client.filter()
|
2020-10-21 10:14:35 +00:00
|
|
|
return render_template("admin/client_list.html", clients=clients, menuitem="admin")
|
2020-08-17 13:49:48 +00:00
|
|
|
|
|
|
|
|
|
|
|
class ClientAdd(FlaskForm):
|
2020-08-26 13:37:15 +00:00
|
|
|
oauthClientName = wtforms.StringField(
|
2020-10-28 14:49:14 +00:00
|
|
|
_("Name"),
|
2020-08-17 13:49:48 +00:00
|
|
|
validators=[wtforms.validators.DataRequired()],
|
|
|
|
render_kw={"placeholder": "Client Name"},
|
|
|
|
)
|
|
|
|
oauthClientContact = wtforms.fields.html5.EmailField(
|
2020-10-28 14:49:14 +00:00
|
|
|
_("Contact"),
|
2020-08-17 13:49:48 +00:00
|
|
|
validators=[wtforms.validators.Optional()],
|
|
|
|
render_kw={"placeholder": "admin@mydomain.tld"},
|
|
|
|
)
|
|
|
|
oauthClientURI = wtforms.fields.html5.URLField(
|
2020-10-28 14:49:14 +00:00
|
|
|
_("URI"),
|
2020-08-17 13:49:48 +00:00
|
|
|
validators=[wtforms.validators.DataRequired()],
|
|
|
|
render_kw={"placeholder": "https://mydomain.tld"},
|
|
|
|
)
|
2020-08-17 15:49:49 +00:00
|
|
|
oauthRedirectURIs = wtforms.fields.html5.URLField(
|
2020-10-28 14:49:14 +00:00
|
|
|
_("Redirect URIs"),
|
2020-08-17 13:49:48 +00:00
|
|
|
validators=[wtforms.validators.DataRequired()],
|
|
|
|
render_kw={"placeholder": "https://mydomain.tld/callback"},
|
|
|
|
)
|
|
|
|
oauthGrantType = wtforms.SelectMultipleField(
|
2020-10-28 14:49:14 +00:00
|
|
|
_("Grant types"),
|
2020-08-17 13:49:48 +00:00
|
|
|
validators=[wtforms.validators.DataRequired()],
|
|
|
|
choices=[
|
|
|
|
("password", "password"),
|
|
|
|
("authorization_code", "authorization_code"),
|
2020-08-20 12:30:42 +00:00
|
|
|
("implicit", "implicit"),
|
|
|
|
("hybrid", "hybrid"),
|
2020-08-24 08:52:21 +00:00
|
|
|
("refresh_token", "refresh_token"),
|
2020-08-17 13:49:48 +00:00
|
|
|
],
|
2020-08-24 08:52:21 +00:00
|
|
|
default=["authorization_code", "refresh_token"],
|
2020-08-17 13:49:48 +00:00
|
|
|
)
|
2020-08-26 13:37:15 +00:00
|
|
|
oauthScope = wtforms.StringField(
|
2020-10-28 14:49:14 +00:00
|
|
|
_("Scope"),
|
2020-08-17 13:49:48 +00:00
|
|
|
validators=[wtforms.validators.Optional()],
|
2020-09-23 15:15:25 +00:00
|
|
|
default="openid profile email",
|
2020-08-17 13:49:48 +00:00
|
|
|
render_kw={"placeholder": "openid profile"},
|
|
|
|
)
|
|
|
|
oauthResponseType = wtforms.SelectMultipleField(
|
2020-10-28 14:49:14 +00:00
|
|
|
_("Response types"),
|
2020-08-17 13:49:48 +00:00
|
|
|
validators=[wtforms.validators.DataRequired()],
|
2020-08-20 12:30:42 +00:00
|
|
|
choices=[("code", "code"), ("token", "token"), ("id_token", "id_token")],
|
2020-08-17 13:49:48 +00:00
|
|
|
default=["code"],
|
|
|
|
)
|
|
|
|
oauthTokenEndpointAuthMethod = wtforms.SelectField(
|
2020-10-28 14:49:14 +00:00
|
|
|
_("Token Endpoint Auth Method"),
|
2020-08-17 13:49:48 +00:00
|
|
|
validators=[wtforms.validators.DataRequired()],
|
|
|
|
choices=[
|
|
|
|
("client_secret_basic", "client_secret_basic"),
|
|
|
|
("client_secret_post", "client_secret_post"),
|
|
|
|
("none", "none"),
|
|
|
|
],
|
|
|
|
default="client_secret_basic",
|
|
|
|
)
|
|
|
|
oauthLogoURI = wtforms.fields.html5.URLField(
|
2020-10-28 14:49:14 +00:00
|
|
|
_("Logo URI"),
|
2020-08-17 13:49:48 +00:00
|
|
|
validators=[wtforms.validators.Optional()],
|
|
|
|
render_kw={"placeholder": "https://mydomain.tld/logo.png"},
|
|
|
|
)
|
|
|
|
oauthTermsOfServiceURI = wtforms.fields.html5.URLField(
|
2020-10-28 14:49:14 +00:00
|
|
|
_("Terms of service URI"),
|
2020-08-17 13:49:48 +00:00
|
|
|
validators=[wtforms.validators.Optional()],
|
|
|
|
render_kw={"placeholder": "https://mydomain.tld/tos.html"},
|
|
|
|
)
|
|
|
|
oauthPolicyURI = wtforms.fields.html5.URLField(
|
2020-10-28 14:49:14 +00:00
|
|
|
_("Policy URI"),
|
2020-08-17 13:49:48 +00:00
|
|
|
validators=[wtforms.validators.Optional()],
|
|
|
|
render_kw={"placeholder": "https://mydomain.tld/policy.html"},
|
|
|
|
)
|
2020-08-26 13:37:15 +00:00
|
|
|
oauthSoftwareID = wtforms.StringField(
|
2020-10-28 14:49:14 +00:00
|
|
|
_("Software ID"),
|
2020-08-17 13:49:48 +00:00
|
|
|
validators=[wtforms.validators.Optional()],
|
|
|
|
render_kw={"placeholder": "xyz"},
|
|
|
|
)
|
2020-08-26 13:37:15 +00:00
|
|
|
oauthSoftwareVersion = wtforms.StringField(
|
2020-10-28 14:49:14 +00:00
|
|
|
_("Software Version"),
|
2020-08-17 13:49:48 +00:00
|
|
|
validators=[wtforms.validators.Optional()],
|
|
|
|
render_kw={"placeholder": "1.0"},
|
|
|
|
)
|
2020-08-26 13:37:15 +00:00
|
|
|
oauthJWK = wtforms.StringField(
|
2020-10-28 14:49:14 +00:00
|
|
|
_("JWK"),
|
2020-08-17 13:49:48 +00:00
|
|
|
validators=[wtforms.validators.Optional()],
|
|
|
|
render_kw={"placeholder": ""},
|
|
|
|
)
|
|
|
|
oauthJWKURI = wtforms.fields.html5.URLField(
|
2020-10-28 14:49:14 +00:00
|
|
|
_("JKW URI"),
|
2020-08-17 13:49:48 +00:00
|
|
|
validators=[wtforms.validators.Optional()],
|
|
|
|
render_kw={"placeholder": ""},
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
@bp.route("/add", methods=["GET", "POST"])
|
2020-08-19 14:20:57 +00:00
|
|
|
@admin_needed()
|
2020-08-17 13:49:48 +00:00
|
|
|
def add():
|
|
|
|
form = ClientAdd(request.form or None)
|
|
|
|
|
|
|
|
if not request.form:
|
2020-10-21 10:14:35 +00:00
|
|
|
return render_template("admin/client_add.html", form=form, menuitem="admin")
|
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 added. Please check your information."),
|
2020-08-17 13:49:48 +00:00
|
|
|
"error",
|
|
|
|
)
|
2020-10-21 10:14:35 +00:00
|
|
|
return render_template("admin/client_add.html", form=form, menuitem="admin")
|
2020-08-17 13:49:48 +00:00
|
|
|
|
|
|
|
client_id = gen_salt(24)
|
|
|
|
client_id_issued_at = datetime.datetime.now().strftime("%Y%m%d%H%M%SZ")
|
|
|
|
client = Client(
|
|
|
|
oauthClientID=client_id,
|
|
|
|
oauthIssueDate=client_id_issued_at,
|
|
|
|
oauthClientName=form["oauthClientName"].data,
|
|
|
|
oauthClientContact=form["oauthClientContact"].data,
|
|
|
|
oauthClientURI=form["oauthClientURI"].data,
|
|
|
|
oauthGrantType=form["oauthGrantType"].data,
|
2020-08-17 15:49:49 +00:00
|
|
|
oauthRedirectURIs=[form["oauthRedirectURIs"].data],
|
2020-08-17 13:49:48 +00:00
|
|
|
oauthResponseType=form["oauthResponseType"].data,
|
|
|
|
oauthScope=form["oauthScope"].data.split(" "),
|
|
|
|
oauthTokenEndpointAuthMethod=form["oauthTokenEndpointAuthMethod"].data,
|
|
|
|
oauthLogoURI=form["oauthLogoURI"].data,
|
|
|
|
oauthTermsOfServiceURI=form["oauthTermsOfServiceURI"].data,
|
|
|
|
oauthPolicyURI=form["oauthPolicyURI"].data,
|
|
|
|
oauthSoftwareID=form["oauthSoftwareID"].data,
|
|
|
|
oauthSoftwareVersion=form["oauthSoftwareVersion"].data,
|
|
|
|
oauthJWK=form["oauthJWK"].data,
|
|
|
|
oauthJWKURI=form["oauthJWKURI"].data,
|
|
|
|
oauthClientSecret=""
|
|
|
|
if form["oauthTokenEndpointAuthMethod"].data == "none"
|
|
|
|
else gen_salt(48),
|
|
|
|
)
|
|
|
|
client.save()
|
|
|
|
flash(
|
2020-10-28 14:49:14 +00:00
|
|
|
_("The client has been created."),
|
2020-08-27 08:50:50 +00:00
|
|
|
"success",
|
2020-08-17 13:49:48 +00:00
|
|
|
)
|
|
|
|
|
2020-10-21 12:04:40 +00:00
|
|
|
return redirect(url_for("canaille.admin.clients.edit", client_id=client_id))
|
2020-08-17 13:49:48 +00:00
|
|
|
|
|
|
|
|
|
|
|
@bp.route("/edit/<client_id>", methods=["GET", "POST"])
|
2020-08-19 14:20:57 +00:00
|
|
|
@admin_needed()
|
2020-08-17 13:49:48 +00:00
|
|
|
def edit(client_id):
|
|
|
|
client = Client.get(client_id)
|
|
|
|
data = dict(client)
|
|
|
|
data["oauthScope"] = " ".join(data["oauthScope"])
|
2020-08-17 15:49:49 +00:00
|
|
|
data["oauthRedirectURIs"] = data["oauthRedirectURIs"][0]
|
2020-08-17 13:49:48 +00:00
|
|
|
form = ClientAdd(request.form or None, data=data, client=client)
|
|
|
|
|
|
|
|
if not request.form:
|
2020-10-21 10:14:35 +00:00
|
|
|
return render_template(
|
|
|
|
"admin/client_edit.html", form=form, client=client, menuitem="admin"
|
|
|
|
)
|
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",
|
|
|
|
)
|
|
|
|
|
|
|
|
else:
|
|
|
|
client.update(
|
|
|
|
oauthClientName=form["oauthClientName"].data,
|
|
|
|
oauthClientContact=form["oauthClientContact"].data,
|
|
|
|
oauthClientURI=form["oauthClientURI"].data,
|
|
|
|
oauthGrantType=form["oauthGrantType"].data,
|
2020-08-17 15:49:49 +00:00
|
|
|
oauthRedirectURIs=[form["oauthRedirectURIs"].data],
|
2020-08-17 13:49:48 +00:00
|
|
|
oauthResponseType=form["oauthResponseType"].data,
|
|
|
|
oauthScope=form["oauthScope"].data.split(" "),
|
|
|
|
oauthTokenEndpointAuthMethod=form["oauthTokenEndpointAuthMethod"].data,
|
|
|
|
oauthLogoURI=form["oauthLogoURI"].data,
|
|
|
|
oauthTermsOfServiceURI=form["oauthTermsOfServiceURI"].data,
|
|
|
|
oauthPolicyURI=form["oauthPolicyURI"].data,
|
|
|
|
oauthSoftwareID=form["oauthSoftwareID"].data,
|
|
|
|
oauthSoftwareVersion=form["oauthSoftwareVersion"].data,
|
|
|
|
oauthJWK=form["oauthJWK"].data,
|
|
|
|
oauthJWKURI=form["oauthJWKURI"].data,
|
|
|
|
)
|
|
|
|
client.save()
|
|
|
|
flash(
|
2020-10-28 14:49:14 +00:00
|
|
|
_("The client has been edited."),
|
2020-08-27 08:50:50 +00:00
|
|
|
"success",
|
2020-08-17 13:49:48 +00:00
|
|
|
)
|
|
|
|
|
2020-10-21 10:14:35 +00:00
|
|
|
return render_template(
|
|
|
|
"admin/client_edit.html", form=form, client=client, menuitem="admin"
|
|
|
|
)
|