Commit 174c5e1b authored by Lukas Burgey's avatar Lukas Burgey
Browse files

Merge branch 'issuer-detection' into dev

parents 592cd99f cc87afa9
import logging import logging
import json import json
import jwt
from urllib.error import HTTPError from urllib.error import HTTPError
from urllib.request import Request, urlopen from urllib.request import Request, urlopen
...@@ -29,16 +30,51 @@ class OIDCTokenAuthBackend: ...@@ -29,16 +30,51 @@ class OIDCTokenAuthBackend:
return user_info return user_info
# no issuer -> try all idps :/
def get_userinfo_bruteforce(self, access_token):
for oidc_client in OIDCConfig.objects.filter(enabled=True):
try:
return oidc_client, self.get_userinfo(
oidc_client,
access_token,
)
except HTTPError as exception:
pass
raise OIDCConfig.DoesNotExist('Unable to determine IdP')
# raises OIDCConfig.DoesNotExist if no idp can be determined # raises OIDCConfig.DoesNotExist if no idp can be determined
def get_idp(self, request): def get_idp(self, request):
# OPTION 1: issuer set in the 'X-Issuer' header # OPTION 1: issuer set in the 'X-Issuer' header
if 'HTTP_X_ISSUER' in request.META: if 'HTTP_X_ISSUER' in request.META:
return OIDCConfig.objects.get(issuer_uri=request.META['HTTP_X_ISSUER']) return OIDCConfig.objects.get(
issuer_uri=request.META['HTTP_X_ISSUER'],
enabled=True,
)
# OPTION 2: issuer set in users session (before redirecting to IdP) # OPTION 2: issuer set in users session (before redirecting to IdP)
idp_id = utils.get_session(request, 'idp_id', None) idp_id = utils.get_session(request, 'idp_id', None)
if idp_id is not None: if idp_id is not None:
return OIDCConfig.objects.get(id=idp_id) return OIDCConfig.objects.get(
id=idp_id,
enabled=True,
)
# OPTION 3: read 'iss' JWT
access_token = request.META['HTTP_AUTHORIZATION']
try:
data = jwt.decode(access_token)
if 'iss' in data:
return OIDCConfig.objects.get(
issuer_uri=data['iss'],
enabled=True,
)
LOGGER.debug("JWT access token does not contain iss field")
except jwt.exceptions.InvalidTokenError as exception: # base exception for jwt.decode
pass
raise OIDCConfig.DoesNotExist('Unable to determine IdP') raise OIDCConfig.DoesNotExist('Unable to determine IdP')
...@@ -74,22 +110,33 @@ class OIDCTokenAuthBackend: ...@@ -74,22 +110,33 @@ class OIDCTokenAuthBackend:
from feudal.backend.models.users import User from feudal.backend.models.users import User
idp = None
userinfo = None
# DETERMINE idp AND userinfo
try: try:
idp = self.get_idp(request) idp = self.get_idp(request)
except OIDCConfig.DoesNotExist:
request.session['auth_error'] = 'Unable to determine IdP'
return None
# get the user info from the idp # get the user info from the idp
try:
userinfo = self.get_userinfo( userinfo = self.get_userinfo(
idp, idp,
access_token, access_token,
) )
except HTTPError as exception:
except OIDCConfig.DoesNotExist: # from get_idp
# Idp was not provided in param / session / JWT -> just try all of them
try:
idp, userinfo = self.get_userinfo_bruteforce(access_token)
except OIDCConfig.DoesNotExist:
request.session['auth_error'] = 'Unable to determine IdP'
return None
except HTTPError as exception: # from get_userinfo
request.session['auth_error'] = 'HTTP when retrieving user info: {}'.format(exception) request.session['auth_error'] = 'HTTP when retrieving user info: {}'.format(exception)
return None return None
# idp and userinfo are set correctly below this point
try: try:
user = User.get_user( user = User.get_user(
userinfo, userinfo,
......
...@@ -9,3 +9,4 @@ django-nose==1.4.6 ...@@ -9,3 +9,4 @@ django-nose==1.4.6
django_polymorphic==2.1.2 django_polymorphic==2.1.2
django-rest-polymorphic==0.1.8 django-rest-polymorphic==0.1.8
mysqlclient==1.4.5 mysqlclient==1.4.5
PyJWT==1.7.1
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment