-
Notifications
You must be signed in to change notification settings - Fork 1
Added Keycloak integration #34
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
Conversation
richturner
left a comment
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.
Nice work! Looks good, maybe more inline with how JAX-RS works in java where any endpoint that doesn't have RolesAllowed annotation is implicitly unsecured so that might remove the need for the exclusion list?
I'd be cautious of writing your own OIDC/OAuth2 middleware as it is such a sensitive piece of code and easy to overlook subtle issues, battle tested well maintained implementations would be preferrable with possible wrapper to support multi-tenancy. Would something like pyoidc be an option?
I'll check whether its straight forward to do something similar to JAX-RS, currently this implementation is based of: fastapi-keycloak-middleware which also does a list of excluded paths. It might make sense to do this as part of #32 in which I wanted to add more granular control over permissions/roles. But requires a bit more research/discussion on how we want to handle service permissions/roles. I took a look at The actual validation here is done in this section: If the token cannot be decoded/verified using the public key it will throw an exception. It doesn't deal with sessions, token creation or such, just validating using the public key from the configured keycloak instance. Most of the code here is just handling the expected exceptions thrown by |
…tching based on issuer + configured OR URL.
|
I cleaned up the middleware code a bit and removed some excessive pre-checking, these would've been caught by the It now also constructs a list of valid issuers based on the enabled realms retrieved from the OpenRemote Manager API. This removed the need for a lot of URL validation/pattern checking that I did to ensure the issuer was a valid and safe URL. Also generally considered a best practice to construct a list of 'allowed' issuers. |
|
Also updated https://test3.openremote.app/manager/#/services (Embedded UI) |
…directly to prevent inconsistent routing behaviour
I haven't exactly tested what happens if the configured service user isn't a super admin, I'll try this out and report back. It might need some changes to accomodate that. It should technically still function, but I am unsure if there are any endpoints that I used that require the user to be a super admin.
I am not entirely sure, from what I can tell it is cookie based. So its safe to assume they have to share a domain for the SSO mechanism to work properly. |
…datapoints in tests
…ob to be constantly rescheduled.
…login and token refresh
…r than defaulting to the hardcoded "master"
This reverts commit 2f55344.
…an in the async event loop It is because the underlying calls are synchronous by nature, in FastAPI endpoints marked with async are always ran in the eventloop even when blocking, when non async it attempts to coalasce and run requests in threads
|
I made some changes to the OpenRemoteClient last week to allow specifying the default realm (it used to default to 'master'). You can now use a service user that isn't a super admin, making it more flexible and also allowing single tentant use. |
|
@richturner I've addressed your review comment + we've discussed the roles/permission topic on Monday. I've re-requested a review, and hope that its be ready to get merged to main :) |
Closes #3
Adds a custom middleware that protects all non-public endpoints via Keycloak.
keycloak/middleware.py
It uses the
JWKS endpointexposed by Keycloak for verifying the token.More details: https://www.keycloak.org/securing-apps/oidc-layers — It is generally recommended to use the JWKS endpoint if the token contains all necessary details (e.g., claims and user information). Additionally, introspection requires more manual setup, as the service then requires its own
client_idandclient_secret.Authentication Flow:
ML_OR_KEYCLOAK_URLkid) from the token header.Authorization:
@allowed_roles(...)to enforce allowed roles, and@realm_accesibleto check for realm access.Security Features:
Configuration:
Front-end Integration via
keycloak-js:Changes made were fairly simple:
SSOmechanism, redirecting to login if not authenticatedmasterrealm)Other changes
manager.api.restfunctionality provided byor-coreFor testing, I am currently disabling the Keycloak middleware conditionally, as there is no easy way of mocking middlewares in FastAPI and I didn't want to make this too complex.
For testing the middleware, I focused on pattern validation and things that were simple to mock without overly complicating it.
Visualization of the Keycloak middleware token validation

The middleware does not inheritly perform any authorization checks. The route handler is responsible for performaning any authorization checks e.g. (is realm accessible by user, does user have appropriate resource roles). These checks can be easily triggered by the decorators provided by the keycloak middleware (@allowed_roles(...), @realm_accessible)