Skip to content

Commit

Permalink
fix: allow user to remove the expiration date of an API Key
Browse files Browse the repository at this point in the history
  • Loading branch information
gaetanmaisse committed Oct 12, 2023
1 parent b7d88f5 commit 8bf3a59
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 39 deletions.
Expand Up @@ -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();
}
Expand Down
Expand Up @@ -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;
Expand Down Expand Up @@ -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());
}
}
Expand Up @@ -227,7 +227,7 @@ private void expireApiKeys(ExecutionContext executionContext, Collection<ApiKey>
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);
}
}
}
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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);
}
}

Expand Down
Expand Up @@ -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";
Expand Down

0 comments on commit 8bf3a59

Please sign in to comment.