From cc45ed4be962e881be4e0ee620842c68980582fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89loi=20Rivard?= Date: Mon, 10 Apr 2023 20:09:47 +0200 Subject: [PATCH] OIDC.JWT.MAPPING configuration option is really optional --- CHANGES.rst | 10 +++++++++- canaille/conf/config.sample.toml | 22 +++++++++++----------- canaille/oidc/oauth.py | 21 ++++++++++++++++++--- demo/conf-docker/canaille.toml | 22 +++++++++++----------- demo/conf/canaille.toml | 22 +++++++++++----------- tests/oidc/conftest.py | 13 ------------- tests/oidc/test_userinfo.py | 19 ++++++------------- 7 files changed, 66 insertions(+), 63 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index 535a7c41..340cd797 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -3,11 +3,19 @@ All notable changes to this project will be documented in this file. The format is based on `Keep a Changelog `_, and this project adheres to `Semantic Versioning `_. + +🚨Configuration files must be updated.🚨 + Changed ******* - Renamed user model attributes to match SCIM naming convention. :pr:`123` - 🚨Configuration files must be updated. See the changes in the PR.🚨 +- Moved OIDC related configuration entries in ``OIDC`` + +Fixed +***** + +- ``OIDC.JWT.MAPPING`` is really optional now. [0.0.24] - 2023-04-07 ===================== diff --git a/canaille/conf/config.sample.toml b/canaille/conf/config.sample.toml index 6600e14d..59c38aa5 100644 --- a/canaille/conf/config.sample.toml +++ b/canaille/conf/config.sample.toml @@ -187,17 +187,17 @@ PUBLIC_KEY = "canaille/conf/public.pem" # User objectClass. # {attribute} will be replaced by the user ldap attribute value. # Default values fits inetOrgPerson. -SUB = "{{ user.user_name[0] }}" -NAME = "{{ user.formatted_name[0] }}" -PHONE_NUMBER = "{{ user.phone_number[0] }}" -EMAIL = "{{ user.mail[0] }}" -GIVEN_NAME = "{{ user.given_name[0] }}" -FAMILY_NAME = "{{ user.family_name[0] }}" -PREFERRED_USERNAME = "{{ user.display_name }}" -LOCALE = "{{ user.preferred_language }}" -ADDRESS = "{{ user.formatted_address[0] }}" -PICTURE = "{% if user.photo %}{{ url_for('account.photo', user_name=user.user_name[0], field='photo', _external=True) }}{% endif %}" -WEBSITE = "{{ user.profile_url[0] }}" +# SUB = "{{ user.user_name[0] }}" +# NAME = "{{ user.formatted_name[0] }}" +# PHONE_NUMBER = "{{ user.phone_number[0] }}" +# EMAIL = "{{ user.mail[0] }}" +# GIVEN_NAME = "{{ user.given_name[0] }}" +# FAMILY_NAME = "{{ user.family_name[0] }}" +# PREFERRED_USERNAME = "{{ user.display_name }}" +# LOCALE = "{{ user.preferred_language }}" +# ADDRESS = "{{ user.formatted_address[0] }}" +# PICTURE = "{% if user.photo %}{{ url_for('account.photo', user_name=user.user_name[0], field='photo', _external=True) }}{% endif %}" +# WEBSITE = "{{ user.profile_url[0] }}" # The SMTP server options. If not set, mail related features such as # user invitations, and password reset emails, will be disabled. diff --git a/canaille/oidc/oauth.py b/canaille/oidc/oauth.py index f31a379f..19e3d52a 100644 --- a/canaille/oidc/oauth.py +++ b/canaille/oidc/oauth.py @@ -39,6 +39,19 @@ DEFAULT_JWT_KTY = "RSA" DEFAULT_JWT_ALG = "RS256" DEFAULT_JWT_EXP = 3600 AUTHORIZATION_CODE_LIFETIME = 84400 +DEFAULT_JWT_MAPPING = { + "SUB": "{{ user.user_name[0] }}", + "NAME": "{{ user.formatted_name[0] }}", + "PHONE_NUMBER": "{{ user.phone_number[0] }}", + "EMAIL": "{{ user.email[0] }}", + "GIVEN_NAME": "{{ user.given_name[0] }}", + "FAMILY_NAME": "{{ user.family_name[0] }}", + "PREFERRED_USERNAME": "{{ user.display_name }}", + "LOCALE": "{{ user.preferred_language }}", + "ADDRESS": "{{ user.formatted_address[0] }}", + "PICTURE": "{% if user.photo %}{{ url_for('account.photo', user_name=user.user_name[0], field='photo', _external=True) }}{% endif %}", + "WEBSITE": "{{ user.profile_url[0] }}", +} def exists_nonce(nonce, req): @@ -103,9 +116,11 @@ def generate_user_info(user, scope): def generate_user_claims(user, claims, jwt_mapping_config=None): - jwt_mapping_config = ( - jwt_mapping_config or current_app.config["OIDC"]["JWT"]["MAPPING"] - ) + jwt_mapping_config = { + **DEFAULT_JWT_MAPPING, + **current_app.config["OIDC"]["JWT"].get("MAPPING", {}), + **(jwt_mapping_config or {}), + } data = {} for claim in claims: diff --git a/demo/conf-docker/canaille.toml b/demo/conf-docker/canaille.toml index 67786234..8042d580 100644 --- a/demo/conf-docker/canaille.toml +++ b/demo/conf-docker/canaille.toml @@ -192,17 +192,17 @@ PUBLIC_KEY = "conf/public.pem" # User objectClass. # {attribute} will be replaced by the user ldap attribute value. # Default values fits inetOrgPerson. -SUB = "{{ user.user_name[0] }}" -NAME = "{{ user.formatted_name[0] }}" -PHONE_NUMBER = "{{ user.phone_number[0] }}" -EMAIL = "{{ user.email[0] }}" -GIVEN_NAME = "{{ user.given_name[0] }}" -FAMILY_NAME = "{{ user.family_name[0] }}" -PREFERRED_USERNAME = "{{ user.display_name }}" -LOCALE = "{{ user.preferred_language }}" -ADDRESS = "{{ user.formatted_address[0] }}" -PICTURE = "{% if user.photo %}{{ url_for('account.photo', user_name=user.user_name[0], field='photo', _external=True) }}{% endif %}" -WEBSITE = "{{ user.profile_url[0] }}" +# SUB = "{{ user.user_name[0] }}" +# NAME = "{{ user.formatted_name[0] }}" +# PHONE_NUMBER = "{{ user.phone_number[0] }}" +# EMAIL = "{{ user.email[0] }}" +# GIVEN_NAME = "{{ user.given_name[0] }}" +# FAMILY_NAME = "{{ user.family_name[0] }}" +# PREFERRED_USERNAME = "{{ user.display_name }}" +# LOCALE = "{{ user.preferred_language }}" +# ADDRESS = "{{ user.formatted_address[0] }}" +# PICTURE = "{% if user.photo %}{{ url_for('account.photo', user_name=user.user_name[0], field='photo', _external=True) }}{% endif %}" +# WEBSITE = "{{ user.profile_url[0] }}" # The SMTP server options. If not set, mail related features such as # user invitations, and password reset emails, will be disabled. diff --git a/demo/conf/canaille.toml b/demo/conf/canaille.toml index 6829b24d..81dadf35 100644 --- a/demo/conf/canaille.toml +++ b/demo/conf/canaille.toml @@ -193,17 +193,17 @@ PUBLIC_KEY = "conf/public.pem" # User objectClass. # {attribute} will be replaced by the user ldap attribute value. # Default values fits inetOrgPerson. -SUB = "{{ user.user_name[0] }}" -NAME = "{{ user.formatted_name[0] }}" -PHONE_NUMBER = "{{ user.phone_number[0] }}" -EMAIL = "{{ user.email[0] }}" -GIVEN_NAME = "{{ user.given_name[0] }}" -FAMILY_NAME = "{{ user.family_name[0] }}" -PREFERRED_USERNAME = "{{ user.display_name }}" -LOCALE = "{{ user.preferred_language }}" -ADDRESS = "{{ user.formatted_address[0] }}" -PICTURE = "{% if user.photo %}{{ url_for('account.photo', user_name=user.user_name[0], field='photo', _external=True) }}{% endif %}" -WEBSITE = "{{ user.profile_url[0] }}" +# SUB = "{{ user.user_name[0] }}" +# NAME = "{{ user.formatted_name[0] }}" +# PHONE_NUMBER = "{{ user.phone_number[0] }}" +# EMAIL = "{{ user.email[0] }}" +# GIVEN_NAME = "{{ user.given_name[0] }}" +# FAMILY_NAME = "{{ user.family_name[0] }}" +# PREFERRED_USERNAME = "{{ user.display_name }}" +# LOCALE = "{{ user.preferred_language }}" +# ADDRESS = "{{ user.formatted_address[0] }}" +# PICTURE = "{% if user.photo %}{{ url_for('account.photo', user_name=user.user_name[0], field='photo', _external=True) }}{% endif %}" +# WEBSITE = "{{ user.profile_url[0] }}" # The SMTP server options. If not set, mail related features such as # user invitations, and password reset emails, will be disabled. diff --git a/tests/oidc/conftest.py b/tests/oidc/conftest.py index 54c643ce..efe9f559 100644 --- a/tests/oidc/conftest.py +++ b/tests/oidc/conftest.py @@ -63,19 +63,6 @@ def configuration(configuration, keypair_path): "PUBLIC_KEY": public_key_path, "PRIVATE_KEY": private_key_path, "ISS": "https://auth.mydomain.tld", - "MAPPING": { - "SUB": "{{ user.user_name[0] }}", - "NAME": "{{ user.formatted_name[0] }}", - "PHONE_NUMBER": "{{ user.phone_number[0] }}", - "EMAIL": "{{ user.email[0] }}", - "GIVEN_NAME": "{{ user.given_name[0] }}", - "FAMILY_NAME": "{{ user.family_name[0] }}", - "PREFERRED_USERNAME": "{{ user.display_name }}", - "LOCALE": "{{ user.preferred_language }}", - "PICTURE": "{% if user.photo %}{{ url_for('account.photo', user_name=user.user_name[0], field='photo', _external=True) }}{% endif %}", - "ADDRESS": "{{ user.formatted_address[0] }}", - "WEBSITE": "{{ user.profile_url[0] }}", - }, } }, } diff --git a/tests/oidc/test_userinfo.py b/tests/oidc/test_userinfo.py index f178b318..61ac3da9 100644 --- a/tests/oidc/test_userinfo.py +++ b/tests/oidc/test_userinfo.py @@ -1,4 +1,5 @@ from canaille.oidc.oauth import claims_from_scope +from canaille.oidc.oauth import DEFAULT_JWT_MAPPING from canaille.oidc.oauth import generate_user_claims @@ -261,16 +262,6 @@ STANDARD_CLAIMS = [ "address", "updated_at", ] -DEFAULT_JWT_MAPPING_CONFIG = { - "SUB": "{{ user.user_name[0] }}", - "NAME": "{{ user.formatted_name[0] }}", - "PHONE_NUMBER": "{{ user.phone_number[0] }}", - "EMAIL": "{{ user.email[0] }}", - "GIVEN_NAME": "{{ user.given_name[0] }}", - "FAMILY_NAME": "{{ user.family_name[0] }}", - "PREFERRED_USERNAME": "{{ user.display_name }}", - "LOCALE": "{{ user.preferred_language }}", -} def test_generate_user_standard_claims_with_default_config( @@ -278,9 +269,10 @@ def test_generate_user_standard_claims_with_default_config( ): user.preferred_language = ["fr"] - data = generate_user_claims(user, STANDARD_CLAIMS, DEFAULT_JWT_MAPPING_CONFIG) + data = generate_user_claims(user, STANDARD_CLAIMS, DEFAULT_JWT_MAPPING) assert data == { + "address": "1235, somewhere", "sub": "user", "name": "John (johnny) Doe", "family_name": "Doe", @@ -288,13 +280,14 @@ def test_generate_user_standard_claims_with_default_config( "email": "john@doe.com", "locale": "fr", "phone_number": "555-000-000", + "website": "https://john.example", } def test_custom_config_format_claim_is_well_formated( testclient, slapd_connection, user ): - jwt_mapping_config = DEFAULT_JWT_MAPPING_CONFIG.copy() + jwt_mapping_config = DEFAULT_JWT_MAPPING.copy() jwt_mapping_config["EMAIL"] = "{{ user.user_name[0] }}@mydomain.tld" data = generate_user_claims(user, STANDARD_CLAIMS, jwt_mapping_config) @@ -308,6 +301,6 @@ def test_claim_is_omitted_if_empty(testclient, slapd_connection, user): user.email = "" user.save() - data = generate_user_claims(user, STANDARD_CLAIMS, DEFAULT_JWT_MAPPING_CONFIG) + data = generate_user_claims(user, STANDARD_CLAIMS, DEFAULT_JWT_MAPPING) assert "email" not in data