-
Notifications
You must be signed in to change notification settings - Fork 58
Add Authenticator for when serving OIDC as a proxy #877
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
base: main
Are you sure you want to change the base?
Conversation
fd664f0
to
02232db
Compare
description: Optional[str] = None, | ||
): | ||
self.model: APIKey = APIKey( | ||
**{"in": APIKeyIn.header}, name=name, description=description |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I hate this but I see why it is required (in
is a reserved keyword but APIKey uses it as an init arg... using _in
does not work, as it is a serialisation alias only).
why |
e1a752c
to
2ee2a42
Compare
@@ -181,6 +182,16 @@ def authorization_endpoint(self) -> httpx.URL: | |||
cast(str, self._config_from_oidc_url.get("authorization_endpoint")) | |||
) | |||
|
|||
async def decode_access_token(self, access_token: str) -> dict[str, Any]: | |||
keys = httpx.get(self.jwks_uri).raise_for_status().json().get("keys", []) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As discussed, use a TTL cache to ensure we do not hammer the AuthN provider
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(for the result of httpx.get(self.jwks_uri)
)
) | ||
|
||
@property | ||
def oauth2_scheme(self) -> Callable[[Request], str]: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
def oauth2_scheme(self) -> Callable[[Request], str]: | |
def oauth2_scheme(self) -> OAuth2: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just some type hinting for my benefit
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just some type hinting for my benefit
tiled/client/container.py
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For consistency with the serialization/deserialization registries.
annotation=Optional[List[field_type]], | ||
) | ||
parameters.append(injected_parameter) | ||
route_with_sig.__signature__ = signature.replace(parameters=parameters) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if much of this could be replaced by replacing search/distinct **kwargs with Unpack[QueryParams]
where QueryParams is a TypedDict generated by the QueryRegistry?
Test Summary as I hand off this PR for a week of leave: 173 failed, 432 passed, 4 skipped, 4 xfailed, 13 warnings in 510.08s (0:08:30) Summary of changes' intents:
|
@@ -55,7 +57,7 @@ def __init__(self, base_url, metadata=None): | |||
self.client = MockClient(base_url) | |||
self.metadata = metadata | |||
|
|||
def with_session_state(self, state): | |||
def with_session_state(self, state: dict[str, Any]) -> Self: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From a design perspective, it's just expected to still be an Adapter (?)
We're down to a tractable number of failures with a hilariously tiny change, pushed above.
|
- Prevents having to inject the password late into the oauth2_schema, and allows supporting Proxied credentials
- Such that decode_access_token can be overriden when serving behind proxied OIDC - Removes injection of password into security obj - Removes use of dependency_override which is intended for use in tests
79f8497
to
3ca1344
Compare
Rebased on |
This is where we are post-rebase:
|
tiled/server/authentication.py
Outdated
): | ||
"Mark a Session as revoked so it cannot be refreshed again." | ||
request.state.endpoint = "auth" | ||
payload = await decode_access_token(refresh_token.refresh_token) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Something's crossed here, where we're decoding the refresh token with decode_access_token
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I think it should be named decode_token
but otherwise it's solid: there's a "get access token from request" method and a "decode token" that can take an access or request token.
I think the next issue is that With fresh eyes, I think that it would make sense to put the database connection pool in We might stash the |
This is where things stand as I set this down. The
|
So what exactly is the difference between what is loaded by Settings, which extends Pydantic BaseSettings and so picks up any environment (PR to make it slightly clearer 😎 ) and what goes into the merged_settings object? I think one of the easiest ways to get to decoupling the fastapi creation from the server startup is making use of BaseSettings as the CLI entrypoint- we looked at using BaseSettings for blueapi previously but because we made heavy use of |
I've made a mockup of how this would look for some of the simple commands, but it would require another turning the sock inside out |
Using a Settings object as the way to initialize an app seems right. I am less sure about building a CLI application around it, but open to exploring. We have quite a lot of CLI code built on Typer (which is in turn built on Click) that would need to be changed. For this PR, given the scope, the small change we can devise that moves in the generally right direction and passes the tests is the thing. |
WIP: adds an Authenticator implementation for use when serving Tiled behind a proxy.
This is intended be used to define an alternative
decode_access_token
In order to inject the desired behaviour for decode_access_token has required a fairly weighty refactor, inverting the creation order of a lot of router objects.
Checklist