예제 #1
0
def logout_service(request):
    """SAML Logout Response endpoint

    The IdP will send the logout response to this view,
    which will process it with pysaml2 help and log the user
    out.
    Note that the IdP can request a logout even when
    we didn't initiate the process as a single logout
    request started by another SP.
    """
    log.debug('Logout service started')

    state = StateCache(request.session)
    client = Saml2Client(request.saml2_config, state_cache=state,
                         identity_cache=IdentityCache(request.session))
    settings = request.registry.settings

    logout_redirect_url = settings.get('saml2.logout_redirect_url')
    next_page = request.GET.get('next_page', logout_redirect_url)

    if 'SAMLResponse' in request.GET:  # we started the logout
        log.debug('Receiving a logout response from the IdP')
        response = client.parse_logout_request_response(
            request.GET['SAMLResponse'],
            BINDING_HTTP_REDIRECT
        )
        state.sync()
        if response and response.status_ok():
            headers = logout(request)
            return HTTPFound(next_page, headers=headers)
        else:
            log.error('Unknown error during the logout')
            return HTTPBadRequest('Error during logout')

    elif 'SAMLRequest' in request.GET:  # logout started by the IdP
        log.debug('Receiving a logout request from the IdP')
        subject_id = _get_name_id(request.session)
        if subject_id is None:
            log.warning(
                'The session does not contain the subject id for user {0} '
                'Performing local logout'.format(
                    authenticated_userid(request)
                )
            )
            headers = logout(request)
            return HTTPFound(location=next_page, headers=headers)
        else:
            http_info = client.handle_logout_request(
                request.GET['SAMLRequest'],
                subject_id,
                BINDING_HTTP_REDIRECT,
                relay_state=request.GET['RelayState']
            )
            state.sync()
            location = get_location(http_info)
            headers = logout(request)
            return HTTPFound(location=location, headers=headers)
    else:
        log.error('No SAMLResponse or SAMLRequest parameter found')
        raise HTTPNotFound('No SAMLResponse or SAMLRequest parameter found')
예제 #2
0
def login_view(request):
    login_redirect_url = request.registry.settings.get(
        'saml2.login_redirect_url', '/')

    came_from = sanitize_get(request, 'next', login_redirect_url)

    if authenticated_userid(request):
        return HTTPFound(location=came_from)

    selected_idp = sanitize_get(request, 'idp', None)
    if selected_idp is not None:
        request.session['selected_idp'] = selected_idp

    idps = request.saml2_config.getattr('idp')
    if selected_idp is None and len(idps) > 1:
        log.debug('A discovery process is needed')

        return render_to_response('templates/wayf.jinja2', {
            'available_idps': idps.items(),
            'came_from': came_from,
            'login_url': request.route_url('saml2-login'),
        })

    result = get_authn_request(request.registry.settings, request.session,
                               came_from, selected_idp)

    schedule_action(request.session, 'login-action')

    log.debug('Redirecting the user to the IdP')
    if not request.is_xhr:
        return HTTPFound(location=get_location(result))
    else:
        loginurl = request.route_url('saml2-login',
                                     _query=(('next', request.path),))
        return HTTPXRelocate(loginurl)
예제 #3
0
def login_view(request):
    login_redirect_url = request.registry.settings.get(
        'saml2.login_redirect_url', '/')

    came_from = request.GET.get('next', login_redirect_url)

    if authenticated_userid(request):
        return HTTPFound(location=came_from)

    selected_idp = request.GET.get('idp', None)

    idps = request.saml2_config.getattr('idp')
    if selected_idp is None and len(idps) > 1:
        log.debug('A discovery process is needed')

        return render_to_response('templates/wayf.jinja2', {
            'available_idps': idps.items(),
            'came_from': came_from,
            'login_url': request.route_url('saml2-login'),
        })

    # Request the right AuthnContext for workmode
    # (AL1 for 'personal', AL2 for 'helpdesk' and AL3 for 'admin' by default)
    required_loa = request.registry.settings.get('required_loa', {})
    workmode = request.registry.settings.get('workmode')
    required_loa = required_loa.get(workmode, '')
    log.debug('Requesting AuthnContext {!r} for workmode {!r}'.format(required_loa, workmode))
    kwargs = {
        "requested_authn_context": RequestedAuthnContext(
            authn_context_class_ref=AuthnContextClassRef(
                text=required_loa
            )
        )
    }

    client = Saml2Client(request.saml2_config)
    try:
        (session_id, result) = client.prepare_for_authenticate(
            entityid=selected_idp, relay_state=came_from,
            binding=BINDING_HTTP_REDIRECT,
            **kwargs
        )
    except TypeError:
        log.error('Unable to know which IdP to use')
        raise

    oq_cache = OutstandingQueriesCache(request.session)
    oq_cache.set(session_id, came_from)

    log.debug('Redirecting the user to the IdP')
    if not request.is_xhr:
        return HTTPFound(location=get_location(result))
    else:
        loginurl = request.route_url('saml2-login',
                                     _query=(('next', request.path),))
        return HTTPXRelocate(loginurl)
예제 #4
0
def start_password_change(context, request):
    '''
    '''
    # check csrf
    csrf = sanitize_post_key(request, 'csrf')
    if csrf != request.session.get_csrf_token():
        return HTTPBadRequest()

    selected_idp = request.session.get('selected_idp')
    relay_state = context.route_url('profile-editor')
    loa = context.get_loa()
    info = get_authn_request(request.registry.settings, request.session,
                             relay_state, selected_idp,
                             required_loa=loa, force_authn=True)
    schedule_action(request.session, 'change-password-action')

    return HTTPFound(location=get_location(info))
예제 #5
0
def terminate_account(context, request):
    '''
    Terminate account view.
    It receives a POST request, checks the csrf token,
    schedules the account termination action,
    and redirects to the IdP.
    '''
    settings = request.registry.settings

    # check csrf
    csrf = request.POST.get('csrf')
    if csrf != request.session.get_csrf_token():
        return HTTPBadRequest()

    selected_idp = request.session.get('selected_idp')
    relay_state = context.route_url('account-terminated')
    loa = context.get_loa()
    info = get_authn_request(request, relay_state, selected_idp,
                             required_loa=loa, force_authn=True)
    schedule_action(request.session, 'account-termination-action')

    return HTTPFound(location=get_location(info))