def login_action(session_info, user): """ Upon successful login in the IdP, store login info in the session and redirect back to the app that asked for authn. :param session_info: the SAML session info :type session_info: dict :param user: the authenticated user :type user: eduid_userdb.User """ current_app.logger.info("User {} logging in.".format(user)) session['_saml2_session_name_id'] = code(session_info['name_id']) session['eduPersonPrincipalName'] = user.eppn session['user_eppn'] = user.eppn loa = get_loa(current_app.config.get('AVAILABLE_LOA'), session_info) session['eduPersonAssurance'] = loa session.persist() # redirect the user to the view where he came from relay_state = verify_relay_state(request.form.get('RelayState', '/')) current_app.logger.debug('Redirecting to the RelayState: ' + relay_state) response = redirect(location=relay_state) session.set_cookie(response) current_app.logger.info('Redirecting user {} to {!r}'.format( user, relay_state)) return response
def logout_service(): """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. """ current_app.logger.debug('Logout service started') state = StateCache(session) identity = IdentityCache(session) client = Saml2Client(current_app.saml2_config, state_cache=state, identity_cache=identity) logout_redirect_url = current_app.config.get('SAML2_LOGOUT_REDIRECT_URL') next_page = session.get('next', logout_redirect_url) next_page = request.args.get('next', next_page) next_page = request.form.get('RelayState', next_page) next_page = verify_relay_state(next_page, logout_redirect_url) if 'SAMLResponse' in request.form: # we started the logout current_app.logger.debug('Receiving a logout response from the IdP') response = client.parse_logout_request_response( request.form['SAMLResponse'], BINDING_HTTP_REDIRECT) state.sync() if response and response.status_ok(): session.clear() return redirect(next_page) else: current_app.logger.error('Unknown error during the logout') abort(400) # logout started by the IdP elif 'SAMLRequest' in request.form: current_app.logger.debug('Receiving a logout request from the IdP') subject_id = _get_name_id(session) if subject_id is None: current_app.logger.warning( 'The session does not contain the subject id for user {0} ' 'Performing local logout'.format( session['eduPersonPrincipalName'])) session.clear() return redirect(next_page) else: http_info = client.handle_logout_request( request.form['SAMLRequest'], subject_id, BINDING_HTTP_REDIRECT, relay_state=request.form['RelayState']) state.sync() location = get_location(http_info) session.clear() return redirect(location) current_app.logger.error('No SAMLResponse or SAMLRequest parameter found') abort(400)
def logout(): """ SAML Logout Request initiator. This view initiates the SAML2 Logout request using the pysaml2 library to create the LogoutRequest. """ eppn = session.get('user_eppn') if eppn is None: current_app.logger.info( 'Session cookie has expired, no logout action needed') location = current_app.config.get('SAML2_LOGOUT_REDIRECT_URL') return redirect(location) user = current_app.central_userdb.get_user_by_eppn(eppn) current_app.logger.debug('Logout process started for user {}'.format(user)) state = StateCache(session) identity = IdentityCache(session) client = Saml2Client(current_app.saml2_config, state_cache=state, identity_cache=identity) # The user doesn't have a SAML2 NameID in the session # after a token login from Signup into Dashboard. subject_id = _get_name_id(session) if subject_id is None: current_app.logger.warning('The session does not contain ' 'the subject id for user {}'.format(user)) session.clear() location = current_app.config.get('SAML2_LOGOUT_REDIRECT_URL') else: logouts = client.global_logout(subject_id) loresponse = logouts.values()[0] # loresponse is a dict for REDIRECT binding, and LogoutResponse for SOAP binding if isinstance(loresponse, LogoutResponse): if loresponse.status_ok(): current_app.logger.debug( 'Performing local logout for {}'.format(user)) session.clear() location = current_app.config.get('SAML2_LOGOUT_REDIRECT_URL') location = verify_relay_state( request.form.get('RelayState', location), location) return redirect(location) else: abort(500) headers_tuple = loresponse[1]['headers'] location = headers_tuple[0][1] current_app.logger.info( 'Redirecting to {!r} to continue the logout process ' 'for user {}'.format(location, user)) state.sync() return redirect(location)
def _reauthn(reason, session_info, user): current_app.logger.info("Reauthenticating user {} for {!r}.".format( user, reason)) session['_saml2_session_name_id'] = code(session_info['name_id']) session[reason] = int(time()) session.persist() # redirect the user to the view where he came from relay_state = verify_relay_state(request.form.get('RelayState', '/')) current_app.logger.debug('Redirecting to the RelayState: ' + relay_state) return redirect(location=relay_state)
def _authn(action, force_authn=False): redirect_url = current_app.config.get('SAML2_LOGIN_REDIRECT_URL', '/') relay_state = verify_relay_state(request.args.get('next', redirect_url), redirect_url) idps = current_app.saml2_config.getattr('idp') assert len(idps) == 1 idp = idps.keys()[0] idp = request.args.get('idp', idp) loa = request.args.get('required_loa', None) authn_request = get_authn_request(current_app.config, session, relay_state, idp, required_loa=loa, force_authn=force_authn) schedule_action(action) current_app.logger.info('Redirecting the user to the IdP for ' + action) return redirect(get_location(authn_request))