-
Notifications
You must be signed in to change notification settings - Fork 15
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
feat: SSO through OpenID Connect #609
Conversation
9d02223
to
cc85041
Compare
e2fba99
to
2854f19
Compare
@@ -23,6 +23,7 @@ django-prometheus==2.2.0 | |||
django-filter==22.1 | |||
pydantic==1.10.1 | |||
redis==4.3.4 | |||
mozilla-django-oidc==3.0.0 |
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.
Presumably 3.1.0
will add support for PKCE (it's in master but hasn't been released)
@@ -1,5 +1,4 @@ | |||
.PHONY: doc | |||
doc: | |||
# There is no release of the readme-generator-for-helm tool on the repo so we target an arbitrary commit | |||
npx https://github.com/bitnami-labs/readme-generator-for-helm/tree/3300343a6cd1c9cd86d13b04d8c85a7415cb849e -v substra-backend/values.yaml -r substra-backend/README.md | |||
npx https://github.com/bitnami-labs/readme-generator-for-helm/tree/2.5.0 -v substra-backend/values.yaml -r substra-backend/README.md |
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.
2.5.0
adds a useful @descriptionStart
feature
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.
Thanks for your contribution! Overall a nice feature on its way, although I made some comments about refactoring and optimizing some DB requests.
1ccfeeb
to
548c430
Compare
a3982fe
to
e6aa275
Compare
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.
LGTM
Signed-off-by: Olivier Léobal <[email protected]>
Signed-off-by: Olivier Léobal <[email protected]>
Signed-off-by: Olivier Léobal <[email protected]>
Signed-off-by: Olivier Léobal <[email protected]>
Signed-off-by: Olivier Léobal <[email protected]>
Signed-off-by: Olivier Léobal <[email protected]>
Signed-off-by: Olivier Léobal <[email protected]>
Signed-off-by: Olivier Léobal <[email protected]>
Not needed right now but will save us headaches if we ever support more than one issuer Signed-off-by: Olivier Léobal <[email protected]>
Signed-off-by: Olivier Léobal <[email protected]>
Signed-off-by: Olivier Léobal <[email protected]>
Signed-off-by: Olivier Léobal <[email protected]>
Signed-off-by: Olivier Léobal <[email protected]>
Signed-off-by: Olivier Léobal <[email protected]>
Signed-off-by: Olivier Léobal <[email protected]>
Signed-off-by: Olivier Léobal <[email protected]>
Signed-off-by: Olivier Léobal <[email protected]>
Description
This adds an OpenID Connect client to the Substra backend. All negotiation with the identity provider is handled by the backend.
We use the mozilla-django-oidc library, but covering for its limitations and fitting in well with the backend ultimately means writing a lot of code, unfortunately. It would be possible to roll some back into the lib, but not very much.
New stuff
API extension
It adds endpoints under
/oidc
. The authentication endpoint ultimately sets the JWT cookies, just like/me/login
, so the frontend doesn't suspect a thing.It adds a new
/api-auth-tap
endpoint (I'm open to feedback on the name), which works like/api-auth-token
, but rather than POST your creds to it you need to be already authenticated somehow to access it. This is so SSO users can get bearer tokens to use in the Python code. Some day down the line we will have something more fully-featured than just returning always the same token.It adds a new field in the dictionary returned by
/info
:auth
, which contains info about available authentication methods. This is intended for use by the frontend (so it can add a new button to the login page).In the
/users
endpoint of the API, there is a newis_external_user
boolean field, which the frontend may use to disable some functions (like changing the password).User model extension
The user model is expanded with a
UserOidcInfo
, which contains anopenid_subject
(the identifier given to us by the provider, which is unique and unchanging) alongside anopenid_issuer
(the identity of the provider -- should be the same for all OIDC users, but will save us headaches if we ever support more than one).To cite the spec
By default mozilla-django-oidc filters on email alone but I'm uneasy about this.
UserOidcInfo
also contains avalid_until
field, which is used to restrict access of associated API tokens: the environment maintainer can choose how long a given user can use tokens associated with their account before they need to OIDC-login again (to validate they still have an account at the identity provider).Because this is a pain, if possible Substra will request a refresh token, so that it can check the user is still valid in the background. However not all identity providers implement that, and not all in the same way, so there is the manual fallback still.
Notes, questions and limitation
A significant limitation is that we only handle a single provider. The library we use is set up this way, we could work on it in the future to get rid of this limitation though. Also, although a PR to handle PKCE (increase security) has been merged there, it hasn't been released yet.
The other thing is that I end up replacing a lot of the library code -- the point is never to override security-sensitive code (so security isn't managed by us), but it has downsides:
How has this been tested?
Through local testing
This uses node-oidc-provider.
package.json
:server.js
:Run it:
node src/server.js
Edit your
/etc/hosts
sooidc-provider
points to localhost, and alsokubectl apply -n org-1 -f
this on the server:That way
oidc-provider
points to the same thing whether it's on your browser or inside the cluster (which is required for these shenanigans).The Skaffold configuration includes OIDC. Deploy, visit
/oidc/authenticate
, and enjoy. In dev mode, it logs you in via Django session so you can use the DRF API browser -- in prod mode, it just gives you the JWT cookies.After logging in, you can get a bearer token at
/api-token-tap/
and use it in Python substra:And also through Google! Turns out Google doesn't obey the OpenID spec regarding refresh tokens, fun stuff. But it works!
Checklist
valid_until
field inUserOidcInfo
that tracks how long the issued SSO token was valid for.This PR should be followed or accompanied by:
a substralib PR: feat: add client.login_with_token substra#349superfluous