-
Notifications
You must be signed in to change notification settings - Fork 4
feat: enable oidc authz code flow #317
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -46,6 +46,7 @@ | |
"rest_framework", | ||
"corsheaders", | ||
"django_filters", | ||
"mozilla_django_oidc", | ||
# 1st parties | ||
"core", | ||
"extractor", | ||
|
@@ -65,6 +66,8 @@ | |
"django.middleware.common.CommonMiddleware", | ||
"django.middleware.csrf.CsrfViewMiddleware", | ||
"django.contrib.auth.middleware.AuthenticationMiddleware", | ||
# Redirect requests to silently re-authenticated: | ||
"mozilla_django_oidc.middleware.SessionRefresh", | ||
"django.contrib.messages.middleware.MessageMiddleware", | ||
"django.middleware.clickjacking.XFrameOptionsMiddleware", | ||
] | ||
|
@@ -114,6 +117,7 @@ | |
# https://docs.djangoproject.com/en/3.1/topics/auth/customizing/#specifying-authentication-backends | ||
|
||
AUTHENTICATION_BACKENDS = [ | ||
"mozilla_django_oidc.auth.OIDCAuthenticationBackend", | ||
simonvadee marked this conversation as resolved.
Show resolved
Hide resolved
|
||
"django.contrib.auth.backends.ModelBackend", | ||
] | ||
|
||
|
@@ -247,3 +251,32 @@ | |
# Prometheus | ||
|
||
EXPORTER_PORT = os.environ.get("EXPORTER_PORT", 8001) | ||
|
||
# Mozilla OpenID Connect | ||
# https://mozilla-django-oidc.readthedocs.io/en/stable/settings.html | ||
|
||
OIDC_STORE_ID_TOKEN = True | ||
OIDC_STORE_ACCESS_TOKEN = True | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you explain why storing the access token which is short lived ? And what about the refresh token ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure if/why you think there is an issue. The access token has an expiration time ( Maybe you're asking me : why even bother storing the access token ?
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Regarding 1., you're also right. I was just saying that : not storing the access token implies that we'll need to make sure to fetch a new one each time a view requires access to a resource server. This has indeed nothing to do with mozilla-oidc. If many views need access to external resources, then we'd better take advantage of storing the access token and reuse it. |
||
# Silently re-authenticated after following time: | ||
OIDC_RENEW_ID_TOKEN_EXPIRY_SECONDS = int(os.environ.get("OIDC_RENEW_ID_TOKEN_EXPIRY_SECONDS", 12 * 60 * 60)) | ||
|
||
# Relying party | ||
OIDC_RP_CLIENT_ID = os.environ.get("OIDC_RP_CLIENT_ID") | ||
OIDC_RP_CLIENT_SECRET = os.environ.get("OIDC_RP_CLIENT_SECRET") | ||
OIDC_RP_EXTRA_SCOPES = os.environ.get("OIDC_RP_EXTRA_SCOPES", "").replace(",", " ").split(" ") | ||
OIDC_RP_SCOPES = " ".join(["openid", *OIDC_RP_EXTRA_SCOPES]) | ||
OIDC_RP_SIGN_ALGO = os.environ.get("OIDC_RP_SIGN_ALGO") | ||
|
||
LOGIN_REDIRECT_URL = os.environ.get("LOGIN_REDIRECT_URL") | ||
LOGIN_REDIRECT_URL_FAILURE = os.environ.get("LOGIN_REDIRECT_URL_FAILURE") | ||
LOGOUT_REDIRECT_URL = os.environ.get("LOGOUT_REDIRECT_URL") | ||
|
||
# Provider | ||
OIDC_OP_AUTHORIZATION_ENDPOINT = os.environ.get("OIDC_OP_AUTHORIZATION_ENDPOINT") | ||
OIDC_OP_TOKEN_ENDPOINT = os.environ.get("OIDC_OP_TOKEN_ENDPOINT") | ||
OIDC_OP_USER_ENDPOINT = os.environ.get("OIDC_OP_USER_ENDPOINT") | ||
|
||
if OIDC_RP_SIGN_ALGO == "RS256": | ||
OIDC_OP_JWKS_ENDPOINT = os.environ.get("OIDC_OP_JWKS_ENDPOINT") | ||
elif OIDC_RP_SIGN_ALGO == "HS256": | ||
pass |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -127,6 +127,19 @@ services: | |
- DJANGO_SUPERUSER_USERNAME=admin | ||
- [email protected] | ||
- DJANGO_SUPERUSER_PASSWORD=admin | ||
- OIDC_RP_CLIENT_ID= | ||
- OIDC_RP_CLIENT_SECRET= | ||
- OIDC_RP_EXTRA_SCOPES=email | ||
- OIDC_RP_SIGN_ALGO=HS256 | ||
- LOGIN_REDIRECT_URL=http://localhost:3000/ | ||
- LOGIN_REDIRECT_URL_FAILURE=http://localhost:3000/error/ | ||
- LOGOUT_REDIRECT_URL=http://localhost:3000/ | ||
# LPT: Always use 127.0.0.1 (not localhost) in public URLs redirecting to the provider | ||
# This is to prevent cookies in the browser from being shared and overridden by | ||
# different services running on the host. | ||
- OIDC_OP_AUTHORIZATION_ENDPOINT=http://127.0.0.1:8001/o/authorize/ | ||
- OIDC_OP_TOKEN_ENDPOINT=http://127.0.0.1:8001/o/token/ | ||
- OIDC_OP_USER_ENDPOINT=http://127.0.0.1:8001/o/userinfo/ | ||
|
||
zookeeper: | ||
image: zookeeper:3.4.10 | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,6 +14,7 @@ fhir.resources @ git+https://github.com/arkhn/[email protected]#egg=fhir.reso | |
fluent-logger==0.9.6 | ||
hiredis==1.1.0 | ||
jsonschema==3.0.2 | ||
mozilla-django-oidc==1.2.4 | ||
msgpack==0.6.2 | ||
prometheus-client==0.8.0 | ||
pyodbc==4.0.30 | ||
|
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.
Did you read the code ? From memory it performs a redirect or in our case (when using an SPA) returns a 403 along with a refresh url in the body. It's not silent. That's why I stored the refresh token and implemented a custom middleware based on this one. There's a couple of issues and PR related to this in the mozilla-django-oidc repo.
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.
Are you're suggesting there is a bug with SPAs ? Point me towards the issues you're referring to.
I did read the code.
It seems to me that what you're describing is not related to mozilla-django-oidc. Rather an issue with the provider implementation when receiving
prompt=none
. It either can be the expected outcome (the end-user do need to reauthenticate) or an issue with the provider implementation.If you want to review this PR, you should also check arkhn/o-provider.
I did have an issue with django-oauth-toolkit, but was able to move past with the following monkeypatch (I can explain what a monkeypatch is if you don't know the pattern):
https://github.com/arkhn/o-provider/blob/master/django/oauth/__init__.py
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'm sorry my comment wasn't very clear. The request to the provider works flawlessly. But the issue is when using an SPA like our React app. When we will perform a redirect, it means we need to store the client-side state before the redirect and restore the state afterwards.
For instance, if the user is filling a form. When submitting this form, he will receive a 403 (because he reached the 15 minutes you set in the settings) and then the app will redirect him to the
redirect_url
which will redirect him back to the app. To make it silent, we need to store the user state before the redirect in some ways in the app and rollback this state after the redirect. In our example, it means restoring the form inputs and submitting again. It's a bit cumbersome.What we can do alternatively is using the refresh token. No redirect is needed in this case. That's what I implemented on my other PR.
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.
Okay ! This is the kind of insightful feedback I was expecting from you !
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.
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.
a. mozilla infosec does not recommend using the refresh token at all (and they just implement the authz code flow).
b. auth0 recommends using refresh token (with rotation) (ref), but they do so in the context of a SPA without a backend (ref). They previously recommended silent reauth but changed their recommendation because :
In short, Auth0 is a centralized session management system and ITP has forced them to recommend refresh token (with rotation) to their users.
c. Refresh token are dangerous because they never expire. Using them securely implies using rotation among other things (cf here and here). Without these, poorly implemented 3rd party clients could leak refresh token that never expire.
a. meaningful data, that should not be lost (e.g. user work), should be progressively (but coherently, as units of user work) saved with the backend. Otherwise it might be a UX problem.
b. for other non meaningful data, we should not bother
c. given 3. the chances of the issue could be low
d. at worst, we have the quick fallback: https://mozilla-django-oidc.readthedocs.io/en/stable/xhr.html
To sum up 2., (severity of the problem occuring) * (probability of the problem occuring) is low and to me it does not justify to preemptively implement something.
Maybe you disagree. For now, let's just see how it goes. If it become truly an issue, I'd be happy to review your implementation.
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.
a. I didn't talk about losing any meaningful data. I'm just saying it won't be silent for the user if we have any local state in our components and that's not like it's not a common thing. For a concrete example, take the drawer in my last PR on Pyrog. If I don't use redux-persist (which stores the state in local storage), that will just close it without warning (there's three steps, each one potentially fetches something). And yes I think we should bother because it just breaks the UX.
c. is not true. You can set an expiry on refresh token as you do on 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.
I feel like this debate needs arbitration lol. I think both of you are more knowledgeable than me on this topic but the way I see it:
is true if the token expiration time is long enough. I think users will be bothered by this at some point, and this is when we'll think of something to patch it (like using refresh token for instance). Central authentication is already a hell of a mess, so let's take it step by step 😉.
@tevariou let's not take any action in the webapp to prevent this and see how problematic it becomes for users.
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.
@tevariou