OIDC.JWT.MAPPING configuration option is really optional

This commit is contained in:
Éloi Rivard 2023-04-10 20:09:47 +02:00
parent 7cd078bf81
commit cc45ed4be9
7 changed files with 66 additions and 63 deletions

View file

@ -3,11 +3,19 @@ All notable changes to this project will be documented in this file.
The format is based on `Keep a Changelog <https://keepachangelog.com/en/1.0.0/>`_,
and this project adheres to `Semantic Versioning <https://semver.org/spec/v2.0.0.html>`_.
🚨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
=====================

View file

@ -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.

View file

@ -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:

View file

@ -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.

View file

@ -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.

View file

@ -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] }}",
},
}
},
}

View file

@ -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