Commit 9cb91a6a authored by Lukas Burgey's avatar Lukas Burgey

Cleanup OIDCConfig model

parent 014d6f17
......@@ -30,69 +30,51 @@ def scopes_default():
class OIDCConfig(db_models.Model):
client_id = db_models.CharField(max_length=200)
client_secret = db_models.CharField(max_length=200)
redirect_uri = db_models.CharField(max_length=200)
issuer_uri = db_models.CharField(max_length=200)
enabled = db_models.BooleanField(default=False)
name = db_models.CharField(max_length=200)
redirect_uri = db_models.CharField(
max_length=200,
default='https://<domain>/backend/auth/v1/callback',
)
# scopes as a list of strings
scopes = JSONField(
default=scopes_default,
editable=True,
help_text='The scopes we request when requesting user infos',
)
# ENTITLEMENT CHANGES
# path in the group tree to the VO Groups
# can be empty if we use the root
vo_subtree_path = db_models.CharField(
max_length=200,
blank=True,
null=True,
help_text='If not emtpy: Operate with groups of the described subtree of group (or entitlements). For example: Let\'s say the groups [/,/foo,/bar] exist and you set vo_subtree_path to "/". In that case the VO-Groups would be /foo and /bar',
)
# If True we shall ignore subgroups of the VO-Groups
# (VO-Group are the group on the path described by subtree_path)
ignore_subgroups = db_models.BooleanField(
default=False,
help_text='Ignore subgroups of VO describing groups. E.g. ignores the group :foo:bar if :foo exists.',
help_text='The scopes we use when requesting user infos',
)
# The field in the userinfo (served by this IdP) that describes groups of the user
userinfo_field_groups = db_models.CharField(
max_length=200,
help_text="The field in the userinfo (served by this IdP) that contains groups of the user. Leave blank if you don't want to use groups of this IdP",
default=None,
help_text="""The field in the userinfo (served by this IdP) that contains groups of the user.
Leave blank if you don't want to use groups of this IdP""",
default='',
blank=True,
null=True,
)
# The field in the userinfo (served by this IdP) that describes entitlements of the user
userinfo_field_entitlements = db_models.CharField(
max_length=200,
help_text="The field in the userinfo (served by this IdP) that contains entitlements of the user. Leave blank if you don't want to use entitlements of this IdP",
default=None,
help_text="""The field in the userinfo (served by this IdP) that contains entitlements of the user.
Leave blank if you don't want to use entitlements of this IdP""",
default='',
blank=True,
null=True,
)
@property
def registration_response(self):
info = {
'client_id': self.client_id,
'client_secret': self.client_secret
}
return RegistrationResponse(**info)
@property
def oidc_client(self):
# create the client object if does no yet exist
if self.id not in OIDC_CLIENT:
new_oidc_client = Client(client_authn_method=CLIENT_AUTHN_METHOD)
new_oidc_client.provider_config(self.issuer_uri)
new_oidc_client.store_registration_info(self.registration_response)
info = {
'client_id': self.client_id,
'client_secret': self.client_secret,
}
new_oidc_client.store_registration_info(RegistrationResponse(**info))
OIDC_CLIENT[self.id] = new_oidc_client
return OIDC_CLIENT[self.id]
......@@ -126,71 +108,69 @@ def default_idp():
return available_idps.first()
class OIDCTokenAuthBackend(object):
class OIDCTokenAuthBackend:
IdPException = Exception
AuthException = Exception('Unable to authenticate user')
def get_userinfo(self, oidc_client, access_token=None):
def get_userinfo(self, oidc_client, access_token):
user_info = None
if access_token is not None:
req = Request(
oidc_client.provider_info['userinfo_endpoint'],
)
auth = ('Bearer ' + access_token)
req.add_header('Authorization', auth)
userinfo_bytes = urlopen(req).read()
user_info = json.loads(userinfo_bytes.decode('UTF-8'))
user_info['iss'] = oidc_client.provider_info['issuer']
# do the user info request
req = Request(
oidc_client.provider_info['userinfo_endpoint'],
)
auth = ('Bearer ' + access_token)
req.add_header('Authorization', auth)
else:
LOGGER.error('Invalid parameters for get_userinfo')
userinfo_bytes = urlopen(req).read()
user_info = json.loads(userinfo_bytes.decode('UTF-8'))
user_info['iss'] = oidc_client.provider_info['issuer']
# LOGGER.debug('Got user info:\n%s\n', user_info)
return user_info
def authenticate(self, request, token=None, issuer_uri=None):
from ....models.users import User
# raises OIDCConfig.DoesNotExist if no idp can be determined
def get_idp(self, idp_id=None, issuer_uri=None):
if idp_id is None and issuer_uri is None:
raise OIDCConfig.DoesNotExist('Need idp_id or issuer_uri to determine IdP')
if issuer_uri is not None:
return OIDCConfig.objects.get(issuer_uri=issuer_uri)
return OIDCConfig.objects.get(id=idp_id)
def authenticate(self, request, token=None, issuer_uri=None):
if token is None:
LOGGER.error('Cannot authenticate without access token')
return None
idp_id = utils.get_session(request, 'idp_id', None)
oidc_client = None
try:
oidc_client = self.get_idp(idp_id=idp_id, issuer_uri=issuer_uri)
if issuer_uri is not None:
oidc_client = OIDCConfig.objects.get(issuer_uri=issuer_uri)
elif idp_id is not None:
oidc_client = OIDCConfig.objects.get(id=idp_id)
# get the user info from the idp
userinfo = self.get_userinfo(
oidc_client,
token,
)
if oidc_client is None:
LOGGER.error('Unable to determine IdP for authentication')
return None
from feudal.backend.models.users import User
return User.get_user(
userinfo,
oidc_client,
)
except OIDCConfig.DoesNotExist:
LOGGER.error('Unable to determine IdP for authentication')
return None
# get the user info from the idp
userinfo = self.get_userinfo(
oidc_client,
access_token=token,
)
return User.get_user(
userinfo,
oidc_client,
)
def get_user(self, user_id):
from ....models.users import User
from feudal.backend.models.users import User
query = User.objects.filter(
user_type='oidcuser',
pk=user_id
pk=user_id,
)
if query.exists():
if len(query) == 1:
......
# Generated by Django 2.1.3 on 2018-12-03 15:08
from django.db import migrations, models
import django_mysql.models
import feudal.backend.auth.v1.models
class Migration(migrations.Migration):
dependencies = [
('backend', '0028_auto_20181128_1400'),
]
operations = [
migrations.RemoveField(
model_name='oidcconfig',
name='ignore_subgroups',
),
migrations.RemoveField(
model_name='oidcconfig',
name='vo_subtree_path',
),
migrations.AlterField(
model_name='oidcconfig',
name='redirect_uri',
field=models.CharField(default='https://<domain>/backend/auth/v1/callback', max_length=200),
),
migrations.AlterField(
model_name='oidcconfig',
name='scopes',
field=django_mysql.models.JSONField(default=feudal.backend.auth.v1.models.scopes_default, help_text='The scopes we use when requesting user infos'),
),
migrations.AlterField(
model_name='oidcconfig',
name='userinfo_field_entitlements',
field=models.CharField(blank=True, default='', help_text="The field in the userinfo (served by this IdP) that contains entitlements of the user.\n Leave blank if you don't want to use entitlements of this IdP", max_length=200),
),
migrations.AlterField(
model_name='oidcconfig',
name='userinfo_field_groups',
field=models.CharField(blank=True, default='', help_text="The field in the userinfo (served by this IdP) that contains groups of the user.\n Leave blank if you don't want to use groups of this IdP", max_length=200),
),
]
Markdown is supported
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