Omit Vault namespace header for sys/init and sys/health endpoints

We now no longer add the default namespace header when issuing requests to opsForSys().init()/health().

Closes gh-534.
This commit is contained in:
Mark Paluch
2020-02-13 09:00:44 +01:00
parent f13bfdcf13
commit 1653439c71
4 changed files with 84 additions and 46 deletions

View File

@@ -233,27 +233,42 @@ public class RestTemplateBuilder {
protected RestTemplate createTemplate() {
ClientHttpRequestFactory requestFactory = this.requestFactory.get();
RestTemplateBuilderClientHttpRequestFactoryWrapper wrapper = new RestTemplateBuilderClientHttpRequestFactoryWrapper(
requestFactory, new LinkedHashMap<>(defaultHeaders),
new LinkedHashSet<>(requestCustomizers));
return VaultClients.createRestTemplate(endpointProvider, wrapper);
LinkedHashMap<String, String> defaultHeaders = new LinkedHashMap<>(
this.defaultHeaders);
LinkedHashSet<RestTemplateRequestCustomizer<ClientHttpRequest>> requestCustomizers = new LinkedHashSet<>(
this.requestCustomizers);
RestTemplate restTemplate = VaultClients.createRestTemplate(this.endpointProvider,
new RestTemplateBuilderClientHttpRequestFactoryWrapper(requestFactory,
requestCustomizers));
restTemplate.getInterceptors()
.add((httpRequest, bytes, clientHttpRequestExecution) -> {
HttpHeaders headers = httpRequest.getHeaders();
defaultHeaders.forEach((key, value) -> {
if (!headers.containsKey(key)) {
headers.add(key, value);
}
});
return clientHttpRequestExecution.execute(httpRequest, bytes);
});
return restTemplate;
}
static class RestTemplateBuilderClientHttpRequestFactoryWrapper
extends AbstractClientHttpRequestFactoryWrapper {
private final Map<String, String> defaultHeaders;
private final Set<RestTemplateRequestCustomizer<ClientHttpRequest>> requestCustomizers;
RestTemplateBuilderClientHttpRequestFactoryWrapper(
ClientHttpRequestFactory requestFactory,
Map<String, String> defaultHeaders,
Set<RestTemplateRequestCustomizer<ClientHttpRequest>> requestCustomizers) {
super(requestFactory);
this.defaultHeaders = defaultHeaders;
this.requestCustomizers = requestCustomizers;
}
@@ -262,15 +277,7 @@ public class RestTemplateBuilder {
ClientHttpRequestFactory requestFactory) throws IOException {
ClientHttpRequest request = requestFactory.createRequest(uri, httpMethod);
HttpHeaders headers = request.getHeaders();
this.defaultHeaders.forEach((key, value) -> {
if (!headers.containsKey(key)) {
headers.add(key, value);
}
});
this.requestCustomizers.forEach(it -> it.customize(request));
return request;

View File

@@ -32,6 +32,7 @@ import com.fasterxml.jackson.databind.SerializationFeature;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
@@ -39,6 +40,7 @@ import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.vault.VaultException;
import org.springframework.vault.client.VaultHttpHeaders;
import org.springframework.vault.client.VaultResponses;
import org.springframework.vault.support.Policy;
import org.springframework.vault.support.VaultHealth;
@@ -99,15 +101,17 @@ public class VaultSysTemplate implements VaultSysOperations {
@SuppressWarnings("unchecked")
public boolean isInitialized() {
return requireResponse(vaultOperations.doWithVault(restOperations -> {
return requireResponse(vaultOperations.doWithSession(restOperations -> {
try {
Map<String, Boolean> body = restOperations.getForObject("sys/init",
Map.class);
ResponseEntity<Map<String, Boolean>> body = (ResponseEntity) restOperations
.exchange("sys/init", HttpMethod.GET, emptyNamespace(null),
Map.class);
Assert.state(body != null, "Initialization response must not be null");
Assert.state(body.getBody() != null,
"Initialization response must not be null");
return body.get("initialized");
return body.getBody().get("initialized");
}
catch (HttpStatusCodeException e) {
throw VaultResponses.buildException(e);
@@ -127,7 +131,7 @@ public class VaultSysTemplate implements VaultSysOperations {
try {
ResponseEntity<VaultInitializationResponseImpl> exchange = restOperations
.exchange("sys/init", HttpMethod.PUT,
new HttpEntity<Object>(vaultInitializationRequest),
emptyNamespace(vaultInitializationRequest),
VaultInitializationResponseImpl.class);
Assert.state(exchange.getBody() != null,
@@ -388,6 +392,12 @@ public class VaultSysTemplate implements VaultSysOperations {
}
}
private static <T> HttpEntity<T> emptyNamespace(@Nullable T body) {
HttpHeaders headers = new HttpHeaders();
headers.add(VaultHttpHeaders.VAULT_NAMESPACE, "");
return new HttpEntity<>(body, headers);
}
private static class Health implements RestOperationsCallback<VaultHealth> {
@Override
@@ -395,7 +405,8 @@ public class VaultSysTemplate implements VaultSysOperations {
try {
ResponseEntity<VaultHealthImpl> healthResponse = restOperations.exchange(
"sys/health", HttpMethod.GET, null, VaultHealthImpl.class);
"sys/health", HttpMethod.GET, emptyNamespace(null),
VaultHealthImpl.class);
return healthResponse.getBody();
}
catch (RestClientResponseException responseError) {

View File

@@ -60,22 +60,6 @@ class RestTemplateBuilderUnitTests {
assertThat(restTemplate.getErrorHandler()).isSameAs(errorHandler);
}
@Test
void shouldApplyDefaultHeaders() throws IOException {
RestTemplate restTemplate = RestTemplateBuilder.builder()
.endpoint(VaultEndpoint.create("localhost", 8200))
.defaultHeader("header", "value").build();
restTemplate.getInterceptors().clear();
ClientHttpRequest request = restTemplate.getRequestFactory()
.createRequest(URI.create("/"), HttpMethod.GET);
assertThat(request.getHeaders()).containsEntry("header",
Collections.singletonList("value"));
}
@Test
void shouldApplyRequestCustomizers() throws IOException {

View File

@@ -69,6 +69,12 @@ class VaultNamespaceSecretIntegrationTests extends IntegrationTestSupport {
RestTemplateBuilder devRestTemplate;
RestTemplateBuilder maketingRestTemplate;
WebClientBuilder marketingWebClientBuilder = WebClientBuilder.builder()
.httpConnector(ClientHttpConnectorFactory.create(new ClientOptions(),
Settings.createSslConfiguration()))
.endpoint(TestRestTemplateFactory.TEST_VAULT_ENDPOINT)
.defaultHeader(VaultHttpHeaders.VAULT_NAMESPACE, "marketing");
String devToken;
String marketingToken;
@@ -166,14 +172,9 @@ class VaultNamespaceSecretIntegrationTests extends IntegrationTestSupport {
VaultTemplate marketing = new VaultTemplate(maketingRestTemplate,
new SimpleSessionManager(new TokenAuthentication(marketingToken)));
WebClientBuilder webClientBuilder = WebClientBuilder.builder()
.httpConnector(ClientHttpConnectorFactory.create(new ClientOptions(),
Settings.createSslConfiguration()))
.endpoint(TestRestTemplateFactory.TEST_VAULT_ENDPOINT)
.defaultHeader(VaultHttpHeaders.VAULT_NAMESPACE, "marketing");
ReactiveVaultTemplate reactiveMarketing = new ReactiveVaultTemplate(
webClientBuilder, () -> Mono.just(VaultToken.of(marketingToken)));
marketingWebClientBuilder,
() -> Mono.just(VaultToken.of(marketingToken)));
marketing.write("marketing-secrets/my-secret",
Collections.singletonMap("key", "marketing"));
@@ -187,6 +188,41 @@ class VaultNamespaceSecretIntegrationTests extends IntegrationTestSupport {
}).verifyComplete();
}
@Test
void shouldReportInitialized() {
VaultTemplate marketing = new VaultTemplate(maketingRestTemplate,
new SimpleSessionManager(new TokenAuthentication(marketingToken)));
assertThat(marketing.opsForSys().isInitialized()).isTrue();
}
@Test
void shouldReportHealth() {
VaultTemplate marketing = new VaultTemplate(maketingRestTemplate,
new SimpleSessionManager(new TokenAuthentication(marketingToken)));
assertThat(marketing.opsForSys().health().isInitialized()).isTrue();
}
@Test
void shouldReportReactiveInitialized() {
ReactiveVaultTemplate reactiveMarketing = new ReactiveVaultTemplate(
marketingWebClientBuilder,
() -> Mono.just(VaultToken.of(marketingToken)));
reactiveMarketing.doWithSession(webClient -> {
return webClient.get().uri("sys/init")
.header(VaultHttpHeaders.VAULT_NAMESPACE, "").exchange()
.flatMap(it -> it.bodyToMono(Map.class));
}).as(StepVerifier::create)
.assertNext(
actual -> assertThat(actual).containsEntry("initialized", true))
.verifyComplete();
}
@Configuration
static class NamespaceConfiguration extends AbstractVaultConfiguration {