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

Eagerly check token validity and handle invalid tokens in flask helpers #205

Open
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

sirosen
Copy link
Member

@sirosen sirosen commented Feb 7, 2025

This changeset makes one primary breaking change and calls out another (more subtle) one as well.

The first and most notable change here is that AuthState now calls AuthState.introspect_token() on init.
This removes error behaviors which were previously lazy -- for example, the first access to AuthState.effective_identity could raise an error.

Instead, users of AuthState should anticipate that the token has already been validated.
This does not guarantee that no calls to the AuthState will do IO and result in errors -- notably the codepath which reaches out to Groups is intentionally left untouched here for two reasons:

  1. To limit the scope and scale of this change (and release)
  2. To ensure that services which have no need for Groups information are not calling out to Groups (current supposition is that almost no AP usages actually interrogate Groups and we do not wish to change that)

Secondarily, now that AuthState(...) can raise an error, it is clearly possible to handle that gracefully in the FlaskAuthStateBuilder.
That component now translates the generic errors which are used by AuthState into an appropriate error for the flask components, which then gets handled and translated into an Unauthorized error in the default handler.
Because FlaskAuthStateBuilder has new and different error raising behavior, it is also noted as a breaking change.


In the course of testing this, I also addressed some unnecessarily aggressive mocking in the testsuite, which resulted in a number of tests evaluating against mocks when it is perfectly feasible for them to evaluate against the real AuthState object.


NB: I assessed some other paths to resolving the issues with uncaught errors, like modifying the flask-blueprint error handler more extensively.
Although many such options are reasonable, my determination was that they do not solve the underlying issue, which is the ability of this object to make errors appear on property access at unpredictable times in the application lifecycle.

This makes evaluation eager and adds handling for potential errors to
the FlaskAuthStateBuilder. Tests are updated minimally in order to
pass in the updated paradigm.
Rather than using a mocked `AuthState` object, our preference is to
mock HTTP with `responses` and use a real instance of the object. This
leads to more effective testing.

A discrepancy was revealed in one of the test fixtures in which the
effective identity ID was not included in the list of all identities
in the mocked token introspect data.

`RegisteredResponse.replace()` is used to put default success mocks in
place and replace them as necessary for specific tests.
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.

1 participant