forked from Github-Mirrors/canaille
split oidc code from the rest
This commit is contained in:
parent
16d2d71194
commit
52e802b34f
37 changed files with 290 additions and 269 deletions
|
@ -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):
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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("/")
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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
17
canaille/oidc/__init__.py
Normal 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)
|
|
@ -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",
|
||||
)
|
|
@ -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"))
|
|
@ -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
182
canaille/oidc/models.py
Normal 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()
|
|
@ -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,
|
|
@ -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"
|
|
@ -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")
|
|
@ -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")
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
||||
|
|
6
tests/fixtures/themes/test/base.html
vendored
6
tests/fixtures/themes/test/base.html
vendored
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from canaille.models import Client
|
||||
from canaille.oidc.models import Client
|
||||
|
||||
|
||||
def test_no_logged_no_access(testclient):
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from canaille.models import Token
|
||||
from canaille.oidc.models import Token
|
||||
|
||||
from . import client_credentials
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in a new issue