def test_confirm_email_view(api): from flask_security.confirmable import generate_confirmation_token app = api with app.app_context(): normal_user = create_test_user(email='*****@*****.**') confirmed_user = create_test_user(email='*****@*****.**', confirmed_at=datetime.datetime.now()) db.session.commit() # Generate token token = generate_confirmation_token(normal_user) confirmed_token = generate_confirmation_token(confirmed_user) with app.test_client() as client: url = url_for('invenio_accounts_rest_auth.confirm_email') # Invalid token res = client.post(url, data=dict(token='foo')) payload = get_json(res) assert 'invalid confirmation token' in \ payload['message'][0].lower() # Already confirmed user res = client.post(url, data=dict(token=confirmed_token)) payload = get_json(res) assert 'email has already been confirmed' in \ payload['message'].lower() # Valid confirm user assert normal_user.confirmed_at is None res = client.post(url, data=dict(token=token)) payload = get_json(res) assert 'your email has been confirmed' in \ payload['message'].lower() assert normal_user.confirmed_at
def default_confirmation_link_func(user): """Return the confirmation link that will be sent to a user via email.""" token = generate_confirmation_token(user) endpoint = current_app.config[ "ACCOUNTS_CONFIRM_EMAIL_ENDPOINT"] or get_security_endpoint_name( "confirm_email") return token, _generate_token_url(endpoint, token)
def generate_confirmation_link(user): """ For a given user, generates confirmation link and token. Stand-in for flask_security function that requires enabling other non-RESTFul confirmation routes """ # Use generate_confirmation_token to create token token = generate_confirmation_token(user) return url_for('confirm', token=token, _external=True), token
def register_user(self): schema = RELS['v1.AuthView:register'][request.method] try: data = request_register_options.parse_args() validate(data, schema, format_checker=FormatChecker()) invite_token = data['token'] if invite_token: expired, invalid, invitor = get_token_status(invite_token, 'invite', 'USE_INVITE') if invalid or not invitor: return dict(status=409, message="Invite is invalid"), 409 if expired: return dict(status=409, message="Invite has expired"), 409 inviteTokenObj = Invite.find(token=invite_token).first() if not inviteTokenObj: return dict(status=409, message="Invite not found"), 409 if inviteTokenObj.invitee_id: return dict(status=409, message="Invite already used"), 409 password = encrypt_password(data['password']) user = register_user(email=data['email'], password=password, first_name=data['firstName'], last_name=data['lastName'], roles=[Role.first(name='user')]) if invite_token: inviteTokenObj.invitee_id = user.id inviteTokenObj.save() token = generate_confirmation_token(user) confirmation_link = urljoin(current_app.config['CLIENT_DOMAIN'], '/#/confirm?token='+token) #TODO this mail send should be performed asynchronously using celery, see issue #88850472 send_message( subject='Please Confirm Your FogMine Account', sender="*****@*****.**", recipients = [user.email], html_body=render_template('email/activate.html', user=user, confirmation_link=confirmation_link), text_body=render_template('email/activate.txt', user=user, confirmation_link=confirmation_link) ) user_data = generate_response_dict(user=user) #SEE 90454516, Login the user login_user(user) user.save() #saving the user as a precaution, want the log data return dict(status=201, message='A confirmation email has been sent to '+user.email, user=user_data), 201 except ValidationError as e: return dict(status=400, message=e.message), 400 except IntegrityError: return {'status': 409, 'message': 'An account with that email already exists.'}, 409 except werkzeug.exceptions.ClientDisconnected: return dict(status=400, message='one or more required arguments missing from this request'), 400
def test_confirmation_token(app, users): """Test expiration of token for email confirmation. Test to ensures that the configuration option is respected. """ user = users[0]["obj"] token = generate_confirmation_token(user) # Valid expired, invalid, token_user = confirm_email_token_status(token) assert expired is False and invalid is False and token_user is user # Expired time.sleep(4) expired, invalid, token_user = confirm_email_token_status(token) assert expired is True and invalid is False and token_user is user
def test_confirmation_token(app, users): """Test expiration of token for email confirmation. Test to ensures that the configuration option is respected. """ user = users[0]['obj'] token = generate_confirmation_token(user) # Valid expired, invalid, token_user = confirm_email_token_status(token) assert expired is False and invalid is False and token_user is user # Expired time.sleep(4) expired, invalid, token_user = confirm_email_token_status(token) assert expired is True and invalid is False and token_user is user
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): 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
def generate_confirmation_link(user, confirmation_url=None): if not confirmation_url: confirmation_url = 'login.confirm_email' token = generate_confirmation_token(user) return url_for(confirmation_url, token=token, _external=True), token
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