def test_login(): """ This tests if we can log in successfully or fail correctly. """ try: os.remove("test-login.authdb.sqlite") except Exception: pass try: os.remove("test-login.authdb.sqlite-shm") except Exception: pass try: os.remove("test-login.authdb.sqlite-wal") except Exception: pass get_test_authdb() get_public_suffix_list() # create the user user_payload = { "full_name": "Test User", "email": "*****@*****.**", "password": "******", "pii_salt": "super-secret-salt", "reqid": 1, } user_created = actions.create_new_user( user_payload, override_authdb_path="sqlite:///test-login.authdb.sqlite") assert user_created["success"] is True assert user_created["user_email"] == "*****@*****.**" assert ("User account created. Please verify your email address to log in." in user_created["messages"]) # create a new session token session_payload = { "user_id": 2, "user_agent": "Mozzarella Killerwhale", "expires": datetime.utcnow() + timedelta(hours=1), "ip_address": "1.1.1.1", "extra_info_json": { "pref_datasets_always_private": True }, "pii_salt": "super-secret-salt", "reqid": 1, } # check creation of session session_token1 = actions.auth_session_new( session_payload, override_authdb_path="sqlite:///test-login.authdb.sqlite", ) assert session_token1["success"] is True assert session_token1["session_token"] is not None # try logging in now with correct password login = actions.auth_user_login( { "session_token": session_token1["session_token"], "email": user_payload["email"], "password": user_payload["password"], "pii_salt": "super-secret-salt", "reqid": 1, }, override_authdb_path="sqlite:///test-login.authdb.sqlite", ) # this should fail because we haven't verified our email yet assert login["success"] is False # verify our email emailverify = actions.set_user_emailaddr_verified( { "email": user_payload["email"], "user_id": user_created["user_id"], "pii_salt": "super-secret-salt", "reqid": 1, }, override_authdb_path="sqlite:///test-login.authdb.sqlite", ) assert emailverify["success"] is True assert emailverify["user_id"] == user_created["user_id"] assert emailverify["is_active"] is True assert emailverify["user_role"] == "authenticated" # now make a new session token session_payload = { "user_id": emailverify["user_id"], "user_agent": "Mozzarella Killerwhale", "expires": datetime.utcnow() + timedelta(hours=1), "ip_address": "1.1.1.1", "extra_info_json": { "pref_datasets_always_private": True }, "pii_salt": "super-secret-salt", "reqid": 1, } # check creation of session session_token2 = actions.auth_session_new( session_payload, override_authdb_path="sqlite:///test-login.authdb.sqlite", ) assert session_token2["success"] is True assert session_token2["session_token"] is not None # and now try to log in again login = actions.auth_user_login( { "session_token": session_token2["session_token"], "email": user_payload["email"], "password": user_payload["password"], "pii_salt": "super-secret-salt", "reqid": 1, }, override_authdb_path="sqlite:///test-login.authdb.sqlite", ) assert login["success"] is True # try logging in now with the wrong password login = actions.auth_user_login( { "session_token": session_token2["session_token"], "email": user_payload["email"], "password": "******", "pii_salt": "super-secret-salt", "reqid": 1, }, override_authdb_path="sqlite:///test-login.authdb.sqlite", ) assert login["success"] is False # tests for no session token provided login = actions.auth_user_login( { "session_token": "correcthorsebatterystaple", "email": user_payload["email"], "password": user_payload["password"], "pii_salt": "super-secret-salt", "reqid": 1, }, override_authdb_path="sqlite:///test-login.authdb.sqlite", ) assert login["success"] is False try: os.remove("test-login.authdb.sqlite") except Exception: pass try: os.remove("test-login.authdb.sqlite-shm") except Exception: pass try: os.remove("test-login.authdb.sqlite-wal") except Exception: pass
def test_login_logout(): """ See if we can login and log out correctly. """ try: os.remove("test-loginlogout.authdb.sqlite") except Exception: pass try: os.remove("test-loginlogout.authdb.sqlite-shm") except Exception: pass try: os.remove("test-loginlogout.authdb.sqlite-wal") except Exception: pass get_test_authdb() get_public_suffix_list() # create the user user_payload = { "full_name": "Test User", "email": "*****@*****.**", "password": "******", "pii_salt": "super-secret-salt", "reqid": 1, } user_created = actions.create_new_user( user_payload, override_authdb_path="sqlite:///test-loginlogout.authdb.sqlite", ) assert user_created["success"] is True assert user_created["user_email"] == "*****@*****.**" assert ( "User account created. Please verify your email address to log in." in user_created["messages"] ) # create a new session token session_payload = { "user_id": 2, "user_agent": "Mozzarella Killerwhale", "expires": datetime.utcnow() + timedelta(hours=1), "ip_address": "1.1.1.1", "extra_info_json": {"pref_datasets_always_private": True}, "pii_salt": "super-secret-salt", "reqid": 1, } # check creation of session session_token1 = actions.auth_session_new( session_payload, override_authdb_path="sqlite:///test-loginlogout.authdb.sqlite", raiseonfail=True, ) assert session_token1["success"] is True assert session_token1["session_token"] is not None # try logging in now with correct password login = actions.auth_user_login( { "session_token": session_token1["session_token"], "email": user_payload["email"], "password": user_payload["password"], "pii_salt": "super-secret-salt", "reqid": 1, }, override_authdb_path="sqlite:///test-loginlogout.authdb.sqlite", raiseonfail=True, ) # this should fail because we haven't verified our email yet assert login["success"] is False # verify our email emailverify = actions.set_user_emailaddr_verified( { "email": user_payload["email"], "user_id": user_created["user_id"], "pii_salt": "super-secret-salt", "reqid": 1, }, override_authdb_path="sqlite:///test-loginlogout.authdb.sqlite", raiseonfail=True, ) assert emailverify["success"] is True assert emailverify["user_id"] == user_created["user_id"] assert emailverify["is_active"] is True assert emailverify["user_role"] == "authenticated" # now make a new session token session_payload = { "user_id": 2, "user_agent": "Mozzarella Killerwhale", "expires": datetime.utcnow() + timedelta(hours=1), "ip_address": "1.1.1.1", "extra_info_json": {"pref_datasets_always_private": True}, "pii_salt": "super-secret-salt", "reqid": 1, } # check creation of session session_token2 = actions.auth_session_new( session_payload, override_authdb_path="sqlite:///test-loginlogout.authdb.sqlite", raiseonfail=True, ) assert session_token2["success"] is True assert session_token2["session_token"] is not None # and now try to log in again login = actions.auth_user_login( { "session_token": session_token2["session_token"], "email": user_payload["email"], "password": user_payload["password"], "pii_salt": "super-secret-salt", "reqid": 1, }, override_authdb_path="sqlite:///test-loginlogout.authdb.sqlite", raiseonfail=True, ) assert login["success"] is True # make sure the session token we used to log in is gone # check if our session was deleted correctly session_still_exists = actions.auth_session_exists( { "session_token": session_token2["session_token"], "pii_salt": "super-secret-salt", "reqid": 1, }, override_authdb_path="sqlite:///test-loginlogout.authdb.sqlite", ) assert session_still_exists["success"] is False # start a new session with this user's user ID authenticated_session_token = actions.auth_session_new( { "user_id": login["user_id"], "user_agent": "Mozzarella Killerwhale", "expires": datetime.utcnow() + timedelta(hours=1), "ip_address": "1.1.1.1", "extra_info_json": {"pref_datasets_always_private": True}, "pii_salt": "super-secret-salt", "reqid": 1, }, override_authdb_path="sqlite:///test-loginlogout.authdb.sqlite", raiseonfail=True, ) # now see if we can log out logged_out = actions.auth_user_logout( { "session_token": authenticated_session_token["session_token"], "user_id": login["user_id"], "pii_salt": "super-secret-salt", "reqid": 1, }, override_authdb_path="sqlite:///test-loginlogout.authdb.sqlite", raiseonfail=True, ) assert logged_out["success"] is True # check if our session was deleted correctly session_still_exists = actions.auth_session_exists( { "session_token": authenticated_session_token, "pii_salt": "super-secret-salt", "reqid": 1, }, override_authdb_path="sqlite:///test-loginlogout.authdb.sqlite", raiseonfail=True, ) assert session_still_exists["success"] is False try: os.remove("test-loginlogout.authdb.sqlite") except Exception: pass try: os.remove("test-loginlogout.authdb.sqlite-shm") except Exception: pass try: os.remove("test-loginlogout.authdb.sqlite-wal") except Exception: pass
def test_sessions(): ''' This tests session token generation, readback, deletion, and expiry. ''' try: os.remove('test-creation.authdb.sqlite') except Exception: pass try: os.remove('test-creation.authdb.sqlite-shm') except Exception: pass try: os.remove('test-creation.authdb.sqlite-wal') except Exception: pass get_test_authdb() # session token payload session_payload = { 'user_id': 2, 'user_agent': 'Mozzarella Killerwhale', 'expires': datetime.utcnow() + timedelta(hours=1), 'ip_address': '1.2.3.4', 'extra_info_json': { 'pref_datasets_always_private': True } } # check creation session_token1 = actions.auth_session_new( session_payload, override_authdb_path='sqlite:///test-creation.authdb.sqlite') assert session_token1['success'] is True assert session_token1['session_token'] is not None # check deletion deleted = actions.auth_session_delete( {'session_token': session_token1['session_token']}, override_authdb_path='sqlite:///test-creation.authdb.sqlite') assert deleted['success'] is True # check readback of deleted check = actions.auth_session_exists( {'session_token': session_token1['session_token']}, override_authdb_path='sqlite:///test-creation.authdb.sqlite') assert check['success'] is False # new session token payload session_payload = { 'user_id': 2, 'user_agent': 'Mozzarella Killerwhale', 'expires': datetime.utcnow() + timedelta(hours=1), 'ip_address': '1.2.3.4', 'extra_info_json': { 'pref_datasets_always_private': True } } # check creation session_token2 = actions.auth_session_new( session_payload, override_authdb_path='sqlite:///test-creation.authdb.sqlite') assert session_token2['success'] is True assert session_token2['session_token'] is not None assert session_token1['session_token'] != session_token2['session_token'] # get items for session_token check = actions.auth_session_exists( {'session_token': session_token2['session_token']}, override_authdb_path='sqlite:///test-creation.authdb.sqlite') assert check['success'] is True for key in ('user_id', 'full_name', 'email', 'email_verified', 'emailverify_sent_datetime', 'is_active', 'last_login_try', 'last_login_success', 'created_on', 'user_role', 'session_token', 'ip_address', 'user_agent', 'created', 'expires', 'extra_info_json'): assert key in check['session_info'] assert check['session_info']['user_id'] == 2 assert check['session_info'][ 'full_name'] == 'The systemwide anonymous user' assert check['session_info']['email'] == 'anonuser@localhost' assert check['session_info']['email_verified'] is True assert check['session_info']['is_active'] is True assert check['session_info']['last_login_try'] is None assert check['session_info']['last_login_success'] is None assert check['session_info']['user_role'] == 'anonymous' assert check['session_info']['session_token'] == session_token2[ 'session_token'] assert check['session_info']['ip_address'] == session_payload['ip_address'] assert check['session_info']['user_agent'] == session_payload['user_agent'] assert check['session_info']['expires'] == session_payload['expires'] assert check['session_info']['extra_info_json'] == session_payload[ 'extra_info_json'] # new session token payload session_payload = { 'user_id': 2, 'user_agent': 'Mozzarella Killerwhale', 'expires': datetime.utcnow() + timedelta(seconds=5), 'ip_address': '1.2.3.4', 'extra_info_json': { 'pref_datasets_always_private': True } } # check creation session_token3 = actions.auth_session_new( session_payload, override_authdb_path='sqlite:///test-creation.authdb.sqlite') assert session_token3['success'] is True assert session_token3['session_token'] is not None assert session_token3['session_token'] != session_token2['session_token'] # check readback when expired time.sleep(10.0) check = actions.auth_session_exists( {'session_token': session_token3['session_token']}, override_authdb_path='sqlite:///test-creation.authdb.sqlite') assert check['success'] is False try: os.remove('test-creation.authdb.sqlite') except Exception: pass try: os.remove('test-creation.authdb.sqlite-shm') except Exception: pass try: os.remove('test-creation.authdb.sqlite-wal') except Exception: pass
def test_login_timing(): """This tests obfuscating the presence/absence of users based on password checks. This may fail randomly if the testing service is under load. """ try: os.remove("test-timing.authdb.sqlite") except Exception: pass try: os.remove("test-timing.authdb.sqlite-shm") except Exception: pass try: os.remove("test-timing.authdb.sqlite-wal") except Exception: pass get_test_authdb() get_public_suffix_list() # create the user user_payload = { "full_name": "Test User", "email": "*****@*****.**", "password": "******", "pii_salt": "super-secret-salt", "reqid": 1, } user_created = actions.create_new_user( user_payload, override_authdb_path="sqlite:///test-timing.authdb.sqlite", ) assert user_created["success"] is True assert user_created["user_email"] == "*****@*****.**" assert ("User account created. Please verify your email address to log in." in user_created["messages"]) # create a new session token session_payload = { "user_id": 2, "user_agent": "Mozzarella Killerwhale", "expires": datetime.utcnow() + timedelta(hours=1), "ip_address": "1.1.1.1", "extra_info_json": { "pref_datasets_always_private": True }, "pii_salt": "super-secret-salt", "reqid": 1, } # check creation of session session_token1 = actions.auth_session_new( session_payload, override_authdb_path="sqlite:///test-timing.authdb.sqlite", ) assert session_token1["success"] is True assert session_token1["session_token"] is not None # try logging in now with correct password login = actions.auth_user_login( { "session_token": session_token1["session_token"], "email": user_payload["email"], "password": user_payload["password"], "pii_salt": "super-secret-salt", "reqid": 1, }, override_authdb_path="sqlite:///test-timing.authdb.sqlite", ) # this should fail because we haven't verified our email yet assert login["success"] is False # verify our email emailverify = actions.set_user_emailaddr_verified( { "email": user_payload["email"], "user_id": user_created["user_id"], "pii_salt": "super-secret-salt", "reqid": 1, }, override_authdb_path="sqlite:///test-timing.authdb.sqlite", ) assert emailverify["success"] is True assert emailverify["user_id"] == user_created["user_id"] assert emailverify["is_active"] is True assert emailverify["user_role"] == "authenticated" # now make a new session token session_payload = { "user_id": 2, "user_agent": "Mozzarella Killerwhale", "expires": datetime.utcnow() + timedelta(hours=1), "ip_address": "1.1.1.1", "extra_info_json": { "pref_datasets_always_private": True }, "pii_salt": "super-secret-salt", "reqid": 1, } # check creation of session session_token2 = actions.auth_session_new( session_payload, override_authdb_path="sqlite:///test-timing.authdb.sqlite", ) assert session_token2["success"] is True assert session_token2["session_token"] is not None # and now try to log in again login = actions.auth_user_login( { "session_token": session_token2["session_token"], "email": user_payload["email"], "password": user_payload["password"], "pii_salt": "super-secret-salt", "reqid": 1, }, override_authdb_path="sqlite:///test-timing.authdb.sqlite", ) assert login["success"] is True # basic tests for timing attacks # incorrect passwords incorrect_timings = [] for _ in range(500): # now make a new session token session_payload = { "user_id": 2, "user_agent": "Mozzarella Killerwhale", "expires": datetime.utcnow() + timedelta(hours=1), "ip_address": "1.1.1.1", "extra_info_json": { "pref_datasets_always_private": True }, "pii_salt": "super-secret-salt", "reqid": 1, } # check creation of session session_token2 = actions.auth_session_new( session_payload, override_authdb_path="sqlite:///test-timing.authdb.sqlite", ) start = time.time() actions.auth_user_login( { "session_token": session_token2["session_token"], "email": user_payload["email"], "password": secrets.token_urlsafe(16), "pii_salt": "super-secret-salt", "reqid": 1, }, override_authdb_path="sqlite:///test-timing.authdb.sqlite", ) end = time.time() incorrect_timings.append(end - start) # correct passwords correct_timings = [] for _ in range(500): # now make a new session token session_payload = { "user_id": 2, "user_agent": "Mozzarella Killerwhale", "expires": datetime.utcnow() + timedelta(hours=1), "ip_address": "1.1.1.1", "extra_info_json": { "pref_datasets_always_private": True }, "pii_salt": "super-secret-salt", "reqid": 1, } # check creation of session session_token2 = actions.auth_session_new( session_payload, override_authdb_path="sqlite:///test-timing.authdb.sqlite", ) start = time.time() actions.auth_user_login( { "session_token": session_token2["session_token"], "email": user_payload["email"], "password": user_payload["password"], "pii_salt": "super-secret-salt", "reqid": 1, }, override_authdb_path="sqlite:///test-timing.authdb.sqlite", ) end = time.time() correct_timings.append(end - start) # wronguser passwords wronguser_timings = [] for _ in range(500): # now make a new session token session_payload = { "user_id": 2, "user_agent": "Mozzarella Killerwhale", "expires": datetime.utcnow() + timedelta(hours=1), "ip_address": "1.1.1.1", "extra_info_json": { "pref_datasets_always_private": True }, "pii_salt": "super-secret-salt", "reqid": 1, } # check creation of session session_token2 = actions.auth_session_new( session_payload, override_authdb_path="sqlite:///test-timing.authdb.sqlite", ) start = time.time() actions.auth_user_login( { "session_token": session_token2["session_token"], "email": secrets.token_urlsafe(16), "password": secrets.token_urlsafe(16), "pii_salt": "super-secret-salt", "reqid": 1, }, override_authdb_path="sqlite:///test-timing.authdb.sqlite", ) end = time.time() wronguser_timings.append(end - start) # broken requests broken_timings = [] for _ in range(500): # now make a new session token session_payload = { "user_id": 2, "user_agent": "Mozzarella Killerwhale", "expires": datetime.utcnow() + timedelta(hours=1), "ip_address": "1.1.1.1", "extra_info_json": { "pref_datasets_always_private": True }, "pii_salt": "super-secret-salt", "reqid": 1, } # check creation of session session_token2 = actions.auth_session_new( session_payload, override_authdb_path="sqlite:///test-timing.authdb.sqlite", ) start = time.time() actions.auth_user_login( { "session_token": "correcthorsebatterystaple", "email": user_payload["email"], "password": user_payload["password"], "pii_salt": "super-secret-salt", "reqid": 1, }, override_authdb_path="sqlite:///test-timing.authdb.sqlite", ) end = time.time() broken_timings.append(end - start) correct_median = statistics.median(correct_timings) incorrect_median = statistics.median(incorrect_timings) broken_median = statistics.median(broken_timings) wronguser_median = statistics.median(wronguser_timings) # all timings should match within 10 milliseconds or so assert abs(correct_median - incorrect_median) < 0.01 assert abs(correct_median - broken_median) < 0.01 assert abs(correct_median - wronguser_median) < 0.01 try: os.remove("test-timing.authdb.sqlite") except Exception: pass try: os.remove("test-timing.authdb.sqlite-shm") except Exception: pass try: os.remove("test-timing.authdb.sqlite-wal") except Exception: pass
def test_login_logout(): ''' See if we can login and log out correctly. ''' try: os.remove('test-loginlogout.authdb.sqlite') except Exception as e: pass try: os.remove('test-loginlogout.authdb.sqlite-shm') except Exception as e: pass try: os.remove('test-loginlogout.authdb.sqlite-wal') except Exception as e: pass get_test_authdb() # create the user user_payload = { 'full_name': 'Test User', 'email': '*****@*****.**', 'password': '******' } user_created = actions.create_new_user( user_payload, override_authdb_path='sqlite:///test-loginlogout.authdb.sqlite') assert user_created['success'] is True assert user_created['user_email'] == '*****@*****.**' assert ('User account created. Please verify your email address to log in.' in user_created['messages']) # create a new session token session_payload = { 'user_id': 2, 'user_agent': 'Mozzarella Killerwhale', 'expires': datetime.utcnow() + timedelta(hours=1), 'ip_address': '1.1.1.1', 'extra_info_json': { 'pref_datasets_always_private': True } } # check creation of session session_token1 = actions.auth_session_new( session_payload, override_authdb_path='sqlite:///test-loginlogout.authdb.sqlite', raiseonfail=True) assert session_token1['success'] is True assert session_token1['session_token'] is not None # try logging in now with correct password login = actions.auth_user_login( { 'session_token': session_token1['session_token'], 'email': user_payload['email'], 'password': user_payload['password'] }, override_authdb_path='sqlite:///test-loginlogout.authdb.sqlite', raiseonfail=True) # this should fail because we haven't verified our email yet assert login['success'] is False # verify our email emailverify = (actions.verify_user_email_address( { 'email': user_payload['email'], 'user_id': user_created['user_id'] }, override_authdb_path='sqlite:///test-loginlogout.authdb.sqlite', raiseonfail=True)) assert emailverify['success'] is True assert emailverify['user_id'] == user_created['user_id'] assert emailverify['is_active'] is True assert emailverify['user_role'] == 'authenticated' # now make a new session token session_payload = { 'user_id': 2, 'user_agent': 'Mozzarella Killerwhale', 'expires': datetime.utcnow() + timedelta(hours=1), 'ip_address': '1.1.1.1', 'extra_info_json': { 'pref_datasets_always_private': True } } # check creation of session session_token2 = actions.auth_session_new( session_payload, override_authdb_path='sqlite:///test-loginlogout.authdb.sqlite', raiseonfail=True) assert session_token2['success'] is True assert session_token2['session_token'] is not None # and now try to log in again login = actions.auth_user_login( { 'session_token': session_token2['session_token'], 'email': user_payload['email'], 'password': user_payload['password'] }, override_authdb_path='sqlite:///test-loginlogout.authdb.sqlite', raiseonfail=True) assert login['success'] is True # make sure the session token we used to log in is gone # check if our session was deleted correctly session_still_exists = actions.auth_session_exists( {'session_token': session_token2['session_token']}, override_authdb_path='sqlite:///test-loginlogout.authdb.sqlite') assert session_still_exists['success'] is False # start a new session with this user's user ID authenticated_session_token = actions.auth_session_new( { 'user_id': login['user_id'], 'user_agent': 'Mozzarella Killerwhale', 'expires': datetime.utcnow() + timedelta(hours=1), 'ip_address': '1.1.1.1', 'extra_info_json': { 'pref_datasets_always_private': True } }, override_authdb_path='sqlite:///test-loginlogout.authdb.sqlite', raiseonfail=True) # now see if we can log out logged_out = actions.auth_user_logout( { 'session_token': authenticated_session_token['session_token'], 'user_id': login['user_id'] }, override_authdb_path='sqlite:///test-loginlogout.authdb.sqlite', raiseonfail=True) assert logged_out['success'] is True # check if our session was deleted correctly session_still_exists = actions.auth_session_exists( {'session_token': authenticated_session_token}, override_authdb_path='sqlite:///test-loginlogout.authdb.sqlite', raiseonfail=True) assert session_still_exists['success'] is False try: os.remove('test-loginlogout.authdb.sqlite') except Exception as e: pass try: os.remove('test-loginlogout.authdb.sqlite-shm') except Exception as e: pass try: os.remove('test-loginlogout.authdb.sqlite-wal') except Exception as e: pass
def test_sessions(): """ This tests session token generation, readback, deletion, and expiry. """ try: os.remove("test-creation.authdb.sqlite") except Exception: pass try: os.remove("test-creation.authdb.sqlite-shm") except Exception: pass try: os.remove("test-creation.authdb.sqlite-wal") except Exception: pass get_test_authdb() # session token payload session_payload = { "user_id": 2, "user_agent": "Mozzarella Killerwhale", "expires": datetime.utcnow() + timedelta(hours=1), "ip_address": "1.2.3.4", "extra_info_json": { "pref_datasets_always_private": True }, "reqid": 1, "pii_salt": "super-random-salt", } # check creation session_token1 = actions.auth_session_new( session_payload, override_authdb_path="sqlite:///test-creation.authdb.sqlite", ) assert session_token1["success"] is True assert session_token1["session_token"] is not None # check deletion deleted = actions.auth_session_delete( { "session_token": session_token1["session_token"], "reqid": 1, "pii_salt": "super-random-salt", }, override_authdb_path="sqlite:///test-creation.authdb.sqlite", ) assert deleted["success"] is True # check readback of deleted check = actions.auth_session_exists( { "session_token": session_token1["session_token"], "reqid": 1, "pii_salt": "super-random-salt", }, override_authdb_path="sqlite:///test-creation.authdb.sqlite", ) assert check["success"] is False # new session token payload session_payload = { "user_id": 2, "user_agent": "Mozzarella Killerwhale", "expires": datetime.utcnow() + timedelta(hours=1), "ip_address": "1.2.3.4", "extra_info_json": { "pref_datasets_always_private": True }, "reqid": 1, "pii_salt": "super-random-salt", } # check creation session_token2 = actions.auth_session_new( session_payload, override_authdb_path="sqlite:///test-creation.authdb.sqlite", ) assert session_token2["success"] is True assert session_token2["session_token"] is not None assert session_token1["session_token"] != session_token2["session_token"] # get items for session_token check = actions.auth_session_exists( { "session_token": session_token2["session_token"], "reqid": 1, "pii_salt": "super-random-salt", }, override_authdb_path="sqlite:///test-creation.authdb.sqlite", ) assert check["success"] is True for key in ( "user_id", "full_name", "email", "email_verified", "emailverify_sent_datetime", "is_active", "last_login_try", "last_login_success", "created_on", "user_role", "session_token", "ip_address", "user_agent", "created", "expires", "extra_info_json", ): assert key in check["session_info"] assert check["session_info"]["user_id"] == 2 assert ( check["session_info"]["full_name"] == "The systemwide anonymous user") assert check["session_info"]["email"] == "anonuser@localhost" assert check["session_info"]["email_verified"] is True assert check["session_info"]["is_active"] is True assert check["session_info"]["last_login_try"] is None assert check["session_info"]["last_login_success"] is None assert check["session_info"]["user_role"] == "anonymous" assert (check["session_info"]["session_token"] == session_token2["session_token"]) assert check["session_info"]["ip_address"] == session_payload["ip_address"] assert check["session_info"]["user_agent"] == session_payload["user_agent"] assert check["session_info"]["expires"] == session_payload["expires"] assert (check["session_info"]["extra_info_json"] == session_payload["extra_info_json"]) # new session token payload session_payload = { "user_id": 2, "user_agent": "Mozzarella Killerwhale", "expires": datetime.utcnow() + timedelta(seconds=5), "ip_address": "1.2.3.4", "extra_info_json": { "pref_datasets_always_private": True }, "reqid": 1, "pii_salt": "super-random-salt", } # check creation session_token3 = actions.auth_session_new( session_payload, override_authdb_path="sqlite:///test-creation.authdb.sqlite", ) assert session_token3["success"] is True assert session_token3["session_token"] is not None assert session_token3["session_token"] != session_token2["session_token"] # check readback when expired time.sleep(10.0) check = actions.auth_session_exists( { "session_token": session_token3["session_token"], "reqid": 1, "pii_salt": "super-random-salt", }, override_authdb_path="sqlite:///test-creation.authdb.sqlite", ) assert check["success"] is False try: os.remove("test-creation.authdb.sqlite") except Exception: pass try: os.remove("test-creation.authdb.sqlite-shm") except Exception: pass try: os.remove("test-creation.authdb.sqlite-wal") except Exception: pass
def test_login_timing(): '''This tests obfuscating the presence/absence of users based on password checks. This may fail randomly if the testing service is under load. ''' try: os.remove('test-timing.authdb.sqlite') except Exception as e: pass try: os.remove('test-timing.authdb.sqlite-shm') except Exception as e: pass try: os.remove('test-timing.authdb.sqlite-wal') except Exception as e: pass get_test_authdb() # create the user user_payload = { 'full_name': 'Test User', 'email': '*****@*****.**', 'password': '******' } user_created = actions.create_new_user( user_payload, override_authdb_path='sqlite:///test-timing.authdb.sqlite') assert user_created['success'] is True assert user_created['user_email'] == '*****@*****.**' assert ('User account created. Please verify your email address to log in.' in user_created['messages']) # create a new session token session_payload = { 'user_id': 2, 'user_agent': 'Mozzarella Killerwhale', 'expires': datetime.utcnow() + timedelta(hours=1), 'ip_address': '1.1.1.1', 'extra_info_json': { 'pref_datasets_always_private': True } } # check creation of session session_token1 = actions.auth_session_new( session_payload, override_authdb_path='sqlite:///test-timing.authdb.sqlite') assert session_token1['success'] is True assert session_token1['session_token'] is not None # try logging in now with correct password login = actions.auth_user_login( { 'session_token': session_token1['session_token'], 'email': user_payload['email'], 'password': user_payload['password'] }, override_authdb_path='sqlite:///test-timing.authdb.sqlite') # this should fail because we haven't verified our email yet assert login['success'] is False # verify our email emailverify = (actions.verify_user_email_address( { 'email': user_payload['email'], 'user_id': user_created['user_id'] }, override_authdb_path='sqlite:///test-timing.authdb.sqlite')) assert emailverify['success'] is True assert emailverify['user_id'] == user_created['user_id'] assert emailverify['is_active'] is True assert emailverify['user_role'] == 'authenticated' # now make a new session token session_payload = { 'user_id': 2, 'user_agent': 'Mozzarella Killerwhale', 'expires': datetime.utcnow() + timedelta(hours=1), 'ip_address': '1.1.1.1', 'extra_info_json': { 'pref_datasets_always_private': True } } # check creation of session session_token2 = actions.auth_session_new( session_payload, override_authdb_path='sqlite:///test-timing.authdb.sqlite') assert session_token2['success'] is True assert session_token2['session_token'] is not None # and now try to log in again login = actions.auth_user_login( { 'session_token': session_token2['session_token'], 'email': user_payload['email'], 'password': user_payload['password'] }, override_authdb_path='sqlite:///test-timing.authdb.sqlite') assert login['success'] is True # basic tests for timing attacks # incorrect passwords incorrect_timings = [] for _ in range(1000): # now make a new session token session_payload = { 'user_id': 2, 'user_agent': 'Mozzarella Killerwhale', 'expires': datetime.utcnow() + timedelta(hours=1), 'ip_address': '1.1.1.1', 'extra_info_json': { 'pref_datasets_always_private': True } } # check creation of session session_token2 = actions.auth_session_new( session_payload, override_authdb_path='sqlite:///test-timing.authdb.sqlite') start = time.time() actions.auth_user_login( { 'session_token': session_token2['session_token'], 'email': user_payload['email'], 'password': secrets.token_urlsafe(16) }, override_authdb_path='sqlite:///test-timing.authdb.sqlite') end = time.time() incorrect_timings.append(end - start) # correct passwords correct_timings = [] for _ in range(1000): # now make a new session token session_payload = { 'user_id': 2, 'user_agent': 'Mozzarella Killerwhale', 'expires': datetime.utcnow() + timedelta(hours=1), 'ip_address': '1.1.1.1', 'extra_info_json': { 'pref_datasets_always_private': True } } # check creation of session session_token2 = actions.auth_session_new( session_payload, override_authdb_path='sqlite:///test-timing.authdb.sqlite') start = time.time() actions.auth_user_login( { 'session_token': session_token2['session_token'], 'email': user_payload['email'], 'password': user_payload['password'] }, override_authdb_path='sqlite:///test-timing.authdb.sqlite') end = time.time() correct_timings.append(end - start) # wronguser passwords wronguser_timings = [] for _ in range(1000): # now make a new session token session_payload = { 'user_id': 2, 'user_agent': 'Mozzarella Killerwhale', 'expires': datetime.utcnow() + timedelta(hours=1), 'ip_address': '1.1.1.1', 'extra_info_json': { 'pref_datasets_always_private': True } } # check creation of session session_token2 = actions.auth_session_new( session_payload, override_authdb_path='sqlite:///test-timing.authdb.sqlite') start = time.time() actions.auth_user_login( { 'session_token': session_token2['session_token'], 'email': secrets.token_urlsafe(16), 'password': secrets.token_urlsafe(16) }, override_authdb_path='sqlite:///test-timing.authdb.sqlite') end = time.time() wronguser_timings.append(end - start) # broken requests broken_timings = [] for _ in range(1000): # now make a new session token session_payload = { 'user_id': 2, 'user_agent': 'Mozzarella Killerwhale', 'expires': datetime.utcnow() + timedelta(hours=1), 'ip_address': '1.1.1.1', 'extra_info_json': { 'pref_datasets_always_private': True } } # check creation of session session_token2 = actions.auth_session_new( session_payload, override_authdb_path='sqlite:///test-timing.authdb.sqlite') start = time.time() actions.auth_user_login( { 'session_token': 'correcthorsebatterystaple', 'email': user_payload['email'], 'password': user_payload['password'] }, override_authdb_path='sqlite:///test-timing.authdb.sqlite') end = time.time() broken_timings.append(end - start) correct_timings = np.array(correct_timings) incorrect_timings = np.array(incorrect_timings) broken_timings = np.array(broken_timings) wronguser_timings = np.array(wronguser_timings) correct_median = np.median(correct_timings) incorrect_median = np.median(incorrect_timings) broken_median = np.median(broken_timings) wronguser_median = np.median(wronguser_timings) # all timings should match within 7 milliseconds or so assert_allclose(correct_median, incorrect_median, atol=7.0e-3) assert_allclose(correct_median, broken_median, atol=7.0e-3) assert_allclose(correct_median, wronguser_median, atol=7.0e-3) try: os.remove('test-timing.authdb.sqlite') except Exception as e: pass try: os.remove('test-timing.authdb.sqlite-shm') except Exception as e: pass try: os.remove('test-timing.authdb.sqlite-wal') except Exception as e: pass
def test_login(): ''' This tests if we can log in successfully or fail correctly. ''' try: os.remove('test-login.authdb.sqlite') except Exception as e: pass try: os.remove('test-login.authdb.sqlite-shm') except Exception as e: pass try: os.remove('test-login.authdb.sqlite-wal') except Exception as e: pass get_test_authdb() # create the user user_payload = { 'full_name': 'Test User', 'email': '*****@*****.**', 'password': '******' } user_created = actions.create_new_user( user_payload, override_authdb_path='sqlite:///test-login.authdb.sqlite') assert user_created['success'] is True assert user_created['user_email'] == '*****@*****.**' assert ('User account created. Please verify your email address to log in.' in user_created['messages']) # create a new session token session_payload = { 'user_id': 2, 'user_agent': 'Mozzarella Killerwhale', 'expires': datetime.utcnow() + timedelta(hours=1), 'ip_address': '1.1.1.1', 'extra_info_json': { 'pref_datasets_always_private': True } } # check creation of session session_token1 = actions.auth_session_new( session_payload, override_authdb_path='sqlite:///test-login.authdb.sqlite') assert session_token1['success'] is True assert session_token1['session_token'] is not None # try logging in now with correct password login = actions.auth_user_login( { 'session_token': session_token1['session_token'], 'email': user_payload['email'], 'password': user_payload['password'] }, override_authdb_path='sqlite:///test-login.authdb.sqlite') # this should fail because we haven't verified our email yet assert login['success'] is False # verify our email emailverify = (actions.verify_user_email_address( { 'email': user_payload['email'], 'user_id': user_created['user_id'] }, override_authdb_path='sqlite:///test-login.authdb.sqlite')) assert emailverify['success'] is True assert emailverify['user_id'] == user_created['user_id'] assert emailverify['is_active'] is True assert emailverify['user_role'] == 'authenticated' # now make a new session token session_payload = { 'user_id': emailverify['user_id'], 'user_agent': 'Mozzarella Killerwhale', 'expires': datetime.utcnow() + timedelta(hours=1), 'ip_address': '1.1.1.1', 'extra_info_json': { 'pref_datasets_always_private': True } } # check creation of session session_token2 = actions.auth_session_new( session_payload, override_authdb_path='sqlite:///test-login.authdb.sqlite') assert session_token2['success'] is True assert session_token2['session_token'] is not None # and now try to log in again login = actions.auth_user_login( { 'session_token': session_token2['session_token'], 'email': user_payload['email'], 'password': user_payload['password'] }, override_authdb_path='sqlite:///test-login.authdb.sqlite') assert login['success'] is True # try logging in now with the wrong password login = actions.auth_user_login( { 'session_token': session_token2['session_token'], 'email': user_payload['email'], 'password': '******' }, override_authdb_path='sqlite:///test-login.authdb.sqlite') assert login['success'] is False # tests for no session token provided login = actions.auth_user_login( { 'session_token': 'correcthorsebatterystaple', 'email': user_payload['email'], 'password': user_payload['password'] }, override_authdb_path='sqlite:///test-login.authdb.sqlite') assert login['success'] is False try: os.remove('test-login.authdb.sqlite') except Exception as e: pass try: os.remove('test-login.authdb.sqlite-shm') except Exception as e: pass try: os.remove('test-login.authdb.sqlite-wal') except Exception as e: pass
def test_create_user_with_email(tmpdir): """ This creates a user and tries to send a verification code to their email. """ test_authdb_url = get_test_authdb(tmpdir) get_public_suffix_list() # 0. start the email server email_server, maildir = generate_email_server(tmpdir) email_server.start() time.sleep(3.0) # 1a. create a new session session_payload = { "user_id": 2, "user_agent": "Mozzarella Killerwhale", "expires": datetime.utcnow() + timedelta(hours=1), "ip_address": "1.1.1.1", "extra_info_json": {"pref_datasets_always_private": True}, "pii_salt": "super-secret-salt", "reqid": 1, } session_token_info = actions.auth_session_new( session_payload, raiseonfail=True, override_authdb_path=test_authdb_url ) # 1b. create a new user payload = { "full_name": "Test User", "email": "*****@*****.**", "password": "******", "reqid": 1, "pii_salt": "super-secret-salt", } user_created = actions.create_new_user( payload, raiseonfail=True, override_authdb_path=test_authdb_url ) assert user_created["success"] is True assert user_created["user_email"] == "*****@*****.**" assert user_created["user_id"] == 4 assert user_created["send_verification"] is True assert ( "User account created. Please verify your email address to log in." in user_created["messages"] ) token_key = Fernet.generate_key() # 2. generate a verification token and send them an email verify_token = tokens.generate_email_token( session_payload["ip_address"], session_payload["user_agent"], "*****@*****.**", session_token_info["session_token"], token_key, ) # this uses the payload method of sending SMTP settings to the backend # function verification_email_info = actions.send_signup_verification_email( { "email_address": "*****@*****.**", "session_token": session_token_info["session_token"], "created_info": user_created, "server_name": "Authnzerver", "server_baseurl": "https://localhost/auth", "account_verify_url": "/users/verify", "verification_token": verify_token, "verification_expiry": 900, "emailuser": None, "emailpass": None, "emailserver": "localhost", "emailport": 9487, "emailsender": "Authnzerver <*****@*****.**>", "reqid": 1337, "pii_salt": "super-secret-salt", }, raiseonfail=True, override_authdb_path=test_authdb_url, ) assert verification_email_info["success"] is True assert verification_email_info["email_address"] == "*****@*****.**" # 3. check the mailbox to see if the email was received mailbox = Maildir(maildir) email_found = False for _, message in mailbox.items(): if "Please verify your account sign up request" in message["Subject"]: email_found = True assert message["From"] == "Authnzerver <*****@*****.**>" assert message["To"] == "*****@*****.**" assert ( "\n".join(textwrap.wrap(verify_token.decode())) in message.as_string() ) break assert email_found is True # now verify that the token from the email contains the same info we # provided received_token_base64 = re.findall( r"enter this code:([\S\n]+)into the account verification", message.as_string(), ) received_token_base64 = received_token_base64[0] received_token_base64 = received_token_base64.replace("\n", "") received_token_valid = tokens.verify_email_token( received_token_base64, session_payload["ip_address"], session_payload["user_agent"], session_token_info["session_token"], "*****@*****.**", token_key, match_returned_items=("ipa", "usa", "stk", "ema"), ) assert received_token_valid is True # 4. set the user's email address as verified email_verified_info = actions.set_user_emailaddr_verified( { "email": "*****@*****.**", "reqid": 123, "pii_salt": "super-secret-salt", }, raiseonfail=True, override_authdb_path=test_authdb_url, ) assert email_verified_info["success"] is True assert email_verified_info["user_id"] == 4 assert email_verified_info["is_active"] is True assert email_verified_info["user_role"] == "authenticated" # 5. send a password forgot email to the user # 5a. create a new session for the user first session_payload = { "user_id": 4, "user_agent": "Mozzarella Killerwhale", "expires": datetime.utcnow() + timedelta(hours=1), "ip_address": "1.1.1.1", "extra_info_json": {"pref_datasets_always_private": True}, "pii_salt": "super-secret-salt", "reqid": 1, } session_token_info = actions.auth_session_new( session_payload, raiseonfail=True, override_authdb_path=test_authdb_url ) # 5b. now send a forgot-password email forgotpass_token = tokens.generate_email_token( session_payload["ip_address"], session_payload["user_agent"], "*****@*****.**", session_token_info["session_token"], token_key, ) # this uses the config object method of sending SMTP settings to the backend # function config_obj = SimpleNamespace() config_obj.emailuser = None config_obj.emailpass = None config_obj.emailserver = "localhost" config_obj.emailport = 9487 config_obj.emailsender = "Authnzerver <*****@*****.**>" forgotpass_email_info = actions.send_forgotpass_verification_email( { "email_address": "*****@*****.**", "session_token": session_token_info["session_token"], "server_name": "Authnzerver", "server_baseurl": "https://localhost/auth", "password_forgot_url": "/password/reset-step1", "verification_token": forgotpass_token, "verification_expiry": 900, "reqid": 1337, "pii_salt": "super-secret-salt", }, raiseonfail=True, override_authdb_path=test_authdb_url, config=config_obj, ) assert forgotpass_email_info["success"] is True assert forgotpass_email_info["email_address"] == "*****@*****.**" # 6. check the mailbox to see if the forgot password email was received mailbox = Maildir(maildir) email_found = False for _, message in mailbox.items(): if "Please verify your password reset request" in message["Subject"]: email_found = True assert message["From"] == "Authnzerver <*****@*****.**>" assert message["To"] == "*****@*****.**" assert ( "\n".join(textwrap.wrap(forgotpass_token.decode())) in message.as_string() ) break assert email_found is True # now verify that the token from the email contains the same info we # provided received_token_base64 = re.findall( r"enter this code:([\S\n]+)into the password reset", message.as_string(), ) received_token_base64 = received_token_base64[0] received_token_base64 = received_token_base64.replace("\n", "") received_token_valid = tokens.verify_email_token( received_token_base64, session_payload["ip_address"], session_payload["user_agent"], session_token_info["session_token"], "*****@*****.**", token_key, match_returned_items=("ipa", "usa", "stk", "ema"), ) assert received_token_valid is True # # clean up # email_server.stop()