diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-management-v2/gravitee-apim-rest-api-management-v2-rest/src/main/java/io/gravitee/rest/api/management/v2/rest/resource/api/ApiSubscriptionsResource.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-management-v2/gravitee-apim-rest-api-management-v2-rest/src/main/java/io/gravitee/rest/api/management/v2/rest/resource/api/ApiSubscriptionsResource.java index d7120e22464..d6a327147e1 100644 --- a/gravitee-apim-rest-api/gravitee-apim-rest-api-management-v2/gravitee-apim-rest-api-management-v2-rest/src/main/java/io/gravitee/rest/api/management/v2/rest/resource/api/ApiSubscriptionsResource.java +++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-management-v2/gravitee-apim-rest-api-management-v2-rest/src/main/java/io/gravitee/rest/api/management/v2/rest/resource/api/ApiSubscriptionsResource.java @@ -545,7 +545,7 @@ public Response updateApiSubscriptionApiKey( return Response.status(Response.Status.NOT_FOUND).entity(apiKeyNotFoundError(apiKeyId)).build(); } - apiKeyEntity.setExpireAt(Date.from(updateApiKey.getExpireAt().toInstant())); + apiKeyEntity.setExpireAt(updateApiKey.getExpireAt() != null ? Date.from(updateApiKey.getExpireAt().toInstant()) : null); return Response.ok(subscriptionMapper.mapToApiKey(apiKeyService.update(executionContext, apiKeyEntity))).build(); } diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-management-v2/gravitee-apim-rest-api-management-v2-rest/src/test/java/io/gravitee/rest/api/management/v2/rest/resource/api/ApiSubscriptionsResource_UpdateApiKeyTest.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-management-v2/gravitee-apim-rest-api-management-v2-rest/src/test/java/io/gravitee/rest/api/management/v2/rest/resource/api/ApiSubscriptionsResource_UpdateApiKeyTest.java index 8e70a4b2b14..e571f013cef 100644 --- a/gravitee-apim-rest-api/gravitee-apim-rest-api-management-v2/gravitee-apim-rest-api-management-v2-rest/src/test/java/io/gravitee/rest/api/management/v2/rest/resource/api/ApiSubscriptionsResource_UpdateApiKeyTest.java +++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-management-v2/gravitee-apim-rest-api-management-v2-rest/src/test/java/io/gravitee/rest/api/management/v2/rest/resource/api/ApiSubscriptionsResource_UpdateApiKeyTest.java @@ -15,11 +15,9 @@ */ package io.gravitee.rest.api.management.v2.rest.resource.api; -import static io.gravitee.common.http.HttpStatusCode.BAD_REQUEST_400; -import static io.gravitee.common.http.HttpStatusCode.FORBIDDEN_403; -import static io.gravitee.common.http.HttpStatusCode.NOT_FOUND_404; -import static io.gravitee.common.http.HttpStatusCode.OK_200; +import static io.gravitee.common.http.HttpStatusCode.*; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.when; @@ -182,4 +180,34 @@ public void should_update_api_key() { assertEquals(API_KEY_ID, apiKey.getId()); assertEquals(updateApiKey.getExpireAt().toInstant().toEpochMilli(), apiKey.getExpireAt().toInstant().toEpochMilli()); } + + @Test + void should_remove_expiration_date_of_api_key() { + final ApiKeyEntity apiKeyEntity = SubscriptionFixtures + .anApiKeyEntity() + .toBuilder() + .id(API_KEY_ID) + .subscriptions( + Set.of( + SubscriptionFixtures.aSubscriptionEntity().toBuilder().id("ANOTHER-SUBSCRIPTION").build(), + SubscriptionFixtures.aSubscriptionEntity().toBuilder().id(SUBSCRIPTION).build() + ) + ) + .build(); + + when(subscriptionService.findById(SUBSCRIPTION)).thenReturn(SubscriptionFixtures.aSubscriptionEntity()); + when(applicationService.findById(GraviteeContext.getExecutionContext(), APPLICATION)) + .thenReturn(ApplicationFixtures.anApplicationEntity().toBuilder().id(APPLICATION).build()); + when(apiKeyService.findById(GraviteeContext.getExecutionContext(), API_KEY_ID)).thenReturn(apiKeyEntity); + when(apiKeyService.update(any(), any())).thenAnswer(i -> i.getArgument(1)); + + final UpdateApiKey updateApiKey = UpdateApiKey.builder().expireAt(null).build(); + final Response response = rootTarget().request().put(Entity.json(updateApiKey)); + + assertEquals(OK_200, response.getStatus()); + + var apiKey = response.readEntity(ApiKey.class); + assertEquals(API_KEY_ID, apiKey.getId()); + assertNull(apiKey.getExpireAt()); + } } diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/rest/api/service/impl/ApiKeyServiceImpl.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/rest/api/service/impl/ApiKeyServiceImpl.java index 08b4bf30969..27a7ce5a437 100644 --- a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/rest/api/service/impl/ApiKeyServiceImpl.java +++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/main/java/io/gravitee/rest/api/service/impl/ApiKeyServiceImpl.java @@ -227,7 +227,7 @@ private void expireApiKeys(ExecutionContext executionContext, Collection for (ApiKey apiKey : apiKeys) { ApiKeyEntity apiKeyEntity = convert(executionContext, apiKey); if (!apiKey.equals(activeApiKey) && !apiKeyEntity.isExpired()) { - setExpiration(executionContext, expirationDate, apiKeyEntity, apiKey); + updateExpirationDate(executionContext, expirationDate, apiKeyEntity, apiKey); } } } @@ -511,12 +511,7 @@ public ApiKeyEntity update(ExecutionContext executionContext, ApiKeyEntity apiKe key.setSubscriptions(apiKeyEntity.getSubscriptionIds()); key.setPaused(apiKeyEntity.isPaused()); - if (apiKeyEntity.getExpireAt() != null) { - setExpiration(executionContext, apiKeyEntity.getExpireAt(), apiKeyEntity, key); - } else { - key.setUpdatedAt(new Date()); - apiKeyRepository.update(key); - } + updateExpirationDate(executionContext, apiKeyEntity.getExpireAt(), apiKeyEntity, key); return convert(executionContext, key); } catch (TechnicalException ex) { @@ -616,49 +611,51 @@ public void delete(String apiKey) { */ } - private void setExpiration(ExecutionContext executionContext, Date expirationDate, ApiKeyEntity apiKeyEntity, ApiKey key) + private void updateExpirationDate(ExecutionContext executionContext, Date expirationDate, ApiKeyEntity apiKeyEntity, ApiKey key) throws TechnicalException { final Date now = new Date(); - if (now.after(expirationDate)) { - expirationDate = now; + key.setUpdatedAt(now); + if (key.isRevoked()) { + apiKeyRepository.update(key); + return; } - key.setUpdatedAt(now); + // If the expiration date is before now, then the key is already expired + if (expirationDate != null && expirationDate.before(now)) { + expirationDate = now; + } - if (!key.isRevoked()) { - // If API Key is not shared - // The expired date must be <= than the subscription end date + // If the API Key is not shared + // The expired date must be <= than the subscription end date + if ( + apiKeyEntity.getApplication() != null && + !apiKeyEntity.getApplication().hasApiKeySharedMode() && + !key.getSubscriptions().isEmpty() + ) { + SubscriptionEntity subscription = subscriptionService.findById(key.getSubscriptions().get(0)); if ( - apiKeyEntity.getApplication() != null && - !apiKeyEntity.getApplication().hasApiKeySharedMode() && - !key.getSubscriptions().isEmpty() + subscription.getEndingAt() != null && (expirationDate == null || subscription.getEndingAt().compareTo(expirationDate) < 0) ) { - SubscriptionEntity subscription = subscriptionService.findById(key.getSubscriptions().get(0)); - if ( - subscription.getEndingAt() != null && - (expirationDate == null || subscription.getEndingAt().compareTo(expirationDate) < 0) - ) { - expirationDate = subscription.getEndingAt(); - } + expirationDate = subscription.getEndingAt(); } + } - ApiKey oldkey = new ApiKey(key); - key.setExpireAt(expirationDate); - key.setDaysToExpirationOnLastNotification(null); - apiKeyRepository.update(key); + ApiKey oldkey = new ApiKey(key); + key.setExpireAt(expirationDate); + key.setDaysToExpirationOnLastNotification(null); + apiKeyRepository.update(key); + + // Audit + createAuditLog(executionContext, convert(executionContext, key), oldkey, APIKEY_EXPIRED, key.getUpdatedAt()); - //notify + // If there is an expiration date then notify + if (expirationDate != null) { NotificationParamsBuilder paramsBuilder = new NotificationParamsBuilder(); if (key.getExpireAt() != null && now.before(key.getExpireAt())) { paramsBuilder.expirationDate(key.getExpireAt()); } triggerNotifierService(executionContext, ApiHook.APIKEY_EXPIRED, key, paramsBuilder); - - // Audit - createAuditLog(executionContext, convert(executionContext, key), oldkey, APIKEY_EXPIRED, key.getUpdatedAt()); - } else { - apiKeyRepository.update(key); } } diff --git a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/io/gravitee/rest/api/service/impl/ApiKeyServiceTest.java b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/io/gravitee/rest/api/service/impl/ApiKeyServiceTest.java index 8694ec0d9af..ed55d7016cd 100644 --- a/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/io/gravitee/rest/api/service/impl/ApiKeyServiceTest.java +++ b/gravitee-apim-rest-api/gravitee-apim-rest-api-service/src/test/java/io/gravitee/rest/api/service/impl/ApiKeyServiceTest.java @@ -824,6 +824,25 @@ public void shouldFindBySubscription() throws TechnicalException { assertEquals("last", bySubscription.get(2).getKey()); } + @Test + public void shouldRemoveExpirationDate() throws TechnicalException { + ApiKey existingApiKey = new ApiKey(); + existingApiKey.setExpireAt(Date.from(Instant.now().plusSeconds(60))); + when(apiKeyRepository.findById("api-key-id")).thenReturn(Optional.of(existingApiKey)); + + ApiKeyEntity apiKeyEntity = new ApiKeyEntity(); + apiKeyEntity.setId("api-key-id"); + apiKeyEntity.setKey("ABC"); + apiKeyEntity.setSubscriptions(Set.of()); + apiKeyEntity.setRevoked(true); + apiKeyEntity.setExpireAt(null); + + apiKeyService.update(GraviteeContext.getExecutionContext(), apiKeyEntity); + + verify(apiKeyRepository, times(1)).update(existingApiKey); + verifyNoInteractions(notifierService); + } + @Test public void canCreate_should_return_true_cause_key_doesnt_exists_yet() throws Exception { String apiKeyToCreate = "apikey-i-want-to-create";