コード例 #1
0
ファイル: helpers.py プロジェクト: SUNET/eduid-webapp
def handle_freja_eid_userinfo(user, proofing_state, userinfo):
    """
    :param user: Central userdb user
    :param proofing_state: Proofing state for user
    :param userinfo: userinfo from OP

    :type user: eduid_userdb.user.User
    :type proofing_state: eduid_userdb.proofing.OidcProofingState
    :type userinfo: dict

    :return: None
    """
    current_app.logger.info('Verifying NIN from Freja eID for user {}'.format(user))
    number = userinfo['results']['freja_eid']['ssn']
    opaque = userinfo['results']['freja_eid']['opaque']
    transaction_id = userinfo['results']['freja_eid']['ref']
    if not number_match_proofing(user, proofing_state, number):
        current_app.logger.warning('Proofing state number did not match number in userinfo.'
                                   'Using number from userinfo.')
        proofing_state.nin.number = number

    current_app.logger.info('Getting address for user {}'.format(user))
    # Lookup official address via Navet
    address = current_app.msg_relay.get_postal_address(proofing_state.nin.number, timeout=15)
    proofing_log_entry = SeLegProofingFrejaEid(user, created_by=proofing_state.nin.created_by,
                                               nin=proofing_state.nin.number, transaction_id=transaction_id,
                                               opaque_data=opaque, user_postal_address=address,
                                               proofing_version='2017v1')
    verify_nin_for_user(user, proofing_state, proofing_log_entry)
    current_app.stats.count(name='freja.authn_response_handled')
コード例 #2
0
ファイル: helpers.py プロジェクト: SUNET/eduid-webapp
def handle_seleg_userinfo(user, proofing_state, userinfo):
    """
    :param user: Central userdb user
    :param proofing_state: Proofing state for user
    :param userinfo: userinfo from OP

    :type user: eduid_userdb.user.User
    :type proofing_state: eduid_userdb.proofing.OidcProofingState

    :type userinfo: dict
    :return: None
    """
    current_app.logger.info('Verifying NIN from seleg for user {}'.format(user))
    number = userinfo['identity']
    metadata = userinfo.get('metadata', {})
    if metadata.get('score', 0) == 100:
        if not number_match_proofing(user, proofing_state, number):
            current_app.logger.warning('Proofing state number did not match number in userinfo.'
                                       'Using number from userinfo.')
            proofing_state.nin.number = number
        current_app.logger.info('Getting address for user {}'.format(user))
        # Lookup official address via Navet
        address = current_app.msg_relay.get_postal_address(proofing_state.nin.number, timeout=15)
        # Transaction id is the same data as used for the QR code
        transaction_id = metadata['opaque']
        proofing_log_entry = SeLegProofing(user, created_by=proofing_state.nin.created_by,
                                           nin=proofing_state.nin.number, vetting_by='se-leg',
                                           transaction_id=transaction_id, user_postal_address=address,
                                           proofing_version='2017v1')
        verify_nin_for_user(user, proofing_state, proofing_log_entry)
        current_app.stats.count(name='seleg.authn_response_handled')
    else:
        current_app.logger.info('se-leg proofing did not result in a verified account due to low score')
        current_app.stats.count(name='seleg.authn_response_with_low_score')
        send_new_verification_method_mail(user)
コード例 #3
0
ファイル: views.py プロジェクト: johanlundberg/eduid-webapp
def proofing(user, nin):
    current_app.logger.info('Trying to verify nin via mobile number for user {}.'.format(user))
    current_app.logger.debug('NIN: {!s}.'.format(nin))

    # Add nin as not verified to the user
    proofing_state = create_proofing_state(user, nin)
    add_nin_to_user(user, proofing_state)

    # Get list of verified mobile numbers
    verified_mobiles = [item.number for item in user.phone_numbers.to_list() if item.is_verified]
    if not verified_mobiles:
        return {'_status': 'error', 'message': 'no_phone'}

    try:
        success, proofing_log_entry = match_mobile_to_user(user, nin, verified_mobiles)
    except LookupMobileTaskFailed:
        current_app.stats.count('validate_nin_by_mobile_error')
        return {'_status': 'error', 'message': 'error_lookup_mobile_task'}
    except MsgTaskFailed:
        current_app.stats.count('navet_error')
        return {'_status': 'error', 'message': 'error_navet_task'}

    if success:
        try:
            # Verify nin for user
            verify_nin_for_user(user, proofing_state, proofing_log_entry)
            return {'success': True, 'message': 'letter.verification_success'}
        except AmTaskFailed as e:
            current_app.logger.error('Verifying nin for user {} failed'.format(user))
            current_app.logger.error('{}'.format(e))
            return {'_status': 'error', 'message': 'Temporary technical problems'}

    return {'_status': 'error', 'message': 'nins.no-mobile-match'}
コード例 #4
0
ファイル: acs_actions.py プロジェクト: SUNET/eduid-webapp
def nin_verify_action(session_info, user):
    """
    Use a Sweden Connect federation IdP assertion to verify a users identity.

    :param session_info: the SAML session info
    :param user: Central db user

    :type session_info: dict
    :type user: eduid_userdb.User

    :return: redirect response
    :rtype: Response
    """
    redirect_url = urlappend(current_app.config['DASHBOARD_URL'], 'nins')

    if not is_required_loa(session_info, 'loa3'):
        return redirect_with_msg(redirect_url, ':ERROR:eidas.authn_context_mismatch')

    if not is_valid_reauthn(session_info):
        return redirect_with_msg(redirect_url, ':ERROR:eidas.reauthn_expired')

    proofing_user = ProofingUser.from_user(user, current_app.private_userdb)
    asserted_nin = get_saml_attribute(session_info, 'personalIdentityNumber')[0]

    if proofing_user.nins.verified.count != 0:
        current_app.logger.error('User already has a verified NIN')
        current_app.logger.debug('Primary NIN: {}. Asserted NIN: {}'.format(proofing_user.nins.primary.number,
                                                                            asserted_nin))
        return redirect_with_msg(redirect_url, ':ERROR:eidas.nin_already_verified')

    # Create a proofing log
    issuer = session_info['issuer']
    authn_context = get_authn_ctx(session_info)
    try:
        user_address = current_app.msg_relay.get_postal_address(asserted_nin)
    except MsgTaskFailed as e:
        current_app.logger.error('Navet lookup failed: {}'.format(e))
        current_app.stats.count('navet_error')
        return redirect_with_msg(redirect_url, ':ERROR:error_navet_task')

    proofing_log_entry = SwedenConnectProofing(user=proofing_user, created_by='eduid-eidas', nin=asserted_nin,
                                               issuer=issuer, authn_context_class=authn_context,
                                               user_postal_address=user_address, proofing_version='2018v1')

    # Verify NIN for user
    try:
        nin_element = NinProofingElement(number=asserted_nin, application='eduid-eidas', verified=False)
        proofing_state = NinProofingState({'eduPersonPrincipalName': user.eppn, 'nin': nin_element.to_dict()})
        verify_nin_for_user(user, proofing_state, proofing_log_entry)
    except AmTaskFailed as e:
        current_app.logger.error('Verifying NIN for user failed')
        current_app.logger.error('{}'.format(e))
        return redirect_with_msg(redirect_url, ':ERROR:Temporary technical problems')
    current_app.stats.count(name='nin_verified')

    return redirect_with_msg(redirect_url, 'eidas.nin_verify_success')
コード例 #5
0
ファイル: helpers.py プロジェクト: johanlundberg/eduid-webapp
def handle_seleg_userinfo(user, proofing_state, userinfo):
    """
    :param user: Central userdb user
    :param proofing_state: Proofing state for user
    :param userinfo: userinfo from OP

    :type user: eduid_userdb.user.User
    :type proofing_state: eduid_userdb.proofing.OidcProofingState

    :type userinfo: dict
    :return: None
    """
    current_app.logger.info(
        'Verifying NIN from seleg for user {}'.format(user))
    number = userinfo['identity']
    metadata = userinfo.get('metadata', {})
    if metadata.get('score', 0) == 100:
        if not number_match_proofing(user, proofing_state, number):
            current_app.logger.warning(
                'Proofing state number did not match number in userinfo.'
                'Using number from userinfo.')
            proofing_state.nin.number = number
        current_app.logger.info('Getting address for user {}'.format(user))
        # Lookup official address via Navet
        address = current_app.msg_relay.get_postal_address(
            proofing_state.nin.number, timeout=15)
        # Transaction id is the same data as used for the QR code
        transaction_id = metadata['opaque']
        proofing_log_entry = SeLegProofing(
            user,
            created_by=proofing_state.nin.created_by,
            nin=proofing_state.nin.number,
            vetting_by='se-leg',
            transaction_id=transaction_id,
            user_postal_address=address,
            proofing_version='2017v1')
        verify_nin_for_user(user, proofing_state, proofing_log_entry)
        current_app.stats.count(name='seleg.authn_response_handled')
    else:
        current_app.logger.info(
            'se-leg proofing did not result in a verified account due to low score'
        )
        current_app.stats.count(name='seleg.authn_response_with_low_score')
        send_new_verification_method_mail(user)
コード例 #6
0
def nin_verify_BACKDOOR(user: User) -> WerkzeugResponse:
    """
    Mock using a Sweden Connect federation IdP assertion to verify a users identity
    when the request carries a magic cookie.

    :param user: Central db user

    :return: redirect response
    """

    redirect_url = current_app.config.nin_verify_redirect_url

    proofing_user = ProofingUser.from_user(user, current_app.private_userdb)
    asserted_nin = request.cookies.get('nin')

    if proofing_user.nins.verified.count != 0:
        current_app.logger.error('User already has a verified NIN')
        current_app.logger.debug(
            'Primary NIN: {}. Asserted NIN: {}'.format(proofing_user.nins.primary.number, asserted_nin)
        )
        return redirect_with_msg(redirect_url, ':ERROR:eidas.nin_already_verified')

    # Create a proofing log
    issuer = 'https://idp.example.com/simplesaml/saml2/idp/metadata.php'
    authn_context = 'http://id.elegnamnden.se/loa/1.0/loa3'

    user_address = {
        'Name': {'GivenNameMarking': '20', 'GivenName': 'Magic Cookie', 'Surname': 'Testsson'},
        'OfficialAddress': {'Address2': 'MAGIC COOKIE', 'PostalCode': '12345', 'City': 'LANDET'},
    }

    proofing_log_entry = SwedenConnectProofing(
        user=proofing_user,
        created_by='eduid-eidas',
        nin=asserted_nin,
        issuer=issuer,
        authn_context_class=authn_context,
        user_postal_address=user_address,
        proofing_version='2018v1',
    )

    # Verify NIN for user
    try:
        nin_element = NinProofingElement.from_dict(dict(number=asserted_nin, created_by='eduid-eidas', verified=False))
        proofing_state = NinProofingState(id=None, modified_ts=None, eppn=user.eppn, nin=nin_element)
        if not verify_nin_for_user(user, proofing_state, proofing_log_entry):
            current_app.logger.error(f'Failed verifying NIN for user {user}')
            return redirect_with_msg(redirect_url, ':ERROR:Temporary technical problems')
    except AmTaskFailed:
        current_app.logger.exception('Verifying NIN for user failed')
        return redirect_with_msg(redirect_url, ':ERROR:Temporary technical problems')
    current_app.stats.count(name='nin_verified')

    return redirect_with_msg(redirect_url, 'eidas.nin_verify_success')
コード例 #7
0
ファイル: views.py プロジェクト: SUNET/eduid-webapp
def verify_code(user, code):
    current_app.logger.info('Verifying code for user {}'.format(user))
    proofing_state = current_app.proofing_statedb.get_state_by_eppn(user.eppn, raise_on_missing=False)

    if not proofing_state:
        return {'_status': 'error', 'message': 'letter.no_state_found'}

    # Check if provided code matches the one in the letter
    if not code == proofing_state.nin.verification_code:
        current_app.logger.error('Verification code for user {} does not match'.format(user))
        # TODO: Throttling to discourage an adversary to try brute force
        return {'_status': 'error', 'message': 'letter.wrong-code'}

    try:
        official_address = get_address(user, proofing_state)
    except MsgTaskFailed as e:
        current_app.logger.error('Navet lookup failed for user {}: {}'.format(user, e))
        current_app.stats.count('navet_error')
        return {'_status': 'error', 'message': 'error_navet_task'}

    proofing_log_entry = LetterProofing(user, created_by='eduid_letter_proofing', nin=proofing_state.nin.number,
                                        letter_sent_to=proofing_state.proofing_letter.address,
                                        transaction_id=proofing_state.proofing_letter.transaction_id,
                                        user_postal_address=official_address, proofing_version='2016v1')
    try:
        # Verify nin for user
        verify_nin_for_user(user, proofing_state, proofing_log_entry)
        current_app.logger.info('Verified code for user {}'.format(user))
        # Remove proofing state
        current_app.proofing_statedb.remove_state(proofing_state)
        return {'success': True,
                'message': 'letter.verification_success',
                'nins': user.nins.to_list_of_dicts()}
    except AmTaskFailed as e:
        current_app.logger.error('Verifying nin for user {} failed'.format(user))
        current_app.logger.error('{}'.format(e))
        return {'_status': 'error', 'message': 'Temporary technical problems'}
コード例 #8
0
def verify_code(user, code):
    current_app.logger.info('Verifying code for user {}'.format(user))
    proofing_state = current_app.proofing_statedb.get_state_by_eppn(user.eppn, raise_on_missing=False)

    if not proofing_state:
        return {'_status': 'error', 'message': 'letter.no_state_found'}

    # Check if provided code matches the one in the letter
    if not code == proofing_state.nin.verification_code:
        current_app.logger.error('Verification code for user {} does not match'.format(user))
        # TODO: Throttling to discourage an adversary to try brute force
        return {'_status': 'error', 'message': 'letter.wrong-code'}

    try:
        official_address = get_address(user, proofing_state)
    except MsgTaskFailed as e:
        current_app.logger.error('Navet lookup failed for user {}: {}'.format(user, e))
        current_app.stats.count('navet_error')
        return {'_status': 'error', 'message': 'error_navet_task'}

    proofing_log_entry = LetterProofing(user, created_by='eduid_letter_proofing', nin=proofing_state.nin.number,
                                        letter_sent_to=proofing_state.proofing_letter.address,
                                        transaction_id=proofing_state.proofing_letter.transaction_id,
                                        user_postal_address=official_address, proofing_version='2016v1')
    try:
        # Verify nin for user
        verify_nin_for_user(user, proofing_state, proofing_log_entry)
        current_app.logger.info('Verified code for user {}'.format(user))
        # Remove proofing state
        current_app.proofing_statedb.remove_state(proofing_state)
        return {'success': True,
                'message': 'letter.verification_success',
                'nins': user.nins.to_list_of_dicts()}
    except AmTaskFailed as e:
        current_app.logger.error('Verifying nin for user {} failed'.format(user))
        current_app.logger.error('{}'.format(e))
        return {'_status': 'error', 'message': 'Temporary technical problems'}
コード例 #9
0
ファイル: helpers.py プロジェクト: johanlundberg/eduid-webapp
def handle_freja_eid_userinfo(user, proofing_state, userinfo):
    """
    :param user: Central userdb user
    :param proofing_state: Proofing state for user
    :param userinfo: userinfo from OP

    :type user: eduid_userdb.user.User
    :type proofing_state: eduid_userdb.proofing.OidcProofingState
    :type userinfo: dict

    :return: None
    """
    current_app.logger.info(
        'Verifying NIN from Freja eID for user {}'.format(user))
    number = userinfo['results']['freja_eid']['ssn']
    opaque = userinfo['results']['freja_eid']['opaque']
    transaction_id = userinfo['results']['freja_eid']['ref']
    if not number_match_proofing(user, proofing_state, number):
        current_app.logger.warning(
            'Proofing state number did not match number in userinfo.'
            'Using number from userinfo.')
        proofing_state.nin.number = number

    current_app.logger.info('Getting address for user {}'.format(user))
    # Lookup official address via Navet
    address = current_app.msg_relay.get_postal_address(
        proofing_state.nin.number, timeout=15)
    proofing_log_entry = SeLegProofingFrejaEid(
        user,
        created_by=proofing_state.nin.created_by,
        nin=proofing_state.nin.number,
        transaction_id=transaction_id,
        opaque_data=opaque,
        user_postal_address=address,
        proofing_version='2017v1')
    verify_nin_for_user(user, proofing_state, proofing_log_entry)
    current_app.stats.count(name='freja.authn_response_handled')
コード例 #10
0
def proofing(user, nin):
    current_app.logger.info(
        'Trying to verify nin via mobile number for user {}.'.format(user))
    current_app.logger.debug('NIN: {!s}.'.format(nin))

    # Add nin as not verified to the user
    proofing_state = create_proofing_state(user, nin)
    add_nin_to_user(user, proofing_state)

    # Get list of verified mobile numbers
    verified_mobiles = [
        item.number for item in user.phone_numbers.to_list()
        if item.is_verified
    ]
    if not verified_mobiles:
        return error_response(message=MobileMsg.no_phone)

    try:
        success, proofing_log_entry = match_mobile_to_user(
            user, nin, verified_mobiles)
    except LookupMobileTaskFailed:
        current_app.stats.count('validate_nin_by_mobile_error')
        return error_response(message=MobileMsg.lookup_error)
    except MsgTaskFailed:
        current_app.stats.count('navet_error')
        return error_response(message=CommonMsg.navet_error)

    if success:
        try:
            # Verify nin for user
            if not verify_nin_for_user(user, proofing_state,
                                       proofing_log_entry):
                return error_response(message=CommonMsg.temp_problem)
            return {
                'success': True,
                'message': str(MobileMsg.verify_success.value)
            }
        except AmTaskFailed:
            current_app.logger.exception(
                f'Verifying nin for user {user} failed')
            return error_response(message=CommonMsg.temp_problem)

    return error_response(message=MobileMsg.no_match)
コード例 #11
0
def nin_verify_action(session_info: Mapping[str, Any], user: User) -> WerkzeugResponse:
    """
    Use a Sweden Connect federation IdP assertion to verify a users identity.

    :param session_info: the SAML session info
    :param user: Central db user

    :return: redirect response
    """

    redirect_url = current_app.config.nin_verify_redirect_url

    if not is_required_loa(session_info, 'loa3'):
        return redirect_with_msg(redirect_url, EidasMsg.authn_context_mismatch)

    if not is_valid_reauthn(session_info):
        return redirect_with_msg(redirect_url, EidasMsg.reauthn_expired)

    proofing_user = ProofingUser.from_user(user, current_app.private_userdb)
    asserted_nin = get_saml_attribute(session_info, 'personalIdentityNumber')[0]

    if proofing_user.nins.verified.count != 0:
        current_app.logger.error('User already has a verified NIN')
        current_app.logger.debug(
            'Primary NIN: {}. Asserted NIN: {}'.format(proofing_user.nins.primary.number, asserted_nin)
        )
        return redirect_with_msg(redirect_url, EidasMsg.nin_already_verified)

    # Create a proofing log
    issuer = session_info['issuer']
    authn_context = get_authn_ctx(session_info)
    try:
        user_address = current_app.msg_relay.get_postal_address(asserted_nin)
    except MsgTaskFailed as e:
        current_app.logger.error('Navet lookup failed: {}'.format(e))
        current_app.stats.count('navet_error')
        return redirect_with_msg(redirect_url, CommonMsg.navet_error)

    proofing_log_entry = SwedenConnectProofing(
        user=proofing_user,
        created_by='eduid-eidas',
        nin=asserted_nin,
        issuer=issuer,
        authn_context_class=authn_context,
        user_postal_address=user_address,
        proofing_version='2018v1',
    )

    # Verify NIN for user
    try:
        nin_element = NinProofingElement.from_dict(dict(number=asserted_nin, created_by='eduid-eidas', verified=False))
        proofing_state = NinProofingState(id=None, modified_ts=None, eppn=user.eppn, nin=nin_element)
        if not verify_nin_for_user(user, proofing_state, proofing_log_entry):
            current_app.logger.error(f'Failed verifying NIN for user {user}')
            return redirect_with_msg(redirect_url, CommonMsg.temp_problem)
    except AmTaskFailed:
        current_app.logger.exception('Verifying NIN for user failed')
        return redirect_with_msg(redirect_url, CommonMsg.temp_problem)
    current_app.stats.count(name='nin_verified')

    return redirect_with_msg(redirect_url, EidasMsg.nin_verify_success, error=False)