split oidc code from the rest

This commit is contained in:
Éloi Rivard 2022-01-11 19:49:06 +01:00
parent 16d2d71194
commit 52e802b34f
37 changed files with 290 additions and 269 deletions

View file

@ -15,7 +15,7 @@ from flask_themer import FileSystemThemeLoader
from flask_themer import render_template from flask_themer import render_template
from flask_themer import Themer from flask_themer import Themer
from .oauth2utils import setup_oauth from .oidc.oauth2utils import setup_oauth
def setup_config(app, config=None, validate=True): def setup_config(app, config=None, validate=True):
@ -214,19 +214,15 @@ def setup_themer(app):
def setup_blueprints(app): def setup_blueprints(app):
import canaille.account import canaille.account
import canaille.admin import canaille.admin
import canaille.consents
import canaille.groups import canaille.groups
import canaille.oauth import canaille.oidc
import canaille.well_known
app.url_map.strict_slashes = False app.url_map.strict_slashes = False
app.register_blueprint(canaille.account.bp) app.register_blueprint(canaille.account.bp)
app.register_blueprint(canaille.admin.bp, url_prefix="/admin") app.register_blueprint(canaille.admin.bp)
app.register_blueprint(canaille.groups.bp, url_prefix="/groups") app.register_blueprint(canaille.groups.bp)
app.register_blueprint(canaille.oauth.bp, url_prefix="/oauth") app.register_blueprint(canaille.oidc.bp)
app.register_blueprint(canaille.consents.bp, url_prefix="/consent")
app.register_blueprint(canaille.well_known.bp, url_prefix="/.well-known")
def create_app(config=None, validate=True): def create_app(config=None, validate=True):

View file

@ -1,13 +1,7 @@
from flask import Blueprint from flask import Blueprint
from . import authorizations
from . import clients
from . import mail from . import mail
from . import tokens
bp = Blueprint("admin", __name__) bp = Blueprint("admin", __name__, url_prefix="/admin")
bp.register_blueprint(tokens.bp, url_prefix="/token") bp.register_blueprint(mail.bp)
bp.register_blueprint(authorizations.bp, url_prefix="/authorization")
bp.register_blueprint(clients.bp, url_prefix="/client")
bp.register_blueprint(mail.bp, url_prefix="/mail")

View file

@ -15,7 +15,7 @@ from wtforms.validators import DataRequired
from wtforms.validators import Email from wtforms.validators import Email
bp = Blueprint("mails", __name__) bp = Blueprint("mails", __name__, url_prefix="/mail")
class MailTestForm(FlaskForm): class MailTestForm(FlaskForm):
@ -43,7 +43,7 @@ def mail_index(user):
else: else:
flash(_("The test invitation mail has been sent correctly"), "error") flash(_("The test invitation mail has been sent correctly"), "error")
return render_template("admin/mails.html", form=form) return render_template("mail/admin.html", form=form)
@bp.route("/password-init.html") @bp.route("/password-init.html")

View file

@ -2,8 +2,8 @@ import sys
import click import click
from canaille import create_app from canaille import create_app
from canaille.models import AuthorizationCode from canaille.oidc.models import AuthorizationCode
from canaille.models import Token from canaille.oidc.models import Token
from flask import current_app from flask import current_app
from flask.cli import FlaskGroup from flask.cli import FlaskGroup
from flask.cli import with_appcontext from flask.cli import with_appcontext

View file

@ -13,7 +13,7 @@ from .forms import GroupForm
from .forms import unique_group from .forms import unique_group
from .models import Group from .models import Group
bp = Blueprint("groups", __name__) bp = Blueprint("groups", __name__, url_prefix="/groups")
@bp.route("/") @bp.route("/")

View file

@ -7,10 +7,10 @@ from cryptography.hazmat.backends import default_backend as crypto_default_backe
from cryptography.hazmat.primitives import serialization as crypto_serialization from cryptography.hazmat.primitives import serialization as crypto_serialization
from cryptography.hazmat.primitives.asymmetric import rsa from cryptography.hazmat.primitives.asymmetric import rsa
from .models import AuthorizationCode from .oidc.models import AuthorizationCode
from .models import Client from .oidc.models import Client
from .models import Consent from .oidc.models import Consent
from .models import Token from .oidc.models import Token
class InstallationException(Exception): class InstallationException(Exception):

View file

@ -1,11 +1,4 @@
import datetime
import uuid
import ldap.filter import ldap.filter
from authlib.oauth2.rfc6749 import AuthorizationCodeMixin
from authlib.oauth2.rfc6749 import ClientMixin
from authlib.oauth2.rfc6749 import TokenMixin
from authlib.oauth2.rfc6749 import util
from flask import current_app from flask import current_app
from flask import session from flask import session
@ -229,176 +222,3 @@ class Group(LDAPObject):
def remove_member(self, user, conn=None): def remove_member(self, user, conn=None):
self.member = [m for m in self.member if m != user.dn] self.member = [m for m in self.member if m != user.dn]
self.save(conn=conn) self.save(conn=conn)
class Client(LDAPObject, ClientMixin):
object_class = ["oauthClient"]
base = "ou=clients,ou=oauth"
id = "oauthClientID"
@property
def issue_date(self):
return self.oauthIssueDate
@property
def preconsent(self):
return self.oauthPreconsent
def get_client_id(self):
return self.oauthClientID
def get_default_redirect_uri(self):
return self.oauthRedirectURIs[0]
def get_allowed_scope(self, scope):
return util.list_to_scope(self.oauthScope)
def check_redirect_uri(self, redirect_uri):
return redirect_uri in self.oauthRedirectURIs
def has_client_secret(self):
return bool(self.oauthClientSecret)
def check_client_secret(self, client_secret):
return client_secret == self.oauthClientSecret
def check_token_endpoint_auth_method(self, method):
return method == self.oauthTokenEndpointAuthMethod
def check_response_type(self, response_type):
return all(r in self.oauthResponseType for r in response_type.split(" "))
def check_grant_type(self, grant_type):
return grant_type in self.oauthGrantType
@property
def client_info(self):
return dict(
client_id=self.client_id,
client_secret=self.client_secret,
client_id_issued_at=self.client_id_issued_at,
client_secret_expires_at=self.client_secret_expires_at,
)
class AuthorizationCode(LDAPObject, AuthorizationCodeMixin):
object_class = ["oauthAuthorizationCode"]
base = "ou=authorizations,ou=oauth"
id = "oauthCode"
@property
def issue_date(self):
return self.oauthIssueDate
def get_redirect_uri(self):
return self.oauthRedirectURI
def get_scope(self):
return self.oauthScope
def get_nonce(self):
return self.oauthNonce
def is_expired(self):
return (
self.oauthAuthorizationDate
+ datetime.timedelta(seconds=int(self.oauthAuthorizationLifetime))
< datetime.datetime.now()
)
def get_auth_time(self):
return int(
(
self.oauthAuthorizationDate - datetime.datetime(1970, 1, 1)
).total_seconds()
)
class Token(LDAPObject, TokenMixin):
object_class = ["oauthToken"]
base = "ou=tokens,ou=oauth"
id = "oauthAccessToken"
@property
def issue_date(self):
return self.oauthIssueDate
@property
def expire_date(self):
return self.oauthIssueDate + datetime.timedelta(
seconds=int(self.oauthTokenLifetime)
)
@property
def revoked(self):
return bool(self.oauthRevokationDate)
def get_client_id(self):
return Client.get(self.oauthClient).oauthClientID
def get_scope(self):
return " ".join(self.oauthScope)
def get_expires_in(self):
return int(self.oauthTokenLifetime)
def get_issued_at(self):
return int(
(self.oauthIssueDate - datetime.datetime(1970, 1, 1)).total_seconds()
)
def get_expires_at(self):
issue_timestamp = (
self.oauthIssueDate - datetime.datetime(1970, 1, 1)
).total_seconds()
return int(issue_timestamp) + int(self.oauthTokenLifetime)
def is_refresh_token_active(self):
if self.oauthRevokationDate:
return False
return self.expire_date >= datetime.datetime.now()
def is_expired(self):
return (
self.oauthIssueDate
+ datetime.timedelta(seconds=int(self.oauthTokenLifetime))
< datetime.datetime.now()
)
class Consent(LDAPObject):
object_class = ["oauthConsent"]
base = "ou=consents,ou=oauth"
id = "cn"
def __init__(self, *args, **kwargs):
if "cn" not in kwargs:
kwargs["cn"] = str(uuid.uuid4())
super().__init__(*args, **kwargs)
@property
def issue_date(self):
return self.oauthIssueDate
@property
def revokation_date(self):
return self.oauthRevokationDate
def revoke(self):
self.oauthRevokationDate = datetime.datetime.now()
self.save()
tokens = Token.filter(
oauthClient=self.oauthClient,
oauthSubject=self.oauthSubject,
)
for t in tokens:
if t.revoked or any(
scope not in t.oauthScope[0] for scope in self.oauthScope
):
continue
t.oauthRevokationDate = self.oauthRevokationDate
t.save()

17
canaille/oidc/__init__.py Normal file
View file

@ -0,0 +1,17 @@
from flask import Blueprint
from . import authorizations
from . import clients
from . import consents
from . import oauth
from . import tokens
from . import well_known
bp = Blueprint("oidc", __name__)
bp.register_blueprint(authorizations.bp)
bp.register_blueprint(clients.bp)
bp.register_blueprint(consents.bp)
bp.register_blueprint(oauth.bp)
bp.register_blueprint(well_known.bp)
bp.register_blueprint(tokens.bp)

View file

@ -1,10 +1,10 @@
from canaille.flaskutils import permissions_needed from canaille.flaskutils import permissions_needed
from canaille.models import AuthorizationCode from canaille.oidc.models import AuthorizationCode
from flask import Blueprint from flask import Blueprint
from flask_themer import render_template from flask_themer import render_template
bp = Blueprint("authorizations", __name__) bp = Blueprint("authorizations", __name__, url_prefix="/admin/authorization")
@bp.route("/") @bp.route("/")
@ -12,7 +12,7 @@ bp = Blueprint("authorizations", __name__)
def index(user): def index(user):
authorizations = AuthorizationCode.filter() authorizations = AuthorizationCode.filter()
return render_template( return render_template(
"admin/authorization_list.html", authorizations=authorizations "oidc/admin/authorization_list.html", authorizations=authorizations
) )
@ -21,5 +21,7 @@ def index(user):
def view(user, authorization_id): def view(user, authorization_id):
authorization = AuthorizationCode.get(authorization_id) authorization = AuthorizationCode.get(authorization_id)
return render_template( return render_template(
"admin/authorization_view.html", authorization=authorization, menuitem="admin" "oidc/admin/authorization_view.html",
authorization=authorization,
menuitem="admin",
) )

View file

@ -2,7 +2,7 @@ import datetime
import wtforms import wtforms
from canaille.flaskutils import permissions_needed from canaille.flaskutils import permissions_needed
from canaille.models import Client from canaille.oidc.models import Client
from flask import abort from flask import abort
from flask import Blueprint from flask import Blueprint
from flask import flash from flask import flash
@ -15,14 +15,16 @@ from flask_wtf import FlaskForm
from werkzeug.security import gen_salt from werkzeug.security import gen_salt
bp = Blueprint("clients", __name__) bp = Blueprint("clients", __name__, url_prefix="/admin/client")
@bp.route("/") @bp.route("/")
@permissions_needed("manage_oidc") @permissions_needed("manage_oidc")
def index(user): def index(user):
clients = Client.filter() clients = Client.filter()
return render_template("admin/client_list.html", clients=clients, menuitem="admin") return render_template(
"oidc/admin/client_list.html", clients=clients, menuitem="admin"
)
def client_audiences(): def client_audiences():
@ -138,14 +140,18 @@ def add(user):
form = ClientAdd(request.form or None) form = ClientAdd(request.form or None)
if not request.form: if not request.form:
return render_template("admin/client_add.html", form=form, menuitem="admin") return render_template(
"oidc/admin/client_add.html", form=form, menuitem="admin"
)
if not form.validate(): if not form.validate():
flash( flash(
_("The client has not been added. Please check your information."), _("The client has not been added. Please check your information."),
"error", "error",
) )
return render_template("admin/client_add.html", form=form, menuitem="admin") return render_template(
"oidc/admin/client_add.html", form=form, menuitem="admin"
)
client_id = gen_salt(24) client_id = gen_salt(24)
client_id_issued_at = datetime.datetime.now() client_id_issued_at = datetime.datetime.now()
@ -179,7 +185,7 @@ def add(user):
"success", "success",
) )
return redirect(url_for("admin.clients.edit", client_id=client_id)) return redirect(url_for("oidc.clients.edit", client_id=client_id))
@bp.route("/edit/<client_id>", methods=["GET", "POST"]) @bp.route("/edit/<client_id>", methods=["GET", "POST"])
@ -204,7 +210,7 @@ def client_edit(client_id):
if not request.form: if not request.form:
return render_template( return render_template(
"admin/client_edit.html", form=form, client=client, menuitem="admin" "oidc/admin/client_edit.html", form=form, client=client, menuitem="admin"
) )
if not form.validate(): if not form.validate():
@ -240,7 +246,7 @@ def client_edit(client_id):
) )
return render_template( return render_template(
"admin/client_edit.html", form=form, client=client, menuitem="admin" "oidc/admin/client_edit.html", form=form, client=client, menuitem="admin"
) )
@ -251,4 +257,4 @@ def client_delete(client_id):
"success", "success",
) )
client.delete() client.delete()
return redirect(url_for("admin.clients.index")) return redirect(url_for("oidc.clients.index"))

View file

@ -1,6 +1,6 @@
from canaille.flaskutils import user_needed from canaille.flaskutils import user_needed
from canaille.models import Client from canaille.oidc.models import Client
from canaille.models import Consent from canaille.oidc.models import Consent
from flask import Blueprint from flask import Blueprint
from flask import flash from flask import flash
from flask import redirect from flask import redirect
@ -9,7 +9,7 @@ from flask_babel import gettext
from flask_themer import render_template from flask_themer import render_template
bp = Blueprint("consents", __name__) bp = Blueprint("consents", __name__, url_prefix="/consent")
@bp.route("/") @bp.route("/")
@ -20,7 +20,10 @@ def consents(user):
client_dns = list({t.oauthClient for t in consents}) client_dns = list({t.oauthClient for t in consents})
clients = {dn: Client.get(dn) for dn in client_dns} clients = {dn: Client.get(dn) for dn in client_dns}
return render_template( return render_template(
"consent_list.html", consents=consents, clients=clients, menuitem="consents" "oidc/user/consent_list.html",
consents=consents,
clients=clients,
menuitem="consents",
) )
@ -36,4 +39,4 @@ def delete(user, consent_id):
consent.revoke() consent.revoke()
flash(gettext("The access has been revoked"), "success") flash(gettext("The access has been revoked"), "success")
return redirect(url_for("consents.consents")) return redirect(url_for("oidc.consents.consents"))

182
canaille/oidc/models.py Normal file
View file

@ -0,0 +1,182 @@
import datetime
import uuid
from authlib.oauth2.rfc6749 import AuthorizationCodeMixin
from authlib.oauth2.rfc6749 import ClientMixin
from authlib.oauth2.rfc6749 import TokenMixin
from authlib.oauth2.rfc6749 import util
from ..ldaputils import LDAPObject
class Client(LDAPObject, ClientMixin):
object_class = ["oauthClient"]
base = "ou=clients,ou=oauth"
id = "oauthClientID"
@property
def issue_date(self):
return self.oauthIssueDate
@property
def preconsent(self):
return self.oauthPreconsent
def get_client_id(self):
return self.oauthClientID
def get_default_redirect_uri(self):
return self.oauthRedirectURIs[0]
def get_allowed_scope(self, scope):
return util.list_to_scope(self.oauthScope)
def check_redirect_uri(self, redirect_uri):
return redirect_uri in self.oauthRedirectURIs
def has_client_secret(self):
return bool(self.oauthClientSecret)
def check_client_secret(self, client_secret):
return client_secret == self.oauthClientSecret
def check_token_endpoint_auth_method(self, method):
return method == self.oauthTokenEndpointAuthMethod
def check_response_type(self, response_type):
return all(r in self.oauthResponseType for r in response_type.split(" "))
def check_grant_type(self, grant_type):
return grant_type in self.oauthGrantType
@property
def client_info(self):
return dict(
client_id=self.client_id,
client_secret=self.client_secret,
client_id_issued_at=self.client_id_issued_at,
client_secret_expires_at=self.client_secret_expires_at,
)
class AuthorizationCode(LDAPObject, AuthorizationCodeMixin):
object_class = ["oauthAuthorizationCode"]
base = "ou=authorizations,ou=oauth"
id = "oauthCode"
@property
def issue_date(self):
return self.oauthIssueDate
def get_redirect_uri(self):
return self.oauthRedirectURI
def get_scope(self):
return self.oauthScope
def get_nonce(self):
return self.oauthNonce
def is_expired(self):
return (
self.oauthAuthorizationDate
+ datetime.timedelta(seconds=int(self.oauthAuthorizationLifetime))
< datetime.datetime.now()
)
def get_auth_time(self):
return int(
(
self.oauthAuthorizationDate - datetime.datetime(1970, 1, 1)
).total_seconds()
)
class Token(LDAPObject, TokenMixin):
object_class = ["oauthToken"]
base = "ou=tokens,ou=oauth"
id = "oauthAccessToken"
@property
def issue_date(self):
return self.oauthIssueDate
@property
def expire_date(self):
return self.oauthIssueDate + datetime.timedelta(
seconds=int(self.oauthTokenLifetime)
)
@property
def revoked(self):
return bool(self.oauthRevokationDate)
def get_client_id(self):
return Client.get(self.oauthClient).oauthClientID
def get_scope(self):
return " ".join(self.oauthScope)
def get_expires_in(self):
return int(self.oauthTokenLifetime)
def get_issued_at(self):
return int(
(self.oauthIssueDate - datetime.datetime(1970, 1, 1)).total_seconds()
)
def get_expires_at(self):
issue_timestamp = (
self.oauthIssueDate - datetime.datetime(1970, 1, 1)
).total_seconds()
return int(issue_timestamp) + int(self.oauthTokenLifetime)
def is_refresh_token_active(self):
if self.oauthRevokationDate:
return False
return self.expire_date >= datetime.datetime.now()
def is_expired(self):
return (
self.oauthIssueDate
+ datetime.timedelta(seconds=int(self.oauthTokenLifetime))
< datetime.datetime.now()
)
class Consent(LDAPObject):
object_class = ["oauthConsent"]
base = "ou=consents,ou=oauth"
id = "cn"
def __init__(self, *args, **kwargs):
if "cn" not in kwargs:
kwargs["cn"] = str(uuid.uuid4())
super().__init__(*args, **kwargs)
@property
def issue_date(self):
return self.oauthIssueDate
@property
def revokation_date(self):
return self.oauthRevokationDate
def revoke(self):
self.oauthRevokationDate = datetime.datetime.now()
self.save()
tokens = Token.filter(
oauthClient=self.oauthClient,
oauthSubject=self.oauthSubject,
)
for t in tokens:
if t.revoked or any(
scope not in t.oauthScope[0] for scope in self.oauthScope
):
continue
t.oauthRevokationDate = self.oauthRevokationDate
t.save()

View file

@ -15,11 +15,11 @@ from flask_babel import gettext
from flask_babel import lazy_gettext as _ from flask_babel import lazy_gettext as _
from flask_themer import render_template from flask_themer import render_template
from .flaskutils import current_user from ..flaskutils import current_user
from .forms import FullLoginForm from ..forms import FullLoginForm
from ..models import User
from .models import Client from .models import Client
from .models import Consent from .models import Consent
from .models import User
from .oauth2utils import authorization from .oauth2utils import authorization
from .oauth2utils import DEFAULT_JWT_ALG from .oauth2utils import DEFAULT_JWT_ALG
from .oauth2utils import DEFAULT_JWT_KTY from .oauth2utils import DEFAULT_JWT_KTY
@ -29,7 +29,7 @@ from .oauth2utils import require_oauth
from .oauth2utils import RevocationEndpoint from .oauth2utils import RevocationEndpoint
bp = Blueprint("oauth", __name__) bp = Blueprint("oauth", __name__, url_prefix="/oauth")
CLAIMS = { CLAIMS = {
"profile": ( "profile": (
@ -110,7 +110,7 @@ def authorize():
return jsonify(response) return jsonify(response)
return render_template( return render_template(
"authorize.html", "oidc/user/authorize.html",
user=user, user=user,
grant=grant, grant=grant,
client=client, client=client,

View file

@ -21,11 +21,11 @@ from authlib.oidc.core.grants import OpenIDHybridGrant as _OpenIDHybridGrant
from authlib.oidc.core.grants import OpenIDImplicitGrant as _OpenIDImplicitGrant from authlib.oidc.core.grants import OpenIDImplicitGrant as _OpenIDImplicitGrant
from flask import current_app from flask import current_app
from ..models import Group
from ..models import User
from .models import AuthorizationCode from .models import AuthorizationCode
from .models import Client from .models import Client
from .models import Group
from .models import Token from .models import Token
from .models import User
DEFAULT_JWT_KTY = "RSA" DEFAULT_JWT_KTY = "RSA"
DEFAULT_JWT_ALG = "RS256" DEFAULT_JWT_ALG = "RS256"

View file

@ -1,21 +1,23 @@
from canaille.flaskutils import permissions_needed from canaille.flaskutils import permissions_needed
from canaille.models import Token from canaille.oidc.models import Token
from flask import Blueprint from flask import Blueprint
from flask_themer import render_template from flask_themer import render_template
bp = Blueprint("tokens", __name__) bp = Blueprint("tokens", __name__, url_prefix="/admin/token")
@bp.route("/") @bp.route("/")
@permissions_needed("manage_oidc") @permissions_needed("manage_oidc")
def index(user): def index(user):
tokens = Token.filter() tokens = Token.filter()
return render_template("admin/token_list.html", tokens=tokens, menuitem="admin") return render_template(
"oidc/admin/token_list.html", tokens=tokens, menuitem="admin"
)
@bp.route("/<token_id>", methods=["GET", "POST"]) @bp.route("/<token_id>", methods=["GET", "POST"])
@permissions_needed("manage_oidc") @permissions_needed("manage_oidc")
def view(user, token_id): def view(user, token_id):
token = Token.get(token_id) token = Token.get(token_id)
return render_template("admin/token_view.html", token=token, menuitem="admin") return render_template("oidc/admin/token_view.html", token=token, menuitem="admin")

View file

@ -5,7 +5,7 @@ from flask import current_app
from flask import jsonify from flask import jsonify
bp = Blueprint("home", __name__) bp = Blueprint("home", __name__, url_prefix="/.well-known")
@bp.route("/oauth-authorization-server") @bp.route("/oauth-authorization-server")

View file

@ -22,8 +22,8 @@
</thead> </thead>
{% for authorization in authorizations %} {% for authorization in authorizations %}
<tr> <tr>
<td><a href="{{ url_for('admin.authorizations.view', authorization_id=authorization.oauthCode) }}">{{ authorization.oauthCode }}</a></td> <td><a href="{{ url_for('oidc.authorizations.view', authorization_id=authorization.oauthCode) }}">{{ authorization.oauthCode }}</a></td>
<td><a href="{{ url_for('admin.clients.edit', client_id=authorization.oauthClientID) }}">{{ authorization.oauthClientID }}</a></td> <td><a href="{{ url_for('oidc.clients.edit', client_id=authorization.oauthClientID) }}">{{ authorization.oauthClientID }}</a></td>
<td>{{ authorization.oauthSubject }}</td> <td>{{ authorization.oauthSubject }}</td>
<td>{{ authorization.issue_date }}</td> <td>{{ authorization.issue_date }}</td>
</tr> </tr>

View file

@ -14,7 +14,7 @@
{% block content %} {% block content %}
<div class="ui segment"> <div class="ui segment">
<a class="ui primary button" href="{{ url_for('admin.clients.add') }}">{% trans %}Add client{% endtrans %}</a> <a class="ui primary button" href="{{ url_for('oidc.clients.add') }}">{% trans %}Add client{% endtrans %}</a>
</div> </div>
<table class="ui table"> <table class="ui table">
@ -27,7 +27,7 @@
{% for client in clients %} {% for client in clients %}
<tr> <tr>
<td> <td>
<a href="{{ url_for('admin.clients.edit', client_id=client.oauthClientID) }}"> <a href="{{ url_for('oidc.clients.edit', client_id=client.oauthClientID) }}">
{% if client.oauthLogoURI %} {% if client.oauthLogoURI %}
<img class="ui avatar image" src="{{ client.oauthLogoURI }}" alt="Client logo"> <img class="ui avatar image" src="{{ client.oauthLogoURI }}" alt="Client logo">
{% else %} {% else %}
@ -35,7 +35,7 @@
{% endif %} {% endif %}
</a> </a>
</td> </td>
<td><a href="{{ url_for('admin.clients.edit', client_id=client.oauthClientID) }}">{{ client.oauthClientName }}</a></td> <td><a href="{{ url_for('oidc.clients.edit', client_id=client.oauthClientID) }}">{{ client.oauthClientName }}</a></td>
<td><a href="{{ client.oauthClientURI }}">{{ client.oauthClientURI }}</a></td> <td><a href="{{ client.oauthClientURI }}">{{ client.oauthClientURI }}</a></td>
<td>{% if client.issue_date %}{{ client.issue_date }}{% endif %}</td> <td>{% if client.issue_date %}{{ client.issue_date }}{% endif %}</td>
</tr> </tr>

View file

@ -22,8 +22,8 @@
</thead> </thead>
{% for token in tokens %} {% for token in tokens %}
<tr> <tr>
<td><a href="{{ url_for('admin.tokens.view', token_id=token.oauthAccessToken) }}">{{ token.oauthAccessToken }}</a></td> <td><a href="{{ url_for('oidc.tokens.view', token_id=token.oauthAccessToken) }}">{{ token.oauthAccessToken }}</a></td>
<td><a href="{{ url_for('admin.clients.edit', client_id=token.oauthClientID) }}">{{ token.oauthClientID }}</a></td> <td><a href="{{ url_for('oidc.clients.edit', client_id=token.oauthClientID) }}">{{ token.oauthClientID }}</a></td>
<td>{{ token.oauthSubject }}</td> <td>{{ token.oauthSubject }}</td>
<td>{{ token.issue_date }}</td> <td>{{ token.issue_date }}</td>
</tr> </tr>

View file

@ -49,7 +49,7 @@
</ul> </ul>
</div> </div>
</div> </div>
<a class="ui bottom attached button" href="{{ url_for('consents.delete', consent_id=consent.cn[0] ) }}"> <a class="ui bottom attached button" href="{{ url_for('oidc.consents.delete', consent_id=consent.cn[0] ) }}">
<i class="remove icon"></i> <i class="remove icon"></i>
{% trans %}Remove access{% endtrans %} {% trans %}Remove access{% endtrans %}
</a> </a>

View file

@ -40,7 +40,7 @@
</a> </a>
{% if user.can_use_oidc %} {% if user.can_use_oidc %}
<a class="item {% if menuitem == "consents" %}active{% endif %}" <a class="item {% if menuitem == "consents" %}active{% endif %}"
href="{{ url_for('consents.consents') }}"> href="{{ url_for('oidc.consents.consents') }}">
<i class="handshake icon"></i> <i class="handshake icon"></i>
{% trans %}My consents{% endtrans %} {% trans %}My consents{% endtrans %}
</a> </a>
@ -64,15 +64,15 @@
<i class="settings icon"></i> <i class="settings icon"></i>
Admin Admin
<div class="menu"> <div class="menu">
<a class="item" href="{{ url_for('admin.clients.index') }}"> <a class="item" href="{{ url_for('oidc.clients.index') }}">
<i class="plug icon"></i> <i class="plug icon"></i>
{% trans %}Clients{% endtrans %} {% trans %}Clients{% endtrans %}
</a> </a>
<a class="item" href="{{ url_for('admin.tokens.index') }}"> <a class="item" href="{{ url_for('oidc.tokens.index') }}">
<i class="key icon"></i> <i class="key icon"></i>
{% trans %}Tokens{% endtrans %} {% trans %}Tokens{% endtrans %}
</a> </a>
<a class="item" href="{{ url_for('admin.authorizations.index') }}"> <a class="item" href="{{ url_for('oidc.authorizations.index') }}">
<i class="user secret icon"></i> <i class="user secret icon"></i>
{% trans %}Codes{% endtrans %} {% trans %}Codes{% endtrans %}
</a> </a>

View file

@ -62,15 +62,15 @@
<i class="settings icon"></i> <i class="settings icon"></i>
Admin Admin
<div class="menu"> <div class="menu">
<a class="item" href="{{ url_for('admin.clients.index') }}"> <a class="item" href="{{ url_for('oidc.clients.index') }}">
<i class="plug icon"></i> <i class="plug icon"></i>
{% trans %}Clients{% endtrans %} {% trans %}Clients{% endtrans %}
</a> </a>
<a class="item" href="{{ url_for('admin.tokens.index') }}"> <a class="item" href="{{ url_for('oidc.tokens.index') }}">
<i class="key icon"></i> <i class="key icon"></i>
{% trans %}Tokens{% endtrans %} {% trans %}Tokens{% endtrans %}
</a> </a>
<a class="item" href="{{ url_for('admin.authorizations.index') }}"> <a class="item" href="{{ url_for('oidc.authorizations.index') }}">
<i class="user secret icon"></i> <i class="user secret icon"></i>
{% trans %}Codes{% endtrans %} {% trans %}Codes{% endtrans %}
</a> </a>

View file

@ -1,10 +1,10 @@
import datetime import datetime
import pytest import pytest
from canaille.models import AuthorizationCode from canaille.oidc.models import AuthorizationCode
from canaille.models import Client from canaille.oidc.models import Client
from canaille.models import Consent from canaille.oidc.models import Consent
from canaille.models import Token from canaille.oidc.models import Token
from werkzeug.security import gen_salt from werkzeug.security import gen_salt

View file

@ -3,9 +3,9 @@ from urllib.parse import urlsplit
from authlib.jose import jwt from authlib.jose import jwt
from authlib.oauth2.rfc7636 import create_s256_code_challenge from authlib.oauth2.rfc7636 import create_s256_code_challenge
from canaille.models import AuthorizationCode from canaille.oidc.models import AuthorizationCode
from canaille.models import Consent from canaille.oidc.models import Consent
from canaille.models import Token from canaille.oidc.models import Token
from werkzeug.security import gen_salt from werkzeug.security import gen_salt
from . import client_credentials from . import client_credentials

View file

@ -1,8 +1,8 @@
import datetime import datetime
from canaille.commands import cli from canaille.commands import cli
from canaille.models import AuthorizationCode from canaille.oidc.models import AuthorizationCode
from canaille.models import Token from canaille.oidc.models import Token
from werkzeug.security import gen_salt from werkzeug.security import gen_salt

View file

@ -1,4 +1,4 @@
from canaille.models import Client from canaille.oidc.models import Client
def test_no_logged_no_access(testclient): def test_no_logged_no_access(testclient):

View file

@ -2,9 +2,9 @@ from urllib.parse import parse_qs
from urllib.parse import urlsplit from urllib.parse import urlsplit
from authlib.jose import jwt from authlib.jose import jwt
from canaille.models import AuthorizationCode
from canaille.models import Token
from canaille.models import User from canaille.models import User
from canaille.oidc.models import AuthorizationCode
from canaille.oidc.models import Token
def test_oauth_hybrid(testclient, slapd_connection, user, client): def test_oauth_hybrid(testclient, slapd_connection, user, client):

View file

@ -2,7 +2,7 @@ from urllib.parse import parse_qs
from urllib.parse import urlsplit from urllib.parse import urlsplit
from authlib.jose import jwt from authlib.jose import jwt
from canaille.models import Token from canaille.oidc.models import Token
def test_oauth_implicit(testclient, slapd_connection, user, client): def test_oauth_implicit(testclient, slapd_connection, user, client):

View file

@ -1,5 +1,5 @@
from canaille.models import User from canaille.models import User
from canaille.oauth2utils import generate_user_claims from canaille.oidc.oauth2utils import generate_user_claims
STANDARD_CLAIMS = [ STANDARD_CLAIMS = [
"sub", "sub",

View file

@ -1,4 +1,4 @@
from canaille.models import Token from canaille.oidc.models import Token
from . import client_credentials from . import client_credentials

View file

@ -1,9 +1,8 @@
from urllib.parse import parse_qs from urllib.parse import parse_qs
from urllib.parse import urlsplit from urllib.parse import urlsplit
from canaille.models import AuthorizationCode from canaille.oidc.models import AuthorizationCode
from canaille.models import Client from canaille.oidc.models import Token
from canaille.models import Token
from . import client_credentials from . import client_credentials