59 |
59 |
from django.contrib.auth import load_backend
|
60 |
60 |
from django.shortcuts import render, redirect
|
61 |
61 |
from django.contrib import messages
|
|
62 |
from django.db.models import Min
|
62 |
63 |
|
|
64 |
from django_rbac.utils import get_role_model
|
63 |
65 |
|
64 |
66 |
import authentic2.views as a2_views
|
65 |
67 |
from authentic2.saml.models import (
|
... | ... | |
101 |
103 |
|
102 |
104 |
|
103 |
105 |
User = get_user_model()
|
|
106 |
Role = get_role_model()
|
104 |
107 |
|
105 |
108 |
logger = logging.getLogger(__name__)
|
106 |
109 |
|
... | ... | |
539 |
542 |
return sso_after_process_request(request, login, nid_format=nid_format)
|
540 |
543 |
|
541 |
544 |
|
542 |
|
def need_login(request, login, nid_format, service):
|
|
545 |
def need_login(request, login, nid_format, service, auth_level=None):
|
543 |
546 |
"""Redirect to the login page with a nonce parameter to verify later that
|
544 |
547 |
the login form was submitted
|
545 |
548 |
"""
|
546 |
549 |
nonce = login.request.id or get_nonce()
|
547 |
550 |
save_key_values(nonce, login.dump(), False, nid_format)
|
548 |
|
next_url = make_url(continue_sso, params={NONCE_FIELD_NAME: nonce})
|
|
551 |
params = {
|
|
552 |
NONCE_FIELD_NAME: nonce
|
|
553 |
}
|
|
554 |
next_url = make_url(continue_sso, params=params)
|
|
555 |
if auth_level:
|
|
556 |
params['auth_level'] = auth_level
|
549 |
557 |
logger.debug('redirect to login page with next url %s', next_url)
|
550 |
|
return login_require(request, next_url=next_url, params={NONCE_FIELD_NAME: nonce},
|
551 |
|
service=service)
|
|
558 |
return login_require(request, next_url=next_url, params=params, service=service)
|
552 |
559 |
|
553 |
560 |
|
554 |
561 |
def get_url_with_nonce(request, function, nonce):
|
... | ... | |
645 |
652 |
did_auth = find_authentication_event(request, nonce) is not None
|
646 |
653 |
force_authn = login.request.forceAuthn
|
647 |
654 |
passive = login.request.isPassive
|
|
655 |
service = LibertyServiceProvider.objects.get(
|
|
656 |
liberty_provider__entity_id=login.remoteProviderId).liberty_provider
|
|
657 |
|
|
658 |
prefix = 'https://entrouvert.com/authn-class-ref/role-uuid/' # TODO setting
|
|
659 |
requested_auth_level = 1
|
|
660 |
if login.request.requestedAuthnContext:
|
|
661 |
authn_classrefs = login.request.requestedAuthnContext.authnContextClassRef
|
|
662 |
roles = Role.objects.for_user(request.user, annotate=True)
|
|
663 |
role_uuids = set()
|
|
664 |
for classref in authn_classrefs:
|
|
665 |
if classref.startswith(prefix):
|
|
666 |
role_uuid = classref[len(prefix):]
|
|
667 |
if role_uuid == 'staff':
|
|
668 |
role_uuids.update(service.roles.values_list('uuid', flat=True))
|
|
669 |
else:
|
|
670 |
role_uuids.add(role_uuid)
|
|
671 |
requested_roles = roles.filter(uuid__in=role_uuids)
|
|
672 |
# TODO if empty, fail with error 'user do not have requested roles'
|
|
673 |
requested_auth_level = \
|
|
674 |
requested_roles.aggregate(min_lvl=Min('needed_auth_level'))['min_lvl']
|
648 |
675 |
|
649 |
676 |
logger.debug('NameIDFormat is %s', nid_format)
|
650 |
677 |
logger.debug('nonce is %s', nonce)
|
651 |
678 |
|
652 |
679 |
# check if user is authorized through this service
|
653 |
|
service = LibertyServiceProvider.objects.get(
|
654 |
|
liberty_provider__entity_id=login.remoteProviderId).liberty_provider
|
655 |
|
|
656 |
|
if not passive and \
|
657 |
|
(user.is_anonymous() or (force_authn and not did_auth)):
|
658 |
|
logger.debug('login required')
|
659 |
|
return need_login(request, login, nid_format, service)
|
660 |
|
|
661 |
|
# No user is authenticated and passive is True, deny request
|
662 |
|
if passive and user.is_anonymous():
|
|
680 |
current_auth_level = request.session.get('auth_level', 1)
|
|
681 |
if not passive:
|
|
682 |
if not user.is_anonymous() and requested_auth_level > current_auth_level:
|
|
683 |
logger.debug('authentication level increase required')
|
|
684 |
requested_auth_level = current_auth_level + 1 # progressively increase auth level
|
|
685 |
return need_login(request, login, nid_format, service, requested_auth_level)
|
|
686 |
if user.is_anonymous() or (force_authn and not did_auth):
|
|
687 |
logger.debug('login required')
|
|
688 |
return need_login(request, login, nid_format, service)
|
|
689 |
|
|
690 |
# No user is authenticated or authentication level is too low and passive
|
|
691 |
# is True, deny request
|
|
692 |
if passive and (user.is_anonymous() or requested_auth_level > current_auth_level):
|
663 |
693 |
logger.debug('no user connected and passive request, returning NoPassive')
|
664 |
694 |
set_saml2_response_responder_status_code(login.response, lasso.SAML2_STATUS_CODE_NO_PASSIVE)
|
665 |
695 |
return finish_sso(request, login)
|
666 |
|
-
|