From 3017dc53c6d742368554f8218291b0a0f55c47b2 Mon Sep 17 00:00:00 2001 From: Ranim Naimi <156652078+ranim-n@users.noreply.github.com> Date: Thu, 25 Apr 2024 10:52:57 +0200 Subject: [PATCH] fix: error code when requesting a pagination limit that surpasses the configured value (#1142) * first draft in changing code error and adding configurable variables for pagination parameters * renamed variables to be be able to bind with properties * renaming variables --- .env | 4 ++++ docker-compose.yml | 4 ++++ .../com/egm/stellio/search/web/EntityHandlerTests.kt | 8 ++++---- .../stellio/search/web/TemporalEntityHandlerTests.kt | 10 +++++----- .../com/egm/stellio/shared/model/ErrorResponse.kt | 7 +++---- .../kotlin/com/egm/stellio/shared/util/ApiResponses.kt | 2 ++ .../kotlin/com/egm/stellio/shared/util/ApiUtils.kt | 2 +- .../subscription/web/SubscriptionHandlerTests.kt | 10 +++++----- 8 files changed, 28 insertions(+), 19 deletions(-) diff --git a/.env b/.env index 51726aa4b..ea880c080 100644 --- a/.env +++ b/.env @@ -22,3 +22,7 @@ SUBSCRIPTION_STELLIO_URL=http://localhost:8080 APPLICATION_TENANTS_0_ISSUER=https://sso.eglobalmark.com/auth/realms/stellio APPLICATION_TENANTS_0_NAME=urn:ngsi-ld:tenant:default APPLICATION_TENANTS_0_DBSCHEMA=public + +# Pagination config for query resources endpoints +APPLICATION_PAGINATION_LIMIT_DEFAULT=30 +APPLICATION_PAGINATION_LIMIT_MAX=100 diff --git a/docker-compose.yml b/docker-compose.yml index 02c83ccac..3bd14898c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -60,6 +60,8 @@ services: - APPLICATION_TENANTS_0_ISSUER=${APPLICATION_TENANTS_0_ISSUER} - APPLICATION_TENANTS_0_NAME=${APPLICATION_TENANTS_0_NAME} - APPLICATION_TENANTS_0_DBSCHEMA=${APPLICATION_TENANTS_0_DBSCHEMA} + - APPLICATION_PAGINATION_LIMIT-DEFAULT=${APPLICATION_PAGINATION_LIMIT_DEFAULT} + - APPLICATION_PAGINATION_LIMIT-MAX=${APPLICATION_PAGINATION_LIMIT_MAX} ports: - "8083:8083" depends_on: @@ -82,6 +84,8 @@ services: - APPLICATION_TENANTS_0_DBSCHEMA=${APPLICATION_TENANTS_0_DBSCHEMA} - SUBSCRIPTION_ENTITY-SERVICE-URL=${SUBSCRIPTION_ENTITY_SERVICE_URL} - SUBSCRIPTION_STELLIO_URL=${SUBSCRIPTION_STELLIO_URL} + - APPLICATION_PAGINATION_LIMIT-DEFAULT=${APPLICATION_PAGINATION_LIMIT_DEFAULT} + - APPLICATION_PAGINATION_LIMIT-MAX=${APPLICATION_PAGINATION_LIMIT_MAX} ports: - "8084:8084" depends_on: diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/web/EntityHandlerTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/web/EntityHandlerTests.kt index 05cc710cb..8747465ec 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/web/EntityHandlerTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/web/EntityHandlerTests.kt @@ -1024,16 +1024,16 @@ class EntityHandlerTests { } @Test - fun `get entities should return 400 if limit is greater than the maximum authorized limit`() { + fun `get entities should return 403 if limit is greater than the maximum authorized limit`() { webClient.get() .uri("/ngsi-ld/v1/entities/?type=Beehive&limit=200&offset=1") .exchange() - .expectStatus().isBadRequest + .expectStatus().isForbidden .expectBody().json( """ { - "type":"https://uri.etsi.org/ngsi-ld/errors/BadRequestData", - "title":"The request includes input data which does not meet the requirements of the operation", + "type":"https://uri.etsi.org/ngsi-ld/errors/TooManyResults", + "title":"The query associated to the operation is producing so many results that can exhaust client or server resources. It should be made more restrictive", "detail":"You asked for 200 results, but the supported maximum limit is 100" } """.trimIndent() diff --git a/search-service/src/test/kotlin/com/egm/stellio/search/web/TemporalEntityHandlerTests.kt b/search-service/src/test/kotlin/com/egm/stellio/search/web/TemporalEntityHandlerTests.kt index d0fcb3c62..0be654954 100644 --- a/search-service/src/test/kotlin/com/egm/stellio/search/web/TemporalEntityHandlerTests.kt +++ b/search-service/src/test/kotlin/com/egm/stellio/search/web/TemporalEntityHandlerTests.kt @@ -1027,11 +1027,11 @@ class TemporalEntityHandlerTests { } @Test - fun `query temporal entity should return 400 if limit is greater than the maximum authorized limit`() { + fun `query temporal entity should return 403 if limit is greater than the maximum authorized limit`() { coEvery { authorizationService.computeAccessRightFilter(any()) } returns { null } coEvery { queryService.queryTemporalEntities(any(), any()) - } throws BadRequestDataException( + } throws TooManyResultsException( "You asked for 200 results, but the supported maximum limit is 100" ) @@ -1042,12 +1042,12 @@ class TemporalEntityHandlerTests { "type=BeeHive&limit=200&offset=1" ) .exchange() - .expectStatus().isBadRequest + .expectStatus().isForbidden .expectBody().json( """ { - "type":"https://uri.etsi.org/ngsi-ld/errors/BadRequestData", - "title":"The request includes input data which does not meet the requirements of the operation", + "type":"https://uri.etsi.org/ngsi-ld/errors/TooManyResults", + "title":"The query associated to the operation is producing so many results that can exhaust client or server resources. It should be made more restrictive", "detail":"You asked for 200 results, but the supported maximum limit is 100" } """.trimIndent() diff --git a/shared/src/main/kotlin/com/egm/stellio/shared/model/ErrorResponse.kt b/shared/src/main/kotlin/com/egm/stellio/shared/model/ErrorResponse.kt index b65fa2059..3e7820cb7 100644 --- a/shared/src/main/kotlin/com/egm/stellio/shared/model/ErrorResponse.kt +++ b/shared/src/main/kotlin/com/egm/stellio/shared/model/ErrorResponse.kt @@ -40,10 +40,9 @@ data class TooComplexQueryResponse(override val detail: String) : ErrorResponse( data class TooManyResultsResponse(override val detail: String) : ErrorResponse( ErrorType.TOO_MANY_RESULTS.type, - """ - The query associated to the operation is producing so many results that can exhaust client or server resources. - It should be made more restrictive - """, + "The query associated to the operation is producing so many results " + + "that can exhaust client or server resources. " + + "It should be made more restrictive", detail ) diff --git a/shared/src/main/kotlin/com/egm/stellio/shared/util/ApiResponses.kt b/shared/src/main/kotlin/com/egm/stellio/shared/util/ApiResponses.kt index 224dead2c..5b9f5d9c6 100644 --- a/shared/src/main/kotlin/com/egm/stellio/shared/util/ApiResponses.kt +++ b/shared/src/main/kotlin/com/egm/stellio/shared/util/ApiResponses.kt @@ -84,6 +84,8 @@ fun APIException.toErrorResponse(): ResponseEntity<*> = generateErrorResponse(HttpStatus.NOT_IMPLEMENTED, NotImplementedResponse(this.message)) is LdContextNotAvailableException -> generateErrorResponse(HttpStatus.SERVICE_UNAVAILABLE, LdContextNotAvailableResponse(this.message)) + is TooManyResultsException -> + generateErrorResponse(HttpStatus.FORBIDDEN, TooManyResultsResponse(this.message)) else -> generateErrorResponse(HttpStatus.INTERNAL_SERVER_ERROR, InternalErrorResponse("$cause")) } diff --git a/shared/src/main/kotlin/com/egm/stellio/shared/util/ApiUtils.kt b/shared/src/main/kotlin/com/egm/stellio/shared/util/ApiUtils.kt index fcbded585..94583c720 100644 --- a/shared/src/main/kotlin/com/egm/stellio/shared/util/ApiUtils.kt +++ b/shared/src/main/kotlin/com/egm/stellio/shared/util/ApiUtils.kt @@ -259,7 +259,7 @@ fun parsePaginationParameters( if (count && (limit < 0 || offset < 0)) return BadRequestDataException("Offset and limit must be greater than zero").left() if (limit > limitMax) - return BadRequestDataException( + return TooManyResultsException( "You asked for $limit results, but the supported maximum limit is $limitMax" ).left() return PaginationQuery(offset, limit, count).right() diff --git a/subscription-service/src/test/kotlin/com/egm/stellio/subscription/web/SubscriptionHandlerTests.kt b/subscription-service/src/test/kotlin/com/egm/stellio/subscription/web/SubscriptionHandlerTests.kt index 01be1ed33..c01981f9c 100644 --- a/subscription-service/src/test/kotlin/com/egm/stellio/subscription/web/SubscriptionHandlerTests.kt +++ b/subscription-service/src/test/kotlin/com/egm/stellio/subscription/web/SubscriptionHandlerTests.kt @@ -465,16 +465,16 @@ class SubscriptionHandlerTests { } @Test - fun `query subscriptions should return 400 if limit is greater than the maximum authorized limit`() { + fun `query subscriptions should return 403 if limit is greater than the maximum authorized limit`() { webClient.get() .uri("/ngsi-ld/v1/subscriptions/?limit=200&offset=1") .exchange() - .expectStatus().isBadRequest + .expectStatus().isForbidden .expectBody().json( """ - { - "type":"https://uri.etsi.org/ngsi-ld/errors/BadRequestData", - "title":"The request includes input data which does not meet the requirements of the operation", + { + "type":"https://uri.etsi.org/ngsi-ld/errors/TooManyResults", + "title":"The query associated to the operation is producing so many results that can exhaust client or server resources. It should be made more restrictive", "detail":"You asked for 200 results, but the supported maximum limit is 100" } """.trimIndent()