def test_process_challenge_req_good_api_version(alice, monkeypatch, client_version, backend_version, valid): # Cast parameters client_version = ApiVersion(*client_version) backend_version = ApiVersion(*backend_version) ch = APIV1_AuthenticatedClientHandshake(alice.organization_id, alice.device_id, alice.signing_key, alice.root_verify_key) req = { "handshake": "challenge", "challenge": b"1234567890", "supported_api_versions": [backend_version], } monkeypatch.setattr(ch, "SUPPORTED_API_VERSIONS", [client_version]) # Invalid versioning if not valid: with pytest.raises(HandshakeAPIVersionError) as context: ch.process_challenge_req(packb(req)) assert context.value.client_versions == [client_version] assert context.value.backend_versions == [backend_version] return # Valid versioning ch.process_challenge_req(packb(req)) assert ch.SUPPORTED_API_VERSIONS == [client_version] assert ch.challenge_data["supported_api_versions"] == [backend_version] assert ch.backend_api_version == backend_version assert ch.client_api_version == client_version
def test_process_challenge_req_good_api_version(alice, monkeypatch, client_version, backend_version, valid): # Cast parameters client_version = ApiVersion(*client_version) backend_version = ApiVersion(*backend_version) ch = APIV1_AnonymousClientHandshake(alice.organization_id, alice.root_verify_key) req = { "handshake": "challenge", "challenge": b"1234567890", "supported_api_versions": [backend_version], "backend_timestamp": pendulum.now(), "ballpark_client_early_offset": BALLPARK_CLIENT_EARLY_OFFSET, "ballpark_client_late_offset": BALLPARK_CLIENT_LATE_OFFSET, } monkeypatch.setattr(ch, "SUPPORTED_API_VERSIONS", [client_version]) # Invalid versioning if not valid: with pytest.raises(HandshakeAPIVersionError) as context: ch.process_challenge_req(packb(req)) assert context.value.client_versions == [client_version] assert context.value.backend_versions == [backend_version] return # Valid versioning ch.process_challenge_req(packb(req)) assert ch.SUPPORTED_API_VERSIONS == [client_version] assert ch.challenge_data["supported_api_versions"] == [backend_version] assert ch.backend_api_version == backend_version assert ch.client_api_version == client_version
def test_handshake_challenge_schema_for_client_server_api_compatibility( mallory, alice, monkeypatch): ash = ServerHandshake() bch = AuthenticatedClientHandshake(mallory.organization_id, mallory.device_id, mallory.signing_key, mallory.root_verify_key) challenge = b"1234567890" # Backend API >= 2.5 and Client API < 2.5 client_version = ApiVersion(2, 4) backend_version = ApiVersion(2, 5) answer = { "handshake": "answer", "type": HandshakeType.AUTHENTICATED.value, "client_api_version": client_version, "organization_id": str(alice.organization_id), "device_id": str(alice.device_id), "rvk": alice.root_verify_key.encode(), "answer": alice.signing_key.sign(challenge), } ash.build_challenge_req() ash.challenge = challenge ash.process_answer_req(packb(answer)) result_req = ash.build_result_req(alice.verify_key) result = handshake_result_serializer.loads(result_req) assert result["result"] == "ok" # Backend API < 2.5 and Client API >= 2.5 client_version = ApiVersion(2, 5) backend_version = ApiVersion(2, 4) req = { "handshake": "challenge", "challenge": challenge, "supported_api_versions": [backend_version], "backend_timestamp": pendulum.now(), "ballpark_client_early_offset": BALLPARK_CLIENT_EARLY_OFFSET, "ballpark_client_late_offset": BALLPARK_CLIENT_LATE_OFFSET, } monkeypatch.setattr(bch, "SUPPORTED_API_VERSIONS", [client_version]) answer_req = bch.process_challenge_req(packb(req)) answer = handshake_answer_serializer.loads(answer_req) assert mallory.verify_key.verify(answer["answer"]) == challenge
async def check_forbidden_cmds(backend_sock, cmds): for cmd in cmds: await backend_sock.send(packb({"cmd": cmd})) rep = await backend_sock.recv() assert unpackb(rep) == { "status": "unknown_command", "reason": "Unknown command" }
async def test_non_admin_has_limited_access(alice_backend_sock): for cmd in (ADMINISTRATION_CMDS | ANONYMOUS_CMDS) - AUTHENTICATED_CMDS: await alice_backend_sock.send(packb({"cmd": cmd})) rep = await alice_backend_sock.recv() assert unpackb(rep) == { "status": "unknown_command", "reason": "Unknown command" }
def test_process_challenge_req_good_multiple_api_version( alice, monkeypatch, client_versions, backend_versions, expected_client_version, expected_backend_version, ): # Cast parameters client_versions = [ApiVersion(*args) for args in client_versions] backend_versions = [ApiVersion(*args) for args in backend_versions] if expected_client_version: expected_client_version = ApiVersion(*expected_client_version) if expected_backend_version: expected_backend_version = ApiVersion(*expected_backend_version) ch = APIV1_AnonymousClientHandshake(alice.organization_id, alice.root_verify_key) req = { "handshake": "challenge", "challenge": b"1234567890", "supported_api_versions": list(backend_versions), "backend_timestamp": pendulum.now(), "ballpark_client_early_offset": BALLPARK_CLIENT_EARLY_OFFSET, "ballpark_client_late_offset": BALLPARK_CLIENT_LATE_OFFSET, } monkeypatch.setattr(ch, "SUPPORTED_API_VERSIONS", client_versions) # Invalid versioning if expected_client_version is None: with pytest.raises(HandshakeAPIVersionError) as context: ch.process_challenge_req(packb(req)) assert context.value.client_versions == client_versions assert context.value.backend_versions == backend_versions return # Valid versioning ch.process_challenge_req(packb(req)) assert ch.SUPPORTED_API_VERSIONS == client_versions assert ch.challenge_data["supported_api_versions"] == list( backend_versions) assert ch.backend_api_version == expected_backend_version assert ch.client_api_version == expected_client_version
def test_process_challenge_req_good_multiple_api_version( alice, monkeypatch, client_versions, backend_versions, expected_client_version, expected_backend_version, ): # Cast parameters client_versions = [ApiVersion(*args) for args in client_versions] backend_versions = [ApiVersion(*args) for args in backend_versions] if expected_client_version: expected_client_version = ApiVersion(*expected_client_version) if expected_backend_version: expected_backend_version = ApiVersion(*expected_backend_version) ch = APIV1_AuthenticatedClientHandshake(alice.organization_id, alice.device_id, alice.signing_key, alice.root_verify_key) req = { "handshake": "challenge", "challenge": b"1234567890", "supported_api_versions": list(backend_versions), } monkeypatch.setattr(ch, "SUPPORTED_API_VERSIONS", client_versions) # Invalid versioning if expected_client_version is None: with pytest.raises(HandshakeAPIVersionError) as context: ch.process_challenge_req(packb(req)) assert context.value.client_versions == client_versions assert context.value.backend_versions == backend_versions return # Valid versioning ch.process_challenge_req(packb(req)) assert ch.SUPPORTED_API_VERSIONS == client_versions assert ch.challenge_data["supported_api_versions"] == list( backend_versions) assert ch.backend_api_version == expected_backend_version assert ch.client_api_version == expected_client_version
def test_process_answer_req_bad_format(req, alice): for key, good_value in [ ("organization_id", str(alice.organization_id)), ("device_id", str(alice.device_id)), ("rvk", alice.root_verify_key.encode()), ]: if req.get(key) == "<good>": req[key] = good_value req["client_api_version"] = API_V1_VERSION sh = ServerHandshake() sh.build_challenge_req() with pytest.raises(InvalidMessageError): sh.process_answer_req(packb(req))
def test_build_result_req_bad_challenge(alice): sh = ServerHandshake() sh.build_challenge_req() answer = { "handshake": "answer", "type": "authenticated", "client_api_version": API_V1_VERSION, "organization_id": alice.organization_id, "device_id": alice.device_id, "rvk": alice.root_verify_key.encode(), "answer": alice.signing_key.sign(sh.challenge + b"-dummy"), } sh.process_answer_req(packb(answer)) with pytest.raises(HandshakeFailedChallenge): sh.build_result_req(alice.verify_key)
def test_build_bad_outcomes(alice, method, expected_result): sh = ServerHandshake() sh.build_challenge_req() answer = { "handshake": "answer", "type": "authenticated", "client_api_version": API_V1_VERSION, "organization_id": alice.organization_id, "device_id": alice.device_id, "rvk": alice.root_verify_key.encode(), "answer": alice.signing_key.sign(sh.challenge), } sh.process_answer_req(packb(answer)) req = getattr(sh, method)() assert unpackb(req) == {"handshake": "result", "result": expected_result, "help": ANY}
def test_build_bad_outcomes(alice, method, expected_result): sh = ServerHandshake() sh.build_challenge_req() answer = { "handshake": "answer", "type": APIV1_HandshakeType.ANONYMOUS.value, "client_api_version": API_V1_VERSION, "organization_id": str(alice.organization_id), "answer": alice.signing_key.sign(sh.challenge), } sh.process_answer_req(packb(answer)) req = getattr(sh, method)() assert unpackb(req) == { "handshake": "result", "result": expected_result, "help": ANY }
def test_process_result_req_bad_outcome(result, exc_cls): ch = BaseClientHandshake() with pytest.raises(exc_cls): ch.process_result_req(packb({"handshake": "result", "result": result}))
def test_process_result_req_bad_format(req): ch = BaseClientHandshake() with pytest.raises(InvalidMessageError): ch.process_result_req(packb(req))
def test_process_challenge_req_bad_format(alice, req): ch = APIV1_AnonymousClientHandshake(alice.organization_id, alice.root_verify_key) with pytest.raises(InvalidMessageError): ch.process_challenge_req(packb(req))
def test_process_challenge_req_bad_format(alice, req): ch = APIV1_AuthenticatedClientHandshake(alice.organization_id, alice.device_id, alice.signing_key, alice.root_verify_key) with pytest.raises(InvalidMessageError): ch.process_challenge_req(packb(req))
async def test_connect_as_anonymous(anonymous_backend_sock): await anonymous_backend_sock.send(packb({"cmd": "ping", "ping": "foo"})) rep = await anonymous_backend_sock.recv() assert unpackb(rep) == {"status": "ok", "pong": "foo"}