Exemple #1
0
 def test_reset_view(self):
     with capture_reset_password_requests() as requests:
         r = self._post('/reset', data=dict(email='*****@*****.**'),
                        follow_redirects=True)
         t = requests[0]['token']
     r = self._get('/reset/' + t)
     self.assertIn(b'<h1>Reset password</h1>', r.data)
def test_expired_reset_token(client, get_message):
    with capture_reset_password_requests() as requests:
        client.post("/reset",
                    data=dict(email="*****@*****.**"),
                    follow_redirects=True)

    user = requests[0]["user"]
    token = requests[0]["token"]

    time.sleep(1)

    with capture_flashes() as flashes:
        msg = get_message("PASSWORD_RESET_EXPIRED",
                          within="1 milliseconds",
                          email=user.email)

        # Test getting reset form with expired token
        response = client.get("/reset/" + token, follow_redirects=True)
        assert msg in response.data

        # Test trying to reset password with expired token
        response = client.post(
            "/reset/" + token,
            data={
                "password": "******",
                "password_confirm": "newpassword"
            },
            follow_redirects=True,
        )

        assert msg in response.data
    assert len(flashes) == 2
def test_used_reset_token(client, get_message):
    with capture_reset_password_requests() as requests:
        client.post("/reset",
                    data=dict(email="*****@*****.**"),
                    follow_redirects=True)

    token = requests[0]["token"]

    # use the token
    response = client.post(
        "/reset/" + token,
        data={
            "password": "******",
            "password_confirm": "awesome sunset"
        },
        follow_redirects=True,
    )

    assert get_message("PASSWORD_RESET") in response.data

    logout(client)

    # attempt to use it a second time
    response2 = client.post(
        "/reset/" + token,
        data={
            "password": "******",
            "password_confirm": "otherpassword"
        },
        follow_redirects=True,
    )

    msg = get_message("INVALID_RESET_PASSWORD_TOKEN")
    assert msg in response2.data
def test_reset_token_deleted_user(app, client, get_message,
                                  sqlalchemy_datastore):
    with capture_reset_password_requests() as requests:
        client.post("/reset",
                    data=dict(email="*****@*****.**"),
                    follow_redirects=True)

    token = requests[0]["token"]

    # Delete user
    with app.app_context():
        # load user (and role) to get into session so cascade delete works.
        user = app.security.datastore.find_user(email="*****@*****.**")
        sqlalchemy_datastore.delete(user)
        sqlalchemy_datastore.commit()

    response = client.post(
        "/reset/" + token,
        data={
            "password": "******",
            "password_confirm": "newpassword"
        },
        follow_redirects=True,
    )

    msg = get_message("INVALID_RESET_PASSWORD_TOKEN")
    assert msg in response.data
def test_bc_password(app, client_nc):
    # Test behavior of BACKWARDS_COMPAT_AUTH_TOKEN_INVALID
    response = json_authenticate(client_nc, email="*****@*****.**")
    token = response.json["response"]["user"]["authentication_token"]
    verify_token(client_nc, token)
    json_logout(client_nc, token)

    with capture_reset_password_requests() as requests:
        response = client_nc.post(
            "/reset",
            json=dict(email="*****@*****.**"),
            headers={"Content-Type": "application/json"},
        )
        assert response.status_code == 200

    reset_token = requests[0]["token"]

    data = dict(password="******", password_confirm="awesome sunset")
    response = client_nc.post(
        "/reset/" + reset_token + "?include_auth_token=1",
        json=data,
        headers={"Content-Type": "application/json"},
    )
    assert response.status_code == 200
    assert "authentication_token" in response.json["response"]["user"]

    # changing password should have rendered existing auth tokens invalid
    verify_token(client_nc, token, status=401)

    # but new auth token should work
    token = response.json["response"]["user"]["authentication_token"]
    verify_token(client_nc, token)
def test_used_reset_token(client, get_message):
    with capture_reset_password_requests() as requests:
        client.post(
            '/reset',
            data=dict(
                email='*****@*****.**'),
            follow_redirects=True)

    token = requests[0]['token']

    # use the token
    response = client.post('/reset/' + token, data={
        'password': '******',
        'password_confirm': 'newpassword'
    }, follow_redirects=True)

    assert get_message('PASSWORD_RESET') in response.data

    logout(client)

    # attempt to use it a second time
    response2 = client.post('/reset/' + token, data={
        'password': '******',
        'password_confirm': 'otherpassword'
    }, follow_redirects=True)

    msg = get_message('INVALID_RESET_PASSWORD_TOKEN')
    assert msg in response2.data
def test_used_reset_token(client, get_message):
    with capture_reset_password_requests() as requests:
        client.post('/reset',
                    data=dict(email='*****@*****.**'),
                    follow_redirects=True)

    token = requests[0]['token']

    # use the token
    response = client.post('/reset/' + token,
                           data={
                               'password': '******',
                               'password_confirm': 'newpassword'
                           },
                           follow_redirects=True)

    assert get_message('PASSWORD_RESET') in response.data

    logout(client)

    # attempt to use it a second time
    response2 = client.post('/reset/' + token,
                            data={
                                'password': '******',
                                'password_confirm': 'otherpassword'
                            },
                            follow_redirects=True)

    msg = get_message('INVALID_RESET_PASSWORD_TOKEN')
    assert msg in response2.data
Exemple #8
0
 def test_reset_password(self):
     with capture_reset_password_requests() as requests:
         self._post('/reset', data=dict(email='*****@*****.**'),
                    follow_redirects=True)
         token = requests[0]['token']
     r = self._get('/reset/' + token)
     self.assertIn(b"My Reset Password Submit Field", r.data)
def test_custom_reset_templates(client):
    response = client.get("/reset")
    assert b"CUSTOM FORGOT PASSWORD" in response.data

    with capture_reset_password_requests() as requests:
        client.post("/reset", data=dict(email="*****@*****.**"), follow_redirects=True)
        token = requests[0]["token"]

    response = client.get("/reset/" + token)
    assert b"CUSTOM RESET PASSWORD" in response.data
def test_custom_reset_templates(client):
    response = client.get('/reset')
    assert b'CUSTOM FORGOT PASSWORD' in response.data

    with capture_reset_password_requests() as requests:
        client.post('/reset', data=dict(email='*****@*****.**'), follow_redirects=True)
        token = requests[0]['token']

    response = client.get('/reset/' + token)
    assert b'CUSTOM RESET PASSWORD' in response.data
Exemple #11
0
    def test_reset_password_template(self):
        with capture_reset_password_requests() as requests:
            r = self._post('/reset', data=dict(email='*****@*****.**'),
                           follow_redirects=True)

            t = requests[0]['token']

        r = self._get('/reset/' + t)

        self.assertIn(b'CUSTOM RESET PASSWORD', r.data)
def test_custom_reset_templates(client):
    response = client.get('/reset')
    assert b'CUSTOM FORGOT PASSWORD' in response.data

    with capture_reset_password_requests() as requests:
        client.post('/reset',
                    data=dict(email='*****@*****.**'),
                    follow_redirects=True)
        token = requests[0]['token']

    response = client.get('/reset/' + token)
    assert b'CUSTOM RESET PASSWORD' in response.data
Exemple #13
0
def test_basic_custom_forms(app, sqlalchemy_datastore):
    class MyLoginForm(LoginForm):
        email = StringField('My Login Email Address Field')

    class MyRegisterForm(RegisterForm):
        email = StringField('My Register Email Address Field')

    class MyForgotPasswordForm(ForgotPasswordForm):
        email = StringField(
            'My Forgot Email Address Field',
            validators=[
                email_required,
                email_validator,
                valid_user_email])

    class MyResetPasswordForm(ResetPasswordForm):
        password = StringField('My Reset Password Field')

    class MyChangePasswordForm(ChangePasswordForm):
        password = PasswordField('My Change Password Field')

    app.security = Security(app,
                            datastore=sqlalchemy_datastore,
                            login_form=MyLoginForm,
                            register_form=MyRegisterForm,
                            forgot_password_form=MyForgotPasswordForm,
                            reset_password_form=MyResetPasswordForm,
                            change_password_form=MyChangePasswordForm)

    populate_data(app)
    client = app.test_client()

    response = client.get('/login')
    assert b'My Login Email Address Field' in response.data

    response = client.get('/register')
    assert b'My Register Email Address Field' in response.data

    response = client.get('/reset')
    assert b'My Forgot Email Address Field' in response.data

    with capture_reset_password_requests() as requests:
        response = client.post('/reset', data=dict(email='*****@*****.**'))

    token = requests[0]['token']
    response = client.get('/reset/' + token)
    assert b'My Reset Password Field' in response.data

    authenticate(client)

    response = client.get('/change')
    assert b'My Change Password Field' in response.data
Exemple #14
0
def test_basic_custom_forms(app, sqlalchemy_datastore):
    class MyLoginForm(LoginForm):
        email = StringField("My Login Email Address Field")

    class MyRegisterForm(RegisterForm):
        email = StringField("My Register Email Address Field")

    class MyForgotPasswordForm(ForgotPasswordForm):
        email = StringField(
            "My Forgot Email Address Field",
            validators=[email_required, email_validator, valid_user_email],
        )

    class MyResetPasswordForm(ResetPasswordForm):
        password = StringField("My Reset Password Field")

    class MyChangePasswordForm(ChangePasswordForm):
        password = PasswordField("My Change Password Field")

    app.security = Security(
        app,
        datastore=sqlalchemy_datastore,
        login_form=MyLoginForm,
        register_form=MyRegisterForm,
        forgot_password_form=MyForgotPasswordForm,
        reset_password_form=MyResetPasswordForm,
        change_password_form=MyChangePasswordForm,
    )

    populate_data(app)
    client = app.test_client()

    response = client.get("/login")
    assert b"My Login Email Address Field" in response.data

    response = client.get("/register")
    assert b"My Register Email Address Field" in response.data

    response = client.get("/reset")
    assert b"My Forgot Email Address Field" in response.data

    with capture_reset_password_requests() as requests:
        response = client.post("/reset", data=dict(email="*****@*****.**"))

    token = requests[0]["token"]
    response = client.get("/reset/" + token)
    assert b"My Reset Password Field" in response.data

    authenticate(client)

    response = client.get("/change")
    assert b"My Change Password Field" in response.data
def test_reset_passwordless_user(client, get_message):
    with capture_reset_password_requests() as requests:
        client.post('/reset', data=dict(email='*****@*****.**'), follow_redirects=True)

    token = requests[0]['token']

    # use the token
    response = client.post('/reset/' + token, data={
        'password': '******',
        'password_confirm': 'newpassword'
    }, follow_redirects=True)

    assert get_message('PASSWORD_RESET') in response.data
 def test_reset_password(self):
     with capture_reset_password_requests() as requests:
         self._post("/reset", data=dict(email="*****@*****.**"), follow_redirects=True)
         token = requests[0]["token"]
     with capture_signals() as mocks:
         data = dict(password="******", password_confirm="newpassword")
         self._post("/reset/" + token, data, follow_redirects=True)
     self.assertEqual(mocks.signals_sent(), set([password_reset]))
     user = self.app.security.datastore.find_user(email="*****@*****.**")
     calls = mocks[password_reset]
     self.assertEqual(len(calls), 1)
     args, kwargs = calls[0]
     self.assertTrue(compare_user(kwargs["user"], user))
     self.assertEqual(args[0], self.app)
Exemple #17
0
    def test_reset_password_with_expired_token(self):
        with capture_reset_password_requests() as requests:
            r = self._post('/reset', data=dict(email='*****@*****.**'),
                           follow_redirects=True)
            t = requests[0]['token']

        time.sleep(1)

        r = self._post('/reset/' + t, data={
            'password': '******',
            'password_confirm': 'newpassword'
        }, follow_redirects=True)

        self.assertIn(b'You did not reset your password within', r.data)
Exemple #18
0
    def test_reset_password_with_valid_token(self):
        with capture_reset_password_requests() as requests:
            r = self._post('/reset', data=dict(email='*****@*****.**'),
                           follow_redirects=True)
            t = requests[0]['token']

        r = self._post('/reset/' + t, data={
            'password': '******',
            'password_confirm': 'newpassword'
        }, follow_redirects=True)

        r = self.logout()
        r = self.authenticate('*****@*****.**', 'newpassword')
        self.assertIn(b'Hello [email protected]', r.data)
def test_reset_passwordless_user(client, get_message):
    with capture_reset_password_requests() as requests:
        client.post("/reset", data=dict(email="*****@*****.**"), follow_redirects=True)

    token = requests[0]["token"]

    # use the token
    response = client.post(
        "/reset/" + token,
        data={"password": "******", "password_confirm": "awesome sunset"},
        follow_redirects=True,
    )

    assert get_message("PASSWORD_RESET") in response.data
def test_easy_password(client, get_message):
    with capture_reset_password_requests() as requests:
        client.post("/reset", data=dict(email="*****@*****.**"), follow_redirects=True)

    token = requests[0]["token"]

    # use the token
    response = client.post(
        "/reset/" + token,
        data={"password": "******", "password_confirm": "mypassword"},
        follow_redirects=True,
    )

    assert b"This is a very common password" in response.data
Exemple #21
0
 def test_reset_password(self):
     with capture_reset_password_requests() as requests:
         self._post('/reset', data=dict(email='*****@*****.**'),
                    follow_redirects=True)
         token = requests[0]['token']
     with capture_signals() as mocks:
         data = dict(password='******', password_confirm='newpassword')
         self._post('/reset/' + token, data, follow_redirects=True)
     self.assertEqual(mocks.signals_sent(), set([password_reset]))
     user = self.app.security.datastore.find_user(email='*****@*****.**')
     calls = mocks[password_reset]
     self.assertEqual(len(calls), 1)
     args, kwargs = calls[0]
     self.assertTrue(compare_user(kwargs['user'], user))
     self.assertEqual(args[0], self.app)
 def test_reset_password(self):
     with capture_reset_password_requests() as requests:
         self._post('/reset', data=dict(email='*****@*****.**'),
                    follow_redirects=True)
         token = requests[0]['token']
     with capture_signals() as mocks:
         data = dict(password='******', password_confirm='newpassword')
         self._post('/reset/' + token, data, follow_redirects=True)
     self.assertEqual(mocks.signals_sent(), set([password_reset]))
     user = self.app.security.datastore.find_user(email='*****@*****.**')
     calls = mocks[password_reset]
     self.assertEqual(len(calls), 1)
     args, kwargs = calls[0]
     self.assertTrue(compare_user(args[0], user))
     self.assertEqual(kwargs['app'], self.app)
Exemple #23
0
def test_reset_token_redirect_to_post_reset(client, get_message):
    with capture_reset_password_requests() as requests:
        client.post('/reset',
                    data=dict(email='*****@*****.**'),
                    follow_redirects=True)

    token = requests[0]['token']

    response = client.post('/reset/' + token,
                           data={
                               'password': '******',
                               'password_confirm': 'newpassword'
                           },
                           follow_redirects=True)
    assert b'Post Reset' in response.data
def test_expired_reset_token(client, get_message):
    with capture_reset_password_requests() as requests:
        client.post('/reset', data=dict(email='*****@*****.**'), follow_redirects=True)

    user = requests[0]['user']
    token = requests[0]['token']

    time.sleep(1)

    response = client.post('/reset/' + token, data={
        'password': '******',
        'password_confirm': 'newpassword'
    }, follow_redirects=True)

    msg = get_message('PASSWORD_RESET_EXPIRED', within='1 milliseconds', email=user.email)
    assert msg in response.data
def test_spa_get_bad_token(app, client, get_message):
    """ Test expired and invalid token"""
    with capture_flashes() as flashes:
        with capture_reset_password_requests() as requests:
            response = client.post(
                "/reset",
                data='{"email": "*****@*****.**"}',
                headers={"Content-Type": "application/json"},
            )
            assert response.headers["Content-Type"] == "application/json"
            assert "user" not in response.jdata["response"]
        token = requests[0]["token"]
        time.sleep(1)

        response = client.get("/reset/" + token)
        assert response.status_code == 302
        split = urlsplit(response.headers["Location"])
        assert "localhost:8081" == split.netloc
        assert "/reset-error" == split.path
        qparams = dict(parse_qsl(split.query))
        assert len(qparams) == 2
        assert all(k in qparams for k in ["email", "error"])

        msg = get_message(
            "PASSWORD_RESET_EXPIRED", within="1 milliseconds", email="*****@*****.**"
        )
        assert msg == qparams["error"].encode("utf-8")

        # Test mangled token
        token = (
            "WyIxNjQ2MzYiLCIxMzQ1YzBlZmVhM2VhZjYwODgwMDhhZGU2YzU0MzZjMiJd."
            "BZEw_Q.lQyo3npdPZtcJ_sNHVHP103syjM"
            "&url_id=fbb89a8328e58c181ea7d064c2987874bc54a23d"
        )
        response = client.get("/reset/" + token)
        assert response.status_code == 302
        split = urlsplit(response.headers["Location"])
        assert "localhost:8081" == split.netloc
        assert "/reset-error" == split.path
        qparams = dict(parse_qsl(split.query))
        assert len(qparams) == 1
        assert all(k in qparams for k in ["error"])

        msg = get_message("INVALID_RESET_PASSWORD_TOKEN")
        assert msg == qparams["error"].encode("utf-8")
    assert len(flashes) == 0
def test_reset_passwordless_user(client, get_message):
    with capture_reset_password_requests() as requests:
        client.post('/reset',
                    data=dict(email='*****@*****.**'),
                    follow_redirects=True)

    token = requests[0]['token']

    # use the token
    response = client.post('/reset/' + token,
                           data={
                               'password': '******',
                               'password_confirm': 'newpassword'
                           },
                           follow_redirects=True)

    assert get_message('PASSWORD_RESET') in response.data
Exemple #27
0
def test_reset_token_redirect(client, get_message):
    with capture_reset_password_requests() as requests:
        client.post('/reset',
                    data=dict(email='*****@*****.**'),
                    follow_redirects=True)

    token = requests[0]['token']

    response = client.post('/reset/' + token,
                           data={
                               'password': '******',
                               'password_confirm': 'newpassword'
                           })

    assert 'location' in response.headers
    assert '/login' in response.location

    response = client.get(response.location)
    assert get_message('PASSWORD_RESET') in response.data
def test_can_add_password(app, client, get_message):
    # Test that if register w/o a password, can use 'recover password' to assign one
    data = dict(email="*****@*****.**", password="")
    response = client.post("/register", data=data, follow_redirects=True)
    assert b"Welcome [email protected]" in response.data
    logout(client)

    with capture_reset_password_requests() as requests:
        client.post("/reset",
                    data=dict(email="*****@*****.**"),
                    follow_redirects=True)
    token = requests[0]["token"]

    response = client.post(
        "/reset/" + token,
        data={
            "password": "******",
            "password_confirm": "awesome sunset"
        },
        follow_redirects=True,
    )

    assert get_message("PASSWORD_RESET") in response.data

    # authenticate with new password using standard/old login endpoint.
    response = authenticate(client,
                            "*****@*****.**",
                            "awesome sunset",
                            follow_redirects=True)
    assert b"Welcome [email protected]" in response.data

    logout(client)
    # authenticate with password and us-signin endpoint
    response = client.post(
        "/us-signin",
        data=dict(identity="*****@*****.**", passcode="awesome sunset"),
        follow_redirects=True,
    )
    assert b"Welcome [email protected]" in response.data
def test_expired_reset_token(client, get_message):
    with capture_reset_password_requests() as requests:
        client.post('/reset',
                    data=dict(email='*****@*****.**'),
                    follow_redirects=True)

    user = requests[0]['user']
    token = requests[0]['token']

    time.sleep(1)

    response = client.post('/reset/' + token,
                           data={
                               'password': '******',
                               'password_confirm': 'newpassword'
                           },
                           follow_redirects=True)

    msg = get_message('PASSWORD_RESET_EXPIRED',
                      within='1 milliseconds',
                      email=user.email)
    assert msg in response.data
def test_spa_get(app, client):
    """
    Test 'single-page-application' style redirects
    This uses json only.
    """
    with capture_reset_password_requests() as requests:
        response = client.post(
            "/reset",
            json=dict(email="*****@*****.**"),
            headers={"Content-Type": "application/json"},
        )
        assert response.headers["Content-Type"] == "application/json"
        assert "user" not in response.json["response"]
    token = requests[0]["token"]

    response = client.get("/reset/" + token)
    assert response.status_code == 302
    split = urlsplit(response.headers["Location"])
    assert "localhost:8081" == split.netloc
    assert "/reset-redirect" == split.path
    qparams = dict(parse_qsl(split.query))
    assert qparams["email"] == "*****@*****.**"
    assert qparams["token"] == token
def test_reset_token_deleted_user(app, client, get_message,
                                  sqlalchemy_datastore):
    with capture_reset_password_requests() as requests:
        client.post('/reset',
                    data=dict(email='*****@*****.**'),
                    follow_redirects=True)

    user = requests[0]['user']
    token = requests[0]['token']

    # Delete user
    with app.app_context():
        sqlalchemy_datastore.delete(user)
        sqlalchemy_datastore.commit()

    response = client.post('/reset/' + token,
                           data={
                               'password': '******',
                               'password_confirm': 'newpassword'
                           },
                           follow_redirects=True)

    msg = get_message('INVALID_RESET_PASSWORD_TOKEN')
    assert msg in response.data
def test_reset_token_deleted_user(app, client, get_message,
                                  sqlalchemy_datastore):
    with capture_reset_password_requests() as requests:
        client.post(
            '/reset',
            data=dict(
                email='*****@*****.**'),
            follow_redirects=True)

    user = requests[0]['user']
    token = requests[0]['token']

    # Delete user
    with app.app_context():
        sqlalchemy_datastore.delete(user)
        sqlalchemy_datastore.commit()

    response = client.post('/reset/' + token, data={
        'password': '******',
        'password_confirm': 'newpassword'
    }, follow_redirects=True)

    msg = get_message('INVALID_RESET_PASSWORD_TOKEN')
    assert msg in response.data
def test_recoverable_flag(app, client, get_message):
    recorded_resets = []
    recorded_instructions_sent = []

    @password_reset.connect_via(app)
    def on_password_reset(app, user):
        recorded_resets.append(user)

    @reset_password_instructions_sent.connect_via(app)
    def on_instructions_sent(app, user, token):
        assert isinstance(app, Flask)
        assert isinstance(user, UserMixin)
        assert isinstance(token, str)
        recorded_instructions_sent.append(user)

    # Test the reset view
    response = client.get('/reset')
    assert b'<h1>Send password reset instructions</h1>' in response.data

    # Test submitting email to reset password creates a token and sends email
    with capture_reset_password_requests() as requests:
        with app.mail.record_messages() as outbox:
            response = client.post('/reset',
                                   data=dict(email='*****@*****.**'),
                                   follow_redirects=True)

    assert len(recorded_instructions_sent) == 1
    assert len(outbox) == 1
    assert response.status_code == 200
    assert get_message('PASSWORD_RESET_REQUEST',
                       email='*****@*****.**') in response.data
    token = requests[0]['token']

    # Test view for reset token
    response = client.get('/reset/' + token)
    assert b'<h1>Reset password</h1>' in response.data

    # Test submitting a new password
    response = client.post('/reset/' + token,
                           data={
                               'password': '******',
                               'password_confirm': 'newpassword'
                           },
                           follow_redirects=True)

    assert get_message('PASSWORD_RESET') in response.data
    assert len(recorded_resets) == 1

    logout(client)

    # Test logging in with the new password
    response = authenticate(client,
                            '*****@*****.**',
                            'newpassword',
                            follow_redirects=True)
    assert b'Hello [email protected]' in response.data

    logout(client)

    # Test invalid email
    response = client.post('/reset',
                           data=dict(email='*****@*****.**'),
                           follow_redirects=True)
    assert get_message('USER_DOES_NOT_EXIST') in response.data

    logout(client)

    # Test invalid token
    response = client.post('/reset/bogus',
                           data={
                               'password': '******',
                               'password_confirm': 'newpassword'
                           },
                           follow_redirects=True)
    assert get_message('INVALID_RESET_PASSWORD_TOKEN') in response.data

    # Test mangled token
    token = ("WyIxNjQ2MzYiLCIxMzQ1YzBlZmVhM2VhZjYwODgwMDhhZGU2YzU0MzZjMiJd."
             "BZEw_Q.lQyo3npdPZtcJ_sNHVHP103syjM"
             "&url_id=fbb89a8328e58c181ea7d064c2987874bc54a23d")
    response = client.post('/reset/' + token,
                           data={
                               'password': '******',
                               'password_confirm': 'newpassword'
                           },
                           follow_redirects=True)
    assert get_message('INVALID_RESET_PASSWORD_TOKEN') in response.data
Exemple #34
0
 def test_forgot_post_sends_email(self):
     with capture_reset_password_requests():
         with self.app.extensions['mail'].record_messages() as outbox:
             self._post('/reset', data=dict(email='*****@*****.**'))
             self.assertEqual(len(outbox), 1)
def test_recoverable_json(app, client, get_message):
    recorded_resets = []
    recorded_instructions_sent = []

    @password_reset.connect_via(app)
    def on_password_reset(app, user):
        recorded_resets.append(user)

    @reset_password_instructions_sent.connect_via(app)
    def on_instructions_sent(app, user, token):
        recorded_instructions_sent.append(user)

    with capture_flashes() as flashes:
        # Test reset password creates a token and sends email
        with capture_reset_password_requests() as requests:
            with app.mail.record_messages() as outbox:
                response = client.post(
                    "/reset",
                    json=dict(email="*****@*****.**"),
                    headers={"Content-Type": "application/json"},
                )
                assert response.headers["Content-Type"] == "application/json"

        assert len(recorded_instructions_sent) == 1
        assert len(outbox) == 1
        assert response.status_code == 200
        token = requests[0]["token"]

        # Test invalid email
        response = client.post(
            "/reset",
            json=dict(email="*****@*****.**"),
            headers={"Content-Type": "application/json"},
        )
        assert response.status_code == 400
        assert response.json["response"]["errors"]["email"][0].encode(
            "utf-8") == get_message("USER_DOES_NOT_EXIST")

        # Test submitting a new password but leave out 'confirm'
        response = client.post(
            "/reset/" + token,
            data='{"password": "******"}',
            headers={"Content-Type": "application/json"},
        )
        assert response.status_code == 400
        assert response.json["response"]["errors"]["password_confirm"][
            0].encode("utf-8") == get_message("PASSWORD_NOT_PROVIDED")

        # Test submitting a new password
        response = client.post(
            "/reset/" + token + "?include_auth_token",
            json=dict(password="******",
                      password_confirm="awesome sunset"),
            headers={"Content-Type": "application/json"},
        )
        assert all(k in response.json["response"]["user"]
                   for k in ["id", "authentication_token"])
        assert len(recorded_resets) == 1

        # reset automatically logs user in
        logout(client)

        # Test logging in with the new password
        response = client.post(
            "/login?include_auth_token",
            json=dict(email="*****@*****.**", password="******"),
            headers={"Content-Type": "application/json"},
        )
        assert all(k in response.json["response"]["user"]
                   for k in ["id", "authentication_token"])

        logout(client)

        # Use token again - should fail since already have set new password.
        response = client.post(
            "/reset/" + token,
            json=dict(password="******", password_confirm="newpassword"),
            headers={"Content-Type": "application/json"},
        )
        assert response.status_code == 400
        assert len(recorded_resets) == 1

        # Test invalid token
        response = client.post(
            "/reset/bogus",
            json=dict(password="******", password_confirm="newpassword"),
            headers={"Content-Type": "application/json"},
        )
        assert response.json["response"]["error"].encode(
            "utf-8") == get_message("INVALID_RESET_PASSWORD_TOKEN")
    assert len(flashes) == 0
def test_recoverable_flag(app, client, get_message):
    recorded_resets = []
    recorded_instructions_sent = []

    @password_reset.connect_via(app)
    def on_password_reset(app, user):
        recorded_resets.append(user)

    @reset_password_instructions_sent.connect_via(app)
    def on_instructions_sent(app, user, token):
        assert isinstance(app, Flask)
        assert isinstance(user, UserMixin)
        assert isinstance(token, string_types)
        recorded_instructions_sent.append(user)

    # Test the reset view
    response = client.get("/reset")
    assert b"<h1>Send password reset instructions</h1>" in response.data

    # Test submitting email to reset password creates a token and sends email
    with capture_reset_password_requests() as requests:
        with app.mail.record_messages() as outbox:
            response = client.post("/reset",
                                   data=dict(email="*****@*****.**"),
                                   follow_redirects=True)

    assert len(recorded_instructions_sent) == 1
    assert len(outbox) == 1
    assert response.status_code == 200
    assert get_message("PASSWORD_RESET_REQUEST",
                       email="*****@*****.**") in response.data
    token = requests[0]["token"]

    # Test view for reset token
    response = client.get("/reset/" + token)
    assert b"<h1>Reset password</h1>" in response.data

    # Test submitting a new password but leave out confirm
    response = client.post("/reset/" + token,
                           data={"password": "******"},
                           follow_redirects=True)
    assert get_message("PASSWORD_NOT_PROVIDED") in response.data
    assert len(recorded_resets) == 0

    # Test submitting a new password
    response = client.post(
        "/reset/" + token,
        data={
            "password": "******",
            "password_confirm": "awesome sunset"
        },
        follow_redirects=True,
    )

    assert get_message("PASSWORD_RESET") in response.data
    assert len(recorded_resets) == 1

    logout(client)

    # Test logging in with the new password
    response = authenticate(client,
                            "*****@*****.**",
                            "awesome sunset",
                            follow_redirects=True)
    assert b"Welcome [email protected]" in response.data

    logout(client)

    # Test invalid email
    response = client.post("/reset",
                           data=dict(email="*****@*****.**"),
                           follow_redirects=True)
    assert get_message("USER_DOES_NOT_EXIST") in response.data

    logout(client)

    # Test invalid token
    response = client.post(
        "/reset/bogus",
        data={
            "password": "******",
            "password_confirm": "awesome sunset"
        },
        follow_redirects=True,
    )
    assert get_message("INVALID_RESET_PASSWORD_TOKEN") in response.data

    # Test mangled token
    token = ("WyIxNjQ2MzYiLCIxMzQ1YzBlZmVhM2VhZjYwODgwMDhhZGU2YzU0MzZjMiJd."
             "BZEw_Q.lQyo3npdPZtcJ_sNHVHP103syjM"
             "&url_id=fbb89a8328e58c181ea7d064c2987874bc54a23d")
    response = client.post(
        "/reset/" + token,
        data={
            "password": "******",
            "password_confirm": "newpassword"
        },
        follow_redirects=True,
    )
    assert get_message("INVALID_RESET_PASSWORD_TOKEN") in response.data
def test_recoverable_flag(app, client, get_message):
    recorded_resets = []
    recorded_instructions_sent = []

    @password_reset.connect_via(app)
    def on_password_reset(app, user):
        recorded_resets.append(user)

    @reset_password_instructions_sent.connect_via(app)
    def on_instructions_sent(app, user, token):
        assert isinstance(app, Flask)
        assert isinstance(user, UserMixin)
        assert isinstance(token, string_types)
        recorded_instructions_sent.append(user)

    # Test the reset view
    response = client.get('/reset')
    assert b'<h1>Send password reset instructions</h1>' in response.data

    # Test submitting email to reset password creates a token and sends email
    with capture_reset_password_requests() as requests:
        with app.mail.record_messages() as outbox:
            response = client.post(
                '/reset',
                data=dict(
                    email='*****@*****.**'),
                follow_redirects=True)

    assert len(recorded_instructions_sent) == 1
    assert len(outbox) == 1
    assert response.status_code == 200
    assert get_message(
        'PASSWORD_RESET_REQUEST',
        email='*****@*****.**') in response.data
    token = requests[0]['token']

    # Test view for reset token
    response = client.get('/reset/' + token)
    assert b'<h1>Reset password</h1>' in response.data

    # Test submitting a new password
    response = client.post('/reset/' + token, data={
        'password': '******',
        'password_confirm': 'newpassword'
    }, follow_redirects=True)

    assert get_message('PASSWORD_RESET') in response.data
    assert len(recorded_resets) == 1

    logout(client)

    # Test logging in with the new password
    response = authenticate(
        client,
        '*****@*****.**',
        'newpassword',
        follow_redirects=True)
    assert b'Hello [email protected]' in response.data

    logout(client)

    # Test submitting JSON
    response = client.post('/reset', data='{"email": "*****@*****.**"}', headers={
        'Content-Type': 'application/json'
    })
    assert response.headers['Content-Type'] == 'application/json'
    assert 'user' not in response.jdata['response']

    logout(client)

    # Test invalid email
    response = client.post(
        '/reset',
        data=dict(
            email='*****@*****.**'),
        follow_redirects=True)
    assert get_message('USER_DOES_NOT_EXIST') in response.data

    logout(client)

    # Test invalid token
    response = client.post('/reset/bogus', data={
        'password': '******',
        'password_confirm': 'newpassword'
    }, follow_redirects=True)
    assert get_message('INVALID_RESET_PASSWORD_TOKEN') in response.data

    # Test mangled token
    token = (
        "WyIxNjQ2MzYiLCIxMzQ1YzBlZmVhM2VhZjYwODgwMDhhZGU2YzU0MzZjMiJd."
        "BZEw_Q.lQyo3npdPZtcJ_sNHVHP103syjM"
        "&url_id=fbb89a8328e58c181ea7d064c2987874bc54a23d")
    response = client.post('/reset/' + token, data={
        'password': '******',
        'password_confirm': 'newpassword'
    }, follow_redirects=True)
    assert get_message('INVALID_RESET_PASSWORD_TOKEN') in response.data