Allow dropping tokens from the session manager for easier recovery on lookup failures.

Closes gh-684
This commit is contained in:
Mark Paluch
2023-03-20 13:26:20 +01:00
parent 62ca6ad40f
commit f90d2fe098
4 changed files with 84 additions and 4 deletions

View File

@@ -25,7 +25,6 @@ import org.springframework.http.HttpEntity;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
import org.springframework.vault.VaultException;
import org.springframework.vault.authentication.event.*;
import org.springframework.vault.client.VaultHttpHeaders;
@@ -149,11 +148,18 @@ public class LifecycleAwareSessionManager extends LifecycleAwareSessionManagerSu
@Override
public void destroy() {
revoke();
}
/**
* Revoke and drop the current {@link VaultToken}.
* @since 3.0.2
*/
public void revoke() {
Optional<TokenWrapper> token = getToken();
setToken(Optional.empty());
token.filter(TokenWrapper::isRevocable).map(TokenWrapper::getToken).ifPresent(this::revoke);
setToken(Optional.empty());
}
/**

View File

@@ -26,7 +26,6 @@ import org.springframework.beans.factory.DisposableBean;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
import org.springframework.vault.VaultException;
import org.springframework.vault.authentication.event.*;
import org.springframework.vault.client.VaultHttpHeaders;
@@ -145,6 +144,23 @@ public class ReactiveLifecycleAwareSessionManager extends LifecycleAwareSessionM
revokeNow(tokenMono);
}
/**
* Revoke and drop the current {@link VaultToken}.
* @return a mono emitting completion upon successful revocation.
* @since 3.0.2
*/
public Mono<Void> revoke() {
return doRevoke(this.token.get()).doOnSuccess(unused -> this.token.set(EMPTY));
}
/**
* Revoke and drop the current {@link VaultToken} now.
* @since 3.0.2
*/
public void revokeNow() {
revoke().block(Duration.ofSeconds(5));
}
/**
* Revoke a {@link VaultToken} now and block execution until revocation completes.
* @param tokenMono

View File

@@ -99,6 +99,33 @@ class LifecycleAwareSessionManagerIntegrationTests extends IntegrationTestSuppor
sessionManager.renewToken();
}
@Test
void shouldRevokeToken() {
final LoginToken loginToken = createLoginToken();
TokenAuthentication tokenAuthentication = new TokenAuthentication(loginToken);
LifecycleAwareSessionManager sessionManager = new LifecycleAwareSessionManager(tokenAuthentication,
this.taskScheduler, prepare().getRestTemplate());
sessionManager.getSessionToken();
sessionManager.revoke();
prepare().getVaultOperations().doWithSession(restOperations -> {
try {
restOperations.getForEntity("auth/token/lookup/{token}", Map.class, loginToken.toCharArray());
fail("Missing HttpStatusCodeException");
}
catch (HttpStatusCodeException e) {
// Compatibility across Vault versions.
assertThat(e.getStatusCode()).isIn(HttpStatus.BAD_REQUEST, HttpStatus.NOT_FOUND, HttpStatus.FORBIDDEN);
}
return null;
});
}
@Test
void shouldRevokeOnDisposal() {

View File

@@ -22,6 +22,7 @@ import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Stream;
import org.assertj.core.util.Files;
@@ -171,6 +172,36 @@ class ReactiveLifecycleAwareSessionManagerIntegrationTests extends IntegrationTe
});
}
@Test
void shouldRevokeToken() {
LoginToken loginToken = createLoginToken();
ReactiveLifecycleAwareSessionManager sessionManager = new ReactiveLifecycleAwareSessionManager(
() -> Flux.fromStream(Stream.of((VaultToken) loginToken)).next(), this.taskScheduler,
prepare().getWebClient());
sessionManager.getSessionToken() //
.as(StepVerifier::create) //
.expectNext(loginToken) //
.verifyComplete();
sessionManager.revokeNow();
prepare().getVaultOperations().doWithSession(restOperations -> {
try {
restOperations.getForEntity("auth/token/lookup/{token}", Map.class, loginToken.toCharArray());
fail("Missing HttpStatusCodeException");
}
catch (HttpStatusCodeException e) {
// Compatibility across Vault versions.
assertThat(e.getStatusCode()).isIn(HttpStatus.BAD_REQUEST, HttpStatus.NOT_FOUND, HttpStatus.FORBIDDEN);
}
return null;
});
}
private LoginToken createLoginToken() {
VaultTokenOperations tokenOperations = prepare().getVaultOperations().opsForToken();