diff --git a/tests/conftest.py b/tests/conftest.py index 19496f5..6651b34 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,4 +1,5 @@ import pytest +from sachet.server.users import manage from click.testing import CliRunner import os @@ -7,14 +8,14 @@ os.environ["APP_SETTINGS"] = "sachet.server.config.TestingConfig" from sachet.server import app, db @pytest.fixture -def flask_app(): +def client(): """Flask application with DB already set up and ready.""" with app.test_client() as client: with app.app_context(): db.drop_all() db.create_all() db.session.commit() - yield app.test_client + yield client db.session.remove() db.drop_all() @@ -28,6 +29,66 @@ def flask_app_bare(): db.drop_all() +@pytest.fixture +def users(client): + """Creates all the test users. + + Returns a dictionary with all the info for each user. + """ + userinfo = { + "jeff": { + "password": "1234", + "admin": False + }, + "administrator": { + "password": "4321", + "admin": True + } + } + + for user, info in userinfo.items(): + info["username"] = user + manage.create_user( + info["admin"], + info["username"], + info["password"] + ) + + return userinfo + + +@pytest.fixture +def validate_info(users): + """Given a dictionary, validate the information against a given user's info.""" + def _validate(user, info): + for k, v in info.items(): + assert users[user][k] == v + + return _validate + + +@pytest.fixture +def tokens(client, users): + """Logs in all test users. + + Returns a dictionary of auth tokens for all test users. + """ + + toks = {} + + for user, creds in users.items(): + resp = client.post("/users/login", json={ + "username": creds["username"], + "password": creds["password"] + }) + resp_json = resp.get_json() + token = resp_json.get("auth_token") + assert token is not None and token != "" + toks[creds["username"]] = token + + return toks + + @pytest.fixture def cli(): """click's testing fixture""" diff --git a/tests/test_auth.py b/tests/test_auth.py new file mode 100644 index 0000000..acd393b --- /dev/null +++ b/tests/test_auth.py @@ -0,0 +1,110 @@ +import pytest +import jwt +from sachet.server import db +from sachet.server.users import manage + +def test_unauth_perms(client): + """Test endpoints to see if they allow unauthenticated users.""" + resp = client.get("/users/jeff") + assert resp.status_code == 401 + +def test_malformed_authorization(client): + """Test attempting authorization incorrectly.""" + + # incorrect token + token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c" + resp = client.get( + "/users/jeff", + headers={ + "Authorization": f"bearer {token}" + } + ) + assert resp.status_code == 401 + + # invalid token + token = "not a.real JWT.token" + resp = client.get( + "/users/jeff", + headers={ + "Authorization": f"bearer {token}" + } + ) + assert resp.status_code == 401 + + # missing token + token = "not a.real JWT.token" + resp = client.get( + "/users/jeff", + headers={ + "Authorization": "" + } + ) + assert resp.status_code == 401 + +def test_login(client, users): + """Test logging in.""" + + # wrong password + resp = client.post("/users/login", json={ + "username": "jeff", + "password": users["jeff"]["password"] + "garbage" + }) + assert resp.status_code == 401 + + # logging in correctly + resp = client.post("/users/login", json={ + "username": "jeff", + "password": users["jeff"]["password"] + }) + assert resp.status_code == 200 + resp_json = resp.get_json() + assert resp_json.get("status") == "success" + assert resp_json.get("username") == "jeff" + token = resp_json.get("auth_token") + assert token is not None and token != "" + +def test_userinfo(client, tokens, validate_info): + """Test accessing the user information endpoint as a normal user.""" + + # access user info endpoint + resp = client.get( + "/users/jeff", + headers={ + "Authorization": f"bearer {tokens['jeff']}" + } + ) + assert resp.status_code == 200 + validate_info("jeff", resp.get_json()) + + + # access other user's info endpoint + resp = client.get( + "/users/administrator", + headers={ + "Authorization": f"bearer {tokens['jeff']}" + } + ) + assert resp.status_code == 403 + +def test_userinfo_admin(client, tokens, validate_info): + """Test accessing other user's information as an admin.""" + + # first test that admin can access its own info + resp = client.get( + "/users/administrator", + headers={ + "Authorization": f"bearer {tokens['administrator']}" + } + ) + assert resp.status_code == 200 + validate_info("administrator", resp.get_json()) + + # now test accessing other user's info + resp = client.get( + "/users/jeff", + headers={ + "Authorization": f"bearer {tokens['administrator']}" + } + ) + assert resp.status_code == 200 + validate_info("jeff", resp.get_json()) diff --git a/tests/test_cli.py b/tests/test_cli.py index 4925bc9..0be7a0f 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -18,7 +18,7 @@ def test_db(flask_app_bare, cli): assert "users" not in inspect(db.engine).get_table_names() -def test_user(flask_app, cli): +def test_user(client, cli): """Test the CLI's ability to create then delete a user.""" # create user result = cli.invoke(create_user, ["--username", "jeff", "--password", "1234"])