Adapt to newly introduced ReactiveSessionManager.
Closes gh-188.
This commit is contained in:
@@ -19,21 +19,34 @@ import java.net.URI;
|
||||
import java.time.Duration;
|
||||
|
||||
import reactor.core.publisher.Flux;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.ListableBeanFactory;
|
||||
import org.springframework.beans.factory.ObjectFactory;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.cloud.vault.config.VaultBootstrapConfiguration.TaskSchedulerWrapper;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.http.client.reactive.ClientHttpConnector;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.vault.authentication.AuthenticationStepsFactory;
|
||||
import org.springframework.vault.authentication.AuthenticationStepsOperator;
|
||||
import org.springframework.vault.authentication.CachingVaultTokenSupplier;
|
||||
import org.springframework.vault.authentication.ClientAuthentication;
|
||||
import org.springframework.vault.authentication.ReactiveLifecycleAwareSessionManager;
|
||||
import org.springframework.vault.authentication.ReactiveSessionManager;
|
||||
import org.springframework.vault.authentication.SessionManager;
|
||||
import org.springframework.vault.authentication.TokenAuthentication;
|
||||
import org.springframework.vault.authentication.VaultTokenSupplier;
|
||||
import org.springframework.vault.client.ReactiveVaultClients;
|
||||
import org.springframework.vault.client.VaultEndpoint;
|
||||
@@ -47,12 +60,17 @@ import org.springframework.web.reactive.function.client.WebClient;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for reactive Spring Vault support.
|
||||
* <p>
|
||||
* This auto-configuration only supports static endpoints without
|
||||
* {@link org.springframework.vault.client.VaultEndpointProvider} support as endpoint
|
||||
* providers could be potentially blocking implementations.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@Configuration
|
||||
@ConditionalOnProperty(name = "spring.cloud.vault.enabled", matchIfMissing = true)
|
||||
@ConditionalOnExpression("${spring.cloud.vault.reactive.enabled:true}")
|
||||
@ConditionalOnClass({ Flux.class, WebClient.class, ReactiveVaultOperations.class })
|
||||
@EnableConfigurationProperties({ VaultProperties.class })
|
||||
@Order(Ordered.LOWEST_PRECEDENCE - 10)
|
||||
@@ -139,28 +157,105 @@ public class ReactiveVaultBootstrapConfiguration {
|
||||
* Creates a {@link ReactiveVaultTemplate}.
|
||||
*
|
||||
* @return
|
||||
* @see #vaultTokenSupplier(AuthenticationStepsFactory)
|
||||
* @see #reactiveVaultSessionManager(BeanFactory, ObjectFactory)
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public ReactiveVaultTemplate reactiveVaultTemplate(VaultTokenSupplier tokenSupplier) {
|
||||
public ReactiveVaultTemplate reactiveVaultTemplate(
|
||||
ReactiveSessionManager tokenSupplier) {
|
||||
return new ReactiveVaultTemplate(vaultEndpoint, clientHttpConnector,
|
||||
tokenSupplier);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the {@link VaultTokenSupplier} for reactive Vault session management.
|
||||
* @return {@link ReactiveSessionManager} for reactive session use.
|
||||
* @see ReactiveSessionManager
|
||||
* @see ReactiveLifecycleAwareSessionManager
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public ReactiveSessionManager reactiveVaultSessionManager(BeanFactory beanFactory,
|
||||
ObjectFactory<TaskSchedulerWrapper> asyncTaskExecutorFactory) {
|
||||
|
||||
VaultTokenSupplier vaultTokenSupplier = beanFactory.getBean("vaultTokenSupplier",
|
||||
VaultTokenSupplier.class);
|
||||
|
||||
if (vaultProperties.getConfig().getLifecycle().isEnabled()) {
|
||||
|
||||
WebClient webClient = ReactiveVaultClients.createWebClient(vaultEndpoint,
|
||||
clientHttpConnector);
|
||||
return new ReactiveLifecycleAwareSessionManager(vaultTokenSupplier,
|
||||
asyncTaskExecutorFactory.getObject().getTaskScheduler(), webClient);
|
||||
}
|
||||
|
||||
return CachingVaultTokenSupplier.of(vaultTokenSupplier);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@link SessionManager} adapter wrapping {@link ReactiveSessionManager}.
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public SessionManager vaultSessionManager(ReactiveSessionManager sessionManager) {
|
||||
return sessionManager.getSessionToken()::block;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the {@link VaultTokenSupplier} for reactive Vault session management
|
||||
* adapting {@link ClientAuthentication} that also implement
|
||||
* {@link AuthenticationStepsFactory}.
|
||||
* @see AuthenticationStepsFactory
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(VaultTokenSupplier.class)
|
||||
public VaultTokenSupplier vaultTokenSupplier(AuthenticationStepsFactory factory) {
|
||||
@ConditionalOnMissingBean(name = "vaultTokenSupplier")
|
||||
public VaultTokenSupplier vaultTokenSupplier(ListableBeanFactory beanFactory) {
|
||||
|
||||
Assert.notNull(beanFactory, "BeanFactory must not be null");
|
||||
|
||||
String[] authStepsFactories = beanFactory
|
||||
.getBeanNamesForType(AuthenticationStepsFactory.class);
|
||||
|
||||
if (!ObjectUtils.isEmpty(authStepsFactories)) {
|
||||
|
||||
AuthenticationStepsFactory factory = beanFactory
|
||||
.getBean(AuthenticationStepsFactory.class);
|
||||
return createAuthenticationStepsOperator(factory);
|
||||
}
|
||||
|
||||
String[] clientAuthentications = beanFactory
|
||||
.getBeanNamesForType(ClientAuthentication.class);
|
||||
|
||||
if (!ObjectUtils.isEmpty(clientAuthentications)) {
|
||||
|
||||
ClientAuthentication clientAuthentication = beanFactory
|
||||
.getBean(ClientAuthentication.class);
|
||||
|
||||
if (clientAuthentication instanceof TokenAuthentication) {
|
||||
|
||||
TokenAuthentication authentication = (TokenAuthentication) clientAuthentication;
|
||||
return () -> Mono.just(authentication.login());
|
||||
}
|
||||
|
||||
if (clientAuthentication instanceof AuthenticationStepsFactory) {
|
||||
return createAuthenticationStepsOperator((AuthenticationStepsFactory) clientAuthentication);
|
||||
}
|
||||
|
||||
throw new IllegalStateException(
|
||||
String.format(
|
||||
"Cannot construct VaultTokenSupplier from %s. "
|
||||
+ "ClientAuthentication must implement AuthenticationStepsFactory or be TokenAuthentication",
|
||||
clientAuthentication));
|
||||
}
|
||||
|
||||
throw new IllegalStateException(
|
||||
"Cannot construct VaultTokenSupplier. Please configure VaultTokenSupplier bean named vaultTokenSupplier.");
|
||||
}
|
||||
|
||||
private VaultTokenSupplier createAuthenticationStepsOperator(
|
||||
AuthenticationStepsFactory factory) {
|
||||
WebClient webClient = ReactiveVaultClients.createWebClient(this.vaultEndpoint,
|
||||
this.clientHttpConnector);
|
||||
AuthenticationStepsOperator operator = new AuthenticationStepsOperator(
|
||||
factory.getAuthenticationSteps(), webClient);
|
||||
|
||||
return CachingVaultTokenSupplier.of(operator);
|
||||
return new AuthenticationStepsOperator(factory.getAuthenticationSteps(),
|
||||
webClient);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -215,7 +215,7 @@ public class VaultBootstrapConfiguration implements InitializingBean {
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public SessionManager sessionManager(ClientAuthentication clientAuthentication,
|
||||
public SessionManager vaultSessionManager(ClientAuthentication clientAuthentication,
|
||||
ObjectFactory<TaskSchedulerWrapper> asyncTaskExecutorFactory) {
|
||||
|
||||
if (vaultProperties.getConfig().getLifecycle().isEnabled()) {
|
||||
|
||||
@@ -15,13 +15,13 @@
|
||||
*/
|
||||
package org.springframework.cloud.vault.config;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link PropertyNameTransformer}.
|
||||
*
|
||||
@@ -35,7 +35,7 @@ public class PropertyNameTransformerUnitTests {
|
||||
PropertyNameTransformer transformer = new PropertyNameTransformer();
|
||||
transformer.addKeyTransformation("old-key", "new-key");
|
||||
|
||||
Map<String, String> map = new HashMap<>();
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
map.put("old-key", "value");
|
||||
map.put("other-key", "other-value");
|
||||
|
||||
@@ -51,4 +51,4 @@ public class PropertyNameTransformerUnitTests {
|
||||
|
||||
assertThat(transformer.transformProperties(null)).isNull();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
* Copyright 2017-2018 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -24,6 +24,9 @@ import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.vault.authentication.AuthenticationSteps;
|
||||
import org.springframework.vault.authentication.AuthenticationStepsFactory;
|
||||
import org.springframework.vault.authentication.LifecycleAwareSessionManager;
|
||||
import org.springframework.vault.authentication.SessionManager;
|
||||
import org.springframework.vault.authentication.SimpleSessionManager;
|
||||
import org.springframework.vault.authentication.VaultTokenSupplier;
|
||||
import org.springframework.vault.core.ReactiveVaultOperations;
|
||||
import org.springframework.vault.support.VaultToken;
|
||||
@@ -43,22 +46,42 @@ public class ReactiveVaultBootstrapConfigurationTests {
|
||||
@Test
|
||||
public void shouldConfigureTemplate() {
|
||||
|
||||
load(AuthenticationFactoryConfiguration.class);
|
||||
load(AuthenticationFactoryConfiguration.class,
|
||||
"spring.cloud.vault.config.lifecycle.enabled=false");
|
||||
|
||||
assertThat(context.getBean(ReactiveVaultOperations.class)).isNotNull();
|
||||
assertThat(context.getBean(AuthenticationStepsFactory.class)).isNotNull();
|
||||
assertThat(context.getBean(SessionManager.class)).isNotNull()
|
||||
.isNotInstanceOf(LifecycleAwareSessionManager.class)
|
||||
.isNotInstanceOf(SimpleSessionManager.class);
|
||||
assertThat(context.getBeanNamesForType(WebClient.class)).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldConfigureTemplateWithTokenSupplier() {
|
||||
|
||||
load(TokeSupplierConfiguration.class);
|
||||
load(TokenSupplierConfiguration.class,
|
||||
"spring.cloud.vault.config.lifecycle.enabled=false");
|
||||
|
||||
assertThat(context.getBean(ReactiveVaultOperations.class)).isNotNull();
|
||||
assertThat(context.getBean(SessionManager.class)).isNotNull()
|
||||
.isNotInstanceOf(LifecycleAwareSessionManager.class)
|
||||
.isNotInstanceOf(SimpleSessionManager.class);
|
||||
assertThat(context.getBeanNamesForType(WebClient.class)).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldNotConfigureReactiveSupport() {
|
||||
|
||||
load(VaultBootstrapConfiguration.class,
|
||||
"spring.cloud.vault.reactive.enabled=false",
|
||||
"spring.cloud.vault.token=foo");
|
||||
|
||||
assertThat(context.getBeanNamesForType(ReactiveVaultOperations.class)).isEmpty();
|
||||
assertThat(context.getBean(SessionManager.class)).isInstanceOf(
|
||||
LifecycleAwareSessionManager.class);
|
||||
}
|
||||
|
||||
private void load(Class<?> config, String... environment) {
|
||||
|
||||
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
|
||||
@@ -82,7 +105,7 @@ public class ReactiveVaultBootstrapConfigurationTests {
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class TokeSupplierConfiguration {
|
||||
static class TokenSupplierConfiguration {
|
||||
|
||||
@Bean
|
||||
VaultTokenSupplier vaultTokenSupplier() {
|
||||
|
||||
Reference in New Issue
Block a user