kanidm/pykanidm/tests/test_authenticate.py
2024-09-10 00:36:50 +00:00

194 lines
6.9 KiB
Python

"""testing auth things"""
import logging
import os
import pytest
from pytest_mock import MockerFixture
# pylint: disable=unused-import
from testutils import client, client_configfile, MockResponse
from kanidm import KanidmClient
from kanidm.exceptions import AuthCredFailed, AuthInitFailed
from kanidm.types import AuthBeginResponse
from kanidm.tokens import TokenStore
logging.basicConfig(level=logging.DEBUG)
@pytest.mark.network
@pytest.mark.asyncio
async def test_auth_init(client_configfile: KanidmClient) -> None:
"""tests the auth init step"""
print("Starting client...")
print(f"Doing auth_init for {client_configfile.config.username}")
if client_configfile.config.username is None:
pytest.skip("Can't run auth test without a username/password")
result = await client_configfile.auth_init(client_configfile.config.username)
print(f"{result=}")
print(result.model_dump_json())
assert result.sessionid
@pytest.mark.network
@pytest.mark.asyncio
async def test_auth_begin(client_configfile: KanidmClient) -> None:
"""tests the auth begin step"""
print(f"Doing auth_init for {client_configfile.config.username}")
if client_configfile.config.username is None:
pytest.skip("Can't run auth test without a username/password")
result = await client_configfile.auth_init(client_configfile.config.username)
print(f"{result=}")
print("Result dict:")
print(result.model_dump_json())
assert result.sessionid
print(f"Doing auth_begin for {client_configfile.config.username}")
if result.response is None:
raise ValueError("Failed to get response")
sessionid = result.response.headers["x-kanidm-auth-session-id"]
begin_result = await client_configfile.auth_begin(
sessionid=sessionid,
method="password",
)
print(f"{begin_result=}")
print(begin_result.data)
retval = begin_result.data
if retval is None:
raise pytest.fail("Failed to do begin_result")
retval["response"] = begin_result.model_dump()
assert AuthBeginResponse.model_validate(retval)
@pytest.mark.network
@pytest.mark.asyncio
async def test_authenticate_flow(client_configfile: KanidmClient) -> None:
"""tests the authenticate() flow"""
if client_configfile.config.username is None or client_configfile.config.password is None:
pytest.skip("Can't run this without a username and password set in the config file")
client_configfile.config.auth_token = None
print(f"Doing client.authenticate for {client_configfile.config.username}")
result = await client_configfile.authenticate_password()
print(result)
@pytest.mark.network
@pytest.mark.asyncio
async def test_authenticate_anonymous(client_configfile: KanidmClient) -> None:
"""tests the authenticate() flow"""
client_configfile.config.auth_token = None
print("Doing anonymous auth")
await client_configfile.auth_as_anonymous()
assert client_configfile.config.auth_token is not None
@pytest.mark.network
@pytest.mark.asyncio
async def test_authenticate_flow_fail(client_configfile: KanidmClient) -> None:
"""tests the authenticate() flow with a valid (hopefully) username and invalid password"""
if not bool(os.getenv("RUN_SCARY_TESTS", None)):
pytest.skip(reason="Skipping because env var RUN_SCARY_TESTS isn't set")
print("Starting client...")
if client_configfile.config.uri is None or client_configfile.config.username is None or client_configfile.config.password is None:
pytest.skip("Please ensure you have a username, password and uri in the config")
print(f"Doing client.authenticate for {client_configfile.config.username}")
client_configfile.config.auth_token = None
with pytest.raises((AuthCredFailed, AuthInitFailed)):
result = await client_configfile.authenticate_password(
username=client_configfile.config.username,
password="cheese",
)
print(result)
# TODO: mock a call to auth_init when a 200 response is not returned, raises AuthInitFailed
# TODO: mock a call to auth_init when "x-kanidm-auth-session-id" not in response.headers, raises ValueError
# TODO: mock a call to auth_begin when a 200 response is not returned, raises AuthBeginFailed
# TODO: mock a call to auth_step_password when a 200 response is not returned, raises AuthCredFailed
@pytest.mark.asyncio
async def test_authenticate_inputs_validation(client: KanidmClient, mocker: MockerFixture) -> None:
"""tests if you pass username but not password and password but not username"""
resp = MockResponse("crabs are cool", 200)
mocker.patch("aiohttp.ClientSession.post", return_value=resp)
with pytest.raises(ValueError):
await client.authenticate_password(username="cheese")
with pytest.raises(ValueError):
await client.authenticate_password(password="cheese")
client.config.password = None
client.config.username = "crabby"
with pytest.raises(ValueError):
await client.authenticate_password()
client.config.password = "cR4bzR0ol"
client.config.username = None
with pytest.raises(ValueError):
await client.authenticate_password()
client.config.username = None
client.config.password = None
with pytest.raises(ValueError):
await client.authenticate_password()
@pytest.mark.network
@pytest.mark.asyncio
async def test_auth_step_password(client: KanidmClient) -> None:
"""tests things"""
with pytest.raises(ValueError):
await client.auth_step_password(sessionid="asdf")
@pytest.mark.network
@pytest.mark.asyncio
async def test_authenticate_with_token(client_configfile: KanidmClient) -> None:
"""tests auth with a token, needs to have a valid token in your local cache"""
logging.basicConfig(level=logging.DEBUG)
if "KANIDM_TEST_USERNAME" in os.environ:
test_username: str = os.environ["KANIDM_TEST_USERNAME"]
print(f"Using username {test_username} from KANIDM_TEST_USERNAME env var")
else:
test_username = "idm_admin"
print(f"Using username {test_username} by default - set KANIDM_TEST_USERNAME env var if you want to change this.")
tokens = TokenStore.model_validate({})
tokens.load()
# TODO: make this actually work now instances are a thing
# if test_username not in tokens:
# print(f"Can't find {test_username} user in token store")
# raise pytest.skip(f"Can't find {test_username} user in token store")
# test_token: str = tokens[test_username]
# if not await client_configfile.check_token_valid(test_token):
# print(f"Token for {test_username} isn't valid")
# pytest.skip(f"Token for {test_username} isn't valid")
# else:
# print("Token was noted as valid, so auth works!")
# # tests the "we set a token and well it works."
# client_configfile.config.auth_token = tokens[test_username]
# result = await client_configfile.call_get("/v1/self")
# print(result)
# assert result.status_code == 200