forked from Github-Mirrors/canaille
OIDC.JWT.MAPPING configuration option is really optional
This commit is contained in:
parent
7cd078bf81
commit
cc45ed4be9
7 changed files with 66 additions and 63 deletions
10
CHANGES.rst
10
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 <https://keepachangelog.com/en/1.0.0/>`_,
|
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>`_.
|
and this project adheres to `Semantic Versioning <https://semver.org/spec/v2.0.0.html>`_.
|
||||||
|
|
||||||
|
|
||||||
|
🚨Configuration files must be updated.🚨
|
||||||
|
|
||||||
Changed
|
Changed
|
||||||
*******
|
*******
|
||||||
|
|
||||||
- Renamed user model attributes to match SCIM naming convention. :pr:`123`
|
- 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
|
[0.0.24] - 2023-04-07
|
||||||
=====================
|
=====================
|
||||||
|
|
|
@ -187,17 +187,17 @@ PUBLIC_KEY = "canaille/conf/public.pem"
|
||||||
# User objectClass.
|
# User objectClass.
|
||||||
# {attribute} will be replaced by the user ldap attribute value.
|
# {attribute} will be replaced by the user ldap attribute value.
|
||||||
# Default values fits inetOrgPerson.
|
# Default values fits inetOrgPerson.
|
||||||
SUB = "{{ user.user_name[0] }}"
|
# SUB = "{{ user.user_name[0] }}"
|
||||||
NAME = "{{ user.formatted_name[0] }}"
|
# NAME = "{{ user.formatted_name[0] }}"
|
||||||
PHONE_NUMBER = "{{ user.phone_number[0] }}"
|
# PHONE_NUMBER = "{{ user.phone_number[0] }}"
|
||||||
EMAIL = "{{ user.mail[0] }}"
|
# EMAIL = "{{ user.mail[0] }}"
|
||||||
GIVEN_NAME = "{{ user.given_name[0] }}"
|
# GIVEN_NAME = "{{ user.given_name[0] }}"
|
||||||
FAMILY_NAME = "{{ user.family_name[0] }}"
|
# FAMILY_NAME = "{{ user.family_name[0] }}"
|
||||||
PREFERRED_USERNAME = "{{ user.display_name }}"
|
# PREFERRED_USERNAME = "{{ user.display_name }}"
|
||||||
LOCALE = "{{ user.preferred_language }}"
|
# LOCALE = "{{ user.preferred_language }}"
|
||||||
ADDRESS = "{{ user.formatted_address[0] }}"
|
# ADDRESS = "{{ user.formatted_address[0] }}"
|
||||||
PICTURE = "{% if user.photo %}{{ url_for('account.photo', user_name=user.user_name[0], field='photo', _external=True) }}{% endif %}"
|
# PICTURE = "{% if user.photo %}{{ url_for('account.photo', user_name=user.user_name[0], field='photo', _external=True) }}{% endif %}"
|
||||||
WEBSITE = "{{ user.profile_url[0] }}"
|
# WEBSITE = "{{ user.profile_url[0] }}"
|
||||||
|
|
||||||
# The SMTP server options. If not set, mail related features such as
|
# The SMTP server options. If not set, mail related features such as
|
||||||
# user invitations, and password reset emails, will be disabled.
|
# user invitations, and password reset emails, will be disabled.
|
||||||
|
|
|
@ -39,6 +39,19 @@ DEFAULT_JWT_KTY = "RSA"
|
||||||
DEFAULT_JWT_ALG = "RS256"
|
DEFAULT_JWT_ALG = "RS256"
|
||||||
DEFAULT_JWT_EXP = 3600
|
DEFAULT_JWT_EXP = 3600
|
||||||
AUTHORIZATION_CODE_LIFETIME = 84400
|
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):
|
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):
|
def generate_user_claims(user, claims, jwt_mapping_config=None):
|
||||||
jwt_mapping_config = (
|
jwt_mapping_config = {
|
||||||
jwt_mapping_config or current_app.config["OIDC"]["JWT"]["MAPPING"]
|
**DEFAULT_JWT_MAPPING,
|
||||||
)
|
**current_app.config["OIDC"]["JWT"].get("MAPPING", {}),
|
||||||
|
**(jwt_mapping_config or {}),
|
||||||
|
}
|
||||||
|
|
||||||
data = {}
|
data = {}
|
||||||
for claim in claims:
|
for claim in claims:
|
||||||
|
|
|
@ -192,17 +192,17 @@ PUBLIC_KEY = "conf/public.pem"
|
||||||
# User objectClass.
|
# User objectClass.
|
||||||
# {attribute} will be replaced by the user ldap attribute value.
|
# {attribute} will be replaced by the user ldap attribute value.
|
||||||
# Default values fits inetOrgPerson.
|
# Default values fits inetOrgPerson.
|
||||||
SUB = "{{ user.user_name[0] }}"
|
# SUB = "{{ user.user_name[0] }}"
|
||||||
NAME = "{{ user.formatted_name[0] }}"
|
# NAME = "{{ user.formatted_name[0] }}"
|
||||||
PHONE_NUMBER = "{{ user.phone_number[0] }}"
|
# PHONE_NUMBER = "{{ user.phone_number[0] }}"
|
||||||
EMAIL = "{{ user.email[0] }}"
|
# EMAIL = "{{ user.email[0] }}"
|
||||||
GIVEN_NAME = "{{ user.given_name[0] }}"
|
# GIVEN_NAME = "{{ user.given_name[0] }}"
|
||||||
FAMILY_NAME = "{{ user.family_name[0] }}"
|
# FAMILY_NAME = "{{ user.family_name[0] }}"
|
||||||
PREFERRED_USERNAME = "{{ user.display_name }}"
|
# PREFERRED_USERNAME = "{{ user.display_name }}"
|
||||||
LOCALE = "{{ user.preferred_language }}"
|
# LOCALE = "{{ user.preferred_language }}"
|
||||||
ADDRESS = "{{ user.formatted_address[0] }}"
|
# ADDRESS = "{{ user.formatted_address[0] }}"
|
||||||
PICTURE = "{% if user.photo %}{{ url_for('account.photo', user_name=user.user_name[0], field='photo', _external=True) }}{% endif %}"
|
# PICTURE = "{% if user.photo %}{{ url_for('account.photo', user_name=user.user_name[0], field='photo', _external=True) }}{% endif %}"
|
||||||
WEBSITE = "{{ user.profile_url[0] }}"
|
# WEBSITE = "{{ user.profile_url[0] }}"
|
||||||
|
|
||||||
# The SMTP server options. If not set, mail related features such as
|
# The SMTP server options. If not set, mail related features such as
|
||||||
# user invitations, and password reset emails, will be disabled.
|
# user invitations, and password reset emails, will be disabled.
|
||||||
|
|
|
@ -193,17 +193,17 @@ PUBLIC_KEY = "conf/public.pem"
|
||||||
# User objectClass.
|
# User objectClass.
|
||||||
# {attribute} will be replaced by the user ldap attribute value.
|
# {attribute} will be replaced by the user ldap attribute value.
|
||||||
# Default values fits inetOrgPerson.
|
# Default values fits inetOrgPerson.
|
||||||
SUB = "{{ user.user_name[0] }}"
|
# SUB = "{{ user.user_name[0] }}"
|
||||||
NAME = "{{ user.formatted_name[0] }}"
|
# NAME = "{{ user.formatted_name[0] }}"
|
||||||
PHONE_NUMBER = "{{ user.phone_number[0] }}"
|
# PHONE_NUMBER = "{{ user.phone_number[0] }}"
|
||||||
EMAIL = "{{ user.email[0] }}"
|
# EMAIL = "{{ user.email[0] }}"
|
||||||
GIVEN_NAME = "{{ user.given_name[0] }}"
|
# GIVEN_NAME = "{{ user.given_name[0] }}"
|
||||||
FAMILY_NAME = "{{ user.family_name[0] }}"
|
# FAMILY_NAME = "{{ user.family_name[0] }}"
|
||||||
PREFERRED_USERNAME = "{{ user.display_name }}"
|
# PREFERRED_USERNAME = "{{ user.display_name }}"
|
||||||
LOCALE = "{{ user.preferred_language }}"
|
# LOCALE = "{{ user.preferred_language }}"
|
||||||
ADDRESS = "{{ user.formatted_address[0] }}"
|
# ADDRESS = "{{ user.formatted_address[0] }}"
|
||||||
PICTURE = "{% if user.photo %}{{ url_for('account.photo', user_name=user.user_name[0], field='photo', _external=True) }}{% endif %}"
|
# PICTURE = "{% if user.photo %}{{ url_for('account.photo', user_name=user.user_name[0], field='photo', _external=True) }}{% endif %}"
|
||||||
WEBSITE = "{{ user.profile_url[0] }}"
|
# WEBSITE = "{{ user.profile_url[0] }}"
|
||||||
|
|
||||||
# The SMTP server options. If not set, mail related features such as
|
# The SMTP server options. If not set, mail related features such as
|
||||||
# user invitations, and password reset emails, will be disabled.
|
# user invitations, and password reset emails, will be disabled.
|
||||||
|
|
|
@ -63,19 +63,6 @@ def configuration(configuration, keypair_path):
|
||||||
"PUBLIC_KEY": public_key_path,
|
"PUBLIC_KEY": public_key_path,
|
||||||
"PRIVATE_KEY": private_key_path,
|
"PRIVATE_KEY": private_key_path,
|
||||||
"ISS": "https://auth.mydomain.tld",
|
"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] }}",
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
from canaille.oidc.oauth import claims_from_scope
|
from canaille.oidc.oauth import claims_from_scope
|
||||||
|
from canaille.oidc.oauth import DEFAULT_JWT_MAPPING
|
||||||
from canaille.oidc.oauth import generate_user_claims
|
from canaille.oidc.oauth import generate_user_claims
|
||||||
|
|
||||||
|
|
||||||
|
@ -261,16 +262,6 @@ STANDARD_CLAIMS = [
|
||||||
"address",
|
"address",
|
||||||
"updated_at",
|
"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(
|
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"]
|
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 == {
|
assert data == {
|
||||||
|
"address": "1235, somewhere",
|
||||||
"sub": "user",
|
"sub": "user",
|
||||||
"name": "John (johnny) Doe",
|
"name": "John (johnny) Doe",
|
||||||
"family_name": "Doe",
|
"family_name": "Doe",
|
||||||
|
@ -288,13 +280,14 @@ def test_generate_user_standard_claims_with_default_config(
|
||||||
"email": "john@doe.com",
|
"email": "john@doe.com",
|
||||||
"locale": "fr",
|
"locale": "fr",
|
||||||
"phone_number": "555-000-000",
|
"phone_number": "555-000-000",
|
||||||
|
"website": "https://john.example",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def test_custom_config_format_claim_is_well_formated(
|
def test_custom_config_format_claim_is_well_formated(
|
||||||
testclient, slapd_connection, user
|
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"
|
jwt_mapping_config["EMAIL"] = "{{ user.user_name[0] }}@mydomain.tld"
|
||||||
|
|
||||||
data = generate_user_claims(user, STANDARD_CLAIMS, jwt_mapping_config)
|
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.email = ""
|
||||||
user.save()
|
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
|
assert "email" not in data
|
||||||
|
|
Loading…
Reference in a new issue