Exemplo n.º 1
0
def spid_login(request,
               config_loader_path=None,
               wayf_template='wayf.html',
               authorization_error_template='djangosaml2/auth_error.html'):
    """SAML Authorization Request initiator

    This view initiates the SAML2 Authorization handshake
    using the pysaml2 library to create the AuthnRequest.
    It uses the SAML 2.0 Http POST protocol binding.
    """

    logger.debug('SPID Login process started')
    next_url = request.GET.get('next', settings.LOGIN_REDIRECT_URL)
    if not next_url:
        logger.warning('The next parameter exists but is empty')
        next_url = settings.LOGIN_REDIRECT_URL

    # Ensure the user-originating redirection url is safe.
    if not validate_referral_url(request, next_url):
        next_url = settings.LOGIN_REDIRECT_URL

    if callable(request.user.is_authenticated):
        redirect_authenticated_user = getattr(
            settings, 'SAML_IGNORE_AUTHENTICATED_USERS_ON_LOGIN', True)
        if redirect_authenticated_user:
            return HttpResponseRedirect(next_url)
        else:
            logger.debug('User is already logged in')
            return render(request, authorization_error_template,
                          {'came_from': next_url})

    # this works only if request came from wayf
    selected_idp = request.GET.get('idp', None)

    conf = get_config(config_loader_path, request)

    # is a embedded wayf needed?
    idps = available_idps(conf)
    if selected_idp is None and len(idps) > 1:
        logger.debug('A discovery process is needed')
        return render(request, wayf_template, {
            'available_idps': idps.items(),
            'next_url': next_url
        })
    else:
        # otherwise is the first one
        try:
            selected_idp = selected_idp or list(idps.keys())[0]
        except TypeError as e:
            logger.error('Unable to know which IdP to use')
            return HttpResponse(text_type(e))

    binding = BINDING_HTTP_POST
    logger.debug(f'Trying binding {binding} for IDP {selected_idp}')

    # ensure our selected binding is supported by the IDP
    supported_bindings = get_idp_sso_supported_bindings(selected_idp,
                                                        config=conf)
    if binding != BINDING_HTTP_POST:
        raise UnsupportedBinding('IDP %s does not support %s or %s',
                                 selected_idp, BINDING_HTTP_POST,
                                 BINDING_HTTP_REDIRECT)

    # SPID things here
    login_response = spid_sp_authn_request(conf, selected_idp, binding,
                                           settings.SPID_NAMEID_FORMAT,
                                           settings.SPID_AUTH_CONTEXT,
                                           settings.SPID_SIG_ALG,
                                           settings.SPID_DIG_ALG, next_url)

    session_id = login_response['session_id']
    http_response = login_response['http_response']

    # success, so save the session ID and return our response
    logger.debug(
        f'Saving session-id {session_id} in the OutstandingQueries cache')
    oq_cache = OutstandingQueriesCache(request.saml_session)
    oq_cache.set(session_id, next_url)
    return HttpResponse(http_response['data'])
Exemplo n.º 2
0
def spid_login(
    request,
    config_loader_path=None,
    wayf_template="wayf.html",
    authorization_error_template="djangosaml2/auth_error.html",
):
    """SAML Authorization Request initiator

    This view initiates the SAML2 Authorization handshake
    using the pysaml2 library to create the AuthnRequest.
    It uses the SAML 2.0 Http POST protocol binding.
    """
    logger.debug("SPID Login process started")

    next_url = request.GET.get("next", settings.LOGIN_REDIRECT_URL)
    if not next_url:
        logger.warning("The next parameter exists but is empty")
        next_url = settings.LOGIN_REDIRECT_URL

    # Ensure the user-originating redirection url is safe.
    if not validate_referral_url(request, next_url):
        next_url = settings.LOGIN_REDIRECT_URL

    if request.user.is_authenticated:
        redirect_authenticated_user = getattr(
            settings, "SAML_IGNORE_AUTHENTICATED_USERS_ON_LOGIN", True)
        if redirect_authenticated_user:
            return HttpResponseRedirect(next_url)
        else:  # pragma: no cover
            logger.debug("User is already logged in")
            return render(request, authorization_error_template,
                          {"came_from": next_url})

    # this works only if request came from wayf
    selected_idp = request.GET.get("idp", None)

    conf = get_config(config_loader_path, request)

    # is a embedded wayf needed?
    idps = available_idps(conf)
    if selected_idp is None and len(idps) > 1:
        logger.debug("A discovery process is needed")
        return render(
            request,
            wayf_template,
            {
                "available_idps": idps.items(),
                "next_url": next_url
            },
        )
    else:
        # otherwise is the first one
        _msg = "Unable to know which IdP to use"
        try:
            selected_idp = selected_idp or list(idps.keys())[0]
        except TypeError as e:  # pragma: no cover
            logger.error(f"{_msg}: {e}")
            return HttpResponseNotFound(_msg)
        except IndexError as e:  # pragma: no cover
            logger.error(f"{_msg}: {e}")
            return HttpResponseNotFound(_msg)

    # ensure our selected binding is supported by the IDP
    logger.debug(
        f"Trying binding {SAML2_DEFAULT_BINDING} for IDP {selected_idp}")
    supported_bindings = get_idp_sso_supported_bindings(selected_idp,
                                                        config=conf)
    if not supported_bindings:
        _msg = "IdP Metadata not found or not valid"
        return HttpResponseNotFound(_msg)

    if SAML2_DEFAULT_BINDING not in supported_bindings:
        _msg = (f"Requested: {SAML2_DEFAULT_BINDING} but the selected "
                f"IDP [{selected_idp}] doesn't support "
                f"{BINDING_HTTP_POST} or {BINDING_HTTP_REDIRECT}. "
                f"Check if IdP Metadata is correctly loaded and updated.")
        logger.error(_msg)
        raise UnsupportedBinding(_msg)

    # SPID things here
    try:
        login_response = spid_sp_authn_request(conf, selected_idp, next_url)
    except UnknownSystemEntity as e:  # pragma: no cover
        _msg = f"Unknown IDP Entity ID: {selected_idp}"
        logger.error(f"{_msg}: {e}")
        return HttpResponseNotFound(_msg)

    session_id = login_response["session_id"]
    http_response = login_response["http_response"]

    # success, so save the session ID and return our response
    logger.debug(
        f"Saving session-id {session_id} in the OutstandingQueries cache")
    oq_cache = OutstandingQueriesCache(request.saml_session)
    oq_cache.set(session_id, next_url)

    if SAML2_DEFAULT_BINDING == saml2.BINDING_HTTP_POST:
        return HttpResponse(http_response["data"])
    elif SAML2_DEFAULT_BINDING == saml2.BINDING_HTTP_REDIRECT:
        headers = dict(login_response["http_response"]["headers"])
        return HttpResponseRedirect(headers["Location"])
Exemplo n.º 3
0
def spid_login(request,
          config_loader_path=None,
          wayf_template='wayf.html',
          authorization_error_template='djangosaml2/auth_error.html'):
    """SAML Authorization Request initiator

    This view initiates the SAML2 Authorization handshake
    using the pysaml2 library to create the AuthnRequest.
    It uses the SAML 2.0 Http POST protocol binding.
    """
    
    logger.debug('SPID Login process started')
    next_url = request.GET.get('next', settings.LOGIN_REDIRECT_URL)
    if not next_url:
        logger.warning('The next parameter exists but is empty')
        next_url = settings.LOGIN_REDIRECT_URL

    # Ensure the user-originating redirection url is safe.
    if not validate_referral_url(request, next_url):
        next_url = settings.LOGIN_REDIRECT_URL
    
    if request.user.is_authenticated:
        redirect_authenticated_user = getattr(settings,
                                              'SAML_IGNORE_AUTHENTICATED_USERS_ON_LOGIN',
                                              True)
        if redirect_authenticated_user:
            return HttpResponseRedirect(next_url)
        else: # pragma: no cover
            logger.debug('User is already logged in')
            return render(request, authorization_error_template, {
                    'came_from': next_url})
    
    # this works only if request came from wayf
    selected_idp = request.GET.get('idp', None)

    conf = get_config(config_loader_path, request)

    # is a embedded wayf needed?
    idps = available_idps(conf)
    if selected_idp is None and len(idps) > 1:
        logger.debug('A discovery process is needed')
        return render(request, wayf_template, 
            {
                'available_idps': idps.items(),
                'next_url': next_url
            }
        )
    else:
        # otherwise is the first one
        _msg = 'Unable to know which IdP to use'
        try:
            selected_idp = selected_idp or list(idps.keys())[0]
        except TypeError as e: # pragma: no cover
            logger.error(f'{_msg}: {e}')
            return HttpResponseError(_msg)
        except IndexError as e: # pragma: no cover
            logger.error(f'{_msg}: {e}')
            return HttpResponseNotFound(_msg)
    
    binding = settings.SPID_DEFAULT_BINDING
    logger.debug(f'Trying binding {binding} for IDP {selected_idp}')
    # ensure our selected binding is supported by the IDP
    supported_bindings = get_idp_sso_supported_bindings(selected_idp, config=conf)
    if binding not in supported_bindings:
        _msg = (
                f"Requested: {binding} but the selected "
                f"IDP [{selected_idp}] doesn't support "
                f"{BINDING_HTTP_POST} or {BINDING_HTTP_REDIRECT}. "
                f"Check if IdP Metadata is correctly loaded and updated."
        )
        logger.error(_msg)
        raise UnsupportedBinding(_msg)

    # SPID things here
    try:
        login_response = spid_sp_authn_request(conf, 
                                               selected_idp, 
                                               binding, 
                                               settings.SPID_NAMEID_FORMAT,
                                               settings.SPID_AUTH_CONTEXT,
                                               settings.SPID_SIG_ALG,
                                               settings.SPID_DIG_ALG,
                                               next_url
        )
    except UnknownSystemEntity as e: # pragma: no cover
        _msg = f'Unknown IDP Entity ID: {selected_idp}'
        logger.error(f'{_msg}: {e}')
        return HttpResponseNotFound(_msg)
    
    session_id = login_response['session_id']
    http_response = login_response['http_response']
    
    # success, so save the session ID and return our response
    logger.debug(f'Saving session-id {session_id} in the OutstandingQueries cache')
    oq_cache = OutstandingQueriesCache(request.saml_session)
    oq_cache.set(session_id, next_url)
    
    if binding == saml2.BINDING_HTTP_POST:
        return HttpResponse(http_response['data'])
    elif binding == saml2.BINDING_HTTP_REDIRECT:
        headers = dict(login_response['http_response']['headers'])
        return HttpResponseRedirect(headers['Location'])