feat: SSO through OpenID Connect#609
Merged
Merged
Conversation
9d02223 to
cc85041
Compare
2 tasks
e2fba99 to
2854f19
Compare
oleobal
commented
Mar 16, 2023
| django-filter==22.1 | ||
| pydantic==1.10.1 | ||
| redis==4.3.4 | ||
| mozilla-django-oidc==3.0.0 |
Contributor
Author
There was a problem hiding this comment.
Presumably 3.1.0 will add support for PKCE (it's in master but hasn't been released)
oleobal
commented
Mar 16, 2023
| 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 |
Contributor
Author
There was a problem hiding this comment.
2.5.0 adds a useful @descriptionStart feature
guilhem-barthes
requested changes
Mar 20, 2023
Contributor
guilhem-barthes
left a comment
There was a problem hiding this comment.
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
Signed-off-by: Olivier Léobal <olivier.leobal@owkin.com>
Signed-off-by: Olivier Léobal <olivier.leobal@owkin.com>
Signed-off-by: Olivier Léobal <olivier.leobal@owkin.com>
Signed-off-by: Olivier Léobal <olivier.leobal@owkin.com>
Signed-off-by: Olivier Léobal <olivier.leobal@owkin.com>
Signed-off-by: Olivier Léobal <olivier.leobal@owkin.com>
Signed-off-by: Olivier Léobal <olivier.leobal@owkin.com>
Signed-off-by: Olivier Léobal <olivier.leobal@owkin.com>
Not needed right now but will save us headaches if we ever support more than one issuer Signed-off-by: Olivier Léobal <olivier.leobal@owkin.com>
Signed-off-by: Olivier Léobal <olivier.leobal@owkin.com>
Signed-off-by: Olivier Léobal <olivier.leobal@owkin.com>
Signed-off-by: Olivier Léobal <olivier.leobal@owkin.com>
Signed-off-by: Olivier Léobal <olivier.leobal@owkin.com>
Signed-off-by: Olivier Léobal <olivier.leobal@owkin.com>
Signed-off-by: Olivier Léobal <olivier.leobal@owkin.com>
Signed-off-by: Olivier Léobal <olivier.leobal@owkin.com>
Signed-off-by: Olivier Léobal <olivier.leobal@owkin.com>
3 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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-tapendpoint (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
/usersendpoint of the API, there is a newis_external_userboolean 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.
UserOidcInfoalso contains avalid_untilfield, 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:{ "dependencies": { "oidc-provider": "^8.1.0" }, "main": "src/server.js", "type": "module" }server.js:Run it:
node src/server.jsEdit your
/etc/hostssooidc-providerpoints to localhost, and alsokubectl apply -n org-1 -fthis on the server:That way
oidc-providerpoints 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_untilfield inUserOidcInfothat 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