forked from Github-Mirrors/canaille
Issuer 'ISS' configuration option is not mandatory anymore
This commit is contained in:
parent
a353a59db8
commit
77ae9df2a9
9 changed files with 45 additions and 11 deletions
|
@ -35,6 +35,7 @@ Changed
|
||||||
manually edit ``oauth-authorizationserver.json`` and
|
manually edit ``oauth-authorizationserver.json`` and
|
||||||
``openid-configuration.json``. :pr:`71`
|
``openid-configuration.json``. :pr:`71`
|
||||||
- The `FROM_ADDR` configuration option is not mandatory anymore. :pr:`73`
|
- The `FROM_ADDR` configuration option is not mandatory anymore. :pr:`73`
|
||||||
|
- The `JWT.ISS` configuration option is not mandatory anymore. :pr:`74`
|
||||||
|
|
||||||
[0.0.12] - 2022-10-24
|
[0.0.12] - 2022-10-24
|
||||||
=====================
|
=====================
|
||||||
|
|
|
@ -12,10 +12,10 @@ SECRET_KEY = "change me before you go in production"
|
||||||
# PREFERRED_URL_SCHEME = "https"
|
# PREFERRED_URL_SCHEME = "https"
|
||||||
|
|
||||||
# You can display a logo to be recognized on login screens
|
# You can display a logo to be recognized on login screens
|
||||||
LOGO = "/static/img/canaille-head.png"
|
# LOGO = "/static/img/canaille-head.png"
|
||||||
|
|
||||||
# Your favicon. If unset the LOGO will be used.
|
# Your favicon. If unset the LOGO will be used.
|
||||||
FAVICON = "/static/img/canaille-c.png"
|
# FAVICON = "/static/img/canaille-c.png"
|
||||||
|
|
||||||
# The name of a theme in the 'theme' directory, or an absolute path
|
# The name of a theme in the 'theme' directory, or an absolute path
|
||||||
# to a theme. Defaults to 'default'. Theming is done with
|
# to a theme. Defaults to 'default'. Theming is done with
|
||||||
|
@ -153,7 +153,7 @@ PRIVATE_KEY = "canaille/conf/private.pem"
|
||||||
# The path to the public key.
|
# The path to the public key.
|
||||||
PUBLIC_KEY = "canaille/conf/public.pem"
|
PUBLIC_KEY = "canaille/conf/public.pem"
|
||||||
# The URI of the identity provider
|
# The URI of the identity provider
|
||||||
ISS = "https://auth.mydomain.tld"
|
# ISS = "https://auth.mydomain.tld"
|
||||||
# The key type parameter
|
# The key type parameter
|
||||||
# KTY = "RSA"
|
# KTY = "RSA"
|
||||||
# The key algorithm
|
# The key algorithm
|
||||||
|
|
|
@ -31,6 +31,7 @@ from .oauth import ClientRegistrationEndpoint
|
||||||
from .oauth import DEFAULT_JWT_ALG
|
from .oauth import DEFAULT_JWT_ALG
|
||||||
from .oauth import DEFAULT_JWT_KTY
|
from .oauth import DEFAULT_JWT_KTY
|
||||||
from .oauth import generate_user_info
|
from .oauth import generate_user_info
|
||||||
|
from .oauth import get_issuer
|
||||||
from .oauth import IntrospectionEndpoint
|
from .oauth import IntrospectionEndpoint
|
||||||
from .oauth import require_oauth
|
from .oauth import require_oauth
|
||||||
from .oauth import RevocationEndpoint
|
from .oauth import RevocationEndpoint
|
||||||
|
@ -281,7 +282,7 @@ def end_session():
|
||||||
|
|
||||||
if data.get("id_token_hint"):
|
if data.get("id_token_hint"):
|
||||||
id_token = jwt.decode(data["id_token_hint"], get_public_key())
|
id_token = jwt.decode(data["id_token_hint"], get_public_key())
|
||||||
if not id_token["iss"] == current_app.config["JWT"]["ISS"]:
|
if not id_token["iss"] == get_issuer():
|
||||||
return jsonify(
|
return jsonify(
|
||||||
{
|
{
|
||||||
"status": "error",
|
"status": "error",
|
||||||
|
|
|
@ -24,6 +24,7 @@ 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 authlib.oidc.core.grants.util import generate_id_token
|
from authlib.oidc.core.grants.util import generate_id_token
|
||||||
from flask import current_app
|
from flask import current_app
|
||||||
|
from flask import request
|
||||||
from werkzeug.security import gen_salt
|
from werkzeug.security import gen_salt
|
||||||
|
|
||||||
from ..models import Group
|
from ..models import Group
|
||||||
|
@ -42,13 +43,23 @@ def exists_nonce(nonce, req):
|
||||||
return bool(exists)
|
return bool(exists)
|
||||||
|
|
||||||
|
|
||||||
|
def get_issuer():
|
||||||
|
if current_app.config["JWT"].get("ISS"):
|
||||||
|
return current_app.config["JWT"].get("ISS")
|
||||||
|
|
||||||
|
if current_app.config.get("SERVER_NAME"):
|
||||||
|
return current_app.config.get("SERVER_NAME")
|
||||||
|
|
||||||
|
return request.url_root
|
||||||
|
|
||||||
|
|
||||||
def get_jwt_config(grant):
|
def get_jwt_config(grant):
|
||||||
|
|
||||||
with open(current_app.config["JWT"]["PRIVATE_KEY"]) as pk:
|
with open(current_app.config["JWT"]["PRIVATE_KEY"]) as pk:
|
||||||
return {
|
return {
|
||||||
"key": pk.read(),
|
"key": pk.read(),
|
||||||
"alg": current_app.config["JWT"].get("ALG", DEFAULT_JWT_ALG),
|
"alg": current_app.config["JWT"].get("ALG", DEFAULT_JWT_ALG),
|
||||||
"iss": current_app.config["JWT"]["ISS"],
|
"iss": get_issuer(),
|
||||||
"exp": current_app.config["JWT"].get("EXP", DEFAULT_JWT_EXP),
|
"exp": current_app.config["JWT"].get("EXP", DEFAULT_JWT_EXP),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -302,7 +313,7 @@ class IntrospectionEndpoint(_IntrospectionEndpoint):
|
||||||
"scope": token.get_scope(),
|
"scope": token.get_scope(),
|
||||||
"sub": user.uid[0],
|
"sub": user.uid[0],
|
||||||
"aud": audience,
|
"aud": audience,
|
||||||
"iss": current_app.config["JWT"]["ISS"],
|
"iss": get_issuer(),
|
||||||
"exp": token.get_expires_at(),
|
"exp": token.get_expires_at(),
|
||||||
"iat": token.get_issued_at(),
|
"iat": token.get_issued_at(),
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,8 @@ from flask import jsonify
|
||||||
from flask import request
|
from flask import request
|
||||||
from flask import url_for
|
from flask import url_for
|
||||||
|
|
||||||
|
from .oauth import get_issuer
|
||||||
|
|
||||||
|
|
||||||
bp = Blueprint("home", __name__, url_prefix="/.well-known")
|
bp = Blueprint("home", __name__, url_prefix="/.well-known")
|
||||||
|
|
||||||
|
@ -15,9 +17,8 @@ def cached_oauth_authorization_server():
|
||||||
if "oauth_authorization_server" in g:
|
if "oauth_authorization_server" in g:
|
||||||
return g.oauth_authorization_server
|
return g.oauth_authorization_server
|
||||||
|
|
||||||
issuer = current_app.config["JWT"]["ISS"]
|
|
||||||
g.oauth_authorization_server = {
|
g.oauth_authorization_server = {
|
||||||
"issuer": issuer,
|
"issuer": get_issuer(),
|
||||||
"authorization_endpoint": url_for("oidc.endpoints.authorize", _external=True),
|
"authorization_endpoint": url_for("oidc.endpoints.authorize", _external=True),
|
||||||
"token_endpoint": url_for("oidc.endpoints.issue_token", _external=True),
|
"token_endpoint": url_for("oidc.endpoints.issue_token", _external=True),
|
||||||
"token_endpoint_auth_methods_supported": [
|
"token_endpoint_auth_methods_supported": [
|
||||||
|
|
|
@ -159,7 +159,7 @@ PRIVATE_KEY = "conf/private.pem"
|
||||||
# The path to the public key.
|
# The path to the public key.
|
||||||
PUBLIC_KEY = "conf/public.pem"
|
PUBLIC_KEY = "conf/public.pem"
|
||||||
# The URI of the identity provider
|
# The URI of the identity provider
|
||||||
ISS = "http://localhost:5000"
|
# ISS = "https://auth.mydomain.tld"
|
||||||
# The key type parameter
|
# The key type parameter
|
||||||
# KTY = "RSA"
|
# KTY = "RSA"
|
||||||
# The key algorithm
|
# The key algorithm
|
||||||
|
|
|
@ -159,7 +159,7 @@ PRIVATE_KEY = "conf/private.pem"
|
||||||
# The path to the public key.
|
# The path to the public key.
|
||||||
PUBLIC_KEY = "conf/public.pem"
|
PUBLIC_KEY = "conf/public.pem"
|
||||||
# The URI of the identity provider
|
# The URI of the identity provider
|
||||||
ISS = "http://localhost:5000"
|
# ISS = "https://auth.mydomain.tld"
|
||||||
# The key type parameter
|
# The key type parameter
|
||||||
# KTY = "RSA"
|
# KTY = "RSA"
|
||||||
# The key algorithm
|
# The key algorithm
|
||||||
|
|
|
@ -171,7 +171,8 @@ Canaille needs a key pair to sign the JWT. The installation command will generat
|
||||||
e.g. ``/path/to/canaille/conf/private.pem``
|
e.g. ``/path/to/canaille/conf/private.pem``
|
||||||
|
|
||||||
:ISS:
|
:ISS:
|
||||||
**Required.** The URI of the identity provider.
|
*Optional.* The URI of the identity provider.
|
||||||
|
Defaults to ``SERVER_NAME`` if set, else the current domain will be used.
|
||||||
e.g. ``https://auth.mydomain.tld``
|
e.g. ``https://auth.mydomain.tld``
|
||||||
|
|
||||||
:KTY:
|
:KTY:
|
||||||
|
|
19
tests/oidc/test_configuration.py
Normal file
19
tests/oidc/test_configuration.py
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
import warnings
|
||||||
|
|
||||||
|
from canaille.oidc.oauth import get_issuer
|
||||||
|
|
||||||
|
|
||||||
|
def test_issuer(testclient):
|
||||||
|
with warnings.catch_warnings(record=True):
|
||||||
|
testclient.app.config["JWT"]["ISS"] = "https://anyauth.mydomain.tld"
|
||||||
|
testclient.app.config["SERVER_NAME"] = "https://otherauth.mydomain.tld"
|
||||||
|
with testclient.app.test_request_context("/"):
|
||||||
|
assert get_issuer() == "https://anyauth.mydomain.tld"
|
||||||
|
|
||||||
|
del testclient.app.config["JWT"]["ISS"]
|
||||||
|
with testclient.app.test_request_context("/"):
|
||||||
|
assert get_issuer() == "https://otherauth.mydomain.tld"
|
||||||
|
|
||||||
|
testclient.app.config["SERVER_NAME"] = None
|
||||||
|
with testclient.app.test_request_context("/"):
|
||||||
|
assert get_issuer() == "http://localhost/"
|
Loading…
Reference in a new issue