зеркало из https://github.com/mozilla/normandy.git
review fixes
This commit is contained in:
Родитель
2ae42f468b
Коммит
f47e9d714b
|
@ -344,8 +344,8 @@ in other Django projects.
|
||||||
|
|
||||||
URL where we sent access tokens received as an authorization bearer token.
|
URL where we sent access tokens received as an authorization bearer token.
|
||||||
This URL needs to match the OIDC domain used by the client to authenticate.
|
This URL needs to match the OIDC domain used by the client to authenticate.
|
||||||
The endpoint URL is actually extracted from reading ``/.well-known/openid-configuration``
|
The value for this setting is usually listed in
|
||||||
on the configured OIDC provider domain.
|
``/.well-known/openid-configuration`` on the OIDC provider.
|
||||||
|
|
||||||
Gunicorn settings
|
Gunicorn settings
|
||||||
-----------------
|
-----------------
|
||||||
|
|
|
@ -139,17 +139,12 @@ class OIDCAccessTokenAuthorizationMiddleware:
|
||||||
an authentication backend, there is no 'Set-Cookie' header returned in the
|
an authentication backend, there is no 'Set-Cookie' header returned in the
|
||||||
response.
|
response.
|
||||||
|
|
||||||
It's admittedly confusing to mix the terms authentication and authorization.
|
|
||||||
Arguably the client has already *authenticated* and basically converted her
|
|
||||||
password for an access token. Here in the context of Normandy we kill two
|
|
||||||
birds with one stone: check that access token and use the user profile that
|
|
||||||
comes out to sign the user into the rest of the Django request.
|
|
||||||
|
|
||||||
The flow is as follows:
|
The flow is as follows:
|
||||||
|
|
||||||
1. Client trades email/username and password with the OIDC for an access token.
|
1. (outside Normandy) Client trades email/username and password with the
|
||||||
|
OIDC provider for an access token.
|
||||||
2. The access token is sent to us here.
|
2. The access token is sent to us here.
|
||||||
3. We send it to the OIDC provider in return for a user profile
|
3. We send it to the OIDC provider in return for a user profile.
|
||||||
4. We extract the email from the user profile (and first- and last name)
|
4. We extract the email from the user profile (and first- and last name)
|
||||||
5. Turn the email into a Django User model instance.
|
5. Turn the email into a Django User model instance.
|
||||||
6. If possible, extracts the first- and last name and updates the User instance persistently.
|
6. If possible, extracts the first- and last name and updates the User instance persistently.
|
||||||
|
@ -164,7 +159,6 @@ class OIDCAccessTokenAuthorizationMiddleware:
|
||||||
|
|
||||||
def __init__(self, get_response):
|
def __init__(self, get_response):
|
||||||
self.get_response = get_response
|
self.get_response = get_response
|
||||||
self.oidc_user_endpoint = settings.OIDC_USER_ENDPOINT
|
|
||||||
self.UserModel = get_user_model()
|
self.UserModel = get_user_model()
|
||||||
|
|
||||||
def __call__(self, request):
|
def __call__(self, request):
|
||||||
|
@ -193,7 +187,7 @@ class OIDCAccessTokenAuthorizationMiddleware:
|
||||||
|
|
||||||
access_token = matched.group(1)
|
access_token = matched.group(1)
|
||||||
|
|
||||||
user_profile = self._fetch_oidc_email(access_token)
|
user_profile = self._fetch_oidc_user_profile(access_token)
|
||||||
email = user_profile.get('email')
|
email = user_profile.get('email')
|
||||||
if not email:
|
if not email:
|
||||||
# This would happen if someone has requested an access token
|
# This would happen if someone has requested an access token
|
||||||
|
@ -237,23 +231,18 @@ class OIDCAccessTokenAuthorizationMiddleware:
|
||||||
user.last_name = user_profile['family_name'].strip()
|
user.last_name = user_profile['family_name'].strip()
|
||||||
user.save()
|
user.save()
|
||||||
|
|
||||||
# We *could* do something like this too:
|
|
||||||
# if user_profile.get('picture'):
|
|
||||||
# pf = user.get_profile()
|
|
||||||
# pf.picture = user_profile['picture']
|
|
||||||
# pf.save()
|
|
||||||
|
|
||||||
# Now, let's "become" this user for the rest of the request.
|
# Now, let's "become" this user for the rest of the request.
|
||||||
request.user = user
|
request.user = user
|
||||||
user_logged_in.send(sender=user.__class__, request=request, user=user)
|
user_logged_in.send(sender=user.__class__, request=request, user=user)
|
||||||
|
|
||||||
@backoff.on_exception(
|
@backoff.on_exception(
|
||||||
backoff.expo,
|
backoff.constant,
|
||||||
requests.exceptions.RequestException,
|
requests.exceptions.RequestException,
|
||||||
max_tries=5,
|
max_tries=5,
|
||||||
)
|
)
|
||||||
def _fetch_oidc_email(self, access_token):
|
def _fetch_oidc_user_profile(self, access_token):
|
||||||
response = requests.get(self.oidc_user_endpoint, headers={
|
url = settings.OIDC_USER_ENDPOINT
|
||||||
|
response = requests.get(url, headers={
|
||||||
'Authorization': 'Bearer {0}'.format(access_token)
|
'Authorization': 'Bearer {0}'.format(access_token)
|
||||||
})
|
})
|
||||||
if response.status_code == 200:
|
if response.status_code == 200:
|
||||||
|
@ -262,9 +251,7 @@ class OIDCAccessTokenAuthorizationMiddleware:
|
||||||
# The OIDC provider did not like the access token.
|
# The OIDC provider did not like the access token.
|
||||||
raise PermissionDenied('Unauthorized access token')
|
raise PermissionDenied('Unauthorized access token')
|
||||||
if response.status_code >= 500:
|
if response.status_code >= 500:
|
||||||
raise requests.exceptions.RequestException(
|
raise requests.exceptions.RequestException(f'{response.status_code} on {url}')
|
||||||
f'{response.status_code} on {self.oidc_user_endpoint}'
|
|
||||||
)
|
|
||||||
|
|
||||||
# This could happen if, for some reason, we're not configured to be
|
# This could happen if, for some reason, we're not configured to be
|
||||||
# allowed to talk to the OIDC endpoint.
|
# allowed to talk to the OIDC endpoint.
|
||||||
|
|
|
@ -194,7 +194,7 @@ class OIDC:
|
||||||
# https://$OIDC_DOMAIN/.well-known/openid-configuration and extract the
|
# https://$OIDC_DOMAIN/.well-known/openid-configuration and extract the
|
||||||
# 'userinfo_endoint' value from that during startup or something.
|
# 'userinfo_endoint' value from that during startup or something.
|
||||||
# As of May 2018, the likelyhood of this URL changing and the fact that it's
|
# As of May 2018, the likelyhood of this URL changing and the fact that it's
|
||||||
# the only URL we need, let's just make the setting thee URL that we need
|
# the only URL we need, let's just make the setting the URL that we need
|
||||||
# for being able to authorization by access token.
|
# for being able to authorization by access token.
|
||||||
OIDC_USER_ENDPOINT = values.URLValue('https://auth.mozilla.auth0.com/userinfo')
|
OIDC_USER_ENDPOINT = values.URLValue('https://auth.mozilla.auth0.com/userinfo')
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче