Ejemplo n.º 1
0
def set_email_verified(request, user, new_mail):
    """
    Mark an e-mail address as verified on a user.

    This process also includes *removing* the e-mail address from any other user
    that had it as a verified e-mail address.

    :param request: The HTTP request
    :param user: The user
    :param new_mail: The e-mail address to mark as verified

    :type request: pyramid.request.Request
    :type user: User
    :type new_mail: str | unicode

    :return: Status message
    :rtype: str | unicode
    """
    log.info('Trying to verify mail address for user {!r}.'.format(user))
    log.debug('Mail address: {!s}.'.format(new_mail))
    # Start by removing the email address from any other user that currently has it (verified)
    old_user = request.userdb_new.get_user_by_mail(new_mail, raise_on_missing=False)
    steal_count = 0
    if old_user and old_user.user_id != user.user_id:
        retrieve_modified_ts(old_user, request.dashboard_userdb)
        old_user = _remove_mail_from_user(new_mail, old_user)
        request.context.save_dashboard_user(old_user)
        steal_count = 1
    # Add the verified mail address to the requesting user
    _add_mail_to_user(new_mail, user)
    log.info('Mail address verified for user {!r}.'.format(user))
    request.stats.count('dashboard/verify_mail_stolen', steal_count)
    request.stats.count('dashboard/verify_mail_completed', 1)
    return _('Email {obj} verified')
Ejemplo n.º 2
0
def verify_mail(request, user, new_mail):
    log.info('Trying to verify mail address for user {!r}.'.format(user))
    log.debug('Mail address: {!s}.'.format(new_mail))
    # Start by removing mail address from any other user
    old_user_docs = request.db.profiles.find({
        'mailAliases': {'$elemMatch': {'email': new_mail, 'verified': True}}
    })
    steal_count = 0
    for old_user_doc in old_user_docs:
        old_user = User(old_user_doc)
        if old_user:
            log.debug('Found old user {!r} with mail address ({!s}) already verified.'.format(old_user, new_mail))
            log.debug('Old user mail BEFORE: {!s}.'.format(old_user.get_mail()))
            log.debug('Old user mail aliases BEFORE: {!r}.'.format(old_user.get_mail_aliases()))
            if old_user.get_mail() == new_mail:
                old_user.set_mail('')
            mails = [m for m in old_user.get_mail_aliases() if m['email'] != new_mail]
            old_user.set_mail_aliases(mails)
            log.debug('Old user mail AFTER: {!s}.'.format(old_user.get_mail()))
            log.debug('Old user mail aliases AFTER: {!r}.'.format(old_user.get_mail_aliases()))
            old_user.retrieve_modified_ts(request.db.profiles)
            old_user.save(request)
            steal_count += 1
    # Add the verified mail address to the requesting user
    user.add_verified_email(new_mail)
    log.info('Mail address verified for user {!r}.'.format(user))
    request.stats.count('dashboard/verify_mail_stolen', steal_count)
    request.stats.count('dashboard/verify_mail_completed', 1)
    return user, _('Email {obj} verified')
Ejemplo n.º 3
0
def set_email_verified(request, user, new_mail):
    """
    Mark an e-mail address as verified on a user.

    This process also includes *removing* the e-mail address from any other user
    that had it as a verified e-mail address.

    :param request: The HTTP request
    :param user: The user
    :param new_mail: The e-mail address to mark as verified

    :type request: pyramid.request.Request
    :type user: User
    :type new_mail: str | unicode

    :return: Status message
    :rtype: str | unicode
    """
    log.info('Trying to verify mail address for user {!r}.'.format(user))
    log.debug('Mail address: {!s}.'.format(new_mail))
    # Start by removing the email address from any other user that currently has it (verified)
    old_user = request.userdb_new.get_user_by_mail(new_mail, raise_on_missing=False)
    steal_count = 0
    if old_user and old_user.user_id != user.user_id:
        retrieve_modified_ts(old_user, request.dashboard_userdb)
        old_user = _remove_mail_from_user(new_mail, old_user)
        request.context.save_dashboard_user(old_user)
        steal_count = 1
    # Add the verified mail address to the requesting user
    _add_mail_to_user(new_mail, user)
    log.info('Mail address verified for user {!r}.'.format(user))
    request.stats.count('verify_mail_stolen', steal_count)
    request.stats.count('verify_mail_completed')
    return _('Email {obj} verified')
Ejemplo n.º 4
0
def send_reset_password_mail(request, user, reset_password_link):
    """ Send an email with the instructions for resetting password """
    mailer = get_mailer(request)

    site_name = request.registry.settings.get("site.name", "eduID")
    password_reset_timeout = int(
        request.registry.settings.get("password_reset_timeout", "120")) / 60

    if user.mail_addresses.primary is not None:
        email = user.mail_addresses.primary.email
    elif user.mail_addresses.count > 0:
        email = user.mail_addresses.to_list()[0].email
    else:
        log.info(
            'User {!r} has no email address, not possible to send a message'.
            format(user))
        return

    context = {
        "email": email,
        "reset_password_link": reset_password_link,
        "password_reset_timeout": password_reset_timeout,
        "site_url": request.route_url("home"),
        "site_name": site_name,
    }

    message = Message(
        subject=_("Reset your {site_name} password").format(
            site_name=site_name),
        sender=request.registry.settings.get("mail.default_sender"),
        recipients=[email],
        body=render(
            "templates/reset-password-email.txt.jinja2",
            context,
            request,
        ),
        html=render(
            "templates/reset-password-email.html.jinja2",
            context,
            request,
        ),
    )

    # DEBUG
    if request.registry.settings.get('developer_mode', False):
        log.debug(message.body)
    else:
        mailer.send(message)
    log.debug(
        "Sent reset password mail to user {!r} with address {!s}.".format(
            user, email))
    request.stats.count('email_send_pwreset_mail')
Ejemplo n.º 5
0
def logout(request):
    """
    Destroy session information when a user logs out.

    :param request:
    :return:
    """
    if 'user' in request.session:
        user = request.session['user']
        log.info("User {!r} logging out".format(user['_id']))

    if request.session is not None:
        request.session.delete()
    headers = forget(request)
    return headers
Ejemplo n.º 6
0
def logout(request):
    """
    Destroy session information when a user logs out.

    :param request:
    :return:
    """
    if request.session is not None:
        user = get_logged_in_user(request, raise_on_not_logged_in = False, legacy_user = True)
        if user:
            log.info("User {!r} logging out".format(user.get_id()))
        request.session.delete()

    headers = forget(request)
    return headers
Ejemplo n.º 7
0
def send_reset_password_mail(request, user, reset_password_link):
    """ Send an email with the instructions for resetting password """
    mailer = get_mailer(request)

    site_name = request.registry.settings.get("site.name", "eduID")
    password_reset_timeout = int(request.registry.settings.get("password_reset_timeout", "120")) / 60

    if user.mail_addresses.primary is not None:
        email = user.mail_addresses.primary.email
    elif user.mail_addresses.count > 0:
        email = user.mail_addresses.to_list()[0].email
    else:
        log.info('User {!r} has no email address, not possible to send a message'.format(user))
        return

    context = {
        "email": email,
        "reset_password_link": reset_password_link,
        "password_reset_timeout": password_reset_timeout,
        "site_url": request.route_url("home"),
        "site_name": site_name,
    }

    message = Message(
        subject=_("Reset your {site_name} password").format(
            site_name=site_name),
        sender=request.registry.settings.get("mail.default_sender"),
        recipients=[email],
        body=render(
            "templates/reset-password-email.txt.jinja2",
            context,
            request,
        ),
        html=render(
            "templates/reset-password-email.html.jinja2",
            context,
            request,
        ),
    )

    # DEBUG
    if request.registry.settings.get('developer_mode', False):
        log.debug(message.body)
    else:
        mailer.send(message)
    log.debug("Sent reset password mail to user {!r} with address {!s}.".format(user, email))
    request.stats.count('email_send_pwreset_mail')
Ejemplo n.º 8
0
def login(request, session_info, user):
    """
    Update session with information about a user that has just logged in.

    :param request: Request object
    :param session_info: Session info received by pysaml2 client
    :param user: Information about user as returned by authenticate()
    :return:
    """
    log.info("User {!r} logging in (eduPersonPrincipalName: {!r})".format(user['_id'], user['eduPersonPrincipalName']))
    request.session['eduPersonPrincipalName'] = user['eduPersonPrincipalName']
    store_session_user(request, user)
    request.session['eduPersonAssurance'] = get_loa(
        request.registry.settings.get('available_loa'),
        session_info
    )
    remember_headers = remember(request, user['eduPersonPrincipalName'])
    return remember_headers
Ejemplo n.º 9
0
def send_termination_mail(request, user):
    user = get_session_user(request)   # XXX remove when context users  are new users
    mailer = get_mailer(request)
    support_email = request.registry.settings.get('mail.support_email', '*****@*****.**')
    site_name = request.registry.settings.get("site.name", "eduID")

    context = {
        'support_mail': support_email,
        'displayName': user.display_name
    }
    if user.mail_addresses.primary is not None:
        address = user.mail_addresses.primary.email
    elif user.mail_addresses.count > 0:
        for a in user.mail_addresses.to_list():
            address = a.email
            break
    else:
        log.info('User {!r} has no email address, not possible to send a message'.format(user))
        return

    message = Message(
        subject=_("{site_name} account termination").format(
            site_name=site_name),
        sender=request.registry.settings.get("mail.default_sender"),
        recipients=[address],
        body=render(
            "templates/termination_email.txt.jinja2",
            context,
            request,
        ),
        html=render(
            "templates/termination_email.html.jinja2",
            context,
            request,
        ),
    )

    # DEBUG
    if request.registry.settings.get('developer_mode', False):
        log.debug(message.body)
    else:
        mailer.send(message)
    log.debug("Sent termination mail to user {!r} with address {!s}.".format(user, address))
    request.stats.count('dashboard/email_send_termination_mail', 1)
Ejemplo n.º 10
0
def login(request, session_info, user):
    """
    Update session with information about a user that has just logged in.

    :param request: Request object
    :param session_info: Session info received by pysaml2 client
    :param user: Information about user as returned by authenticate()
    :return:
    """
    main_attribute = request.registry.settings.get('saml2.user_main_attribute')
    log.info("User {!r} logging in ({!r}: {!r})".format(user['_id'], main_attribute, user[main_attribute]))
    request.session[main_attribute] = user[main_attribute]
    request.session['user'] = user
    request.session['eduPersonAssurance'] = get_loa(
        request.registry.settings.get('available_loa'),
        session_info
    )
    remember_headers = remember(request, user[main_attribute])
    return remember_headers
Ejemplo n.º 11
0
def send_termination_mail(request, user):
    mailer = get_mailer(request)
    support_email = request.registry.settings.get('mail.support_email',
                                                  '*****@*****.**')
    site_name = request.registry.settings.get("site.name", "eduID")

    context = {'support_mail': support_email, 'displayName': user.display_name}
    if user.mail_addresses.primary is not None:
        address = user.mail_addresses.primary.email
    elif user.mail_addresses.count > 0:
        address = user.mail_addresses.to_list()[0].email
    else:
        log.info(
            'User {!r} has no email address, not possible to send a message'.
            format(user))
        return

    message = Message(
        subject=_("{site_name} account termination").format(
            site_name=site_name),
        sender=request.registry.settings.get("mail.default_sender"),
        recipients=[address],
        body=render(
            "templates/termination_email.txt.jinja2",
            context,
            request,
        ),
        html=render(
            "templates/termination_email.html.jinja2",
            context,
            request,
        ),
    )

    # DEBUG
    if request.registry.settings.get('developer_mode', False):
        log.debug(message.body)
    else:
        mailer.send(message)
    log.debug("Sent termination mail to user {!r} with address {!s}.".format(
        user, address))
    request.stats.count('email_send_termination_mail')
Ejemplo n.º 12
0
def new_verification_code(request, model_name, obj_id, user, hasher=None):
    """
    Match a user supplied code (`code') against an actual entry in the database.

    :param request: The HTTP request
    :param model_name: 'norEduPersonNIN', 'phone', or 'mailAliases'
    :param obj_id: The data covered by the verification, like the phone number or nin or ...
    :param user: The user
    :param hasher: Callable used to generate the code

    :type request: pyramid.request.Request
    :type model_name: str | unicode
    :type obj_id: str | unicode
    :type user: User | OldUser
    :type hasher: callable
    """
    assert model_name in ['norEduPersonNIN', 'phone', 'mailAliases']

    try:
        userid = user.user_id
    except AttributeError:
        userid = user.get_id()

    if hasher is None:
        hasher = get_unique_hash
    code = hasher()
    obj = {
        'model_name': model_name,
        'obj_id': obj_id,
        'user_oid': userid,
        'code': code,
        'verified': False,
        'timestamp': datetime.now(utc),
    }
    doc_id = request.db.verifications.insert(obj)
    reference = unicode(doc_id)
    session_verifications = request.session.get('verifications', [])
    session_verifications.append(code)
    request.session['verifications'] = session_verifications
    log.info('Created new {!s} verification code for user {!r}.'.format(model_name, user))
    log.debug('Verification object id {!s}. Code: {!s}.'.format(obj_id, code))
    return reference, code
Ejemplo n.º 13
0
def new_verification_code(request, model_name, obj_id, user, hasher=None):
    """
    Match a user supplied code (`code') against an actual entry in the database.

    :param request: The HTTP request
    :param model_name: 'norEduPersonNIN', 'phone', or 'mailAliases'
    :param obj_id: The data covered by the verification, like the phone number or nin or ...
    :param user: The user
    :param hasher: Callable used to generate the code

    :type request: pyramid.request.Request
    :type model_name: str | unicode
    :type obj_id: str | unicode
    :type user: User | OldUser
    :type hasher: callable
    """
    assert model_name in ['norEduPersonNIN', 'phone', 'mailAliases']

    try:
        userid = user.user_id
    except AttributeError:
        userid = user.get_id()

    if hasher is None:
        hasher = get_unique_hash
    code = hasher()
    obj = {
        'model_name': model_name,
        'obj_id': obj_id,
        'user_oid': userid,
        'code': code,
        'verified': False,
        'timestamp': datetime.now(utc),
    }
    doc_id = request.db.verifications.insert(obj)
    reference = unicode(doc_id)
    session_verifications = request.session.get('verifications', [])
    session_verifications.append(code)
    request.session['verifications'] = session_verifications
    log.info('Created new {!s} verification code for user {!r}.'.format(model_name, user))
    log.debug('Verification object id {!s}. Code: {!s}.'.format(obj_id, code))
    return reference, code
Ejemplo n.º 14
0
def new_verification_code(request, model_name, obj_id, user, hasher=None):
    if hasher is None:
        hasher = get_unique_hash
    code = hasher()
    obj = {
        "model_name": model_name,
        "obj_id": obj_id,
        "user_oid": user.get_id(),
        "code": code,
        "verified": False,
        "timestamp": datetime.now(utc),
    }
    doc_id = request.db.verifications.insert(obj)
    reference = unicode(doc_id)
    session_verifications = request.session.get('verifications', [])
    session_verifications.append(code)
    request.session['verifications'] = session_verifications
    log.info('Created new {!s} verification code for user {!r}.'.format(model_name, user))
    log.debug('Verification object id {!s}. Code: {!s}.'.format(obj_id, code))
    return reference, code
Ejemplo n.º 15
0
    def add_by_mobile_success(self, ninform):
        """ This method is bounded to the "add_by_mobile"-button by it's name """
        newnin = self.schema.serialize(ninform)
        newnin = newnin['norEduPersonNIN']
        newnin = normalize_nin(newnin)

        self.user = get_session_user(self.request)
        message = set_nin_verified(self.request, self.user, newnin)

        try:
            self.request.context.save_dashboard_user(self.user)
        except UserOutOfSync:
            log.info("Failed to save user {!r} after mobile phone vetting. User out of sync.".format(self.user))
            raise

        log.info("Saved user {!r} after NIN vetting using mobile phone".format(self.user))
        self.request.session.flash(
            get_localizer(self.request).translate(message),
            queue='forms')

        self.request.stats.count('nin_add_mobile')
Ejemplo n.º 16
0
    def add_by_mobile_success(self, ninform):
        """ This method is bounded to the "add_by_mobile"-button by it's name """
        newnin = self.schema.serialize(ninform)
        newnin = newnin['norEduPersonNIN']
        newnin = normalize_nin(newnin)

        self.user = get_session_user(self.request)
        message = set_nin_verified(self.request, self.user, newnin)

        try:
            self.request.context.save_dashboard_user(self.user)
        except UserOutOfSync:
            log.info("Failed to save user {!r} after mobile phone vetting. User out of sync.".format(self.user))
            raise

        log.info("Saved user {!r} after NIN vetting using mobile phone".format(self.user))
        self.request.session.flash(
            get_localizer(self.request).translate(message),
            queue='forms')

        self.request.stats.count('dashboard/nin_add_mobile', 1)
Ejemplo n.º 17
0
def set_phone_verified(request, user, new_number):
    """
    Mark a phone number as verified on a user.

    This process also includes *removing* the phone number from any other user
    that had it as a verified phone number.

    :param request: The HTTP request
    :param user: The user
    :param new_number: The phone number to mark as verified

    :type request: pyramid.request.Request
    :type user: User
    :type new_number: str | unicode

    :return: Status message
    :rtype: str | unicode
    """
    log.info('Trying to verify phone number for user {!r}.'.format(user))
    log.debug('Phone number: {!s}.'.format(new_number))
    # Start by removing mobile number from any other user
    old_user = request.userdb_new.get_user_by_phone(new_number, raise_on_missing=False)
    steal_count = 0
    if old_user and old_user.user_id != user.user_id:
        retrieve_modified_ts(old_user, request.dashboard_userdb)
        _remove_phone_from_user(new_number, old_user)
        request.context.save_dashboard_user(old_user)
        log.info('Removed phone number from user {!r}.'.format(old_user))
        steal_count = 1
    # Add the verified mobile number to the requesting user
    _add_phone_to_user(new_number, user)
    log.info('Phone number verified for user {!r}.'.format(user))
    request.stats.count('verify_mobile_stolen', steal_count)
    request.stats.count('verify_mobile_completed')
    return _('Phone {obj} verified')
Ejemplo n.º 18
0
def set_phone_verified(request, user, new_number):
    """
    Mark a phone number as verified on a user.

    This process also includes *removing* the phone number from any other user
    that had it as a verified phone number.

    :param request: The HTTP request
    :param user: The user
    :param new_number: The phone number to mark as verified

    :type request: pyramid.request.Request
    :type user: User
    :type new_number: str | unicode

    :return: Status message
    :rtype: str | unicode
    """
    log.info('Trying to verify phone number for user {!r}.'.format(user))
    log.debug('Phone number: {!s}.'.format(new_number))
    # Start by removing mobile number from any other user
    old_user = request.userdb_new.get_user_by_phone(new_number, raise_on_missing=False)
    steal_count = 0
    if old_user and old_user.user_id != user.user_id:
        retrieve_modified_ts(old_user, request.dashboard_userdb)
        _remove_phone_from_user(new_number, old_user)
        request.context.save_dashboard_user(old_user)
        log.info('Removed phone number from user {!r}.'.format(old_user))
        steal_count = 1
    # Add the verified mobile number to the requesting user
    _add_phone_to_user(new_number, user)
    log.info('Phone number verified for user {!r}.'.format(user))
    request.stats.count('dashboard/verify_mobile_stolen', steal_count)
    request.stats.count('dashboard/verify_mobile_completed', 1)
    return _('Phone {obj} verified')
Ejemplo n.º 19
0
def verify_mobile(request, user, new_mobile):
    log.info('Trying to verify mobile number for user {!r}.'.format(user))
    log.debug('Mobile number: {!s}.'.format(new_mobile))
    # Start by removing mobile number from any other user
    old_user_docs = request.db.profiles.find({
        'mobile': {'$elemMatch': {'mobile': new_mobile, 'verified': True}}
    })
    steal_count = 0
    for old_user_doc in old_user_docs:
        old_user = User(old_user_doc)
        if old_user:
            log.debug('Found old user {!r} with mobile number ({!s}) already verified.'.format(old_user, new_mobile))
            log.debug('Old user mobile numbers BEFORE: {!r}.'.format(old_user.get_mobiles()))
            mobiles = [m for m in old_user.get_mobiles() if m['mobile'] != new_mobile]
            old_user.set_mobiles(mobiles)
            log.debug('Old user mobile numbers AFTER: {!r}.'.format(old_user.get_mobiles()))
            old_user.retrieve_modified_ts(request.db.profiles)
            old_user.save(request)
            log.info('Removed mobile number from user {!r}.'.format(old_user))
            steal_count += 1
    # Add the verified mobile number to the requesting user
    user.add_verified_mobile(new_mobile)
    log.info('Mobile number verified for user {!r}.'.format(user))
    request.stats.count('dashboard/verify_mobile_stolen', steal_count)
    request.stats.count('dashboard/verify_mobile_completed', 1)
    return user, _('Mobile {obj} verified')
Ejemplo n.º 20
0
def verify_nin(request, user, new_nin, reference):
    log.info('Trying to verify NIN for user {!r}.'.format(user))
    log.debug('NIN: {!s}.'.format(new_nin))
    # Start by removing nin from any other user
    old_user_docs = request.db.profiles.find({
        'norEduPersonNIN': new_nin
    })
    steal_count = 0
    for old_user_doc in old_user_docs:
        old_user = User(old_user_doc)
        if old_user:
            log.debug('Found old user {!r} with NIN ({!s}) already verified.'.format(old_user, new_nin))
            log.debug('Old user NINs BEFORE: {!r}.'.format(old_user.get_nins()))
            nins = [nin for nin in old_user.get_nins() if nin != new_nin]
            old_user.set_nins(nins)
            log.debug('Old user NINs AFTER: {!r}.'.format(old_user.get_nins()))
            log.debug('Old user addresses BEFORE: {!r}.'.format(old_user.get_addresses()))
            addresses = [a for a in old_user.get_addresses() if not a['verified']]
            old_user.set_addresses(addresses)
            log.debug('Old user addresses AFTER: {!r}.'.format(old_user.get_addresses()))
            old_user.retrieve_modified_ts(request.db.profiles)
            old_user.save(request)
            log.info('Removed NIN and associated addresses from user {!r}.'.format(old_user))
            steal_count += 1
    # Add the verified nin to the requesting user
    user.add_verified_nin(new_nin)
    user.retrieve_address(request, new_nin)
    # Connect the verification to the transaction audit log
    request.msgrelay.postal_address_to_transaction_audit_log(reference)
    # Reset session eduPersonIdentityProofing on NIN verification
    request.session['eduPersonIdentityProofing'] = None
    log.info('NIN verified for user {!r}.'.format(user))
    request.stats.count('dashboard/verify_nin_stolen', steal_count)
    request.stats.count('dashboard/verify_nin_completed', 1)
    return user, _('National identity number {obj} verified')
Ejemplo n.º 21
0
def set_nin_verified(request, user, new_nin, reference=None):
    """
    Mark a National Identity Number (NIN) as verified on a user.

    This process also includes *removing* the NIN from any other user
    that had it as a verified NIN.

    :param request: The HTTP request
    :param user: The user
    :param new_nin: The National Identity Number to mark as verified
    :param reference: A reference to the verification code - used for audit logging

    :type request: pyramid.request.Request
    :type user: User
    :type new_nin: str | unicode

    :return: Status message
    :rtype: str | unicode
    """
    log.info('Trying to verify NIN for user {!r}.'.format(user))
    log.debug('NIN: {!s}.'.format(new_nin))
    # Start by removing nin from any other user
    old_user = request.userdb_new.get_user_by_nin(new_nin, raise_on_missing=False)
    log.debug('Searched for NIN {!r} in {!s}: {!r}'.format(new_nin, request.userdb_new, old_user))
    steal_count = 0
    if old_user and old_user.user_id != user.user_id:
        retrieve_modified_ts(old_user, request.dashboard_userdb)
        _remove_nin_from_user(new_nin, old_user)
        request.context.save_dashboard_user(old_user)
        log.info('Removed NIN and associated addresses from user {!r}.'.format(old_user))
        steal_count = 1
    # Add the verified nin to the requesting user
    _add_nin_to_user(new_nin, user)
    _nin_verified_transaction_audit(request, reference)
    log.info('NIN verified for user {!r}.'.format(user))
    request.stats.count('verify_nin_stolen', steal_count)
    request.stats.count('verify_nin_completed')
    return _('National identity number {obj} verified')
Ejemplo n.º 22
0
def set_nin_verified(request, user, new_nin, reference=None):
    """
    Mark a National Identity Number (NIN) as verified on a user.

    This process also includes *removing* the NIN from any other user
    that had it as a verified NIN.

    :param request: The HTTP request
    :param user: The user
    :param new_nin: The National Identity Number to mark as verified
    :param reference: A reference to the verification code - used for audit logging

    :type request: pyramid.request.Request
    :type user: User
    :type new_nin: str | unicode

    :return: Status message
    :rtype: str | unicode
    """
    log.info('Trying to verify NIN for user {!r}.'.format(user))
    log.debug('NIN: {!s}.'.format(new_nin))
    # Start by removing nin from any other user
    old_user = request.userdb_new.get_user_by_nin(new_nin, raise_on_missing=False)
    log.debug('Searched for NIN {!r} in {!s}: {!r}'.format(new_nin, request.userdb_new, old_user))
    steal_count = 0
    if old_user and old_user.user_id != user.user_id:
        retrieve_modified_ts(old_user, request.dashboard_userdb)
        _remove_nin_from_user(new_nin, old_user)
        request.context.save_dashboard_user(old_user)
        log.info('Removed NIN and associated addresses from user {!r}.'.format(old_user))
        steal_count = 1
    # Add the verified nin to the requesting user
    _add_nin_to_user(new_nin, user)
    _nin_verified_transaction_audit(request, reference)
    log.info('NIN verified for user {!r}.'.format(user))
    request.stats.count('dashboard/verify_nin_stolen', steal_count)
    request.stats.count('dashboard/verify_nin_completed', 1)
    return _('National identity number {obj} verified')
Ejemplo n.º 23
0
    def finish_letter_action(self, data, post_data):
        """
        Contact the eduid-idproofing-letter service and give it the code the user supplied.

        If the letter proofing service approves of the code, this code does the following:
          * Put together some LetterProofing data with information about the user, the vetting, the
            users registered address etc. (Kantara requirement)
          * Log what the letter proofing service returned on the user (we put it there for now...)
          * Upgrade the NIN in question to verified=True
          * Mark the verification code as used

        :returns: status, message in a dict
        :rtype: dict
        """
        nin, index = data.split()
        index = int(index)

        settings = self.request.registry.settings
        letter_url = settings.get('letter_service_url')
        verify_letter_url = urlparse.urljoin(letter_url, 'verify-code')

        code = post_data['verification_code']

        self.user = get_session_user(self.request)

        # small helper function to make rest of the function more readable
        def make_result(result, msg):
            return dict(result = result, message = msg)

        data = {'eppn': self.user.eppn,
                'verification_code': code}
        logger.info("Posting letter verification code for user {!r}.".format(self.user))
        response = requests.post(verify_letter_url, data=data)
        logger.info("Received response from idproofing-letter after posting verification code "
                    "for user {!r}.".format(self.user))
        if response.status_code != 200:
            # Do nothing, just return above error message and log microservice return code
            logger.info("Received status code {!s} from idproofing-letter after posting verification code "
                        "for user {!r}.".format(response.status_code, self.user))
            return make_result('error', _('There was a problem with the letter service. '
                                          'Please try again later.'))

        rdata = response.json().get('data', {})
        if not (rdata.get('verified', False) and nin == rdata.get('number', None)):
            log.info('User {!r} supplied wrong letter verification code or nin did not match.'.format(
                self.user))
            log.debug('NIN in dashboard: {!s}, NIN in idproofing-letter: {!s}'.format(
                nin, rdata.get('number', None)))
            return make_result('error', _('Your verification code seems to be wrong, please try again.'))

        # Save data from successful verification call for later addition to user proofing collection.
        # Convert self.user to a DashboardUser manually instead of letting save_dashboard_user do
        # it to get access to add_letter_proofing_data().
        user = DashboardUser(data = self.user.to_dict())
        rdata['created_ts'] = datetime.utcfromtimestamp(int(rdata['created_ts']))
        rdata['verified_ts'] = datetime.utcfromtimestamp(int(rdata['verified_ts']))
        user.add_letter_proofing_data(rdata)

        # Look up users official address at the time of verification per Kantara requirements
        logger.info("Looking up address via Navet for user {!r}.".format(self.user))
        user_postal_address = self.request.msgrelay.get_full_postal_address(rdata['number'])
        logger.info("Finished looking up address via Navet for user {!r}.".format(self.user))
        proofing_data = LetterProofing(self.user, rdata['number'], rdata['official_address'],
                                       rdata['transaction_id'], user_postal_address)

        # Log verification event and fail if that goes wrong
        logger.info("Logging proofing data for user {!r}.".format(self.user))
        if not self.request.idproofinglog.log_verification(proofing_data):
            log.error('Logging of letter proofing data for user {!r} failed.'.format(self.user))
            return make_result('error', _('Sorry, we are experiencing temporary technical '
                                          'problems, please try again later.'))

        logger.info("Finished logging proofing data for user {!r}.".format(self.user))
        # This is a hack to reuse the existing proofing functionality, the users code has
        # already been verified by the micro service but we decided the dashboard could
        # continue 'upgrading' the users until we've made the planned proofing consumer
        set_nin_verified(self.request, user, nin)
        try:
            self.request.context.save_dashboard_user(user)
        except UserOutOfSync:
            log.error("Verified norEduPersonNIN NOT saved for user {!r}. User out of sync.".format(
                self.user))
            return self.sync_user()
        self.user = user

        # Finally mark the verification as used
        save_as_verified(self.request, 'norEduPersonNIN', self.user, nin)
        logger.info("Verified NIN by physical letter saved for user {!r}.".format(
            self.user))

        return make_result('success', _('You have successfully verified your identity'))
Ejemplo n.º 24
0
def verify_code(request, model_name, code):
    """
    Verify a code and act accordingly to the model_name ('norEduPersonNIN', 'mobile', or 'mailAliases').

    This is what turns an unconfirmed NIN/mobile/e-mail into a confirmed one.

    :param request: The HTTP request
    :param model_name: 'norEduPersonNIN', 'mobile', or 'mailAliases'
    :param code: The user supplied code
    :type request: webob.request.BaseRequest
    :return: string of verified data
    """
    this_verification = request.db.verifications.find_one(
        {
            "model_name": model_name,
            "code": code,
        })

    if not this_verification:
        log.error("Could not find verification record for code {!r}, model {!r}".format(code, model_name))
        return

    reference = unicode(this_verification['_id'])
    obj_id = this_verification['obj_id']

    if not obj_id:
        return None

    if 'edit-user' in request.session:
        # non personal mode
        user = request.session['edit-user']
    elif 'user' in request.session:
        # personal mode
        user = request.session['user']

    assert_error_msg = 'Requesting users ID does not match verifications user ID'
    assert user.get_id() == this_verification['user_oid'], assert_error_msg

    if model_name == 'norEduPersonNIN':
        user, msg = verify_nin(request, user, obj_id, reference)
    elif model_name == 'mobile':
        user, msg = verify_mobile(request, user, obj_id)
    elif model_name == 'mailAliases':
        user, msg = verify_mail(request, user, obj_id)
    else:
        raise NotImplementedError('Unknown validation model_name')

    try:
        user.save(request)
        log.info("Verified {!s} saved for user {!r}.".format(model_name, user))
        verified = {
            'verified': True,
            'verified_timestamp': datetime.utcnow()
        }
        this_verification.update(verified)
        request.db.verifications.update({'_id': this_verification['_id']}, this_verification)
        log.info("Code {!r} ({!s}) marked as verified".format(code, obj_id))
    except UserOutOfSync:
        log.info("Verified {!s} NOT saved for user {!r}. User out of sync.".format(model_name, user))
        raise
    else:
        msg = get_localizer(request).translate(msg)
        request.session.flash(msg.format(obj=obj_id), queue='forms')
        request.stats.count('dashboard/verify_code_completed', 1)
    return obj_id
Ejemplo n.º 25
0
def validate_nin_by_mobile(request, user, nin):
    """
    :param request: The pyramid request
    :param user: The eduid user
    :param nin: The NIN
    :type request: pyramid.request.Request
    :type user: eduid_userdb.User
    :type nin: str
    :return:dict
    """
    log.info(
        'Trying to verify nin via mobile number for user {!r}.'.format(user))
    log.debug('NIN: {!s}.'.format(nin))
    from eduid_lookup_mobile.utilities import format_NIN
    # Get list of verified mobile numbers
    verified_mobiles = [
        x.number for x in user.phone_numbers.to_list() if x.is_verified
    ]

    national_identity_number = format_NIN(nin)
    status = 'no_phone'
    valid_mobile = None
    registered_to_nin = None

    age = _get_age(national_identity_number)

    try:
        for mobile_number in verified_mobiles:
            status = 'no_match'
            # Get the registered owner of the mobile number
            registered_to_nin = request.lookuprelay.find_NIN_by_mobile(
                mobile_number)
            registered_to_nin = format_NIN(registered_to_nin)

            if registered_to_nin == national_identity_number:
                # Check if registered nin was the given nin
                valid_mobile = mobile_number
                status = 'match'
                log.info('Mobile number matched for user {!r}.'.format(user))
                log.debug('Mobile {!s} registered to NIN: {!s}.'.format(
                    valid_mobile, registered_to_nin))
                request.stats.count('validate_nin_by_mobile_exact_match')
                break
            elif registered_to_nin is not None and age < 18:
                # Check if registered nin is related to given nin
                relation = request.msgrelay.get_relations_to(
                    national_identity_number, registered_to_nin)
                # TODO All relations?
                #valid_relations = ['M', 'B', 'FA', 'MO', 'VF']
                valid_relations = ['FA', 'MO']
                if any(r in relation for r in valid_relations):
                    valid_mobile = mobile_number
                    status = 'match_by_navet'
                    log.info('Mobile number matched for user {!r} via navet.'.
                             format(user))
                    log.debug('Mobile {!s} registered to NIN: {!s}.'.format(
                        valid_mobile, registered_to_nin))
                    log.debug(
                        'Person with NIN {!s} have relation {!s} to user: {!r}.'
                        .format(registered_to_nin, relation, user))
                    request.stats.count(
                        'validate_nin_by_mobile_relative_match')
                    break
    except request.lookuprelay.TaskFailed:
        status = 'error_lookup'
    except request.msgrelay.TaskFailed:
        status = 'error_navet'

    msg = None
    if status == 'no_phone':
        msg = _('You have no confirmed mobile phone')
        log.info('User {!r} has no verified mobile phone number.'.format(user))
    elif status == 'no_match':
        log.info(
            'User {!r} NIN is not associated with any verified mobile phone number.'
            .format(user))
        msg = _(
            'A company subscription or protected phone number cannot be used with this service.'
        )
        request.stats.count('validate_nin_by_mobile_no_match')
    elif status == 'error_lookup' or status == 'error_navet':
        log.error(
            'Validate NIN via mobile failed with status "{!s}" for user {!r}.'.
            format(status, user))
        msg = _('Sorry, we are experiencing temporary technical '
                'problem with ${service_name}, please try again '
                'later.')
        request.stats.count('validate_nin_by_mobile_error')

    if status == 'match' or status == 'match_by_navet':
        log.info(
            'Validate NIN via mobile succeeded with status "{!s}" for user {!r}.'
            .format(status, user))
        msg = _('Validate NIN via mobile with succeeded')
        user_postal_address = request.msgrelay.get_full_postal_address(
            national_identity_number)
        if status == 'match':
            proofing_data = TeleAdressProofing(user, status,
                                               national_identity_number,
                                               valid_mobile,
                                               user_postal_address)
        else:
            registered_postal_address = request.msgrelay.get_full_postal_address(
                registered_to_nin)
            proofing_data = TeleAdressProofingRelation(
                user, status, national_identity_number, valid_mobile,
                user_postal_address, registered_to_nin, relation,
                registered_postal_address)

        log.info('Logging of mobile proofing data for user {!r}.'.format(user))
        if not request.idproofinglog.log_verification(proofing_data):
            log.error(
                'Logging of mobile proofing data for user {!r} failed.'.format(
                    user))
            valid_mobile = None
            msg = _('Sorry, we are experiencing temporary technical '
                    'problem with ${service_name}, please try again '
                    'later.')

    validation_result = {
        'success': valid_mobile is not None,
        'message': msg,
        'mobile': valid_mobile
    }
    return validation_result
Ejemplo n.º 26
0
    def finish_letter_action(self, data, post_data):
        """
        Contact the eduid-idproofing-letter service and give it the code the user supplied.

        If the letter proofing service approves of the code, this code does the following:
          * Put together some LetterProofing data with information about the user, the vetting, the
            users registered address etc. (Kantara requirement)
          * Log what the letter proofing service returned on the user (we put it there for now...)
          * Upgrade the NIN in question to verified=True
          * Mark the verification code as used

        :returns: status, message in a dict
        :rtype: dict
        """
        nin, index = data.split()
        index = int(index)

        settings = self.request.registry.settings
        letter_url = settings.get('letter_service_url')
        verify_letter_url = urlappend(letter_url, 'verify-code')

        code = post_data['verification_code']

        self.user = get_session_user(self.request)

        # small helper function to make rest of the function more readable
        def make_result(result, msg):
            return dict(result = result, message = msg)

        data = {'eppn': self.user.eppn,
                'verification_code': code}
        logger.info("Posting letter verification code for user {!r}.".format(self.user))
        response = requests.post(verify_letter_url, data=data)
        logger.info("Received response from idproofing-letter after posting verification code "
                    "for user {!r}.".format(self.user))
        if response.status_code != 200:
            # Do nothing, just return above error message and log microservice return code
            logger.info("Received status code {!s} from idproofing-letter after posting verification code "
                        "for user {!r}.".format(response.status_code, self.user))
            return make_result('error', _('There was a problem with the letter service. '
                                          'Please try again later.'))

        rdata = response.json().get('data', {})
        if not (rdata.get('verified', False) and nin == rdata.get('number', None)):
            log.info('User {!r} supplied wrong letter verification code or nin did not match.'.format(
                self.user))
            log.debug('NIN in dashboard: {!s}, NIN in idproofing-letter: {!s}'.format(
                nin, rdata.get('number', None)))
            return make_result('error', _('Your verification code seems to be wrong, please try again.'))

        # Save data from successful verification call for later addition to user proofing collection.
        # Convert self.user to a DashboardUser manually instead of letting save_dashboard_user do
        # it to get access to add_letter_proofing_data().
        user = DashboardUser(data = self.user.to_dict())
        rdata['created_ts'] = datetime.utcfromtimestamp(int(rdata['created_ts']))
        rdata['verified_ts'] = datetime.utcfromtimestamp(int(rdata['verified_ts']))
        user.add_letter_proofing_data(rdata)

        # Look up users official address at the time of verification per Kantara requirements
        logger.info("Looking up address via Navet for user {!r}.".format(self.user))
        user_postal_address = self.request.msgrelay.get_full_postal_address(rdata['number'])
        logger.info("Finished looking up address via Navet for user {!r}.".format(self.user))
        proofing_data = LetterProofing(self.user, rdata['number'], rdata['official_address'],
                                       rdata['transaction_id'], user_postal_address)

        # Log verification event and fail if that goes wrong
        logger.info("Logging proofing data for user {!r}.".format(self.user))
        if not self.request.idproofinglog.log_verification(proofing_data):
            log.error('Logging of letter proofing data for user {!r} failed.'.format(self.user))
            return make_result('error', _('Sorry, we are experiencing temporary technical '
                                          'problems, please try again later.'))

        logger.info("Finished logging proofing data for user {!r}.".format(self.user))
        # This is a hack to reuse the existing proofing functionality, the users code has
        # already been verified by the micro service but we decided the dashboard could
        # continue 'upgrading' the users until we've made the planned proofing consumer
        set_nin_verified(self.request, user, nin)
        try:
            self.request.context.save_dashboard_user(user)
        except UserOutOfSync:
            log.error("Verified norEduPersonNIN NOT saved for user {!r}. User out of sync.".format(
                self.user))
            return self.sync_user()
        self.user = user

        # Finally mark the verification as used
        save_as_verified(self.request, 'norEduPersonNIN', self.user, nin)
        logger.info("Verified NIN by physical letter saved for user {!r}.".format(
            self.user))

        return make_result('success', _('You have successfully verified your identity'))
Ejemplo n.º 27
0
def validate_nin_by_mobile(request, user, nin):
    """
    :param request: The pyramid request
    :param user: The eduid user
    :param nin: The NIN
    :type request: pyramid.request.Request
    :type user: eduid_userdb.User
    :type nin: str
    :return:dict
    """
    log.info('Trying to verify nin via mobile number for user {!r}.'.format(user))
    log.debug('NIN: {!s}.'.format(nin))
    from eduid_lookup_mobile.utilities import format_NIN
    # Get list of verified mobile numbers
    verified_mobiles = [x.number for x in user.phone_numbers.to_list() if x.is_verified]

    national_identity_number = format_NIN(nin)
    status = 'no_phone'
    valid_mobile = None
    registered_to_nin = None

    age = _get_age(national_identity_number)

    try:
        for mobile_number in verified_mobiles:
            status = 'no_match'
            # Get the registered owner of the mobile number
            registered_to_nin = request.lookuprelay.find_NIN_by_mobile(mobile_number)
            registered_to_nin = format_NIN(registered_to_nin)

            if registered_to_nin == national_identity_number:
                # Check if registered nin was the given nin
                valid_mobile = mobile_number
                status = 'match'
                log.info('Mobile number matched for user {!r}.'.format(user))
                log.debug('Mobile {!s} registered to NIN: {!s}.'.format(valid_mobile, registered_to_nin))
                request.stats.count('dashboard/validate_nin_by_mobile_exact_match', 1)
                break
            elif registered_to_nin is not None and age < 18:
                # Check if registered nin is related to given nin
                relation = request.msgrelay.get_relations_to(national_identity_number, registered_to_nin)
                # TODO All relations?
                #valid_relations = ['M', 'B', 'FA', 'MO', 'VF']
                valid_relations = ['FA', 'MO']
                if any(r in relation for r in valid_relations):
                    valid_mobile = mobile_number
                    status = 'match_by_navet'
                    log.info('Mobile number matched for user {!r} via navet.'.format(user))
                    log.debug('Mobile {!s} registered to NIN: {!s}.'.format(valid_mobile, registered_to_nin))
                    log.debug('Person with NIN {!s} have relation {!s} to user: {!r}.'.format(registered_to_nin,
                                                                                              relation, user))
                    request.stats.count('dashboard/validate_nin_by_mobile_relative_match', 1)
                    break
    except request.lookuprelay.TaskFailed:
        status = 'error_lookup'
    except request.msgrelay.TaskFailed:
        status = 'error_navet'

    msg = None
    if status == 'no_phone':
        msg = _('You have no confirmed mobile phone')
        log.info('User {!r} has no verified mobile phone number.'.format(user))
    elif status == 'no_match':
        log.info('User {!r} NIN is not associated with any verified mobile phone number.'.format(user))
        msg = _('The given mobile number was not associated to the given national identity number')
        request.stats.count('dashboard/validate_nin_by_mobile_no_match', 1)
    elif status == 'error_lookup' or status == 'error_navet':
        log.error('Validate NIN via mobile failed with status "{!s}" for user {!r}.'.format(status, user))
        msg = _('Sorry, we are experiencing temporary technical '
                'problem with ${service_name}, please try again '
                'later.')
        request.stats.count('dashboard/validate_nin_by_mobile_error', 1)

    if status == 'match' or status == 'match_by_navet':
        log.info('Validate NIN via mobile succeeded with status "{!s}" for user {!r}.'.format(status, user))
        msg = _('Validate NIN via mobile with succeeded')
        user_postal_address = request.msgrelay.get_full_postal_address(national_identity_number)
        if status == 'match':
            proofing_data = TeleAdressProofing(user, status, national_identity_number, valid_mobile,
                                               user_postal_address)
        else:
            registered_postal_address = request.msgrelay.get_full_postal_address(registered_to_nin)
            proofing_data = TeleAdressProofingRelation(user, status, national_identity_number, valid_mobile,
                                                       user_postal_address, registered_to_nin, relation,
                                                       registered_postal_address)

        log.info('Logging of mobile proofing data for user {!r}.'.format(user))
        if not request.idproofinglog.log_verification(proofing_data):
            log.error('Logging of mobile proofing data for user {!r} failed.'.format(user))
            valid_mobile = None
            msg = _('Sorry, we are experiencing temporary technical '
                    'problem with ${service_name}, please try again '
                    'later.')

    validation_result = {'success': valid_mobile is not None, 'message': msg, 'mobile': valid_mobile}
    return validation_result
Ejemplo n.º 28
0
def verify_code(request, model_name, code):
    """
    Verify a code and act accordingly to the model_name ('norEduPersonNIN', 'phone', or 'mailAliases').

    This is what turns an unconfirmed NIN/mobile/e-mail into a confirmed one.

    :param request: The HTTP request
    :param model_name: 'norEduPersonNIN', 'phone', or 'mailAliases'
    :param code: The user supplied code
    :type request: pyramid.request.Request
    :return: string of verified data
    """
    assert model_name in ['norEduPersonNIN', 'phone', 'mailAliases']

    this_verification = request.db.verifications.find_one(
        {
            "model_name": model_name,
            "code": code,
        })

    if not this_verification:
        log.error("Could not find verification record for code {!r}, model {!r}".format(code, model_name))
        return

    reference = unicode(this_verification['_id'])
    obj_id = this_verification['obj_id']

    if not obj_id:
        return None

    user = get_session_user(request, legacy_user=False)
    retrieve_modified_ts(user, request.dashboard_userdb)

    assert_error_msg = 'Requesting users ID does not match verifications user ID'
    assert user.user_id == this_verification['user_oid'], assert_error_msg

    if model_name == 'norEduPersonNIN':
        msg = set_nin_verified(request, user, obj_id, reference)
    elif model_name == 'phone':
        msg = set_phone_verified(request, user, obj_id)
    elif model_name == 'mailAliases':
        msg = set_email_verified(request, user, obj_id)
    else:
        raise NotImplementedError('Unknown validation model_name: {!r}'.format(model_name))

    try:
        request.context.save_dashboard_user(user)
        log.info("Verified {!s} saved for user {!r}.".format(model_name, user))
        verified = {
            'verified': True,
            'verified_timestamp': datetime.utcnow()
        }
        this_verification.update(verified)
        request.db.verifications.update({'_id': this_verification['_id']}, this_verification)
        log.info("Code {!r} ({!s}) marked as verified".format(code, obj_id))
    except UserOutOfSync:
        log.info("Verified {!s} NOT saved for user {!r}. User out of sync.".format(model_name, user))
        raise
    else:
        msg = get_localizer(request).translate(msg)
        request.session.flash(msg.format(obj=obj_id), queue='forms')
        request.stats.count('verify_code_completed')
    return obj_id