def delete_verification_token(token):
    """
    Gives call to party service to delete a verification token for the respondent
    :param token: the verification token
    """
    email = decode_email_token(token)
    logger.info("Attempting to delete respondent verification token",
                email=obfuscate_email(email))

    party_id = get_respondent_by_email(email)["id"]
    url = f"{app.config['PARTY_URL']}/party-api/v1/respondents/{party_id}/password-verification-token/{token}"
    response = requests.delete(url, auth=app.config["BASIC_AUTH"])

    try:
        response.raise_for_status()
    except requests.exceptions.HTTPError:
        if response.status_code == 404:
            logger.error("Verification token not found")
            raise NotFound("Token not found")
        logger.error("Failed to delete respondent verification token",
                     email=obfuscate_email(email))
        raise ApiError(logger, response)

    logger.info("Successfully deleted respondent verification token",
                email=obfuscate_email(email))

    return response.json()
def post_reset_password(token):
    form = ResetPasswordForm(request.form)

    if not form.validate():
        return get_reset_password(token, form_errors=form.errors)

    password = request.form.get('password')

    try:
        duration = app.config['EMAIL_TOKEN_EXPIRY']
        email = verification.decode_email_token(token, duration)
        party_controller.change_password(email, password)
    except ApiError as exc:
        if exc.status_code == 409:
            logger.warning('Token expired', api_url=exc.url, api_status_code=exc.status_code, token=token)
            return render_template('passwords/password-expired.html', token=token)
        elif exc.status_code == 404:
            logger.warning('Invalid token sent to party service', api_url=exc.url, api_status_code=exc.status_code,
                           token=token)
            abort(404)
        else:
            raise exc

    logger.info('Successfully changed user password', token=token)
    return redirect(url_for('passwords_bp.reset_password_confirmation'))
def get_reset_password(token, form_errors=None):
    form = ResetPasswordForm(request.form)

    try:
        duration = app.config['EMAIL_TOKEN_EXPIRY']
        _ = verification.decode_email_token(token, duration)
    except SignatureExpired:
        logger.warning('Token expired for frontstage reset', token=token, exc_info=True)
        return render_template('passwords/password-expired.html', token=token)
    except (BadSignature, BadData):
        logger.warning('Invalid token sent to frontstage password reset', token=token, exc_info=True)
        return render_template('passwords/password-expired.html', token=token)

    template_data = {
        "error": {
            "type": form_errors
        },
        'token': token
    }
    return render_template('passwords/reset-password.html', form=form, data=template_data)
示例#4
0
def get_reset_password(token, form_errors=None):
    form = ResetPasswordForm(request.form)

    try:
        duration = app.config["EMAIL_TOKEN_EXPIRY"]
        email = verification.decode_email_token(token, duration)
        respondent = party_controller.get_respondent_by_email(email)
        db_token = respondent["password_verification_token"]
        if not token == db_token:
            logger.warning("Token not found for respondent",
                           token=token,
                           respondent_id=respondent["id"])
            return render_template("passwords/password-token-not-found.html",
                                   token=token)
    except KeyError:
        logger.warning("Token not found for respondent",
                       token=token,
                       exc_info=True)
        return render_template("passwords/password-token-not-found.html",
                               token=token)
    except SignatureExpired:
        try:
            party_controller.delete_verification_token(token)
        except NotFound:
            return render_template("passwords/password-token-not-found.html",
                                   token=token)
        logger.warning("Token expired for frontstage reset",
                       token=token,
                       exc_info=True)
        return render_template("passwords/password-expired.html", token=token)
    except (BadSignature, BadData):
        logger.warning("Invalid token sent to frontstage password reset",
                       token=token,
                       exc_info=True)
        return render_template("passwords/password-expired.html", token=token)

    template_data = {"error": {"type": form_errors}, "token": token}
    return render_template("passwords/reset-password.html",
                           form=form,
                           data=template_data)
def resend_password_email_expired_token(token):
    email = verification.decode_email_token(token)
    return request_password_change(email)
示例#6
0
def request_password_change(email):
    respondent = party_controller.get_respondent_by_email(email)

    if not respondent:
        logger.info("Respondent does not exist")
        return redirect(url_for("passwords_bp.reset_password_trouble"))

    party_id = str(respondent["id"])
    password_reset_counter = party_controller.get_password_reset_counter(
        party_id)["counter"]

    if password_reset_counter != 0:
        try:
            email = verification.decode_email_token(
                respondent["password_verification_token"],
                app.config["PASSWORD_RESET_ATTEMPTS_TIMEOUT"])
        except SignatureExpired:
            try:
                party_controller.reset_password_reset_counter(party_id)
                password_reset_counter = 0
            except ApiError:
                logger.error("Error resetting password reset counter")
                return redirect(url_for("passwords_bp.reset_password_trouble"))

    if password_reset_counter >= 5:
        logger.error("Password reset attempts exceeded")
        return redirect(
            url_for("passwords_bp.exceeded_number_of_reset_attempts"))

    logger.info("Requesting password change", party_id=party_id)

    token = verification.generate_email_token(email)

    url_root = request.url_root
    # url_for comes with a leading slash, so strip off the trailing slash in url_root if there is one
    if url_root.endswith("/"):
        url_root = url_root[:-1]
    verification_url = url_root + url_for("passwords_bp.post_reset_password",
                                          token=token)

    personalisation = {
        "RESET_PASSWORD_URL": verification_url,
        "FIRST_NAME": respondent["firstName"]
    }

    logger.info("Reset password url", url=verification_url, party_id=party_id)

    party_controller.post_verification_token(email, token)

    try:
        NotifyGateway(app.config).request_to_notify(
            email=email, personalisation=personalisation, reference=party_id)
        logger.info("Password reset email successfully sent",
                    party_id=party_id)
    except RasNotifyError:
        # Note: intentionally suppresses exception
        logger.error("Error sending request to Notify Gateway",
                     respondent_id=party_id,
                     exc_info=True)

    # Get real time counter to check how many attempts are left
    password_reset_counter = party_controller.get_password_reset_counter(
        party_id)["counter"]
    if password_reset_counter == 4:
        flash(message="You have 1 try left to reset your password",
              category="warn")

    return redirect(
        url_for("passwords_bp.reset_password_check_email", token=token))
示例#7
0
def resend_password_email_expired_token(token):
    email = verification.decode_email_token(token)
    party_controller.post_verification_token(email, token)
    return request_password_change(email)
示例#8
0
def reset_password_check_email(token):
    email = verification.decode_email_token(token)
    return render_template("passwords/reset-password.check-email.html",
                           email=email)