diff --git a/pom.xml b/pom.xml index 42111a6..2179a39 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.uid2 uid2-e2e - 4.2.17 + 4.2.18-alpha-96-SNAPSHOT 21 diff --git a/src/test/java/app/component/Core.java b/src/test/java/app/component/Core.java index 27f32cd..ccd794c 100644 --- a/src/test/java/app/component/Core.java +++ b/src/test/java/app/component/Core.java @@ -30,6 +30,11 @@ public JsonNode attest(String attestationRequest) throws Exception { return OBJECT_MAPPER.readTree(response); } + public JsonNode attestWithApiKey(String attestationRequest, String apiKey) throws Exception { + String response = HttpClient.post(getBaseUrl() + "/attest", attestationRequest, apiKey); + return OBJECT_MAPPER.readTree(response); + } + public JsonNode getWithCoreApiToken(String path) throws Exception { return getWithCoreApiToken(path, false); } diff --git a/src/test/java/common/HttpClient.java b/src/test/java/common/HttpClient.java index 47ab050..739f398 100644 --- a/src/test/java/common/HttpClient.java +++ b/src/test/java/common/HttpClient.java @@ -42,6 +42,10 @@ public JsonNode getResponseJson() throws Exception { return OBJECT_MAPPER.readTree(response); } + public int getCode() { + return code; + } + private static String createErrorMessage(HttpMethod method, String url, int code, String message, String response) { return "Unsuccessful %s request - URL: %s - Code: %d %s - Response body: %s".formatted( method, url, code, message, response diff --git a/src/test/java/suite/core/CoreTest.java b/src/test/java/suite/core/CoreTest.java index 04e95b8..4916c37 100644 --- a/src/test/java/suite/core/CoreTest.java +++ b/src/test/java/suite/core/CoreTest.java @@ -30,9 +30,61 @@ public void testAttest_EmptyAttestationRequest(Core core) { assertEquals("Unsuccessful POST request - URL: " + coreUrl + "/attest - Code: 400 Bad Request - Response body: {\"status\":\"no attestation_request attached\"}", exception.getMessage()); } + /** + * Tests that an unknown / mistyped operator key is rejected with HTTP 401 and a body that + * names the cause (reason=unrecognized_key). + */ + @ParameterizedTest(name = "/attest unrecognized key - {0}") + @MethodSource({ + "suite.core.TestData#baseArgs" + }) + public void testAttest_UnrecognizedOperatorKey(Core core) { + // A well-formed but unknown key - not present in the operators store. + String bogusOperatorKey = "UID2-O-L-000-thisKeyDoesNotExist000000000000000000000000="; + + HttpClient.HttpException exception = assertThrows( + HttpClient.HttpException.class, + () -> core.attestWithApiKey("{\"attestation_request\":\"AA==\"}", bogusOperatorKey) + ); + + assertEquals(401, exception.getCode(), "unknown operator key should be rejected with 401"); + JsonNode body = assertDoesNotThrow(exception::getResponseJson); + assertAll("401 body should name the rejection cause", + () -> assertEquals("unauthorized", body.get("status").asText()), + () -> assertEquals("unrecognized_key", body.get("reason").asText()), + () -> assertTrue(body.get("message").asText().toLowerCase().contains("not recognized"), + "message should tell the operator the key was not recognized")); + } + + /** + * Tests that a recognized-but-disabled operator key is rejected with HTTP 401 and reason=key_disabled, + * distinguishing it from an unknown key. Relies on the disabled operator key seeded in + * uid2-admin localstack (site_id 998, "Disabled Operator (E2E)"). + */ + @ParameterizedTest(name = "/attest disabled key - {0}") + @MethodSource({ + "suite.core.TestData#baseArgs" + }) + public void testAttest_DisabledOperatorKey(Core core) { + String disabledOperatorKey = "UID2-O-L-998-d1sabledKeyForE2ETestOnly00000000000000000000="; + + HttpClient.HttpException exception = assertThrows( + HttpClient.HttpException.class, + () -> core.attestWithApiKey("{\"attestation_request\":\"AA==\"}", disabledOperatorKey) + ); + + assertEquals(401, exception.getCode(), "disabled operator key should be rejected with 401"); + JsonNode body = assertDoesNotThrow(exception::getResponseJson); + assertAll("401 body should identify the key as disabled", + () -> assertEquals("unauthorized", body.get("status").asText()), + () -> assertEquals("key_disabled", body.get("reason").asText()), + () -> assertTrue(body.get("message").asText().toLowerCase().contains("disabled"), + "message should tell the operator the key is disabled")); + } + /** * Tests valid attestation request with JWT signing. - * + * * Since LocalStack generates its own RSA key material, * we dynamically fetch the public key from LocalStack's * KMS using GetPublicKey API to validate JWT signatures.