Drop VaultToken on infrastructure errors during renewal.

We now drop the VaultToken if an infrastructure error (connection refused/connection timeout/read timeout/…) occurs. Dropping the token prevents usage of an expired token.

Closes gh-222.
This commit is contained in:
Mark Paluch
2018-03-20 11:45:17 +01:00
parent b6a96451f4
commit 60d9534c9c
4 changed files with 84 additions and 15 deletions

View File

@@ -33,7 +33,6 @@ import org.springframework.vault.client.VaultResponses;
import org.springframework.vault.support.VaultResponse;
import org.springframework.vault.support.VaultToken;
import org.springframework.web.client.HttpStatusCodeException;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestOperations;
/**
@@ -213,18 +212,26 @@ public class LifecycleAwareSessionManager extends LifecycleAwareSessionManagerSu
}
catch (HttpStatusCodeException e) {
logger.debug(String.format(
"Cannot renew token, resetting token and performing re-login: %s",
VaultResponses.getError(e.getResponseBodyAsString())));
this.token = Optional.empty();
if (e.getStatusCode().is4xxClientError()) {
logger.debug(String
.format("Cannot refresh token, resetting token and performing re-login: %s",
VaultResponses.getError(e.getResponseBodyAsString())));
this.token = Optional.empty();
return false;
}
throw new VaultException(VaultResponses.getError(e.getResponseBodyAsString()));
throw new VaultException(String.format("Cannot renew token: %s",
VaultResponses.getError(e.getResponseBodyAsString())));
}
catch (RestClientException e) {
throw new VaultException("Cannot refresh token", e);
catch (RuntimeException e) {
logger.debug(String.format(
"Cannot renew token, resetting token and performing re-login: %s",
e.toString()));
this.token = Optional.empty();
throw new VaultException("Cannot renew token", e);
}
}

View File

@@ -211,23 +211,36 @@ public class ReactiveLifecycleAwareSessionManager extends
WebClientResponseException.class,
e -> {
dropCurrentToken();
if (e.getStatusCode().is4xxClientError()) {
logger.debug(String
.format("Cannot refresh token, resetting token and performing re-login: %s",
.format("Cannot renew token, resetting token and performing re-login on next token access: %s",
VaultResponses.getError(e
.getResponseBodyAsString())));
dropCurrentToken();
return EMPTY;
}
return Mono.error(new VaultException(VaultResponses
.getError(e.getResponseBodyAsString())));
logger.debug(String
.format("Cannot renew token, resetting token and performing re-login on next token access: %s",
e.toString()));
return Mono.error(new VaultException(String.format(
"Cannot renew token: %s",
VaultResponses.getError(e.getResponseBodyAsString()))));
})
.onErrorMap(WebClientException.class,
e -> new VaultException("Cannot refresh token", e))
.map(TokenWrapper::getToken);
.onErrorMap(
e -> {
dropCurrentToken();
logger.debug(String
.format("Cannot renew token, resetting token and performing re-login on next token access: %s",
e.toString()));
return new VaultException("Cannot renew token", e);
}).map(TokenWrapper::getToken);
}
private Mono<TokenWrapper> doRenew(TokenWrapper tokenWrapper) {

View File

@@ -39,6 +39,7 @@ import org.springframework.vault.support.VaultResponse;
import org.springframework.vault.support.VaultToken;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.HttpServerErrorException;
import org.springframework.web.client.ResourceAccessException;
import org.springframework.web.client.RestOperations;
import static org.assertj.core.api.Assertions.assertThat;
@@ -263,6 +264,26 @@ public class LifecycleAwareSessionManagerUnitTests {
verify(clientAuthentication, times(2)).login();
}
@Test
public void shouldReLoginIfRenewalFails() {
when(clientAuthentication.login()).thenReturn(
LoginToken.renewable("login".toCharArray(), Duration.ofSeconds(5)),
LoginToken.renewable("bar".toCharArray(), Duration.ofSeconds(5)));
when(restOperations.postForObject(anyString(), any(), eq(VaultResponse.class)))
.thenThrow(new ResourceAccessException("Connection refused"));
ArgumentCaptor<Runnable> runnableCaptor = ArgumentCaptor.forClass(Runnable.class);
sessionManager.getSessionToken();
verify(taskScheduler).schedule(runnableCaptor.capture(), any(Trigger.class));
runnableCaptor.getValue().run();
assertThat(sessionManager.getSessionToken()).isEqualTo(
LoginToken.renewable("bar".toCharArray(), Duration.ofSeconds(5)));
verify(clientAuthentication, times(2)).login();
}
@Test
public void shouldUseTaskScheduler() {

View File

@@ -291,6 +291,34 @@ public class ReactiveLifecycleAwareSessionManagerUnitTests {
verify(tokenSupplier, times(2)).getVaultToken();
}
@Test
public void shouldReLoginIfRenewFails() {
when(tokenSupplier.getVaultToken())
.thenReturn(
Mono.just(LoginToken.renewable("login".toCharArray(),
Duration.ofSeconds(5))),
Mono.just(LoginToken.renewable("bar".toCharArray(),
Duration.ofSeconds(5))));
when(responseSpec.bodyToMono(VaultResponse.class)).thenReturn(
Mono.error(new RuntimeException("foo")));
ArgumentCaptor<Runnable> runnableCaptor = ArgumentCaptor.forClass(Runnable.class);
sessionManager.getSessionToken().as(StepVerifier::create).expectNextCount(1)
.verifyComplete();
verify(taskScheduler).schedule(runnableCaptor.capture(), any(Trigger.class));
runnableCaptor.getValue().run();
sessionManager
.getSessionToken()
.as(StepVerifier::create)
.expectNext(
LoginToken.renewable("bar".toCharArray(), Duration.ofSeconds(5)))
.verifyComplete();
verify(tokenSupplier, times(2)).getVaultToken();
}
private static VaultResponse fromToken(LoginToken loginToken) {
Map<String, Object> auth = new HashMap<>();