From c83590bf7a599ab94f530c3594f6aa3dbf0b1766 Mon Sep 17 00:00:00 2001 From: Ivan Senic Date: Tue, 14 Feb 2023 14:01:49 +0100 Subject: [PATCH] closes #102: protect against metric tag explosion on unauthorized access --- src/main/resources/application.yaml | 2 + .../jsonapi/api/UnauthorizedMetricsTest.java | 84 +++++++++++++++++++ .../v1/CollectionResourceIntegrationTest.java | 22 ----- src/test/resources/application.yaml | 5 ++ 4 files changed, 91 insertions(+), 22 deletions(-) create mode 100644 src/test/java/io/stargate/sgv2/jsonapi/api/UnauthorizedMetricsTest.java diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index ec0c55c8be..e93991409f 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -47,6 +47,8 @@ quarkus: # we need to define uri templating on our own for now # note that order is important match-patterns: | + /v1/[^/]+=/v1/{namespace}, + /v1/.+/.+=/v1/{namespace}/{collection} # adapt path of the open api definitions smallrye-openapi: diff --git a/src/test/java/io/stargate/sgv2/jsonapi/api/UnauthorizedMetricsTest.java b/src/test/java/io/stargate/sgv2/jsonapi/api/UnauthorizedMetricsTest.java new file mode 100644 index 0000000000..60a9c30ae5 --- /dev/null +++ b/src/test/java/io/stargate/sgv2/jsonapi/api/UnauthorizedMetricsTest.java @@ -0,0 +1,84 @@ +package io.stargate.sgv2.jsonapi.api; + +import static io.restassured.RestAssured.given; +import static org.assertj.core.api.Assertions.assertThat; + +import io.quarkus.test.junit.QuarkusTest; +import io.quarkus.test.junit.TestProfile; +import io.restassured.http.ContentType; +import io.stargate.sgv2.common.testprofiles.NoGlobalResourcesTestProfile; +import io.stargate.sgv2.jsonapi.api.v1.CollectionResource; +import io.stargate.sgv2.jsonapi.api.v1.NamespaceResource; +import java.util.List; +import org.junit.jupiter.api.Test; + +@QuarkusTest +@TestProfile(NoGlobalResourcesTestProfile.Impl.class) +public class UnauthorizedMetricsTest { + + @Test + public void namespaceResource() { + String json = + """ + { + "createCollection": { + "name": "whatever" + } + } + """; + + // ensure namespace not in tags when no auth token used + given() + .contentType(ContentType.JSON) + .body(json) + .when() + .post(NamespaceResource.BASE_PATH, "keyspace") + .then() + .statusCode(200); + + String metrics = given().when().get("/metrics").then().statusCode(200).extract().asString(); + List httpMetrics = + metrics.lines().filter(line -> line.startsWith("http_server_requests_seconds")).toList(); + + assertThat(httpMetrics) + .allSatisfy( + line -> + assertThat(line) + .containsAnyOf( + "uri=\"/v1\"", + "uri=\"/v1/{namespace}\"", + "uri=\"/v1/{namespace}/{collection}\"")); + } + + @Test + public void collectionResource() { + String json = """ + { + "find": { + } + } + """; + + // ensure namespace not in tags when no auth token used + given() + .contentType(ContentType.JSON) + .body(json) + .when() + .post(CollectionResource.BASE_PATH, "keyspace", "collection") + .then() + .statusCode(200); + + String metrics = given().when().get("/metrics").then().statusCode(200).extract().asString(); + List httpMetrics = + metrics.lines().filter(line -> line.startsWith("http_server_requests_seconds")).toList(); + + assertThat(httpMetrics) + .allSatisfy( + line -> + assertThat(line) + .containsAnyOf( + "uri=\"/v1\"", + "uri=\"/v1/{namespace}\"", + "uri=\"/v1/{namespace}/{collection}\"")); + } +} diff --git a/src/test/java/io/stargate/sgv2/jsonapi/api/v1/CollectionResourceIntegrationTest.java b/src/test/java/io/stargate/sgv2/jsonapi/api/v1/CollectionResourceIntegrationTest.java index ab768bf0de..df2cec859b 100644 --- a/src/test/java/io/stargate/sgv2/jsonapi/api/v1/CollectionResourceIntegrationTest.java +++ b/src/test/java/io/stargate/sgv2/jsonapi/api/v1/CollectionResourceIntegrationTest.java @@ -30,28 +30,6 @@ public static void enableLog() { RestAssured.enableLoggingOfRequestAndResponseIfValidationFails(); } - @Test - public final void createCollection() { - String json = - String.format( - """ - { - "createCollection": { - "name": "%s" - } - } - """, - collectionName); - given() - .header(HttpConstants.AUTHENTICATION_TOKEN_HEADER_NAME, getAuthToken()) - .contentType(ContentType.JSON) - .body(json) - .when() - .post(NamespaceResource.BASE_PATH, keyspaceId.asInternal()) - .then() - .statusCode(200); - } - @Nested class ClientErrors { diff --git a/src/test/resources/application.yaml b/src/test/resources/application.yaml index 02621b5d42..981f48b855 100644 --- a/src/test/resources/application.yaml +++ b/src/test/resources/application.yaml @@ -3,3 +3,8 @@ stargate: data-store: ignore-bridge: true + +# change test port from 8081 (used by other SG services) +quarkus: + http: + test-port: 9080