Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace digid_eherkenning_oidc_generics with library code #1297

Open
wants to merge 8 commits into
base: develop
Choose a base branch
from

Conversation

sergei-maertens
Copy link
Member

@sergei-maertens sergei-maertens commented Jul 5, 2024

Trying this is as backwards compatible as possible, but there are some breaking changes. I can't find where to mention this in the documenation :/

Breaking changes

  • ADMIN_OIDC_CLAIM_MAPPING must now be a mapping of key -> list of strings. This makes it possible to use dots in claim names while still supporting nesting. Every element in the array is a level of nesting. Change is because of ClaimField support in mozilla-django-oidc-db 0.16+
  • ADMIN_OIDC_USERNAME_CLAIM must now be a list of strings. Same reason as above. I don't know how to fix this for the configuration via envvars, since the whole point of this feature is that no characters gain magical meaning. A comma could be used in a claim, so CSV splitting suffers from the same problem. Maybe it should just be a json.loads(...) call on the envvar string?
  • ADMIN_OIDC_GROUPS_CLAIM same as for ADMIN_OIDC_USERNAME_CLAIM
  • Removed the OIDC_EXEMPT_URLS configuration variables, after checking in the office these don't appear to be used at all. The config option was removed in mozilla-django-oidc-db
  • Removed the *_OIDC_ERROR_MESSAGE_MAPPING configuration variables, in favour of hardcoded messages.

Questions

  • is the error_message_mapping really necessary? Error code + prescribed error messages are specified by OIDC standard and Logius, no?
  • do we need to set a hardcoded OIDC_EXEMPT_URLS setting for the non-standard URLs? Otherwise there is a session refresh redirect loop issue for DigiD/eHerkenning/admin via OIDC I suspect.
  • ...

@sergei-maertens sergei-maertens force-pushed the chore/replace-digid-eh-oidc-generics branch 2 times, most recently from a3f7e32 to 748d8b8 Compare July 5, 2024 22:32
@codecov-commenter
Copy link

codecov-commenter commented Jul 5, 2024

Codecov Report

Attention: Patch coverage is 96.27329% with 12 lines in your changes missing coverage. Please review.

Project coverage is 94.86%. Comparing base (fdb51bb) to head (7d70386).

Files with missing lines Patch % Lines
...grations/0076_copy_legacy_oidc_digid_eh_configs.py 75.00% 4 Missing ⚠️
src/digid_eherkenning_oidc_generics/apps.py 80.00% 2 Missing ⚠️
...erkenning_oidc_generics/migrations/0001_initial.py 50.00% 2 Missing ⚠️
...herkenning_oidc_generics/migrations/0001_legacy.py 81.81% 2 Missing ⚠️
src/open_inwoner/accounts/backends.py 95.45% 1 Missing ⚠️
src/open_inwoner/accounts/views/auth_oidc.py 98.71% 1 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##           develop    #1297      +/-   ##
===========================================
- Coverage    94.88%   94.86%   -0.03%     
===========================================
  Files         1045     1045              
  Lines        38692    38691       -1     
===========================================
- Hits         36714    36704      -10     
- Misses        1978     1987       +9     
Flag Coverage Δ
?

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose this will need some face-to-face discussion :)

Comment on lines 290 to 299
ADMIN_OIDC_USERNAME_CLAIM = config("ADMIN_OIDC_USERNAME_CLAIM", None)
ADMIN_OIDC_GROUPS_CLAIM = config("ADMIN_OIDC_GROUPS_CLAIM", None)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these need to be lists of strings rather than strings

@sergei-maertens sergei-maertens force-pushed the chore/replace-digid-eh-oidc-generics branch 3 times, most recently from f078ed1 to 924977d Compare July 8, 2024 19:50
@@ -87,8 +87,7 @@
"django.contrib.auth.backends.ModelBackend",
"digid_eherkenning.mock.backends.DigiDBackend",
"eherkenning.mock.backends.eHerkenningBackend",
"digid_eherkenning_oidc_generics.backends.OIDCAuthenticationDigiDBackend",
"digid_eherkenning_oidc_generics.backends.OIDCAuthenticationEHerkenningBackend",
"open_inwoner.accounts.backends.DigiDEHerkenningOIDCBackend",
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the setting duplication here bit my ass in development, spent about 20 minutes trying to figure out why my breakpoint wasn't hitting :(

@sergei-maertens sergei-maertens force-pushed the chore/replace-digid-eh-oidc-generics branch from 686d522 to c728bd4 Compare July 10, 2024 10:06
@sergei-maertens sergei-maertens changed the title WIP - replace digid_eherkenning_oidc_generics with library code Replace digid_eherkenning_oidc_generics with library code Jul 10, 2024
@sergei-maertens sergei-maertens marked this pull request as ready for review July 10, 2024 12:21
@sergei-maertens sergei-maertens force-pushed the chore/replace-digid-eh-oidc-generics branch 2 times, most recently from 71e22ad to fd35173 Compare August 9, 2024 15:09
@@ -16,6 +16,8 @@
from .forms import GroupAdminForm
from .models import Action, Document, Invite, Message, User

# XXX: register proxy models and unregister digid_eherkenning.oidc models
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

self-reminder!

Upgrade digid-eherkenning to a version with OIDC support. This
requires a newer version of mozilla-django-oidc-db too.
The app_label is changed to avoid conflicts with the app_label defined
in the 'digid_eherkenning.oidc' package. Migrations are added to
rename any existing database tables and keep a consistent migration
history/state.

Special care is needed with regards to the django_migrations table -
fixes here cannot be done through migrations, so the AppConfig.ready
hook is used to bring these in a consistent state.

Finally, the code that is replaced by the library is deleted to
de-clutter, which includes uninstalling the models. The migrations are
defined such that the new tables are created first and configuration can
be copied over, which prevents data loss.
Some database fields have been renamed, which requires settings for the
setup_configuration to be updated too.

Future commits provide different authentication backends/views
implementations, which require listing in their respective django
settings too.
Using proxy models is the preferred approach to modify python behaviour
as no database schema changes are usually required. This does require
all code to call the proxy model rather than the concrete base model,
or different outcomes for the same checks would cause problems.

This includes the copy of the legacy data into the new models, which
should be a smooth automatic migration.
The OIDC libraries support different OIDC-configurations/flow through
the same views and backends, which is what this changeset achieves.

The init views are exposed via separate URLs/endpoints, and bind the
specific OIDC config flavour to be used to the endpoint. This
information is recorded in the (session) state, and consulted again
in the callback flow.

All return flows (when returning from the OIDC Provider) go through
the same callback view, which can route to specific handlers based on
the configuration used. DigiD/eHerkenning is sent to a single
authentication backend, which implements behaviours depending on the
specific flavour used. The admin OIDC configuration is bound to the
admin user backend, isolated from the DigiD/eHerkenning backend.

Currently the callback URLs are still different urls for admin, digid
and eherkenning, but there is no need for this - you can already
use /oidc/callback/ instead (see the setting OIDC_CALLBACK_CLASS).
The configuration settings are tightly coupled to the django model
fields (names and data types). The field names for the configuration
have been changed compared to the vendored library, and the structure
has been changed to be able to use claims with dots in their name.

Unfortunately, this means that breaking changes in the infrastructure/
configuration setup are required because of the way this config is
specified and used.
@pi-sigma pi-sigma force-pushed the chore/replace-digid-eh-oidc-generics branch from fd35173 to fb2e811 Compare October 2, 2024 07:46
@pi-sigma pi-sigma force-pushed the chore/replace-digid-eh-oidc-generics branch from fb2e811 to 7d70386 Compare October 2, 2024 08:17
Possible values string
Default value roles

Possible values list of strings
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can specify the values by adding the ClaimField to custom fields in the settings:

DJANGO_SETUP_CONFIG_CUSTOM_FIELDS = [
    {
        "field": "mozilla_django_oidc_db.fields.ClaimField",
        "description": "list of strings representing a claim",
    },
]

Default value roles

Possible values list of strings
Default value [roles]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code responsible for returning roles instead of [roles] as default value is this:

if isinstance(field, (JSONField, ArrayField)) and isinstance(default, Sequence):
            try:
                return ", ".join(str(item) for item in default)
            except TypeError:
                return str(default)

The values for env variables used to configure an ArrayField are comma-delimited strings, not lists (the comma-delimited string is transformed into a list via a call to config in the settings).


def rename_app_label():
with connection.cursor() as cursor:
# uses explicit query names so that we don't accidentally rwrite the
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# uses explicit query names so that we don't accidentally rwrite the
# uses explicit query names so that we don't accidentally rewrite the

(
"digid_eherkenning_oidc_generics_legacy",
"0003_alter_openidconnectdigidconfig_oidc_exempt_urls_and_more",
),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something's going wrong. After renaming of the tables Django attempts to run:

digid_eherkenning_oidc_generics_legacy.0004_alter_openidconnectdigidconfig_table_and_more

and complains:

psycopg2.errors.UndefinedTable: relation "digid_eherkenning_oidc_generics_legacy_openidconnectdigidconfig" does not exist

Default value {'email': 'email', 'first_name': 'given_name', 'last_name': 'family_name'}

Description Mapping from user-model fields to OIDC claim paths
Possible values Mapping: {'some_key': ['Some value']}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The possible values are hard-coded for the different field types. Needs change in the library (or overwrite in the configuration step, but this would need to be done for every setting separately)

    - Various models for digid-eherkenning-generics have the wrong
      database tables associated due to renaming of the app label
      before the migrations.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants