Compare commits
4 Commits
main
...
wip/32376-
Author | SHA1 | Date |
---|---|---|
Valentin Deniaud | 1c3f3d887c | |
Valentin Deniaud | 12a5327367 | |
Valentin Deniaud | 2aae735841 | |
Valentin Deniaud | 0f26806791 |
|
@ -182,33 +182,20 @@ class DefaultAdapter(object):
|
|||
user.save()
|
||||
|
||||
def provision_superuser(self, user, idp, saml_attributes):
|
||||
superuser_mapping = utils.get_setting(idp, 'SUPERUSER_MAPPING')
|
||||
if not superuser_mapping:
|
||||
return
|
||||
attribute_set = False
|
||||
for key, values in superuser_mapping.items():
|
||||
if key in saml_attributes:
|
||||
if not isinstance(values, (tuple, list)):
|
||||
values = [values]
|
||||
values = set(values)
|
||||
attribute_values = saml_attributes[key]
|
||||
if not isinstance(attribute_values, (tuple, list)):
|
||||
attribute_values = [attribute_values]
|
||||
attribute_values = set(attribute_values)
|
||||
if attribute_values & values:
|
||||
if not (user.is_staff and user.is_superuser):
|
||||
user.is_staff = True
|
||||
user.is_superuser = True
|
||||
attribute_set = True
|
||||
self.logger.info('flag is_staff and is_superuser added to user %s', user)
|
||||
break
|
||||
if utils.has_superuser_flag(idp, saml_attributes):
|
||||
if not (user.is_staff and user.is_superuser):
|
||||
user.is_staff = True
|
||||
user.is_superuser = True
|
||||
user.save()
|
||||
self.logger.info('flag is_staff and is_superuser added to user %s', user)
|
||||
else:
|
||||
if user.is_superuser or user.is_staff:
|
||||
user.is_staff = False
|
||||
user.is_superuser = False
|
||||
self.logger.info('flag is_staff and is_superuser removed from user %s', user)
|
||||
attribute_set = True
|
||||
if attribute_set:
|
||||
self.remove_superuser(user)
|
||||
|
||||
def remove_superuser(self, user):
|
||||
if user.is_superuser or user.is_staff:
|
||||
user.is_staff = False
|
||||
user.is_superuser = False
|
||||
self.logger.info('flag is_staff and is_superuser removed from user %s', user)
|
||||
user.save()
|
||||
|
||||
def provision_groups(self, user, idp, saml_attributes):
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
class RolesNotInSession(Exception):
|
||||
|
||||
def __init__(self, roles):
|
||||
self.roles = roles
|
|
@ -3,6 +3,7 @@ from django.http import HttpResponseRedirect
|
|||
from django.core.urlresolvers import reverse
|
||||
|
||||
from . import app_settings, utils
|
||||
from .exceptions import RolesNotInSession
|
||||
|
||||
PASSIVE_TRIED_COOKIE = 'MELLON_PASSIVE_TRIED'
|
||||
|
||||
|
@ -50,3 +51,10 @@ class PassiveAuthenticationMiddleware(object):
|
|||
# prevent loops
|
||||
response.set_cookie(PASSIVE_TRIED_COOKIE, value='1', max_age=None)
|
||||
return response
|
||||
|
||||
|
||||
class RolesRequestMiddleware(object):
|
||||
def process_exception(self, request, exception):
|
||||
if isinstance(exception, RolesNotInSession):
|
||||
return HttpResponseRedirect(
|
||||
utils.get_role_request_url(request, exception.roles))
|
||||
|
|
|
@ -6,7 +6,9 @@ import isodate
|
|||
from xml.parsers import expat
|
||||
|
||||
from django.contrib import auth
|
||||
from django.contrib.auth.models import Group
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.http import QueryDict, HttpResponseRedirect
|
||||
from django.template.loader import render_to_string
|
||||
from django.utils.timezone import make_aware, now, make_naive, is_aware, get_default_timezone
|
||||
from django.conf import settings
|
||||
|
@ -14,6 +16,7 @@ from django.utils.six.moves.urllib.parse import urlparse
|
|||
import lasso
|
||||
|
||||
from . import app_settings
|
||||
from .exceptions import RolesNotInSession
|
||||
|
||||
|
||||
def create_metadata(request):
|
||||
|
@ -271,3 +274,49 @@ def get_local_path(request, url):
|
|||
if request.META.get('SCRIPT_NAME'):
|
||||
path = path[len(request.META['SCRIPT_NAME']):]
|
||||
return path
|
||||
|
||||
|
||||
def has_superuser_flag(idp, saml_attributes):
|
||||
superuser_mapping = get_setting(idp, 'SUPERUSER_MAPPING')
|
||||
if not superuser_mapping:
|
||||
return False
|
||||
for key, values in superuser_mapping.items():
|
||||
if key in saml_attributes:
|
||||
if not isinstance(values, (tuple, list)):
|
||||
values = [values]
|
||||
values = set(values)
|
||||
attribute_values = saml_attributes[key]
|
||||
if not isinstance(attribute_values, (tuple, list)):
|
||||
attribute_values = [attribute_values]
|
||||
attribute_values = set(attribute_values)
|
||||
if attribute_values & values:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def user_has_roles(request, roles):
|
||||
if request.user.is_staff and request.session.get('is_staff'):
|
||||
return True
|
||||
groups = set(roles).intersection(request.user.groups.all())
|
||||
if not groups:
|
||||
if request.user.is_staff:
|
||||
raise RolesNotInSession(('staff',))
|
||||
return False
|
||||
role_uuids = {getattr(group, 'role').uuid for group in groups}
|
||||
if not role_uuids:
|
||||
return True
|
||||
if set(request.session['mellon_session']['role-slug']) & role_uuids:
|
||||
return True
|
||||
raise RolesNotInSession(role_uuids)
|
||||
|
||||
|
||||
def user_has_role(request, role):
|
||||
return user_has_roles(request, {role})
|
||||
|
||||
|
||||
def get_role_request_url(request, roles):
|
||||
login_url = reverse(app_settings.LOGIN_URL)
|
||||
q = QueryDict(mutable=True)
|
||||
q.setlist('roles', roles)
|
||||
q['next'] = request.get_full_path()
|
||||
return '?'.join((login_url, q.urlencode(safe='/')))
|
||||
|
|
|
@ -19,6 +19,7 @@ from django.utils import six
|
|||
from django.utils.encoding import force_text
|
||||
from django.contrib.auth import REDIRECT_FIELD_NAME
|
||||
from django.db import transaction
|
||||
from django.utils.six.moves.urllib.parse import urljoin
|
||||
from django.utils.translation import ugettext as _
|
||||
|
||||
from . import app_settings, utils
|
||||
|
@ -217,6 +218,8 @@ class LoginView(ProfileMixin, LogMixin, View):
|
|||
if user is not None:
|
||||
if user.is_active:
|
||||
utils.login(request, user)
|
||||
idp = self.get_idp(request)
|
||||
request.session['is_staff'] = utils.has_superuser_flag(idp, attributes)
|
||||
self.log.info('user %s (NameID is %r) logged in using SAML', user,
|
||||
attributes['name_id_content'])
|
||||
request.session['mellon_session'] = utils.flatten_datetime(attributes)
|
||||
|
@ -375,6 +378,7 @@ class LoginView(ProfileMixin, LogMixin, View):
|
|||
request, is_passive=request.GET.get('passive') == '1')
|
||||
|
||||
next_url = check_next_url(self.request, request.GET.get(REDIRECT_FIELD_NAME))
|
||||
requested_roles = request.GET.getlist('roles')
|
||||
idp = self.get_idp(request)
|
||||
if idp is None:
|
||||
return HttpResponseBadRequest('no idp found')
|
||||
|
@ -394,7 +398,13 @@ class LoginView(ProfileMixin, LogMixin, View):
|
|||
authn_request.isPassive = True
|
||||
# configure requested AuthnClassRef
|
||||
authn_classref = utils.get_setting(idp, 'AUTHN_CLASSREF')
|
||||
if authn_classref:
|
||||
if requested_roles:
|
||||
prefix = 'https://entrouvert.com/authn-class-ref/role-uuid/' # TODO add setting
|
||||
authn_classref = tuple(str(urljoin(prefix, role)) for role in requested_roles)
|
||||
req_authncontext = lasso.Samlp2RequestedAuthnContext()
|
||||
authn_request.requestedAuthnContext = req_authncontext
|
||||
req_authncontext.authnContextClassRef = authn_classref
|
||||
elif authn_classref:
|
||||
authn_classref = tuple([str(x) for x in authn_classref])
|
||||
req_authncontext = lasso.Samlp2RequestedAuthnContext()
|
||||
authn_request.requestedAuthnContext = req_authncontext
|
||||
|
|
Loading…
Reference in New Issue