diff --git a/.github/workflows/oidc2fer.yml b/.github/workflows/oidc2fer.yml index 4d6059a..1b342da 100644 --- a/.github/workflows/oidc2fer.yml +++ b/.github/workflows/oidc2fer.yml @@ -87,7 +87,6 @@ jobs: defaults: run: working-directory: src/satosa - steps: - name: Checkout repository uses: actions/checkout@v2 diff --git a/docker-compose.yml b/docker-compose.yml index 23ab72e..e9c57a7 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -42,11 +42,13 @@ services: environment: OIDC_ROOT_URL: https://oidc-test-client.traefik.me OIDC_PROVIDER: https://satosa.traefik.me + #OIDC_PROVIDER: https://oidc2fer-staging.beta.numerique.gouv.fr OIDC_CLIENT_ID: oidc-test-client OIDC_CLIENT_SECRET: oidc-test-secret OIDC_DO_INTROSPECTION: false OIDC_DO_REFRESH: false OIDC_DO_USER_INFO: true + OIDC_SCOPES: openid,uid,given_name,usual_name,email nginx: image: nginx:1.25 diff --git a/src/satosa/.pylintrc b/src/satosa/.pylintrc index ac7e7e7..8c36e5d 100644 --- a/src/satosa/.pylintrc +++ b/src/satosa/.pylintrc @@ -9,6 +9,8 @@ extension-pkg-whitelist= # paths. ignore=migrations +recursive=yes + # Add files or directories matching the regex patterns to the blacklist. The # regex matches against base names, not paths. ignore-patterns= @@ -62,7 +64,10 @@ disable=bad-inline-option, no-self-use, raw-checker-failed, suppressed-message, - useless-suppression + useless-suppression, + missing-module-docstring, + missing-class-docstring, + missing-function-docstring # Enable the message, report, category or checker with the given id(s). You can # either give multiple identifier separated by comma (,) or put this option diff --git a/src/satosa/internal_attributes.yaml b/src/satosa/internal_attributes.yaml index 9b43933..30c22ff 100644 --- a/src/satosa/internal_attributes.yaml +++ b/src/satosa/internal_attributes.yaml @@ -1,19 +1,4 @@ attributes: - address: - openid: - - address.street_address - saml: - - postaladdress - displayname: - openid: - - nickname - saml: - - displayName - edupersontargetedid: - openid: - - sub - saml: - - eduPersonTargetedID givenname: openid: - given_name @@ -27,23 +12,18 @@ attributes: - email - emailAddress - mail - name: + usual_name: openid: - - name - saml: - - cn - surname: - openid: - - family_name + - usual_name saml: - sn - surname - lastName - organization: - saml: - - o - openid: - - organization acr: openid: - acr + uid: + openid: + - uid + saml: + - eduPersonPrincipalName diff --git a/src/satosa/__init__.py b/src/satosa/oidc2fer/__init__.py similarity index 100% rename from src/satosa/__init__.py rename to src/satosa/oidc2fer/__init__.py diff --git a/src/satosa/oidc2fer/attribute_processors/__init__.py b/src/satosa/oidc2fer/attribute_processors/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/satosa/oidc2fer/attribute_processors/flattening_processor.py b/src/satosa/oidc2fer/attribute_processors/flattening_processor.py new file mode 100644 index 0000000..fab112a --- /dev/null +++ b/src/satosa/oidc2fer/attribute_processors/flattening_processor.py @@ -0,0 +1,21 @@ +import logging + +from satosa.micro_services.processors.base_processor import BaseProcessor + +logger = logging.getLogger(__name__) + + +class FlatteningProcessor(BaseProcessor): + def __init__(self): + pass + + # There's a bug in BaseProcessor, the 'self' argument is missing! + # pylint: disable-next=arguments-differ + def process(self, internal_data, attribute, **kwargs): + attributes = internal_data.attributes + if attribute in attributes: + values = attributes.get(attribute) + if isinstance(values, list): + new_value = " ".join(values) + logger.debug("flattening %s into %s", values, new_value) + attributes[attribute] = new_value diff --git a/src/satosa/plugins/frontends/openid_connect_frontend.yaml b/src/satosa/plugins/frontends/openid_connect_frontend.yaml index d632dc5..3342796 100644 --- a/src/satosa/plugins/frontends/openid_connect_frontend.yaml +++ b/src/satosa/plugins/frontends/openid_connect_frontend.yaml @@ -37,8 +37,20 @@ config: client_registration_supported: no response_types_supported: ["code", "id_token token"] subject_types_supported: ["public"] - scopes_supported: ["openid", "email"] + scopes_supported: + - openid + - email + - uid + - given_name + - usual_name id_token_lifetime: 3600 + extra_scopes: + uid: + - uid + given_name: + - given_name + usual_name: + - usual_name extra_id_token_claims: oidc-test-client: - acr diff --git a/src/satosa/plugins/microservices/attribute_processor.yaml b/src/satosa/plugins/microservices/attribute_processor.yaml new file mode 100644 index 0000000..34b924a --- /dev/null +++ b/src/satosa/plugins/microservices/attribute_processor.yaml @@ -0,0 +1,12 @@ +module: satosa.micro_services.attribute_processor.AttributeProcessor +name: AttributeProcessor +config: + process: + - attribute: uid + processors: + - module: oidc2fer.attribute_processors.flattening_processor + name: FlatteningProcessor + - attribute: usual_name + processors: + - module: oidc2fer.attribute_processors.flattening_processor + name: FlatteningProcessor diff --git a/src/satosa/proxy_conf.yaml b/src/satosa/proxy_conf.yaml index 2dcaf6c..f992e2a 100644 --- a/src/satosa/proxy_conf.yaml +++ b/src/satosa/proxy_conf.yaml @@ -13,6 +13,7 @@ FRONTEND_MODULES: - plugins/frontends/ping_frontend.yaml MICRO_SERVICES: - plugins/microservices/static_attributes.yaml + - plugins/microservices/attribute_processor.yaml LOGGING: version: 1 formatters: diff --git a/src/satosa/tests/oidc2fer/attribute_processors/test_flattening_processor.py b/src/satosa/tests/oidc2fer/attribute_processors/test_flattening_processor.py new file mode 100644 index 0000000..c5caaea --- /dev/null +++ b/src/satosa/tests/oidc2fer/attribute_processors/test_flattening_processor.py @@ -0,0 +1,26 @@ +from satosa.internal import InternalData + +from oidc2fer.attribute_processors.flattening_processor import FlatteningProcessor + + +class TestFlatteningProcessor: + def test_flattens_values(self): + processor = FlatteningProcessor() + internal_data = InternalData() + internal_data.attributes = {"name": ["Albert", "Betty"]} + processor.process(internal_data, "name") + assert internal_data.attributes["name"] == "Albert Betty" + + def test_ignores_missing_attribute(self): + processor = FlatteningProcessor() + internal_data = InternalData() + internal_data.attributes = {} + processor.process(internal_data, "name") + assert internal_data.attributes == {} + + def test_leaves_string_alone(self): + processor = FlatteningProcessor() + internal_data = InternalData() + internal_data.attributes = {"name": "AlreadyFlat"} + processor.process(internal_data, "name") + assert internal_data.attributes["name"] == "AlreadyFlat" diff --git a/src/satosa/tests/test_dummy.py b/src/satosa/tests/test_dummy.py deleted file mode 100644 index 566cf95..0000000 --- a/src/satosa/tests/test_dummy.py +++ /dev/null @@ -1,6 +0,0 @@ -import pytest - - -def test_dummy(): - actual = "hello" - assert actual == "hello"