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

View file

@ -1,13 +1,7 @@
from flask import Blueprint
from . import authorizations
from . import clients
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(authorizations.bp, url_prefix="/authorization")
bp.register_blueprint(clients.bp, url_prefix="/client")
bp.register_blueprint(mail.bp, url_prefix="/mail")
bp.register_blueprint(mail.bp)

View file

@ -15,7 +15,7 @@ from wtforms.validators import DataRequired
from wtforms.validators import Email
bp = Blueprint("mails", __name__)
bp = Blueprint("mails", __name__, url_prefix="/mail")
class MailTestForm(FlaskForm):
@ -43,7 +43,7 @@ def mail_index(user):
else:
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")

View file

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

View file

@ -13,7 +13,7 @@ from .forms import GroupForm
from .forms import unique_group
from .models import Group
bp = Blueprint("groups", __name__)
bp = Blueprint("groups", __name__, url_prefix="/groups")
@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.asymmetric import rsa
from .models import AuthorizationCode
from .models import Client
from .models import Consent
from .models import Token
from .oidc.models import AuthorizationCode
from .oidc.models import Client
from .oidc.models import Consent
from .oidc.models import Token
class InstallationException(Exception):

View file

@ -1,11 +1,4 @@
import datetime
import uuid
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 session
@ -229,176 +222,3 @@ class Group(LDAPObject):
def remove_member(self, user, conn=None):
self.member = [m for m in self.member if m != user.dn]
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.models import AuthorizationCode
from canaille.oidc.models import AuthorizationCode
from flask import Blueprint
from flask_themer import render_template
bp = Blueprint("authorizations", __name__)
bp = Blueprint("authorizations", __name__, url_prefix="/admin/authorization")
@bp.route("/")
@ -12,7 +12,7 @@ bp = Blueprint("authorizations", __name__)
def index(user):
authorizations = AuthorizationCode.filter()
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):
authorization = AuthorizationCode.get(authorization_id)
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
from canaille.flaskutils import permissions_needed
from canaille.models import Client
from canaille.oidc.models import Client
from flask import abort
from flask import Blueprint
from flask import flash
@ -15,14 +15,16 @@ from flask_wtf import FlaskForm
from werkzeug.security import gen_salt
bp = Blueprint("clients", __name__)
bp = Blueprint("clients", __name__, url_prefix="/admin/client")
@bp.route("/")
@permissions_needed("manage_oidc")
def index(user):
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():
@ -138,14 +140,18 @@ def add(user):
form = ClientAdd(request.form or None)
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():
flash(
_("The client has not been added. Please check your information."),
"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_issued_at = datetime.datetime.now()
@ -179,7 +185,7 @@ def add(user):
"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"])
@ -204,7 +210,7 @@ def client_edit(client_id):
if not request.form:
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():
@ -240,7 +246,7 @@ def client_edit(client_id):
)
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",
)
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.models import Client
from canaille.models import Consent
from canaille.oidc.models import Client
from canaille.oidc.models import Consent
from flask import Blueprint
from flask import flash
from flask import redirect
@ -9,7 +9,7 @@ from flask_babel import gettext
from flask_themer import render_template
bp = Blueprint("consents", __name__)
bp = Blueprint("consents", __name__, url_prefix="/consent")
@bp.route("/")
@ -20,7 +20,10 @@ def consents(user):
client_dns = list({t.oauthClient for t in consents})
clients = {dn: Client.get(dn) for dn in client_dns}
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()
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_themer import render_template
from .flaskutils import current_user
from .forms import FullLoginForm
from ..flaskutils import current_user
from ..forms import FullLoginForm
from ..models import User
from .models import Client
from .models import Consent
from .models import User
from .oauth2utils import authorization
from .oauth2utils import DEFAULT_JWT_ALG
from .oauth2utils import DEFAULT_JWT_KTY
@ -29,7 +29,7 @@ from .oauth2utils import require_oauth
from .oauth2utils import RevocationEndpoint
bp = Blueprint("oauth", __name__)
bp = Blueprint("oauth", __name__, url_prefix="/oauth")
CLAIMS = {
"profile": (
@ -110,7 +110,7 @@ def authorize():
return jsonify(response)
return render_template(
"authorize.html",
"oidc/user/authorize.html",
user=user,
grant=grant,
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 flask import current_app
from ..models import Group
from ..models import User
from .models import AuthorizationCode
from .models import Client
from .models import Group
from .models import Token
from .models import User
DEFAULT_JWT_KTY = "RSA"
DEFAULT_JWT_ALG = "RS256"

View file

@ -1,21 +1,23 @@
from canaille.flaskutils import permissions_needed
from canaille.models import Token
from canaille.oidc.models import Token
from flask import Blueprint
from flask_themer import render_template
bp = Blueprint("tokens", __name__)
bp = Blueprint("tokens", __name__, url_prefix="/admin/token")
@bp.route("/")
@permissions_needed("manage_oidc")
def index(user):
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"])
@permissions_needed("manage_oidc")
def view(user, 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
bp = Blueprint("home", __name__)
bp = Blueprint("home", __name__, url_prefix="/.well-known")
@bp.route("/oauth-authorization-server")

View file

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

View file

@ -14,7 +14,7 @@
{% block content %}
<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>
<table class="ui table">
@ -27,7 +27,7 @@
{% for client in clients %}
<tr>
<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 %}
<img class="ui avatar image" src="{{ client.oauthLogoURI }}" alt="Client logo">
{% else %}
@ -35,7 +35,7 @@
{% endif %}
</a>
</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>{% if client.issue_date %}{{ client.issue_date }}{% endif %}</td>
</tr>

View file

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

View file

@ -49,7 +49,7 @@
</ul>
</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>
{% trans %}Remove access{% endtrans %}
</a>

View file

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

View file

@ -62,15 +62,15 @@
<i class="settings icon"></i>
Admin
<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>
{% trans %}Clients{% endtrans %}
</a>
<a class="item" href="{{ url_for('admin.tokens.index') }}">
<a class="item" href="{{ url_for('oidc.tokens.index') }}">
<i class="key icon"></i>
{% trans %}Tokens{% endtrans %}
</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>
{% trans %}Codes{% endtrans %}
</a>

View file

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

View file

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

View file

@ -1,8 +1,8 @@
import datetime
from canaille.commands import cli
from canaille.models import AuthorizationCode
from canaille.models import Token
from canaille.oidc.models import AuthorizationCode
from canaille.oidc.models import Token
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):

View file

@ -2,9 +2,9 @@ from urllib.parse import parse_qs
from urllib.parse import urlsplit
from authlib.jose import jwt
from canaille.models import AuthorizationCode
from canaille.models import Token
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):

View file

@ -2,7 +2,7 @@ from urllib.parse import parse_qs
from urllib.parse import urlsplit
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):

View file

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

View file

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

View file

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