Allow dropping tokens from the session manager for easier recovery on lookup failures.
Closes gh-684
This commit is contained in:
@@ -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());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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() {
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user