def test_confirmation_different_user_when_logged_in_no_auto( client, get_message): """ Default - AUTO_LOGIN == false so shouldn't log in second user. """ e1 = "*****@*****.**" e2 = "*****@*****.**" with capture_registrations() as registrations: for e in e1, e2: data = dict(email=e, password="******", next="") client.post("/register", data=data) logout(client) token1 = registrations[0]["confirm_token"] token2 = registrations[1]["confirm_token"] client.get("/confirm/" + token1, follow_redirects=True) logout(client) authenticate(client, email=e1) response = client.get("/confirm/" + token2, follow_redirects=True) assert get_message("EMAIL_CONFIRMED") in response.data # should get a login view assert ( b'<input id="password" name="password" required type="password" value="">' in response.data)
def test_two_factor_json(app, client, get_message): with capture_registrations() as registrations: data = dict(email="*****@*****.**", password="******") response = client.post("/register", content_type="application/json", data=json.dumps(data)) assert response.headers["content-type"] == "application/json" assert response.jdata["meta"]["code"] == 200 assert len(response.jdata["response"]) == 2 assert all(k in response.jdata["response"] for k in ["csrf_token", "user"]) # make sure not logged in response = client.get("/profile", headers={"accept": "application/json"}) assert response.status_code == 401 assert response.jdata["response"]["error"].encode("utf-8") == get_message( "UNAUTHENTICATED") token = registrations[0]["confirm_token"] response = client.get("/confirm/" + token, headers={"Accept": "application/json"}) assert response.status_code == 200 assert response.jdata["response"]["tf_required"] assert response.jdata["response"]["tf_state"] == "setup_from_login"
def test_confirm_bad_token(self): e = '*****@*****.**' with capture_registrations(): self.register(e) with capture_signals() as mocks: self.client.get('/confirm/bogus', follow_redirects=True) self.assertEqual(mocks.signals_sent(), set())
def test_spa_get(app, client): """ Test 'single-page-application' style redirects This uses json only. """ with capture_flashes() as flashes: with capture_registrations() as registrations: response = client.post( "/register", data='{"email": "*****@*****.**",\ "password": "******"}', headers={"Content-Type": "application/json"}, ) assert response.headers["Content-Type"] == "application/json" token = registrations[0]["confirm_token"] response = client.get("/confirm/" + token) assert response.status_code == 302 split = urlsplit(response.headers["Location"]) assert "localhost:8081" == split.netloc assert "/confirm-redirect" == split.path qparams = dict(parse_qsl(split.query)) assert qparams["email"] == "*****@*****.**" # Arguably for json we shouldn't have any - this is buried in register_user # but really shouldn't be. assert len(flashes) == 1
def test_confirm_redirect_to_post_confirm(client, get_message): with capture_registrations() as registrations: data = dict(email="*****@*****.**", password="******", next="") client.post("/register", data=data, follow_redirects=True) token = registrations[0]["confirm_token"] response = client.get("/confirm/" + token, follow_redirects=True) assert b"Post Confirm" in response.data
def test_confirm_redirect_to_post_confirm(client, get_message): with capture_registrations() as registrations: data = dict(email='*****@*****.**', password='******', next='') client.post('/register', data=data, follow_redirects=True) token = registrations[0]['confirm_token'] response = client.get('/confirm/' + token, follow_redirects=True) assert b'Post Confirm' in response.data
def test_confirm_twice(self): e = '*****@*****.**' with capture_registrations() as registrations: self.register(e) token = registrations[0]['confirm_token'] self.client.get('/confirm/' + token, follow_redirects=True) self.logout() with capture_signals() as mocks: self.client.get('/confirm/' + token, follow_redirects=True) self.assertEqual(mocks.signals_sent(), set([user_confirmed]))
def test_send_confirmation_of_already_confirmed_account(self): e = '*****@*****.**' with capture_registrations() as registrations: r = self.register(e) token = registrations[0]['confirm_token'] self.client.get('/confirm/' + token, follow_redirects=True) self.logout() r = self._post('/confirm', data=dict(email=e)) m = self.get_message('ALREADY_CONFIRMED') self.assertIn(m.encode('utf-8'), r.data)
def test_confirm_redirect(client, get_message): with capture_registrations() as registrations: data = dict(email="*****@*****.**", password="******", next="") client.post("/register", data=data, follow_redirects=True) token = registrations[0]["confirm_token"] response = client.get("/confirm/" + token) assert "location" in response.headers assert "/login" in response.location response = client.get(response.location) assert get_message("EMAIL_CONFIRMED") in response.data
def test_expired_confirmation_token(client, get_message): with capture_registrations() as registrations: data = dict(email='*****@*****.**', password='******', next='') client.post('/register', data=data, follow_redirects=True) user = registrations[0]['user'] token = registrations[0]['confirm_token'] time.sleep(1) response = client.get('/confirm/' + token, follow_redirects=True) msg = get_message('CONFIRMATION_EXPIRED', within='1 milliseconds', email=user.email) assert msg in response.data
def test_confirm_redirect(client, get_message): with capture_registrations() as registrations: data = dict(email='*****@*****.**', password='******', next='') client.post('/register', data=data, follow_redirects=True) token = registrations[0]['confirm_token'] response = client.get('/confirm/' + token) assert 'location' in response.headers assert '/login' in response.location response = client.get(response.location) assert get_message('EMAIL_CONFIRMED') in response.data
def test_confirm(self): e = '*****@*****.**' with capture_registrations() as registrations: self.register(e) token = registrations[0]['confirm_token'] with capture_signals() as mocks: self.client.get('/confirm/' + token, follow_redirects=True) user = self.app.security.datastore.find_user(email='*****@*****.**') self.assertTrue(mocks.signals_sent(), set([user_confirmed])) calls = mocks[user_confirmed] self.assertEqual(len(calls), 1) args, kwargs = calls[0] self.assertEqual(args[0].id, user.id) self.assertEqual(kwargs['app'], self.app)
def test_confirm(self): e = '*****@*****.**' with capture_registrations() as registrations: self.register(e) token = registrations[0]['confirm_token'] with capture_signals() as mocks: self.client.get('/confirm/' + token, follow_redirects=True) user = self.app.security.datastore.find_user(email='*****@*****.**') self.assertTrue(mocks.signals_sent(), set([user_confirmed])) calls = mocks[user_confirmed] self.assertEqual(len(calls), 1) args, kwargs = calls[0] self.assertEqual(args[0], self.app) self.assertTrue(compare_user(kwargs['user'], user))
def test_confirm(self): e = "*****@*****.**" with capture_registrations() as registrations: self.register(e) token = registrations[0]["confirm_token"] with capture_signals() as mocks: self.client.get("/confirm/" + token, follow_redirects=True) user = self.app.security.datastore.find_user(email="*****@*****.**") self.assertTrue(mocks.signals_sent(), set([user_confirmed])) calls = mocks[user_confirmed] self.assertEqual(len(calls), 1) args, kwargs = calls[0] self.assertEqual(args[0], self.app) self.assertTrue(compare_user(kwargs["user"], user))
def test_expired_confirmation_token(client, get_message): with capture_registrations() as registrations: data = dict(email="*****@*****.**", password="******", next="") client.post("/register", data=data, follow_redirects=True) user = registrations[0]["user"] token = registrations[0]["confirm_token"] time.sleep(1) response = client.get("/confirm/" + token, follow_redirects=True) msg = get_message("CONFIRMATION_EXPIRED", within="1 milliseconds", email=user.email) assert msg in response.data
def test_user_deleted_before_confirmation(self): e = '*****@*****.**' with capture_registrations() as registrations: self.register(e) user = registrations[0]['user'] token = registrations[0]['confirm_token'] with self.app.app_context(): from flask_security.core import _security _security.datastore.delete(user) _security.datastore.commit() r = self.client.get('/confirm/' + token, follow_redirects=True) msg = self.app.config['SECURITY_MSG_INVALID_CONFIRMATION_TOKEN'][0] self.assertIn(msg.encode('utf-8'), r.data)
def test_two_factor(app, client): """ If two-factor is enabled, the confirm shouldn't login, but start the 2-factor setup. """ with capture_registrations() as registrations: data = dict(email="*****@*****.**", password="******", next="") client.post("/register", data=data, follow_redirects=True) # make sure not logged in response = client.get("/profile") assert response.status_code == 302 assert "/login?next=%2Fprofile" in response.location token = registrations[0]["confirm_token"] response = client.get("/confirm/" + token, follow_redirects=False) assert "tf-setup" in response.location
def test_confirm_email_of_user_different_than_current_user(self): e1 = '*****@*****.**' e2 = '*****@*****.**' with capture_registrations() as registrations: self.register(e1) self.register(e2) token1 = registrations[0]['confirm_token'] token2 = registrations[1]['confirm_token'] self.client.get('/confirm/' + token1, follow_redirects=True) self.client.get('/logout') self.authenticate(email=e1) r = self.client.get('/confirm/' + token2, follow_redirects=True) m = self.app.config['SECURITY_MSG_EMAIL_CONFIRMED'][0] self.assertIn(m.encode('utf-8'), r.data) self.assertIn(b'Hello [email protected]', r.data)
def test_spa_get_bad_token(app, client, get_message): """ Test expired and invalid token""" with capture_flashes() as flashes: with capture_registrations() as registrations: response = client.post( "/register", data='{"email": "*****@*****.**",\ "password": "******"}', headers={"Content-Type": "application/json"}, ) assert response.headers["Content-Type"] == "application/json" token = registrations[0]["confirm_token"] time.sleep(1) response = client.get("/confirm/" + token) assert response.status_code == 302 split = urlsplit(response.headers["Location"]) assert "localhost:8081" == split.netloc assert "/confirm-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("CONFIRMATION_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("/confirm/" + token) assert response.status_code == 302 split = urlsplit(response.headers["Location"]) assert "localhost:8081" == split.netloc assert "/confirm-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_CONFIRMATION_TOKEN") assert msg == qparams["error"].encode("utf-8") assert len(flashes) == 1
def test_confirm_email_of_user_different_than_current_user(self): e1 = '*****@*****.**' e2 = '*****@*****.**' with capture_registrations() as registrations: self.register(e1) self.logout() self.register(e2) token1 = registrations[0]['confirm_token'] token2 = registrations[1]['confirm_token'] self.client.get('/confirm/' + token1, follow_redirects=True) self.client.get('/logout') self.authenticate(email=e1) r = self.client.get('/confirm/' + token2, follow_redirects=True) m = self.app.config['SECURITY_MSG_EMAIL_CONFIRMED'][0] self.assertIn(m.encode('utf-8'), r.data) self.assertIn(b'Hello [email protected]', r.data)
def test_email_conflict_for_confirmation_token(app, client, get_message, sqlalchemy_datastore): with capture_registrations() as registrations: data = dict(email="*****@*****.**", password="******", next="") client.post("/register", data=data, follow_redirects=True) user = registrations[0]["user"] token = registrations[0]["confirm_token"] # Change the user's email user.email = "*****@*****.**" with app.app_context(): sqlalchemy_datastore.put(user) sqlalchemy_datastore.commit() response = client.get("/confirm/" + token, follow_redirects=True) msg = get_message("INVALID_CONFIRMATION_TOKEN") assert msg in response.data
def test_email_conflict_for_confirmation_token(app, client, get_message, sqlalchemy_datastore): with capture_registrations() as registrations: data = dict(email='*****@*****.**', password='******', next='') client.post('/register', data=data, follow_redirects=True) user = registrations[0]['user'] token = registrations[0]['confirm_token'] # Change the user's email user.email = '*****@*****.**' with app.app_context(): sqlalchemy_datastore.put(user) sqlalchemy_datastore.commit() response = client.get('/confirm/' + token, follow_redirects=True) msg = get_message('INVALID_CONFIRMATION_TOKEN') assert msg in response.data
def test_confirmation_different_user_when_logged_in(client, get_message): e1 = '*****@*****.**' e2 = '*****@*****.**' with capture_registrations() as registrations: for e in e1, e2: client.post('/register', data=dict(email=e, password='******')) logout(client) token1 = registrations[0]['confirm_token'] token2 = registrations[1]['confirm_token'] client.get('/confirm/' + token1, follow_redirects=True) logout(client) authenticate(client, email=e1) response = client.get('/confirm/' + token2, follow_redirects=True) assert get_message('EMAIL_CONFIRMED') in response.data assert b'Hello [email protected]' in response.data
def test_expired_confirmation_token_sends_email(self): e = '*****@*****.**' with capture_registrations() as registrations: self.register(e) token = registrations[0]['confirm_token'] time.sleep(1.25) with self.app.extensions['mail'].record_messages() as outbox: r = self.client.get('/confirm/' + token, follow_redirects=True) self.assertEqual(len(outbox), 1) self.assertNotIn(token, outbox[0].html) expire_text = self.AUTH_CONFIG['SECURITY_CONFIRM_EMAIL_WITHIN'] msg = self.app.config['SECURITY_MSG_CONFIRMATION_EXPIRED'][0] msg = msg % dict(within=expire_text, email=e) self.assertIn(msg.encode('utf-8'), r.data)
def test_confirmation_different_user_when_logged_in(client, get_message): e1 = "*****@*****.**" e2 = "*****@*****.**" with capture_registrations() as registrations: for e in e1, e2: data = dict(email=e, password="******", next="") client.post("/register", data=data) logout(client) token1 = registrations[0]["confirm_token"] token2 = registrations[1]["confirm_token"] client.get("/confirm/" + token1, follow_redirects=True) logout(client) authenticate(client, email=e1) response = client.get("/confirm/" + token2, follow_redirects=True) assert get_message("EMAIL_CONFIRMED") in response.data assert b"Welcome [email protected]" in response.data
def test_confirmable_flag(app, client, sqlalchemy_datastore, get_message): recorded_confirms = [] recorded_instructions_sent = [] @user_confirmed.connect_via(app) def on_confirmed(app, user): assert isinstance(app, Flask) assert isinstance(user, UserMixin) recorded_confirms.append(user) @confirm_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 login before confirmation email = "*****@*****.**" with capture_registrations() as registrations: data = dict(email=email, password="******", next="") response = client.post("/register", data=data) assert response.status_code == 302 response = authenticate(client, email=email) assert get_message("CONFIRMATION_REQUIRED") in response.data # Test invalid token response = client.get("/confirm/bogus", follow_redirects=True) assert get_message("INVALID_CONFIRMATION_TOKEN") in response.data # Test JSON response = client.post( "/confirm", data='{"email": "*****@*****.**"}', headers={"Content-Type": "application/json"}, ) assert response.status_code == 200 assert response.headers["Content-Type"] == "application/json" assert "user" in response.jdata["response"] assert len(recorded_instructions_sent) == 1 # Test ask for instructions with invalid email response = client.post("/confirm", data=dict(email="*****@*****.**")) assert get_message("USER_DOES_NOT_EXIST") in response.data # Test resend instructions response = client.post("/confirm", data=dict(email=email)) assert get_message("CONFIRMATION_REQUEST", email=email) in response.data assert len(recorded_instructions_sent) == 2 # Test confirm token = registrations[0]["confirm_token"] response = client.get("/confirm/" + token, follow_redirects=True) assert get_message("EMAIL_CONFIRMED") in response.data assert len(recorded_confirms) == 1 # Test already confirmed response = client.get("/confirm/" + token, follow_redirects=True) assert get_message("ALREADY_CONFIRMED") in response.data assert len(recorded_instructions_sent) == 2 # Test already confirmed and expired token app.config["SECURITY_CONFIRM_EMAIL_WITHIN"] = "-1 days" with app.app_context(): user = registrations[0]["user"] expired_token = generate_confirmation_token(user) response = client.get("/confirm/" + expired_token, follow_redirects=True) assert get_message("ALREADY_CONFIRMED") in response.data assert len(recorded_instructions_sent) == 2 # Test already confirmed when asking for confirmation instructions logout(client) response = client.get("/confirm") assert response.status_code == 200 response = client.post("/confirm", data=dict(email=email)) assert get_message("ALREADY_CONFIRMED") in response.data # Test user was deleted before confirmation with capture_registrations() as registrations: data = dict(email="*****@*****.**", password="******", next="") client.post("/register", data=data) user = registrations[0]["user"] token = registrations[0]["confirm_token"] with app.app_context(): sqlalchemy_datastore.delete(user) sqlalchemy_datastore.commit() response = client.get("/confirm/" + token, follow_redirects=True) assert get_message("INVALID_CONFIRMATION_TOKEN") in response.data
def test_confirmable_flag(app, client, sqlalchemy_datastore, get_message): recorded_confirms = [] recorded_instructions_sent = [] @user_confirmed.connect_via(app) def on_confirmed(app, user): recorded_confirms.append(user) @confirm_instructions_sent.connect_via(app) def on_instructions_sent(app, user): recorded_instructions_sent.append(user) # Test login before confirmation email = '*****@*****.**' with capture_registrations() as registrations: data = dict(email=email, password='******', next='') response = client.post('/register', data=data) assert response.status_code == 302 response = authenticate(client, email=email) assert get_message('CONFIRMATION_REQUIRED') in response.data # Test invalid token response = client.get('/confirm/bogus', follow_redirects=True) assert get_message('INVALID_CONFIRMATION_TOKEN') in response.data # Test JSON response = client.post('/confirm', data='{"email": "*****@*****.**"}', headers={ 'Content-Type': 'application/json' }) assert response.status_code == 200 assert response.headers['Content-Type'] == 'application/json' assert 'user' in response.jdata['response'] assert len(recorded_instructions_sent) == 1 # Test ask for instructions with invalid email response = client.post('/confirm', data=dict(email='*****@*****.**')) assert get_message('USER_DOES_NOT_EXIST') in response.data # Test resend instructions response = client.post('/confirm', data=dict(email=email)) assert get_message('CONFIRMATION_REQUEST', email=email) in response.data assert len(recorded_instructions_sent) == 2 # Test confirm token = registrations[0]['confirm_token'] response = client.get('/confirm/' + token, follow_redirects=True) assert get_message('EMAIL_CONFIRMED') in response.data assert len(recorded_confirms) == 1 # Test already confirmed response = client.get('/confirm/' + token, follow_redirects=True) assert get_message('ALREADY_CONFIRMED') in response.data # Test already confirmed when asking for confirmation instructions logout(client) response = client.get('/confirm') assert response.status_code == 200 response = client.post('/confirm', data=dict(email=email)) assert get_message('ALREADY_CONFIRMED') in response.data # Test user was deleted before confirmation with capture_registrations() as registrations: data = dict(email='*****@*****.**', password='******', next='') client.post('/register', data=data) user = registrations[0]['user'] token = registrations[0]['confirm_token'] with app.app_context(): sqlalchemy_datastore.delete(user) sqlalchemy_datastore.commit() response = client.get('/confirm/' + token, follow_redirects=True) assert get_message('INVALID_CONFIRMATION_TOKEN') in response.data
def test_confirmable_flag(app, client, sqlalchemy_datastore, get_message): recorded_confirms = [] recorded_instructions_sent = [] @user_confirmed.connect_via(app) def on_confirmed(app, user): recorded_confirms.append(user) @confirm_instructions_sent.connect_via(app) def on_instructions_sent(app, user): recorded_instructions_sent.append(user) # Test login before confirmation email = '*****@*****.**' with capture_registrations() as registrations: response = client.post('/register', data=dict(email=email, password='******')) assert response.status_code == 302 response = authenticate(client, email=email) assert get_message('CONFIRMATION_REQUIRED') in response.data # Test invalid token response = client.get('/confirm/bogus', follow_redirects=True) assert get_message('INVALID_CONFIRMATION_TOKEN') in response.data # Test JSON response = client.post('/confirm', data='{"email": "*****@*****.**"}', headers={'Content-Type': 'application/json'}) assert response.status_code == 200 assert response.headers['Content-Type'] == 'application/json' assert 'user' in response.jdata['response'] assert len(recorded_instructions_sent) == 1 # Test ask for instructions with invalid email response = client.post('/confirm', data=dict(email='*****@*****.**')) assert get_message('USER_DOES_NOT_EXIST') in response.data # Test resend instructions response = client.post('/confirm', data=dict(email=email)) assert get_message('CONFIRMATION_REQUEST', email=email) in response.data assert len(recorded_instructions_sent) == 2 # Test confirm token = registrations[0]['confirm_token'] response = client.get('/confirm/' + token, follow_redirects=True) assert get_message('EMAIL_CONFIRMED') in response.data assert len(recorded_confirms) == 1 # Test already confirmed response = client.get('/confirm/' + token, follow_redirects=True) assert get_message('ALREADY_CONFIRMED') in response.data # Test already confirmed when asking for confirmation instructions logout(client) response = client.get('/confirm') assert response.status_code == 200 response = client.post('/confirm', data=dict(email=email)) assert get_message('ALREADY_CONFIRMED') in response.data # Test user was deleted before confirmation with capture_registrations() as registrations: client.post('/register', data=dict(email='*****@*****.**', password='******')) user = registrations[0]['user'] token = registrations[0]['confirm_token'] with app.app_context(): sqlalchemy_datastore.delete(user) sqlalchemy_datastore.commit() response = client.get('/confirm/' + token, follow_redirects=True) assert get_message('INVALID_CONFIRMATION_TOKEN') in response.data
def test_confirmable_flag(app, client, sqlalchemy_datastore, get_message): recorded_confirms = [] recorded_instructions_sent = [] @user_confirmed.connect_via(app) def on_confirmed(app, user): assert isinstance(app, Flask) assert isinstance(user, UserMixin) recorded_confirms.append(user) @confirm_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 login before confirmation email = '*****@*****.**' with capture_registrations() as registrations: data = dict(email=email, password='******', next='') response = client.post('/register', data=data) assert response.status_code == 302 response = authenticate(client, email=email) assert get_message('CONFIRMATION_REQUIRED') in response.data # Test invalid token response = client.get('/confirm/bogus', follow_redirects=True) assert get_message('INVALID_CONFIRMATION_TOKEN') in response.data # Test ask for instructions with invalid email response = client.post('/confirm', data=dict(email='*****@*****.**')) assert get_message('USER_DOES_NOT_EXIST') in response.data # Test resend instructions response = client.post('/confirm', data=dict(email=email)) assert get_message('CONFIRMATION_REQUEST', email=email) in response.data assert len(recorded_instructions_sent) == 1 # Test confirm token = registrations[0]['confirm_token'] response = client.get('/confirm/' + token, follow_redirects=True) assert get_message('EMAIL_CONFIRMED') in response.data assert len(recorded_confirms) == 1 # Test already confirmed response = client.get('/confirm/' + token, follow_redirects=True) assert get_message('ALREADY_CONFIRMED') in response.data assert len(recorded_instructions_sent) == 1 # Test already confirmed and expired token app.config['SECURITY_CONFIRM_EMAIL_WITHIN'] = '-1 days' with app.app_context(): user = registrations[0]['user'] expired_token = generate_confirmation_token(user) response = client.get('/confirm/' + expired_token, follow_redirects=True) assert get_message('ALREADY_CONFIRMED') in response.data assert len(recorded_instructions_sent) == 1 # Test already confirmed when asking for confirmation instructions logout(client) response = client.get('/confirm') assert response.status_code == 200 response = client.post('/confirm', data=dict(email=email)) assert get_message('ALREADY_CONFIRMED') in response.data # Test user was deleted before confirmation with capture_registrations() as registrations: data = dict(email='*****@*****.**', password='******', next='') client.post('/register', data=data) user = registrations[0]['user'] token = registrations[0]['confirm_token'] with app.app_context(): sqlalchemy_datastore.delete(user) sqlalchemy_datastore.commit() response = client.get('/confirm/' + token, follow_redirects=True) assert get_message('INVALID_CONFIRMATION_TOKEN') in response.data