import uuid from unittest.mock import ANY import pytest from tests.app.db import create_user, create_webauthn_credential def test_get_webauthn_credentials_returns_all_credentials_for_user( admin_request, notify_db_session ): me = create_user(email="a") other = create_user(email="b") first = create_webauthn_credential(me, "1") create_webauthn_credential(me, "2") create_webauthn_credential(other, "3") response = admin_request.get( "webauthn.get_webauthn_credentials", user_id=me.id, ) creds = sorted(response["data"], key=lambda x: x["name"]) assert len(creds) == 2 assert creds[0] == { "id": str(first.id), "user_id": str(me.id), "name": "1", "credential_data": "ABC123", "created_at": ANY, "updated_at": None, } assert creds[1]["name"] == "2" def test_get_webauthn_credentials_returns_empty_list_if_no_creds( admin_request, sample_user ): response = admin_request.get( "webauthn.get_webauthn_credentials", user_id=sample_user.id ) assert response == {"data": []} def test_get_webauthn_credentials_errors_if_user_doesnt_exist( admin_request, sample_user ): create_webauthn_credential(sample_user, "1") admin_request.get( "webauthn.get_webauthn_credentials", user_id=uuid.uuid4(), _expected_status=404 ) def test_create_webauthn_credential_returns_201(admin_request, sample_user): response = admin_request.post( "webauthn.create_webauthn_credential", user_id=sample_user.id, _data={ "name": "my key", "credential_data": "ABC123", "registration_response": "DEF456", }, _expected_status=201, ) assert len(sample_user.webauthn_credentials) == 1 new_cred = sample_user.webauthn_credentials[0] assert new_cred.name == "my key" assert new_cred.credential_data == "ABC123" assert new_cred.registration_response == "DEF456" assert response["data"]["id"] == str(new_cred.id) @pytest.mark.parametrize( "data, err_msg", [ # missing registration_response ( {"name": "my key", "credential_data": "ABC123"}, "registration_response is a required property", ), # name is null ( {"name": None, "credential_data": "ABC123"}, "name None is not of type string", ), # name is empty ({"name": "", "credential_data": "ABC123"}, "name should be non-empty"), ], ) def test_create_webauthn_credential_errors_if_schema_violation( admin_request, sample_user, data, err_msg ): response = admin_request.post( "webauthn.create_webauthn_credential", user_id=sample_user.id, _data=data, _expected_status=400, ) assert response["errors"][0] == {"error": "ValidationError", "message": err_msg} def test_update_webauthn_credential_returns_200(admin_request, sample_user): cred = create_webauthn_credential(sample_user) assert cred.name != "new name" response = admin_request.post( "webauthn.update_webauthn_credential", user_id=sample_user.id, webauthn_credential_id=cred.id, _data={ "name": "new name", }, ) assert response["data"]["id"] == str(cred.id) assert response["data"]["name"] == "new name" @pytest.mark.parametrize( "data, err_msg", [ # you can't update credential_data ( {"name": "my key", "credential_data": "NAUGHTY123"}, "Additional properties are not allowed (credential_data was unexpected)", ), # name is null ({"name": None}, "name None is not of type string"), # name is empty ({"name": ""}, "name should be non-empty"), ], ) def test_update_webauthn_credential_errors_if_schema_violation( admin_request, sample_user, data, err_msg ): cred = create_webauthn_credential(sample_user) response = admin_request.post( "webauthn.update_webauthn_credential", user_id=sample_user.id, webauthn_credential_id=cred.id, _data=data, _expected_status=400, ) assert response["errors"][0] == {"error": "ValidationError", "message": err_msg} def test_update_webauthn_credential_errors_if_webauthn_credential_doesnt_exist( admin_request, sample_user ): admin_request.post( "webauthn.update_webauthn_credential", user_id=sample_user.id, webauthn_credential_id=uuid.uuid4(), _data={ "name": "my key", }, _expected_status=404, ) def test_update_webauthn_credential_errors_if_user_id_doesnt_match( admin_request, notify_db_session ): user_1 = create_user(email="1") user_2 = create_user(email="2") cred_2 = create_webauthn_credential(user_2) response = admin_request.post( "webauthn.update_webauthn_credential", user_id=user_1.id, webauthn_credential_id=cred_2.id, _data={ "name": "new key name", }, _expected_status=404, ) assert response["message"] == "No result found" def test_delete_webauthn_credential_returns_204(admin_request, sample_user): cred1 = create_webauthn_credential(sample_user) cred2 = create_webauthn_credential(sample_user) admin_request.delete( "webauthn.update_webauthn_credential", user_id=sample_user.id, webauthn_credential_id=cred1.id, _expected_status=204, ) assert sample_user.webauthn_credentials == [cred2] def test_delete_webauthn_credential_errors_if_last_key(admin_request, sample_user): cred = create_webauthn_credential(sample_user) response = admin_request.delete( "webauthn.delete_webauthn_credential", user_id=sample_user.id, webauthn_credential_id=cred.id, _expected_status=400, ) assert ( response["message"] == "Cannot delete last remaining webauthn credential for user" ) def test_delete_webauthn_credential_errors_if_user_id_doesnt_match( admin_request, notify_db_session ): user_1 = create_user(email="1") user_2 = create_user(email="2") cred_2a = create_webauthn_credential(user_2) response = admin_request.delete( "webauthn.delete_webauthn_credential", user_id=user_1.id, webauthn_credential_id=cred_2a.id, _expected_status=404, ) assert response["message"] == "No result found"