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
Exemplo n.º 2
0
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
Exemplo n.º 3
0
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
Exemplo n.º 4
0
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
Exemplo n.º 5
0
def test_create_user():
    '''
    This runs through various iterations of creating a user.

    '''
    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()

    # 1. dumb password
    payload = {
        'full_name': 'Test User',
        'email': '*****@*****.**',
        'password': '******'
    }
    user_created = actions.create_new_user(
        payload, override_authdb_path='sqlite:///test-creation.authdb.sqlite')
    assert user_created['success'] is False
    assert user_created['user_email'] == '*****@*****.**'
    assert user_created['user_id'] is None
    assert user_created['send_verification'] is False
    assert ('Your password is too short. It must have at least 12 characters.'
            in user_created['messages'])
    assert ('Your password is too similar to either '
            'the domain name of this server or your '
            'own name or email address.' in user_created['messages'])
    assert ('Your password is not complex enough. '
            'One or more characters appear appear too frequently.'
            in user_created['messages'])
    assert ('Your password is on the list of the most common '
            'passwords and is vulnerable to guessing.'
            in user_created['messages'])

    # 2. all numeric password
    payload = {
        'full_name': 'Test User',
        'email': '*****@*****.**',
        'password': '******'
    }
    user_created = actions.create_new_user(
        payload, override_authdb_path='sqlite:///test-creation.authdb.sqlite')
    assert user_created['success'] is False
    assert user_created['user_email'] == '*****@*****.**'
    assert user_created['user_id'] is None
    assert user_created['send_verification'] is False
    assert ('Your password cannot be all numbers.' in user_created['messages'])

    # 3a. password ~= email address
    payload = {
        'full_name': 'Test User',
        'email': '*****@*****.**',
        'password': '******'
    }
    user_created = actions.create_new_user(
        payload, override_authdb_path='sqlite:///test-creation.authdb.sqlite')
    assert user_created['success'] is False
    assert user_created['user_email'] == '*****@*****.**'
    assert user_created['user_id'] is None
    assert user_created['send_verification'] is False
    assert ('Your password is not complex enough. '
            'One or more characters appear appear too frequently.'
            in user_created['messages'])
    assert ('Your password is too similar to either '
            'the domain name of this server or your '
            'own name or email address.' in user_created['messages'])

    # 3b. password ~= full name
    payload = {
        'full_name': 'Test User',
        'email': '*****@*****.**',
        'password': '******'
    }
    user_created = actions.create_new_user(
        payload, override_authdb_path='sqlite:///test-creation.authdb.sqlite')
    assert user_created['success'] is False
    assert user_created['user_email'] == '*****@*****.**'
    assert user_created['user_id'] is None
    assert user_created['send_verification'] is False
    assert ('Your password is too similar to either '
            'the domain name of this server or your '
            'own name or email address.' in user_created['messages'])

    # 4. password is OK
    payload = {
        'full_name': 'Test User',
        'email': '*****@*****.**',
        'password': '******'
    }
    user_created = actions.create_new_user(
        payload, override_authdb_path='sqlite:///test-creation.authdb.sqlite')
    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'])

    # 5. try to create a new user with an existing email address
    payload = {
        'full_name': 'Test User',
        'email': '*****@*****.**',
        'password': '******'
    }
    user_created = actions.create_new_user(
        payload, override_authdb_path='sqlite:///test-creation.authdb.sqlite')
    assert user_created['success'] is False
    assert user_created['user_email'] == '*****@*****.**'
    assert user_created['user_id'] == 4

    # we should not send a verification email because the user already has an
    # account or if the account is not active yet, the last verification email
    # was sent less than 24 hours ago
    assert user_created['send_verification'] is False
    assert ('User account created. Please verify your email address to log in.'
            in user_created['messages'])

    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
Exemplo n.º 6
0
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
Exemplo n.º 7
0
def test_create_user():
    """
    This runs through various iterations of creating a user.

    """
    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()
    suff_list = get_public_suffix_list()

    # 0a. full name spam with no http://
    payload = {
        "full_name": "Test User bIt.Ly/hahaspam",
        "email": "*****@*****.**",
        "password": "******",
        "reqid": 1,
        "pii_salt": "super-random-salt",
        "public_suffix_list": suff_list,
    }
    user_created = actions.create_new_user(
        payload, override_authdb_path="sqlite:///test-creation.authdb.sqlite")
    assert user_created["success"] is False
    assert user_created["user_email"] is None
    assert user_created["user_id"] is None
    assert user_created["send_verification"] is False
    assert user_created["failure_reason"] == "invalid full name"

    # 0b. full name spam with http://
    payload = {
        "full_name": "Test User HttPs://BIT.lY/hahaspam",
        "email": "*****@*****.**",
        "password": "******",
        "reqid": 1,
        "pii_salt": "super-random-salt",
        "public_suffix_list": suff_list,
    }
    user_created = actions.create_new_user(
        payload, override_authdb_path="sqlite:///test-creation.authdb.sqlite")
    assert user_created["success"] is False
    assert user_created["user_email"] is None
    assert user_created["user_id"] is None
    assert user_created["send_verification"] is False
    assert user_created["failure_reason"] == "invalid full name"

    # 0c. full name spam with http:// and checking if currproc works OK
    payload = {
        "full_name": "Test User HttPs://BIT.lY/hahaspam",
        "email": "*****@*****.**",
        "password": "******",
        "reqid": 1,
        "pii_salt": "super-random-salt",
    }
    user_created = actions.create_new_user(
        payload, override_authdb_path="sqlite:///test-creation.authdb.sqlite")
    assert user_created["success"] is False
    assert user_created["user_email"] is None
    assert user_created["user_id"] is None
    assert user_created["send_verification"] is False
    assert user_created["failure_reason"] == "invalid full name"

    # 1. dumb password
    payload = {
        "full_name": "Test User",
        "email": "*****@*****.**",
        "password": "******",
        "reqid": 1,
        "pii_salt": "super-random-salt",
        "public_suffix_list": suff_list,
    }
    user_created = actions.create_new_user(
        payload, override_authdb_path="sqlite:///test-creation.authdb.sqlite")
    assert user_created["success"] is False
    assert user_created["user_email"] == "*****@*****.**"
    assert user_created["user_id"] is None
    assert user_created["send_verification"] is False
    assert ("Your password is too short. It must have at least 12 characters."
            in user_created["messages"])
    assert ("Your password is too similar to either "
            "the domain name of this server or your "
            "own name or email address." in user_created["messages"])
    assert ("Your password is on the list of the most common "
            "passwords and is vulnerable to guessing."
            in user_created["messages"])

    # 1a. 'clever'-dumb password
    payload = {
        "full_name": "Test User",
        "email": "*****@*****.**",
        "password": "******",
        "reqid": 1,
        "pii_salt": "super-random-salt",
    }
    user_created = actions.create_new_user(
        payload, override_authdb_path="sqlite:///test-creation.authdb.sqlite")
    assert user_created["success"] is False
    assert user_created["user_email"] == "*****@*****.**"
    assert user_created["user_id"] is None
    assert user_created["send_verification"] is False
    msg_found = False
    for msg in user_created["messages"]:
        if "recently compromised Web account passwords from" in msg:
            msg_found = True
            break
    assert msg_found, f"Pwned message not in {user_created['messages']}"

    # 2. all numeric password
    payload = {
        "full_name": "Test User",
        "email": "*****@*****.**",
        "password": "******",
        "reqid": 1,
        "pii_salt": "super-random-salt",
        "public_suffix_list": suff_list,
    }
    user_created = actions.create_new_user(
        payload, override_authdb_path="sqlite:///test-creation.authdb.sqlite")
    assert user_created["success"] is False
    assert user_created["user_email"] == "*****@*****.**"
    assert user_created["user_id"] is None
    assert user_created["send_verification"] is False
    assert "Your password cannot be all numbers." in user_created["messages"]

    # 3a. password ~= email address
    payload = {
        "full_name": "Test User",
        "email": "*****@*****.**",
        "password": "******",
        "reqid": 1,
        "pii_salt": "super-random-salt",
    }
    user_created = actions.create_new_user(
        payload, override_authdb_path="sqlite:///test-creation.authdb.sqlite")
    assert user_created["success"] is False
    assert user_created["user_email"] == "*****@*****.**"
    assert user_created["user_id"] is None
    assert user_created["send_verification"] is False
    assert ("Your password is too similar to either "
            "the domain name of this server or your "
            "own name or email address." in user_created["messages"])

    # 3b. password ~= full name
    payload = {
        "full_name": "Test User",
        "email": "*****@*****.**",
        "password": "******",
        "reqid": 1,
        "pii_salt": "super-random-salt",
        "public_suffix_list": suff_list,
    }
    user_created = actions.create_new_user(
        payload, override_authdb_path="sqlite:///test-creation.authdb.sqlite")
    assert user_created["success"] is False
    assert user_created["user_email"] == "*****@*****.**"
    assert user_created["user_id"] is None
    assert user_created["send_verification"] is False
    assert ("Your password is too similar to either "
            "the domain name of this server or your "
            "own name or email address." in user_created["messages"])

    # 4. password is OK
    payload = {
        "full_name": "Test User",
        "email": "*****@*****.**",
        "password": "******",
        "system_id": "totally-random-systemid-1234",
        "reqid": 1,
        "pii_salt": "super-random-salt",
    }
    user_created = actions.create_new_user(
        payload, override_authdb_path="sqlite:///test-creation.authdb.sqlite")
    assert user_created["success"] is True
    assert user_created["user_email"] == "*****@*****.**"
    assert user_created["user_id"] == 4
    assert user_created["system_id"] == "totally-random-systemid-1234"
    assert user_created["send_verification"] is True
    assert ("User account created. Please verify your email address to log in."
            in user_created["messages"])

    # 5. try to create a new user with an existing email address
    payload = {
        "full_name": "Test User",
        "email": "*****@*****.**",
        "password": "******",
        "reqid": 1,
        "pii_salt": "super-random-salt",
        "public_suffix_list": suff_list,
    }
    user_created = actions.create_new_user(
        payload, override_authdb_path="sqlite:///test-creation.authdb.sqlite")
    assert user_created["success"] is False
    assert user_created["user_email"] == "*****@*****.**"
    assert user_created["user_id"] == 4

    # we should not send a verification email because the user already has an
    # account or if the account is not active yet, the last verification email
    # was sent less than 24 hours ago
    assert user_created["send_verification"] is False
    assert ("User account created. Please verify your email address to log in."
            in user_created["messages"])

    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
Exemplo n.º 8
0
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()
Exemplo n.º 9
0
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_issue_apikey(tmpdir):
    """
    Test if issuing an API key works.

    """

    delete_test_authdb(tmpdir)
    test_authdb_url = get_test_authdb(tmpdir)
    teardown()

    get_public_suffix_list()

    # 1. 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

    # 2. verify their email
    email_verified_info = actions.set_user_emailaddr_verified(
        {
            "email": "*****@*****.**",
            "reqid": 2,
            "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"

    # 3. generate an API key
    apikey_issue_payload = {
        "issuer": "authnzerver",
        "audience": "test-service",
        "subject": "/test-endpoint",
        "apiversion": 1,
        "expires_seconds": 7,
        "not_valid_before": 1,
        "user_id": 4,
        "user_role": "authenticated",
        "ip_address": "1.2.3.4",
        "refresh_expires": 10,
        "refresh_nbf": 2,
        "reqid": 3,
        "pii_salt": "super-secret-salt",
    }

    apikey_info = actions.issue_apikey_nosession(
        apikey_issue_payload,
        raiseonfail=True,
        override_authdb_path=test_authdb_url,
        override_permissions_json=permissions_json,
    )

    assert apikey_info["success"] is True
    for key in ("apikey", "expires", "refresh_token", "refresh_token_expires"):
        assert key in apikey_info

    apikey = json.loads(apikey_info["apikey"])

    assert apikey["ipa"] == apikey_issue_payload["ip_address"]
    assert apikey["uid"] == apikey_issue_payload["user_id"]
    assert apikey["rol"] == apikey_issue_payload["user_role"]

    teardown()
def test_refresh_apikey(tmpdir):
    """
    This tests refreshing an API key.

    - before it expires
    - after it expires
    - with an unexpired correct refresh token
    - with the incorrect refresh token
    - with an expired refresh token

    """

    delete_test_authdb(tmpdir)
    test_authdb_url = get_test_authdb(tmpdir)
    teardown()

    get_public_suffix_list()

    # 1. 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

    # 2. verify their email
    email_verified_info = actions.set_user_emailaddr_verified(
        {
            "email": "*****@*****.**",
            "reqid": 2,
            "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"

    # 3. generate an API key
    apikey_issue_payload = {
        "issuer": "authnzerver",
        "audience": "test-service",
        "subject": "/test-endpoint",
        "apiversion": 1,
        "expires_seconds": 6,
        "not_valid_before": 1,
        "user_id": 4,
        "user_role": "authenticated",
        "ip_address": "1.2.3.4",
        "refresh_expires": 10,
        "refresh_nbf": 1,
        "reqid": 3,
        "pii_salt": "super-secret-salt",
    }

    apikey_info = actions.issue_apikey_nosession(
        apikey_issue_payload,
        raiseonfail=True,
        override_authdb_path=test_authdb_url,
        override_permissions_json=permissions_json,
    )

    assert apikey_info["success"] is True
    for key in ("apikey", "expires", "refresh_token", "refresh_token_expires"):
        assert key in apikey_info

    apikey = json.loads(apikey_info["apikey"])

    assert apikey["ipa"] == apikey_issue_payload["ip_address"]
    assert apikey["uid"] == apikey_issue_payload["user_id"]
    assert apikey["rol"] == apikey_issue_payload["user_role"]

    # 4. refresh the key immediately - this should fail because of refresh_nbf
    apikey_refresh_payload = {
        "apikey_dict": apikey,
        "user_id": 4,
        "user_role": "authenticated",
        "refresh_token": apikey_info["refresh_token"],
        "ip_address": "1.2.3.4",
        "expires_seconds": 4,
        "not_valid_before": 1,
        "refresh_expires": 10,
        "refresh_nbf": 1,
        "reqid": 3,
        "pii_salt": "super-secret-salt",
    }

    refreshed_apikey = actions.refresh_apikey_nosession(
        apikey_refresh_payload,
        raiseonfail=True,
        override_authdb_path=test_authdb_url,
        override_permissions_json=permissions_json,
    )

    assert refreshed_apikey["success"] is False

    # 5. now try to refresh within the lifetime of the key but with incorrect
    # refresh token - should fail
    time.sleep(2)

    apikey_refresh_payload["refresh_token"] = "haha wrong token"

    refreshed_apikey = actions.refresh_apikey_nosession(
        apikey_refresh_payload,
        raiseonfail=True,
        override_authdb_path=test_authdb_url,
        override_permissions_json=permissions_json,
    )

    assert refreshed_apikey["success"] is False

    # 6. now try to refresh with correct refresh token - should pass
    apikey_refresh_payload["refresh_token"] = apikey_info["refresh_token"]

    refreshed_apikey = actions.refresh_apikey_nosession(
        apikey_refresh_payload,
        raiseonfail=True,
        override_authdb_path=test_authdb_url,
        override_permissions_json=permissions_json,
    )

    assert refreshed_apikey["success"] is True

    # 7. now try to refresh after the key expires - should pass
    time.sleep(6)

    refreshed_apikey_dict = json.loads(refreshed_apikey["apikey"])

    apikey_refresh_payload = {
        "apikey_dict": refreshed_apikey_dict,
        "user_id": 4,
        "user_role": "authenticated",
        "refresh_token": refreshed_apikey["refresh_token"],
        "ip_address": "1.2.3.4",
        "expires_seconds": 4,
        "not_valid_before": 1,
        "refresh_expires": 5,
        "refresh_nbf": 1,
        "reqid": 3,
        "pii_salt": "super-secret-salt",
    }

    refreshed_apikey = actions.refresh_apikey_nosession(
        apikey_refresh_payload,
        raiseonfail=True,
        override_authdb_path=test_authdb_url,
        override_permissions_json=permissions_json,
    )

    assert refreshed_apikey["success"] is True

    # 8. now try to refresh after the refresh token expires - should fail
    time.sleep(6)

    refreshed_apikey = actions.refresh_apikey_nosession(
        apikey_refresh_payload,
        raiseonfail=True,
        override_authdb_path=test_authdb_url,
        override_permissions_json=permissions_json,
    )

    assert refreshed_apikey["success"] is False

    teardown()
def test_revoke_all_apikeys(tmpdir):
    """
    This tests if all API keys for a user can be revoked.

    """

    delete_test_authdb(tmpdir)
    test_authdb_url = get_test_authdb(tmpdir)
    teardown()

    get_public_suffix_list()

    # 1. 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

    # 2. verify their email
    email_verified_info = actions.set_user_emailaddr_verified(
        {
            "email": "*****@*****.**",
            "reqid": 2,
            "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"

    # 3. generate a couple of API keys
    apikey_payload_one = {
        "issuer": "authnzerver",
        "audience": "test-service",
        "subject": "/test-endpoint-one",
        "apiversion": 1,
        "expires_seconds": 7,
        "not_valid_before": 1,
        "user_id": 4,
        "user_role": "authenticated",
        "ip_address": "1.2.3.4",
        "refresh_expires": 10,
        "refresh_nbf": 2,
        "reqid": 3,
        "pii_salt": "super-secret-salt",
    }

    apikey_info_one = actions.issue_apikey_nosession(
        apikey_payload_one,
        raiseonfail=True,
        override_authdb_path=test_authdb_url,
        override_permissions_json=permissions_json,
    )

    apikey_one = json.loads(apikey_info_one["apikey"])

    apikey_payload_two = {
        "issuer": "authnzerver",
        "audience": "test-service",
        "subject": "/test-endpoint-two",
        "apiversion": 1,
        "expires_seconds": 7,
        "not_valid_before": 1,
        "user_id": 4,
        "user_role": "authenticated",
        "ip_address": "1.2.3.4",
        "refresh_expires": 10,
        "refresh_nbf": 2,
        "reqid": 3,
        "pii_salt": "super-secret-salt",
    }

    apikey_info_two = actions.issue_apikey_nosession(
        apikey_payload_two,
        raiseonfail=True,
        override_authdb_path=test_authdb_url,
        override_permissions_json=permissions_json,
    )

    apikey_two = json.loads(apikey_info_two["apikey"])

    time.sleep(2)

    # 1. try to revoke all API keys with an incorrect API key
    good_tkn = apikey_one["tkn"]
    apikey_one["tkn"] = "haha-bad-token"
    revoke_one = actions.revoke_all_apikeys_nosession(
        {
            "apikey_dict": apikey_one,
            "user_id": 4,
            "user_role": "authenticated",
            "reqid": 2,
            "pii_salt": "super-secret-salt",
        },
        raiseonfail=True,
        override_authdb_path=test_authdb_url,
        override_permissions_json=permissions_json,
    )
    assert revoke_one["success"] is False

    # 2. try to revoke all API keys with a correct API key
    revoke_two = actions.revoke_all_apikeys_nosession(
        {
            "apikey_dict": apikey_two,
            "user_id": 4,
            "user_role": "authenticated",
            "reqid": 2,
            "pii_salt": "super-secret-salt",
        },
        raiseonfail=True,
        override_authdb_path=test_authdb_url,
        override_permissions_json=permissions_json,
    )
    assert revoke_two["success"] is True

    # 3. make sure we can't use any API key afterwards
    apikey_one["tkn"] = good_tkn

    verify_one = actions.verify_apikey_nosession(
        {
            "apikey_dict": apikey_one,
            "user_id": 4,
            "user_role": "authenticated",
            "reqid": 3,
            "pii_salt": "super-secret-salt",
        },
        raiseonfail=True,
        override_authdb_path=test_authdb_url,
        override_permissions_json=permissions_json,
    )
    assert verify_one["success"] is False

    verify_two = actions.verify_apikey_nosession(
        {
            "apikey_dict": apikey_two,
            "user_id": 4,
            "user_role": "authenticated",
            "reqid": 4,
            "pii_salt": "super-secret-salt",
        },
        raiseonfail=True,
        override_authdb_path=test_authdb_url,
        override_permissions_json=permissions_json,
    )
    assert verify_two["success"] is False

    teardown()
def test_revoke_apikey(tmpdir):
    """
    This tests if an apikey can be revoked.

    - by the original user
    - by another user who somehow gets the API key

    """

    delete_test_authdb(tmpdir)
    test_authdb_url = get_test_authdb(tmpdir)
    teardown()

    get_public_suffix_list()

    # 1. create a couple of new users
    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

    payload = {
        "full_name": "Another Test User",
        "email": "*****@*****.**",
        "password": "******",
        "reqid": 2,
        "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"] == 5

    # 2. verify their emails
    email_verified_info = actions.set_user_emailaddr_verified(
        {
            "email": "*****@*****.**",
            "reqid": 3,
            "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"

    email_verified_info = actions.set_user_emailaddr_verified(
        {
            "email": "*****@*****.**",
            "reqid": 4,
            "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"] == 5
    assert email_verified_info["is_active"] is True
    assert email_verified_info["user_role"] == "authenticated"

    # 3. generate an API key for the first user
    apikey_issue_payload = {
        "issuer": "authnzerver",
        "audience": "test-service",
        "subject": "/test-endpoint",
        "apiversion": 1,
        "expires_seconds": 6,
        "not_valid_before": 2,
        "user_id": 4,
        "user_role": "authenticated",
        "ip_address": "1.2.3.4",
        "refresh_expires": 10,
        "refresh_nbf": 2,
        "reqid": 5,
        "pii_salt": "super-secret-salt",
    }

    apikey_info = actions.issue_apikey_nosession(
        apikey_issue_payload,
        raiseonfail=True,
        override_authdb_path=test_authdb_url,
        override_permissions_json=permissions_json,
    )
    assert apikey_info["success"] is True

    apikey_dict = json.loads(apikey_info["apikey"])
    time.sleep(2)

    # 4. try to revoke the API key as a different user
    # this should fail
    apikey_revocation = actions.revoke_apikey_nosession(
        {
            "apikey_dict": apikey_dict,
            "user_id": 5,
            "user_role": "authenticated",
            "reqid": 6,
            "pii_salt": "super-secret-salt",
        },
        raiseonfail=True,
        override_authdb_path=test_authdb_url,
        override_permissions_json=permissions_json,
    )
    assert apikey_revocation["success"] is False

    # 5. try to revoke the API key as the correct user
    # this should pass
    apikey_revocation = actions.revoke_apikey_nosession(
        {
            "apikey_dict": apikey_dict,
            "user_id": 4,
            "user_role": "authenticated",
            "reqid": 7,
            "pii_salt": "super-secret-salt",
        },
        raiseonfail=True,
        override_authdb_path=test_authdb_url,
        override_permissions_json=permissions_json,
    )
    assert apikey_revocation["success"] is True

    # 6. try to verify the API key after it has been revoked
    # this should fail
    apikey_verification = actions.verify_apikey_nosession(
        {
            "apikey_dict": apikey_dict,
            "user_id": 4,
            "user_role": "authenticated",
            "reqid": 8,
            "pii_salt": "super-secret-salt",
        },
        raiseonfail=True,
        override_authdb_path=test_authdb_url,
        override_permissions_json=permissions_json,
    )
    assert apikey_verification["success"] is False

    # 7. try to verify the API key as a different user - this should fail anyway
    apikey_verification = actions.verify_apikey_nosession(
        {
            "apikey_dict": apikey_dict,
            "user_id": 5,
            "user_role": "authenticated",
            "reqid": 9,
            "pii_salt": "super-secret-salt",
        },
        raiseonfail=True,
        override_authdb_path=test_authdb_url,
        override_permissions_json=permissions_json,
    )
    assert apikey_verification["success"] is False

    teardown()
def test_verify_apikey(tmpdir):
    """
    This tests if the issued API key can be verified:

    - within expiry time
    - within expiry but with other user
    - after expiry time

    """

    delete_test_authdb(tmpdir)
    test_authdb_url = get_test_authdb(tmpdir)
    teardown()

    get_public_suffix_list()

    # 1. create a couple of new users
    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

    payload = {
        "full_name": "Another Test User",
        "email": "*****@*****.**",
        "password": "******",
        "reqid": 2,
        "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"] == 5

    # 2. verify their emails
    email_verified_info = actions.set_user_emailaddr_verified(
        {
            "email": "*****@*****.**",
            "reqid": 3,
            "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"

    email_verified_info = actions.set_user_emailaddr_verified(
        {
            "email": "*****@*****.**",
            "reqid": 4,
            "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"] == 5
    assert email_verified_info["is_active"] is True
    assert email_verified_info["user_role"] == "authenticated"

    # 3. generate an API key for the first user
    apikey_issue_payload = {
        "issuer": "authnzerver",
        "audience": "test-service",
        "subject": "/test-endpoint",
        "apiversion": 1,
        "expires_seconds": 6,
        "not_valid_before": 2,
        "user_id": 4,
        "user_role": "authenticated",
        "ip_address": "1.2.3.4",
        "refresh_expires": 10,
        "refresh_nbf": 2,
        "reqid": 4,
        "pii_salt": "super-secret-salt",
    }

    apikey_info = actions.issue_apikey_nosession(
        apikey_issue_payload,
        raiseonfail=True,
        override_authdb_path=test_authdb_url,
        override_permissions_json=permissions_json,
    )
    assert apikey_info["success"] is True

    apikey_dict = json.loads(apikey_info["apikey"])

    # 4. try to verify the API key immediately - should fail because of
    # not-before
    apikey_verification = actions.verify_apikey_nosession(
        {
            "apikey_dict": apikey_dict,
            "user_id": 4,
            "user_role": "authenticated",
            "reqid": 5,
            "pii_salt": "super-secret-salt",
        },
        raiseonfail=True,
        override_authdb_path=test_authdb_url,
        override_permissions_json=permissions_json,
    )
    assert apikey_verification["success"] is False

    # 5. wait 3 seconds, then verify again - this should pass
    time.sleep(3)
    apikey_verification = actions.verify_apikey_nosession(
        {
            "apikey_dict": apikey_dict,
            "user_id": 4,
            "user_role": "authenticated",
            "reqid": 6,
            "pii_salt": "super-secret-salt",
        },
        raiseonfail=True,
        override_authdb_path=test_authdb_url,
        override_permissions_json=permissions_json,
    )
    assert apikey_verification["success"] is True

    # 6. try to verify the API key as a different user - this should fail
    apikey_verification = actions.verify_apikey_nosession(
        {
            "apikey_dict": apikey_dict,
            "user_id": 5,
            "user_role": "authenticated",
            "reqid": 6,
            "pii_salt": "super-secret-salt",
        },
        raiseonfail=True,
        override_authdb_path=test_authdb_url,
        override_permissions_json=permissions_json,
    )
    assert apikey_verification["success"] is False

    # 7. wait 6 seconds, then try to reverify the API key as the original user
    # it should have expired by now so this should fail
    time.sleep(6)
    apikey_verification = actions.verify_apikey_nosession(
        {
            "apikey_dict": apikey_dict,
            "user_id": 4,
            "user_role": "authenticated",
            "reqid": 7,
            "pii_salt": "super-secret-salt",
        },
        raiseonfail=True,
        override_authdb_path=test_authdb_url,
    )
    assert apikey_verification["success"] is False

    teardown()