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.