Integrate spring-javaformat
Closes gh-564.
This commit is contained in:
29
pom.xml
29
pom.xml
@@ -233,6 +233,21 @@
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>io.spring.javaformat</groupId>
|
||||
<artifactId>spring-javaformat-maven-plugin</artifactId>
|
||||
<version>0.0.22</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>validate</phase>
|
||||
<inherited>true</inherited>
|
||||
<goals>
|
||||
<goal>apply</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-maven-plugin</artifactId>
|
||||
@@ -748,13 +763,13 @@
|
||||
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<pluginRepositories>
|
||||
<pluginRepository>
|
||||
<id>spring-plugins-release</id>
|
||||
<url>https://repo.spring.io/plugins-release</url>
|
||||
</pluginRepository>
|
||||
</pluginRepositories>
|
||||
</profile>
|
||||
</profiles>
|
||||
|
||||
<pluginRepositories>
|
||||
<pluginRepository>
|
||||
<id>spring-plugins-release</id>
|
||||
<url>https://repo.spring.io/plugins-release</url>
|
||||
</pluginRepository>
|
||||
</pluginRepositories>
|
||||
</project>
|
||||
|
||||
@@ -27,7 +27,6 @@ public class VaultException extends NestedRuntimeException {
|
||||
|
||||
/**
|
||||
* Create a {@code VaultException} with the specified detail message.
|
||||
*
|
||||
* @param msg the detail message.
|
||||
*/
|
||||
public VaultException(String msg) {
|
||||
@@ -37,11 +36,11 @@ public class VaultException extends NestedRuntimeException {
|
||||
/**
|
||||
* Create a {@code VaultException} with the specified detail message and nested
|
||||
* exception.
|
||||
*
|
||||
* @param msg the detail message.
|
||||
* @param cause the nested exception.
|
||||
*/
|
||||
public VaultException(String msg, Throwable cause) {
|
||||
super(msg, cause);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -131,5 +131,7 @@ public @interface VaultPropertySource {
|
||||
* expires.
|
||||
*/
|
||||
ROTATE;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -56,8 +56,8 @@ import org.springframework.vault.core.util.PropertyTransformers;
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
class VaultPropertySourceRegistrar implements ImportBeanDefinitionRegistrar,
|
||||
BeanFactoryPostProcessor, EnvironmentAware {
|
||||
class VaultPropertySourceRegistrar
|
||||
implements ImportBeanDefinitionRegistrar, BeanFactoryPostProcessor, EnvironmentAware {
|
||||
|
||||
private @Nullable Environment environment;
|
||||
|
||||
@@ -67,24 +67,21 @@ class VaultPropertySourceRegistrar implements ImportBeanDefinitionRegistrar,
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
|
||||
throws BeansException {
|
||||
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
|
||||
|
||||
ConfigurableEnvironment env = beanFactory.getBean(ConfigurableEnvironment.class);
|
||||
MutablePropertySources propertySources = env.getPropertySources();
|
||||
|
||||
registerPropertySources(beanFactory
|
||||
.getBeansOfType(
|
||||
org.springframework.vault.core.env.VaultPropertySource.class)
|
||||
.values(), propertySources);
|
||||
registerPropertySources(
|
||||
beanFactory.getBeansOfType(org.springframework.vault.core.env.VaultPropertySource.class).values(),
|
||||
propertySources);
|
||||
|
||||
registerPropertySources(beanFactory.getBeansOfType(
|
||||
org.springframework.vault.core.env.LeaseAwareVaultPropertySource.class)
|
||||
.values(), propertySources);
|
||||
registerPropertySources(beanFactory
|
||||
.getBeansOfType(org.springframework.vault.core.env.LeaseAwareVaultPropertySource.class).values(),
|
||||
propertySources);
|
||||
}
|
||||
|
||||
private void registerPropertySources(
|
||||
Collection<? extends PropertySource<?>> propertySources,
|
||||
private void registerPropertySources(Collection<? extends PropertySource<?>> propertySources,
|
||||
MutablePropertySources mutablePropertySources) {
|
||||
|
||||
for (PropertySource<?> vaultPropertySource : propertySources) {
|
||||
@@ -98,23 +95,20 @@ class VaultPropertySourceRegistrar implements ImportBeanDefinitionRegistrar,
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerBeanDefinitions(AnnotationMetadata annotationMetadata,
|
||||
BeanDefinitionRegistry registry) {
|
||||
public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry registry) {
|
||||
|
||||
Assert.notNull(annotationMetadata, "AnnotationMetadata must not be null");
|
||||
Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
|
||||
|
||||
if (!registry.isBeanNameInUse("VaultPropertySourceRegistrar")) {
|
||||
registry.registerBeanDefinition("VaultPropertySourceRegistrar",
|
||||
BeanDefinitionBuilder //
|
||||
.rootBeanDefinition(VaultPropertySourceRegistrar.class) //
|
||||
.setRole(BeanDefinition.ROLE_INFRASTRUCTURE) //
|
||||
.getBeanDefinition());
|
||||
registry.registerBeanDefinition("VaultPropertySourceRegistrar", BeanDefinitionBuilder //
|
||||
.rootBeanDefinition(VaultPropertySourceRegistrar.class) //
|
||||
.setRole(BeanDefinition.ROLE_INFRASTRUCTURE) //
|
||||
.getBeanDefinition());
|
||||
}
|
||||
|
||||
Set<AnnotationAttributes> propertySources = attributesForRepeatable(
|
||||
annotationMetadata, VaultPropertySources.class.getName(),
|
||||
VaultPropertySource.class.getName());
|
||||
Set<AnnotationAttributes> propertySources = attributesForRepeatable(annotationMetadata,
|
||||
VaultPropertySources.class.getName(), VaultPropertySource.class.getName());
|
||||
|
||||
int counter = 0;
|
||||
|
||||
@@ -124,19 +118,14 @@ class VaultPropertySourceRegistrar implements ImportBeanDefinitionRegistrar,
|
||||
String ref = propertySource.getString("vaultTemplateRef");
|
||||
String propertyNamePrefix = propertySource.getString("propertyNamePrefix");
|
||||
Renewal renewal = propertySource.getEnum("renewal");
|
||||
boolean ignoreSecretNotFound = propertySource
|
||||
.getBoolean("ignoreSecretNotFound");
|
||||
boolean ignoreSecretNotFound = propertySource.getBoolean("ignoreSecretNotFound");
|
||||
|
||||
Assert.isTrue(paths.length > 0,
|
||||
"At least one @VaultPropertySource(value) location is required");
|
||||
Assert.isTrue(paths.length > 0, "At least one @VaultPropertySource(value) location is required");
|
||||
|
||||
Assert.hasText(ref,
|
||||
"'vaultTemplateRef' in @EnableVaultPropertySource must not be empty");
|
||||
Assert.hasText(ref, "'vaultTemplateRef' in @EnableVaultPropertySource must not be empty");
|
||||
|
||||
PropertyTransformer propertyTransformer = StringUtils
|
||||
.hasText(propertyNamePrefix)
|
||||
? PropertyTransformers.propertyNamePrefix(propertyNamePrefix)
|
||||
: PropertyTransformers.noop();
|
||||
PropertyTransformer propertyTransformer = StringUtils.hasText(propertyNamePrefix)
|
||||
? PropertyTransformers.propertyNamePrefix(propertyNamePrefix) : PropertyTransformers.noop();
|
||||
|
||||
for (String propertyPath : paths) {
|
||||
|
||||
@@ -144,9 +133,8 @@ class VaultPropertySourceRegistrar implements ImportBeanDefinitionRegistrar,
|
||||
continue;
|
||||
}
|
||||
|
||||
AbstractBeanDefinition beanDefinition = createBeanDefinition(ref, renewal,
|
||||
propertyTransformer, ignoreSecretNotFound,
|
||||
potentiallyResolveRequiredPlaceholders(propertyPath));
|
||||
AbstractBeanDefinition beanDefinition = createBeanDefinition(ref, renewal, propertyTransformer,
|
||||
ignoreSecretNotFound, potentiallyResolveRequiredPlaceholders(propertyPath));
|
||||
|
||||
do {
|
||||
String beanName = "vaultPropertySource#" + counter;
|
||||
@@ -164,23 +152,19 @@ class VaultPropertySourceRegistrar implements ImportBeanDefinitionRegistrar,
|
||||
}
|
||||
|
||||
private String potentiallyResolveRequiredPlaceholders(String expression) {
|
||||
return this.environment != null
|
||||
? this.environment.resolveRequiredPlaceholders(expression)
|
||||
: expression;
|
||||
return this.environment != null ? this.environment.resolveRequiredPlaceholders(expression) : expression;
|
||||
}
|
||||
|
||||
private AbstractBeanDefinition createBeanDefinition(String ref, Renewal renewal,
|
||||
PropertyTransformer propertyTransformer, boolean ignoreResourceNotFound,
|
||||
String propertyPath) {
|
||||
PropertyTransformer propertyTransformer, boolean ignoreResourceNotFound, String propertyPath) {
|
||||
|
||||
BeanDefinitionBuilder builder;
|
||||
|
||||
if (isRenewable(renewal)) {
|
||||
builder = BeanDefinitionBuilder.rootBeanDefinition(
|
||||
org.springframework.vault.core.env.LeaseAwareVaultPropertySource.class);
|
||||
builder = BeanDefinitionBuilder
|
||||
.rootBeanDefinition(org.springframework.vault.core.env.LeaseAwareVaultPropertySource.class);
|
||||
|
||||
RequestedSecret requestedSecret = renewal == Renewal.ROTATE
|
||||
? RequestedSecret.rotating(propertyPath)
|
||||
RequestedSecret requestedSecret = renewal == Renewal.ROTATE ? RequestedSecret.rotating(propertyPath)
|
||||
: RequestedSecret.renewable(propertyPath);
|
||||
|
||||
builder.addConstructorArgValue(propertyPath);
|
||||
@@ -188,8 +172,8 @@ class VaultPropertySourceRegistrar implements ImportBeanDefinitionRegistrar,
|
||||
builder.addConstructorArgValue(requestedSecret);
|
||||
}
|
||||
else {
|
||||
builder = BeanDefinitionBuilder.rootBeanDefinition(
|
||||
org.springframework.vault.core.env.VaultPropertySource.class);
|
||||
builder = BeanDefinitionBuilder
|
||||
.rootBeanDefinition(org.springframework.vault.core.env.VaultPropertySource.class);
|
||||
|
||||
builder.addConstructorArgValue(propertyPath);
|
||||
builder.addConstructorArgReference(ref);
|
||||
@@ -208,18 +192,15 @@ class VaultPropertySourceRegistrar implements ImportBeanDefinitionRegistrar,
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
static Set<AnnotationAttributes> attributesForRepeatable(AnnotationMetadata metadata,
|
||||
String containerClassName, String annotationClassName) {
|
||||
static Set<AnnotationAttributes> attributesForRepeatable(AnnotationMetadata metadata, String containerClassName,
|
||||
String annotationClassName) {
|
||||
|
||||
Set<AnnotationAttributes> result = new LinkedHashSet<>();
|
||||
addAttributesIfNotNull(result,
|
||||
metadata.getAnnotationAttributes(annotationClassName, false));
|
||||
addAttributesIfNotNull(result, metadata.getAnnotationAttributes(annotationClassName, false));
|
||||
|
||||
Map<String, Object> container = metadata
|
||||
.getAnnotationAttributes(containerClassName, false);
|
||||
Map<String, Object> container = metadata.getAnnotationAttributes(containerClassName, false);
|
||||
if (container != null && container.containsKey("value")) {
|
||||
for (Map<String, Object> containedAttributes : (Map<String, Object>[]) container
|
||||
.get("value")) {
|
||||
for (Map<String, Object> containedAttributes : (Map<String, Object>[]) container.get("value")) {
|
||||
addAttributesIfNotNull(result, containedAttributes);
|
||||
}
|
||||
}
|
||||
@@ -232,4 +213,5 @@ class VaultPropertySourceRegistrar implements ImportBeanDefinitionRegistrar,
|
||||
result.add(AnnotationAttributes.fromMap(attributes));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -42,4 +42,5 @@ import org.springframework.context.annotation.Import;
|
||||
public @interface VaultPropertySources {
|
||||
|
||||
VaultPropertySource[] value();
|
||||
|
||||
}
|
||||
|
||||
@@ -40,8 +40,7 @@ import org.springframework.web.client.RestOperations;
|
||||
* @deprecated since 2.2. Use {@link AppRoleAuthentication}.
|
||||
*/
|
||||
@Deprecated
|
||||
public class AppIdAuthentication
|
||||
implements ClientAuthentication, AuthenticationStepsFactory {
|
||||
public class AppIdAuthentication implements ClientAuthentication, AuthenticationStepsFactory {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(AppIdAuthentication.class);
|
||||
|
||||
@@ -52,12 +51,10 @@ public class AppIdAuthentication
|
||||
/**
|
||||
* Create a {@link AppIdAuthentication} using {@link AppIdAuthenticationOptions} and
|
||||
* {@link RestOperations}.
|
||||
*
|
||||
* @param options must not be {@literal null}.
|
||||
* @param restOperations must not be {@literal null}.
|
||||
*/
|
||||
public AppIdAuthentication(AppIdAuthenticationOptions options,
|
||||
RestOperations restOperations) {
|
||||
public AppIdAuthentication(AppIdAuthenticationOptions options, RestOperations restOperations) {
|
||||
|
||||
Assert.notNull(options, "AppIdAuthenticationOptions must not be null");
|
||||
Assert.notNull(restOperations, "RestOperations must not be null");
|
||||
@@ -69,19 +66,16 @@ public class AppIdAuthentication
|
||||
/**
|
||||
* Creates a {@link AuthenticationSteps} for AppId authentication given
|
||||
* {@link AppIdAuthenticationOptions}.
|
||||
*
|
||||
* @param options must not be {@literal null}.
|
||||
* @return {@link AuthenticationSteps} for AppId authentication.
|
||||
* @since 2.0
|
||||
*/
|
||||
public static AuthenticationSteps createAuthenticationSteps(
|
||||
AppIdAuthenticationOptions options) {
|
||||
public static AuthenticationSteps createAuthenticationSteps(AppIdAuthenticationOptions options) {
|
||||
|
||||
Assert.notNull(options, "AppIdAuthenticationOptions must not be null");
|
||||
|
||||
return AuthenticationSteps
|
||||
.fromSupplier(() -> getAppIdLogin(options.getAppId(),
|
||||
options.getUserIdMechanism().createUserId())) //
|
||||
.fromSupplier(() -> getAppIdLogin(options.getAppId(), options.getUserIdMechanism().createUserId())) //
|
||||
.login(AuthenticationUtil.getLoginPath(options.getPath()));
|
||||
}
|
||||
|
||||
@@ -92,20 +86,19 @@ public class AppIdAuthentication
|
||||
|
||||
@Override
|
||||
public AuthenticationSteps getAuthenticationSteps() {
|
||||
return createAuthenticationSteps(options);
|
||||
return createAuthenticationSteps(this.options);
|
||||
}
|
||||
|
||||
private VaultToken createTokenUsingAppId() {
|
||||
|
||||
Map<String, String> login = getAppIdLogin(options.getAppId(),
|
||||
options.getUserIdMechanism().createUserId());
|
||||
Map<String, String> login = getAppIdLogin(this.options.getAppId(),
|
||||
this.options.getUserIdMechanism().createUserId());
|
||||
|
||||
try {
|
||||
VaultResponse response = restOperations.postForObject(AuthenticationUtil.getLoginPath(options.getPath()),
|
||||
login, VaultResponse.class);
|
||||
VaultResponse response = this.restOperations
|
||||
.postForObject(AuthenticationUtil.getLoginPath(this.options.getPath()), login, VaultResponse.class);
|
||||
|
||||
Assert.state(response != null && response.getAuth() != null,
|
||||
"Auth field must not be null");
|
||||
Assert.state(response != null && response.getAuth() != null, "Auth field must not be null");
|
||||
|
||||
logger.debug("Login successful using AppId authentication");
|
||||
|
||||
@@ -125,4 +118,5 @@ public class AppIdAuthentication
|
||||
|
||||
return login;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -50,8 +50,7 @@ public class AppIdAuthenticationOptions {
|
||||
*/
|
||||
private final AppIdUserIdMechanism userIdMechanism;
|
||||
|
||||
private AppIdAuthenticationOptions(String path, String appId,
|
||||
AppIdUserIdMechanism userIdMechanism) {
|
||||
private AppIdAuthenticationOptions(String path, String appId, AppIdUserIdMechanism userIdMechanism) {
|
||||
|
||||
this.path = path;
|
||||
this.appId = appId;
|
||||
@@ -69,21 +68,21 @@ public class AppIdAuthenticationOptions {
|
||||
* @return the mount path.
|
||||
*/
|
||||
public String getPath() {
|
||||
return path;
|
||||
return this.path;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the AppId.
|
||||
*/
|
||||
public String getAppId() {
|
||||
return appId;
|
||||
return this.appId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the {@link AppIdUserIdMechanism}.
|
||||
*/
|
||||
public AppIdUserIdMechanism getUserIdMechanism() {
|
||||
return userIdMechanism;
|
||||
return this.userIdMechanism;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -102,7 +101,6 @@ public class AppIdAuthenticationOptions {
|
||||
|
||||
/**
|
||||
* Configure the mount path.
|
||||
*
|
||||
* @param path must not be empty or {@literal null}.
|
||||
* @return {@code this} {@link AppIdAuthenticationOptionsBuilder}.
|
||||
* @see #DEFAULT_APPID_AUTHENTICATION_PATH
|
||||
@@ -117,7 +115,6 @@ public class AppIdAuthenticationOptions {
|
||||
|
||||
/**
|
||||
* Configure the AppId.
|
||||
*
|
||||
* @param appId must not be empty or {@literal null}.
|
||||
* @return {@code this} {@link AppIdAuthenticationOptionsBuilder}.
|
||||
*/
|
||||
@@ -131,12 +128,10 @@ public class AppIdAuthenticationOptions {
|
||||
|
||||
/**
|
||||
* Configure the {@link AppIdUserIdMechanism}.
|
||||
*
|
||||
* @param userIdMechanism must not be {@literal null}.
|
||||
* @return {@code this} {@link AppIdAuthenticationOptionsBuilder}.
|
||||
*/
|
||||
public AppIdAuthenticationOptionsBuilder userIdMechanism(
|
||||
AppIdUserIdMechanism userIdMechanism) {
|
||||
public AppIdAuthenticationOptionsBuilder userIdMechanism(AppIdUserIdMechanism userIdMechanism) {
|
||||
|
||||
Assert.notNull(userIdMechanism, "AppIdUserIdMechanism must not be null");
|
||||
|
||||
@@ -147,15 +142,16 @@ public class AppIdAuthenticationOptions {
|
||||
/**
|
||||
* Build a new {@link AppIdAuthenticationOptions} instance. Requires
|
||||
* {@link #userIdMechanism(AppIdUserIdMechanism)} to be configured.
|
||||
*
|
||||
* @return a new {@link AppIdAuthenticationOptions}.
|
||||
*/
|
||||
public AppIdAuthenticationOptions build() {
|
||||
|
||||
Assert.hasText(appId, "AppId must not be empty");
|
||||
Assert.notNull(userIdMechanism, "AppIdUserIdMechanism must not be null");
|
||||
Assert.hasText(this.appId, "AppId must not be empty");
|
||||
Assert.notNull(this.userIdMechanism, "AppIdUserIdMechanism must not be null");
|
||||
|
||||
return new AppIdAuthenticationOptions(path, appId, userIdMechanism);
|
||||
return new AppIdAuthenticationOptions(this.path, this.appId, this.userIdMechanism);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -30,8 +30,8 @@ public interface AppIdUserIdMechanism {
|
||||
|
||||
/**
|
||||
* Create a UserId for AppId authentication.
|
||||
*
|
||||
* @return the UserId.
|
||||
*/
|
||||
String createUserId();
|
||||
|
||||
}
|
||||
|
||||
@@ -63,8 +63,7 @@ import static org.springframework.vault.authentication.AuthenticationUtil.getLog
|
||||
* @see <a href="https://www.vaultproject.io/docs/auth/approle.html">Auth Backend:
|
||||
* AppRole</a>
|
||||
*/
|
||||
public class AppRoleAuthentication
|
||||
implements ClientAuthentication, AuthenticationStepsFactory {
|
||||
public class AppRoleAuthentication implements ClientAuthentication, AuthenticationStepsFactory {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(AppRoleAuthentication.class);
|
||||
|
||||
@@ -75,12 +74,10 @@ public class AppRoleAuthentication
|
||||
/**
|
||||
* Create a {@link AppRoleAuthentication} using {@link AppRoleAuthenticationOptions}
|
||||
* and {@link RestOperations}.
|
||||
*
|
||||
* @param options must not be {@literal null}.
|
||||
* @param restOperations must not be {@literal null}.
|
||||
*/
|
||||
public AppRoleAuthentication(AppRoleAuthenticationOptions options,
|
||||
RestOperations restOperations) {
|
||||
public AppRoleAuthentication(AppRoleAuthenticationOptions options, RestOperations restOperations) {
|
||||
|
||||
Assert.notNull(options, "AppRoleAuthenticationOptions must not be null");
|
||||
Assert.notNull(restOperations, "RestOperations must not be null");
|
||||
@@ -92,35 +89,30 @@ public class AppRoleAuthentication
|
||||
/**
|
||||
* Creates a {@link AuthenticationSteps} for AppRole authentication given
|
||||
* {@link AppRoleAuthenticationOptions}.
|
||||
*
|
||||
* @param options must not be {@literal null}.
|
||||
* @return {@link AuthenticationSteps} for AppRole authentication.
|
||||
* @since 2.0
|
||||
*/
|
||||
public static AuthenticationSteps createAuthenticationSteps(
|
||||
AppRoleAuthenticationOptions options) {
|
||||
public static AuthenticationSteps createAuthenticationSteps(AppRoleAuthenticationOptions options) {
|
||||
|
||||
Assert.notNull(options, "AppRoleAuthenticationOptions must not be null");
|
||||
|
||||
RoleId roleId = options.getRoleId();
|
||||
SecretId secretId = options.getSecretId();
|
||||
|
||||
return getAuthenticationSteps(options, roleId, secretId)
|
||||
.login(getLoginPath(options.getPath()));
|
||||
return getAuthenticationSteps(options, roleId, secretId).login(getLoginPath(options.getPath()));
|
||||
}
|
||||
|
||||
private static Node<Map<String, String>> getAuthenticationSteps(
|
||||
AppRoleAuthenticationOptions options, RoleId roleId, SecretId secretId) {
|
||||
private static Node<Map<String, String>> getAuthenticationSteps(AppRoleAuthenticationOptions options, RoleId roleId,
|
||||
SecretId secretId) {
|
||||
|
||||
Node<String> roleIdSteps = getRoleIdSteps(options, roleId);
|
||||
Node<String> secretIdSteps = getSecretIdSteps(options, secretId);
|
||||
|
||||
return roleIdSteps.zipWith(secretIdSteps)
|
||||
.map(it -> getAppRoleLoginBody(it.getLeft(), it.getRight()));
|
||||
return roleIdSteps.zipWith(secretIdSteps).map(it -> getAppRoleLoginBody(it.getLeft(), it.getRight()));
|
||||
}
|
||||
|
||||
private static Node<String> getRoleIdSteps(AppRoleAuthenticationOptions options,
|
||||
RoleId roleId) {
|
||||
private static Node<String> getRoleIdSteps(AppRoleAuthenticationOptions options, RoleId roleId) {
|
||||
|
||||
if (roleId instanceof Provided) {
|
||||
return AuthenticationSteps.fromSupplier(((Provided) roleId)::getValue);
|
||||
@@ -131,24 +123,19 @@ public class AppRoleAuthentication
|
||||
HttpHeaders headers = createHttpHeaders(((Pull) roleId).getInitialToken());
|
||||
|
||||
return AuthenticationSteps
|
||||
.fromHttpRequest(get(getRoleIdIdPath(options)).with(headers)
|
||||
.as(VaultResponse.class))
|
||||
.map(vaultResponse -> (String) vaultResponse.getRequiredData()
|
||||
.get("role_id"));
|
||||
.fromHttpRequest(get(getRoleIdIdPath(options)).with(headers).as(VaultResponse.class))
|
||||
.map(vaultResponse -> (String) vaultResponse.getRequiredData().get("role_id"));
|
||||
}
|
||||
|
||||
if (roleId instanceof Wrapped) {
|
||||
return unwrapResponse(options.getUnwrappingEndpoints(),
|
||||
((Wrapped) roleId).getInitialToken())
|
||||
.map(vaultResponse -> (String) vaultResponse.getRequiredData()
|
||||
.get("role_id"));
|
||||
return unwrapResponse(options.getUnwrappingEndpoints(), ((Wrapped) roleId).getInitialToken())
|
||||
.map(vaultResponse -> (String) vaultResponse.getRequiredData().get("role_id"));
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("Unknown RoleId configuration: " + roleId);
|
||||
}
|
||||
|
||||
private static Node<String> getSecretIdSteps(AppRoleAuthenticationOptions options,
|
||||
SecretId secretId) {
|
||||
private static Node<String> getSecretIdSteps(AppRoleAuthenticationOptions options, SecretId secretId) {
|
||||
|
||||
if (secretId instanceof Provided) {
|
||||
return AuthenticationSteps.fromSupplier(((Provided) secretId)::getValue);
|
||||
@@ -158,31 +145,25 @@ public class AppRoleAuthentication
|
||||
HttpHeaders headers = createHttpHeaders(((Pull) secretId).getInitialToken());
|
||||
|
||||
return AuthenticationSteps
|
||||
.fromHttpRequest(post(getSecretIdPath(options)).with(headers)
|
||||
.as(VaultResponse.class))
|
||||
.map(vaultResponse -> (String) vaultResponse.getRequiredData()
|
||||
.get("secret_id"));
|
||||
.fromHttpRequest(post(getSecretIdPath(options)).with(headers).as(VaultResponse.class))
|
||||
.map(vaultResponse -> (String) vaultResponse.getRequiredData().get("secret_id"));
|
||||
}
|
||||
|
||||
if (secretId instanceof Wrapped) {
|
||||
|
||||
return unwrapResponse(options.getUnwrappingEndpoints(),
|
||||
((Wrapped) secretId).getInitialToken())
|
||||
.map(vaultResponse -> (String) vaultResponse.getRequiredData()
|
||||
.get("secret_id"));
|
||||
return unwrapResponse(options.getUnwrappingEndpoints(), ((Wrapped) secretId).getInitialToken())
|
||||
.map(vaultResponse -> (String) vaultResponse.getRequiredData().get("secret_id"));
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("Unknown SecretId configuration: " + secretId);
|
||||
|
||||
}
|
||||
|
||||
private static Node<VaultResponse> unwrapResponse(
|
||||
UnwrappingEndpoints unwrappingEndpoints, VaultToken token) {
|
||||
private static Node<VaultResponse> unwrapResponse(UnwrappingEndpoints unwrappingEndpoints, VaultToken token) {
|
||||
|
||||
return AuthenticationSteps
|
||||
.fromHttpRequest(method(unwrappingEndpoints.getUnwrapRequestMethod(),
|
||||
unwrappingEndpoints.getPath()).with(createHttpHeaders(token))
|
||||
.as(VaultResponse.class))
|
||||
.fromHttpRequest(method(unwrappingEndpoints.getUnwrapRequestMethod(), unwrappingEndpoints.getPath())
|
||||
.with(createHttpHeaders(token)).as(VaultResponse.class))
|
||||
.map(unwrappingEndpoints::unwrap);
|
||||
}
|
||||
|
||||
@@ -193,20 +174,18 @@ public class AppRoleAuthentication
|
||||
|
||||
@Override
|
||||
public AuthenticationSteps getAuthenticationSteps() {
|
||||
return createAuthenticationSteps(options);
|
||||
return createAuthenticationSteps(this.options);
|
||||
}
|
||||
|
||||
private VaultToken createTokenUsingAppRole() {
|
||||
|
||||
Map<String, String> login = getAppRoleLoginBody(options.getRoleId(),
|
||||
options.getSecretId());
|
||||
Map<String, String> login = getAppRoleLoginBody(this.options.getRoleId(), this.options.getSecretId());
|
||||
|
||||
try {
|
||||
VaultResponse response = restOperations.postForObject(
|
||||
getLoginPath(options.getPath()), login, VaultResponse.class);
|
||||
VaultResponse response = this.restOperations.postForObject(getLoginPath(this.options.getPath()), login,
|
||||
VaultResponse.class);
|
||||
|
||||
Assert.state(response != null && response.getAuth() != null,
|
||||
"Auth field must not be null");
|
||||
Assert.state(response != null && response.getAuth() != null, "Auth field must not be null");
|
||||
|
||||
logger.debug("Login successful using AppRole authentication");
|
||||
|
||||
@@ -229,16 +208,13 @@ public class AppRoleAuthentication
|
||||
|
||||
try {
|
||||
|
||||
ResponseEntity<VaultResponse> entity = restOperations.exchange(
|
||||
getRoleIdIdPath(options), HttpMethod.GET, createHttpEntity(token),
|
||||
VaultResponse.class);
|
||||
ResponseEntity<VaultResponse> entity = this.restOperations.exchange(getRoleIdIdPath(this.options),
|
||||
HttpMethod.GET, createHttpEntity(token), VaultResponse.class);
|
||||
return (String) entity.getBody().getRequiredData().get("role_id");
|
||||
}
|
||||
catch (HttpStatusCodeException e) {
|
||||
throw new VaultLoginException(
|
||||
String.format("Cannot get Role id using AppRole: %s",
|
||||
VaultResponses.getError(e.getResponseBodyAsString())),
|
||||
e);
|
||||
throw new VaultLoginException(String.format("Cannot get Role id using AppRole: %s",
|
||||
VaultResponses.getError(e.getResponseBodyAsString())), e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -247,22 +223,17 @@ public class AppRoleAuthentication
|
||||
VaultToken token = ((Wrapped) roleId).getInitialToken();
|
||||
|
||||
try {
|
||||
UnwrappingEndpoints unwrappingEndpoints = options
|
||||
.getUnwrappingEndpoints();
|
||||
ResponseEntity<VaultResponse> entity = restOperations.exchange(
|
||||
unwrappingEndpoints.getPath(),
|
||||
unwrappingEndpoints.getUnwrapRequestMethod(),
|
||||
createHttpEntity(token), VaultResponse.class);
|
||||
UnwrappingEndpoints unwrappingEndpoints = this.options.getUnwrappingEndpoints();
|
||||
ResponseEntity<VaultResponse> entity = this.restOperations.exchange(unwrappingEndpoints.getPath(),
|
||||
unwrappingEndpoints.getUnwrapRequestMethod(), createHttpEntity(token), VaultResponse.class);
|
||||
|
||||
VaultResponse response = unwrappingEndpoints.unwrap(entity.getBody());
|
||||
|
||||
return (String) response.getRequiredData().get("role_id");
|
||||
}
|
||||
catch (HttpStatusCodeException e) {
|
||||
throw new VaultLoginException(
|
||||
String.format("Cannot unwrap Role id using AppRole: %s",
|
||||
VaultResponses.getError(e.getResponseBodyAsString())),
|
||||
e);
|
||||
throw new VaultLoginException(String.format("Cannot unwrap Role id using AppRole: %s",
|
||||
VaultResponses.getError(e.getResponseBodyAsString())), e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -280,16 +251,13 @@ public class AppRoleAuthentication
|
||||
VaultToken token = ((Pull) secretId).getInitialToken();
|
||||
|
||||
try {
|
||||
VaultResponse response = restOperations.postForObject(
|
||||
getSecretIdPath(options), createHttpEntity(token),
|
||||
VaultResponse.class);
|
||||
VaultResponse response = this.restOperations.postForObject(getSecretIdPath(this.options),
|
||||
createHttpEntity(token), VaultResponse.class);
|
||||
return (String) response.getRequiredData().get("secret_id");
|
||||
}
|
||||
catch (HttpStatusCodeException e) {
|
||||
throw new VaultLoginException(
|
||||
String.format("Cannot get Secret id using AppRole: %s",
|
||||
VaultResponses.getError(e.getResponseBodyAsString())),
|
||||
e);
|
||||
throw new VaultLoginException(String.format("Cannot get Secret id using AppRole: %s",
|
||||
VaultResponses.getError(e.getResponseBodyAsString())), e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -299,22 +267,17 @@ public class AppRoleAuthentication
|
||||
|
||||
try {
|
||||
|
||||
UnwrappingEndpoints unwrappingEndpoints = options
|
||||
.getUnwrappingEndpoints();
|
||||
ResponseEntity<VaultResponse> entity = restOperations.exchange(
|
||||
unwrappingEndpoints.getPath(),
|
||||
unwrappingEndpoints.getUnwrapRequestMethod(),
|
||||
createHttpEntity(token), VaultResponse.class);
|
||||
UnwrappingEndpoints unwrappingEndpoints = this.options.getUnwrappingEndpoints();
|
||||
ResponseEntity<VaultResponse> entity = this.restOperations.exchange(unwrappingEndpoints.getPath(),
|
||||
unwrappingEndpoints.getUnwrapRequestMethod(), createHttpEntity(token), VaultResponse.class);
|
||||
|
||||
VaultResponse response = unwrappingEndpoints.unwrap(entity.getBody());
|
||||
|
||||
return (String) response.getRequiredData().get("secret_id");
|
||||
}
|
||||
catch (HttpStatusCodeException e) {
|
||||
throw new VaultLoginException(
|
||||
String.format("Cannot unwrap Role id using AppRole: %s",
|
||||
VaultResponses.getError(e.getResponseBodyAsString())),
|
||||
e);
|
||||
throw new VaultLoginException(String.format("Cannot unwrap Role id using AppRole: %s",
|
||||
VaultResponses.getError(e.getResponseBodyAsString())), e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -346,8 +309,7 @@ public class AppRoleAuthentication
|
||||
return login;
|
||||
}
|
||||
|
||||
private static Map<String, String> getAppRoleLoginBody(String roleId,
|
||||
@Nullable String secretId) {
|
||||
private static Map<String, String> getAppRoleLoginBody(String roleId, @Nullable String secretId) {
|
||||
|
||||
Map<String, String> login = new HashMap<>();
|
||||
|
||||
@@ -361,12 +323,11 @@ public class AppRoleAuthentication
|
||||
}
|
||||
|
||||
private static String getSecretIdPath(AppRoleAuthenticationOptions options) {
|
||||
return String.format("auth/%s/role/%s/secret-id", options.getPath(),
|
||||
options.getAppRole());
|
||||
return String.format("auth/%s/role/%s/secret-id", options.getPath(), options.getAppRole());
|
||||
}
|
||||
|
||||
private static String getRoleIdIdPath(AppRoleAuthenticationOptions options) {
|
||||
return String.format("auth/%s/role/%s/role-id", options.getPath(),
|
||||
options.getAppRole());
|
||||
return String.format("auth/%s/role/%s/role-id", options.getPath(), options.getAppRole());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -74,9 +74,8 @@ public class AppRoleAuthenticationOptions {
|
||||
@Deprecated
|
||||
private final VaultToken initialToken;
|
||||
|
||||
private AppRoleAuthenticationOptions(String path, RoleId roleId, SecretId secretId,
|
||||
@Nullable String appRole, UnwrappingEndpoints unwrappingEndpoints,
|
||||
@Nullable VaultToken initialToken) {
|
||||
private AppRoleAuthenticationOptions(String path, RoleId roleId, SecretId secretId, @Nullable String appRole,
|
||||
UnwrappingEndpoints unwrappingEndpoints, @Nullable VaultToken initialToken) {
|
||||
|
||||
this.path = path;
|
||||
this.roleId = roleId;
|
||||
@@ -97,21 +96,21 @@ public class AppRoleAuthenticationOptions {
|
||||
* @return the mount path.
|
||||
*/
|
||||
public String getPath() {
|
||||
return path;
|
||||
return this.path;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the RoleId.
|
||||
*/
|
||||
public RoleId getRoleId() {
|
||||
return roleId;
|
||||
return this.roleId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the bound SecretId.
|
||||
*/
|
||||
public SecretId getSecretId() {
|
||||
return secretId;
|
||||
return this.secretId;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -120,7 +119,7 @@ public class AppRoleAuthenticationOptions {
|
||||
*/
|
||||
@Nullable
|
||||
public String getAppRole() {
|
||||
return appRole;
|
||||
return this.appRole;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -128,7 +127,7 @@ public class AppRoleAuthenticationOptions {
|
||||
* @since 2.2
|
||||
*/
|
||||
public UnwrappingEndpoints getUnwrappingEndpoints() {
|
||||
return unwrappingEndpoints;
|
||||
return this.unwrappingEndpoints;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -140,7 +139,7 @@ public class AppRoleAuthenticationOptions {
|
||||
@Nullable
|
||||
@Deprecated
|
||||
public VaultToken getInitialToken() {
|
||||
return initialToken;
|
||||
return this.initialToken;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -176,7 +175,6 @@ public class AppRoleAuthenticationOptions {
|
||||
|
||||
/**
|
||||
* Configure the mount path.
|
||||
*
|
||||
* @param path must not be empty or {@literal null}.
|
||||
* @return {@code this} {@link AppRoleAuthenticationOptionsBuilder}.
|
||||
* @see #DEFAULT_APPROLE_AUTHENTICATION_PATH
|
||||
@@ -191,7 +189,6 @@ public class AppRoleAuthenticationOptions {
|
||||
|
||||
/**
|
||||
* Configure the RoleId.
|
||||
*
|
||||
* @param roleId must not be empty or {@literal null}.
|
||||
* @return {@code this} {@link AppRoleAuthenticationOptionsBuilder}.
|
||||
* @since 2.0
|
||||
@@ -206,10 +203,10 @@ public class AppRoleAuthenticationOptions {
|
||||
|
||||
/**
|
||||
* Configure the RoleId.
|
||||
*
|
||||
* @param roleId must not be empty or {@literal null}.
|
||||
* @return {@code this} {@link AppRoleAuthenticationOptionsBuilder}.
|
||||
* @deprecated since 2.0, use {@link #roleId(AppRoleAuthenticationOptions.RoleId)}.
|
||||
* @deprecated since 2.0, use
|
||||
* {@link #roleId(AppRoleAuthenticationOptions.RoleId)}.
|
||||
*/
|
||||
@Deprecated
|
||||
public AppRoleAuthenticationOptionsBuilder roleId(String roleId) {
|
||||
@@ -222,7 +219,6 @@ public class AppRoleAuthenticationOptions {
|
||||
|
||||
/**
|
||||
* Configure a {@code secretId}.
|
||||
*
|
||||
* @param secretId must not be empty or {@literal null}.
|
||||
* @return {@code this} {@link AppRoleAuthenticationOptionsBuilder}.
|
||||
* @since 2.0
|
||||
@@ -237,10 +233,10 @@ public class AppRoleAuthenticationOptions {
|
||||
|
||||
/**
|
||||
* Configure a {@code secretId}.
|
||||
*
|
||||
* @param secretId must not be empty or {@literal null}.
|
||||
* @return {@code this} {@link AppRoleAuthenticationOptionsBuilder}.
|
||||
* @deprecated since 2.0, use {@link #secretId(AppRoleAuthenticationOptions.SecretId)}.
|
||||
* @deprecated since 2.0, use
|
||||
* {@link #secretId(AppRoleAuthenticationOptions.SecretId)}.
|
||||
*/
|
||||
@Deprecated
|
||||
public AppRoleAuthenticationOptionsBuilder secretId(String secretId) {
|
||||
@@ -253,7 +249,6 @@ public class AppRoleAuthenticationOptions {
|
||||
|
||||
/**
|
||||
* Configure a {@code appRole}.
|
||||
*
|
||||
* @param appRole must not be empty or {@literal null}.
|
||||
* @return {@code this} {@link AppRoleAuthenticationOptionsBuilder}.
|
||||
* @since 1.1
|
||||
@@ -268,13 +263,11 @@ public class AppRoleAuthenticationOptions {
|
||||
|
||||
/**
|
||||
* Configure the {@link UnwrappingEndpoints} to use.
|
||||
*
|
||||
* @param endpoints must not be {@literal null}.
|
||||
* @return {@code this} {@link AppRoleAuthenticationOptionsBuilder}
|
||||
* @since 2.2
|
||||
*/
|
||||
public AppRoleAuthenticationOptionsBuilder unwrappingEndpoints(
|
||||
UnwrappingEndpoints endpoints) {
|
||||
public AppRoleAuthenticationOptionsBuilder unwrappingEndpoints(UnwrappingEndpoints endpoints) {
|
||||
|
||||
Assert.notNull(endpoints, "UnwrappingEndpoints must not be empty");
|
||||
|
||||
@@ -284,7 +277,6 @@ public class AppRoleAuthenticationOptions {
|
||||
|
||||
/**
|
||||
* Configure a {@code initialToken}.
|
||||
*
|
||||
* @param initialToken must not be empty or {@literal null}.
|
||||
* @return {@code this} {@link AppRoleAuthenticationOptionsBuilder}.
|
||||
* @since 1.1
|
||||
@@ -305,47 +297,47 @@ public class AppRoleAuthenticationOptions {
|
||||
* Build a new {@link AppRoleAuthenticationOptions} instance. Requires
|
||||
* {@link #roleId(String)} for push mode or {@link #appRole(String)} and
|
||||
* {@link #initialToken(VaultToken)} for pull mode to be configured.
|
||||
*
|
||||
* @return a new {@link AppRoleAuthenticationOptions}.
|
||||
*/
|
||||
public AppRoleAuthenticationOptions build() {
|
||||
|
||||
Assert.hasText(path, "Path must not be empty");
|
||||
Assert.hasText(this.path, "Path must not be empty");
|
||||
|
||||
if (secretId == null) {
|
||||
if (this.secretId == null) {
|
||||
|
||||
if (providedSecretId != null) {
|
||||
secretId(SecretId.provided(providedSecretId));
|
||||
if (this.providedSecretId != null) {
|
||||
secretId(SecretId.provided(this.providedSecretId));
|
||||
}
|
||||
else if (initialToken != null) {
|
||||
secretId(SecretId.pull(initialToken));
|
||||
else if (this.initialToken != null) {
|
||||
secretId(SecretId.pull(this.initialToken));
|
||||
}
|
||||
else {
|
||||
secretId(SecretId.absent());
|
||||
}
|
||||
}
|
||||
|
||||
if (roleId == null) {
|
||||
if (this.roleId == null) {
|
||||
|
||||
if (providedRoleId != null) {
|
||||
roleId(RoleId.provided(providedRoleId));
|
||||
if (this.providedRoleId != null) {
|
||||
roleId(RoleId.provided(this.providedRoleId));
|
||||
}
|
||||
else {
|
||||
|
||||
Assert.notNull(initialToken,
|
||||
Assert.notNull(this.initialToken,
|
||||
"AppRole authentication configured for pull mode. InitialToken must not be null (pull mode)");
|
||||
roleId(RoleId.pull(initialToken));
|
||||
roleId(RoleId.pull(this.initialToken));
|
||||
}
|
||||
}
|
||||
|
||||
if (roleId instanceof Pull || secretId instanceof Pull) {
|
||||
Assert.notNull(appRole,
|
||||
if (this.roleId instanceof Pull || this.secretId instanceof Pull) {
|
||||
Assert.notNull(this.appRole,
|
||||
"AppRole authentication configured for pull mode. AppRole must not be null.");
|
||||
}
|
||||
|
||||
return new AppRoleAuthenticationOptions(path, roleId, secretId, appRole,
|
||||
unwrappingEndpoints, initialToken);
|
||||
return new AppRoleAuthenticationOptions(this.path, this.roleId, this.secretId, this.appRole,
|
||||
this.unwrappingEndpoints, this.initialToken);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -360,7 +352,6 @@ public class AppRoleAuthenticationOptions {
|
||||
/**
|
||||
* Create a {@link RoleId} object that obtains its value from unwrapping a
|
||||
* response using the {@link VaultToken initial token} from a Cubbyhole.
|
||||
*
|
||||
* @param initialToken must not be {@literal null}.
|
||||
* @return {@link RoleId} object that obtains its value from unwrapping a response
|
||||
* using the {@link VaultToken initial token}.
|
||||
@@ -377,7 +368,6 @@ public class AppRoleAuthenticationOptions {
|
||||
* Create a {@link RoleId} that obtains its value using pull-mode, specifying a
|
||||
* {@link VaultToken initial token}. The token policy must allow reading the
|
||||
* roleId from {@code auth/approle/role/(role-name)/role-id}.
|
||||
*
|
||||
* @param initialToken must not be {@literal null}.
|
||||
* @return {@link RoleId} that obtains its value using pull-mode.
|
||||
*/
|
||||
@@ -390,7 +380,6 @@ public class AppRoleAuthenticationOptions {
|
||||
|
||||
/**
|
||||
* Create a {@link RoleId} that encapsulates a static {@code roleId}.
|
||||
*
|
||||
* @param roleId must not be {@literal null} or empty.
|
||||
* @return {@link RoleId} that encapsulates a static {@code roleId}.
|
||||
*/
|
||||
@@ -400,6 +389,7 @@ public class AppRoleAuthenticationOptions {
|
||||
|
||||
return new Provided(roleId);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -414,7 +404,6 @@ public class AppRoleAuthenticationOptions {
|
||||
/**
|
||||
* Create a {@link SecretId} object that obtains its value from unwrapping a
|
||||
* response using the {@link VaultToken initial token} from a Cubbyhole.
|
||||
*
|
||||
* @param initialToken must not be {@literal null}.
|
||||
* @return {@link SecretId} object that obtains its value from unwrapping a
|
||||
* response using the {@link VaultToken initial token}.
|
||||
@@ -431,7 +420,6 @@ public class AppRoleAuthenticationOptions {
|
||||
* Create a {@link SecretId} that obtains its value using pull-mode, specifying a
|
||||
* {@link VaultToken initial token}. The token policy must allow reading the
|
||||
* SecretId from {@code auth/approle/role/(role-name)/secret-id}.
|
||||
*
|
||||
* @param initialToken must not be {@literal null}.
|
||||
* @return {@link SecretId} that obtains its value using pull-mode.
|
||||
*/
|
||||
@@ -444,7 +432,6 @@ public class AppRoleAuthenticationOptions {
|
||||
|
||||
/**
|
||||
* Create a {@link SecretId} that encapsulates a static {@code secretId}.
|
||||
*
|
||||
* @param secretId must not be {@literal null} or empty.
|
||||
* @return {@link SecretId} that encapsulates a static {@code SecretId}.
|
||||
*/
|
||||
@@ -458,11 +445,12 @@ public class AppRoleAuthenticationOptions {
|
||||
/**
|
||||
* Create a {@link SecretId} that represents an absent secretId. Using this object
|
||||
* will not send a secretId during AppRole login.
|
||||
*
|
||||
* @return a {@link SecretId} that represents an absent secretId
|
||||
*/
|
||||
static SecretId absent() {
|
||||
return AbsentSecretId.INSTANCE;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -31,7 +31,9 @@ class AppRoleTokens {
|
||||
* Absent secretId.
|
||||
*/
|
||||
enum AbsentSecretId implements SecretId {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -48,6 +50,7 @@ class AppRoleTokens {
|
||||
public VaultToken getInitialToken() {
|
||||
return this.initialToken;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -64,6 +67,7 @@ class AppRoleTokens {
|
||||
public VaultToken getInitialToken() {
|
||||
return this.initialToken;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -80,5 +84,7 @@ class AppRoleTokens {
|
||||
public String getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -46,7 +46,6 @@ public abstract class AuthenticationEventPublisher {
|
||||
/**
|
||||
* Add a {@link AuthenticationListener}. The listener starts receiving events as soon
|
||||
* as possible.
|
||||
*
|
||||
* @param listener lease listener, must not be {@literal null}.
|
||||
*/
|
||||
public void addAuthenticationListener(AuthenticationListener listener) {
|
||||
@@ -58,7 +57,6 @@ public abstract class AuthenticationEventPublisher {
|
||||
|
||||
/**
|
||||
* Remove a {@link AuthenticationListener}.
|
||||
*
|
||||
* @param listener must not be {@literal null}.
|
||||
*/
|
||||
public void removeAuthenticationListener(AuthenticationListener listener) {
|
||||
@@ -68,7 +66,6 @@ public abstract class AuthenticationEventPublisher {
|
||||
/**
|
||||
* Add a {@link AuthenticationErrorListener}. The listener starts receiving events as
|
||||
* soon as possible.
|
||||
*
|
||||
* @param listener lease listener, must not be {@literal null}.
|
||||
*/
|
||||
public void addErrorListener(AuthenticationErrorListener listener) {
|
||||
@@ -80,7 +77,6 @@ public abstract class AuthenticationEventPublisher {
|
||||
|
||||
/**
|
||||
* Remove a {@link AuthenticationErrorListener}.
|
||||
*
|
||||
* @param listener must not be {@literal null}.
|
||||
*/
|
||||
public void removeErrorListener(AuthenticationErrorListener listener) {
|
||||
@@ -89,25 +85,24 @@ public abstract class AuthenticationEventPublisher {
|
||||
|
||||
/**
|
||||
* Dispatch the event to all {@link AuthenticationListener}s.
|
||||
*
|
||||
* @param authenticationEvent the event to dispatch.
|
||||
*/
|
||||
void dispatch(AuthenticationEvent authenticationEvent) {
|
||||
|
||||
for (AuthenticationListener listener : listeners) {
|
||||
for (AuthenticationListener listener : this.listeners) {
|
||||
listener.onAuthenticationEvent(authenticationEvent);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatch the event to all {@link AuthenticationErrorListener}s.
|
||||
*
|
||||
* @param authenticationEvent the event to dispatch.
|
||||
*/
|
||||
void dispatch(AuthenticationErrorEvent authenticationEvent) {
|
||||
|
||||
for (AuthenticationErrorListener listener : errorListeners) {
|
||||
for (AuthenticationErrorListener listener : this.errorListeners) {
|
||||
listener.onAuthenticationError(authenticationEvent);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -70,7 +70,6 @@ import org.springframework.vault.support.VaultToken;
|
||||
* {@link AuthenticationSteps} describes the authentication flow. Computation on the
|
||||
* source data is only performed when the flow definition is interpreted by an executor.
|
||||
*
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @since 2.0
|
||||
* @see AuthenticationStepsFactory
|
||||
@@ -83,17 +82,15 @@ public class AuthenticationSteps {
|
||||
|
||||
/**
|
||||
* Create a flow definition using a provided {@link VaultToken}.
|
||||
*
|
||||
* @param token the token to be used from this {@link AuthenticationSteps}, must not
|
||||
* be {@literal null}.
|
||||
* be {@literal null}.
|
||||
* @return the {@link AuthenticationSteps}.
|
||||
*/
|
||||
public static AuthenticationSteps just(VaultToken token) {
|
||||
|
||||
Assert.notNull(token, "Vault token must not be null");
|
||||
|
||||
return new AuthenticationSteps(
|
||||
new SupplierStep<>(() -> token, AuthenticationSteps.HEAD));
|
||||
return new AuthenticationSteps(new SupplierStep<>(() -> token, AuthenticationSteps.HEAD));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -106,15 +103,13 @@ public class AuthenticationSteps {
|
||||
|
||||
Assert.notNull(request, "HttpRequest must not be null");
|
||||
|
||||
return new AuthenticationSteps(
|
||||
new HttpRequestNode<>(request, AuthenticationSteps.HEAD));
|
||||
return new AuthenticationSteps(new HttpRequestNode<>(request, AuthenticationSteps.HEAD));
|
||||
}
|
||||
|
||||
/**
|
||||
* Start flow composition from a {@link Supplier}.
|
||||
*
|
||||
* @param supplier supplier function that will produce the flow value, must not be
|
||||
* {@literal null}.
|
||||
* {@literal null}.
|
||||
* @return the first {@link Node}.
|
||||
*/
|
||||
public static <T> Node<T> fromSupplier(Supplier<T> supplier) {
|
||||
@@ -126,7 +121,6 @@ public class AuthenticationSteps {
|
||||
|
||||
/**
|
||||
* Start flow composition from a {@link HttpRequest}.
|
||||
*
|
||||
* @param request the HTTP request definition, must not be {@literal null}.
|
||||
* @return the first {@link Node}.
|
||||
*/
|
||||
@@ -143,7 +137,6 @@ public class AuthenticationSteps {
|
||||
|
||||
/**
|
||||
* Return a {@link List} of node given a {@link PathAware} starting point.
|
||||
*
|
||||
* @param pathAware must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
@@ -182,9 +175,8 @@ public class AuthenticationSteps {
|
||||
|
||||
/**
|
||||
* Transform the state object into a different object.
|
||||
*
|
||||
* @param mappingFunction mapping function to be applied to the state object, must
|
||||
* not be {@literal null}.
|
||||
* not be {@literal null}.
|
||||
* @param <R> resulting object type
|
||||
* @return the next {@link Node}.
|
||||
*/
|
||||
@@ -197,7 +189,6 @@ public class AuthenticationSteps {
|
||||
|
||||
/**
|
||||
* Combine the result from this {@link Node} and another into a {@link Pair}.
|
||||
*
|
||||
* @return the next {@link Node}.
|
||||
* @since 2.1
|
||||
*/
|
||||
@@ -211,9 +202,8 @@ public class AuthenticationSteps {
|
||||
|
||||
/**
|
||||
* Callback with the current state object.
|
||||
*
|
||||
* @param consumerFunction consumer function to be called with the state object,
|
||||
* must not be {@literal null}.
|
||||
* must not be {@literal null}.
|
||||
* @return the next {@link Node}.
|
||||
*/
|
||||
public Node<T> onNext(Consumer<? super T> consumerFunction) {
|
||||
@@ -225,7 +215,6 @@ public class AuthenticationSteps {
|
||||
|
||||
/**
|
||||
* Request data using a {@link HttpRequest}.
|
||||
*
|
||||
* @param request the HTTP request definition, must not be {@literal null}.
|
||||
* @return the next {@link Node}.
|
||||
*/
|
||||
@@ -239,9 +228,8 @@ public class AuthenticationSteps {
|
||||
/**
|
||||
* Terminal operation requesting a {@link VaultToken token} from Vault by posting
|
||||
* the current state to Vaults {@code uriTemplate}.
|
||||
*
|
||||
* @param uriTemplate Vault authentication endpoint, must not be {@literal null}
|
||||
* or empty.
|
||||
* or empty.
|
||||
* @param uriVariables URI variables for URI template expansion.
|
||||
* @return the {@link AuthenticationSteps}.
|
||||
*/
|
||||
@@ -249,14 +237,12 @@ public class AuthenticationSteps {
|
||||
|
||||
Assert.hasText(uriTemplate, "URI template must not be null or empty");
|
||||
|
||||
return login(HttpRequestBuilder.post(uriTemplate, uriVariables)
|
||||
.as(VaultResponse.class));
|
||||
return login(HttpRequestBuilder.post(uriTemplate, uriVariables).as(VaultResponse.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Terminal operation requesting a {@link VaultToken token} from Vault by issuing
|
||||
* a HTTP request with the current state to Vaults {@code uriTemplate}.
|
||||
*
|
||||
* @param request HTTP request definition.
|
||||
* @return the {@link AuthenticationSteps}.
|
||||
*/
|
||||
@@ -270,18 +256,17 @@ public class AuthenticationSteps {
|
||||
/**
|
||||
* Terminal operation resulting in a {@link VaultToken token} by applying a
|
||||
* mapping {@link Function} to the current state object.
|
||||
*
|
||||
* @param mappingFunction mapping function to be applied to the state object, must
|
||||
* not be {@literal null}.
|
||||
* not be {@literal null}.
|
||||
* @return the {@link AuthenticationSteps}.
|
||||
*/
|
||||
public AuthenticationSteps login(
|
||||
Function<? super T, ? extends VaultToken> mappingFunction) {
|
||||
public AuthenticationSteps login(Function<? super T, ? extends VaultToken> mappingFunction) {
|
||||
|
||||
Assert.notNull(mappingFunction, "Mapping function must not be null");
|
||||
|
||||
return new AuthenticationSteps(new MapStep<>(mappingFunction, this));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -305,7 +290,6 @@ public class AuthenticationSteps {
|
||||
|
||||
/**
|
||||
* Builder entry point to {@code GET} from {@code uriTemplate}.
|
||||
*
|
||||
* @param uriTemplate must not be {@literal null} or empty.
|
||||
* @param uriVariables the variables to expand the template.
|
||||
* @return a new {@link HttpRequestBuilder}.
|
||||
@@ -316,7 +300,6 @@ public class AuthenticationSteps {
|
||||
|
||||
/**
|
||||
* Builder entry point to {@code GET} from {@code uri}.
|
||||
*
|
||||
* @param uri must not be {@literal null}.
|
||||
* @return a new {@link HttpRequestBuilder}.
|
||||
*/
|
||||
@@ -326,19 +309,16 @@ public class AuthenticationSteps {
|
||||
|
||||
/**
|
||||
* Builder entry point to {@code POST} to {@code uriTemplate}.
|
||||
*
|
||||
* @param uriTemplate must not be {@literal null} or empty.
|
||||
* @param uriVariables the variables to expand the template.
|
||||
* @return a new {@link HttpRequestBuilder}.
|
||||
*/
|
||||
public static HttpRequestBuilder post(String uriTemplate,
|
||||
String... uriVariables) {
|
||||
public static HttpRequestBuilder post(String uriTemplate, String... uriVariables) {
|
||||
return new HttpRequestBuilder(HttpMethod.POST, uriTemplate, uriVariables);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder entry point to {@code POST} to {@code uri}.
|
||||
*
|
||||
* @param uri must not be {@literal null}.
|
||||
* @return a new {@link HttpRequestBuilder}.
|
||||
*/
|
||||
@@ -348,14 +328,12 @@ public class AuthenticationSteps {
|
||||
|
||||
/**
|
||||
* Builder entry point to use {@link HttpMethod} for {@code uriTemplate}.
|
||||
*
|
||||
* @param uriTemplate must not be {@literal null} or empty.
|
||||
* @param uriVariables the variables to expand the template.
|
||||
* @return a new {@link HttpRequestBuilder}.
|
||||
* @since 2.2
|
||||
*/
|
||||
public static HttpRequestBuilder method(HttpMethod method, String uriTemplate,
|
||||
String... uriVariables) {
|
||||
public static HttpRequestBuilder method(HttpMethod method, String uriTemplate, String... uriVariables) {
|
||||
return new HttpRequestBuilder(method, uriTemplate, uriVariables);
|
||||
}
|
||||
|
||||
@@ -364,16 +342,14 @@ public class AuthenticationSteps {
|
||||
this.uri = uri;
|
||||
}
|
||||
|
||||
private HttpRequestBuilder(HttpMethod method, @Nullable String uriTemplate,
|
||||
@Nullable String[] urlVariables) {
|
||||
private HttpRequestBuilder(HttpMethod method, @Nullable String uriTemplate, @Nullable String[] urlVariables) {
|
||||
this.method = method;
|
||||
this.uriTemplate = uriTemplate;
|
||||
this.urlVariables = urlVariables;
|
||||
}
|
||||
|
||||
private HttpRequestBuilder(HttpMethod method, @Nullable URI uri,
|
||||
@Nullable String uriTemplate, @Nullable String[] urlVariables,
|
||||
@Nullable HttpEntity<?> entity) {
|
||||
private HttpRequestBuilder(HttpMethod method, @Nullable URI uri, @Nullable String uriTemplate,
|
||||
@Nullable String[] urlVariables, @Nullable HttpEntity<?> entity) {
|
||||
this.method = method;
|
||||
this.uri = uri;
|
||||
this.uriTemplate = uriTemplate;
|
||||
@@ -383,7 +359,6 @@ public class AuthenticationSteps {
|
||||
|
||||
/**
|
||||
* Configure a request {@link HttpEntity entity}.
|
||||
*
|
||||
* @param httpEntity must not be {@literal null}.
|
||||
* @return a new {@link HttpRequestBuilder}.
|
||||
*/
|
||||
@@ -391,13 +366,11 @@ public class AuthenticationSteps {
|
||||
|
||||
Assert.notNull(httpEntity, "HttpEntity must not be null");
|
||||
|
||||
return new HttpRequestBuilder(method, uri, uriTemplate, urlVariables,
|
||||
httpEntity);
|
||||
return new HttpRequestBuilder(this.method, this.uri, this.uriTemplate, this.urlVariables, httpEntity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure a request {@link HttpHeaders headers}.
|
||||
*
|
||||
* @param headers must not be {@literal null}.
|
||||
* @return a new {@link HttpRequestBuilder}.
|
||||
*/
|
||||
@@ -405,7 +378,7 @@ public class AuthenticationSteps {
|
||||
|
||||
Assert.notNull(headers, "HttpHeaders must not be null");
|
||||
|
||||
return new HttpRequestBuilder(method, uri, uriTemplate, urlVariables,
|
||||
return new HttpRequestBuilder(this.method, this.uri, this.uriTemplate, this.urlVariables,
|
||||
new HttpEntity<>(headers));
|
||||
}
|
||||
|
||||
@@ -420,6 +393,7 @@ public class AuthenticationSteps {
|
||||
|
||||
return new HttpRequest<>(this, type);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -456,8 +430,8 @@ public class AuthenticationSteps {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("%s %s AS %s", getMethod(),
|
||||
getUri() != null ? getUri() : getUriTemplate(), getResponseType());
|
||||
return String.format("%s %s AS %s", getMethod(), getUri() != null ? getUri() : getUriTemplate(),
|
||||
getResponseType());
|
||||
}
|
||||
|
||||
HttpMethod getMethod() {
|
||||
@@ -487,6 +461,7 @@ public class AuthenticationSteps {
|
||||
Class<T> getResponseType() {
|
||||
return this.responseType;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static final class HttpRequestNode<T> extends Node<T> implements PathAware {
|
||||
@@ -502,7 +477,7 @@ public class AuthenticationSteps {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return definition.toString();
|
||||
return this.definition.toString();
|
||||
}
|
||||
|
||||
public HttpRequest<T> getDefinition() {
|
||||
@@ -520,13 +495,14 @@ public class AuthenticationSteps {
|
||||
if (!(o instanceof HttpRequestNode))
|
||||
return false;
|
||||
HttpRequestNode<?> that = (HttpRequestNode<?>) o;
|
||||
return definition.equals(that.definition) && previous.equals(that.previous);
|
||||
return this.definition.equals(that.definition) && this.previous.equals(that.previous);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(definition, previous);
|
||||
return Objects.hash(this.definition, this.previous);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static final class MapStep<I, O> extends Node<O> implements PathAware {
|
||||
@@ -541,12 +517,12 @@ public class AuthenticationSteps {
|
||||
}
|
||||
|
||||
O apply(I in) {
|
||||
return mapper.apply(in);
|
||||
return this.mapper.apply(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Map: " + mapper.toString();
|
||||
return "Map: " + this.mapper.toString();
|
||||
}
|
||||
|
||||
public Function<? super I, ? extends O> getMapper() {
|
||||
@@ -564,13 +540,14 @@ public class AuthenticationSteps {
|
||||
if (!(o instanceof MapStep))
|
||||
return false;
|
||||
MapStep<?, ?> mapStep = (MapStep<?, ?>) o;
|
||||
return mapper.equals(mapStep.mapper) && previous.equals(mapStep.previous);
|
||||
return this.mapper.equals(mapStep.mapper) && this.previous.equals(mapStep.previous);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(mapper, previous);
|
||||
return Objects.hash(this.mapper, this.previous);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static final class ZipStep<L, R> extends Node<Pair<L, R>> implements PathAware {
|
||||
@@ -586,7 +563,7 @@ public class AuthenticationSteps {
|
||||
|
||||
@Override
|
||||
public Node<?> getPrevious() {
|
||||
return left;
|
||||
return this.left;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -609,13 +586,14 @@ public class AuthenticationSteps {
|
||||
if (!(o instanceof ZipStep))
|
||||
return false;
|
||||
ZipStep<?, ?> zipStep = (ZipStep<?, ?>) o;
|
||||
return left.equals(zipStep.left) && right.equals(zipStep.right);
|
||||
return this.left.equals(zipStep.left) && this.right.equals(zipStep.right);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(left, right);
|
||||
return Objects.hash(this.left, this.right);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static final class OnNextStep<T> extends Node<T> implements PathAware {
|
||||
@@ -630,13 +608,13 @@ public class AuthenticationSteps {
|
||||
}
|
||||
|
||||
T apply(T in) {
|
||||
consumer.accept(in);
|
||||
this.consumer.accept(in);
|
||||
return in;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Consumer: " + consumer.toString();
|
||||
return "Consumer: " + this.consumer.toString();
|
||||
}
|
||||
|
||||
public Consumer<? super T> getConsumer() {
|
||||
@@ -654,13 +632,14 @@ public class AuthenticationSteps {
|
||||
if (!(o instanceof OnNextStep))
|
||||
return false;
|
||||
OnNextStep<?> that = (OnNextStep<?>) o;
|
||||
return consumer.equals(that.consumer) && previous.equals(that.previous);
|
||||
return this.consumer.equals(that.consumer) && this.previous.equals(that.previous);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(consumer, previous);
|
||||
return Objects.hash(this.consumer, this.previous);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static final class SupplierStep<T> extends Node<T> implements PathAware {
|
||||
@@ -675,12 +654,12 @@ public class AuthenticationSteps {
|
||||
}
|
||||
|
||||
public T get() {
|
||||
return supplier.get();
|
||||
return this.supplier.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Supplier: " + supplier.toString();
|
||||
return "Supplier: " + this.supplier.toString();
|
||||
}
|
||||
|
||||
public Supplier<T> getSupplier() {
|
||||
@@ -698,17 +677,20 @@ public class AuthenticationSteps {
|
||||
if (!(o instanceof SupplierStep))
|
||||
return false;
|
||||
SupplierStep<?> that = (SupplierStep<?>) o;
|
||||
return supplier.equals(that.supplier) && previous.equals(that.previous);
|
||||
return this.supplier.equals(that.supplier) && this.previous.equals(that.previous);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(supplier, previous);
|
||||
return Objects.hash(this.supplier, this.previous);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
interface PathAware {
|
||||
|
||||
Node<?> getPrevious();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -731,7 +713,6 @@ public class AuthenticationSteps {
|
||||
|
||||
/**
|
||||
* Create a new {@link Pair} given {@code left} and {@code right} values.
|
||||
*
|
||||
* @param left the left value.
|
||||
* @param right the right value.
|
||||
* @return the {@link Pair}.
|
||||
@@ -742,20 +723,18 @@ public class AuthenticationSteps {
|
||||
|
||||
/**
|
||||
* Type-safe way to get the fist object of this {@link Pair}.
|
||||
*
|
||||
* @return The first object
|
||||
*/
|
||||
public L getLeft() {
|
||||
return left;
|
||||
return this.left;
|
||||
}
|
||||
|
||||
/**
|
||||
* Type-safe way to get the second object of this {@link Pair}.
|
||||
*
|
||||
* @return The second object
|
||||
*/
|
||||
public R getRight() {
|
||||
return right;
|
||||
return this.right;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -765,22 +744,24 @@ public class AuthenticationSteps {
|
||||
if (!(o instanceof Pair))
|
||||
return false;
|
||||
Pair<?, ?> pair = (Pair<?, ?>) o;
|
||||
return left.equals(pair.left) && right.equals(pair.right);
|
||||
return this.left.equals(pair.left) && this.right.equals(pair.right);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(left, right);
|
||||
return Objects.hash(this.left, this.right);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
sb.append(getClass().getSimpleName());
|
||||
sb.append(" [left=").append(left);
|
||||
sb.append(", right=").append(right);
|
||||
sb.append(" [left=").append(this.left);
|
||||
sb.append(", right=").append(this.right);
|
||||
sb.append(']');
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -56,12 +56,10 @@ public class AuthenticationStepsExecutor implements ClientAuthentication {
|
||||
/**
|
||||
* Create a new {@link AuthenticationStepsExecutor} given {@link AuthenticationSteps}
|
||||
* and {@link RestOperations}.
|
||||
*
|
||||
* @param steps must not be {@literal null}.
|
||||
* @param restOperations must not be {@literal null}.
|
||||
*/
|
||||
public AuthenticationStepsExecutor(AuthenticationSteps steps,
|
||||
RestOperations restOperations) {
|
||||
public AuthenticationStepsExecutor(AuthenticationSteps steps, RestOperations restOperations) {
|
||||
|
||||
Assert.notNull(steps, "AuthenticationSteps must not be null");
|
||||
Assert.notNull(restOperations, "RestOperations must not be null");
|
||||
@@ -74,7 +72,7 @@ public class AuthenticationStepsExecutor implements ClientAuthentication {
|
||||
@SuppressWarnings("unchecked")
|
||||
public VaultToken login() throws VaultException {
|
||||
|
||||
Iterable<Node<?>> steps = chain.steps;
|
||||
Iterable<Node<?>> steps = this.chain.steps;
|
||||
|
||||
Object state = evaluate(steps);
|
||||
|
||||
@@ -89,9 +87,8 @@ public class AuthenticationStepsExecutor implements ClientAuthentication {
|
||||
return LoginTokenUtil.from(response.getAuth());
|
||||
}
|
||||
|
||||
throw new IllegalStateException(String.format(
|
||||
"Cannot retrieve VaultToken from authentication chain. Got instead %s",
|
||||
state));
|
||||
throw new IllegalStateException(
|
||||
String.format("Cannot retrieve VaultToken from authentication chain. Got instead %s", state));
|
||||
}
|
||||
|
||||
private Object evaluate(Iterable<Node<?>> steps) {
|
||||
@@ -101,8 +98,7 @@ public class AuthenticationStepsExecutor implements ClientAuthentication {
|
||||
for (Node<?> o : steps) {
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(
|
||||
String.format("Executing %s with current state %s", o, state));
|
||||
logger.debug(String.format("Executing %s with current state %s", o, state));
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -127,19 +123,17 @@ public class AuthenticationStepsExecutor implements ClientAuthentication {
|
||||
}
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(
|
||||
String.format("Executed %s with current state %s", o, state));
|
||||
logger.debug(String.format("Executed %s with current state %s", o, state));
|
||||
}
|
||||
}
|
||||
catch (HttpStatusCodeException e) {
|
||||
throw new VaultLoginException(String.format(
|
||||
"HTTP request %s in state %s failed with Status %s and body %s",
|
||||
o, state, e.getRawStatusCode(),
|
||||
VaultResponses.getError(e.getResponseBodyAsString())), e);
|
||||
throw new VaultLoginException(
|
||||
String.format("HTTP request %s in state %s failed with Status %s and body %s", o, state,
|
||||
e.getRawStatusCode(), VaultResponses.getError(e.getResponseBodyAsString())),
|
||||
e);
|
||||
}
|
||||
catch (RuntimeException e) {
|
||||
throw new VaultLoginException(
|
||||
String.format("Authentication execution failed in %s", o), e);
|
||||
throw new VaultLoginException(String.format("Authentication execution failed in %s", o), e);
|
||||
}
|
||||
}
|
||||
return state;
|
||||
@@ -171,17 +165,14 @@ public class AuthenticationStepsExecutor implements ClientAuthentication {
|
||||
|
||||
if (definition.getUri() == null) {
|
||||
|
||||
ResponseEntity<?> exchange = restOperations.exchange(
|
||||
definition.getUriTemplate(), definition.getMethod(),
|
||||
getEntity(definition.getEntity(), state),
|
||||
definition.getResponseType(),
|
||||
ResponseEntity<?> exchange = this.restOperations.exchange(definition.getUriTemplate(),
|
||||
definition.getMethod(), getEntity(definition.getEntity(), state), definition.getResponseType(),
|
||||
(Object[]) definition.getUrlVariables());
|
||||
|
||||
return exchange.getBody();
|
||||
}
|
||||
ResponseEntity<?> exchange = restOperations.exchange(definition.getUri(),
|
||||
definition.getMethod(), getEntity(definition.getEntity(), state),
|
||||
definition.getResponseType());
|
||||
ResponseEntity<?> exchange = this.restOperations.exchange(definition.getUri(), definition.getMethod(),
|
||||
getEntity(definition.getEntity(), state), definition.getResponseType());
|
||||
|
||||
return exchange.getBody();
|
||||
|
||||
@@ -199,4 +190,5 @@ public class AuthenticationStepsExecutor implements ClientAuthentication {
|
||||
|
||||
return entity;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -30,8 +30,8 @@ public interface AuthenticationStepsFactory {
|
||||
|
||||
/**
|
||||
* Get the {@link AuthenticationSteps} describing an authentication flow.
|
||||
*
|
||||
* @return the {@link AuthenticationSteps} describing an authentication flow.
|
||||
*/
|
||||
AuthenticationSteps getAuthenticationSteps();
|
||||
|
||||
}
|
||||
|
||||
@@ -52,8 +52,7 @@ import org.springframework.web.reactive.function.client.WebClient.RequestBodySpe
|
||||
*/
|
||||
public class AuthenticationStepsOperator implements VaultTokenSupplier {
|
||||
|
||||
private static final Log logger = LogFactory
|
||||
.getLog(AuthenticationStepsOperator.class);
|
||||
private static final Log logger = LogFactory.getLog(AuthenticationStepsOperator.class);
|
||||
|
||||
private final AuthenticationSteps chain;
|
||||
|
||||
@@ -62,7 +61,6 @@ public class AuthenticationStepsOperator implements VaultTokenSupplier {
|
||||
/**
|
||||
* Create a new {@link AuthenticationStepsOperator} given {@link AuthenticationSteps}
|
||||
* and {@link WebClient}.
|
||||
*
|
||||
* @param steps must not be {@literal null}.
|
||||
* @param webClient must not be {@literal null}.
|
||||
*/
|
||||
@@ -78,7 +76,7 @@ public class AuthenticationStepsOperator implements VaultTokenSupplier {
|
||||
@Override
|
||||
public Mono<VaultToken> getVaultToken() throws VaultException {
|
||||
|
||||
Mono<Object> state = createMono(chain.steps);
|
||||
Mono<Object> state = createMono(this.chain.steps);
|
||||
|
||||
return state.map(stateObject -> {
|
||||
|
||||
@@ -95,11 +93,9 @@ public class AuthenticationStepsOperator implements VaultTokenSupplier {
|
||||
return LoginTokenUtil.from(response.getAuth());
|
||||
}
|
||||
|
||||
throw new IllegalStateException(String.format(
|
||||
"Cannot retrieve VaultToken from authentication chain. Got instead %s",
|
||||
stateObject));
|
||||
}).onErrorMap(t -> new VaultLoginException(
|
||||
"Cannot retrieve VaultToken from authentication chain", t));
|
||||
throw new IllegalStateException(
|
||||
String.format("Cannot retrieve VaultToken from authentication chain. Got instead %s", stateObject));
|
||||
}).onErrorMap(t -> new VaultLoginException("Cannot retrieve VaultToken from authentication chain", t));
|
||||
}
|
||||
|
||||
private Mono<Object> createMono(Iterable<Node<?>> steps) {
|
||||
@@ -109,19 +105,15 @@ public class AuthenticationStepsOperator implements VaultTokenSupplier {
|
||||
for (Node<?> o : steps) {
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(
|
||||
String.format("Executing %s with current state %s", o, state));
|
||||
logger.debug(String.format("Executing %s with current state %s", o, state));
|
||||
}
|
||||
|
||||
if (o instanceof HttpRequestNode) {
|
||||
state = state
|
||||
.flatMap(stateObject -> doHttpRequest((HttpRequestNode<Object>) o,
|
||||
stateObject));
|
||||
state = state.flatMap(stateObject -> doHttpRequest((HttpRequestNode<Object>) o, stateObject));
|
||||
}
|
||||
|
||||
if (o instanceof MapStep) {
|
||||
state = state.map(stateObject -> doMapStep((MapStep<Object, Object>) o,
|
||||
stateObject));
|
||||
state = state.map(stateObject -> doMapStep((MapStep<Object, Object>) o, stateObject));
|
||||
}
|
||||
|
||||
if (o instanceof ZipStep) {
|
||||
@@ -130,18 +122,15 @@ public class AuthenticationStepsOperator implements VaultTokenSupplier {
|
||||
}
|
||||
|
||||
if (o instanceof OnNextStep) {
|
||||
state = state.doOnNext(
|
||||
stateObject -> doOnNext((OnNextStep<Object>) o, stateObject));
|
||||
state = state.doOnNext(stateObject -> doOnNext((OnNextStep<Object>) o, stateObject));
|
||||
}
|
||||
|
||||
if (o instanceof SupplierStep<?>) {
|
||||
state = state
|
||||
.map(stateObject -> doSupplierStep((SupplierStep<Object>) o));
|
||||
state = state.map(stateObject -> doSupplierStep((SupplierStep<Object>) o));
|
||||
}
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(
|
||||
String.format("Executed %s with current state %s", o, state));
|
||||
logger.debug(String.format("Executed %s with current state %s", o, state));
|
||||
}
|
||||
}
|
||||
return state;
|
||||
@@ -171,11 +160,11 @@ public class AuthenticationStepsOperator implements VaultTokenSupplier {
|
||||
RequestBodySpec spec;
|
||||
if (definition.getUri() == null) {
|
||||
|
||||
spec = webClient.method(definition.getMethod()).uri(
|
||||
definition.getUriTemplate(), definition.getUrlVariables());
|
||||
spec = this.webClient.method(definition.getMethod()).uri(definition.getUriTemplate(),
|
||||
definition.getUrlVariables());
|
||||
}
|
||||
else {
|
||||
spec = webClient.method(definition.getMethod()).uri(definition.getUri());
|
||||
spec = this.webClient.method(definition.getMethod()).uri(definition.getUri());
|
||||
}
|
||||
|
||||
for (Entry<String, List<String>> header : entity.getHeaders().entrySet()) {
|
||||
@@ -183,8 +172,7 @@ public class AuthenticationStepsOperator implements VaultTokenSupplier {
|
||||
}
|
||||
|
||||
if (entity.getBody() != null && !entity.getBody().equals(Undefinded.INSTANCE)) {
|
||||
return spec.bodyValue(entity.getBody()).retrieve()
|
||||
.bodyToMono(definition.getResponseType());
|
||||
return spec.bodyValue(entity.getBody()).retrieve().bodyToMono(definition.getResponseType());
|
||||
}
|
||||
|
||||
return spec.retrieve().bodyToMono(definition.getResponseType());
|
||||
@@ -209,5 +197,7 @@ public class AuthenticationStepsOperator implements VaultTokenSupplier {
|
||||
|
||||
private Undefinded() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ abstract class AuthenticationUtil {
|
||||
|
||||
/**
|
||||
* Returns the login path for a {@code authMount}.
|
||||
*
|
||||
* @param authMount
|
||||
* @return
|
||||
*/
|
||||
@@ -19,4 +18,5 @@ abstract class AuthenticationUtil {
|
||||
|
||||
private AuthenticationUtil() {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -46,8 +46,7 @@ import org.springframework.web.client.RestOperations;
|
||||
* @see <a href="https://www.vaultproject.io/docs/auth/aws-ec2.html">Auth Backend:
|
||||
* aws-ec2</a>
|
||||
*/
|
||||
public class AwsEc2Authentication
|
||||
implements ClientAuthentication, AuthenticationStepsFactory {
|
||||
public class AwsEc2Authentication implements ClientAuthentication, AuthenticationStepsFactory {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(AwsEc2Authentication.class);
|
||||
|
||||
@@ -63,31 +62,26 @@ public class AwsEc2Authentication
|
||||
|
||||
/**
|
||||
* Create a new {@link AwsEc2Authentication}.
|
||||
*
|
||||
* @param vaultRestOperations must not be {@literal null}.
|
||||
*/
|
||||
public AwsEc2Authentication(RestOperations vaultRestOperations) {
|
||||
this(AwsEc2AuthenticationOptions.DEFAULT, vaultRestOperations,
|
||||
vaultRestOperations);
|
||||
this(AwsEc2AuthenticationOptions.DEFAULT, vaultRestOperations, vaultRestOperations);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link AwsEc2Authentication} specifying
|
||||
* {@link AwsEc2AuthenticationOptions}, a Vault and an AWS-Metadata-specific
|
||||
* {@link RestOperations}.
|
||||
*
|
||||
* @param options must not be {@literal null}.
|
||||
* @param vaultRestOperations must not be {@literal null}.
|
||||
* @param awsMetadataRestOperations must not be {@literal null}.
|
||||
*/
|
||||
public AwsEc2Authentication(AwsEc2AuthenticationOptions options,
|
||||
RestOperations vaultRestOperations,
|
||||
public AwsEc2Authentication(AwsEc2AuthenticationOptions options, RestOperations vaultRestOperations,
|
||||
RestOperations awsMetadataRestOperations) {
|
||||
|
||||
Assert.notNull(options, "AwsEc2AuthenticationOptions must not be null");
|
||||
Assert.notNull(vaultRestOperations, "Vault RestOperations must not be null");
|
||||
Assert.notNull(awsMetadataRestOperations,
|
||||
"AWS Metadata RestOperations must not be null");
|
||||
Assert.notNull(awsMetadataRestOperations, "AWS Metadata RestOperations must not be null");
|
||||
|
||||
this.options = options;
|
||||
this.vaultRestOperations = vaultRestOperations;
|
||||
@@ -97,13 +91,11 @@ public class AwsEc2Authentication
|
||||
/**
|
||||
* Creates a {@link AuthenticationSteps} for AWS-EC2 authentication given
|
||||
* {@link AwsEc2AuthenticationOptions}.
|
||||
*
|
||||
* @param options must not be {@literal null}.
|
||||
* @return {@link AuthenticationSteps} for AWS-EC2 authentication.
|
||||
* @since 2.0
|
||||
*/
|
||||
public static AuthenticationSteps createAuthenticationSteps(
|
||||
AwsEc2AuthenticationOptions options) {
|
||||
public static AuthenticationSteps createAuthenticationSteps(AwsEc2AuthenticationOptions options) {
|
||||
|
||||
Assert.notNull(options, "AwsEc2AuthenticationOptions must not be null");
|
||||
|
||||
@@ -112,14 +104,11 @@ public class AwsEc2Authentication
|
||||
return createAuthenticationSteps(options, nonce, () -> doCreateNonce(options));
|
||||
}
|
||||
|
||||
protected static AuthenticationSteps createAuthenticationSteps(
|
||||
AwsEc2AuthenticationOptions options, AtomicReference<char[]> nonce,
|
||||
Supplier<char[]> nonceSupplier) {
|
||||
protected static AuthenticationSteps createAuthenticationSteps(AwsEc2AuthenticationOptions options,
|
||||
AtomicReference<char[]> nonce, Supplier<char[]> nonceSupplier) {
|
||||
|
||||
return AuthenticationSteps
|
||||
.fromHttpRequest(HttpRequestBuilder
|
||||
.get(options.getIdentityDocumentUri().toString())
|
||||
.as(String.class)) //
|
||||
.fromHttpRequest(HttpRequestBuilder.get(options.getIdentityDocumentUri().toString()).as(String.class)) //
|
||||
.map(pkcs7 -> pkcs7.replaceAll("\\r", "")) //
|
||||
.map(pkcs7 -> pkcs7.replace("\\n", "")) //
|
||||
.map(pkcs7 -> {
|
||||
@@ -158,19 +147,16 @@ public class AwsEc2Authentication
|
||||
|
||||
try {
|
||||
|
||||
VaultResponse response = this.vaultRestOperations.postForObject(
|
||||
AuthenticationUtil.getLoginPath(options.getPath()), login, VaultResponse.class);
|
||||
VaultResponse response = this.vaultRestOperations
|
||||
.postForObject(AuthenticationUtil.getLoginPath(this.options.getPath()), login, VaultResponse.class);
|
||||
|
||||
Assert.state(response != null && response.getAuth() != null,
|
||||
"Auth field must not be null");
|
||||
Assert.state(response != null && response.getAuth() != null, "Auth field must not be null");
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
|
||||
if (response.getAuth().get("metadata") instanceof Map) {
|
||||
Map<Object, Object> metadata = (Map<Object, Object>) response
|
||||
.getAuth().get("metadata");
|
||||
logger.debug(String.format(
|
||||
"Login successful using AWS-EC2 authentication for instance %s, AMI %s",
|
||||
Map<Object, Object> metadata = (Map<Object, Object>) response.getAuth().get("metadata");
|
||||
logger.debug(String.format("Login successful using AWS-EC2 authentication for instance %s, AMI %s",
|
||||
metadata.get("instance_id"), metadata.get("instance_id")));
|
||||
}
|
||||
else {
|
||||
@@ -189,8 +175,8 @@ public class AwsEc2Authentication
|
||||
|
||||
Map<String, String> login = new HashMap<>();
|
||||
|
||||
if (StringUtils.hasText(options.getRole())) {
|
||||
login.put("role", options.getRole());
|
||||
if (StringUtils.hasText(this.options.getRole())) {
|
||||
login.put("role", this.options.getRole());
|
||||
}
|
||||
|
||||
if (Objects.equals(this.nonce.get(), EMPTY)) {
|
||||
@@ -200,8 +186,8 @@ public class AwsEc2Authentication
|
||||
login.put("nonce", new String(this.nonce.get()));
|
||||
|
||||
try {
|
||||
String pkcs7 = this.awsMetadataRestOperations
|
||||
.getForObject(this.options.getIdentityDocumentUri(), String.class);
|
||||
String pkcs7 = this.awsMetadataRestOperations.getForObject(this.options.getIdentityDocumentUri(),
|
||||
String.class);
|
||||
if (StringUtils.hasText(pkcs7)) {
|
||||
login.put("pkcs7", pkcs7.replaceAll("\\r", "").replace("\\n", ""));
|
||||
}
|
||||
@@ -210,9 +196,7 @@ public class AwsEc2Authentication
|
||||
}
|
||||
catch (RestClientException e) {
|
||||
throw new VaultLoginException(
|
||||
String.format("Cannot obtain Identity Document from %s",
|
||||
options.getIdentityDocumentUri()),
|
||||
e);
|
||||
String.format("Cannot obtain Identity Document from %s", this.options.getIdentityDocumentUri()), e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -223,4 +207,5 @@ public class AwsEc2Authentication
|
||||
private static char[] doCreateNonce(AwsEc2AuthenticationOptions options) {
|
||||
return options.getNonce().getValue();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -69,12 +69,10 @@ public class AwsEc2AuthenticationOptions {
|
||||
private final Nonce nonce;
|
||||
|
||||
private AwsEc2AuthenticationOptions() {
|
||||
this(DEFAULT_AWS_AUTHENTICATION_PATH, DEFAULT_PKCS7_IDENTITY_DOCUMENT_URI, "",
|
||||
Nonce.generated());
|
||||
this(DEFAULT_AWS_AUTHENTICATION_PATH, DEFAULT_PKCS7_IDENTITY_DOCUMENT_URI, "", Nonce.generated());
|
||||
}
|
||||
|
||||
private AwsEc2AuthenticationOptions(String path, URI identityDocumentUri,
|
||||
@Nullable String role, Nonce nonce) {
|
||||
private AwsEc2AuthenticationOptions(String path, URI identityDocumentUri, @Nullable String role, Nonce nonce) {
|
||||
|
||||
this.path = path;
|
||||
this.identityDocumentUri = identityDocumentUri;
|
||||
@@ -93,14 +91,14 @@ public class AwsEc2AuthenticationOptions {
|
||||
* @return the path of the aws-ec2 authentication backend mount.
|
||||
*/
|
||||
public String getPath() {
|
||||
return path;
|
||||
return this.path;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the {@link URI} to the AWS EC2 PKCS#7-signed identity document.
|
||||
*/
|
||||
public URI getIdentityDocumentUri() {
|
||||
return identityDocumentUri;
|
||||
return this.identityDocumentUri;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -108,14 +106,14 @@ public class AwsEc2AuthenticationOptions {
|
||||
*/
|
||||
@Nullable
|
||||
public String getRole() {
|
||||
return role;
|
||||
return this.role;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the configured {@link Nonce}.
|
||||
*/
|
||||
public Nonce getNonce() {
|
||||
return nonce;
|
||||
return this.nonce;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -124,6 +122,7 @@ public class AwsEc2AuthenticationOptions {
|
||||
public static class AwsEc2AuthenticationOptionsBuilder {
|
||||
|
||||
private String path = DEFAULT_AWS_AUTHENTICATION_PATH;
|
||||
|
||||
private URI identityDocumentUri = DEFAULT_PKCS7_IDENTITY_DOCUMENT_URI;
|
||||
|
||||
@Nullable
|
||||
@@ -136,7 +135,6 @@ public class AwsEc2AuthenticationOptions {
|
||||
|
||||
/**
|
||||
* Configure the mount path.
|
||||
*
|
||||
* @param path must not be empty or {@literal null}.
|
||||
* @return {@code this} {@link AwsEc2AuthenticationOptionsBuilder}.
|
||||
*/
|
||||
@@ -150,13 +148,11 @@ public class AwsEc2AuthenticationOptions {
|
||||
|
||||
/**
|
||||
* Configure the Identity Document {@link URI}.
|
||||
*
|
||||
* @param identityDocumentUri must not be {@literal null}.
|
||||
* @return {@code this} {@link AwsEc2AuthenticationOptionsBuilder}.
|
||||
* @see #DEFAULT_PKCS7_IDENTITY_DOCUMENT_URI
|
||||
*/
|
||||
public AwsEc2AuthenticationOptionsBuilder identityDocumentUri(
|
||||
URI identityDocumentUri) {
|
||||
public AwsEc2AuthenticationOptionsBuilder identityDocumentUri(URI identityDocumentUri) {
|
||||
|
||||
Assert.notNull(identityDocumentUri, "Identity document URI must not be null");
|
||||
|
||||
@@ -168,7 +164,6 @@ public class AwsEc2AuthenticationOptions {
|
||||
* Configure the name of the role against which the login is being attempted.If
|
||||
* role is not specified, then the login endpoint looks for a role bearing the
|
||||
* name of the AMI ID of the EC2 instance that is trying to login.
|
||||
*
|
||||
* @param role may be empty or {@literal null}.
|
||||
* @return {@code this} {@link AwsEc2AuthenticationOptionsBuilder}.
|
||||
*/
|
||||
@@ -181,7 +176,6 @@ public class AwsEc2AuthenticationOptions {
|
||||
/**
|
||||
* Configure a {@link Nonce} for login requests. Defaults to
|
||||
* {@link Nonce#generated()}.
|
||||
*
|
||||
* @param nonce must not be {@literal null}.
|
||||
* @return {@code this} {@link AwsEc2AuthenticationOptionsBuilder}.
|
||||
* @since 1.1
|
||||
@@ -196,16 +190,15 @@ public class AwsEc2AuthenticationOptions {
|
||||
|
||||
/**
|
||||
* Build a new {@link AwsEc2AuthenticationOptions} instance.
|
||||
*
|
||||
* @return a new {@link AwsEc2AuthenticationOptions}.
|
||||
*/
|
||||
public AwsEc2AuthenticationOptions build() {
|
||||
|
||||
Assert.notNull(identityDocumentUri, "IdentityDocumentUri must not be null");
|
||||
Assert.notNull(this.identityDocumentUri, "IdentityDocumentUri must not be null");
|
||||
|
||||
return new AwsEc2AuthenticationOptions(path, identityDocumentUri, role,
|
||||
nonce);
|
||||
return new AwsEc2AuthenticationOptions(this.path, this.identityDocumentUri, this.role, this.nonce);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -223,7 +216,6 @@ public class AwsEc2AuthenticationOptions {
|
||||
|
||||
/**
|
||||
* Create a new generated {@link Nonce} using {@link UUID}.
|
||||
*
|
||||
* @return a new generated {@link Nonce} using {@link UUID}.
|
||||
*/
|
||||
public static Nonce generated() {
|
||||
@@ -232,7 +224,6 @@ public class AwsEc2AuthenticationOptions {
|
||||
|
||||
/**
|
||||
* Create a wrapped {@link Nonce} given a {@code nonce} value.
|
||||
*
|
||||
* @return a wrapped {@link Nonce} given for the {@code nonce} value.
|
||||
*/
|
||||
public static Nonce provided(char[] nonce) {
|
||||
@@ -246,7 +237,7 @@ public class AwsEc2AuthenticationOptions {
|
||||
* @return the nonce value.
|
||||
*/
|
||||
public char[] getValue() {
|
||||
return value;
|
||||
return this.value;
|
||||
}
|
||||
|
||||
static class Generated extends Nonce {
|
||||
@@ -254,6 +245,7 @@ public class AwsEc2AuthenticationOptions {
|
||||
Generated() {
|
||||
super(UUID.randomUUID().toString().toCharArray());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class Provided extends Nonce {
|
||||
@@ -261,6 +253,9 @@ public class AwsEc2AuthenticationOptions {
|
||||
Provided(char[] nonce) {
|
||||
super(nonce);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -66,8 +66,7 @@ import org.springframework.web.client.RestOperations;
|
||||
* "https://docs.aws.amazon.com/STS/latest/APIReference/API_GetCallerIdentity.html">AWS:
|
||||
* GetCallerIdentity</a>
|
||||
*/
|
||||
public class AwsIamAuthentication
|
||||
implements ClientAuthentication, AuthenticationStepsFactory {
|
||||
public class AwsIamAuthentication implements ClientAuthentication, AuthenticationStepsFactory {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(AwsIamAuthentication.class);
|
||||
|
||||
@@ -75,8 +74,7 @@ public class AwsIamAuthentication
|
||||
|
||||
private static final String REQUEST_BODY = "Action=GetCallerIdentity&Version=2011-06-15";
|
||||
|
||||
private static final String REQUEST_BODY_BASE64_ENCODED = Base64Utils
|
||||
.encodeToString(REQUEST_BODY.getBytes());
|
||||
private static final String REQUEST_BODY_BASE64_ENCODED = Base64Utils.encodeToString(REQUEST_BODY.getBytes());
|
||||
|
||||
private final AwsIamAuthenticationOptions options;
|
||||
|
||||
@@ -86,12 +84,10 @@ public class AwsIamAuthentication
|
||||
* Create a new {@link AwsIamAuthentication} specifying
|
||||
* {@link AwsIamAuthenticationOptions}, a Vault and an AWS-Metadata-specific
|
||||
* {@link RestOperations}.
|
||||
*
|
||||
* @param options must not be {@literal null}.
|
||||
* @param vaultRestOperations must not be {@literal null}.
|
||||
*/
|
||||
public AwsIamAuthentication(AwsIamAuthenticationOptions options,
|
||||
RestOperations vaultRestOperations) {
|
||||
public AwsIamAuthentication(AwsIamAuthenticationOptions options, RestOperations vaultRestOperations) {
|
||||
|
||||
Assert.notNull(options, "AwsIamAuthenticationOptions must not be null");
|
||||
Assert.notNull(vaultRestOperations, "Vault RestOperations must not be null");
|
||||
@@ -105,13 +101,11 @@ public class AwsIamAuthentication
|
||||
* {@link AwsIamAuthenticationOptions}. The resulting {@link AuthenticationSteps}
|
||||
* reuse eagerly-fetched {@link AWSCredentials} to prevent blocking I/O during
|
||||
* authentication.
|
||||
*
|
||||
* @param options must not be {@literal null}.
|
||||
* @return {@link AuthenticationSteps} for AWS-IAM authentication.
|
||||
* @since 2.2
|
||||
*/
|
||||
public static AuthenticationSteps createAuthenticationSteps(
|
||||
AwsIamAuthenticationOptions options) {
|
||||
public static AuthenticationSteps createAuthenticationSteps(AwsIamAuthenticationOptions options) {
|
||||
|
||||
Assert.notNull(options, "AwsIamAuthenticationOptions must not be null");
|
||||
|
||||
@@ -120,11 +114,10 @@ public class AwsIamAuthentication
|
||||
return createAuthenticationSteps(options, credentials);
|
||||
}
|
||||
|
||||
protected static AuthenticationSteps createAuthenticationSteps(
|
||||
AwsIamAuthenticationOptions options, AWSCredentials credentials) {
|
||||
protected static AuthenticationSteps createAuthenticationSteps(AwsIamAuthenticationOptions options,
|
||||
AWSCredentials credentials) {
|
||||
|
||||
return AuthenticationSteps
|
||||
.fromSupplier(() -> createRequestBody(options, credentials)) //
|
||||
return AuthenticationSteps.fromSupplier(() -> createRequestBody(options, credentials)) //
|
||||
.login(AuthenticationUtil.getLoginPath(options.getPath()));
|
||||
}
|
||||
|
||||
@@ -135,8 +128,7 @@ public class AwsIamAuthentication
|
||||
|
||||
@Override
|
||||
public AuthenticationSteps getAuthenticationSteps() {
|
||||
return createAuthenticationSteps(this.options,
|
||||
this.options.getCredentialsProvider().getCredentials());
|
||||
return createAuthenticationSteps(this.options, this.options.getCredentialsProvider().getCredentials());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@@ -146,21 +138,17 @@ public class AwsIamAuthentication
|
||||
|
||||
try {
|
||||
|
||||
VaultResponse response = this.vaultRestOperations.postForObject(
|
||||
AuthenticationUtil.getLoginPath(options.getPath()), login, VaultResponse.class);
|
||||
VaultResponse response = this.vaultRestOperations
|
||||
.postForObject(AuthenticationUtil.getLoginPath(this.options.getPath()), login, VaultResponse.class);
|
||||
|
||||
Assert.state(response != null && response.getAuth() != null,
|
||||
"Auth field must not be null");
|
||||
Assert.state(response != null && response.getAuth() != null, "Auth field must not be null");
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
|
||||
if (response.getAuth().get("metadata") instanceof Map) {
|
||||
Map<Object, Object> metadata = (Map<Object, Object>) response
|
||||
.getAuth().get("metadata");
|
||||
logger.debug(String.format(
|
||||
"Login successful using AWS-IAM authentication for user id %s, ARN %s",
|
||||
metadata.get("client_user_id"),
|
||||
metadata.get("canonical_arn")));
|
||||
Map<Object, Object> metadata = (Map<Object, Object>) response.getAuth().get("metadata");
|
||||
logger.debug(String.format("Login successful using AWS-IAM authentication for user id %s, ARN %s",
|
||||
metadata.get("client_user_id"), metadata.get("canonical_arn")));
|
||||
}
|
||||
else {
|
||||
logger.debug("Login successful using AWS-IAM authentication");
|
||||
@@ -177,37 +165,31 @@ public class AwsIamAuthentication
|
||||
/**
|
||||
* Create the request body to perform a Vault login using the AWS-IAM authentication
|
||||
* method.
|
||||
*
|
||||
* @param options must not be {@literal null}.
|
||||
* @return the map containing body key-value pairs.
|
||||
*/
|
||||
protected static Map<String, String> createRequestBody(
|
||||
AwsIamAuthenticationOptions options) {
|
||||
return createRequestBody(options,
|
||||
options.getCredentialsProvider().getCredentials());
|
||||
protected static Map<String, String> createRequestBody(AwsIamAuthenticationOptions options) {
|
||||
return createRequestBody(options, options.getCredentialsProvider().getCredentials());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the request body to perform a Vault login using the AWS-IAM authentication
|
||||
* method.
|
||||
*
|
||||
* @param options must not be {@literal null}.
|
||||
* @return the map containing body key-value pairs.
|
||||
*/
|
||||
private static Map<String, String> createRequestBody(
|
||||
AwsIamAuthenticationOptions options, AWSCredentials credentials) {
|
||||
private static Map<String, String> createRequestBody(AwsIamAuthenticationOptions options,
|
||||
AWSCredentials credentials) {
|
||||
|
||||
Map<String, String> login = new HashMap<>();
|
||||
|
||||
login.put("iam_http_request_method", "POST");
|
||||
login.put("iam_request_url", Base64Utils
|
||||
.encodeToString(options.getEndpointUri().toString().getBytes()));
|
||||
login.put("iam_request_url", Base64Utils.encodeToString(options.getEndpointUri().toString().getBytes()));
|
||||
login.put("iam_request_body", REQUEST_BODY_BASE64_ENCODED);
|
||||
|
||||
String headerJson = getSignedHeaders(options, credentials);
|
||||
|
||||
login.put("iam_request_headers",
|
||||
Base64Utils.encodeToString(headerJson.getBytes()));
|
||||
login.put("iam_request_headers", Base64Utils.encodeToString(headerJson.getBytes()));
|
||||
|
||||
if (!StringUtils.isEmpty(options.getRole())) {
|
||||
login.put("role", options.getRole());
|
||||
@@ -215,8 +197,7 @@ public class AwsIamAuthentication
|
||||
return login;
|
||||
}
|
||||
|
||||
private static String getSignedHeaders(AwsIamAuthenticationOptions options,
|
||||
AWSCredentials credentials) {
|
||||
private static String getSignedHeaders(AwsIamAuthenticationOptions options, AWSCredentials credentials) {
|
||||
|
||||
Map<String, String> headers = createIamRequestHeaders(options);
|
||||
|
||||
@@ -246,14 +227,12 @@ public class AwsIamAuthentication
|
||||
}
|
||||
}
|
||||
|
||||
private static Map<String, String> createIamRequestHeaders(
|
||||
AwsIamAuthenticationOptions options) {
|
||||
private static Map<String, String> createIamRequestHeaders(AwsIamAuthenticationOptions options) {
|
||||
|
||||
Map<String, String> headers = new LinkedHashMap<>();
|
||||
|
||||
headers.put(HttpHeaders.CONTENT_LENGTH, "" + REQUEST_BODY.length());
|
||||
headers.put(HttpHeaders.CONTENT_TYPE,
|
||||
MediaType.APPLICATION_FORM_URLENCODED_VALUE);
|
||||
headers.put(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED_VALUE);
|
||||
|
||||
if (StringUtils.hasText(options.getServerId())) {
|
||||
headers.put("X-Vault-AWS-IAM-Server-ID", options.getServerId());
|
||||
@@ -261,4 +240,5 @@ public class AwsIamAuthentication
|
||||
|
||||
return headers;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -71,8 +71,7 @@ public class AwsIamAuthenticationOptions {
|
||||
*/
|
||||
private final URI endpointUri;
|
||||
|
||||
private AwsIamAuthenticationOptions(String path,
|
||||
AWSCredentialsProvider credentialsProvider, @Nullable String role,
|
||||
private AwsIamAuthenticationOptions(String path, AWSCredentialsProvider credentialsProvider, @Nullable String role,
|
||||
@Nullable String serverId, URI endpointUri) {
|
||||
|
||||
this.path = path;
|
||||
@@ -93,14 +92,14 @@ public class AwsIamAuthenticationOptions {
|
||||
* @return the path of the aws authentication backend mount.
|
||||
*/
|
||||
public String getPath() {
|
||||
return path;
|
||||
return this.path;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the credentials provider to obtain AWS credentials.
|
||||
*/
|
||||
public AWSCredentialsProvider getCredentialsProvider() {
|
||||
return credentialsProvider;
|
||||
return this.credentialsProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -108,7 +107,7 @@ public class AwsIamAuthenticationOptions {
|
||||
*/
|
||||
@Nullable
|
||||
public String getRole() {
|
||||
return role;
|
||||
return this.role;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -119,7 +118,7 @@ public class AwsIamAuthenticationOptions {
|
||||
*/
|
||||
@Nullable
|
||||
public String getServerId() {
|
||||
return serverId;
|
||||
return this.serverId;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -130,14 +129,14 @@ public class AwsIamAuthenticationOptions {
|
||||
@Nullable
|
||||
@Deprecated
|
||||
public String getServerName() {
|
||||
return serverId;
|
||||
return this.serverId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return STS server URI.
|
||||
*/
|
||||
public URI getEndpointUri() {
|
||||
return endpointUri;
|
||||
return this.endpointUri;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -163,7 +162,6 @@ public class AwsIamAuthenticationOptions {
|
||||
|
||||
/**
|
||||
* Configure the mount path, defaults to {@literal aws}.
|
||||
*
|
||||
* @param path must not be empty or {@literal null}.
|
||||
* @return {@code this} {@link AwsIamAuthenticationOptionsBuilder}.
|
||||
*/
|
||||
@@ -179,13 +177,11 @@ public class AwsIamAuthenticationOptions {
|
||||
* Configure static AWS credentials, required to calculate the signature. Either
|
||||
* use static credentials or provide a
|
||||
* {@link #credentialsProvider(AWSCredentialsProvider) credentials provider}.
|
||||
*
|
||||
* @param credentials must not be {@literal null}.
|
||||
* @return {@code this} {@link AwsIamAuthenticationOptionsBuilder}.
|
||||
* @see #credentialsProvider(AWSCredentialsProvider)
|
||||
*/
|
||||
public AwsIamAuthenticationOptionsBuilder credentials(
|
||||
AWSCredentials credentials) {
|
||||
public AwsIamAuthenticationOptionsBuilder credentials(AWSCredentials credentials) {
|
||||
|
||||
Assert.notNull(credentials, "Credentials must not be null");
|
||||
|
||||
@@ -196,16 +192,13 @@ public class AwsIamAuthenticationOptions {
|
||||
* Configure an {@link AWSCredentialsProvider}, required to calculate the
|
||||
* signature. Alternatively, configure static {@link #credentials(AWSCredentials)
|
||||
* credentials}.
|
||||
*
|
||||
* @param credentialsProvider must not be {@literal null}.
|
||||
* @return {@code this} {@link AwsIamAuthenticationOptionsBuilder}.
|
||||
* @see #credentials(AWSCredentials)
|
||||
*/
|
||||
public AwsIamAuthenticationOptionsBuilder credentialsProvider(
|
||||
AWSCredentialsProvider credentialsProvider) {
|
||||
public AwsIamAuthenticationOptionsBuilder credentialsProvider(AWSCredentialsProvider credentialsProvider) {
|
||||
|
||||
Assert.notNull(credentialsProvider,
|
||||
"AWSCredentialsProvider must not be null");
|
||||
Assert.notNull(credentialsProvider, "AWSCredentialsProvider must not be null");
|
||||
|
||||
this.credentialsProvider = credentialsProvider;
|
||||
return this;
|
||||
@@ -215,7 +208,6 @@ public class AwsIamAuthenticationOptions {
|
||||
* Configure the name of the role against which the login is being attempted. If
|
||||
* role is not specified, the friendly name (i.e., role name or username) of the
|
||||
* IAM principal authenticated. If a matching role is not found, login fails.
|
||||
*
|
||||
* @param role must not be empty or {@literal null}.
|
||||
* @return {@code this} {@link AwsIamAuthenticationOptionsBuilder}.
|
||||
*/
|
||||
@@ -231,7 +223,6 @@ public class AwsIamAuthenticationOptions {
|
||||
* Configure a server name (used for {@literal Vault-AWS-IAM-Server-ID}) that is
|
||||
* included in the signature to mitigate the risk of replay attacks. Preferably
|
||||
* use the Vault server DNS name.
|
||||
*
|
||||
* @param serverId must not be {@literal null} or empty.
|
||||
* @return {@code this} {@link AwsIamAuthenticationOptionsBuilder}.
|
||||
* @since 2.1
|
||||
@@ -247,7 +238,6 @@ public class AwsIamAuthenticationOptions {
|
||||
/**
|
||||
* Configure a server name that is included in the signature to mitigate the risk
|
||||
* of replay attacks. Preferably use the Vault server DNS name.
|
||||
*
|
||||
* @param serverName must not be {@literal null} or empty.
|
||||
* @return {@code this} {@link AwsIamAuthenticationOptionsBuilder}.
|
||||
*/
|
||||
@@ -258,7 +248,6 @@ public class AwsIamAuthenticationOptions {
|
||||
/**
|
||||
* Configure an endpoint URI of the STS API, defaults to
|
||||
* {@literal https://sts.amazonaws.com/}.
|
||||
*
|
||||
* @param endpointUri must not be {@literal null}.
|
||||
* @return {@code this} {@link AwsIamAuthenticationOptionsBuilder}.
|
||||
*/
|
||||
@@ -272,16 +261,16 @@ public class AwsIamAuthenticationOptions {
|
||||
|
||||
/**
|
||||
* Build a new {@link AwsIamAuthenticationOptions} instance.
|
||||
*
|
||||
* @return a new {@link AwsIamAuthenticationOptions}.
|
||||
*/
|
||||
public AwsIamAuthenticationOptions build() {
|
||||
|
||||
Assert.state(credentialsProvider != null,
|
||||
"Credentials or CredentialProvider must not be null");
|
||||
Assert.state(this.credentialsProvider != null, "Credentials or CredentialProvider must not be null");
|
||||
|
||||
return new AwsIamAuthenticationOptions(path, credentialsProvider, role,
|
||||
serverId, endpointUri);
|
||||
return new AwsIamAuthenticationOptions(this.path, this.credentialsProvider, this.role, this.serverId,
|
||||
this.endpointUri);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -73,12 +73,10 @@ public class AzureMsiAuthentication implements ClientAuthentication {
|
||||
|
||||
/**
|
||||
* Create a new {@link AzureMsiAuthentication}.
|
||||
*
|
||||
* @param options must not be {@literal null}.
|
||||
* @param restOperations must not be {@literal null}.
|
||||
*/
|
||||
public AzureMsiAuthentication(AzureMsiAuthenticationOptions options,
|
||||
RestOperations restOperations) {
|
||||
public AzureMsiAuthentication(AzureMsiAuthenticationOptions options, RestOperations restOperations) {
|
||||
this(options, restOperations, restOperations);
|
||||
}
|
||||
|
||||
@@ -86,19 +84,16 @@ public class AzureMsiAuthentication implements ClientAuthentication {
|
||||
* Create a new {@link AzureMsiAuthentication} specifying
|
||||
* {@link AzureMsiAuthenticationOptions}, a Vault and an Azure-Metadata-specific
|
||||
* {@link RestOperations}.
|
||||
*
|
||||
* @param options must not be {@literal null}.
|
||||
* @param vaultRestOperations must not be {@literal null}.
|
||||
* @param azureMetadataRestOperations must not be {@literal null}.
|
||||
*/
|
||||
public AzureMsiAuthentication(AzureMsiAuthenticationOptions options,
|
||||
RestOperations vaultRestOperations,
|
||||
public AzureMsiAuthentication(AzureMsiAuthenticationOptions options, RestOperations vaultRestOperations,
|
||||
RestOperations azureMetadataRestOperations) {
|
||||
|
||||
Assert.notNull(options, "AzureAuthenticationOptions must not be null");
|
||||
Assert.notNull(vaultRestOperations, "Vault RestOperations must not be null");
|
||||
Assert.notNull(azureMetadataRestOperations,
|
||||
"Azure Instance Metadata RestOperations must not be null");
|
||||
Assert.notNull(azureMetadataRestOperations, "Azure Instance Metadata RestOperations must not be null");
|
||||
|
||||
this.options = options;
|
||||
this.vaultRestOperations = vaultRestOperations;
|
||||
@@ -108,26 +103,22 @@ public class AzureMsiAuthentication implements ClientAuthentication {
|
||||
/**
|
||||
* Creates a {@link AuthenticationSteps} for Azure authentication given
|
||||
* {@link AzureMsiAuthenticationOptions}.
|
||||
*
|
||||
* @param options must not be {@literal null}.
|
||||
* @return {@link AuthenticationSteps} for Azure authentication.
|
||||
*/
|
||||
public static AuthenticationSteps createAuthenticationSteps(
|
||||
AzureMsiAuthenticationOptions options) {
|
||||
public static AuthenticationSteps createAuthenticationSteps(AzureMsiAuthenticationOptions options) {
|
||||
|
||||
Assert.notNull(options, "AzureMsiAuthenticationOptions must not be null");
|
||||
|
||||
return createAuthenticationSteps(options, options.getVmEnvironment());
|
||||
}
|
||||
|
||||
protected static AuthenticationSteps createAuthenticationSteps(
|
||||
AzureMsiAuthenticationOptions options,
|
||||
protected static AuthenticationSteps createAuthenticationSteps(AzureMsiAuthenticationOptions options,
|
||||
@Nullable AzureVmEnvironment environment) {
|
||||
|
||||
Node<String> msiToken = AuthenticationSteps
|
||||
.fromHttpRequest(
|
||||
HttpRequestBuilder.get(options.getIdentityTokenServiceUri())
|
||||
.with(METADATA_HEADERS).as(Map.class)) //
|
||||
.fromHttpRequest(HttpRequestBuilder.get(options.getIdentityTokenServiceUri()).with(METADATA_HEADERS)
|
||||
.as(Map.class)) //
|
||||
.map(token -> (String) token.get("access_token"));
|
||||
|
||||
Node<AzureVmEnvironment> environmentSteps;
|
||||
@@ -135,8 +126,7 @@ public class AzureMsiAuthentication implements ClientAuthentication {
|
||||
if (environment == null) {
|
||||
|
||||
environmentSteps = AuthenticationSteps
|
||||
.fromHttpRequest(HttpRequestBuilder
|
||||
.get(options.getInstanceMetadataServiceUri())
|
||||
.fromHttpRequest(HttpRequestBuilder.get(options.getInstanceMetadataServiceUri())
|
||||
.with(METADATA_HEADERS).as(Map.class)) //
|
||||
.map(AzureMsiAuthentication::toAzureVmEnvironment);
|
||||
}
|
||||
@@ -145,8 +135,7 @@ public class AzureMsiAuthentication implements ClientAuthentication {
|
||||
}
|
||||
|
||||
return environmentSteps.zipWith(msiToken)
|
||||
.map(tuple -> getAzureLogin(options.getRole(), tuple.getLeft(),
|
||||
tuple.getRight())) //
|
||||
.map(tuple -> getAzureLogin(options.getRole(), tuple.getLeft(), tuple.getRight())) //
|
||||
.login(AuthenticationUtil.getLoginPath(options.getPath()));
|
||||
}
|
||||
|
||||
@@ -157,16 +146,14 @@ public class AzureMsiAuthentication implements ClientAuthentication {
|
||||
|
||||
private VaultToken createTokenUsingAzureMsiCompute() {
|
||||
|
||||
Map<String, String> login = getAzureLogin(options.getRole(), getVmEnvironment(),
|
||||
getAccessToken());
|
||||
Map<String, String> login = getAzureLogin(this.options.getRole(), getVmEnvironment(), getAccessToken());
|
||||
|
||||
try {
|
||||
|
||||
VaultResponse response = this.vaultRestOperations.postForObject(
|
||||
AuthenticationUtil.getLoginPath(options.getPath()), login, VaultResponse.class);
|
||||
VaultResponse response = this.vaultRestOperations
|
||||
.postForObject(AuthenticationUtil.getLoginPath(this.options.getPath()), login, VaultResponse.class);
|
||||
|
||||
Assert.state(response != null && response.getAuth() != null,
|
||||
"Auth field must not be null");
|
||||
Assert.state(response != null && response.getAuth() != null, "Auth field must not be null");
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Login successful using Azure authentication");
|
||||
@@ -179,8 +166,7 @@ public class AzureMsiAuthentication implements ClientAuthentication {
|
||||
}
|
||||
}
|
||||
|
||||
private static Map<String, String> getAzureLogin(String role,
|
||||
AzureVmEnvironment vmEnvironment, String jwt) {
|
||||
private static Map<String, String> getAzureLogin(String role, AzureVmEnvironment vmEnvironment, String jwt) {
|
||||
|
||||
Map<String, String> loginBody = new LinkedHashMap<>();
|
||||
loginBody.put("resource_group_name", vmEnvironment.getResourceGroupName());
|
||||
@@ -194,32 +180,29 @@ public class AzureMsiAuthentication implements ClientAuthentication {
|
||||
|
||||
private String getAccessToken() {
|
||||
|
||||
ResponseEntity<Map> response = this.azureMetadataRestOperations.exchange(
|
||||
options.getIdentityTokenServiceUri(), HttpMethod.GET, METADATA_HEADERS,
|
||||
Map.class);
|
||||
ResponseEntity<Map> response = this.azureMetadataRestOperations
|
||||
.exchange(this.options.getIdentityTokenServiceUri(), HttpMethod.GET, METADATA_HEADERS, Map.class);
|
||||
|
||||
return (String) response.getBody().get("access_token");
|
||||
}
|
||||
|
||||
private AzureVmEnvironment getVmEnvironment() {
|
||||
|
||||
AzureVmEnvironment vmEnvironment = options.getVmEnvironment();
|
||||
AzureVmEnvironment vmEnvironment = this.options.getVmEnvironment();
|
||||
|
||||
return vmEnvironment != null ? vmEnvironment : fetchAzureVmEnvironment();
|
||||
}
|
||||
|
||||
private AzureVmEnvironment fetchAzureVmEnvironment() {
|
||||
|
||||
ResponseEntity<Map> response = this.azureMetadataRestOperations.exchange(
|
||||
options.getInstanceMetadataServiceUri(), HttpMethod.GET, METADATA_HEADERS,
|
||||
Map.class);
|
||||
ResponseEntity<Map> response = this.azureMetadataRestOperations
|
||||
.exchange(this.options.getInstanceMetadataServiceUri(), HttpMethod.GET, METADATA_HEADERS, Map.class);
|
||||
|
||||
return toAzureVmEnvironment(response.getBody());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static AzureVmEnvironment toAzureVmEnvironment(
|
||||
Map<String, Object> instanceMetadata) {
|
||||
private static AzureVmEnvironment toAzureVmEnvironment(Map<String, Object> instanceMetadata) {
|
||||
|
||||
Map<String, String> compute = (Map) instanceMetadata.get("compute");
|
||||
|
||||
@@ -229,4 +212,5 @@ public class AzureMsiAuthentication implements ClientAuthentication {
|
||||
|
||||
return new AzureVmEnvironment(subscriptionId, resourceGroupName, vmName);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -69,9 +69,8 @@ public class AzureMsiAuthenticationOptions {
|
||||
@Nullable
|
||||
private final AzureVmEnvironment vmEnvironment;
|
||||
|
||||
private AzureMsiAuthenticationOptions(String path, String role,
|
||||
URI instanceMetadataServiceUri, URI identityTokenServiceUri,
|
||||
@Nullable AzureVmEnvironment vmEnvironment) {
|
||||
private AzureMsiAuthenticationOptions(String path, String role, URI instanceMetadataServiceUri,
|
||||
URI identityTokenServiceUri, @Nullable AzureVmEnvironment vmEnvironment) {
|
||||
|
||||
this.path = path;
|
||||
this.role = role;
|
||||
@@ -91,14 +90,14 @@ public class AzureMsiAuthenticationOptions {
|
||||
* @return the path of the azure authentication backend mount.
|
||||
*/
|
||||
public String getPath() {
|
||||
return path;
|
||||
return this.path;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the role against which the login is being attempted.
|
||||
*/
|
||||
public String getRole() {
|
||||
return role;
|
||||
return this.role;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -108,21 +107,21 @@ public class AzureMsiAuthenticationOptions {
|
||||
*/
|
||||
@Nullable
|
||||
public AzureVmEnvironment getVmEnvironment() {
|
||||
return vmEnvironment;
|
||||
return this.vmEnvironment;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@link URI} to the instance metadata endpoint.
|
||||
*/
|
||||
public URI getInstanceMetadataServiceUri() {
|
||||
return instanceMetadataServiceUri;
|
||||
return this.instanceMetadataServiceUri;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@link URI} to the token service for the managed identity.
|
||||
*/
|
||||
public URI getIdentityTokenServiceUri() {
|
||||
return identityTokenServiceUri;
|
||||
return this.identityTokenServiceUri;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -147,7 +146,6 @@ public class AzureMsiAuthenticationOptions {
|
||||
|
||||
/**
|
||||
* Configure the mount path, defaults to {@literal azure}.
|
||||
*
|
||||
* @param path must not be empty or {@literal null}.
|
||||
* @return {@code this} {@link AzureMsiAuthenticationOptionsBuilder}.
|
||||
*/
|
||||
@@ -161,7 +159,6 @@ public class AzureMsiAuthenticationOptions {
|
||||
|
||||
/**
|
||||
* Configure the name of the role against which the login is being attempted.
|
||||
*
|
||||
* @param role must not be empty or {@literal null}.
|
||||
* @return {@code this} {@link AzureMsiAuthenticationOptionsBuilder}.
|
||||
*/
|
||||
@@ -178,12 +175,10 @@ public class AzureMsiAuthenticationOptions {
|
||||
* Environment details are passed to Vault as login body. If left unconfigured,
|
||||
* {@link AzureMsiAuthentication} looks up the details from the instance metadata
|
||||
* service.
|
||||
*
|
||||
* @param vmEnvironment must not be {@literal null}.
|
||||
* @return {@code this} {@link AzureMsiAuthenticationOptionsBuilder}.
|
||||
*/
|
||||
public AzureMsiAuthenticationOptionsBuilder vmEnvironment(
|
||||
AzureVmEnvironment vmEnvironment) {
|
||||
public AzureMsiAuthenticationOptionsBuilder vmEnvironment(AzureVmEnvironment vmEnvironment) {
|
||||
|
||||
Assert.notNull(vmEnvironment, "AzureVmEnvironment must not be null");
|
||||
|
||||
@@ -193,16 +188,13 @@ public class AzureMsiAuthenticationOptions {
|
||||
|
||||
/**
|
||||
* Configure the instance metadata {@link URI}.
|
||||
*
|
||||
* @param instanceMetadataServiceUri must not be {@literal null}.
|
||||
* @return {@code this} {@link AzureMsiAuthenticationOptionsBuilder}.
|
||||
* @see #DEFAULT_IDENTITY_TOKEN_SERVICE_URI
|
||||
*/
|
||||
public AzureMsiAuthenticationOptionsBuilder instanceMetadataUri(
|
||||
URI instanceMetadataServiceUri) {
|
||||
public AzureMsiAuthenticationOptionsBuilder instanceMetadataUri(URI instanceMetadataServiceUri) {
|
||||
|
||||
Assert.notNull(identityTokenServiceUri,
|
||||
"Instance metadata service URI must not be null");
|
||||
Assert.notNull(this.identityTokenServiceUri, "Instance metadata service URI must not be null");
|
||||
|
||||
this.instanceMetadataServiceUri = instanceMetadataServiceUri;
|
||||
return this;
|
||||
@@ -210,16 +202,13 @@ public class AzureMsiAuthenticationOptions {
|
||||
|
||||
/**
|
||||
* Configure the managed identity service token {@link URI}.
|
||||
*
|
||||
* @param identityTokenServiceUri must not be {@literal null}.
|
||||
* @return {@code this} {@link AzureMsiAuthenticationOptionsBuilder}.
|
||||
* @see #DEFAULT_IDENTITY_TOKEN_SERVICE_URI
|
||||
*/
|
||||
public AzureMsiAuthenticationOptionsBuilder identityTokenServiceUri(
|
||||
URI identityTokenServiceUri) {
|
||||
public AzureMsiAuthenticationOptionsBuilder identityTokenServiceUri(URI identityTokenServiceUri) {
|
||||
|
||||
Assert.notNull(identityTokenServiceUri,
|
||||
"Identity token service URI must not be null");
|
||||
Assert.notNull(identityTokenServiceUri, "Identity token service URI must not be null");
|
||||
|
||||
this.identityTokenServiceUri = identityTokenServiceUri;
|
||||
return this;
|
||||
@@ -227,15 +216,16 @@ public class AzureMsiAuthenticationOptions {
|
||||
|
||||
/**
|
||||
* Build a new {@link AzureMsiAuthenticationOptions} instance.
|
||||
*
|
||||
* @return a new {@link AzureMsiAuthenticationOptions}.
|
||||
*/
|
||||
public AzureMsiAuthenticationOptions build() {
|
||||
|
||||
Assert.hasText(role, "Role must not be null or empty");
|
||||
Assert.hasText(this.role, "Role must not be null or empty");
|
||||
|
||||
return new AzureMsiAuthenticationOptions(path, role,
|
||||
instanceMetadataServiceUri, identityTokenServiceUri, vmEnvironment);
|
||||
return new AzureMsiAuthenticationOptions(this.path, this.role, this.instanceMetadataServiceUri,
|
||||
this.identityTokenServiceUri, this.vmEnvironment);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -39,13 +39,11 @@ public class AzureVmEnvironment {
|
||||
|
||||
/**
|
||||
* Creates a new {@link AzureVmEnvironment}.
|
||||
*
|
||||
* @param subscriptionId must not be {@literal null}.
|
||||
* @param resourceGroupName must not be {@literal null}.
|
||||
* @param vmName must not be {@literal null}.
|
||||
*/
|
||||
public AzureVmEnvironment(String subscriptionId, String resourceGroupName,
|
||||
String vmName) {
|
||||
public AzureVmEnvironment(String subscriptionId, String resourceGroupName, String vmName) {
|
||||
|
||||
Assert.notNull(subscriptionId, "SubscriptionId must not be null");
|
||||
Assert.notNull(resourceGroupName, "Resource group name must not be null");
|
||||
@@ -57,14 +55,15 @@ public class AzureVmEnvironment {
|
||||
}
|
||||
|
||||
public String getSubscriptionId() {
|
||||
return subscriptionId;
|
||||
return this.subscriptionId;
|
||||
}
|
||||
|
||||
public String getResourceGroupName() {
|
||||
return resourceGroupName;
|
||||
return this.resourceGroupName;
|
||||
}
|
||||
|
||||
public String getVmName() {
|
||||
return vmName;
|
||||
return this.vmName;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -32,15 +32,13 @@ import org.springframework.vault.support.VaultToken;
|
||||
* @see VaultTokenSupplier
|
||||
* @see VaultToken
|
||||
*/
|
||||
public class CachingVaultTokenSupplier
|
||||
implements VaultTokenSupplier, ReactiveSessionManager {
|
||||
public class CachingVaultTokenSupplier implements VaultTokenSupplier, ReactiveSessionManager {
|
||||
|
||||
private static final Mono<VaultToken> EMPTY = Mono.empty();
|
||||
|
||||
private final VaultTokenSupplier clientAuthentication;
|
||||
|
||||
private final AtomicReference<Mono<VaultToken>> tokenRef = new AtomicReference<>(
|
||||
EMPTY);
|
||||
private final AtomicReference<Mono<VaultToken>> tokenRef = new AtomicReference<>(EMPTY);
|
||||
|
||||
private CachingVaultTokenSupplier(VaultTokenSupplier clientAuthentication) {
|
||||
this.clientAuthentication = clientAuthentication;
|
||||
@@ -49,7 +47,6 @@ public class CachingVaultTokenSupplier
|
||||
/**
|
||||
* Creates a new {@link CachingVaultTokenSupplier} given a {@link VaultTokenSupplier
|
||||
* delegate supplier}.
|
||||
*
|
||||
* @param delegate must not be {@literal null}.
|
||||
* @return the {@link CachingVaultTokenSupplier} for a {@link VaultTokenSupplier
|
||||
* delegate supplier}.
|
||||
@@ -61,10 +58,11 @@ public class CachingVaultTokenSupplier
|
||||
@Override
|
||||
public Mono<VaultToken> getVaultToken() throws VaultException {
|
||||
|
||||
if (Objects.equals(tokenRef.get(), EMPTY)) {
|
||||
tokenRef.compareAndSet(EMPTY, clientAuthentication.getVaultToken().cache());
|
||||
if (Objects.equals(this.tokenRef.get(), EMPTY)) {
|
||||
this.tokenRef.compareAndSet(EMPTY, this.clientAuthentication.getVaultToken().cache());
|
||||
}
|
||||
|
||||
return tokenRef.get();
|
||||
return this.tokenRef.get();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -31,8 +31,8 @@ public interface ClientAuthentication {
|
||||
/**
|
||||
* Return a {@link VaultToken}. This method can optionally log into Vault to obtain a
|
||||
* {@link VaultToken token}.
|
||||
*
|
||||
* @return a {@link VaultToken}.
|
||||
*/
|
||||
VaultToken login() throws VaultException;
|
||||
|
||||
}
|
||||
|
||||
@@ -33,11 +33,9 @@ import static org.springframework.vault.authentication.AuthenticationSteps.HttpR
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class ClientCertificateAuthentication
|
||||
implements ClientAuthentication, AuthenticationStepsFactory {
|
||||
public class ClientCertificateAuthentication implements ClientAuthentication, AuthenticationStepsFactory {
|
||||
|
||||
private static final Log logger = LogFactory
|
||||
.getLog(ClientCertificateAuthentication.class);
|
||||
private static final Log logger = LogFactory.getLog(ClientCertificateAuthentication.class);
|
||||
|
||||
private final ClientCertificateAuthenticationOptions options;
|
||||
|
||||
@@ -45,7 +43,6 @@ public class ClientCertificateAuthentication
|
||||
|
||||
/**
|
||||
* Create a {@link ClientCertificateAuthentication} using {@link RestOperations}.
|
||||
*
|
||||
* @param restOperations must not be {@literal null}.
|
||||
*/
|
||||
public ClientCertificateAuthentication(RestOperations restOperations) {
|
||||
@@ -54,7 +51,6 @@ public class ClientCertificateAuthentication
|
||||
|
||||
/**
|
||||
* Create a {@link ClientCertificateAuthentication} using {@link RestOperations}.
|
||||
*
|
||||
* @param options must not be {@literal null}.
|
||||
* @param restOperations must not be {@literal null}.
|
||||
* @since 2.2.3
|
||||
@@ -62,8 +58,7 @@ public class ClientCertificateAuthentication
|
||||
public ClientCertificateAuthentication(ClientCertificateAuthenticationOptions options,
|
||||
RestOperations restOperations) {
|
||||
|
||||
Assert.notNull(options,
|
||||
"ClientCertificateAuthenticationOptions must not be null");
|
||||
Assert.notNull(options, "ClientCertificateAuthenticationOptions must not be null");
|
||||
Assert.notNull(restOperations, "RestOperations must not be null");
|
||||
|
||||
this.restOperations = restOperations;
|
||||
@@ -72,31 +67,25 @@ public class ClientCertificateAuthentication
|
||||
|
||||
/**
|
||||
* Creates a {@link AuthenticationSteps} for client certificate authentication.
|
||||
*
|
||||
* @return {@link AuthenticationSteps} for client certificate authentication.
|
||||
* @since 2.0
|
||||
*/
|
||||
public static AuthenticationSteps createAuthenticationSteps() {
|
||||
return createAuthenticationSteps(
|
||||
ClientCertificateAuthenticationOptions.builder().build());
|
||||
return createAuthenticationSteps(ClientCertificateAuthenticationOptions.builder().build());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link AuthenticationSteps} for client certificate authentication.
|
||||
*
|
||||
* @param options must not be {@literal null}.
|
||||
* @return {@link AuthenticationSteps} for client certificate authentication.
|
||||
* @since 2.2.3
|
||||
*/
|
||||
public static AuthenticationSteps createAuthenticationSteps(
|
||||
ClientCertificateAuthenticationOptions options) {
|
||||
public static AuthenticationSteps createAuthenticationSteps(ClientCertificateAuthenticationOptions options) {
|
||||
|
||||
Assert.notNull(options,
|
||||
"ClientCertificateAuthenticationOptions must not be null");
|
||||
Assert.notNull(options, "ClientCertificateAuthenticationOptions must not be null");
|
||||
|
||||
return AuthenticationSteps
|
||||
.just(post(AuthenticationUtil.getLoginPath(options.getPath()))
|
||||
.as(VaultResponse.class));
|
||||
.just(post(AuthenticationUtil.getLoginPath(options.getPath())).as(VaultResponse.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -106,15 +95,15 @@ public class ClientCertificateAuthentication
|
||||
|
||||
@Override
|
||||
public AuthenticationSteps getAuthenticationSteps() {
|
||||
return createAuthenticationSteps(options);
|
||||
return createAuthenticationSteps(this.options);
|
||||
}
|
||||
|
||||
private VaultToken createTokenUsingTlsCertAuthentication() {
|
||||
|
||||
try {
|
||||
VaultResponse response = restOperations.postForObject(
|
||||
AuthenticationUtil.getLoginPath(options.getPath()),
|
||||
Collections.emptyMap(), VaultResponse.class);
|
||||
VaultResponse response = this.restOperations.postForObject(
|
||||
AuthenticationUtil.getLoginPath(this.options.getPath()), Collections.emptyMap(),
|
||||
VaultResponse.class);
|
||||
|
||||
Assert.state(response.getAuth() != null, "Auth field must not be null");
|
||||
|
||||
@@ -126,4 +115,5 @@ public class ClientCertificateAuthentication
|
||||
throw VaultLoginException.create("TLS Certificates", e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ public class ClientCertificateAuthenticationOptions {
|
||||
* @return the path of the azure authentication backend mount.
|
||||
*/
|
||||
public String getPath() {
|
||||
return path;
|
||||
return this.path;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -68,7 +68,6 @@ public class ClientCertificateAuthenticationOptions {
|
||||
|
||||
/**
|
||||
* Configure the mount path, defaults to {@literal azure}.
|
||||
*
|
||||
* @param path must not be empty or {@literal null}.
|
||||
* @return {@code this} {@link ClientCertificateAuthenticationOptionsBuilder}.
|
||||
*/
|
||||
@@ -82,11 +81,12 @@ public class ClientCertificateAuthenticationOptions {
|
||||
|
||||
/**
|
||||
* Build a new {@link ClientCertificateAuthenticationOptions} instance.
|
||||
*
|
||||
* @return a new {@link ClientCertificateAuthenticationOptions}.
|
||||
*/
|
||||
public ClientCertificateAuthenticationOptions build() {
|
||||
return new ClientCertificateAuthenticationOptions(path);
|
||||
return new ClientCertificateAuthenticationOptions(this.path);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -31,7 +31,6 @@ public interface CredentialSupplier extends Supplier<String> {
|
||||
|
||||
/**
|
||||
* Get a credential to be used with an authentication mechanism.
|
||||
*
|
||||
* @return the credential.
|
||||
*/
|
||||
@Override
|
||||
@@ -44,7 +43,6 @@ public interface CredentialSupplier extends Supplier<String> {
|
||||
* <p>
|
||||
* Reusing a cached token can lead to authentication failures if the credential
|
||||
* expires.
|
||||
*
|
||||
* @return a caching {@link CredentialSupplier}.
|
||||
*/
|
||||
default CredentialSupplier cached() {
|
||||
@@ -53,4 +51,5 @@ public interface CredentialSupplier extends Supplier<String> {
|
||||
|
||||
return () -> credential;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -56,8 +56,7 @@ import static org.springframework.vault.authentication.AuthenticationSteps.HttpR
|
||||
* wrapping_token_ttl: 0h10m0s
|
||||
* wrapping_token_creation_time: 2016-09-18 20:29:48.652957077 +0200 CEST
|
||||
* wrapped_accessor: 46b6aebb-187f-932a-26d7-4f3d86a68319
|
||||
* </code>
|
||||
* </pre>
|
||||
* </code> </pre>
|
||||
*
|
||||
* <strong>Setup {@link CubbyholeAuthentication}</strong>
|
||||
*
|
||||
@@ -69,8 +68,7 @@ import static org.springframework.vault.authentication.AuthenticationSteps.HttpR
|
||||
* .wrapped()
|
||||
* .build();
|
||||
* CubbyholeAuthentication authentication = new CubbyholeAuthentication(options, restOperations);
|
||||
* </code>
|
||||
* </pre>
|
||||
* </code> </pre>
|
||||
*
|
||||
* <h2>Stored token response usage</h2> <strong>Create a Token</strong>
|
||||
*
|
||||
@@ -96,8 +94,7 @@ import static org.springframework.vault.authentication.AuthenticationSteps.HttpR
|
||||
*
|
||||
* $ export VAULT_TOKEN=895cb88b-aef4-0e33-ba65-d50007290780
|
||||
* $ vault write cubbyhole/token token=f9e30681-d46a-cdaf-aaa0-2ae0a9ad0819
|
||||
* </code>
|
||||
* </pre>
|
||||
* </code> </pre>
|
||||
*
|
||||
* <strong>Setup {@link CubbyholeAuthentication}</strong>
|
||||
*
|
||||
@@ -109,8 +106,7 @@ import static org.springframework.vault.authentication.AuthenticationSteps.HttpR
|
||||
* .path("cubbyhole/token")
|
||||
* .build();
|
||||
* CubbyholeAuthentication authentication = new CubbyholeAuthentication(options, restOperations);
|
||||
* </code>
|
||||
* </pre>
|
||||
* </code> </pre>
|
||||
*
|
||||
* <strong>Remaining TTL/Renewability</strong>
|
||||
* <p>
|
||||
@@ -135,8 +131,7 @@ import static org.springframework.vault.authentication.AuthenticationSteps.HttpR
|
||||
* "https://www.vaultproject.io/docs/concepts/response-wrapping.html">Response
|
||||
* Wrapping</a>
|
||||
*/
|
||||
public class CubbyholeAuthentication
|
||||
implements ClientAuthentication, AuthenticationStepsFactory {
|
||||
public class CubbyholeAuthentication implements ClientAuthentication, AuthenticationStepsFactory {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(CubbyholeAuthentication.class);
|
||||
|
||||
@@ -147,12 +142,10 @@ public class CubbyholeAuthentication
|
||||
/**
|
||||
* Create a new {@link CubbyholeAuthentication} given
|
||||
* {@link CubbyholeAuthenticationOptions} and {@link RestOperations}.
|
||||
*
|
||||
* @param options must not be {@literal null}.
|
||||
* @param restOperations must not be {@literal null}.
|
||||
*/
|
||||
public CubbyholeAuthentication(CubbyholeAuthenticationOptions options,
|
||||
RestOperations restOperations) {
|
||||
public CubbyholeAuthentication(CubbyholeAuthenticationOptions options, RestOperations restOperations) {
|
||||
|
||||
Assert.notNull(options, "CubbyholeAuthenticationOptions must not be null");
|
||||
Assert.notNull(restOperations, "RestOperations must not be null");
|
||||
@@ -164,13 +157,11 @@ public class CubbyholeAuthentication
|
||||
/**
|
||||
* Creates a {@link AuthenticationSteps} for cubbyhole authentication given
|
||||
* {@link CubbyholeAuthenticationOptions}.
|
||||
*
|
||||
* @param options must not be {@literal null}.
|
||||
* @return {@link AuthenticationSteps} for cubbyhole authentication.
|
||||
* @since 2.0
|
||||
*/
|
||||
public static AuthenticationSteps createAuthenticationSteps(
|
||||
CubbyholeAuthenticationOptions options) {
|
||||
public static AuthenticationSteps createAuthenticationSteps(CubbyholeAuthenticationOptions options) {
|
||||
|
||||
Assert.notNull(options, "CubbyholeAuthenticationOptions must not be null");
|
||||
|
||||
@@ -190,15 +181,14 @@ public class CubbyholeAuthentication
|
||||
@Override
|
||||
public VaultToken login() throws VaultException {
|
||||
|
||||
String url = getRequestPath(options);
|
||||
String url = getRequestPath(this.options);
|
||||
VaultResponse data = lookupToken(url);
|
||||
|
||||
VaultToken tokenToUse = getToken(this.options, data, url);
|
||||
|
||||
if (shouldEnhanceTokenWithSelfLookup(tokenToUse)) {
|
||||
|
||||
LoginTokenAdapter adapter = new LoginTokenAdapter(
|
||||
new TokenAuthentication(tokenToUse), restOperations);
|
||||
LoginTokenAdapter adapter = new LoginTokenAdapter(new TokenAuthentication(tokenToUse), this.restOperations);
|
||||
tokenToUse = adapter.login();
|
||||
}
|
||||
|
||||
@@ -208,17 +198,17 @@ public class CubbyholeAuthentication
|
||||
|
||||
@Override
|
||||
public AuthenticationSteps getAuthenticationSteps() {
|
||||
return createAuthenticationSteps(options);
|
||||
return createAuthenticationSteps(this.options);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private VaultResponse lookupToken(String url) {
|
||||
|
||||
try {
|
||||
HttpMethod unwrapMethod = getRequestMethod(options);
|
||||
HttpEntity<Object> requestEntity = getRequestEntity(options);
|
||||
ResponseEntity<VaultResponse> entity = restOperations.exchange(url,
|
||||
unwrapMethod, requestEntity, VaultResponse.class);
|
||||
HttpMethod unwrapMethod = getRequestMethod(this.options);
|
||||
HttpEntity<Object> requestEntity = getRequestEntity(this.options);
|
||||
ResponseEntity<VaultResponse> entity = this.restOperations.exchange(url, unwrapMethod, requestEntity,
|
||||
VaultResponse.class);
|
||||
|
||||
Assert.state(entity.getBody() != null, "Auth response must not be null");
|
||||
|
||||
@@ -231,7 +221,7 @@ public class CubbyholeAuthentication
|
||||
|
||||
private boolean shouldEnhanceTokenWithSelfLookup(VaultToken token) {
|
||||
|
||||
if (!options.isSelfLookup()) {
|
||||
if (!this.options.isSelfLookup()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -247,8 +237,7 @@ public class CubbyholeAuthentication
|
||||
return true;
|
||||
}
|
||||
|
||||
private static HttpEntity<Object> getRequestEntity(
|
||||
CubbyholeAuthenticationOptions options) {
|
||||
private static HttpEntity<Object> getRequestEntity(CubbyholeAuthenticationOptions options) {
|
||||
return new HttpEntity<>(VaultHttpHeaders.from(options.getInitialToken()));
|
||||
}
|
||||
|
||||
@@ -270,13 +259,11 @@ public class CubbyholeAuthentication
|
||||
return options.getPath();
|
||||
}
|
||||
|
||||
private static VaultToken getToken(CubbyholeAuthenticationOptions options,
|
||||
VaultResponse response, String url) {
|
||||
private static VaultToken getToken(CubbyholeAuthenticationOptions options, VaultResponse response, String url) {
|
||||
|
||||
if (options.isWrappedToken()) {
|
||||
|
||||
VaultResponse responseToUse = options.getUnwrappingEndpoints()
|
||||
.unwrap(response);
|
||||
VaultResponse responseToUse = options.getUnwrappingEndpoints().unwrap(response);
|
||||
|
||||
Assert.state(responseToUse.getAuth() != null, "Auth field must not be null");
|
||||
|
||||
@@ -285,9 +272,9 @@ public class CubbyholeAuthentication
|
||||
|
||||
Map<String, Object> data = response.getData();
|
||||
if (data == null || data.isEmpty()) {
|
||||
throw new VaultLoginException(String.format(
|
||||
"Cannot retrieve Token from Cubbyhole: Response at %s does not contain a token",
|
||||
options.getPath()));
|
||||
throw new VaultLoginException(
|
||||
String.format("Cannot retrieve Token from Cubbyhole: Response at %s does not contain a token",
|
||||
options.getPath()));
|
||||
}
|
||||
|
||||
if (data.size() == 1) {
|
||||
@@ -295,8 +282,8 @@ public class CubbyholeAuthentication
|
||||
return VaultToken.of(token);
|
||||
}
|
||||
|
||||
throw new VaultLoginException(String.format(
|
||||
"Cannot retrieve Token from Cubbyhole: Response at %s does not contain an unique token",
|
||||
url));
|
||||
throw new VaultLoginException(String
|
||||
.format("Cannot retrieve Token from Cubbyhole: Response at %s does not contain an unique token", url));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -58,8 +58,7 @@ public class CubbyholeAuthenticationOptions {
|
||||
private final boolean selfLookup;
|
||||
|
||||
private CubbyholeAuthenticationOptions(VaultToken initialToken, String path,
|
||||
UnwrappingEndpoints unwrappingEndpoints, boolean wrappedToken,
|
||||
boolean selfLookup) {
|
||||
UnwrappingEndpoints unwrappingEndpoints, boolean wrappedToken, boolean selfLookup) {
|
||||
|
||||
this.initialToken = initialToken;
|
||||
this.path = path;
|
||||
@@ -79,14 +78,14 @@ public class CubbyholeAuthenticationOptions {
|
||||
* @return the initial {@link VaultToken} to access Cubbyhole.
|
||||
*/
|
||||
public VaultToken getInitialToken() {
|
||||
return initialToken;
|
||||
return this.initialToken;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the path of the Cubbyhole response path.
|
||||
*/
|
||||
public String getPath() {
|
||||
return path;
|
||||
return this.path;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -94,7 +93,7 @@ public class CubbyholeAuthenticationOptions {
|
||||
* @since 2.2
|
||||
*/
|
||||
public UnwrappingEndpoints getUnwrappingEndpoints() {
|
||||
return unwrappingEndpoints;
|
||||
return this.unwrappingEndpoints;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -103,7 +102,7 @@ public class CubbyholeAuthenticationOptions {
|
||||
* response.
|
||||
*/
|
||||
public boolean isWrappedToken() {
|
||||
return wrappedToken;
|
||||
return this.wrappedToken;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -114,7 +113,7 @@ public class CubbyholeAuthenticationOptions {
|
||||
* @since 1.0.1
|
||||
*/
|
||||
public boolean isSelfLookup() {
|
||||
return selfLookup;
|
||||
return this.selfLookup;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -139,12 +138,10 @@ public class CubbyholeAuthenticationOptions {
|
||||
|
||||
/**
|
||||
* Configure the initial {@link VaultToken} to access Cubbyhole.
|
||||
*
|
||||
* @param initialToken must not be {@literal null}.
|
||||
* @return {@code this} {@link CubbyholeAuthenticationOptionsBuilder}.
|
||||
*/
|
||||
public CubbyholeAuthenticationOptionsBuilder initialToken(
|
||||
VaultToken initialToken) {
|
||||
public CubbyholeAuthenticationOptionsBuilder initialToken(VaultToken initialToken) {
|
||||
|
||||
Assert.notNull(initialToken, "Initial Vault Token must not be null");
|
||||
|
||||
@@ -155,7 +152,6 @@ public class CubbyholeAuthenticationOptions {
|
||||
/**
|
||||
* Configure the cubbyhole path, such as {@code cubbyhole/token}. Expects a token
|
||||
* in the {@code data} response.
|
||||
*
|
||||
* @param path must not be empty or {@literal null}.
|
||||
* @return {@code this} {@link CubbyholeAuthenticationOptionsBuilder}.
|
||||
*/
|
||||
@@ -169,13 +165,11 @@ public class CubbyholeAuthenticationOptions {
|
||||
|
||||
/**
|
||||
* Configure the {@link UnwrappingEndpoints} to use.
|
||||
*
|
||||
* @param endpoints must not be {@literal null}.
|
||||
* @return {@code this} {@link CubbyholeAuthenticationOptionsBuilder}
|
||||
* @since 2.2
|
||||
*/
|
||||
public CubbyholeAuthenticationOptionsBuilder unwrappingEndpoints(
|
||||
UnwrappingEndpoints endpoints) {
|
||||
public CubbyholeAuthenticationOptionsBuilder unwrappingEndpoints(UnwrappingEndpoints endpoints) {
|
||||
|
||||
Assert.notNull(endpoints, "UnwrappingEndpoints must not be empty");
|
||||
|
||||
@@ -185,7 +179,6 @@ public class CubbyholeAuthenticationOptions {
|
||||
|
||||
/**
|
||||
* Configure whether to use wrapped token responses.
|
||||
*
|
||||
* @return {@code this} {@link CubbyholeAuthenticationOptionsBuilder}.
|
||||
*/
|
||||
public CubbyholeAuthenticationOptionsBuilder wrapped() {
|
||||
@@ -198,9 +191,8 @@ public class CubbyholeAuthenticationOptions {
|
||||
/**
|
||||
* Configure whether to perform a self-lookup after token retrieval. Defaults to
|
||||
* {@literal true}.
|
||||
*
|
||||
* @param selfLookup {@literal true} to perform a self-lookup or {@literal false}
|
||||
* to disable it.
|
||||
* to disable it.
|
||||
* @return {@code this} {@link CubbyholeAuthenticationOptionsBuilder}.
|
||||
* @since 1.0.1
|
||||
*/
|
||||
@@ -213,16 +205,17 @@ public class CubbyholeAuthenticationOptions {
|
||||
/**
|
||||
* Build a new {@link CubbyholeAuthenticationOptions} instance. Requires
|
||||
* {@link #path(String)} or {@link #wrapped()} to be configured.
|
||||
*
|
||||
* @return a new {@link CubbyholeAuthenticationOptions}.
|
||||
*/
|
||||
public CubbyholeAuthenticationOptions build() {
|
||||
|
||||
Assert.notNull(initialToken, "Initial Vault Token must not be null");
|
||||
Assert.notNull(path, "Path must not be null");
|
||||
Assert.notNull(this.initialToken, "Initial Vault Token must not be null");
|
||||
Assert.notNull(this.path, "Path must not be null");
|
||||
|
||||
return new CubbyholeAuthenticationOptions(initialToken, path, endpoints,
|
||||
wrappedToken, selfLookup);
|
||||
return new CubbyholeAuthenticationOptions(this.initialToken, this.path, this.endpoints, this.wrappedToken,
|
||||
this.selfLookup);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -29,14 +29,12 @@ import org.springframework.util.StringUtils;
|
||||
* @since 2.1
|
||||
* @see GcpIamAuthentication
|
||||
*/
|
||||
enum DefaultGcpCredentialAccessors
|
||||
implements GcpProjectIdAccessor, GcpServiceAccountIdAccessor {
|
||||
enum DefaultGcpCredentialAccessors implements GcpProjectIdAccessor, GcpServiceAccountIdAccessor {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
/**
|
||||
* Get a the service account id (email) to be placed in the signed JWT.
|
||||
*
|
||||
* @param credential credential object to obtain the service account id from.
|
||||
* @return the service account id to use.
|
||||
*/
|
||||
@@ -52,7 +50,6 @@ enum DefaultGcpCredentialAccessors
|
||||
|
||||
/**
|
||||
* Get a the GCP project id to used in Google Cloud IAM API calls.
|
||||
*
|
||||
* @param credential the credential object to obtain the project id from.
|
||||
* @return the service account id to use.
|
||||
*/
|
||||
@@ -64,4 +61,5 @@ enum DefaultGcpCredentialAccessors
|
||||
return StringUtils.isEmpty(credential.getServiceAccountProjectId()) ? "-"
|
||||
: credential.getServiceAccountProjectId();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -63,12 +63,10 @@ public class GcpComputeAuthentication extends GcpJwtAuthenticationSupport
|
||||
* Create a new {@link GcpComputeAuthentication} instance given
|
||||
* {@link GcpComputeAuthenticationOptions} and {@link RestOperations} for Vault and
|
||||
* Google API use.
|
||||
*
|
||||
* @param options must not be {@literal null}.
|
||||
* @param vaultRestOperations must not be {@literal null}.
|
||||
*/
|
||||
public GcpComputeAuthentication(GcpComputeAuthenticationOptions options,
|
||||
RestOperations vaultRestOperations) {
|
||||
public GcpComputeAuthentication(GcpComputeAuthenticationOptions options, RestOperations vaultRestOperations) {
|
||||
this(options, vaultRestOperations, vaultRestOperations);
|
||||
}
|
||||
|
||||
@@ -76,20 +74,17 @@ public class GcpComputeAuthentication extends GcpJwtAuthenticationSupport
|
||||
* Create a new {@link GcpComputeAuthentication} instance given
|
||||
* {@link GcpComputeAuthenticationOptions} and {@link RestOperations} for Vault and
|
||||
* Google API use.
|
||||
*
|
||||
* @param options must not be {@literal null}.
|
||||
* @param vaultRestOperations must not be {@literal null}.
|
||||
* @param googleMetadataRestOperations must not be {@literal null}.
|
||||
*/
|
||||
public GcpComputeAuthentication(GcpComputeAuthenticationOptions options,
|
||||
RestOperations vaultRestOperations,
|
||||
public GcpComputeAuthentication(GcpComputeAuthenticationOptions options, RestOperations vaultRestOperations,
|
||||
RestOperations googleMetadataRestOperations) {
|
||||
|
||||
super(vaultRestOperations);
|
||||
|
||||
Assert.notNull(options, "GcpGceAuthenticationOptions must not be null");
|
||||
Assert.notNull(googleMetadataRestOperations,
|
||||
"Google Metadata RestOperations must not be null");
|
||||
Assert.notNull(googleMetadataRestOperations, "Google Metadata RestOperations must not be null");
|
||||
|
||||
this.options = options;
|
||||
this.googleMetadataRestOperations = googleMetadataRestOperations;
|
||||
@@ -98,22 +93,19 @@ public class GcpComputeAuthentication extends GcpJwtAuthenticationSupport
|
||||
/**
|
||||
* Creates a {@link AuthenticationSteps} for GCE authentication given
|
||||
* {@link GcpComputeAuthenticationOptions}.
|
||||
*
|
||||
* @param options must not be {@literal null}.
|
||||
* @return {@link AuthenticationSteps} for cubbyhole authentication.
|
||||
*/
|
||||
public static AuthenticationSteps createAuthenticationSteps(
|
||||
GcpComputeAuthenticationOptions options) {
|
||||
public static AuthenticationSteps createAuthenticationSteps(GcpComputeAuthenticationOptions options) {
|
||||
|
||||
Assert.notNull(options, "CubbyholeAuthenticationOptions must not be null");
|
||||
|
||||
String serviceAccount = options.getServiceAccount();
|
||||
String audience = getAudience(options.getRole());
|
||||
|
||||
HttpRequest<String> jwtRequest = get(COMPUTE_METADATA_URL_TEMPLATE,
|
||||
serviceAccount, audience, "full") //
|
||||
.with(getMetadataHttpHeaders()) //
|
||||
.as(String.class);
|
||||
HttpRequest<String> jwtRequest = get(COMPUTE_METADATA_URL_TEMPLATE, serviceAccount, audience, "full") //
|
||||
.with(getMetadataHttpHeaders()) //
|
||||
.as(String.class);
|
||||
|
||||
return AuthenticationSteps.fromHttpRequest(jwtRequest)
|
||||
//
|
||||
@@ -126,13 +118,12 @@ public class GcpComputeAuthentication extends GcpJwtAuthenticationSupport
|
||||
|
||||
String signedJwt = signJwt();
|
||||
|
||||
return doLogin("GCP-GCE", signedJwt, this.options.getPath(),
|
||||
this.options.getRole());
|
||||
return doLogin("GCP-GCE", signedJwt, this.options.getPath(), this.options.getRole());
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthenticationSteps getAuthenticationSteps() {
|
||||
return createAuthenticationSteps(options);
|
||||
return createAuthenticationSteps(this.options);
|
||||
}
|
||||
|
||||
protected String signJwt() {
|
||||
@@ -146,9 +137,8 @@ public class GcpComputeAuthentication extends GcpJwtAuthenticationSupport
|
||||
HttpHeaders headers = getMetadataHttpHeaders();
|
||||
HttpEntity<Object> entity = new HttpEntity<>(headers);
|
||||
|
||||
ResponseEntity<String> response = googleMetadataRestOperations.exchange(
|
||||
COMPUTE_METADATA_URL_TEMPLATE, HttpMethod.GET, entity, String.class,
|
||||
urlParameters);
|
||||
ResponseEntity<String> response = this.googleMetadataRestOperations.exchange(COMPUTE_METADATA_URL_TEMPLATE,
|
||||
HttpMethod.GET, entity, String.class, urlParameters);
|
||||
|
||||
return response.getBody();
|
||||
}
|
||||
@@ -169,4 +159,5 @@ public class GcpComputeAuthentication extends GcpJwtAuthenticationSupport
|
||||
private static String getAudience(String role) {
|
||||
return String.format("https://localhost:8200/vault/%s", role);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -50,8 +50,7 @@ public class GcpComputeAuthenticationOptions {
|
||||
*/
|
||||
private final String role;
|
||||
|
||||
private GcpComputeAuthenticationOptions(String path, String serviceAccount,
|
||||
String role) {
|
||||
private GcpComputeAuthenticationOptions(String path, String serviceAccount, String role) {
|
||||
|
||||
this.path = path;
|
||||
this.serviceAccount = serviceAccount;
|
||||
@@ -69,21 +68,21 @@ public class GcpComputeAuthenticationOptions {
|
||||
* @return the path of the gcp authentication backend mount.
|
||||
*/
|
||||
public String getPath() {
|
||||
return path;
|
||||
return this.path;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the GCE service account identifier.
|
||||
*/
|
||||
public String getServiceAccount() {
|
||||
return serviceAccount;
|
||||
return this.serviceAccount;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return name of the role against which the login is being attempted.
|
||||
*/
|
||||
public String getRole() {
|
||||
return role;
|
||||
return this.role;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -103,7 +102,6 @@ public class GcpComputeAuthenticationOptions {
|
||||
|
||||
/**
|
||||
* Configure the mount path, defaults to {@literal aws}.
|
||||
*
|
||||
* @param path must not be empty or {@literal null}.
|
||||
* @return {@code this} {@link GcpComputeAuthenticationOptionsBuilder}.
|
||||
*/
|
||||
@@ -118,12 +116,10 @@ public class GcpComputeAuthenticationOptions {
|
||||
/**
|
||||
* Configure the service account identifier. Uses the {@code default} service
|
||||
* account if left unconfigured.
|
||||
*
|
||||
* @param serviceAccount must not be empty or {@literal null}.
|
||||
* @return {@code this} {@link GcpComputeAuthenticationOptionsBuilder}.
|
||||
*/
|
||||
public GcpComputeAuthenticationOptionsBuilder serviceAccount(
|
||||
String serviceAccount) {
|
||||
public GcpComputeAuthenticationOptionsBuilder serviceAccount(String serviceAccount) {
|
||||
|
||||
Assert.hasText(serviceAccount, "Service account must not be null");
|
||||
|
||||
@@ -133,7 +129,6 @@ public class GcpComputeAuthenticationOptions {
|
||||
|
||||
/**
|
||||
* Configure the name of the role against which the login is being attempted.
|
||||
*
|
||||
* @param role must not be empty or {@literal null}.
|
||||
* @return {@code this} {@link GcpComputeAuthenticationOptionsBuilder}.
|
||||
*/
|
||||
@@ -147,14 +142,15 @@ public class GcpComputeAuthenticationOptions {
|
||||
|
||||
/**
|
||||
* Build a new {@link GcpComputeAuthenticationOptions} instance.
|
||||
*
|
||||
* @return a new {@link GcpComputeAuthenticationOptions}.
|
||||
*/
|
||||
public GcpComputeAuthenticationOptions build() {
|
||||
|
||||
Assert.notNull(role, "Role must not be null");
|
||||
Assert.notNull(this.role, "Role must not be null");
|
||||
|
||||
return new GcpComputeAuthenticationOptions(path, serviceAccount, role);
|
||||
return new GcpComputeAuthenticationOptions(this.path, this.serviceAccount, this.role);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -33,7 +33,6 @@ public interface GcpCredentialSupplier extends Supplier<GoogleCredential> {
|
||||
|
||||
/**
|
||||
* Exception-safe helper to get {@link GoogleCredential} from {@link #getCredential}.
|
||||
*
|
||||
* @return the GoogleCredential for JWT signing.
|
||||
*/
|
||||
@Override
|
||||
@@ -49,9 +48,9 @@ public interface GcpCredentialSupplier extends Supplier<GoogleCredential> {
|
||||
|
||||
/**
|
||||
* Get a {@link GoogleCredential} for GCP IAM authentication via JWT signing.
|
||||
*
|
||||
* @return the {@link GoogleCredential}.
|
||||
* @throws IOException if the credential lookup fails.
|
||||
*/
|
||||
GoogleCredential getCredential() throws IOException;
|
||||
|
||||
}
|
||||
|
||||
@@ -63,8 +63,7 @@ import org.springframework.web.client.RestOperations;
|
||||
* "https://cloud.google.com/iam/reference/rest/v1/projects.serviceAccounts/signJwt">GCP:
|
||||
* projects.serviceAccounts.signJwt</a>
|
||||
*/
|
||||
public class GcpIamAuthentication extends GcpJwtAuthenticationSupport
|
||||
implements ClientAuthentication {
|
||||
public class GcpIamAuthentication extends GcpJwtAuthenticationSupport implements ClientAuthentication {
|
||||
|
||||
private static final JsonFactory JSON_FACTORY = new JacksonFactory();
|
||||
|
||||
@@ -78,12 +77,10 @@ public class GcpIamAuthentication extends GcpJwtAuthenticationSupport
|
||||
* Create a new instance of {@link GcpIamAuthentication} given
|
||||
* {@link GcpIamAuthenticationOptions} and {@link RestOperations}. This constructor
|
||||
* initializes {@link GoogleApacheHttpTransport} for Google API usage.
|
||||
*
|
||||
* @param options must not be {@literal null}.
|
||||
* @param restOperations HTTP client for for Vault login, must not be {@literal null}.
|
||||
*/
|
||||
public GcpIamAuthentication(GcpIamAuthenticationOptions options,
|
||||
RestOperations restOperations) {
|
||||
public GcpIamAuthentication(GcpIamAuthenticationOptions options, RestOperations restOperations) {
|
||||
this(options, restOperations, new NetHttpTransport());
|
||||
}
|
||||
|
||||
@@ -91,13 +88,12 @@ public class GcpIamAuthentication extends GcpJwtAuthenticationSupport
|
||||
* Create a new instance of {@link GcpIamAuthentication} given
|
||||
* {@link GcpIamAuthenticationOptions}, {@link RestOperations} and
|
||||
* {@link HttpTransport}.
|
||||
*
|
||||
* @param options must not be {@literal null}.
|
||||
* @param restOperations HTTP client for for Vault login, must not be {@literal null}.
|
||||
* @param httpTransport HTTP client for Google API use, must not be {@literal null}.
|
||||
*/
|
||||
public GcpIamAuthentication(GcpIamAuthenticationOptions options,
|
||||
RestOperations restOperations, HttpTransport httpTransport) {
|
||||
public GcpIamAuthentication(GcpIamAuthenticationOptions options, RestOperations restOperations,
|
||||
HttpTransport httpTransport) {
|
||||
|
||||
super(restOperations);
|
||||
|
||||
@@ -115,17 +111,16 @@ public class GcpIamAuthentication extends GcpJwtAuthenticationSupport
|
||||
|
||||
String signedJwt = signJwt();
|
||||
|
||||
return doLogin("GCP-IAM", signedJwt, this.options.getPath(),
|
||||
this.options.getRole());
|
||||
return doLogin("GCP-IAM", signedJwt, this.options.getPath(), this.options.getRole());
|
||||
}
|
||||
|
||||
protected String signJwt() {
|
||||
|
||||
String projectId = getProjectId();
|
||||
String serviceAccount = getServiceAccountId();
|
||||
Map<String, Object> jwtPayload = getJwtPayload(options, serviceAccount);
|
||||
Map<String, Object> jwtPayload = getJwtPayload(this.options, serviceAccount);
|
||||
|
||||
Iam iam = new Builder(httpTransport, JSON_FACTORY, credential)
|
||||
Iam iam = new Builder(this.httpTransport, JSON_FACTORY, this.credential)
|
||||
.setApplicationName("Spring Vault/" + getClass().getName()).build();
|
||||
|
||||
try {
|
||||
@@ -134,9 +129,8 @@ public class GcpIamAuthentication extends GcpJwtAuthenticationSupport
|
||||
SignJwtRequest request = new SignJwtRequest();
|
||||
request.setPayload(payload);
|
||||
|
||||
SignJwt signJwt = iam.projects().serviceAccounts().signJwt(String
|
||||
.format("projects/%s/serviceAccounts/%s", projectId, serviceAccount),
|
||||
request);
|
||||
SignJwt signJwt = iam.projects().serviceAccounts()
|
||||
.signJwt(String.format("projects/%s/serviceAccounts/%s", projectId, serviceAccount), request);
|
||||
|
||||
SignJwtResponse response = signJwt.execute();
|
||||
|
||||
@@ -148,15 +142,14 @@ public class GcpIamAuthentication extends GcpJwtAuthenticationSupport
|
||||
}
|
||||
|
||||
private String getServiceAccountId() {
|
||||
return options.getServiceAccountIdAccessor().getServiceAccountId(credential);
|
||||
return this.options.getServiceAccountIdAccessor().getServiceAccountId(this.credential);
|
||||
}
|
||||
|
||||
private String getProjectId() {
|
||||
return options.getProjectIdAccessor().getProjectId(credential);
|
||||
return this.options.getProjectIdAccessor().getProjectId(this.credential);
|
||||
}
|
||||
|
||||
private static Map<String, Object> getJwtPayload(GcpIamAuthenticationOptions options,
|
||||
String serviceAccount) {
|
||||
private static Map<String, Object> getJwtPayload(GcpIamAuthenticationOptions options, String serviceAccount) {
|
||||
|
||||
Instant validUntil = options.getClock().instant().plus(options.getJwtValidity());
|
||||
|
||||
@@ -168,4 +161,5 @@ public class GcpIamAuthentication extends GcpJwtAuthenticationSupport
|
||||
|
||||
return payload;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -75,9 +75,8 @@ public class GcpIamAuthenticationOptions {
|
||||
*/
|
||||
private final GcpProjectIdAccessor projectIdAccessor;
|
||||
|
||||
private GcpIamAuthenticationOptions(String path,
|
||||
GcpCredentialSupplier credentialSupplier, String role, Duration jwtValidity,
|
||||
Clock clock, GcpServiceAccountIdAccessor serviceAccountIdSupplier,
|
||||
private GcpIamAuthenticationOptions(String path, GcpCredentialSupplier credentialSupplier, String role,
|
||||
Duration jwtValidity, Clock clock, GcpServiceAccountIdAccessor serviceAccountIdSupplier,
|
||||
GcpProjectIdAccessor projectIdAccessor) {
|
||||
|
||||
this.path = path;
|
||||
@@ -100,35 +99,35 @@ public class GcpIamAuthenticationOptions {
|
||||
* @return the path of the gcp authentication backend mount.
|
||||
*/
|
||||
public String getPath() {
|
||||
return path;
|
||||
return this.path;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the gcp {@link Credential} supplier.
|
||||
*/
|
||||
public GcpCredentialSupplier getCredentialSupplier() {
|
||||
return credentialSupplier;
|
||||
return this.credentialSupplier;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return name of the role against which the login is being attempted.
|
||||
*/
|
||||
public String getRole() {
|
||||
return role;
|
||||
return this.role;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@link Duration} of the JWT to generate.
|
||||
*/
|
||||
public Duration getJwtValidity() {
|
||||
return jwtValidity;
|
||||
return this.jwtValidity;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@link Clock} used to calculate epoch seconds until the JWT expires.
|
||||
*/
|
||||
public Clock getClock() {
|
||||
return clock;
|
||||
return this.clock;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -136,7 +135,7 @@ public class GcpIamAuthenticationOptions {
|
||||
* @since 2.1
|
||||
*/
|
||||
public GcpServiceAccountIdAccessor getServiceAccountIdAccessor() {
|
||||
return serviceAccountIdAccessor;
|
||||
return this.serviceAccountIdAccessor;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -144,7 +143,7 @@ public class GcpIamAuthenticationOptions {
|
||||
* @since 2.1
|
||||
*/
|
||||
public GcpProjectIdAccessor getProjectIdAccessor() {
|
||||
return projectIdAccessor;
|
||||
return this.projectIdAccessor;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -173,7 +172,6 @@ public class GcpIamAuthenticationOptions {
|
||||
|
||||
/**
|
||||
* Configure the mount path, defaults to {@literal aws}.
|
||||
*
|
||||
* @param path must not be empty or {@literal null}.
|
||||
* @return {@code this} {@link GcpIamAuthenticationOptionsBuilder}.
|
||||
*/
|
||||
@@ -189,13 +187,11 @@ public class GcpIamAuthenticationOptions {
|
||||
* Configure static Google credentials, required to create a signed JWT. Either
|
||||
* use static credentials or provide a
|
||||
* {@link #credentialSupplier(GcpCredentialSupplier) credentials provider}.
|
||||
*
|
||||
* @param credential must not be {@literal null}.
|
||||
* @return {@code this} {@link GcpIamAuthenticationOptionsBuilder}.
|
||||
* @see #credentialSupplier(GcpCredentialSupplier)
|
||||
*/
|
||||
public GcpIamAuthenticationOptionsBuilder credential(
|
||||
GoogleCredential credential) {
|
||||
public GcpIamAuthenticationOptionsBuilder credential(GoogleCredential credential) {
|
||||
|
||||
Assert.notNull(credential, "Credential must not be null");
|
||||
|
||||
@@ -206,13 +202,11 @@ public class GcpIamAuthenticationOptions {
|
||||
* Configure a {@link GcpCredentialSupplier}, required to create a signed JWT.
|
||||
* Alternatively, configure static {@link #credential(GoogleCredential)
|
||||
* credentials}.
|
||||
*
|
||||
* @param credentialSupplier must not be {@literal null}.
|
||||
* @return {@code this} {@link GcpIamAuthenticationOptionsBuilder}.
|
||||
* @see #credential(GoogleCredential)
|
||||
*/
|
||||
public GcpIamAuthenticationOptionsBuilder credentialSupplier(
|
||||
GcpCredentialSupplier credentialSupplier) {
|
||||
public GcpIamAuthenticationOptionsBuilder credentialSupplier(GcpCredentialSupplier credentialSupplier) {
|
||||
|
||||
Assert.notNull(credentialSupplier, "GcpCredentialSupplier must not be null");
|
||||
|
||||
@@ -223,25 +217,21 @@ public class GcpIamAuthenticationOptions {
|
||||
/**
|
||||
* Configure an explicit service account id to use in GCP IAM calls. If none is
|
||||
* configured, falls back to using {@link GoogleCredential#getServiceAccountId()}.
|
||||
*
|
||||
* @param serviceAccountId the service account id (email) to use
|
||||
* @return {@code this} {@link GcpIamAuthenticationOptionsBuilder}.
|
||||
* @since 2.1
|
||||
*/
|
||||
public GcpIamAuthenticationOptionsBuilder serviceAccountId(
|
||||
String serviceAccountId) {
|
||||
public GcpIamAuthenticationOptionsBuilder serviceAccountId(String serviceAccountId) {
|
||||
|
||||
Assert.notNull(serviceAccountId, "Service account id may not be null");
|
||||
|
||||
return serviceAccountIdAccessor(
|
||||
(GoogleCredential credential) -> serviceAccountId);
|
||||
return serviceAccountIdAccessor((GoogleCredential credential) -> serviceAccountId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure an {@link GcpServiceAccountIdAccessor} to obtain the service account
|
||||
* id used in GCP IAM calls. If none is configured, falls back to using
|
||||
* {@link GoogleCredential#getServiceAccountId()}.
|
||||
*
|
||||
* @param serviceAccountIdAccessor the service account id provider to use
|
||||
* @return {@code this} {@link GcpIamAuthenticationOptionsBuilder}.
|
||||
* @see GcpServiceAccountIdAccessor
|
||||
@@ -250,8 +240,7 @@ public class GcpIamAuthenticationOptions {
|
||||
GcpIamAuthenticationOptionsBuilder serviceAccountIdAccessor(
|
||||
GcpServiceAccountIdAccessor serviceAccountIdAccessor) {
|
||||
|
||||
Assert.notNull(serviceAccountIdAccessor,
|
||||
"GcpServiceAccountIdAccessor must not be null");
|
||||
Assert.notNull(serviceAccountIdAccessor, "GcpServiceAccountIdAccessor must not be null");
|
||||
|
||||
this.serviceAccountIdAccessor = serviceAccountIdAccessor;
|
||||
return this;
|
||||
@@ -261,7 +250,6 @@ public class GcpIamAuthenticationOptions {
|
||||
* Configure an explicit GCP project id to use in GCP IAM API calls. If none is
|
||||
* configured, falls back using
|
||||
* {@link GoogleCredential#getServiceAccountProjectId()}.
|
||||
*
|
||||
* @param projectId the GCP project id to use in GCP IAM API calls
|
||||
* @return {@code this} {@link GcpIamAuthenticationOptionsBuilder}.
|
||||
* @since 2.1
|
||||
@@ -277,14 +265,12 @@ public class GcpIamAuthenticationOptions {
|
||||
* Configure an {@link GcpProjectIdAccessor} to use in GCP IAM API calls. If none
|
||||
* is configured, falls back using
|
||||
* {@link GoogleCredential#getServiceAccountProjectId()}.
|
||||
*
|
||||
* @param projectIdAccessor the GCP project id supplier to use in GCP IAM API
|
||||
* calls
|
||||
* calls
|
||||
* @return {@code this} {@link GcpIamAuthenticationOptionsBuilder}.
|
||||
* @since 2.1
|
||||
*/
|
||||
GcpIamAuthenticationOptionsBuilder projectIdAccessor(
|
||||
GcpProjectIdAccessor projectIdAccessor) {
|
||||
GcpIamAuthenticationOptionsBuilder projectIdAccessor(GcpProjectIdAccessor projectIdAccessor) {
|
||||
|
||||
Assert.notNull(projectIdAccessor, "GcpProjectIdAccessor must not be null");
|
||||
|
||||
@@ -294,7 +280,6 @@ public class GcpIamAuthenticationOptions {
|
||||
|
||||
/**
|
||||
* Configure the name of the role against which the login is being attempted.
|
||||
*
|
||||
* @param role must not be empty or {@literal null}.
|
||||
* @return {@code this} {@link GcpIamAuthenticationOptionsBuilder}.
|
||||
*/
|
||||
@@ -309,13 +294,12 @@ public class GcpIamAuthenticationOptions {
|
||||
/**
|
||||
* Configure the {@link Duration} for the JWT expiration. This defaults to 15
|
||||
* minutes and cannot be more than a hour.
|
||||
*
|
||||
* @param jwtValidity must not be {@literal null}.
|
||||
* @return {@code this} {@link GcpIamAuthenticationOptionsBuilder}.
|
||||
*/
|
||||
public GcpIamAuthenticationOptionsBuilder jwtValidity(Duration jwtValidity) {
|
||||
|
||||
Assert.hasText(role, "JWT validity duration must not be null");
|
||||
Assert.hasText(this.role, "JWT validity duration must not be null");
|
||||
|
||||
this.jwtValidity = jwtValidity;
|
||||
return this;
|
||||
@@ -324,13 +308,12 @@ public class GcpIamAuthenticationOptions {
|
||||
/**
|
||||
* Configure the {@link Clock} used to calculate epoch seconds until the JWT
|
||||
* expiration.
|
||||
*
|
||||
* @param clock must not be {@literal null}.
|
||||
* @return {@code this} {@link GcpIamAuthenticationOptionsBuilder}.
|
||||
*/
|
||||
public GcpIamAuthenticationOptionsBuilder clock(Clock clock) {
|
||||
|
||||
Assert.hasText(role, "Clock must not be null");
|
||||
Assert.hasText(this.role, "Clock must not be null");
|
||||
|
||||
this.clock = clock;
|
||||
return this;
|
||||
@@ -338,16 +321,17 @@ public class GcpIamAuthenticationOptions {
|
||||
|
||||
/**
|
||||
* Build a new {@link GcpIamAuthenticationOptions} instance.
|
||||
*
|
||||
* @return a new {@link GcpIamAuthenticationOptions}.
|
||||
*/
|
||||
public GcpIamAuthenticationOptions build() {
|
||||
|
||||
Assert.notNull(credentialSupplier, "GcpCredentialSupplier must not be null");
|
||||
Assert.notNull(role, "Role must not be null");
|
||||
Assert.notNull(this.credentialSupplier, "GcpCredentialSupplier must not be null");
|
||||
Assert.notNull(this.role, "Role must not be null");
|
||||
|
||||
return new GcpIamAuthenticationOptions(path, credentialSupplier, role,
|
||||
jwtValidity, clock, serviceAccountIdAccessor, projectIdAccessor);
|
||||
return new GcpIamAuthenticationOptions(this.path, this.credentialSupplier, this.role, this.jwtValidity,
|
||||
this.clock, this.serviceAccountIdAccessor, this.projectIdAccessor);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -35,8 +35,7 @@ import org.springframework.web.client.RestOperations;
|
||||
*/
|
||||
public abstract class GcpJwtAuthenticationSupport {
|
||||
|
||||
private static final Log logger = LogFactory
|
||||
.getLog(GcpJwtAuthenticationSupport.class);
|
||||
private static final Log logger = LogFactory.getLog(GcpJwtAuthenticationSupport.class);
|
||||
|
||||
private final RestOperations restOperations;
|
||||
|
||||
@@ -49,39 +48,33 @@ public abstract class GcpJwtAuthenticationSupport {
|
||||
|
||||
/**
|
||||
* Perform the actual Vault login given {@code signedJwt}.
|
||||
*
|
||||
* @param authenticationName authentication name for logging.
|
||||
* @param signedJwt the JSON web token.
|
||||
* @param path GCP authentication mount path.
|
||||
* @param role Vault role.
|
||||
* @return the {@link VaultToken}.
|
||||
*/
|
||||
VaultToken doLogin(String authenticationName, String signedJwt, String path,
|
||||
String role) {
|
||||
VaultToken doLogin(String authenticationName, String signedJwt, String path, String role) {
|
||||
|
||||
Map<String, String> login = createRequestBody(role, signedJwt);
|
||||
|
||||
try {
|
||||
|
||||
VaultResponse response = this.restOperations.postForObject(
|
||||
AuthenticationUtil.getLoginPath(path), login, VaultResponse.class);
|
||||
VaultResponse response = this.restOperations.postForObject(AuthenticationUtil.getLoginPath(path), login,
|
||||
VaultResponse.class);
|
||||
|
||||
Assert.state(response != null && response.getAuth() != null,
|
||||
"Auth field must not be null");
|
||||
Assert.state(response != null && response.getAuth() != null, "Auth field must not be null");
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
|
||||
if (response.getAuth().get("metadata") instanceof Map) {
|
||||
|
||||
Map<Object, Object> metadata = (Map<Object, Object>) response
|
||||
.getAuth().get("metadata");
|
||||
logger.debug(String.format(
|
||||
"Login successful using %s authentication for user id %s",
|
||||
Map<Object, Object> metadata = (Map<Object, Object>) response.getAuth().get("metadata");
|
||||
logger.debug(String.format("Login successful using %s authentication for user id %s",
|
||||
authenticationName, metadata.get("service_account_email")));
|
||||
}
|
||||
else {
|
||||
logger.debug("Login successful using " + authenticationName
|
||||
+ " authentication");
|
||||
logger.debug("Login successful using " + authenticationName + " authentication");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,4 +94,5 @@ public abstract class GcpJwtAuthenticationSupport {
|
||||
|
||||
return login;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -31,9 +31,9 @@ public interface GcpProjectIdAccessor {
|
||||
|
||||
/**
|
||||
* Get a the GCP project id to used in Google Cloud IAM API calls.
|
||||
*
|
||||
* @param credential the credential object to obtain the project id from.
|
||||
* @return the service account id to use.
|
||||
*/
|
||||
String getProjectId(GoogleCredential credential);
|
||||
|
||||
}
|
||||
|
||||
@@ -30,9 +30,9 @@ public interface GcpServiceAccountIdAccessor {
|
||||
|
||||
/**
|
||||
* Get a the service account id (email) to be placed in the signed JWT.
|
||||
*
|
||||
* @param credential credential object to obtain the service account id from.
|
||||
* @return the service account id to use.
|
||||
*/
|
||||
String getServiceAccountId(GoogleCredential credential);
|
||||
|
||||
}
|
||||
|
||||
@@ -37,4 +37,5 @@ public class IpAddressUserId implements AppIdUserIdMechanism {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -42,8 +42,7 @@ import org.springframework.web.client.RestOperations;
|
||||
* @see <a href="https://www.vaultproject.io/docs/auth/kubernetes.html">Auth Backend:
|
||||
* Kubernetes</a>
|
||||
*/
|
||||
public class KubernetesAuthentication
|
||||
implements ClientAuthentication, AuthenticationStepsFactory {
|
||||
public class KubernetesAuthentication implements ClientAuthentication, AuthenticationStepsFactory {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(KubernetesAuthentication.class);
|
||||
|
||||
@@ -54,12 +53,10 @@ public class KubernetesAuthentication
|
||||
/**
|
||||
* Create a {@link KubernetesAuthentication} using
|
||||
* {@link KubernetesAuthenticationOptions} and {@link RestOperations}.
|
||||
*
|
||||
* @param options must not be {@literal null}.
|
||||
* @param restOperations must not be {@literal null}.
|
||||
*/
|
||||
public KubernetesAuthentication(KubernetesAuthenticationOptions options,
|
||||
RestOperations restOperations) {
|
||||
public KubernetesAuthentication(KubernetesAuthenticationOptions options, RestOperations restOperations) {
|
||||
|
||||
Assert.notNull(options, "KubernetesAuthenticationOptions must not be null");
|
||||
Assert.notNull(restOperations, "RestOperations must not be null");
|
||||
@@ -71,33 +68,28 @@ public class KubernetesAuthentication
|
||||
/**
|
||||
* Creates a {@link AuthenticationSteps} for kubernetes authentication given
|
||||
* {@link KubernetesAuthenticationOptions}.
|
||||
*
|
||||
* @param options must not be {@literal null}.
|
||||
* @return {@link AuthenticationSteps} for kubernetes authentication.
|
||||
*/
|
||||
public static AuthenticationSteps createAuthenticationSteps(
|
||||
KubernetesAuthenticationOptions options) {
|
||||
public static AuthenticationSteps createAuthenticationSteps(KubernetesAuthenticationOptions options) {
|
||||
|
||||
Assert.notNull(options, "KubernetesAuthenticationOptions must not be null");
|
||||
|
||||
String token = options.getJwtSupplier().get();
|
||||
return AuthenticationSteps
|
||||
.fromSupplier(() -> getKubernetesLogin(options.getRole(), token))
|
||||
return AuthenticationSteps.fromSupplier(() -> getKubernetesLogin(options.getRole(), token))
|
||||
.login(AuthenticationUtil.getLoginPath(options.getPath()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public VaultToken login() throws VaultException {
|
||||
|
||||
Map<String, String> login = getKubernetesLogin(options.getRole(),
|
||||
options.getJwtSupplier().get());
|
||||
Map<String, String> login = getKubernetesLogin(this.options.getRole(), this.options.getJwtSupplier().get());
|
||||
|
||||
try {
|
||||
VaultResponse response = restOperations.postForObject(AuthenticationUtil.getLoginPath(options.getPath()),
|
||||
login, VaultResponse.class);
|
||||
VaultResponse response = this.restOperations
|
||||
.postForObject(AuthenticationUtil.getLoginPath(this.options.getPath()), login, VaultResponse.class);
|
||||
|
||||
Assert.state(response != null && response.getAuth() != null,
|
||||
"Auth field must not be null");
|
||||
Assert.state(response != null && response.getAuth() != null, "Auth field must not be null");
|
||||
|
||||
logger.debug("Login successful using Kubernetes authentication");
|
||||
|
||||
@@ -125,4 +117,5 @@ public class KubernetesAuthentication
|
||||
|
||||
return login;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -57,8 +57,7 @@ public class KubernetesAuthenticationOptions {
|
||||
*/
|
||||
private final Supplier<String> jwtSupplier;
|
||||
|
||||
private KubernetesAuthenticationOptions(String path, String role,
|
||||
Supplier<String> jwtSupplier) {
|
||||
private KubernetesAuthenticationOptions(String path, String role, Supplier<String> jwtSupplier) {
|
||||
|
||||
this.path = path;
|
||||
this.role = role;
|
||||
@@ -76,21 +75,21 @@ public class KubernetesAuthenticationOptions {
|
||||
* @return the path of the kubernetes authentication backend mount.
|
||||
*/
|
||||
public String getPath() {
|
||||
return path;
|
||||
return this.path;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return name of the role against which the login is being attempted.
|
||||
*/
|
||||
public String getRole() {
|
||||
return role;
|
||||
return this.role;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return JSON Web Token supplier.
|
||||
*/
|
||||
public Supplier<String> getJwtSupplier() {
|
||||
return jwtSupplier;
|
||||
return this.jwtSupplier;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -108,7 +107,6 @@ public class KubernetesAuthenticationOptions {
|
||||
|
||||
/**
|
||||
* Configure the mount path.
|
||||
*
|
||||
* @param path must not be {@literal null} or empty.
|
||||
* @return {@code this} {@link KubernetesAuthenticationOptionsBuilder}.
|
||||
*/
|
||||
@@ -122,9 +120,8 @@ public class KubernetesAuthenticationOptions {
|
||||
|
||||
/**
|
||||
* Configure the role.
|
||||
*
|
||||
* @param role name of the role against which the login is being attempted, must
|
||||
* not be {@literal null} or empty.
|
||||
* not be {@literal null} or empty.
|
||||
* @return {@code this} {@link KubernetesAuthenticationOptionsBuilder}.
|
||||
*/
|
||||
public KubernetesAuthenticationOptionsBuilder role(String role) {
|
||||
@@ -137,13 +134,11 @@ public class KubernetesAuthenticationOptions {
|
||||
|
||||
/**
|
||||
* Configure the {@link Supplier} to obtain a Kubernetes authentication token.
|
||||
*
|
||||
* @param jwtSupplier the supplier, must not be {@literal null}.
|
||||
* @return {@code this} {@link KubernetesAuthenticationOptionsBuilder}.
|
||||
* @see KubernetesJwtSupplier
|
||||
*/
|
||||
public KubernetesAuthenticationOptionsBuilder jwtSupplier(
|
||||
Supplier<String> jwtSupplier) {
|
||||
public KubernetesAuthenticationOptionsBuilder jwtSupplier(Supplier<String> jwtSupplier) {
|
||||
|
||||
Assert.notNull(jwtSupplier, "JwtSupplier must not be null");
|
||||
|
||||
@@ -153,16 +148,16 @@ public class KubernetesAuthenticationOptions {
|
||||
|
||||
/**
|
||||
* Build a new {@link KubernetesAuthenticationOptions} instance.
|
||||
*
|
||||
* @return a new {@link KubernetesAuthenticationOptions}.
|
||||
*/
|
||||
public KubernetesAuthenticationOptions build() {
|
||||
|
||||
Assert.notNull(role, "Role must not be null");
|
||||
Assert.notNull(this.role, "Role must not be null");
|
||||
|
||||
return new KubernetesAuthenticationOptions(path, role,
|
||||
jwtSupplier == null ? new KubernetesServiceAccountTokenFile().cached()
|
||||
: jwtSupplier);
|
||||
return new KubernetesAuthenticationOptions(this.path, this.role,
|
||||
this.jwtSupplier == null ? new KubernetesServiceAccountTokenFile().cached() : this.jwtSupplier);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -31,8 +31,7 @@ import org.springframework.core.io.Resource;
|
||||
* @since 2.0
|
||||
* @see KubernetesJwtSupplier
|
||||
*/
|
||||
public class KubernetesServiceAccountTokenFile extends ResourceCredentialSupplier
|
||||
implements KubernetesJwtSupplier {
|
||||
public class KubernetesServiceAccountTokenFile extends ResourceCredentialSupplier implements KubernetesJwtSupplier {
|
||||
|
||||
/**
|
||||
* Default path to the service account token file.
|
||||
@@ -43,9 +42,8 @@ public class KubernetesServiceAccountTokenFile extends ResourceCredentialSupplie
|
||||
* Create a new {@link KubernetesServiceAccountTokenFile} pointing to the
|
||||
* {@link #DEFAULT_KUBERNETES_SERVICE_ACCOUNT_TOKEN_FILE}. Construction fails with an
|
||||
* exception if the file does not exist.
|
||||
*
|
||||
* @throws IllegalArgumentException if the
|
||||
* {@link #DEFAULT_KUBERNETES_SERVICE_ACCOUNT_TOKEN_FILE} does not exist.
|
||||
* {@link #DEFAULT_KUBERNETES_SERVICE_ACCOUNT_TOKEN_FILE} does not exist.
|
||||
*/
|
||||
public KubernetesServiceAccountTokenFile() {
|
||||
this(DEFAULT_KUBERNETES_SERVICE_ACCOUNT_TOKEN_FILE);
|
||||
@@ -54,7 +52,6 @@ public class KubernetesServiceAccountTokenFile extends ResourceCredentialSupplie
|
||||
/**
|
||||
* Create a new {@link KubernetesServiceAccountTokenFile}
|
||||
* {@link KubernetesServiceAccountTokenFile} from a {@code path}.
|
||||
*
|
||||
* @param path path to the service account token file.
|
||||
* @throws IllegalArgumentException if the{@code path} does not exist.
|
||||
*/
|
||||
@@ -65,7 +62,6 @@ public class KubernetesServiceAccountTokenFile extends ResourceCredentialSupplie
|
||||
/**
|
||||
* Create a new {@link KubernetesServiceAccountTokenFile}
|
||||
* {@link KubernetesServiceAccountTokenFile} from a {@link File} handle.
|
||||
*
|
||||
* @param file path to the service account token file.
|
||||
* @throws IllegalArgumentException if the{@code path} does not exist.
|
||||
*/
|
||||
@@ -76,11 +72,11 @@ public class KubernetesServiceAccountTokenFile extends ResourceCredentialSupplie
|
||||
/**
|
||||
* Create a new {@link KubernetesServiceAccountTokenFile}
|
||||
* {@link KubernetesServiceAccountTokenFile} from a {@link Resource} handle.
|
||||
*
|
||||
* @param resource resource pointing to the service account token file.
|
||||
* @throws IllegalArgumentException if the{@code path} does not exist.
|
||||
*/
|
||||
public KubernetesServiceAccountTokenFile(Resource resource) {
|
||||
super(resource);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -102,14 +102,13 @@ public class LifecycleAwareSessionManager extends LifecycleAwareSessionManagerSu
|
||||
/**
|
||||
* Create a {@link LifecycleAwareSessionManager} given {@link ClientAuthentication},
|
||||
* {@link TaskScheduler} and {@link RestOperations}.
|
||||
*
|
||||
* @param clientAuthentication must not be {@literal null}.
|
||||
* @param taskScheduler must not be {@literal null}.
|
||||
* @param restOperations must not be {@literal null}.
|
||||
* @since 1.0.1
|
||||
*/
|
||||
public LifecycleAwareSessionManager(ClientAuthentication clientAuthentication,
|
||||
TaskScheduler taskScheduler, RestOperations restOperations) {
|
||||
public LifecycleAwareSessionManager(ClientAuthentication clientAuthentication, TaskScheduler taskScheduler,
|
||||
RestOperations restOperations) {
|
||||
|
||||
super(taskScheduler);
|
||||
|
||||
@@ -124,16 +123,14 @@ public class LifecycleAwareSessionManager extends LifecycleAwareSessionManagerSu
|
||||
/**
|
||||
* Create a {@link LifecycleAwareSessionManager} given {@link ClientAuthentication},
|
||||
* {@link TaskScheduler} and {@link RestOperations}.
|
||||
*
|
||||
* @param clientAuthentication must not be {@literal null}.
|
||||
* @param taskScheduler must not be {@literal null}.
|
||||
* @param restOperations must not be {@literal null}.
|
||||
* @param refreshTrigger must not be {@literal null}.
|
||||
* @since 1.0.1
|
||||
*/
|
||||
public LifecycleAwareSessionManager(ClientAuthentication clientAuthentication,
|
||||
TaskScheduler taskScheduler, RestOperations restOperations,
|
||||
RefreshTrigger refreshTrigger) {
|
||||
public LifecycleAwareSessionManager(ClientAuthentication clientAuthentication, TaskScheduler taskScheduler,
|
||||
RestOperations restOperations, RefreshTrigger refreshTrigger) {
|
||||
|
||||
super(taskScheduler, refreshTrigger);
|
||||
|
||||
@@ -151,7 +148,7 @@ public class LifecycleAwareSessionManager extends LifecycleAwareSessionManagerSu
|
||||
* session.
|
||||
*/
|
||||
protected Optional<TokenWrapper> getToken() {
|
||||
return token;
|
||||
return this.token;
|
||||
}
|
||||
|
||||
protected void setToken(Optional<TokenWrapper> token) {
|
||||
@@ -164,25 +161,23 @@ public class LifecycleAwareSessionManager extends LifecycleAwareSessionManagerSu
|
||||
Optional<TokenWrapper> token = getToken();
|
||||
setToken(Optional.empty());
|
||||
|
||||
token.filter(TokenWrapper::isRevocable).map(TokenWrapper::getToken)
|
||||
.ifPresent(this::revoke);
|
||||
token.filter(TokenWrapper::isRevocable).map(TokenWrapper::getToken).ifPresent(this::revoke);
|
||||
}
|
||||
|
||||
/**
|
||||
* Revoke a {@link VaultToken}.
|
||||
*
|
||||
* @param token the token to revoke, must not be {@literal null}.
|
||||
*/
|
||||
protected void revoke(VaultToken token) {
|
||||
|
||||
try {
|
||||
dispatch(new BeforeLoginTokenRevocationEvent(token));
|
||||
restOperations.postForObject("auth/token/revoke-self",
|
||||
new HttpEntity<>(VaultHttpHeaders.from(token)), Map.class);
|
||||
this.restOperations.postForObject("auth/token/revoke-self", new HttpEntity<>(VaultHttpHeaders.from(token)),
|
||||
Map.class);
|
||||
dispatch(new AfterLoginTokenRevocationEvent(token));
|
||||
}
|
||||
catch (RuntimeException e) {
|
||||
logger.warn("Cannot revoke VaultToken: %s", e);
|
||||
this.logger.warn("Cannot revoke VaultToken: %s", e);
|
||||
dispatch(new LoginTokenRevocationFailedEvent(token, e));
|
||||
}
|
||||
}
|
||||
@@ -192,13 +187,12 @@ public class LifecycleAwareSessionManager extends LifecycleAwareSessionManagerSu
|
||||
* token was obtained before, it uses self-renewal to renew the current token.
|
||||
* Client-side errors (like permission denied) indicate the token cannot be renewed
|
||||
* because it's expired or simply not found.
|
||||
*
|
||||
* @return {@literal true} if the refresh was successful. {@literal false} if a new
|
||||
* token was obtained or refresh failed.
|
||||
*/
|
||||
public boolean renewToken() {
|
||||
|
||||
logger.info("Renewing token");
|
||||
this.logger.info("Renewing token");
|
||||
|
||||
Optional<TokenWrapper> token = getToken();
|
||||
if (!token.isPresent()) {
|
||||
@@ -212,22 +206,20 @@ public class LifecycleAwareSessionManager extends LifecycleAwareSessionManagerSu
|
||||
}
|
||||
catch (RuntimeException e) {
|
||||
|
||||
VaultTokenRenewalException exception = new VaultTokenRenewalException(
|
||||
format("Cannot renew token", e), e);
|
||||
VaultTokenRenewalException exception = new VaultTokenRenewalException(format("Cannot renew token", e), e);
|
||||
|
||||
if (getLeaseStrategy().shouldDrop(exception)) {
|
||||
setToken(Optional.empty());
|
||||
}
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(exception.getMessage(), exception);
|
||||
if (this.logger.isDebugEnabled()) {
|
||||
this.logger.debug(exception.getMessage(), exception);
|
||||
}
|
||||
else {
|
||||
logger.warn(exception.getMessage());
|
||||
this.logger.warn(exception.getMessage());
|
||||
}
|
||||
|
||||
dispatch(
|
||||
new LoginTokenRenewalFailedEvent(tokenWrapper.getToken(), exception));
|
||||
dispatch(new LoginTokenRenewalFailedEvent(tokenWrapper.getToken(), exception));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -235,24 +227,20 @@ public class LifecycleAwareSessionManager extends LifecycleAwareSessionManagerSu
|
||||
private boolean doRenew(TokenWrapper wrapper) {
|
||||
|
||||
dispatch(new BeforeLoginTokenRenewedEvent(wrapper.getToken()));
|
||||
VaultResponse vaultResponse = restOperations.postForObject(
|
||||
"auth/token/renew-self",
|
||||
new HttpEntity<>(VaultHttpHeaders.from(wrapper.token)),
|
||||
VaultResponse.class);
|
||||
VaultResponse vaultResponse = this.restOperations.postForObject("auth/token/renew-self",
|
||||
new HttpEntity<>(VaultHttpHeaders.from(wrapper.token)), VaultResponse.class);
|
||||
|
||||
LoginToken renewed = LoginTokenUtil.from(vaultResponse.getRequiredAuth());
|
||||
|
||||
if (isExpired(renewed)) {
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
Duration validTtlThreshold = getRefreshTrigger()
|
||||
.getValidTtlThreshold(renewed);
|
||||
logger.info(String.format(
|
||||
"Token TTL (%s) exceeded validity TTL threshold (%s). Dropping token.",
|
||||
if (this.logger.isDebugEnabled()) {
|
||||
Duration validTtlThreshold = getRefreshTrigger().getValidTtlThreshold(renewed);
|
||||
this.logger.info(String.format("Token TTL (%s) exceeded validity TTL threshold (%s). Dropping token.",
|
||||
renewed.getLeaseDuration(), validTtlThreshold));
|
||||
}
|
||||
else {
|
||||
logger.info("Token TTL exceeded validity TTL threshold. Dropping token.");
|
||||
this.logger.info("Token TTL exceeded validity TTL threshold. Dropping token.");
|
||||
}
|
||||
|
||||
setToken(Optional.empty());
|
||||
@@ -271,7 +259,7 @@ public class LifecycleAwareSessionManager extends LifecycleAwareSessionManagerSu
|
||||
|
||||
if (!getToken().isPresent()) {
|
||||
|
||||
synchronized (lock) {
|
||||
synchronized (this.lock) {
|
||||
|
||||
if (!getToken().isPresent()) {
|
||||
doGetSessionToken();
|
||||
@@ -288,25 +276,22 @@ public class LifecycleAwareSessionManager extends LifecycleAwareSessionManagerSu
|
||||
VaultToken token;
|
||||
|
||||
try {
|
||||
token = clientAuthentication.login();
|
||||
token = this.clientAuthentication.login();
|
||||
}
|
||||
catch (VaultException e) {
|
||||
dispatch(new LoginFailedEvent(clientAuthentication, e));
|
||||
dispatch(new LoginFailedEvent(this.clientAuthentication, e));
|
||||
throw e;
|
||||
}
|
||||
|
||||
TokenWrapper wrapper = new TokenWrapper(token, token instanceof LoginToken);
|
||||
|
||||
if (isTokenSelfLookupEnabled()
|
||||
&& !ClassUtils.isAssignableValue(LoginToken.class, token)) {
|
||||
if (isTokenSelfLookupEnabled() && !ClassUtils.isAssignableValue(LoginToken.class, token)) {
|
||||
try {
|
||||
token = LoginTokenAdapter.augmentWithSelfLookup(this.restOperations,
|
||||
token);
|
||||
token = LoginTokenAdapter.augmentWithSelfLookup(this.restOperations, token);
|
||||
wrapper = new TokenWrapper(token, false);
|
||||
}
|
||||
catch (VaultTokenLookupException e) {
|
||||
logger.warn(String.format("Cannot enhance VaultToken to a LoginToken: %s",
|
||||
e.getMessage()));
|
||||
this.logger.warn(String.format("Cannot enhance VaultToken to a LoginToken: %s", e.getMessage()));
|
||||
dispatch(new AuthenticationErrorEvent(token, e));
|
||||
}
|
||||
}
|
||||
@@ -320,7 +305,7 @@ public class LifecycleAwareSessionManager extends LifecycleAwareSessionManagerSu
|
||||
}
|
||||
|
||||
protected VaultToken login() {
|
||||
return clientAuthentication.login();
|
||||
return this.clientAuthentication.login();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -333,14 +318,13 @@ public class LifecycleAwareSessionManager extends LifecycleAwareSessionManagerSu
|
||||
.filter(it -> {
|
||||
|
||||
LoginToken loginToken = (LoginToken) it;
|
||||
return !loginToken.getLeaseDuration().isZero()
|
||||
&& loginToken.isRenewable();
|
||||
return !loginToken.getLeaseDuration().isZero() && loginToken.isRenewable();
|
||||
}).isPresent();
|
||||
}
|
||||
|
||||
private void scheduleRenewal() {
|
||||
|
||||
logger.info("Scheduling Token renewal");
|
||||
this.logger.info("Scheduling Token renewal");
|
||||
|
||||
Runnable task = () -> {
|
||||
Optional<TokenWrapper> tokenWrapper = getToken();
|
||||
@@ -359,21 +343,19 @@ public class LifecycleAwareSessionManager extends LifecycleAwareSessionManagerSu
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
logger.error("Cannot renew VaultToken", e);
|
||||
this.logger.error("Cannot renew VaultToken", e);
|
||||
dispatch(new LoginTokenRenewalFailedEvent(token, e));
|
||||
}
|
||||
};
|
||||
|
||||
Optional<TokenWrapper> token = getToken();
|
||||
|
||||
token.ifPresent(tokenWrapper -> getTaskScheduler().schedule(task,
|
||||
createTrigger(tokenWrapper)));
|
||||
token.ifPresent(tokenWrapper -> getTaskScheduler().schedule(task, createTrigger(tokenWrapper)));
|
||||
}
|
||||
|
||||
private OneShotTrigger createTrigger(TokenWrapper tokenWrapper) {
|
||||
|
||||
return new OneShotTrigger(getRefreshTrigger()
|
||||
.nextExecutionTime((LoginToken) tokenWrapper.getToken()));
|
||||
return new OneShotTrigger(getRefreshTrigger().nextExecutionTime((LoginToken) tokenWrapper.getToken()));
|
||||
}
|
||||
|
||||
private static String format(String message, RuntimeException e) {
|
||||
@@ -381,8 +363,7 @@ public class LifecycleAwareSessionManager extends LifecycleAwareSessionManagerSu
|
||||
if (e instanceof HttpStatusCodeException) {
|
||||
|
||||
HttpStatusCodeException hsce = (HttpStatusCodeException) e;
|
||||
return String.format("%s: Status %s %s %s", message, hsce.getRawStatusCode(),
|
||||
hsce.getStatusText(),
|
||||
return String.format("%s: Status %s %s %s", message, hsce.getRawStatusCode(), hsce.getStatusText(),
|
||||
VaultResponses.getError(hsce.getResponseBodyAsString()));
|
||||
}
|
||||
|
||||
@@ -398,6 +379,7 @@ public class LifecycleAwareSessionManager extends LifecycleAwareSessionManagerSu
|
||||
protected static class TokenWrapper {
|
||||
|
||||
private final VaultToken token;
|
||||
|
||||
private final boolean revocable;
|
||||
|
||||
TokenWrapper(VaultToken token, boolean revocable) {
|
||||
@@ -412,5 +394,7 @@ public class LifecycleAwareSessionManager extends LifecycleAwareSessionManagerSu
|
||||
public boolean isRevocable() {
|
||||
return this.revocable;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -41,16 +41,15 @@ import org.springframework.vault.support.VaultToken;
|
||||
* @author Mark Paluch
|
||||
* @since 2.0
|
||||
*/
|
||||
public abstract class LifecycleAwareSessionManagerSupport
|
||||
extends AuthenticationEventPublisher {
|
||||
public abstract class LifecycleAwareSessionManagerSupport extends AuthenticationEventPublisher {
|
||||
|
||||
/**
|
||||
* Refresh 5 seconds before the token expires.
|
||||
*/
|
||||
public static final int REFRESH_PERIOD_BEFORE_EXPIRY = 5;
|
||||
|
||||
private static final RefreshTrigger DEFAULT_TRIGGER = new FixedTimeoutRefreshTrigger(
|
||||
REFRESH_PERIOD_BEFORE_EXPIRY, TimeUnit.SECONDS);
|
||||
private static final RefreshTrigger DEFAULT_TRIGGER = new FixedTimeoutRefreshTrigger(REFRESH_PERIOD_BEFORE_EXPIRY,
|
||||
TimeUnit.SECONDS);
|
||||
|
||||
/**
|
||||
* Logger available to subclasses.
|
||||
@@ -81,7 +80,6 @@ public abstract class LifecycleAwareSessionManagerSupport
|
||||
/**
|
||||
* Create a {@link LifecycleAwareSessionManager} given {@link TaskScheduler}. Using
|
||||
* {@link #DEFAULT_TRIGGER} to trigger refresh.
|
||||
*
|
||||
* @param taskScheduler must not be {@literal null}.
|
||||
*/
|
||||
public LifecycleAwareSessionManagerSupport(TaskScheduler taskScheduler) {
|
||||
@@ -91,12 +89,10 @@ public abstract class LifecycleAwareSessionManagerSupport
|
||||
/**
|
||||
* Create a {@link LifecycleAwareSessionManager} given {@link TaskScheduler} and
|
||||
* {@link RefreshTrigger}.
|
||||
*
|
||||
* @param taskScheduler must not be {@literal null}.
|
||||
* @param refreshTrigger must not be {@literal null}.
|
||||
*/
|
||||
public LifecycleAwareSessionManagerSupport(TaskScheduler taskScheduler,
|
||||
RefreshTrigger refreshTrigger) {
|
||||
public LifecycleAwareSessionManagerSupport(TaskScheduler taskScheduler, RefreshTrigger refreshTrigger) {
|
||||
|
||||
Assert.notNull(taskScheduler, "TaskScheduler must not be null");
|
||||
Assert.notNull(refreshTrigger, "RefreshTrigger must not be null");
|
||||
@@ -114,21 +110,19 @@ public abstract class LifecycleAwareSessionManagerSupport
|
||||
* Self-lookup for tokens without a permission to access
|
||||
* {@code auth/token/lookup-self} will fail gracefully and continue without token
|
||||
* renewal.
|
||||
*
|
||||
* @return {@literal true} to enable self-lookup, {@literal false} to disable
|
||||
* self-lookup. Enabled by default.
|
||||
*/
|
||||
protected boolean isTokenSelfLookupEnabled() {
|
||||
return tokenSelfLookupEnabled;
|
||||
return this.tokenSelfLookupEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables/disables token self-lookup. Self-lookup augments {@link VaultToken}
|
||||
* obtained from a {@link ClientAuthentication}. Self-lookup determines whether a
|
||||
* token is renewable and its TTL.
|
||||
*
|
||||
* @param tokenSelfLookupEnabled {@literal true} to enable self-lookup,
|
||||
* {@literal false} to disable self-lookup. Enabled by default.
|
||||
* {@literal false} to disable self-lookup. Enabled by default.
|
||||
*/
|
||||
public void setTokenSelfLookupEnabled(boolean tokenSelfLookupEnabled) {
|
||||
this.tokenSelfLookupEnabled = tokenSelfLookupEnabled;
|
||||
@@ -136,7 +130,6 @@ public abstract class LifecycleAwareSessionManagerSupport
|
||||
|
||||
/**
|
||||
* Set the {@link LeaseStrategy} for lease renewal error handling.
|
||||
*
|
||||
* @param leaseStrategy the {@link LeaseStrategy}, must not be {@literal null}.
|
||||
* @since 2.2
|
||||
*/
|
||||
@@ -147,28 +140,27 @@ public abstract class LifecycleAwareSessionManagerSupport
|
||||
}
|
||||
|
||||
LeaseStrategy getLeaseStrategy() {
|
||||
return leaseStrategy;
|
||||
return this.leaseStrategy;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the underlying {@link TaskScheduler}.
|
||||
*/
|
||||
protected TaskScheduler getTaskScheduler() {
|
||||
return taskScheduler;
|
||||
return this.taskScheduler;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the underlying {@link RefreshTrigger}.
|
||||
*/
|
||||
protected RefreshTrigger getRefreshTrigger() {
|
||||
return refreshTrigger;
|
||||
return this.refreshTrigger;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the Token falls below its
|
||||
* {@link RefreshTrigger#getValidTtlThreshold(LoginToken) validity threshold}.
|
||||
* Typically used to discard a token.
|
||||
*
|
||||
* @param loginToken must not be {@literal null}.
|
||||
* @return {@literal true} if token validity falls below validity threshold,
|
||||
* {@literal false} if still valid.
|
||||
@@ -196,12 +188,13 @@ public abstract class LifecycleAwareSessionManagerSupport
|
||||
@Nullable
|
||||
public Date nextExecutionTime(TriggerContext triggerContext) {
|
||||
|
||||
if (fired.compareAndSet(false, true)) {
|
||||
return nextExecutionTime;
|
||||
if (this.fired.compareAndSet(false, true)) {
|
||||
return this.nextExecutionTime;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -212,7 +205,6 @@ public abstract class LifecycleAwareSessionManagerSupport
|
||||
|
||||
/**
|
||||
* Determine the next execution time according to the given trigger context.
|
||||
*
|
||||
* @param loginToken login token encapsulating renewability and lease duration.
|
||||
* @return the next execution time as defined by the trigger, or {@code null} if
|
||||
* the trigger won't fire anymore
|
||||
@@ -222,12 +214,12 @@ public abstract class LifecycleAwareSessionManagerSupport
|
||||
/**
|
||||
* Returns the minimum TTL duration to consider a token valid after renewal.
|
||||
* Tokens with a shorter TTL are revoked and considered expired.
|
||||
*
|
||||
* @param loginToken the login token after renewal.
|
||||
* @return minimum TTL {@link Duration} to consider a token valid.
|
||||
* @since 2.0
|
||||
*/
|
||||
Duration getValidTtlThreshold(LoginToken loginToken);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -242,19 +234,18 @@ public abstract class LifecycleAwareSessionManagerSupport
|
||||
private static final Duration ONE_SECOND = Duration.ofSeconds(1);
|
||||
|
||||
private final Duration duration;
|
||||
|
||||
private final Duration validTtlThreshold;
|
||||
|
||||
/**
|
||||
* Create a new {@link FixedTimeoutRefreshTrigger} to calculate execution times of
|
||||
* {@code timeout} before the {@link LoginToken} expires
|
||||
*
|
||||
* @param timeout timeout value, non-negative long value.
|
||||
* @param timeUnit must not be {@literal null}.
|
||||
*/
|
||||
public FixedTimeoutRefreshTrigger(long timeout, TimeUnit timeUnit) {
|
||||
|
||||
Assert.isTrue(timeout >= 0,
|
||||
"Timeout duration must be greater or equal to zero");
|
||||
Assert.isTrue(timeout >= 0, "Timeout duration must be greater or equal to zero");
|
||||
Assert.notNull(timeUnit, "TimeUnit must not be null");
|
||||
|
||||
this.duration = Duration.ofMillis(timeUnit.toMillis(timeout));
|
||||
@@ -265,7 +256,6 @@ public abstract class LifecycleAwareSessionManagerSupport
|
||||
* Create a new {@link FixedTimeoutRefreshTrigger} to calculate execution times of
|
||||
* {@code timeout} before the {@link LoginToken} expires. Valid TTL threshold is
|
||||
* set to two seconds longer to compensate for timing issues during scheduling.
|
||||
*
|
||||
* @param timeout timeout value.
|
||||
* @since 2.0
|
||||
*/
|
||||
@@ -276,17 +266,15 @@ public abstract class LifecycleAwareSessionManagerSupport
|
||||
/**
|
||||
* Create a new {@link FixedTimeoutRefreshTrigger} to calculate execution times of
|
||||
* {@code timeout} before the {@link LoginToken} expires.
|
||||
*
|
||||
* @param timeout timeout value.
|
||||
* @param validTtlThreshold minimum TTL duration to consider a Token as valid.
|
||||
* Tokens with a shorter TTL are not used anymore. Should be greater than
|
||||
* {@code timeout} to prevent token expiry.
|
||||
* Tokens with a shorter TTL are not used anymore. Should be greater than
|
||||
* {@code timeout} to prevent token expiry.
|
||||
* @since 2.0
|
||||
*/
|
||||
public FixedTimeoutRefreshTrigger(Duration timeout, Duration validTtlThreshold) {
|
||||
|
||||
Assert.isTrue(timeout.toMillis() >= 0,
|
||||
"Timeout duration must be greater or equal to zero");
|
||||
Assert.isTrue(timeout.toMillis() >= 0, "Timeout duration must be greater or equal to zero");
|
||||
|
||||
Assert.notNull(validTtlThreshold, "Valid TTL threshold must not be null");
|
||||
|
||||
@@ -298,14 +286,16 @@ public abstract class LifecycleAwareSessionManagerSupport
|
||||
public Date nextExecutionTime(LoginToken loginToken) {
|
||||
|
||||
long milliseconds = Math.max(ONE_SECOND.toMillis(),
|
||||
loginToken.getLeaseDuration().toMillis() - duration.toMillis());
|
||||
loginToken.getLeaseDuration().toMillis() - this.duration.toMillis());
|
||||
|
||||
return new Date(System.currentTimeMillis() + milliseconds);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Duration getValidTtlThreshold(LoginToken loginToken) {
|
||||
return validTtlThreshold;
|
||||
return this.validTtlThreshold;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -44,7 +44,6 @@ public class LoginToken extends VaultToken {
|
||||
|
||||
/**
|
||||
* Create a new {@link LoginToken}.
|
||||
*
|
||||
* @param token must not be {@literal null}.
|
||||
* @return the created {@link VaultToken}
|
||||
*/
|
||||
@@ -57,7 +56,6 @@ public class LoginToken extends VaultToken {
|
||||
|
||||
/**
|
||||
* Create a new {@link LoginToken}.
|
||||
*
|
||||
* @param token must not be {@literal null}.
|
||||
* @return the created {@link VaultToken}
|
||||
* @since 1.1
|
||||
@@ -68,7 +66,6 @@ public class LoginToken extends VaultToken {
|
||||
|
||||
/**
|
||||
* Create a new {@link LoginToken} with a {@code leaseDurationSeconds}.
|
||||
*
|
||||
* @param token must not be {@literal null}.
|
||||
* @param leaseDurationSeconds the lease duration in seconds, must not be negative.
|
||||
* @return the created {@link VaultToken}
|
||||
@@ -85,7 +82,6 @@ public class LoginToken extends VaultToken {
|
||||
|
||||
/**
|
||||
* Create a new {@link LoginToken} with a {@code leaseDurationSeconds}.
|
||||
*
|
||||
* @param token must not be {@literal null}.
|
||||
* @param leaseDurationSeconds the lease duration in seconds, must not be negative.
|
||||
* @return the created {@link VaultToken}
|
||||
@@ -104,11 +100,9 @@ public class LoginToken extends VaultToken {
|
||||
|
||||
/**
|
||||
* Create a new {@link LoginToken} with a {@code leaseDurationSeconds}.
|
||||
*
|
||||
* @param token must not be {@literal null}.
|
||||
*
|
||||
* @param leaseDuration the lease duration, must not be negative and not be
|
||||
* {@literal null}.
|
||||
* {@literal null}.
|
||||
* @return the created {@link VaultToken}
|
||||
* @since 2.0
|
||||
*/
|
||||
@@ -124,7 +118,6 @@ public class LoginToken extends VaultToken {
|
||||
|
||||
/**
|
||||
* Create a new renewable {@link LoginToken} with a {@code leaseDurationSeconds}.
|
||||
*
|
||||
* @param token must not be {@literal null}.
|
||||
* @param leaseDurationSeconds the lease duration in seconds, must not be negative.
|
||||
* @return the created {@link VaultToken}
|
||||
@@ -142,7 +135,6 @@ public class LoginToken extends VaultToken {
|
||||
|
||||
/**
|
||||
* Create a new renewable {@link LoginToken} with a {@code leaseDurationSeconds}.
|
||||
*
|
||||
* @param token must not be {@literal null}.
|
||||
* @param leaseDurationSeconds the lease duration in seconds, must not be negative.
|
||||
* @return the created {@link VaultToken}
|
||||
@@ -162,7 +154,6 @@ public class LoginToken extends VaultToken {
|
||||
|
||||
/**
|
||||
* Create a new renewable {@link LoginToken} with a {@code leaseDurationSeconds}.
|
||||
*
|
||||
* @param token must not be {@literal null}.
|
||||
* @param leaseDuration the lease duration, must not be {@literal null} or negative.
|
||||
* @return the created {@link VaultToken}
|
||||
@@ -177,7 +168,6 @@ public class LoginToken extends VaultToken {
|
||||
|
||||
/**
|
||||
* Create a new renewable {@link LoginToken} with a {@code leaseDurationSeconds}.
|
||||
*
|
||||
* @param token must not be {@literal null}.
|
||||
* @param leaseDuration the lease duration, must not be {@literal null} or negative.
|
||||
* @return the created {@link VaultToken}
|
||||
@@ -197,23 +187,24 @@ public class LoginToken extends VaultToken {
|
||||
* @return the lease duration in seconds. May be {@literal 0} if none.
|
||||
*/
|
||||
public Duration getLeaseDuration() {
|
||||
return leaseDuration;
|
||||
return this.leaseDuration;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@literal true} if this token is renewable; {@literal false} otherwise.
|
||||
*/
|
||||
public boolean isRenewable() {
|
||||
return renewable;
|
||||
return this.renewable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
sb.append(getClass().getSimpleName());
|
||||
sb.append(" [renewable=").append(renewable);
|
||||
sb.append(", leaseDuration=").append(leaseDuration);
|
||||
sb.append(" [renewable=").append(this.renewable);
|
||||
sb.append(", leaseDuration=").append(this.leaseDuration);
|
||||
sb.append(']');
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -52,12 +52,10 @@ public class LoginTokenAdapter implements ClientAuthentication {
|
||||
/**
|
||||
* Create a new {@link LoginTokenAdapter} given {@link ClientAuthentication} to
|
||||
* decorate and {@link RestOperations}.
|
||||
*
|
||||
* @param delegate must not be {@literal null}.
|
||||
* @param restOperations must not be {@literal null}.
|
||||
*/
|
||||
public LoginTokenAdapter(ClientAuthentication delegate,
|
||||
RestOperations restOperations) {
|
||||
public LoginTokenAdapter(ClientAuthentication delegate, RestOperations restOperations) {
|
||||
|
||||
Assert.notNull(delegate, "ClientAuthentication delegate must not be null");
|
||||
Assert.notNull(restOperations, "RestOperations must not be null");
|
||||
@@ -68,15 +66,14 @@ public class LoginTokenAdapter implements ClientAuthentication {
|
||||
|
||||
@Override
|
||||
public LoginToken login() throws VaultException {
|
||||
return augmentWithSelfLookup(delegate.login());
|
||||
return augmentWithSelfLookup(this.delegate.login());
|
||||
}
|
||||
|
||||
private LoginToken augmentWithSelfLookup(VaultToken token) {
|
||||
return augmentWithSelfLookup(this.restOperations, token);
|
||||
}
|
||||
|
||||
static LoginToken augmentWithSelfLookup(RestOperations restOperations,
|
||||
VaultToken token) {
|
||||
static LoginToken augmentWithSelfLookup(RestOperations restOperations, VaultToken token) {
|
||||
|
||||
Map<String, Object> data = lookupSelf(restOperations, token);
|
||||
|
||||
@@ -90,23 +87,19 @@ public class LoginTokenAdapter implements ClientAuthentication {
|
||||
return LoginToken.of(token.toCharArray(), getLeaseDuration(ttl));
|
||||
}
|
||||
|
||||
private static Map<String, Object> lookupSelf(RestOperations restOperations,
|
||||
VaultToken token) {
|
||||
private static Map<String, Object> lookupSelf(RestOperations restOperations, VaultToken token) {
|
||||
|
||||
try {
|
||||
ResponseEntity<VaultResponse> entity = restOperations.exchange(
|
||||
"auth/token/lookup-self", HttpMethod.GET,
|
||||
ResponseEntity<VaultResponse> entity = restOperations.exchange("auth/token/lookup-self", HttpMethod.GET,
|
||||
new HttpEntity<>(VaultHttpHeaders.from(token)), VaultResponse.class);
|
||||
|
||||
Assert.state(entity.getBody() != null && entity.getBody().getData() != null,
|
||||
"Token response is null");
|
||||
Assert.state(entity.getBody() != null && entity.getBody().getData() != null, "Token response is null");
|
||||
|
||||
return entity.getBody().getData();
|
||||
}
|
||||
catch (HttpStatusCodeException e) {
|
||||
throw new VaultTokenLookupException(
|
||||
String.format("Token self-lookup failed: %s %s", e.getRawStatusCode(),
|
||||
VaultResponses.getError(e.getResponseBodyAsString())));
|
||||
throw new VaultTokenLookupException(String.format("Token self-lookup failed: %s %s", e.getRawStatusCode(),
|
||||
VaultResponses.getError(e.getResponseBodyAsString())));
|
||||
}
|
||||
catch (RestClientException e) {
|
||||
throw new VaultTokenLookupException("Token self-lookup failed", e);
|
||||
@@ -116,4 +109,5 @@ public class LoginTokenAdapter implements ClientAuthentication {
|
||||
static Duration getLeaseDuration(@Nullable Number ttl) {
|
||||
return ttl == null ? Duration.ZERO : Duration.ofSeconds(ttl.longValue());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -28,13 +28,11 @@ import org.springframework.util.Assert;
|
||||
final class LoginTokenUtil {
|
||||
|
||||
private LoginTokenUtil() {
|
||||
throw new UnsupportedOperationException(
|
||||
"This is a utility class and cannot be instantiated");
|
||||
throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a {@link LoginToken} from an auth response.
|
||||
*
|
||||
* @param auth {@link Map} holding a login response.
|
||||
* @return the {@link LoginToken}
|
||||
*/
|
||||
@@ -49,7 +47,6 @@ final class LoginTokenUtil {
|
||||
|
||||
/**
|
||||
* Construct a {@link LoginToken} from an auth response.
|
||||
*
|
||||
* @param auth {@link Map} holding a login response.
|
||||
* @return the {@link LoginToken}
|
||||
* @since 2.0
|
||||
@@ -66,8 +63,7 @@ final class LoginTokenUtil {
|
||||
}
|
||||
|
||||
if (renewable != null && renewable) {
|
||||
return LoginToken.renewable(token,
|
||||
Duration.ofSeconds(leaseDuration.longValue()));
|
||||
return LoginToken.renewable(token, Duration.ofSeconds(leaseDuration.longValue()));
|
||||
}
|
||||
|
||||
if (leaseDuration != null) {
|
||||
@@ -76,4 +72,5 @@ final class LoginTokenUtil {
|
||||
|
||||
return LoginToken.of(token);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -57,13 +57,11 @@ public class MacAddressUserId implements AppIdUserIdMechanism {
|
||||
* Create a new {@link MacAddressUserId} using a {@code networkInterfaceIndex}. The
|
||||
* index is applied to {@link NetworkInterface#getNetworkInterfaces()} to obtain the
|
||||
* desired network interface.
|
||||
*
|
||||
* @param networkInterfaceIndex must be greater or equal to zero.
|
||||
*/
|
||||
public MacAddressUserId(int networkInterfaceIndex) {
|
||||
|
||||
Assert.isTrue(networkInterfaceIndex >= 0,
|
||||
"NetworkInterfaceIndex must be greater or equal to 0");
|
||||
Assert.isTrue(networkInterfaceIndex >= 0, "NetworkInterfaceIndex must be greater or equal to 0");
|
||||
|
||||
this.networkInterfaceHint = "" + networkInterfaceIndex;
|
||||
}
|
||||
@@ -72,7 +70,6 @@ public class MacAddressUserId implements AppIdUserIdMechanism {
|
||||
* Create a new {@link MacAddressUserId} using a {@code networkInterfaceName}. This
|
||||
* name is compared with {@link NetworkInterface#getName()} and
|
||||
* {@link NetworkInterface#getDisplayName()} to obtain the desired network interface.
|
||||
*
|
||||
* @param networkInterfaceName must not be {@literal null}.
|
||||
*/
|
||||
public MacAddressUserId(String networkInterfaceName) {
|
||||
@@ -88,35 +85,29 @@ public class MacAddressUserId implements AppIdUserIdMechanism {
|
||||
try {
|
||||
|
||||
Optional<NetworkInterface> networkInterface = Optional.empty();
|
||||
List<NetworkInterface> interfaces = Collections
|
||||
.list(NetworkInterface.getNetworkInterfaces());
|
||||
List<NetworkInterface> interfaces = Collections.list(NetworkInterface.getNetworkInterfaces());
|
||||
|
||||
if (StringUtils.hasText(networkInterfaceHint)) {
|
||||
if (StringUtils.hasText(this.networkInterfaceHint)) {
|
||||
|
||||
try {
|
||||
networkInterface = getNetworkInterface(
|
||||
Integer.parseInt(networkInterfaceHint), interfaces);
|
||||
networkInterface = getNetworkInterface(Integer.parseInt(this.networkInterfaceHint), interfaces);
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
networkInterface = getNetworkInterface((networkInterfaceHint),
|
||||
interfaces);
|
||||
networkInterface = getNetworkInterface((this.networkInterfaceHint), interfaces);
|
||||
}
|
||||
}
|
||||
|
||||
if (!networkInterface.isPresent()) {
|
||||
|
||||
if (StringUtils.hasText(networkInterfaceHint)) {
|
||||
log.warn(String.format(
|
||||
"Did not find a NetworkInterface applying hint %s",
|
||||
networkInterfaceHint));
|
||||
if (StringUtils.hasText(this.networkInterfaceHint)) {
|
||||
this.log.warn(String.format("Did not find a NetworkInterface applying hint %s",
|
||||
this.networkInterfaceHint));
|
||||
}
|
||||
|
||||
InetAddress localHost = InetAddress.getLocalHost();
|
||||
networkInterface = Optional
|
||||
.ofNullable(NetworkInterface.getByInetAddress(localHost));
|
||||
networkInterface = Optional.ofNullable(NetworkInterface.getByInetAddress(localHost));
|
||||
|
||||
if (!networkInterface.filter(MacAddressUserId::hasNetworkAddress)
|
||||
.isPresent()) {
|
||||
if (!networkInterface.filter(MacAddressUserId::hasNetworkAddress).isPresent()) {
|
||||
networkInterface = getNetworkInterfaceWithHardwareAddress(interfaces);
|
||||
}
|
||||
}
|
||||
@@ -124,8 +115,7 @@ public class MacAddressUserId implements AppIdUserIdMechanism {
|
||||
return networkInterface.map(MacAddressUserId::getRequiredNetworkAddress) //
|
||||
.map(Sha256::toHexString) //
|
||||
.map(Sha256::toSha256) //
|
||||
.orElseThrow(() -> new IllegalStateException(
|
||||
"Cannot determine NetworkInterface"));
|
||||
.orElseThrow(() -> new IllegalStateException("Cannot determine NetworkInterface"));
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new IllegalStateException(e);
|
||||
@@ -133,8 +123,7 @@ public class MacAddressUserId implements AppIdUserIdMechanism {
|
||||
|
||||
}
|
||||
|
||||
private static Optional<NetworkInterface> getNetworkInterface(Number hint,
|
||||
List<NetworkInterface> interfaces) {
|
||||
private static Optional<NetworkInterface> getNetworkInterface(Number hint, List<NetworkInterface> interfaces) {
|
||||
|
||||
if (interfaces.size() > hint.intValue() && hint.intValue() >= 0) {
|
||||
return Optional.of(interfaces.get(hint.intValue()));
|
||||
@@ -143,8 +132,7 @@ public class MacAddressUserId implements AppIdUserIdMechanism {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
private static Optional<NetworkInterface> getNetworkInterface(String hint,
|
||||
List<NetworkInterface> interfaces) {
|
||||
private static Optional<NetworkInterface> getNetworkInterface(String hint, List<NetworkInterface> interfaces) {
|
||||
|
||||
return interfaces.stream() //
|
||||
.filter(anInterface -> matchesHint(hint, anInterface)) //
|
||||
@@ -153,8 +141,7 @@ public class MacAddressUserId implements AppIdUserIdMechanism {
|
||||
|
||||
private static boolean matchesHint(String hint, NetworkInterface networkInterface) {
|
||||
|
||||
return hint.equals(networkInterface.getDisplayName())
|
||||
|| hint.equals(networkInterface.getName());
|
||||
return hint.equals(networkInterface.getDisplayName()) || hint.equals(networkInterface.getName());
|
||||
}
|
||||
|
||||
private static Optional<NetworkInterface> getNetworkInterfaceWithHardwareAddress(
|
||||
@@ -172,19 +159,19 @@ public class MacAddressUserId implements AppIdUserIdMechanism {
|
||||
return Optional.ofNullable(it.getHardwareAddress());
|
||||
}
|
||||
catch (SocketException e) {
|
||||
throw new IllegalStateException(String
|
||||
.format("Cannot determine hardware address for %s", it.getName()));
|
||||
throw new IllegalStateException(String.format("Cannot determine hardware address for %s", it.getName()));
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] getRequiredNetworkAddress(NetworkInterface it) {
|
||||
|
||||
return getNetworkAddress(it) //
|
||||
.orElseThrow(() -> new IllegalStateException(String.format(
|
||||
"Network interface %s has no hardware address", it.getName())));
|
||||
.orElseThrow(() -> new IllegalStateException(
|
||||
String.format("Network interface %s has no hardware address", it.getName())));
|
||||
}
|
||||
|
||||
private static boolean hasNetworkAddress(NetworkInterface it) {
|
||||
return getNetworkAddress(it).isPresent();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -52,13 +52,11 @@ import org.springframework.web.client.RestOperations;
|
||||
* @see RestOperations
|
||||
* @see <a href="https://www.vaultproject.io/docs/auth/pcf.html">Auth Backend: PCF</a>
|
||||
*/
|
||||
public class PcfAuthentication
|
||||
implements ClientAuthentication, AuthenticationStepsFactory {
|
||||
public class PcfAuthentication implements ClientAuthentication, AuthenticationStepsFactory {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(PcfAuthentication.class);
|
||||
|
||||
private static final DateTimeFormatter TIME_FORMAT = DateTimeFormatter
|
||||
.ofPattern("yyyy-MM-dd'T'HH:mm:ss'Z'");
|
||||
private static final DateTimeFormatter TIME_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss'Z'");
|
||||
|
||||
// SHA256 hash and a salt length of 222
|
||||
private static final int SALT_LENGTH = 222;
|
||||
@@ -70,12 +68,10 @@ public class PcfAuthentication
|
||||
/**
|
||||
* Create a {@link PcfAuthentication} using {@link PcfAuthenticationOptions} and
|
||||
* {@link RestOperations}.
|
||||
*
|
||||
* @param options must not be {@literal null}.
|
||||
* @param restOperations must not be {@literal null}.
|
||||
*/
|
||||
public PcfAuthentication(PcfAuthenticationOptions options,
|
||||
RestOperations restOperations) {
|
||||
public PcfAuthentication(PcfAuthenticationOptions options, RestOperations restOperations) {
|
||||
|
||||
Assert.notNull(options, "PcfAuthenticationOptions must not be null");
|
||||
Assert.notNull(restOperations, "RestOperations must not be null");
|
||||
@@ -87,36 +83,31 @@ public class PcfAuthentication
|
||||
/**
|
||||
* Creates a {@link AuthenticationSteps} for pcf authentication given
|
||||
* {@link PcfAuthenticationOptions}.
|
||||
*
|
||||
* @param options must not be {@literal null}.
|
||||
* @return {@link AuthenticationSteps} for pcf authentication.
|
||||
*/
|
||||
public static AuthenticationSteps createAuthenticationSteps(
|
||||
PcfAuthenticationOptions options) {
|
||||
public static AuthenticationSteps createAuthenticationSteps(PcfAuthenticationOptions options) {
|
||||
|
||||
Assert.notNull(options, "PcfAuthenticationOptions must not be null");
|
||||
|
||||
String instanceCert = options.getInstanceCertSupplier().get();
|
||||
String instanceKey = options.getInstanceKeySupplier().get();
|
||||
return AuthenticationSteps
|
||||
.fromSupplier(() -> getPcfLogin(options.getRole(), options.getClock(),
|
||||
instanceCert, instanceKey)) //
|
||||
.fromSupplier(() -> getPcfLogin(options.getRole(), options.getClock(), instanceCert, instanceKey)) //
|
||||
.login(AuthenticationUtil.getLoginPath(options.getPath()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public VaultToken login() throws VaultException {
|
||||
|
||||
Map<String, String> login = getPcfLogin(options.getRole(), options.getClock(),
|
||||
options.getInstanceCertSupplier().get(),
|
||||
options.getInstanceKeySupplier().get());
|
||||
Map<String, String> login = getPcfLogin(this.options.getRole(), this.options.getClock(),
|
||||
this.options.getInstanceCertSupplier().get(), this.options.getInstanceKeySupplier().get());
|
||||
|
||||
try {
|
||||
VaultResponse response = restOperations.postForObject(AuthenticationUtil.getLoginPath(options.getPath()),
|
||||
login, VaultResponse.class);
|
||||
VaultResponse response = this.restOperations
|
||||
.postForObject(AuthenticationUtil.getLoginPath(this.options.getPath()), login, VaultResponse.class);
|
||||
|
||||
Assert.state(response != null && response.getAuth() != null,
|
||||
"Auth field must not be null");
|
||||
Assert.state(response != null && response.getAuth() != null, "Auth field must not be null");
|
||||
|
||||
logger.debug("Login successful using PCF authentication");
|
||||
|
||||
@@ -132,8 +123,7 @@ public class PcfAuthentication
|
||||
return createAuthenticationSteps(this.options);
|
||||
}
|
||||
|
||||
private static Map<String, String> getPcfLogin(String role, Clock clock,
|
||||
String instanceCert, String instanceKey) {
|
||||
private static Map<String, String> getPcfLogin(String role, Clock clock, String instanceCert, String instanceKey) {
|
||||
|
||||
Assert.hasText(role, "Role must not be empty");
|
||||
|
||||
@@ -160,23 +150,20 @@ public class PcfAuthentication
|
||||
}
|
||||
}
|
||||
|
||||
private static String getMessage(String role, String signingTime,
|
||||
String instanceCertPem) {
|
||||
private static String getMessage(String role, String signingTime, String instanceCertPem) {
|
||||
return signingTime + instanceCertPem + role;
|
||||
}
|
||||
|
||||
private static String doSign(byte[] message, String instanceKeyPem)
|
||||
throws CryptoException {
|
||||
private static String doSign(byte[] message, String instanceKeyPem) throws CryptoException {
|
||||
|
||||
RSAPrivateKeySpec privateKey = PemObject.fromKey(instanceKeyPem).getRSAKeySpec();
|
||||
PSSSigner signer = new PSSSigner(new RSAEngine(), new SHA256Digest(),
|
||||
SALT_LENGTH);
|
||||
PSSSigner signer = new PSSSigner(new RSAEngine(), new SHA256Digest(), SALT_LENGTH);
|
||||
|
||||
signer.init(true, new RSAKeyParameters(true, privateKey.getModulus(),
|
||||
privateKey.getPrivateExponent()));
|
||||
signer.init(true, new RSAKeyParameters(true, privateKey.getModulus(), privateKey.getPrivateExponent()));
|
||||
signer.update(message, 0, message.length);
|
||||
|
||||
byte[] signature = signer.generateSignature();
|
||||
return Base64Utils.encodeToUrlSafeString(signature);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -63,8 +63,8 @@ public class PcfAuthenticationOptions {
|
||||
*/
|
||||
private final Supplier<String> instanceKeySupplier;
|
||||
|
||||
private PcfAuthenticationOptions(String path, String role, Clock clock,
|
||||
Supplier<String> instanceCertSupplier, Supplier<String> instanceKeySupplier) {
|
||||
private PcfAuthenticationOptions(String path, String role, Clock clock, Supplier<String> instanceCertSupplier,
|
||||
Supplier<String> instanceKeySupplier) {
|
||||
this.path = path;
|
||||
this.role = role;
|
||||
this.clock = clock;
|
||||
@@ -83,35 +83,35 @@ public class PcfAuthenticationOptions {
|
||||
* @return the path of the pcf authentication backend mount.
|
||||
*/
|
||||
public String getPath() {
|
||||
return path;
|
||||
return this.path;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return name of the role against which the login is being attempted.
|
||||
*/
|
||||
public String getRole() {
|
||||
return role;
|
||||
return this.role;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the {@link Clock}.
|
||||
*/
|
||||
public Clock getClock() {
|
||||
return clock;
|
||||
return this.clock;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the instance certificate {@link Supplier}.
|
||||
*/
|
||||
public Supplier<String> getInstanceCertSupplier() {
|
||||
return instanceCertSupplier;
|
||||
return this.instanceCertSupplier;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the instance key {@link Supplier}.
|
||||
*/
|
||||
public Supplier<String> getInstanceKeySupplier() {
|
||||
return instanceKeySupplier;
|
||||
return this.instanceKeySupplier;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -137,7 +137,6 @@ public class PcfAuthenticationOptions {
|
||||
|
||||
/**
|
||||
* Configure the mount path.
|
||||
*
|
||||
* @param path must not be empty or {@literal null}.
|
||||
* @return {@code this} {@link PcfAuthenticationOptionsBuilder}.
|
||||
* @see #DEFAULT_PCF_AUTHENTICATION_PATH
|
||||
@@ -152,9 +151,8 @@ public class PcfAuthenticationOptions {
|
||||
|
||||
/**
|
||||
* Configure the role.
|
||||
*
|
||||
* @param role name of the role against which the login is being attempted, must
|
||||
* not be {@literal null} or empty.
|
||||
* not be {@literal null} or empty.
|
||||
* @return {@code this} {@link PcfAuthenticationOptionsBuilder}.
|
||||
*/
|
||||
public PcfAuthenticationOptionsBuilder role(String role) {
|
||||
@@ -167,7 +165,6 @@ public class PcfAuthenticationOptions {
|
||||
|
||||
/**
|
||||
* Configure the {@link Clock}.
|
||||
*
|
||||
* @param clock must not be {@literal null}.
|
||||
* @return {@code this} {@link PcfAuthenticationOptionsBuilder}.
|
||||
*/
|
||||
@@ -181,16 +178,13 @@ public class PcfAuthenticationOptions {
|
||||
|
||||
/**
|
||||
* Configure the {@link Supplier} to obtain the instance certificate.
|
||||
*
|
||||
* @param instanceCertSupplier the supplier, must not be {@literal null}.
|
||||
* @return {@code this} {@link PcfAuthenticationOptionsBuilder}.
|
||||
* @see ResourceCredentialSupplier
|
||||
*/
|
||||
public PcfAuthenticationOptionsBuilder instanceCertificate(
|
||||
Supplier<String> instanceCertSupplier) {
|
||||
public PcfAuthenticationOptionsBuilder instanceCertificate(Supplier<String> instanceCertSupplier) {
|
||||
|
||||
Assert.notNull(instanceCertSupplier,
|
||||
"Instance certificate supplier must not be null");
|
||||
Assert.notNull(instanceCertSupplier, "Instance certificate supplier must not be null");
|
||||
|
||||
this.instanceCertSupplier = instanceCertSupplier;
|
||||
return this;
|
||||
@@ -198,16 +192,13 @@ public class PcfAuthenticationOptions {
|
||||
|
||||
/**
|
||||
* Configure the {@link Supplier} to obtain the instance key.
|
||||
*
|
||||
* @param instanceKeySupplier the supplier, must not be {@literal null}.
|
||||
* @return {@code this} {@link PcfAuthenticationOptionsBuilder}.
|
||||
* @see ResourceCredentialSupplier
|
||||
*/
|
||||
public PcfAuthenticationOptionsBuilder instanceKey(
|
||||
Supplier<String> instanceKeySupplier) {
|
||||
public PcfAuthenticationOptionsBuilder instanceKey(Supplier<String> instanceKeySupplier) {
|
||||
|
||||
Assert.notNull(instanceKeySupplier,
|
||||
"Instance certificate supplier must not be null");
|
||||
Assert.notNull(instanceKeySupplier, "Instance certificate supplier must not be null");
|
||||
|
||||
this.instanceKeySupplier = instanceKeySupplier;
|
||||
return this;
|
||||
@@ -219,31 +210,28 @@ public class PcfAuthenticationOptions {
|
||||
* Falls back to the instance certificate at {@code CF_INSTANCE_CERT} if
|
||||
* {@link #instanceCertificate(Supplier)} is not configured respective
|
||||
* {@code CF_INSTANCE_KEY} if {@link #instanceKey(Supplier)} is not configured.
|
||||
*
|
||||
* @return a new {@link PcfAuthenticationOptions}.
|
||||
* @throws IllegalStateException if {@link #instanceCertificate(Supplier)} or
|
||||
* {@link #instanceKey(Supplier)} are not set and the corresponding
|
||||
* environment variable {@code CF_INSTANCE_CERT} respective
|
||||
* {@code CF_INSTANCE_KEY} is not set.
|
||||
* {@link #instanceKey(Supplier)} are not set and the corresponding environment
|
||||
* variable {@code CF_INSTANCE_CERT} respective {@code CF_INSTANCE_KEY} is not
|
||||
* set.
|
||||
*/
|
||||
public PcfAuthenticationOptions build() {
|
||||
|
||||
Assert.notNull(role, "Role must not be null");
|
||||
Assert.notNull(this.role, "Role must not be null");
|
||||
|
||||
Supplier<String> instanceCertSupplier = this.instanceCertSupplier;
|
||||
|
||||
if (instanceCertSupplier == null) {
|
||||
instanceCertSupplier = new ResourceCredentialSupplier(
|
||||
resolveEnvVariable("CF_INSTANCE_CERT")).cached();
|
||||
instanceCertSupplier = new ResourceCredentialSupplier(resolveEnvVariable("CF_INSTANCE_CERT")).cached();
|
||||
}
|
||||
|
||||
Supplier<String> instanceKeySupplier = this.instanceKeySupplier;
|
||||
if (instanceKeySupplier == null) {
|
||||
instanceKeySupplier = new ResourceCredentialSupplier(
|
||||
resolveEnvVariable("CF_INSTANCE_KEY")).cached();
|
||||
instanceKeySupplier = new ResourceCredentialSupplier(resolveEnvVariable("CF_INSTANCE_KEY")).cached();
|
||||
}
|
||||
|
||||
return new PcfAuthenticationOptions(path, role, clock, instanceCertSupplier,
|
||||
return new PcfAuthenticationOptions(this.path, this.role, this.clock, instanceCertSupplier,
|
||||
instanceKeySupplier);
|
||||
}
|
||||
|
||||
@@ -252,11 +240,12 @@ public class PcfAuthenticationOptions {
|
||||
String value = System.getenv(name);
|
||||
|
||||
if (StringUtils.isEmpty(value)) {
|
||||
throw new IllegalStateException(
|
||||
String.format("Environment variable %s not set", name));
|
||||
throw new IllegalStateException(String.format("Environment variable %s not set", name));
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -80,14 +80,13 @@ import org.springframework.web.reactive.function.client.WebClientResponseExcepti
|
||||
* @see TaskScheduler
|
||||
* @see AuthenticationEventPublisher
|
||||
*/
|
||||
public class ReactiveLifecycleAwareSessionManager
|
||||
extends LifecycleAwareSessionManagerSupport
|
||||
public class ReactiveLifecycleAwareSessionManager extends LifecycleAwareSessionManagerSupport
|
||||
implements ReactiveSessionManager, DisposableBean {
|
||||
|
||||
private static final Mono<TokenWrapper> EMPTY = Mono.empty();
|
||||
|
||||
private static final Mono<TokenWrapper> TERMINATED = Mono
|
||||
.error(new TerminatedException());
|
||||
private static final Mono<TokenWrapper> TERMINATED = Mono.error(new TerminatedException());
|
||||
|
||||
/**
|
||||
* Client authentication mechanism. Used to obtain a {@link VaultToken} or
|
||||
* {@link LoginToken}.
|
||||
@@ -103,19 +102,17 @@ public class ReactiveLifecycleAwareSessionManager
|
||||
* The token state: Contains the currently valid token that identifies the Vault
|
||||
* session.
|
||||
*/
|
||||
private volatile AtomicReference<Mono<TokenWrapper>> token = new AtomicReference<>(
|
||||
EMPTY);
|
||||
private volatile AtomicReference<Mono<TokenWrapper>> token = new AtomicReference<>(EMPTY);
|
||||
|
||||
/**
|
||||
* Create a {@link ReactiveLifecycleAwareSessionManager} given
|
||||
* {@link ClientAuthentication}, {@link TaskScheduler} and {@link WebClient}.
|
||||
*
|
||||
* @param clientAuthentication must not be {@literal null}.
|
||||
* @param taskScheduler must not be {@literal null}.
|
||||
* @param webClient must not be {@literal null}.
|
||||
*/
|
||||
public ReactiveLifecycleAwareSessionManager(VaultTokenSupplier clientAuthentication,
|
||||
TaskScheduler taskScheduler, WebClient webClient) {
|
||||
public ReactiveLifecycleAwareSessionManager(VaultTokenSupplier clientAuthentication, TaskScheduler taskScheduler,
|
||||
WebClient webClient) {
|
||||
|
||||
super(taskScheduler);
|
||||
|
||||
@@ -130,15 +127,13 @@ public class ReactiveLifecycleAwareSessionManager
|
||||
/**
|
||||
* Create a {@link ReactiveLifecycleAwareSessionManager} given
|
||||
* {@link VaultTokenSupplier}, {@link TaskScheduler} and {@link WebClient}.
|
||||
*
|
||||
* @param clientAuthentication must not be {@literal null}.
|
||||
* @param taskScheduler must not be {@literal null}.
|
||||
* @param webClient must not be {@literal null}.
|
||||
* @param refreshTrigger must not be {@literal null}.
|
||||
*/
|
||||
public ReactiveLifecycleAwareSessionManager(VaultTokenSupplier clientAuthentication,
|
||||
TaskScheduler taskScheduler, WebClient webClient,
|
||||
RefreshTrigger refreshTrigger) {
|
||||
public ReactiveLifecycleAwareSessionManager(VaultTokenSupplier clientAuthentication, TaskScheduler taskScheduler,
|
||||
WebClient webClient, RefreshTrigger refreshTrigger) {
|
||||
|
||||
super(taskScheduler, refreshTrigger);
|
||||
|
||||
@@ -162,7 +157,6 @@ public class ReactiveLifecycleAwareSessionManager
|
||||
|
||||
/**
|
||||
* Revoke a {@link VaultToken} now and block execution until revocation completes.
|
||||
*
|
||||
* @param tokenMono
|
||||
*/
|
||||
protected void revokeNow(Mono<TokenWrapper> tokenMono) {
|
||||
@@ -171,32 +165,29 @@ public class ReactiveLifecycleAwareSessionManager
|
||||
|
||||
protected Mono<Void> doRevoke(Mono<TokenWrapper> tokenMono) {
|
||||
|
||||
return tokenMono.filter(TokenWrapper::isRevocable).map(TokenWrapper::getToken)
|
||||
.flatMap(this::revoke);
|
||||
return tokenMono.filter(TokenWrapper::isRevocable).map(TokenWrapper::getToken).flatMap(this::revoke);
|
||||
}
|
||||
|
||||
/**
|
||||
* Revoke a {@link VaultToken}.
|
||||
*
|
||||
* @param token the token to revoke, must not be {@literal null}.
|
||||
*/
|
||||
protected Mono<Void> revoke(VaultToken token) {
|
||||
|
||||
return webClient.post().uri("auth/token/revoke-self").headers(httpHeaders -> {
|
||||
return this.webClient.post().uri("auth/token/revoke-self").headers(httpHeaders -> {
|
||||
httpHeaders.addAll(VaultHttpHeaders.from(token));
|
||||
}).retrieve().bodyToMono(String.class)
|
||||
.doOnSubscribe(
|
||||
ignore -> dispatch(new BeforeLoginTokenRevocationEvent(token)))
|
||||
.doOnSubscribe(ignore -> dispatch(new BeforeLoginTokenRevocationEvent(token)))
|
||||
.doOnNext(ignore -> dispatch(new AfterLoginTokenRevocationEvent(token)))
|
||||
.onErrorResume(WebClientResponseException.class, e -> {
|
||||
|
||||
logger.warn(format("Could not revoke token", e));
|
||||
this.logger.warn(format("Could not revoke token", e));
|
||||
dispatch(new LoginTokenRevocationFailedEvent(token, e));
|
||||
|
||||
return Mono.empty();
|
||||
}).onErrorResume(Exception.class, e -> {
|
||||
|
||||
logger.warn("Could not revoke token", e);
|
||||
this.logger.warn("Could not revoke token", e);
|
||||
dispatch(new LoginTokenRevocationFailedEvent(token, e));
|
||||
|
||||
return Mono.empty();
|
||||
@@ -208,14 +199,13 @@ public class ReactiveLifecycleAwareSessionManager
|
||||
* token was obtained before, it uses self-renewal to renew the current token.
|
||||
* Client-side errors (like permission denied) indicate the token cannot be renewed
|
||||
* because it's expired or simply not found.
|
||||
*
|
||||
* @return the {@link VaultToken} if the refresh was successful or a new token was
|
||||
* obtained. {@link Mono#empty()} if a new the token expired or
|
||||
* {@link Mono#error(Throwable)} if refresh failed.
|
||||
*/
|
||||
public Mono<VaultToken> renewToken() {
|
||||
|
||||
logger.info("Renewing token");
|
||||
this.logger.info("Renewing token");
|
||||
|
||||
Mono<TokenWrapper> tokenWrapper = this.token.get();
|
||||
|
||||
@@ -234,38 +224,33 @@ public class ReactiveLifecycleAwareSessionManager
|
||||
|
||||
return doRenew(wrapper).onErrorResume(RuntimeException.class, e -> {
|
||||
|
||||
VaultTokenRenewalException exception = new VaultTokenRenewalException(
|
||||
format("Cannot renew token", e), e);
|
||||
VaultTokenRenewalException exception = new VaultTokenRenewalException(format("Cannot renew token", e), e);
|
||||
|
||||
if (getLeaseStrategy().shouldDrop(exception)) {
|
||||
dropCurrentToken();
|
||||
}
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(exception.getMessage(), exception);
|
||||
if (this.logger.isDebugEnabled()) {
|
||||
this.logger.debug(exception.getMessage(), exception);
|
||||
}
|
||||
else {
|
||||
logger.warn(exception.getMessage());
|
||||
this.logger.warn(exception.getMessage());
|
||||
}
|
||||
|
||||
|
||||
dispatch(new LoginTokenRenewalFailedEvent(wrapper.getToken(), exception));
|
||||
return EMPTY;
|
||||
}
|
||||
return EMPTY;
|
||||
}
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
private Mono<TokenWrapper> doRenew(TokenWrapper tokenWrapper) {
|
||||
|
||||
Mono<VaultResponse> exchange = webClient.post().uri("auth/token/renew-self")
|
||||
.headers(httpHeaders -> httpHeaders
|
||||
.putAll(VaultHttpHeaders.from(tokenWrapper.token)))
|
||||
.retrieve().bodyToMono(VaultResponse.class);
|
||||
Mono<VaultResponse> exchange = this.webClient.post().uri("auth/token/renew-self")
|
||||
.headers(httpHeaders -> httpHeaders.putAll(VaultHttpHeaders.from(tokenWrapper.token))).retrieve()
|
||||
.bodyToMono(VaultResponse.class);
|
||||
|
||||
return exchange
|
||||
.doOnSubscribe(ignore -> dispatch(
|
||||
new BeforeLoginTokenRenewedEvent(tokenWrapper.getToken())))
|
||||
return exchange.doOnSubscribe(ignore -> dispatch(new BeforeLoginTokenRenewedEvent(tokenWrapper.getToken())))
|
||||
.handle((response, sink) -> {
|
||||
|
||||
LoginToken renewed = LoginTokenUtil.from(response.getRequiredAuth());
|
||||
@@ -276,17 +261,15 @@ public class ReactiveLifecycleAwareSessionManager
|
||||
return;
|
||||
}
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
if (this.logger.isDebugEnabled()) {
|
||||
|
||||
Duration validTtlThreshold = getRefreshTrigger()
|
||||
.getValidTtlThreshold(renewed);
|
||||
logger.info(String.format(
|
||||
"Token TTL (%s) exceeded validity TTL threshold (%s). Dropping token.",
|
||||
renewed.getLeaseDuration(), validTtlThreshold));
|
||||
Duration validTtlThreshold = getRefreshTrigger().getValidTtlThreshold(renewed);
|
||||
this.logger.info(
|
||||
String.format("Token TTL (%s) exceeded validity TTL threshold (%s). Dropping token.",
|
||||
renewed.getLeaseDuration(), validTtlThreshold));
|
||||
}
|
||||
else {
|
||||
logger.info(
|
||||
"Token TTL exceeded validity TTL threshold. Dropping token.");
|
||||
this.logger.info("Token TTL exceeded validity TTL threshold. Dropping token.");
|
||||
}
|
||||
|
||||
dropCurrentToken();
|
||||
@@ -310,10 +293,9 @@ public class ReactiveLifecycleAwareSessionManager
|
||||
|
||||
if (tokenWrapper == EMPTY) {
|
||||
|
||||
Mono<TokenWrapper> obtainToken = clientAuthentication.getVaultToken()
|
||||
.flatMap(this::doSelfLookup) //
|
||||
Mono<TokenWrapper> obtainToken = this.clientAuthentication.getVaultToken().flatMap(this::doSelfLookup) //
|
||||
.onErrorMap(it -> {
|
||||
dispatch(new LoginFailedEvent(clientAuthentication, it));
|
||||
dispatch(new LoginFailedEvent(this.clientAuthentication, it));
|
||||
return it;
|
||||
}).doOnNext(it -> {
|
||||
|
||||
@@ -334,16 +316,13 @@ public class ReactiveLifecycleAwareSessionManager
|
||||
|
||||
TokenWrapper wrapper = new TokenWrapper(token, token instanceof LoginToken);
|
||||
|
||||
if (isTokenSelfLookupEnabled()
|
||||
&& !ClassUtils.isAssignableValue(LoginToken.class, token)) {
|
||||
if (isTokenSelfLookupEnabled() && !ClassUtils.isAssignableValue(LoginToken.class, token)) {
|
||||
|
||||
Mono<VaultToken> loginTokenMono = augmentWithSelfLookup(this.webClient,
|
||||
token);
|
||||
Mono<VaultToken> loginTokenMono = augmentWithSelfLookup(this.webClient, token);
|
||||
|
||||
return loginTokenMono.onErrorResume(e -> {
|
||||
|
||||
logger.warn(String.format("Cannot enhance VaultToken to a LoginToken: %s",
|
||||
e.getMessage()));
|
||||
this.logger.warn(String.format("Cannot enhance VaultToken to a LoginToken: %s", e.getMessage()));
|
||||
dispatch(new AuthenticationErrorEvent(token, e));
|
||||
return Mono.just(token);
|
||||
}).map(it -> new TokenWrapper(it, false));
|
||||
@@ -362,35 +341,32 @@ public class ReactiveLifecycleAwareSessionManager
|
||||
.filter(it -> {
|
||||
|
||||
LoginToken loginToken = (LoginToken) it;
|
||||
return !loginToken.getLeaseDuration().isZero()
|
||||
&& loginToken.isRenewable();
|
||||
return !loginToken.getLeaseDuration().isZero() && loginToken.isRenewable();
|
||||
}).isPresent();
|
||||
}
|
||||
|
||||
private void scheduleRenewal(VaultToken token) {
|
||||
|
||||
logger.info("Scheduling Token renewal");
|
||||
this.logger.info("Scheduling Token renewal");
|
||||
|
||||
Runnable task = () -> {
|
||||
try {
|
||||
|
||||
Mono<TokenWrapper> tokenWrapper = ReactiveLifecycleAwareSessionManager.this.token
|
||||
.get();
|
||||
Mono<TokenWrapper> tokenWrapper = ReactiveLifecycleAwareSessionManager.this.token.get();
|
||||
|
||||
if (tokenWrapper == Mono.<TokenWrapper> empty()
|
||||
|| tokenWrapper == TERMINATED) {
|
||||
if (tokenWrapper == Mono.<TokenWrapper>empty() || tokenWrapper == TERMINATED) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isTokenRenewable(token)) {
|
||||
renewToken().subscribe(this::scheduleRenewal, e -> {
|
||||
logger.error("Cannot renew VaultToken", e);
|
||||
this.logger.error("Cannot renew VaultToken", e);
|
||||
dispatch(new LoginTokenRenewalFailedEvent(token, e));
|
||||
});
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
logger.error("Cannot renew VaultToken", e);
|
||||
this.logger.error("Cannot renew VaultToken", e);
|
||||
dispatch(new LoginTokenRenewalFailedEvent(token, e));
|
||||
}
|
||||
};
|
||||
@@ -400,12 +376,10 @@ public class ReactiveLifecycleAwareSessionManager
|
||||
|
||||
private OneShotTrigger createTrigger(VaultToken token) {
|
||||
|
||||
return new OneShotTrigger(
|
||||
getRefreshTrigger().nextExecutionTime((LoginToken) token));
|
||||
return new OneShotTrigger(getRefreshTrigger().nextExecutionTime((LoginToken) token));
|
||||
}
|
||||
|
||||
private static Mono<VaultToken> augmentWithSelfLookup(WebClient webClient,
|
||||
VaultToken token) {
|
||||
private static Mono<VaultToken> augmentWithSelfLookup(WebClient webClient, VaultToken token) {
|
||||
|
||||
Mono<Map<String, Object>> data = lookupSelf(webClient, token);
|
||||
|
||||
@@ -415,27 +389,23 @@ public class ReactiveLifecycleAwareSessionManager
|
||||
Number ttl = (Number) it.get("ttl");
|
||||
|
||||
if (renewable != null && renewable) {
|
||||
return LoginToken.renewable(token.toCharArray(),
|
||||
LoginTokenAdapter.getLeaseDuration(ttl));
|
||||
return LoginToken.renewable(token.toCharArray(), LoginTokenAdapter.getLeaseDuration(ttl));
|
||||
}
|
||||
|
||||
return LoginToken.of(token.toCharArray(),
|
||||
LoginTokenAdapter.getLeaseDuration(ttl));
|
||||
return LoginToken.of(token.toCharArray(), LoginTokenAdapter.getLeaseDuration(ttl));
|
||||
});
|
||||
}
|
||||
|
||||
private static Mono<Map<String, Object>> lookupSelf(WebClient webClient,
|
||||
VaultToken token) {
|
||||
private static Mono<Map<String, Object>> lookupSelf(WebClient webClient, VaultToken token) {
|
||||
|
||||
return webClient.get().uri("auth/token/lookup-self")
|
||||
.headers(httpHeaders -> httpHeaders.putAll(VaultHttpHeaders.from(token)))
|
||||
.retrieve().bodyToMono(VaultResponse.class).map(it -> {
|
||||
.headers(httpHeaders -> httpHeaders.putAll(VaultHttpHeaders.from(token))).retrieve()
|
||||
.bodyToMono(VaultResponse.class).map(it -> {
|
||||
|
||||
Assert.state(it.getData() != null, "Token response is null");
|
||||
return it.getRequiredData();
|
||||
}).onErrorMap(WebClientResponseException.class, e -> {
|
||||
return new VaultTokenLookupException(format("Token self-lookup", e),
|
||||
e);
|
||||
return new VaultTokenLookupException(format("Token self-lookup", e), e);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -444,8 +414,7 @@ public class ReactiveLifecycleAwareSessionManager
|
||||
if (e instanceof WebClientResponseException) {
|
||||
|
||||
WebClientResponseException wce = (WebClientResponseException) e;
|
||||
return String.format("%s: Status %s %s %s", message, wce.getRawStatusCode(),
|
||||
wce.getStatusText(),
|
||||
return String.format("%s: Status %s %s %s", message, wce.getRawStatusCode(), wce.getStatusText(),
|
||||
VaultResponses.getError(wce.getResponseBodyAsString()));
|
||||
}
|
||||
|
||||
@@ -461,6 +430,7 @@ public class ReactiveLifecycleAwareSessionManager
|
||||
protected static class TokenWrapper {
|
||||
|
||||
private final VaultToken token;
|
||||
|
||||
private final boolean revocable;
|
||||
|
||||
public TokenWrapper(VaultToken token, boolean revocable) {
|
||||
@@ -475,6 +445,7 @@ public class ReactiveLifecycleAwareSessionManager
|
||||
public boolean isRevocable() {
|
||||
return this.revocable;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -486,5 +457,7 @@ public class ReactiveLifecycleAwareSessionManager
|
||||
super("Session manager terminated");
|
||||
setStackTrace(new StackTraceElement[0]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -37,10 +37,10 @@ public interface ReactiveSessionManager extends VaultTokenSupplier {
|
||||
|
||||
/**
|
||||
* Obtain a session token.
|
||||
*
|
||||
* @return a session token.
|
||||
*/
|
||||
default Mono<VaultToken> getSessionToken() {
|
||||
return getVaultToken();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -40,7 +40,6 @@ public class ResourceCredentialSupplier implements CredentialSupplier {
|
||||
/**
|
||||
* Create a new {@link ResourceCredentialSupplier} {@link ResourceCredentialSupplier}
|
||||
* from a {@code path}.
|
||||
*
|
||||
* @param path path to the file holding the credential.
|
||||
* @throws IllegalArgumentException if the{@code path} does not exist.
|
||||
*/
|
||||
@@ -51,7 +50,6 @@ public class ResourceCredentialSupplier implements CredentialSupplier {
|
||||
/**
|
||||
* Create a new {@link ResourceCredentialSupplier} {@link ResourceCredentialSupplier}
|
||||
* from a {@link File} handle.
|
||||
*
|
||||
* @param file path to the file holding the credential.
|
||||
* @throws IllegalArgumentException if the{@code path} does not exist.
|
||||
*/
|
||||
@@ -62,14 +60,12 @@ public class ResourceCredentialSupplier implements CredentialSupplier {
|
||||
/**
|
||||
* Create a new {@link ResourceCredentialSupplier} {@link ResourceCredentialSupplier}
|
||||
* from a {@link Resource} handle.
|
||||
*
|
||||
* @param resource resource pointing to the resource holding the credential.
|
||||
* @throws IllegalArgumentException if the {@link Resource} does not exist.
|
||||
*/
|
||||
public ResourceCredentialSupplier(Resource resource) {
|
||||
|
||||
Assert.isTrue(resource.exists(),
|
||||
() -> String.format("Resource %s does not exist", resource));
|
||||
Assert.isTrue(resource.exists(), () -> String.format("Resource %s does not exist", resource));
|
||||
|
||||
this.resource = resource;
|
||||
}
|
||||
@@ -81,15 +77,12 @@ public class ResourceCredentialSupplier implements CredentialSupplier {
|
||||
return new String(readToken(this.resource), StandardCharsets.US_ASCII);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new VaultException(
|
||||
String.format("Credential retrieval from %s failed", this.resource),
|
||||
e);
|
||||
throw new VaultException(String.format("Credential retrieval from %s failed", this.resource), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the token from {@link Resource}.
|
||||
*
|
||||
* @param resource the resource to read from, must not be {@literal null}.
|
||||
* @return the new byte array that has been copied to (possibly empty).
|
||||
* @throws IOException in case of I/O errors.
|
||||
@@ -102,4 +95,5 @@ public class ResourceCredentialSupplier implements CredentialSupplier {
|
||||
return StreamUtils.copyToByteArray(is);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -34,8 +34,8 @@ public interface SessionManager {
|
||||
|
||||
/**
|
||||
* Obtain a session token.
|
||||
*
|
||||
* @return a session token.
|
||||
*/
|
||||
VaultToken getSessionToken();
|
||||
|
||||
}
|
||||
|
||||
@@ -34,7 +34,6 @@ class Sha256 {
|
||||
|
||||
/**
|
||||
* Generates a hex-encoded SHA256 checksum from the supplied {@code content}.
|
||||
*
|
||||
* @param content must not be {@literal null} and not empty.
|
||||
* @return hex-encoded SHA256 checksum
|
||||
*/
|
||||
@@ -50,12 +49,10 @@ class Sha256 {
|
||||
/**
|
||||
* Get a MessageDigest instance for the given algorithm. Throws an
|
||||
* IllegalArgumentException if <i>algorithm</i> is unknown
|
||||
*
|
||||
* @return MessageDigest instance
|
||||
* @throws IllegalArgumentException if NoSuchAlgorithmException is thrown
|
||||
*/
|
||||
private static MessageDigest getMessageDigest(String algorithm)
|
||||
throws IllegalArgumentException {
|
||||
private static MessageDigest getMessageDigest(String algorithm) throws IllegalArgumentException {
|
||||
try {
|
||||
return MessageDigest.getInstance(algorithm);
|
||||
}
|
||||
@@ -74,4 +71,5 @@ class Sha256 {
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -40,7 +40,6 @@ public class SimpleSessionManager implements SessionManager {
|
||||
|
||||
/**
|
||||
* Create a new {@link SimpleSessionManager} using a {@link ClientAuthentication}.
|
||||
*
|
||||
* @param clientAuthentication must not be {@literal null}.
|
||||
*/
|
||||
public SimpleSessionManager(ClientAuthentication clientAuthentication) {
|
||||
@@ -53,15 +52,15 @@ public class SimpleSessionManager implements SessionManager {
|
||||
@Override
|
||||
public VaultToken getSessionToken() {
|
||||
|
||||
if (!token.isPresent()) {
|
||||
synchronized (lock) {
|
||||
if (!token.isPresent()) {
|
||||
token = Optional.of(clientAuthentication.login());
|
||||
if (!this.token.isPresent()) {
|
||||
synchronized (this.lock) {
|
||||
if (!this.token.isPresent()) {
|
||||
this.token = Optional.of(this.clientAuthentication.login());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return token
|
||||
.orElseThrow(() -> new IllegalStateException("Cannot obtain VaultToken"));
|
||||
return this.token.orElseThrow(() -> new IllegalStateException("Cannot obtain VaultToken"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -30,7 +30,6 @@ public class StaticUserId implements AppIdUserIdMechanism {
|
||||
|
||||
/**
|
||||
* Create a new {@link StaticUserId} for a given {@code userId}.
|
||||
*
|
||||
* @param userId must not be empty or {@literal null}.
|
||||
*/
|
||||
public StaticUserId(String userId) {
|
||||
@@ -41,6 +40,7 @@ public class StaticUserId implements AppIdUserIdMechanism {
|
||||
|
||||
@Override
|
||||
public String createUserId() {
|
||||
return userId;
|
||||
return this.userId;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -30,14 +30,12 @@ import static org.springframework.vault.authentication.AuthenticationSteps.HttpR
|
||||
* @see VaultToken
|
||||
* @see <a href="https://www.vaultproject.io/docs/auth/token.html">Auth Backend: Token</a>
|
||||
*/
|
||||
public class TokenAuthentication
|
||||
implements ClientAuthentication, AuthenticationStepsFactory {
|
||||
public class TokenAuthentication implements ClientAuthentication, AuthenticationStepsFactory {
|
||||
|
||||
private final VaultToken token;
|
||||
|
||||
/**
|
||||
* Create a new {@link TokenAuthentication} with a static {@code token}.
|
||||
*
|
||||
* @param token the Vault token, must not be empty or {@literal null}.
|
||||
*/
|
||||
public TokenAuthentication(String token) {
|
||||
@@ -49,7 +47,6 @@ public class TokenAuthentication
|
||||
|
||||
/**
|
||||
* Create a new {@link TokenAuthentication} with a static {@code token}.
|
||||
*
|
||||
* @param token the Vault token, must not be {@literal null}.
|
||||
*/
|
||||
public TokenAuthentication(VaultToken token) {
|
||||
@@ -62,27 +59,24 @@ public class TokenAuthentication
|
||||
/**
|
||||
* Creates a {@link AuthenticationSteps} for token authentication given
|
||||
* {@link VaultToken}.
|
||||
*
|
||||
* @param token must not be {@literal null}.
|
||||
* @param selfLookup {@literal true} to perform a self-lookup using the given
|
||||
* {@link VaultToken}. Self-lookup will create a {@link LoginToken} and provide
|
||||
* renewability and TTL.
|
||||
* {@link VaultToken}. Self-lookup will create a {@link LoginToken} and provide
|
||||
* renewability and TTL.
|
||||
* @return {@link AuthenticationSteps} for token authentication.
|
||||
* @since 2.0
|
||||
*/
|
||||
public static AuthenticationSteps createAuthenticationSteps(VaultToken token,
|
||||
boolean selfLookup) {
|
||||
public static AuthenticationSteps createAuthenticationSteps(VaultToken token, boolean selfLookup) {
|
||||
|
||||
Assert.notNull(token, "VaultToken must not be null");
|
||||
|
||||
if (selfLookup) {
|
||||
|
||||
HttpRequest<VaultResponse> httpRequest = get("auth/token/lookup-self")
|
||||
.with(VaultHttpHeaders.from(token)).as(VaultResponse.class);
|
||||
HttpRequest<VaultResponse> httpRequest = get("auth/token/lookup-self").with(VaultHttpHeaders.from(token))
|
||||
.as(VaultResponse.class);
|
||||
|
||||
return AuthenticationSteps.fromHttpRequest(httpRequest)
|
||||
.login(response -> LoginTokenUtil.from(token.toCharArray(),
|
||||
response.getRequiredData()));
|
||||
.login(response -> LoginTokenUtil.from(token.toCharArray(), response.getRequiredData()));
|
||||
}
|
||||
|
||||
return AuthenticationSteps.just(token);
|
||||
@@ -97,4 +91,5 @@ public class TokenAuthentication
|
||||
public AuthenticationSteps getAuthenticationSteps() {
|
||||
return createAuthenticationSteps(this.token, false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -40,9 +40,7 @@ public enum UnwrappingEndpoints {
|
||||
|
||||
@Override
|
||||
VaultResponse unwrap(VaultResponse vaultResponse) {
|
||||
return VaultResponses.unwrap(
|
||||
(String) vaultResponse.getRequiredData().get("response"),
|
||||
VaultResponse.class);
|
||||
return VaultResponses.unwrap((String) vaultResponse.getRequiredData().get("response"), VaultResponse.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -75,14 +73,12 @@ public enum UnwrappingEndpoints {
|
||||
|
||||
/**
|
||||
* Retrieve the path of the unwrapping endpoint.
|
||||
*
|
||||
* @return the unwrapping endpoint path.
|
||||
*/
|
||||
abstract String getPath();
|
||||
|
||||
/**
|
||||
* Unwrap the response data from {@link VaultResponses}.
|
||||
*
|
||||
* @param response the raw response entity.
|
||||
* @return unwrapped {@link VaultResponse}.
|
||||
*/
|
||||
@@ -90,8 +86,8 @@ public enum UnwrappingEndpoints {
|
||||
|
||||
/**
|
||||
* Unwrapping request {@link HttpMethod method}.
|
||||
*
|
||||
* @return the unwrapping request {@link HttpMethod method}.
|
||||
*/
|
||||
abstract HttpMethod getUnwrapRequestMethod();
|
||||
|
||||
}
|
||||
|
||||
@@ -29,7 +29,6 @@ public class VaultLoginException extends VaultException {
|
||||
|
||||
/**
|
||||
* Create a {@code VaultLoginException} with the specified detail message.
|
||||
*
|
||||
* @param msg the detail message.
|
||||
*/
|
||||
public VaultLoginException(String msg) {
|
||||
@@ -39,7 +38,6 @@ public class VaultLoginException extends VaultException {
|
||||
/**
|
||||
* Create a {@code VaultLoginException} with the specified detail message and nested
|
||||
* exception.
|
||||
*
|
||||
* @param msg the detail message.
|
||||
* @param cause the nested exception.
|
||||
*/
|
||||
@@ -50,7 +48,6 @@ public class VaultLoginException extends VaultException {
|
||||
/**
|
||||
* Create a {@link VaultLoginException} given {@code authMethod} and a
|
||||
* {@link Throwable cause}.
|
||||
*
|
||||
* @param authMethod must not be {@literal null}.
|
||||
* @param cause must not be {@literal null}.
|
||||
* @return the {@link VaultLoginException}.
|
||||
@@ -59,12 +56,12 @@ public class VaultLoginException extends VaultException {
|
||||
|
||||
if (cause instanceof RestClientResponseException) {
|
||||
|
||||
String response = ((RestClientResponseException) cause)
|
||||
.getResponseBodyAsString();
|
||||
return new VaultLoginException(String.format("Cannot login using %s: %s",
|
||||
authMethod, VaultResponses.getError(response)), cause);
|
||||
String response = ((RestClientResponseException) cause).getResponseBodyAsString();
|
||||
return new VaultLoginException(
|
||||
String.format("Cannot login using %s: %s", authMethod, VaultResponses.getError(response)), cause);
|
||||
}
|
||||
|
||||
return new VaultLoginException(String.format("Cannot login using %s", cause));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,7 +27,6 @@ public abstract class VaultSessionManagerException extends VaultException {
|
||||
|
||||
/**
|
||||
* Create a {@code VaultSessionManagerException} with the specified detail message.
|
||||
*
|
||||
* @param msg the detail message.
|
||||
*/
|
||||
public VaultSessionManagerException(String msg) {
|
||||
@@ -37,11 +36,11 @@ public abstract class VaultSessionManagerException extends VaultException {
|
||||
/**
|
||||
* Create a {@code VaultSessionManagerException} with the specified detail message and
|
||||
* nested exception.
|
||||
*
|
||||
* @param msg the detail message.
|
||||
* @param cause the nested exception.
|
||||
*/
|
||||
public VaultSessionManagerException(String msg, Throwable cause) {
|
||||
super(msg, cause);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,7 +27,6 @@ public class VaultTokenLookupException extends VaultException {
|
||||
|
||||
/**
|
||||
* Create a {@code VaultTokenLookupException} with the specified detail message.
|
||||
*
|
||||
* @param msg the detail message.
|
||||
*/
|
||||
public VaultTokenLookupException(String msg) {
|
||||
@@ -37,7 +36,6 @@ public class VaultTokenLookupException extends VaultException {
|
||||
/**
|
||||
* Create a {@code VaultTokenLookupException} with the specified detail message and
|
||||
* nested exception.
|
||||
*
|
||||
* @param msg the detail message.
|
||||
* @param cause the nested exception.
|
||||
* @since 2.1
|
||||
@@ -45,4 +43,5 @@ public class VaultTokenLookupException extends VaultException {
|
||||
public VaultTokenLookupException(String msg, Throwable cause) {
|
||||
super(msg, cause);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -25,7 +25,6 @@ public class VaultTokenRenewalException extends VaultSessionManagerException {
|
||||
|
||||
/**
|
||||
* Create a {@code VaultTokenRenewalException} with the specified detail message.
|
||||
*
|
||||
* @param msg the detail message.
|
||||
*/
|
||||
public VaultTokenRenewalException(String msg) {
|
||||
@@ -35,11 +34,11 @@ public class VaultTokenRenewalException extends VaultSessionManagerException {
|
||||
/**
|
||||
* Create a {@code VaultTokenRenewalException} with the specified detail message and
|
||||
* nested exception.
|
||||
*
|
||||
* @param msg the detail message.
|
||||
* @param cause the nested exception.
|
||||
*/
|
||||
public VaultTokenRenewalException(String msg, Throwable cause) {
|
||||
super(msg, cause);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -33,8 +33,8 @@ public interface VaultTokenSupplier {
|
||||
/**
|
||||
* Return a {@link VaultToken}. This can declare a Vault login flow to obtain a
|
||||
* {@link VaultToken token}.
|
||||
*
|
||||
* @return a {@link Mono} with the {@link VaultToken}.
|
||||
*/
|
||||
Mono<VaultToken> getVaultToken();
|
||||
|
||||
}
|
||||
|
||||
@@ -31,11 +31,11 @@ public class AfterLoginEvent extends AuthenticationEvent {
|
||||
|
||||
/**
|
||||
* Create a new {@link AfterLoginEvent} given {@link VaultToken}.
|
||||
*
|
||||
* @param source the {@link VaultToken} associated with this event, must not be
|
||||
* {@literal null}.
|
||||
* {@literal null}.
|
||||
*/
|
||||
public AfterLoginEvent(VaultToken source) {
|
||||
super(source);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -31,11 +31,11 @@ public class AfterLoginTokenRenewedEvent extends AuthenticationEvent {
|
||||
|
||||
/**
|
||||
* Create a new {@link AfterLoginTokenRenewedEvent} given {@link VaultToken}.
|
||||
*
|
||||
* @param source the {@link VaultToken} associated with this event, must not be
|
||||
* {@literal null}.
|
||||
* {@literal null}.
|
||||
*/
|
||||
public AfterLoginTokenRenewedEvent(VaultToken source) {
|
||||
super(source);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -31,11 +31,11 @@ public class AfterLoginTokenRevocationEvent extends AuthenticationEvent {
|
||||
|
||||
/**
|
||||
* Create a new {@link AfterLoginTokenRevocationEvent} given {@link VaultToken}.
|
||||
*
|
||||
* @param source the {@link VaultToken} associated with this event, must not be
|
||||
* {@literal null}.
|
||||
* {@literal null}.
|
||||
*/
|
||||
public AfterLoginTokenRevocationEvent(VaultToken source) {
|
||||
super(source);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -37,7 +37,6 @@ public class AuthenticationErrorEvent extends ApplicationEvent {
|
||||
/**
|
||||
* Create a new {@link AuthenticationErrorEvent} given {@code source} and
|
||||
* {@link Exception}.
|
||||
*
|
||||
* @param source must not be {@literal null}.
|
||||
* @param exception must not be {@literal null}.
|
||||
*/
|
||||
@@ -47,6 +46,7 @@ public class AuthenticationErrorEvent extends ApplicationEvent {
|
||||
}
|
||||
|
||||
public Throwable getException() {
|
||||
return exception;
|
||||
return this.exception;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -28,8 +28,8 @@ public interface AuthenticationErrorListener {
|
||||
|
||||
/**
|
||||
* Callback for a {@link AuthenticationErrorEvent}.
|
||||
*
|
||||
* @param authenticationEvent the event object, must not be {@literal null}.
|
||||
*/
|
||||
void onAuthenticationError(AuthenticationErrorEvent authenticationEvent);
|
||||
|
||||
}
|
||||
|
||||
@@ -31,9 +31,8 @@ public abstract class AuthenticationEvent extends ApplicationEvent {
|
||||
|
||||
/**
|
||||
* Create a new {@link AuthenticationEvent} given {@link VaultToken}.
|
||||
*
|
||||
* @param source the {@link VaultToken} associated with this event, must not be
|
||||
* {@literal null}.
|
||||
* {@literal null}.
|
||||
*/
|
||||
protected AuthenticationEvent(VaultToken source) {
|
||||
super(source);
|
||||
@@ -43,4 +42,5 @@ public abstract class AuthenticationEvent extends ApplicationEvent {
|
||||
public VaultToken getSource() {
|
||||
return (VaultToken) super.getSource();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,8 +27,8 @@ public interface AuthenticationListener {
|
||||
|
||||
/**
|
||||
* Callback for a {@link AuthenticationEvent}
|
||||
*
|
||||
* @param leaseEvent the event object, must not be {@literal null}.
|
||||
*/
|
||||
void onAuthenticationEvent(AuthenticationEvent leaseEvent);
|
||||
|
||||
}
|
||||
|
||||
@@ -31,11 +31,11 @@ public class BeforeLoginTokenRenewedEvent extends AuthenticationEvent {
|
||||
|
||||
/**
|
||||
* Create a new {@link BeforeLoginTokenRenewedEvent} given {@link VaultToken}.
|
||||
*
|
||||
* @param source the {@link VaultToken} associated with this event, must not be
|
||||
* {@literal null}.
|
||||
* {@literal null}.
|
||||
*/
|
||||
public BeforeLoginTokenRenewedEvent(VaultToken source) {
|
||||
super(source);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -31,11 +31,11 @@ public class BeforeLoginTokenRevocationEvent extends AuthenticationEvent {
|
||||
|
||||
/**
|
||||
* Create a new {@link BeforeLoginTokenRevocationEvent} given {@link VaultToken}.
|
||||
*
|
||||
* @param source the {@link VaultToken} associated with this event, must not be
|
||||
* {@literal null}.
|
||||
* {@literal null}.
|
||||
*/
|
||||
public BeforeLoginTokenRevocationEvent(VaultToken source) {
|
||||
super(source);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -36,12 +36,12 @@ public class LoginFailedEvent extends AuthenticationErrorEvent {
|
||||
|
||||
/**
|
||||
* Create a new {@link LoginFailedEvent} given {@link Exception}.
|
||||
*
|
||||
* @param source the {@link ClientAuthentication} or {@link VaultTokenSupplier}
|
||||
* associated with this event, must not be {@literal null}.
|
||||
* associated with this event, must not be {@literal null}.
|
||||
* @param exception must not be {@literal null}.
|
||||
*/
|
||||
public LoginFailedEvent(Object source, Throwable exception) {
|
||||
super(source, exception);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -31,11 +31,11 @@ public class LoginTokenExpiredEvent extends AuthenticationEvent {
|
||||
|
||||
/**
|
||||
* Create a new {@link LoginTokenExpiredEvent} given {@link VaultToken}.
|
||||
*
|
||||
* @param source the {@link VaultToken} associated with this event, must not be
|
||||
* {@literal null}.
|
||||
* {@literal null}.
|
||||
*/
|
||||
public LoginTokenExpiredEvent(VaultToken source) {
|
||||
super(source);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -32,9 +32,8 @@ public class LoginTokenRenewalFailedEvent extends AuthenticationErrorEvent {
|
||||
/**
|
||||
* Create a new {@link LoginTokenRenewalFailedEvent} given {@link VaultToken} and
|
||||
* {@link Exception}.
|
||||
*
|
||||
* @param source the {@link VaultToken} associated with this event, must not be
|
||||
* {@literal null}.
|
||||
* {@literal null}.
|
||||
* @param exception must not be {@literal null}.
|
||||
*/
|
||||
public LoginTokenRenewalFailedEvent(VaultToken source, Throwable exception) {
|
||||
@@ -44,4 +43,5 @@ public class LoginTokenRenewalFailedEvent extends AuthenticationErrorEvent {
|
||||
public VaultToken getSource() {
|
||||
return (VaultToken) super.getSource();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -32,9 +32,8 @@ public class LoginTokenRevocationFailedEvent extends AuthenticationErrorEvent {
|
||||
/**
|
||||
* Create a new {@link LoginTokenRevocationFailedEvent} given {@link VaultToken} and
|
||||
* {@link Exception}.
|
||||
*
|
||||
* @param source the {@link VaultToken} associated with this event, must not be
|
||||
* {@literal null}.
|
||||
* {@literal null}.
|
||||
* @param exception must not be {@literal null}.
|
||||
*/
|
||||
public LoginTokenRevocationFailedEvent(VaultToken source, Throwable exception) {
|
||||
@@ -44,4 +43,5 @@ public class LoginTokenRevocationFailedEvent extends AuthenticationErrorEvent {
|
||||
public VaultToken getSource() {
|
||||
return (VaultToken) super.getSource();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -51,15 +51,12 @@ import static org.springframework.vault.client.ClientHttpRequestFactoryFactory.h
|
||||
*/
|
||||
public class ClientHttpConnectorFactory {
|
||||
|
||||
private static final boolean REACTOR_NETTY_PRESENT = isPresent(
|
||||
"reactor.netty.http.client.HttpClient");
|
||||
private static final boolean REACTOR_NETTY_PRESENT = isPresent("reactor.netty.http.client.HttpClient");
|
||||
|
||||
private static final boolean JETTY_PRESENT = isPresent(
|
||||
"org.eclipse.jetty.client.HttpClient");
|
||||
private static final boolean JETTY_PRESENT = isPresent("org.eclipse.jetty.client.HttpClient");
|
||||
|
||||
/**
|
||||
* Checks for presence of all {@code classNames} using this class' classloader.
|
||||
*
|
||||
* @param classNames
|
||||
* @return {@literal true} if all classes are present; {@literal false} if at least
|
||||
* one class cannot be found.
|
||||
@@ -67,8 +64,7 @@ public class ClientHttpConnectorFactory {
|
||||
private static boolean isPresent(String... classNames) {
|
||||
|
||||
for (String className : classNames) {
|
||||
if (!ClassUtils.isPresent(className,
|
||||
ClientHttpConnectorFactory.class.getClassLoader())) {
|
||||
if (!ClassUtils.isPresent(className, ClientHttpConnectorFactory.class.getClassLoader())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -79,13 +75,11 @@ public class ClientHttpConnectorFactory {
|
||||
/**
|
||||
* Create a {@link ClientHttpConnector} for the given {@link ClientOptions} and
|
||||
* {@link SslConfiguration}.
|
||||
*
|
||||
* @param options must not be {@literal null}
|
||||
* @param sslConfiguration must not be {@literal null}
|
||||
* @return a new {@link ClientHttpConnector}.
|
||||
*/
|
||||
public static ClientHttpConnector create(ClientOptions options,
|
||||
SslConfiguration sslConfiguration) {
|
||||
public static ClientHttpConnector create(ClientOptions options, SslConfiguration sslConfiguration) {
|
||||
|
||||
Assert.notNull(options, "ClientOptions must not be null");
|
||||
Assert.notNull(sslConfiguration, "SslConfiguration must not be null");
|
||||
@@ -98,23 +92,20 @@ public class ClientHttpConnectorFactory {
|
||||
return JettyClient.usingJetty(options, sslConfiguration);
|
||||
}
|
||||
|
||||
throw new IllegalStateException(
|
||||
"No supported Reactive Http Client library available (Reactor Netty, Jetty)");
|
||||
throw new IllegalStateException("No supported Reactive Http Client library available (Reactor Netty, Jetty)");
|
||||
}
|
||||
|
||||
private static void configureSsl(SslConfiguration sslConfiguration,
|
||||
SslContextBuilder sslContextBuilder) {
|
||||
private static void configureSsl(SslConfiguration sslConfiguration, SslContextBuilder sslContextBuilder) {
|
||||
|
||||
try {
|
||||
|
||||
if (sslConfiguration.getTrustStoreConfiguration().isPresent()) {
|
||||
sslContextBuilder.trustManager(createTrustManagerFactory(
|
||||
sslConfiguration.getTrustStoreConfiguration()));
|
||||
sslContextBuilder
|
||||
.trustManager(createTrustManagerFactory(sslConfiguration.getTrustStoreConfiguration()));
|
||||
}
|
||||
|
||||
if (sslConfiguration.getKeyStoreConfiguration().isPresent()) {
|
||||
sslContextBuilder.keyManager(createKeyManagerFactory(
|
||||
sslConfiguration.getKeyStoreConfiguration(),
|
||||
sslContextBuilder.keyManager(createKeyManagerFactory(sslConfiguration.getKeyStoreConfiguration(),
|
||||
sslConfiguration.getKeyConfiguration()));
|
||||
}
|
||||
}
|
||||
@@ -130,8 +121,7 @@ public class ClientHttpConnectorFactory {
|
||||
*/
|
||||
static class ReactorNetty {
|
||||
|
||||
static ClientHttpConnector usingReactorNetty(ClientOptions options,
|
||||
SslConfiguration sslConfiguration) {
|
||||
static ClientHttpConnector usingReactorNetty(ClientOptions options, SslConfiguration sslConfiguration) {
|
||||
HttpClient client = HttpClient.create();
|
||||
|
||||
if (hasSslConfiguration(sslConfiguration)) {
|
||||
@@ -144,21 +134,20 @@ public class ClientHttpConnectorFactory {
|
||||
});
|
||||
}
|
||||
|
||||
client = client.tcpConfiguration(
|
||||
it -> it.option(ChannelOption.CONNECT_TIMEOUT_MILLIS,
|
||||
Math.toIntExact(options.getConnectionTimeout().toMillis())));
|
||||
client = client.tcpConfiguration(it -> it.option(ChannelOption.CONNECT_TIMEOUT_MILLIS,
|
||||
Math.toIntExact(options.getConnectionTimeout().toMillis())));
|
||||
|
||||
return new ReactorClientHttpConnector(client);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class JettyClient {
|
||||
static ClientHttpConnector usingJetty(ClientOptions options,
|
||||
SslConfiguration sslConfiguration) {
|
||||
|
||||
static ClientHttpConnector usingJetty(ClientOptions options, SslConfiguration sslConfiguration) {
|
||||
|
||||
try {
|
||||
return new JettyClientHttpConnector(
|
||||
configureClient(getHttpClient(sslConfiguration), options));
|
||||
return new JettyClientHttpConnector(configureClient(getHttpClient(sslConfiguration), options));
|
||||
}
|
||||
catch (GeneralSecurityException | IOException e) {
|
||||
throw new IllegalStateException(e);
|
||||
@@ -169,15 +158,13 @@ public class ClientHttpConnectorFactory {
|
||||
org.eclipse.jetty.client.HttpClient httpClient, ClientOptions options) {
|
||||
|
||||
httpClient.setConnectTimeout(options.getConnectionTimeout().toMillis());
|
||||
httpClient.setAddressResolutionTimeout(
|
||||
options.getConnectionTimeout().toMillis());
|
||||
httpClient.setAddressResolutionTimeout(options.getConnectionTimeout().toMillis());
|
||||
|
||||
return httpClient;
|
||||
}
|
||||
|
||||
private static org.eclipse.jetty.client.HttpClient getHttpClient(
|
||||
SslConfiguration sslConfiguration) throws KeyStoreException, IOException,
|
||||
NoSuchAlgorithmException, CertificateException {
|
||||
private static org.eclipse.jetty.client.HttpClient getHttpClient(SslConfiguration sslConfiguration)
|
||||
throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException {
|
||||
|
||||
if (hasSslConfiguration(sslConfiguration)) {
|
||||
|
||||
@@ -195,16 +182,14 @@ public class ClientHttpConnectorFactory {
|
||||
sslContextFactory.setTrustStore(keyStore);
|
||||
}
|
||||
|
||||
SslConfiguration.KeyConfiguration keyConfiguration = sslConfiguration
|
||||
.getKeyConfiguration();
|
||||
SslConfiguration.KeyConfiguration keyConfiguration = sslConfiguration.getKeyConfiguration();
|
||||
|
||||
if (keyConfiguration.getKeyAlias() != null) {
|
||||
sslContextFactory.setCertAlias(keyConfiguration.getKeyAlias());
|
||||
}
|
||||
|
||||
if (keyConfiguration.getKeyPassword() != null) {
|
||||
sslContextFactory.setKeyManagerPassword(
|
||||
new String(keyConfiguration.getKeyPassword()));
|
||||
sslContextFactory.setKeyManagerPassword(new String(keyConfiguration.getKeyPassword()));
|
||||
}
|
||||
|
||||
return new org.eclipse.jetty.client.HttpClient(sslContextFactory);
|
||||
@@ -212,5 +197,7 @@ public class ClientHttpConnectorFactory {
|
||||
|
||||
return new org.eclipse.jetty.client.HttpClient();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -80,21 +80,17 @@ import static org.springframework.vault.support.SslConfiguration.KeyConfiguratio
|
||||
*/
|
||||
public class ClientHttpRequestFactoryFactory {
|
||||
|
||||
private static final Log logger = LogFactory
|
||||
.getLog(ClientHttpRequestFactoryFactory.class);
|
||||
private static final Log logger = LogFactory.getLog(ClientHttpRequestFactoryFactory.class);
|
||||
|
||||
private static final boolean HTTP_COMPONENTS_PRESENT = isPresent(
|
||||
"org.apache.http.client.HttpClient");
|
||||
private static final boolean HTTP_COMPONENTS_PRESENT = isPresent("org.apache.http.client.HttpClient");
|
||||
|
||||
private static final boolean OKHTTP3_PRESENT = isPresent("okhttp3.OkHttpClient");
|
||||
|
||||
private static final boolean NETTY_PRESENT = isPresent(
|
||||
"io.netty.channel.nio.NioEventLoopGroup", "io.netty.handler.ssl.SslContext",
|
||||
"io.netty.handler.codec.http.HttpClientCodec");
|
||||
private static final boolean NETTY_PRESENT = isPresent("io.netty.channel.nio.NioEventLoopGroup",
|
||||
"io.netty.handler.ssl.SslContext", "io.netty.handler.codec.http.HttpClientCodec");
|
||||
|
||||
/**
|
||||
* Checks for presence of all {@code classNames} using this class' classloader.
|
||||
*
|
||||
* @param classNames
|
||||
* @return {@literal true} if all classes are present; {@literal false} if at least
|
||||
* one class cannot be found.
|
||||
@@ -102,8 +98,7 @@ public class ClientHttpRequestFactoryFactory {
|
||||
private static boolean isPresent(String... classNames) {
|
||||
|
||||
for (String className : classNames) {
|
||||
if (!ClassUtils.isPresent(className,
|
||||
ClientHttpRequestFactoryFactory.class.getClassLoader())) {
|
||||
if (!ClassUtils.isPresent(className, ClientHttpRequestFactoryFactory.class.getClassLoader())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -114,14 +109,12 @@ public class ClientHttpRequestFactoryFactory {
|
||||
/**
|
||||
* Create a {@link ClientHttpRequestFactory} for the given {@link ClientOptions} and
|
||||
* {@link SslConfiguration}.
|
||||
*
|
||||
* @param options must not be {@literal null}
|
||||
* @param sslConfiguration must not be {@literal null}
|
||||
* @return a new {@link ClientHttpRequestFactory}. Lifecycle beans must be initialized
|
||||
* after obtaining.
|
||||
*/
|
||||
public static ClientHttpRequestFactory create(ClientOptions options,
|
||||
SslConfiguration sslConfiguration) {
|
||||
public static ClientHttpRequestFactory create(ClientOptions options, SslConfiguration sslConfiguration) {
|
||||
|
||||
Assert.notNull(options, "ClientOptions must not be null");
|
||||
Assert.notNull(sslConfiguration, "SslConfiguration must not be null");
|
||||
@@ -155,13 +148,13 @@ public class ClientHttpRequestFactoryFactory {
|
||||
return new SimpleClientHttpRequestFactory();
|
||||
}
|
||||
|
||||
static SSLContext getSSLContext(SslConfiguration sslConfiguration,
|
||||
TrustManager[] trustManagers) throws GeneralSecurityException, IOException {
|
||||
static SSLContext getSSLContext(SslConfiguration sslConfiguration, TrustManager[] trustManagers)
|
||||
throws GeneralSecurityException, IOException {
|
||||
|
||||
KeyConfiguration keyConfiguration = sslConfiguration.getKeyConfiguration();
|
||||
KeyManager[] keyManagers = sslConfiguration.getKeyStoreConfiguration().isPresent()
|
||||
? createKeyManagerFactory(sslConfiguration.getKeyStoreConfiguration(),
|
||||
keyConfiguration).getKeyManagers()
|
||||
? createKeyManagerFactory(sslConfiguration.getKeyStoreConfiguration(), keyConfiguration)
|
||||
.getKeyManagers()
|
||||
: null;
|
||||
|
||||
SSLContext sslContext = SSLContext.getInstance("TLS");
|
||||
@@ -174,26 +167,20 @@ public class ClientHttpRequestFactoryFactory {
|
||||
throws GeneralSecurityException, IOException {
|
||||
|
||||
return sslConfiguration.getTrustStoreConfiguration().isPresent()
|
||||
? createTrustManagerFactory(sslConfiguration.getTrustStoreConfiguration())
|
||||
.getTrustManagers()
|
||||
: null;
|
||||
? createTrustManagerFactory(sslConfiguration.getTrustStoreConfiguration()).getTrustManagers() : null;
|
||||
}
|
||||
|
||||
static KeyManagerFactory createKeyManagerFactory(
|
||||
KeyStoreConfiguration keyStoreConfiguration,
|
||||
KeyConfiguration keyConfiguration)
|
||||
throws GeneralSecurityException, IOException {
|
||||
static KeyManagerFactory createKeyManagerFactory(KeyStoreConfiguration keyStoreConfiguration,
|
||||
KeyConfiguration keyConfiguration) throws GeneralSecurityException, IOException {
|
||||
|
||||
KeyStore keyStore = getKeyStore(keyStoreConfiguration);
|
||||
|
||||
KeyManagerFactory keyManagerFactory = KeyManagerFactory
|
||||
.getInstance(KeyManagerFactory.getDefaultAlgorithm());
|
||||
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
|
||||
|
||||
char[] keyPasswordToUse = keyConfiguration.getKeyPassword();
|
||||
|
||||
if (keyPasswordToUse == null) {
|
||||
keyPasswordToUse = keyStoreConfiguration.getStorePassword() == null
|
||||
? new char[0]
|
||||
keyPasswordToUse = keyStoreConfiguration.getStorePassword() == null ? new char[0]
|
||||
: keyStoreConfiguration.getStorePassword();
|
||||
}
|
||||
|
||||
@@ -207,20 +194,16 @@ public class ClientHttpRequestFactoryFactory {
|
||||
}
|
||||
|
||||
static KeyStore getKeyStore(KeyStoreConfiguration keyStoreConfiguration)
|
||||
throws KeyStoreException, IOException, NoSuchAlgorithmException,
|
||||
CertificateException {
|
||||
throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException {
|
||||
|
||||
KeyStore keyStore = KeyStore
|
||||
.getInstance(StringUtils.hasText(keyStoreConfiguration.getStoreType())
|
||||
? keyStoreConfiguration.getStoreType()
|
||||
: KeyStore.getDefaultType());
|
||||
KeyStore keyStore = KeyStore.getInstance(StringUtils.hasText(keyStoreConfiguration.getStoreType())
|
||||
? keyStoreConfiguration.getStoreType() : KeyStore.getDefaultType());
|
||||
|
||||
loadKeyStore(keyStoreConfiguration, keyStore);
|
||||
return keyStore;
|
||||
}
|
||||
|
||||
static TrustManagerFactory createTrustManagerFactory(
|
||||
KeyStoreConfiguration keyStoreConfiguration)
|
||||
static TrustManagerFactory createTrustManagerFactory(KeyStoreConfiguration keyStoreConfiguration)
|
||||
throws GeneralSecurityException, IOException {
|
||||
|
||||
KeyStore trustStore = getKeyStore(keyStoreConfiguration);
|
||||
@@ -232,8 +215,7 @@ public class ClientHttpRequestFactoryFactory {
|
||||
return trustManagerFactory;
|
||||
}
|
||||
|
||||
private static void loadKeyStore(KeyStoreConfiguration keyStoreConfiguration,
|
||||
KeyStore keyStore)
|
||||
private static void loadKeyStore(KeyStoreConfiguration keyStoreConfiguration, KeyStore keyStore)
|
||||
throws IOException, NoSuchAlgorithmException, CertificateException {
|
||||
|
||||
InputStream inputStream = null;
|
||||
@@ -260,31 +242,26 @@ public class ClientHttpRequestFactoryFactory {
|
||||
*/
|
||||
static class HttpComponents {
|
||||
|
||||
static ClientHttpRequestFactory usingHttpComponents(ClientOptions options,
|
||||
SslConfiguration sslConfiguration)
|
||||
static ClientHttpRequestFactory usingHttpComponents(ClientOptions options, SslConfiguration sslConfiguration)
|
||||
throws GeneralSecurityException, IOException {
|
||||
|
||||
HttpClientBuilder httpClientBuilder = HttpClients.custom();
|
||||
|
||||
httpClientBuilder.setRoutePlanner(new SystemDefaultRoutePlanner(
|
||||
DefaultSchemePortResolver.INSTANCE, ProxySelector.getDefault()));
|
||||
httpClientBuilder.setRoutePlanner(
|
||||
new SystemDefaultRoutePlanner(DefaultSchemePortResolver.INSTANCE, ProxySelector.getDefault()));
|
||||
|
||||
if (hasSslConfiguration(sslConfiguration)) {
|
||||
|
||||
SSLContext sslContext = getSSLContext(sslConfiguration,
|
||||
getTrustManagers(sslConfiguration));
|
||||
SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(
|
||||
sslContext);
|
||||
SSLContext sslContext = getSSLContext(sslConfiguration, getTrustManagers(sslConfiguration));
|
||||
SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(sslContext);
|
||||
httpClientBuilder.setSSLSocketFactory(sslSocketFactory);
|
||||
httpClientBuilder.setSSLContext(sslContext);
|
||||
}
|
||||
|
||||
RequestConfig requestConfig = RequestConfig.custom()
|
||||
//
|
||||
.setConnectTimeout(
|
||||
Math.toIntExact(options.getConnectionTimeout().toMillis())) //
|
||||
.setSocketTimeout(
|
||||
Math.toIntExact(options.getReadTimeout().toMillis())) //
|
||||
.setConnectTimeout(Math.toIntExact(options.getConnectionTimeout().toMillis())) //
|
||||
.setSocketTimeout(Math.toIntExact(options.getReadTimeout().toMillis())) //
|
||||
.setAuthenticationEnabled(true) //
|
||||
.build();
|
||||
|
||||
@@ -295,6 +272,7 @@ public class ClientHttpRequestFactoryFactory {
|
||||
|
||||
return new HttpComponentsClientHttpRequestFactory(httpClientBuilder.build());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -304,8 +282,7 @@ public class ClientHttpRequestFactoryFactory {
|
||||
*/
|
||||
static class OkHttp3 {
|
||||
|
||||
static ClientHttpRequestFactory usingOkHttp3(ClientOptions options,
|
||||
SslConfiguration sslConfiguration)
|
||||
static ClientHttpRequestFactory usingOkHttp3(ClientOptions options, SslConfiguration sslConfiguration)
|
||||
throws GeneralSecurityException, IOException {
|
||||
|
||||
Builder builder = new Builder();
|
||||
@@ -314,10 +291,9 @@ public class ClientHttpRequestFactoryFactory {
|
||||
|
||||
TrustManager[] trustManagers = getTrustManagers(sslConfiguration);
|
||||
|
||||
if (trustManagers.length != 1
|
||||
|| !(trustManagers[0] instanceof X509TrustManager)) {
|
||||
throw new IllegalStateException("Unexpected default trust managers:"
|
||||
+ Arrays.toString(trustManagers));
|
||||
if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {
|
||||
throw new IllegalStateException(
|
||||
"Unexpected default trust managers:" + Arrays.toString(trustManagers));
|
||||
}
|
||||
|
||||
X509TrustManager trustManager = (X509TrustManager) trustManagers[0];
|
||||
@@ -326,12 +302,12 @@ public class ClientHttpRequestFactoryFactory {
|
||||
builder.sslSocketFactory(sslContext.getSocketFactory(), trustManager);
|
||||
}
|
||||
|
||||
builder.connectTimeout(options.getConnectionTimeout().toMillis(),
|
||||
TimeUnit.MILLISECONDS).readTimeout(
|
||||
options.getReadTimeout().toMillis(), TimeUnit.MILLISECONDS);
|
||||
builder.connectTimeout(options.getConnectionTimeout().toMillis(), TimeUnit.MILLISECONDS)
|
||||
.readTimeout(options.getReadTimeout().toMillis(), TimeUnit.MILLISECONDS);
|
||||
|
||||
return new OkHttp3ClientHttpRequestFactory(builder.build());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -341,8 +317,7 @@ public class ClientHttpRequestFactoryFactory {
|
||||
*/
|
||||
static class Netty {
|
||||
|
||||
static ClientHttpRequestFactory usingNetty(ClientOptions options,
|
||||
SslConfiguration sslConfiguration)
|
||||
static ClientHttpRequestFactory usingNetty(ClientOptions options, SslConfiguration sslConfiguration)
|
||||
throws GeneralSecurityException, IOException {
|
||||
|
||||
Netty4ClientHttpRequestFactory requestFactory = new Netty4ClientHttpRequestFactory();
|
||||
@@ -353,44 +328,38 @@ public class ClientHttpRequestFactoryFactory {
|
||||
.forClient();
|
||||
|
||||
if (sslConfiguration.getTrustStoreConfiguration().isPresent()) {
|
||||
sslContextBuilder.trustManager(createTrustManagerFactory(
|
||||
sslConfiguration.getTrustStoreConfiguration()));
|
||||
sslContextBuilder
|
||||
.trustManager(createTrustManagerFactory(sslConfiguration.getTrustStoreConfiguration()));
|
||||
}
|
||||
|
||||
if (sslConfiguration.getKeyStoreConfiguration().isPresent()) {
|
||||
sslContextBuilder.keyManager(createKeyManagerFactory(
|
||||
sslConfiguration.getKeyStoreConfiguration(),
|
||||
sslContextBuilder.keyManager(createKeyManagerFactory(sslConfiguration.getKeyStoreConfiguration(),
|
||||
sslConfiguration.getKeyConfiguration()));
|
||||
}
|
||||
|
||||
requestFactory.setSslContext(
|
||||
sslContextBuilder.sslProvider(SslProvider.JDK).build());
|
||||
requestFactory.setSslContext(sslContextBuilder.sslProvider(SslProvider.JDK).build());
|
||||
}
|
||||
|
||||
requestFactory.setConnectTimeout(
|
||||
Math.toIntExact(options.getConnectionTimeout().toMillis()));
|
||||
requestFactory
|
||||
.setReadTimeout(Math.toIntExact(options.getReadTimeout().toMillis()));
|
||||
requestFactory.setConnectTimeout(Math.toIntExact(options.getConnectionTimeout().toMillis()));
|
||||
requestFactory.setReadTimeout(Math.toIntExact(options.getReadTimeout().toMillis()));
|
||||
|
||||
return requestFactory;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class KeySelectingKeyManagerFactory extends KeyManagerFactory {
|
||||
|
||||
KeySelectingKeyManagerFactory(KeyManagerFactory factory,
|
||||
KeyConfiguration keyConfiguration) {
|
||||
KeySelectingKeyManagerFactory(KeyManagerFactory factory, KeyConfiguration keyConfiguration) {
|
||||
super(new KeyManagerFactorySpi() {
|
||||
@Override
|
||||
protected void engineInit(KeyStore keyStore, char[] chars)
|
||||
throws KeyStoreException, NoSuchAlgorithmException,
|
||||
UnrecoverableKeyException {
|
||||
throws KeyStoreException, NoSuchAlgorithmException, UnrecoverableKeyException {
|
||||
factory.init(keyStore, chars);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void engineInit(
|
||||
ManagerFactoryParameters managerFactoryParameters)
|
||||
protected void engineInit(ManagerFactoryParameters managerFactoryParameters)
|
||||
throws InvalidAlgorithmParameterException {
|
||||
factory.init(managerFactoryParameters);
|
||||
}
|
||||
@@ -400,66 +369,64 @@ public class ClientHttpRequestFactoryFactory {
|
||||
|
||||
KeyManager[] keyManagers = factory.getKeyManagers();
|
||||
|
||||
if (keyManagers.length == 1
|
||||
&& keyManagers[0] instanceof X509ExtendedKeyManager) {
|
||||
if (keyManagers.length == 1 && keyManagers[0] instanceof X509ExtendedKeyManager) {
|
||||
|
||||
return new KeyManager[] { new KeySelectingX509KeyManager(
|
||||
(X509ExtendedKeyManager) keyManagers[0],
|
||||
keyConfiguration) };
|
||||
(X509ExtendedKeyManager) keyManagers[0], keyConfiguration) };
|
||||
}
|
||||
|
||||
return keyManagers;
|
||||
}
|
||||
}, factory.getProvider(), factory.getAlgorithm());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class KeySelectingX509KeyManager extends X509ExtendedKeyManager {
|
||||
|
||||
private final X509ExtendedKeyManager delegate;
|
||||
|
||||
private final KeyConfiguration keyConfiguration;
|
||||
|
||||
KeySelectingX509KeyManager(X509ExtendedKeyManager delegate,
|
||||
KeyConfiguration keyConfiguration) {
|
||||
KeySelectingX509KeyManager(X509ExtendedKeyManager delegate, KeyConfiguration keyConfiguration) {
|
||||
this.delegate = delegate;
|
||||
this.keyConfiguration = keyConfiguration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getClientAliases(String keyType, Principal[] issuers) {
|
||||
return delegate.getClientAliases(keyType, issuers);
|
||||
return this.delegate.getClientAliases(keyType, issuers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String chooseClientAlias(String[] keyType, Principal[] issuers,
|
||||
Socket socket) {
|
||||
return keyConfiguration.getKeyAlias();
|
||||
public String chooseClientAlias(String[] keyType, Principal[] issuers, Socket socket) {
|
||||
return this.keyConfiguration.getKeyAlias();
|
||||
}
|
||||
|
||||
public String chooseEngineClientAlias(String[] keyType, Principal[] issuers,
|
||||
SSLEngine engine) {
|
||||
return keyConfiguration.getKeyAlias();
|
||||
public String chooseEngineClientAlias(String[] keyType, Principal[] issuers, SSLEngine engine) {
|
||||
return this.keyConfiguration.getKeyAlias();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getServerAliases(String keyType, Principal[] issuers) {
|
||||
return delegate.getServerAliases(keyType, issuers);
|
||||
return this.delegate.getServerAliases(keyType, issuers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String chooseServerAlias(String keyType, Principal[] issuers,
|
||||
Socket socket) {
|
||||
return delegate.chooseServerAlias(keyType, issuers, socket);
|
||||
public String chooseServerAlias(String keyType, Principal[] issuers, Socket socket) {
|
||||
return this.delegate.chooseServerAlias(keyType, issuers, socket);
|
||||
}
|
||||
|
||||
@Override
|
||||
public X509Certificate[] getCertificateChain(String alias) {
|
||||
return delegate.getCertificateChain(alias);
|
||||
return this.delegate.getCertificateChain(alias);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PrivateKey getPrivateKey(String alias) {
|
||||
return delegate.getPrivateKey(alias);
|
||||
return this.delegate.getPrivateKey(alias);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -46,13 +46,11 @@ public class ReactiveVaultClients {
|
||||
* slash that are expanded to use {@link VaultEndpoint}.
|
||||
* <p>
|
||||
* Requires Jackson 2 for Object-to-JSON mapping.
|
||||
*
|
||||
* @param endpoint must not be {@literal null}.
|
||||
* @param connector must not be {@literal null}.
|
||||
* @return the configured {@link WebClient}.
|
||||
*/
|
||||
public static WebClient createWebClient(VaultEndpoint endpoint,
|
||||
ClientHttpConnector connector) {
|
||||
public static WebClient createWebClient(VaultEndpoint endpoint, ClientHttpConnector connector) {
|
||||
return createWebClient(SimpleVaultEndpointProvider.of(endpoint), connector);
|
||||
}
|
||||
|
||||
@@ -62,13 +60,11 @@ public class ReactiveVaultClients {
|
||||
* slash that are expanded to use {@link VaultEndpoint}.
|
||||
* <p>
|
||||
* Requires Jackson 2 for Object-to-JSON mapping.
|
||||
*
|
||||
* @param endpointProvider must not be {@literal null}.
|
||||
* @param connector must not be {@literal null}.
|
||||
* @return the configured {@link WebClient}.
|
||||
*/
|
||||
public static WebClient createWebClient(VaultEndpointProvider endpointProvider,
|
||||
ClientHttpConnector connector) {
|
||||
public static WebClient createWebClient(VaultEndpointProvider endpointProvider, ClientHttpConnector connector) {
|
||||
|
||||
Assert.notNull(endpointProvider, "VaultEndpointProvider must not be null");
|
||||
Assert.notNull(connector, "ClientHttpConnector must not be null");
|
||||
@@ -82,42 +78,38 @@ public class ReactiveVaultClients {
|
||||
* slash that are expanded to use {@link VaultEndpoint}.
|
||||
* <p>
|
||||
* Requires Jackson 2 for Object-to-JSON mapping.
|
||||
*
|
||||
* @param endpointProvider must not be {@literal null}.
|
||||
* @param connector must not be {@literal null}.
|
||||
* @return the prepared {@link WebClient.Builder}.
|
||||
*/
|
||||
static WebClient.Builder createWebClientBuilder(
|
||||
VaultEndpointProvider endpointProvider, ClientHttpConnector connector) {
|
||||
static WebClient.Builder createWebClientBuilder(VaultEndpointProvider endpointProvider,
|
||||
ClientHttpConnector connector) {
|
||||
|
||||
Assert.notNull(endpointProvider, "VaultEndpointProvider must not be null");
|
||||
Assert.notNull(connector, "ClientHttpConnector must not be null");
|
||||
|
||||
UriBuilderFactory uriBuilderFactory = VaultClients
|
||||
.createUriBuilderFactory(endpointProvider);
|
||||
UriBuilderFactory uriBuilderFactory = VaultClients.createUriBuilderFactory(endpointProvider);
|
||||
|
||||
ExchangeStrategies strategies = ExchangeStrategies.builder()
|
||||
.codecs(configurer -> {
|
||||
ExchangeStrategies strategies = ExchangeStrategies.builder().codecs(configurer -> {
|
||||
|
||||
CustomCodecs cc = configurer.customCodecs();
|
||||
CustomCodecs cc = configurer.customCodecs();
|
||||
|
||||
cc.decoder(new ByteArrayDecoder());
|
||||
cc.decoder(new Jackson2JsonDecoder());
|
||||
cc.decoder(StringDecoder.allMimeTypes());
|
||||
cc.decoder(new ByteArrayDecoder());
|
||||
cc.decoder(new Jackson2JsonDecoder());
|
||||
cc.decoder(StringDecoder.allMimeTypes());
|
||||
|
||||
cc.encoder(new ByteArrayEncoder());
|
||||
cc.encoder(new Jackson2JsonEncoder());
|
||||
cc.encoder(new ByteArrayEncoder());
|
||||
cc.encoder(new Jackson2JsonEncoder());
|
||||
|
||||
}).build();
|
||||
}).build();
|
||||
|
||||
return WebClient.builder().uriBuilderFactory(uriBuilderFactory)
|
||||
.exchangeStrategies(strategies).clientConnector(connector);
|
||||
return WebClient.builder().uriBuilderFactory(uriBuilderFactory).exchangeStrategies(strategies)
|
||||
.clientConnector(connector);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link ExchangeFilterFunction} that associates each request with a
|
||||
* {@code X-Vault-Namespace} header if the header is not present.
|
||||
*
|
||||
* @param namespace the Vault namespace to use. Must not be {@literal null} or empty.
|
||||
* @return the {@link ExchangeFilterFunction} to register with {@link WebClient}.
|
||||
* @see VaultHttpHeaders#VAULT_NAMESPACE
|
||||
@@ -140,4 +132,5 @@ public class ReactiveVaultClients {
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -73,7 +73,6 @@ public class RestTemplateBuilder {
|
||||
|
||||
/**
|
||||
* Create a new {@link RestTemplateBuilder}.
|
||||
*
|
||||
* @return a new {@link RestTemplateBuilder}.
|
||||
*/
|
||||
public static RestTemplateBuilder builder() {
|
||||
@@ -82,7 +81,6 @@ public class RestTemplateBuilder {
|
||||
|
||||
/**
|
||||
* Set the {@link VaultEndpoint} that should be used with the {@link RestTemplate}.
|
||||
*
|
||||
* @param endpoint the {@link VaultEndpoint} provider.
|
||||
* @return {@code this} {@link RestTemplateBuilder}.
|
||||
*/
|
||||
@@ -93,7 +91,6 @@ public class RestTemplateBuilder {
|
||||
/**
|
||||
* Set the {@link VaultEndpointProvider} that should be used with the
|
||||
* {@link RestTemplate}.
|
||||
*
|
||||
* @param provider the {@link VaultEndpoint} provider.
|
||||
* @return {@code this} {@link RestTemplateBuilder}.
|
||||
*/
|
||||
@@ -109,7 +106,6 @@ public class RestTemplateBuilder {
|
||||
/**
|
||||
* Set the {@link ClientHttpRequestFactory} that should be used with the
|
||||
* {@link RestTemplate}.
|
||||
*
|
||||
* @param requestFactory the request factory.
|
||||
* @return {@code this} {@link RestTemplateBuilder}.
|
||||
*/
|
||||
@@ -123,15 +119,12 @@ public class RestTemplateBuilder {
|
||||
/**
|
||||
* Set the {@link Supplier} of {@link ClientHttpRequestFactory} that should be called
|
||||
* each time we {@link #build()} a new {@link RestTemplate} instance.
|
||||
*
|
||||
* @param requestFactory the supplier for the request factory.
|
||||
* @return {@code this} {@link RestTemplateBuilder}.
|
||||
*/
|
||||
public RestTemplateBuilder requestFactory(
|
||||
Supplier<ClientHttpRequestFactory> requestFactory) {
|
||||
public RestTemplateBuilder requestFactory(Supplier<ClientHttpRequestFactory> requestFactory) {
|
||||
|
||||
Assert.notNull(requestFactory,
|
||||
"Supplier of ClientHttpRequestFactory must not be null");
|
||||
Assert.notNull(requestFactory, "Supplier of ClientHttpRequestFactory must not be null");
|
||||
|
||||
this.requestFactory = requestFactory;
|
||||
return this;
|
||||
@@ -140,7 +133,6 @@ public class RestTemplateBuilder {
|
||||
/**
|
||||
* Set the {@link ResponseErrorHandler} that should be used with the
|
||||
* {@link RestTemplate}.
|
||||
*
|
||||
* @param errorHandler the error handler to use.
|
||||
* @return {@code this} {@link RestTemplateBuilder}.
|
||||
*/
|
||||
@@ -155,7 +147,6 @@ public class RestTemplateBuilder {
|
||||
/**
|
||||
* Add a default header that will be set if not already present on the outgoing
|
||||
* {@link HttpRequest}.
|
||||
*
|
||||
* @param name the name of the header.
|
||||
* @param value the header value.
|
||||
* @return {@code this} {@link RestTemplateBuilder}.
|
||||
@@ -173,7 +164,6 @@ public class RestTemplateBuilder {
|
||||
* Add the {@link RestTemplateCustomizer RestTemplateCustomizers} that should be
|
||||
* applied to the {@link RestTemplate}. Customizers are applied in the order that they
|
||||
* were added.
|
||||
*
|
||||
* @param customizer the template customizers to add.
|
||||
* @return {@code this} {@link RestTemplateBuilder}.
|
||||
*/
|
||||
@@ -188,13 +178,11 @@ public class RestTemplateBuilder {
|
||||
* Add the {@link RestTemplateRequestCustomizer RestTemplateRequestCustomizers} that
|
||||
* should be applied to the {@link ClientHttpRequest}. Customizers are applied in the
|
||||
* order that they were added.
|
||||
*
|
||||
* @param requestCustomizers the request customizers to add.
|
||||
* @return {@code this} {@link RestTemplateBuilder}.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public RestTemplateBuilder requestCustomizers(
|
||||
RestTemplateRequestCustomizer<?>... requestCustomizers) {
|
||||
public RestTemplateBuilder requestCustomizers(RestTemplateRequestCustomizer<?>... requestCustomizers) {
|
||||
|
||||
Assert.notNull(requestCustomizers, "RequestCustomizers must not be null");
|
||||
|
||||
@@ -207,66 +195,58 @@ public class RestTemplateBuilder {
|
||||
*
|
||||
* Applies also {@link ResponseErrorHandler} and {@link RestTemplateCustomizer} if
|
||||
* configured.
|
||||
*
|
||||
* @return a new {@link RestTemplate}.
|
||||
*/
|
||||
public RestTemplate build() {
|
||||
|
||||
Assert.state(this.endpointProvider != null,
|
||||
"VaultEndpointProvider must not be null");
|
||||
Assert.state(this.endpointProvider != null, "VaultEndpointProvider must not be null");
|
||||
|
||||
RestTemplate restTemplate = createTemplate();
|
||||
|
||||
if (errorHandler != null) {
|
||||
restTemplate.setErrorHandler(errorHandler);
|
||||
if (this.errorHandler != null) {
|
||||
restTemplate.setErrorHandler(this.errorHandler);
|
||||
}
|
||||
|
||||
customizers.forEach(customizer -> customizer.customize(restTemplate));
|
||||
this.customizers.forEach(customizer -> customizer.customize(restTemplate));
|
||||
|
||||
return restTemplate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the {@link RestTemplate} to use.
|
||||
*
|
||||
* @return the {@link RestTemplate} to use.
|
||||
*/
|
||||
protected RestTemplate createTemplate() {
|
||||
|
||||
ClientHttpRequestFactory requestFactory = this.requestFactory.get();
|
||||
|
||||
LinkedHashMap<String, String> defaultHeaders = new LinkedHashMap<>(
|
||||
this.defaultHeaders);
|
||||
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));
|
||||
new RestTemplateBuilderClientHttpRequestFactoryWrapper(requestFactory, requestCustomizers));
|
||||
|
||||
restTemplate.getInterceptors()
|
||||
.add((httpRequest, bytes, clientHttpRequestExecution) -> {
|
||||
restTemplate.getInterceptors().add((httpRequest, bytes, clientHttpRequestExecution) -> {
|
||||
|
||||
HttpHeaders headers = httpRequest.getHeaders();
|
||||
defaultHeaders.forEach((key, value) -> {
|
||||
if (!headers.containsKey(key)) {
|
||||
headers.add(key, value);
|
||||
}
|
||||
});
|
||||
HttpHeaders headers = httpRequest.getHeaders();
|
||||
defaultHeaders.forEach((key, value) -> {
|
||||
if (!headers.containsKey(key)) {
|
||||
headers.add(key, value);
|
||||
}
|
||||
});
|
||||
|
||||
return clientHttpRequestExecution.execute(httpRequest, bytes);
|
||||
});
|
||||
return clientHttpRequestExecution.execute(httpRequest, bytes);
|
||||
});
|
||||
|
||||
return restTemplate;
|
||||
}
|
||||
|
||||
static class RestTemplateBuilderClientHttpRequestFactoryWrapper
|
||||
extends AbstractClientHttpRequestFactoryWrapper {
|
||||
static class RestTemplateBuilderClientHttpRequestFactoryWrapper extends AbstractClientHttpRequestFactoryWrapper {
|
||||
|
||||
private final Set<RestTemplateRequestCustomizer<ClientHttpRequest>> requestCustomizers;
|
||||
|
||||
RestTemplateBuilderClientHttpRequestFactoryWrapper(
|
||||
ClientHttpRequestFactory requestFactory,
|
||||
RestTemplateBuilderClientHttpRequestFactoryWrapper(ClientHttpRequestFactory requestFactory,
|
||||
Set<RestTemplateRequestCustomizer<ClientHttpRequest>> requestCustomizers) {
|
||||
|
||||
super(requestFactory);
|
||||
@@ -283,5 +263,7 @@ public class RestTemplateBuilder {
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -29,8 +29,8 @@ public interface RestTemplateCustomizer {
|
||||
|
||||
/**
|
||||
* Callback to customize a {@link RestTemplate} instance.
|
||||
*
|
||||
* @param restTemplate the template to customize.
|
||||
*/
|
||||
void customize(RestTemplate restTemplate);
|
||||
|
||||
}
|
||||
|
||||
@@ -31,8 +31,8 @@ public interface RestTemplateRequestCustomizer<T extends ClientHttpRequest> {
|
||||
|
||||
/**
|
||||
* Customize the specified {@link ClientHttpRequest}.
|
||||
*
|
||||
* @param request the request to customize.
|
||||
*/
|
||||
void customize(T request);
|
||||
|
||||
}
|
||||
|
||||
@@ -33,7 +33,6 @@ public class SimpleVaultEndpointProvider implements VaultEndpointProvider {
|
||||
|
||||
/**
|
||||
* Creates a new {@link VaultEndpointProvider} given {@link VaultEndpoint}.
|
||||
*
|
||||
* @param endpoint must not be {@literal null}.
|
||||
*/
|
||||
public static VaultEndpointProvider of(VaultEndpoint endpoint) {
|
||||
@@ -45,6 +44,7 @@ public class SimpleVaultEndpointProvider implements VaultEndpointProvider {
|
||||
|
||||
@Override
|
||||
public VaultEndpoint getVaultEndpoint() {
|
||||
return endpoint;
|
||||
return this.endpoint;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -58,17 +58,14 @@ public class VaultClients {
|
||||
* Otherwise, Vault will deny body processing.
|
||||
* <p>
|
||||
* Requires Jackson 2 for Object-to-JSON mapping.
|
||||
*
|
||||
* @param endpoint must not be {@literal null}.
|
||||
* @param requestFactory must not be {@literal null}.
|
||||
* @return the {@link RestTemplate}.
|
||||
* @see org.springframework.http.client.Netty4ClientHttpRequestFactory
|
||||
* @see MappingJackson2HttpMessageConverter
|
||||
*/
|
||||
public static RestTemplate createRestTemplate(VaultEndpoint endpoint,
|
||||
ClientHttpRequestFactory requestFactory) {
|
||||
return createRestTemplate(SimpleVaultEndpointProvider.of(endpoint),
|
||||
requestFactory);
|
||||
public static RestTemplate createRestTemplate(VaultEndpoint endpoint, ClientHttpRequestFactory requestFactory) {
|
||||
return createRestTemplate(SimpleVaultEndpointProvider.of(endpoint), requestFactory);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -82,7 +79,6 @@ public class VaultClients {
|
||||
* Otherwise, Vault will deny body processing.
|
||||
* <p>
|
||||
* Requires Jackson 2 for Object-to-JSON mapping.
|
||||
*
|
||||
* @param endpointProvider must not be {@literal null}.
|
||||
* @param requestFactory must not be {@literal null}.
|
||||
* @return the {@link RestTemplate}.
|
||||
@@ -110,7 +106,6 @@ public class VaultClients {
|
||||
* Otherwise, Vault will deny body processing.
|
||||
* <p>
|
||||
* Requires Jackson 2 for Object-to-JSON mapping.
|
||||
*
|
||||
* @return the {@link RestTemplate}.
|
||||
* @see org.springframework.http.client.Netty4ClientHttpRequestFactory
|
||||
* @see MappingJackson2HttpMessageConverter
|
||||
@@ -124,8 +119,7 @@ public class VaultClients {
|
||||
|
||||
RestTemplate restTemplate = new RestTemplate(messageConverters);
|
||||
|
||||
restTemplate.getInterceptors()
|
||||
.add((request, body, execution) -> execution.execute(request, body));
|
||||
restTemplate.getInterceptors().add((request, body, execution) -> execution.execute(request, body));
|
||||
|
||||
return restTemplate;
|
||||
}
|
||||
@@ -133,15 +127,13 @@ public class VaultClients {
|
||||
/**
|
||||
* Create a {@link ClientHttpRequestInterceptor} that associates each request with a
|
||||
* {@code X-Vault-Namespace} header if the header is not present.
|
||||
*
|
||||
* @param namespace the Vault namespace to use. Must not be {@literal null} or empty.
|
||||
* @return the {@link ClientHttpRequestInterceptor} to register with
|
||||
* {@link RestTemplate}.
|
||||
* @see VaultHttpHeaders#VAULT_NAMESPACE
|
||||
* @since 2.2
|
||||
*/
|
||||
public static ClientHttpRequestInterceptor createNamespaceInterceptor(
|
||||
String namespace) {
|
||||
public static ClientHttpRequestInterceptor createNamespaceInterceptor(String namespace) {
|
||||
|
||||
Assert.hasText(namespace, "Vault Namespace must not be empty!");
|
||||
|
||||
@@ -157,8 +149,7 @@ public class VaultClients {
|
||||
};
|
||||
}
|
||||
|
||||
public static UriBuilderFactory createUriBuilderFactory(
|
||||
VaultEndpointProvider endpointProvider) {
|
||||
public static UriBuilderFactory createUriBuilderFactory(VaultEndpointProvider endpointProvider) {
|
||||
return new PrefixAwareUriBuilderFactory(endpointProvider);
|
||||
}
|
||||
|
||||
@@ -177,27 +168,26 @@ public class VaultClients {
|
||||
|
||||
@Override
|
||||
protected URI expandInternal(String uriTemplate, Map<String, ?> uriVariables) {
|
||||
return super.expandInternal(prepareUriTemplate(getBaseUrl(), uriTemplate),
|
||||
uriVariables);
|
||||
return super.expandInternal(prepareUriTemplate(getBaseUrl(), uriTemplate), uriVariables);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected URI expandInternal(String uriTemplate, Object... uriVariables) {
|
||||
return super.expandInternal(prepareUriTemplate(getBaseUrl(), uriTemplate),
|
||||
uriVariables);
|
||||
return super.expandInternal(prepareUriTemplate(getBaseUrl(), uriTemplate), uriVariables);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getBaseUrl() {
|
||||
|
||||
if (endpointProvider != null) {
|
||||
if (this.endpointProvider != null) {
|
||||
|
||||
VaultEndpoint endpoint = endpointProvider.getVaultEndpoint();
|
||||
VaultEndpoint endpoint = this.endpointProvider.getVaultEndpoint();
|
||||
return toBaseUri(endpoint);
|
||||
}
|
||||
|
||||
return super.getBaseUrl();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -218,27 +208,26 @@ public class VaultClients {
|
||||
return UriComponentsBuilder.fromUriString(uriTemplate);
|
||||
}
|
||||
|
||||
VaultEndpoint endpoint = endpointProvider.getVaultEndpoint();
|
||||
VaultEndpoint endpoint = this.endpointProvider.getVaultEndpoint();
|
||||
|
||||
String baseUri = toBaseUri(endpoint);
|
||||
UriComponents uriComponents = UriComponentsBuilder
|
||||
.fromUriString(prepareUriTemplate(baseUri, uriTemplate)).build();
|
||||
UriComponents uriComponents = UriComponentsBuilder.fromUriString(prepareUriTemplate(baseUri, uriTemplate))
|
||||
.build();
|
||||
|
||||
return UriComponentsBuilder.fromUriString(baseUri)
|
||||
.uriComponents(uriComponents);
|
||||
return UriComponentsBuilder.fromUriString(baseUri).uriComponents(uriComponents);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static String toBaseUri(VaultEndpoint endpoint) {
|
||||
|
||||
return String.format("%s://%s:%s/%s", endpoint.getScheme(), endpoint.getHost(),
|
||||
endpoint.getPort(), endpoint.getPath());
|
||||
return String.format("%s://%s:%s/%s", endpoint.getScheme(), endpoint.getHost(), endpoint.getPort(),
|
||||
endpoint.getPath());
|
||||
}
|
||||
|
||||
/**
|
||||
* Strip/add leading slashes from {@code uriTemplate} depending on whether the base
|
||||
* url has a trailing slash.
|
||||
*
|
||||
* @param uriTemplate
|
||||
* @return
|
||||
*/
|
||||
@@ -277,4 +266,5 @@ public class VaultClients {
|
||||
|
||||
return uriTemplate;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -59,7 +59,6 @@ public class VaultEndpoint implements Serializable {
|
||||
/**
|
||||
* Create a secure {@link VaultEndpoint} given a {@code host} and {@code port} using
|
||||
* {@code https}.
|
||||
*
|
||||
* @param host must not be empty or {@literal null}.
|
||||
* @param port must be a valid port in the range of 1-65535
|
||||
* @return a new {@link VaultEndpoint}.
|
||||
@@ -78,9 +77,8 @@ public class VaultEndpoint implements Serializable {
|
||||
|
||||
/**
|
||||
* Create a {@link VaultEndpoint} given a {@link URI}.
|
||||
*
|
||||
* @param uri must contain hostname, port and scheme, must not be empty or
|
||||
* {@literal null}.
|
||||
* {@literal null}.
|
||||
* @return a new {@link VaultEndpoint}.
|
||||
*/
|
||||
public static VaultEndpoint from(URI uri) {
|
||||
@@ -93,12 +91,10 @@ public class VaultEndpoint implements Serializable {
|
||||
|
||||
vaultEndpoint.setHost(uri.getHost());
|
||||
try {
|
||||
vaultEndpoint.setPort(
|
||||
uri.getPort() == -1 ? uri.toURL().getDefaultPort() : uri.getPort());
|
||||
vaultEndpoint.setPort(uri.getPort() == -1 ? uri.toURL().getDefaultPort() : uri.getPort());
|
||||
}
|
||||
catch (MalformedURLException e) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format("Can't retrieve default port from %s", uri), e);
|
||||
throw new IllegalArgumentException(String.format("Can't retrieve default port from %s", uri), e);
|
||||
}
|
||||
vaultEndpoint.setScheme(uri.getScheme());
|
||||
|
||||
@@ -122,12 +118,11 @@ public class VaultEndpoint implements Serializable {
|
||||
* @return the hostname.
|
||||
*/
|
||||
public String getHost() {
|
||||
return host;
|
||||
return this.host;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the hostname.
|
||||
*
|
||||
* @param host must not be empty or {@literal null}.
|
||||
*/
|
||||
public void setHost(String host) {
|
||||
@@ -138,7 +133,7 @@ public class VaultEndpoint implements Serializable {
|
||||
* @return the port.
|
||||
*/
|
||||
public int getPort() {
|
||||
return port;
|
||||
return this.port;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -146,8 +141,7 @@ public class VaultEndpoint implements Serializable {
|
||||
*/
|
||||
public void setPort(int port) {
|
||||
|
||||
Assert.isTrue(port >= 1 && port <= 65535,
|
||||
"Port must be a valid port in the range between 1 and 65535");
|
||||
Assert.isTrue(port >= 1 && port <= 65535, "Port must be a valid port in the range between 1 and 65535");
|
||||
|
||||
this.port = port;
|
||||
}
|
||||
@@ -156,7 +150,7 @@ public class VaultEndpoint implements Serializable {
|
||||
* @return the protocol scheme.
|
||||
*/
|
||||
public String getScheme() {
|
||||
return scheme;
|
||||
return this.scheme;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -164,8 +158,7 @@ public class VaultEndpoint implements Serializable {
|
||||
*/
|
||||
public void setScheme(String scheme) {
|
||||
|
||||
Assert.isTrue("http".equals(scheme) || "https".equals(scheme),
|
||||
"Scheme must be http or https");
|
||||
Assert.isTrue("http".equals(scheme) || "https".equals(scheme), "Scheme must be http or https");
|
||||
|
||||
this.scheme = scheme;
|
||||
}
|
||||
@@ -175,26 +168,24 @@ public class VaultEndpoint implements Serializable {
|
||||
* @since 2.1
|
||||
*/
|
||||
public String getPath() {
|
||||
return path;
|
||||
return this.path;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param path context path prefix. Must not be {@literal null} or empty and must not
|
||||
* start with a leading slash.
|
||||
* start with a leading slash.
|
||||
* @since 2.1
|
||||
*/
|
||||
public void setPath(String path) {
|
||||
|
||||
Assert.hasText(path, "Path must not be null or empty");
|
||||
Assert.isTrue(!path.startsWith("/"),
|
||||
() -> String.format("Path %s must not start with a leading slash", path));
|
||||
Assert.isTrue(!path.startsWith("/"), () -> String.format("Path %s must not start with a leading slash", path));
|
||||
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the Vault {@link URI} based on the given {@code path}.
|
||||
*
|
||||
* @param path must not be empty or {@literal null}.
|
||||
* @return constructed {@link URI}.
|
||||
*/
|
||||
@@ -204,7 +195,6 @@ public class VaultEndpoint implements Serializable {
|
||||
|
||||
/**
|
||||
* Build the Vault URI string based on the given {@code path}.
|
||||
*
|
||||
* @param path must not be empty or {@literal null}.
|
||||
* @return constructed URI String.
|
||||
*/
|
||||
@@ -212,8 +202,7 @@ public class VaultEndpoint implements Serializable {
|
||||
|
||||
Assert.hasText(path, "Path must not be empty");
|
||||
|
||||
return String.format("%s://%s:%s/%s/%s", getScheme(), getHost(), getPort(),
|
||||
getPath(), path);
|
||||
return String.format("%s://%s:%s/%s/%s", getScheme(), getHost(), getPort(), getPath(), path);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -223,17 +212,18 @@ public class VaultEndpoint implements Serializable {
|
||||
if (!(o instanceof VaultEndpoint))
|
||||
return false;
|
||||
VaultEndpoint that = (VaultEndpoint) o;
|
||||
return port == that.port && host.equals(that.host) && scheme.equals(that.scheme)
|
||||
&& path.equals(that.path);
|
||||
return this.port == that.port && this.host.equals(that.host) && this.scheme.equals(that.scheme)
|
||||
&& this.path.equals(that.path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(host, port, scheme, path);
|
||||
return Objects.hash(this.host, this.port, this.scheme, this.path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("%s://%s:%d", scheme, host, port);
|
||||
return String.format("%s://%s:%d", this.scheme, this.host, this.port);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,8 +27,8 @@ public interface VaultEndpointProvider {
|
||||
|
||||
/**
|
||||
* Provides access to {@link VaultEndpoint}.
|
||||
*
|
||||
* @return the {@link VaultEndpoint}.
|
||||
*/
|
||||
VaultEndpoint getVaultEndpoint();
|
||||
|
||||
}
|
||||
|
||||
@@ -56,4 +56,5 @@ public abstract class VaultHttpHeaders {
|
||||
|
||||
return headers;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -60,13 +60,11 @@ public abstract class VaultResponses {
|
||||
String message = VaultResponses.getError(e.getResponseBodyAsString());
|
||||
|
||||
if (StringUtils.hasText(message)) {
|
||||
return new VaultException(String.format("Status %s %s: %s",
|
||||
e.getRawStatusCode(), e.getStatusText(), message), e);
|
||||
return new VaultException(
|
||||
String.format("Status %s %s: %s", e.getRawStatusCode(), e.getStatusText(), message), e);
|
||||
}
|
||||
|
||||
return new VaultException(
|
||||
String.format("Status %s %s", e.getRawStatusCode(), e.getStatusText()),
|
||||
e);
|
||||
return new VaultException(String.format("Status %s %s", e.getRawStatusCode(), e.getStatusText()), e);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -83,20 +81,17 @@ public abstract class VaultResponses {
|
||||
String message = VaultResponses.getError(e.getResponseBodyAsString());
|
||||
|
||||
if (StringUtils.hasText(message)) {
|
||||
return new VaultException(String.format("Status %s %s [%s]: %s",
|
||||
e.getRawStatusCode(), e.getStatusText(), path, message), e);
|
||||
return new VaultException(
|
||||
String.format("Status %s %s [%s]: %s", e.getRawStatusCode(), e.getStatusText(), path, message), e);
|
||||
}
|
||||
|
||||
return new VaultException(String.format("Status %s %s [%s]", e.getRawStatusCode(),
|
||||
e.getStatusText(), path), e);
|
||||
return new VaultException(String.format("Status %s %s [%s]", e.getRawStatusCode(), e.getStatusText(), path), e);
|
||||
}
|
||||
|
||||
public static VaultException buildException(HttpStatus statusCode, String path,
|
||||
String message) {
|
||||
public static VaultException buildException(HttpStatus statusCode, String path, String message) {
|
||||
|
||||
if (StringUtils.hasText(message)) {
|
||||
return new VaultException(
|
||||
String.format("Status %s [%s]: %s", statusCode, path, message));
|
||||
return new VaultException(String.format("Status %s [%s]: %s", statusCode, path, message));
|
||||
}
|
||||
|
||||
return new VaultException(String.format("Status %s [%s]", statusCode, path));
|
||||
@@ -140,7 +135,6 @@ public abstract class VaultResponses {
|
||||
|
||||
/**
|
||||
* Obtain the error message from a JSON response.
|
||||
*
|
||||
* @param json must not be {@literal null}.
|
||||
* @return extracted error string.
|
||||
*/
|
||||
@@ -152,8 +146,7 @@ public abstract class VaultResponses {
|
||||
if (json.contains("\"errors\":")) {
|
||||
|
||||
try {
|
||||
Map<String, Object> map = OBJECT_MAPPER.readValue(json.getBytes(),
|
||||
Map.class);
|
||||
Map<String, Object> map = OBJECT_MAPPER.readValue(json.getBytes(), Map.class);
|
||||
if (map.containsKey("errors")) {
|
||||
|
||||
Collection<String> errors = (Collection<String>) map.get("errors");
|
||||
@@ -173,7 +166,6 @@ public abstract class VaultResponses {
|
||||
|
||||
/**
|
||||
* Unwrap a wrapped response created by Vault Response Wrapping
|
||||
*
|
||||
* @param wrappedResponse the wrapped response , must not be empty or {@literal null}.
|
||||
* @param responseType the type of the return value.
|
||||
* @return the unwrapped response.
|
||||
@@ -200,4 +192,5 @@ public abstract class VaultResponses {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -51,8 +51,8 @@ public class WebClientBuilder {
|
||||
|
||||
private @Nullable VaultEndpointProvider endpointProvider;
|
||||
|
||||
private Supplier<ClientHttpConnector> httpConnector = () -> ClientHttpConnectorFactory
|
||||
.create(new ClientOptions(), SslConfiguration.unconfigured());
|
||||
private Supplier<ClientHttpConnector> httpConnector = () -> ClientHttpConnectorFactory.create(new ClientOptions(),
|
||||
SslConfiguration.unconfigured());
|
||||
|
||||
private final Map<String, String> defaultHeaders = new LinkedHashMap<>();
|
||||
|
||||
@@ -65,7 +65,6 @@ public class WebClientBuilder {
|
||||
|
||||
/**
|
||||
* Create a new {@link WebClientBuilder}.
|
||||
*
|
||||
* @return a new {@link WebClientBuilder}.
|
||||
*/
|
||||
public static WebClientBuilder builder() {
|
||||
@@ -74,7 +73,6 @@ public class WebClientBuilder {
|
||||
|
||||
/**
|
||||
* Set the {@link VaultEndpoint} that should be used with the {@link WebClient}.
|
||||
*
|
||||
* @param endpoint the {@link VaultEndpoint} provider.
|
||||
* @return {@code this} {@link WebClientBuilder}.
|
||||
*/
|
||||
@@ -85,7 +83,6 @@ public class WebClientBuilder {
|
||||
/**
|
||||
* Set the {@link VaultEndpointProvider} that should be used with the
|
||||
* {@link WebClient}.
|
||||
*
|
||||
* @param provider the {@link VaultEndpoint} provider.
|
||||
* @return {@code this} {@link WebClientBuilder}.
|
||||
*/
|
||||
@@ -100,7 +97,6 @@ public class WebClientBuilder {
|
||||
|
||||
/**
|
||||
* Set the {@link ClientHttpConnector} that should be used with the {@link WebClient}.
|
||||
*
|
||||
* @param httpConnector the HTTP connector.
|
||||
* @return {@code this} {@link WebClientBuilder}.
|
||||
*/
|
||||
@@ -114,13 +110,11 @@ public class WebClientBuilder {
|
||||
/**
|
||||
* Set the {@link Supplier} of {@link ClientHttpConnector} that should be called each
|
||||
* time we {@link #build()} a new {@link WebClient} instance.
|
||||
*
|
||||
* @param httpConnector the supplier for the HTTP connector.
|
||||
* @return {@code this} {@link WebClientBuilder}.
|
||||
* @since 2.2.1
|
||||
*/
|
||||
public WebClientBuilder httpConnectorFactory(
|
||||
Supplier<ClientHttpConnector> httpConnector) {
|
||||
public WebClientBuilder httpConnectorFactory(Supplier<ClientHttpConnector> httpConnector) {
|
||||
|
||||
Assert.notNull(httpConnector, "Supplier of ClientHttpConnector must not be null");
|
||||
|
||||
@@ -131,7 +125,6 @@ public class WebClientBuilder {
|
||||
/**
|
||||
* Set the {@link Supplier} of {@link ClientHttpConnector} that should be called each
|
||||
* time we {@link #build()} a new {@link WebClient} instance.
|
||||
*
|
||||
* @param httpConnector the supplier for the HTTP connector.
|
||||
* @return {@code this} {@link WebClientBuilder}.
|
||||
* @deprecated since 2.2.1 as the name is wrong, use
|
||||
@@ -145,7 +138,6 @@ public class WebClientBuilder {
|
||||
/**
|
||||
* Add a default header that will be set if not already present on the outgoing
|
||||
* {@link HttpRequest}.
|
||||
*
|
||||
* @param name the name of the header.
|
||||
* @param value the header value.
|
||||
* @return {@code this} {@link WebClientBuilder}.
|
||||
@@ -162,7 +154,6 @@ public class WebClientBuilder {
|
||||
/**
|
||||
* Add the {@link WebClientCustomizer WebClientCustomizers} that should be applied to
|
||||
* the {@link WebClient}. Customizers are applied in the order that they were added.
|
||||
*
|
||||
* @param customizer the client customizers to add.
|
||||
* @return {@code this} {@link WebClientBuilder}.
|
||||
*/
|
||||
@@ -177,7 +168,6 @@ public class WebClientBuilder {
|
||||
* Add the {@link ExchangeFilterFunction ExchangeFilterFunctions} that should be
|
||||
* applied to the {@link ClientRequest}. {@link ExchangeFilterFunction}s are applied
|
||||
* in the order that they were added.
|
||||
*
|
||||
* @param filterFunctions the request customizers to add.
|
||||
* @return {@code this} {@link WebClientBuilder}.
|
||||
*/
|
||||
@@ -194,23 +184,21 @@ public class WebClientBuilder {
|
||||
*
|
||||
* Applies also {@link ExchangeFilterFunction} and {@link WebClientCustomizer} if
|
||||
* configured.
|
||||
*
|
||||
* @return a new {@link WebClient}.
|
||||
*/
|
||||
public WebClient build() {
|
||||
|
||||
Assert.state(this.endpointProvider != null,
|
||||
"VaultEndpointProvider must not be null");
|
||||
Assert.state(this.endpointProvider != null, "VaultEndpointProvider must not be null");
|
||||
|
||||
WebClient.Builder builder = createWebClientBuilder();
|
||||
|
||||
if (!defaultHeaders.isEmpty()) {
|
||||
if (!this.defaultHeaders.isEmpty()) {
|
||||
|
||||
Map<String, String> defaultHeaders = this.defaultHeaders;
|
||||
builder.filter((request, next) -> {
|
||||
|
||||
return next.exchange(ClientRequest.from(request)
|
||||
.headers(headers -> defaultHeaders.forEach((key, value) -> {
|
||||
return next.exchange(
|
||||
ClientRequest.from(request).headers(headers -> defaultHeaders.forEach((key, value) -> {
|
||||
if (!headers.containsKey(key)) {
|
||||
headers.add(key, value);
|
||||
}
|
||||
@@ -219,23 +207,22 @@ public class WebClientBuilder {
|
||||
});
|
||||
}
|
||||
|
||||
builder.filters(exchangeFilterFunctions -> exchangeFilterFunctions
|
||||
.addAll(this.filterFunctions));
|
||||
builder.filters(exchangeFilterFunctions -> exchangeFilterFunctions.addAll(this.filterFunctions));
|
||||
|
||||
customizers.forEach(customizer -> customizer.customize(builder));
|
||||
this.customizers.forEach(customizer -> customizer.customize(builder));
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the {@link WebClient.Builder} to use.
|
||||
*
|
||||
* @return the {@link WebClient.Builder} to use.
|
||||
*/
|
||||
protected WebClient.Builder createWebClientBuilder() {
|
||||
|
||||
ClientHttpConnector connector = this.httpConnector.get();
|
||||
|
||||
return ReactiveVaultClients.createWebClientBuilder(endpointProvider, connector);
|
||||
return ReactiveVaultClients.createWebClientBuilder(this.endpointProvider, connector);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -29,8 +29,8 @@ public interface WebClientCustomizer {
|
||||
|
||||
/**
|
||||
* Callback to customize a {@link WebClient.Builder} instance.
|
||||
*
|
||||
* @param webClientBuilder the client builder to customize.
|
||||
*/
|
||||
void customize(WebClient.Builder webClientBuilder);
|
||||
|
||||
}
|
||||
|
||||
@@ -61,13 +61,11 @@ import org.springframework.web.reactive.function.client.WebClient;
|
||||
* @since 2.0
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
public abstract class AbstractReactiveVaultConfiguration
|
||||
extends AbstractVaultConfiguration {
|
||||
public abstract class AbstractReactiveVaultConfiguration extends AbstractVaultConfiguration {
|
||||
|
||||
/**
|
||||
* Create a {@link WebClientBuilder} initialized with {@link VaultEndpointProvider}
|
||||
* and {@link ClientHttpConnector}. May be overridden by subclasses.
|
||||
*
|
||||
* @return the {@link WebClientBuilder}.
|
||||
* @see #vaultEndpointProvider()
|
||||
* @see #clientHttpConnector()
|
||||
@@ -75,13 +73,11 @@ public abstract class AbstractReactiveVaultConfiguration
|
||||
*/
|
||||
protected WebClientBuilder webClientBuilder(VaultEndpointProvider endpointProvider,
|
||||
ClientHttpConnector httpConnector) {
|
||||
return WebClientBuilder.builder().endpointProvider(endpointProvider)
|
||||
.httpConnector(httpConnector);
|
||||
return WebClientBuilder.builder().endpointProvider(endpointProvider).httpConnector(httpConnector);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link ReactiveVaultTemplate}.
|
||||
*
|
||||
* @return the {@link ReactiveVaultTemplate}.
|
||||
* @see #vaultEndpoint()
|
||||
* @see #clientHttpConnector()
|
||||
@@ -89,15 +85,13 @@ public abstract class AbstractReactiveVaultConfiguration
|
||||
*/
|
||||
@Bean
|
||||
public ReactiveVaultTemplate reactiveVaultTemplate() {
|
||||
return new ReactiveVaultTemplate(
|
||||
webClientBuilder(vaultEndpointProvider(), clientHttpConnector()),
|
||||
return new ReactiveVaultTemplate(webClientBuilder(vaultEndpointProvider(), clientHttpConnector()),
|
||||
getReactiveSessionManager());
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a session manager adapter wrapping {@link #reactiveSessionManager()} and
|
||||
* exposing imperative {@link SessionManager} on top of a reactive API.
|
||||
*
|
||||
* @return the {@link SessionManager} adapter.
|
||||
*/
|
||||
@Bean
|
||||
@@ -110,7 +104,6 @@ public abstract class AbstractReactiveVaultConfiguration
|
||||
* Construct a {@link ReactiveSessionManager} using {@link #vaultTokenSupplier()}.
|
||||
* This {@link org.springframework.vault.authentication.ReactiveSessionManager} uses
|
||||
* {@link #threadPoolTaskScheduler()}.
|
||||
*
|
||||
* @return the {@link VaultTokenSupplier} for Vault session token management.
|
||||
* @see VaultTokenSupplier
|
||||
* @see #clientAuthentication()
|
||||
@@ -118,15 +111,13 @@ public abstract class AbstractReactiveVaultConfiguration
|
||||
@Bean
|
||||
public ReactiveSessionManager reactiveSessionManager() {
|
||||
|
||||
WebClient webClient = ReactiveVaultClients.createWebClient(vaultEndpoint(),
|
||||
clientHttpConnector());
|
||||
return new ReactiveLifecycleAwareSessionManager(vaultTokenSupplier(),
|
||||
getVaultThreadPoolTaskScheduler(), webClient);
|
||||
WebClient webClient = ReactiveVaultClients.createWebClient(vaultEndpoint(), clientHttpConnector());
|
||||
return new ReactiveLifecycleAwareSessionManager(vaultTokenSupplier(), getVaultThreadPoolTaskScheduler(),
|
||||
webClient);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a {@link VaultTokenSupplier} using {@link #clientAuthentication()}.
|
||||
*
|
||||
* @return the {@link VaultTokenSupplier} for Vault session token management.
|
||||
* @see VaultTokenSupplier
|
||||
* @see #clientAuthentication()
|
||||
@@ -147,8 +138,7 @@ public abstract class AbstractReactiveVaultConfiguration
|
||||
|
||||
AuthenticationStepsFactory factory = (AuthenticationStepsFactory) clientAuthentication;
|
||||
|
||||
WebClient webClient = ReactiveVaultClients.createWebClient(vaultEndpoint(),
|
||||
clientHttpConnector());
|
||||
WebClient webClient = ReactiveVaultClients.createWebClient(vaultEndpoint(), clientHttpConnector());
|
||||
AuthenticationStepsOperator stepsOperator = new AuthenticationStepsOperator(
|
||||
factory.getAuthenticationSteps(), webClient);
|
||||
|
||||
@@ -164,7 +154,6 @@ public abstract class AbstractReactiveVaultConfiguration
|
||||
/**
|
||||
* Create a {@link ClientHttpConnector} configured with {@link ClientOptions} and
|
||||
* {@link org.springframework.vault.support.SslConfiguration}.
|
||||
*
|
||||
* @return the {@link ClientHttpConnector} instance.
|
||||
* @see #clientOptions()
|
||||
* @see #sslConfiguration()
|
||||
@@ -174,8 +163,7 @@ public abstract class AbstractReactiveVaultConfiguration
|
||||
}
|
||||
|
||||
private ReactiveSessionManager getReactiveSessionManager() {
|
||||
return getBeanFactory().getBean("reactiveSessionManager",
|
||||
ReactiveSessionManager.class);
|
||||
return getBeanFactory().getBean("reactiveSessionManager", ReactiveSessionManager.class);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -192,7 +180,9 @@ public abstract class AbstractReactiveVaultConfiguration
|
||||
|
||||
@Override
|
||||
public VaultToken getSessionToken() {
|
||||
return sessionManager.getSessionToken().block(Duration.ofSeconds(30));
|
||||
return this.sessionManager.getSessionToken().block(Duration.ofSeconds(30));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -72,7 +72,6 @@ public abstract class AbstractVaultConfiguration implements ApplicationContextAw
|
||||
* Annotate with {@link Bean} in case you want to expose a
|
||||
* {@link ClientAuthentication} instance to the
|
||||
* {@link org.springframework.context.ApplicationContext}.
|
||||
*
|
||||
* @return the {@link ClientAuthentication} to use. Must not be {@literal null}.
|
||||
*/
|
||||
public abstract ClientAuthentication clientAuthentication();
|
||||
@@ -80,22 +79,18 @@ public abstract class AbstractVaultConfiguration implements ApplicationContextAw
|
||||
/**
|
||||
* Create a {@link RestTemplateBuilder} initialized with {@link VaultEndpointProvider}
|
||||
* and {@link ClientHttpRequestFactory}. May be overridden by subclasses.
|
||||
*
|
||||
* @return the {@link RestTemplateBuilder}.
|
||||
* @see #vaultEndpointProvider()
|
||||
* @see #clientHttpRequestFactoryWrapper()
|
||||
* @since 2.2
|
||||
*/
|
||||
protected RestTemplateBuilder restTemplateBuilder(
|
||||
VaultEndpointProvider endpointProvider,
|
||||
protected RestTemplateBuilder restTemplateBuilder(VaultEndpointProvider endpointProvider,
|
||||
ClientHttpRequestFactory requestFactory) {
|
||||
return RestTemplateBuilder.builder().endpointProvider(endpointProvider)
|
||||
.requestFactory(requestFactory);
|
||||
return RestTemplateBuilder.builder().endpointProvider(endpointProvider).requestFactory(requestFactory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link VaultTemplate}.
|
||||
*
|
||||
* @return the {@link VaultTemplate}.
|
||||
* @see #vaultEndpointProvider()
|
||||
* @see #clientHttpRequestFactoryWrapper()
|
||||
@@ -104,8 +99,7 @@ public abstract class AbstractVaultConfiguration implements ApplicationContextAw
|
||||
@Bean
|
||||
public VaultTemplate vaultTemplate() {
|
||||
return new VaultTemplate(
|
||||
restTemplateBuilder(vaultEndpointProvider(),
|
||||
getClientFactoryWrapper().getClientHttpRequestFactory()),
|
||||
restTemplateBuilder(vaultEndpointProvider(), getClientFactoryWrapper().getClientHttpRequestFactory()),
|
||||
getBeanFactory().getBean("sessionManager", SessionManager.class));
|
||||
}
|
||||
|
||||
@@ -113,7 +107,6 @@ public abstract class AbstractVaultConfiguration implements ApplicationContextAw
|
||||
* Construct a {@link LifecycleAwareSessionManager} using
|
||||
* {@link #clientAuthentication()}. This {@link SessionManager} uses
|
||||
* {@link #threadPoolTaskScheduler()}.
|
||||
*
|
||||
* @return the {@link SessionManager} for Vault session management.
|
||||
* @see SessionManager
|
||||
* @see LifecycleAwareSessionManager
|
||||
@@ -128,14 +121,13 @@ public abstract class AbstractVaultConfiguration implements ApplicationContextAw
|
||||
|
||||
Assert.notNull(clientAuthentication, "ClientAuthentication must not be null");
|
||||
|
||||
return new LifecycleAwareSessionManager(clientAuthentication,
|
||||
getVaultThreadPoolTaskScheduler(), restOperations());
|
||||
return new LifecycleAwareSessionManager(clientAuthentication, getVaultThreadPoolTaskScheduler(),
|
||||
restOperations());
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a {@link SecretLeaseContainer} using {@link #vaultTemplate()} and
|
||||
* {@link #threadPoolTaskScheduler()}.
|
||||
*
|
||||
* @return the {@link SecretLeaseContainer} to allocate, renew and rotate secrets and
|
||||
* their leases.
|
||||
* @see #vaultTemplate()
|
||||
@@ -145,8 +137,7 @@ public abstract class AbstractVaultConfiguration implements ApplicationContextAw
|
||||
public SecretLeaseContainer secretLeaseContainer() throws Exception {
|
||||
|
||||
SecretLeaseContainer secretLeaseContainer = new SecretLeaseContainer(
|
||||
getBeanFactory().getBean("vaultTemplate", VaultTemplate.class),
|
||||
getVaultThreadPoolTaskScheduler());
|
||||
getBeanFactory().getBean("vaultTemplate", VaultTemplate.class), getVaultThreadPoolTaskScheduler());
|
||||
|
||||
secretLeaseContainer.afterPropertiesSet();
|
||||
secretLeaseContainer.start();
|
||||
@@ -162,7 +153,6 @@ public abstract class AbstractVaultConfiguration implements ApplicationContextAw
|
||||
* to the {@link org.springframework.context.ApplicationContext}. This might be useful
|
||||
* to supply managed executor instances or {@link ThreadPoolTaskScheduler}s using a
|
||||
* queue/pooled threads.
|
||||
*
|
||||
* @return the {@link ThreadPoolTaskScheduler} to use. Must not be {@literal null}.
|
||||
*/
|
||||
@Bean("vaultThreadPoolTaskScheduler")
|
||||
@@ -170,8 +160,7 @@ public abstract class AbstractVaultConfiguration implements ApplicationContextAw
|
||||
|
||||
ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
|
||||
|
||||
threadPoolTaskScheduler
|
||||
.setThreadNamePrefix("spring-vault-ThreadPoolTaskScheduler-");
|
||||
threadPoolTaskScheduler.setThreadNamePrefix("spring-vault-ThreadPoolTaskScheduler-");
|
||||
threadPoolTaskScheduler.setDaemon(true);
|
||||
|
||||
return threadPoolTaskScheduler;
|
||||
@@ -181,14 +170,13 @@ public abstract class AbstractVaultConfiguration implements ApplicationContextAw
|
||||
* Construct a {@link RestOperations} object configured for Vault session management
|
||||
* and authentication usage. Can be customized by overriding
|
||||
* {@link #restTemplateBuilder(VaultEndpointProvider, ClientHttpRequestFactory)}.
|
||||
*
|
||||
* @return the {@link RestOperations} to be used for Vault access.
|
||||
* @see #vaultEndpointProvider()
|
||||
* @see #clientHttpRequestFactoryWrapper()
|
||||
*/
|
||||
public RestOperations restOperations() {
|
||||
return restTemplateBuilder(vaultEndpointProvider(),
|
||||
getClientFactoryWrapper().getClientHttpRequestFactory()).build();
|
||||
return restTemplateBuilder(vaultEndpointProvider(), getClientFactoryWrapper().getClientHttpRequestFactory())
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -197,7 +185,6 @@ public abstract class AbstractVaultConfiguration implements ApplicationContextAw
|
||||
* {@link ClientHttpRequestFactory} is configured with {@link ClientOptions} and
|
||||
* {@link SslConfiguration} which are not necessarily applicable for the whole
|
||||
* application.
|
||||
*
|
||||
* @return the {@link ClientFactoryWrapper} to wrap a {@link ClientHttpRequestFactory}
|
||||
* instance.
|
||||
* @see #clientOptions()
|
||||
@@ -205,8 +192,7 @@ public abstract class AbstractVaultConfiguration implements ApplicationContextAw
|
||||
*/
|
||||
@Bean
|
||||
public ClientFactoryWrapper clientHttpRequestFactoryWrapper() {
|
||||
return new ClientFactoryWrapper(ClientHttpRequestFactoryFactory
|
||||
.create(clientOptions(), sslConfiguration()));
|
||||
return new ClientFactoryWrapper(ClientHttpRequestFactoryFactory.create(clientOptions(), sslConfiguration()));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -231,40 +217,36 @@ public abstract class AbstractVaultConfiguration implements ApplicationContextAw
|
||||
* Return the {@link Environment} to access property sources during Spring Vault
|
||||
* bootstrapping. Requires {@link #setApplicationContext(ApplicationContext)
|
||||
* ApplicationContext} to be set.
|
||||
*
|
||||
* @return the {@link Environment} to access property sources during Spring Vault
|
||||
* bootstrapping.
|
||||
*/
|
||||
protected Environment getEnvironment() {
|
||||
|
||||
Assert.state(applicationContext != null,
|
||||
Assert.state(this.applicationContext != null,
|
||||
"ApplicationContext must be set before accessing getEnvironment()");
|
||||
|
||||
return applicationContext.getEnvironment();
|
||||
return this.applicationContext.getEnvironment();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext)
|
||||
throws BeansException {
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
this.applicationContext = applicationContext;
|
||||
}
|
||||
|
||||
BeanFactory getBeanFactory() {
|
||||
|
||||
Assert.state(applicationContext != null,
|
||||
Assert.state(this.applicationContext != null,
|
||||
"ApplicationContext must be set before accessing getBeanFactory()");
|
||||
|
||||
return applicationContext;
|
||||
return this.applicationContext;
|
||||
}
|
||||
|
||||
ThreadPoolTaskScheduler getVaultThreadPoolTaskScheduler() {
|
||||
return getBeanFactory().getBean("vaultThreadPoolTaskScheduler",
|
||||
ThreadPoolTaskScheduler.class);
|
||||
return getBeanFactory().getBean("vaultThreadPoolTaskScheduler", ThreadPoolTaskScheduler.class);
|
||||
}
|
||||
|
||||
private ClientFactoryWrapper getClientFactoryWrapper() {
|
||||
return getBeanFactory().getBean("clientHttpRequestFactoryWrapper",
|
||||
ClientFactoryWrapper.class);
|
||||
return getBeanFactory().getBean("clientHttpRequestFactoryWrapper", ClientFactoryWrapper.class);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -280,21 +262,23 @@ public abstract class AbstractVaultConfiguration implements ApplicationContextAw
|
||||
|
||||
@Override
|
||||
public void destroy() throws Exception {
|
||||
if (clientHttpRequestFactory instanceof DisposableBean) {
|
||||
((DisposableBean) clientHttpRequestFactory).destroy();
|
||||
if (this.clientHttpRequestFactory instanceof DisposableBean) {
|
||||
((DisposableBean) this.clientHttpRequestFactory).destroy();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
|
||||
if (clientHttpRequestFactory instanceof InitializingBean) {
|
||||
((InitializingBean) clientHttpRequestFactory).afterPropertiesSet();
|
||||
if (this.clientHttpRequestFactory instanceof InitializingBean) {
|
||||
((InitializingBean) this.clientHttpRequestFactory).afterPropertiesSet();
|
||||
}
|
||||
}
|
||||
|
||||
public ClientHttpRequestFactory getClientHttpRequestFactory() {
|
||||
return clientHttpRequestFactory;
|
||||
return this.clientHttpRequestFactory;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -36,14 +36,12 @@ public class ClientHttpConnectorFactory {
|
||||
/**
|
||||
* Create a {@link ClientHttpConnector} for the given {@link ClientOptions} and
|
||||
* {@link SslConfiguration}.
|
||||
*
|
||||
* @param options must not be {@literal null}
|
||||
* @param sslConfiguration must not be {@literal null}
|
||||
* @return a new {@link ClientHttpConnector}.
|
||||
*/
|
||||
public static ClientHttpConnector create(ClientOptions options,
|
||||
SslConfiguration sslConfiguration) {
|
||||
return org.springframework.vault.client.ClientHttpConnectorFactory.create(options,
|
||||
sslConfiguration);
|
||||
public static ClientHttpConnector create(ClientOptions options, SslConfiguration sslConfiguration) {
|
||||
return org.springframework.vault.client.ClientHttpConnectorFactory.create(options, sslConfiguration);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -35,15 +35,13 @@ public class ClientHttpRequestFactoryFactory {
|
||||
/**
|
||||
* Create a {@link ClientHttpRequestFactory} for the given {@link ClientOptions} and
|
||||
* {@link SslConfiguration}.
|
||||
*
|
||||
* @param options must not be {@literal null}
|
||||
* @param sslConfiguration must not be {@literal null}
|
||||
* @return a new {@link ClientHttpRequestFactory}. Lifecycle beans must be initialized
|
||||
* after obtaining.
|
||||
*/
|
||||
public static ClientHttpRequestFactory create(ClientOptions options,
|
||||
SslConfiguration sslConfiguration) {
|
||||
return org.springframework.vault.client.ClientHttpRequestFactoryFactory
|
||||
.create(options, sslConfiguration);
|
||||
public static ClientHttpRequestFactory create(ClientOptions options, SslConfiguration sslConfiguration) {
|
||||
return org.springframework.vault.client.ClientHttpRequestFactoryFactory.create(options, sslConfiguration);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -80,8 +80,7 @@ import org.springframework.web.client.RestOperations;
|
||||
* @Import(EnvironmentVaultConfiguration.class)
|
||||
* public class MyConfiguration {
|
||||
* }
|
||||
* </code>
|
||||
* </pre>
|
||||
* </code> </pre>
|
||||
*
|
||||
* Supplied properties:
|
||||
*
|
||||
@@ -89,8 +88,7 @@ import org.springframework.web.client.RestOperations;
|
||||
* <code>
|
||||
* vault.uri=https://localhost:8200
|
||||
* vault.token=00000000-0000-0000-0000-000000000000
|
||||
* </code>
|
||||
* </pre>
|
||||
* </code> </pre>
|
||||
*
|
||||
* <h3>Property keys</h3>
|
||||
*
|
||||
@@ -185,13 +183,12 @@ import org.springframework.web.client.RestOperations;
|
||||
* @see KubernetesAuthentication
|
||||
*/
|
||||
@Configuration
|
||||
public class EnvironmentVaultConfiguration extends AbstractVaultConfiguration
|
||||
implements ApplicationContextAware {
|
||||
public class EnvironmentVaultConfiguration extends AbstractVaultConfiguration implements ApplicationContextAware {
|
||||
|
||||
private static final Log logger = LogFactory
|
||||
.getLog(EnvironmentVaultConfiguration.class);
|
||||
private static final Log logger = LogFactory.getLog(EnvironmentVaultConfiguration.class);
|
||||
|
||||
private @Nullable RestOperations cachedRestOperations;
|
||||
|
||||
private @Nullable ApplicationContext applicationContext;
|
||||
|
||||
@Override
|
||||
@@ -206,8 +203,7 @@ public class EnvironmentVaultConfiguration extends AbstractVaultConfiguration
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext)
|
||||
throws BeansException {
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
|
||||
this.applicationContext = applicationContext;
|
||||
super.setApplicationContext(applicationContext);
|
||||
@@ -227,17 +223,16 @@ public class EnvironmentVaultConfiguration extends AbstractVaultConfiguration
|
||||
@Override
|
||||
public SslConfiguration sslConfiguration() {
|
||||
|
||||
KeyStoreConfiguration keyStoreConfiguration = getKeyStoreConfiguration(
|
||||
"vault.ssl.key-store", "vault.ssl.key-store-password");
|
||||
KeyStoreConfiguration keyStoreConfiguration = getKeyStoreConfiguration("vault.ssl.key-store",
|
||||
"vault.ssl.key-store-password");
|
||||
|
||||
KeyStoreConfiguration trustStoreConfiguration = getKeyStoreConfiguration(
|
||||
"vault.ssl.trust-store", "vault.ssl.trust-store-password");
|
||||
KeyStoreConfiguration trustStoreConfiguration = getKeyStoreConfiguration("vault.ssl.trust-store",
|
||||
"vault.ssl.trust-store-password");
|
||||
|
||||
return new SslConfiguration(keyStoreConfiguration, trustStoreConfiguration);
|
||||
}
|
||||
|
||||
private KeyStoreConfiguration getKeyStoreConfiguration(String resourceProperty,
|
||||
String passwordProperty) {
|
||||
private KeyStoreConfiguration getKeyStoreConfiguration(String resourceProperty, String passwordProperty) {
|
||||
|
||||
Resource keyStore = getResource(resourceProperty);
|
||||
String keyStorePassword = getProperty(passwordProperty);
|
||||
@@ -256,11 +251,10 @@ public class EnvironmentVaultConfiguration extends AbstractVaultConfiguration
|
||||
@Override
|
||||
public ClientAuthentication clientAuthentication() {
|
||||
|
||||
String authentication = getProperty("vault.authentication",
|
||||
AuthenticationMethod.TOKEN.name()).toUpperCase().replace('-', '_');
|
||||
String authentication = getProperty("vault.authentication", AuthenticationMethod.TOKEN.name()).toUpperCase()
|
||||
.replace('-', '_');
|
||||
|
||||
AuthenticationMethod authenticationMethod = AuthenticationMethod
|
||||
.valueOf(authentication);
|
||||
AuthenticationMethod authenticationMethod = AuthenticationMethod.valueOf(authentication);
|
||||
|
||||
switch (authenticationMethod) {
|
||||
|
||||
@@ -281,8 +275,7 @@ public class EnvironmentVaultConfiguration extends AbstractVaultConfiguration
|
||||
case KUBERNETES:
|
||||
return kubeAuthentication();
|
||||
default:
|
||||
throw new IllegalStateException(String.format(
|
||||
"Vault authentication method %s is not supported with %s",
|
||||
throw new IllegalStateException(String.format("Vault authentication method %s is not supported with %s",
|
||||
authenticationMethod, getClass().getSimpleName()));
|
||||
}
|
||||
}
|
||||
@@ -294,27 +287,23 @@ public class EnvironmentVaultConfiguration extends AbstractVaultConfiguration
|
||||
protected ClientAuthentication tokenAuthentication() {
|
||||
|
||||
String token = getProperty("vault.token");
|
||||
Assert.hasText(token,
|
||||
"Vault Token authentication: Token (vault.token) must not be empty");
|
||||
Assert.hasText(token, "Vault Token authentication: Token (vault.token) must not be empty");
|
||||
|
||||
return new TokenAuthentication(token);
|
||||
}
|
||||
|
||||
protected ClientAuthentication appIdAuthentication() {
|
||||
|
||||
String appId = getProperty("vault.app-id.app-id",
|
||||
getProperty("spring.application.name"));
|
||||
String appId = getProperty("vault.app-id.app-id", getProperty("spring.application.name"));
|
||||
String userId = getProperty("vault.app-id.user-id");
|
||||
String path = getProperty("vault.app-id.app-id-path",
|
||||
AppIdAuthenticationOptions.DEFAULT_APPID_AUTHENTICATION_PATH);
|
||||
|
||||
Assert.hasText(appId,
|
||||
"Vault AppId authentication: AppId (vault.app-id.app-id) must not be empty");
|
||||
Assert.hasText(userId,
|
||||
"Vault AppId authentication: UserId (vault.app-id.user-id) must not be empty");
|
||||
Assert.hasText(appId, "Vault AppId authentication: AppId (vault.app-id.app-id) must not be empty");
|
||||
Assert.hasText(userId, "Vault AppId authentication: UserId (vault.app-id.user-id) must not be empty");
|
||||
|
||||
AppIdAuthenticationOptionsBuilder builder = AppIdAuthenticationOptions.builder()
|
||||
.appId(appId).userIdMechanism(getAppIdUserIdMechanism(userId)).path(path);
|
||||
AppIdAuthenticationOptionsBuilder builder = AppIdAuthenticationOptions.builder().appId(appId)
|
||||
.userIdMechanism(getAppIdUserIdMechanism(userId)).path(path);
|
||||
|
||||
return new AppIdAuthentication(builder.build(), restOperations());
|
||||
}
|
||||
@@ -326,11 +315,10 @@ public class EnvironmentVaultConfiguration extends AbstractVaultConfiguration
|
||||
String path = getProperty("vault.app-role.app-role-path",
|
||||
AppRoleAuthenticationOptions.DEFAULT_APPROLE_AUTHENTICATION_PATH);
|
||||
|
||||
Assert.hasText(roleId,
|
||||
"Vault AppRole authentication: RoleId (vault.app-role.role-id) must not be empty");
|
||||
Assert.hasText(roleId, "Vault AppRole authentication: RoleId (vault.app-role.role-id) must not be empty");
|
||||
|
||||
AppRoleAuthenticationOptionsBuilder builder = AppRoleAuthenticationOptions
|
||||
.builder().roleId(RoleId.provided(roleId)).path(path);
|
||||
AppRoleAuthenticationOptionsBuilder builder = AppRoleAuthenticationOptions.builder()
|
||||
.roleId(RoleId.provided(roleId)).path(path);
|
||||
|
||||
if (StringUtils.hasText(secretId)) {
|
||||
builder = builder.secretId(SecretId.provided(secretId));
|
||||
@@ -364,9 +352,8 @@ public class EnvironmentVaultConfiguration extends AbstractVaultConfiguration
|
||||
"Vault AWS-EC2 authentication: Role (vault.aws-ec2.role) must not be empty");
|
||||
|
||||
if (StringUtils.hasText(roleId) && StringUtils.hasText(role)) {
|
||||
throw new IllegalStateException(
|
||||
"AWS-EC2 Authentication: Only one of Role (vault.aws-ec2.role) or"
|
||||
+ " RoleId (deprecated, vault.aws-ec2.roleId) must be provided");
|
||||
throw new IllegalStateException("AWS-EC2 Authentication: Only one of Role (vault.aws-ec2.role) or"
|
||||
+ " RoleId (deprecated, vault.aws-ec2.roleId) must be provided");
|
||||
}
|
||||
|
||||
if (StringUtils.hasText(roleId)) {
|
||||
@@ -381,8 +368,7 @@ public class EnvironmentVaultConfiguration extends AbstractVaultConfiguration
|
||||
builder.identityDocumentUri(URI.create(identityDocument));
|
||||
}
|
||||
|
||||
return new AwsEc2Authentication(builder.build(), restOperations(),
|
||||
restOperations());
|
||||
return new AwsEc2Authentication(builder.build(), restOperations(), restOperations());
|
||||
}
|
||||
|
||||
protected ClientAuthentication azureMsiAuthentication() {
|
||||
@@ -394,12 +380,10 @@ public class EnvironmentVaultConfiguration extends AbstractVaultConfiguration
|
||||
AzureMsiAuthenticationOptions.DEFAULT_INSTANCE_METADATA_SERVICE_URI);
|
||||
URI identityTokenServiceUri = getUri("vault.azure-msi.identity-token-service",
|
||||
AzureMsiAuthenticationOptions.DEFAULT_IDENTITY_TOKEN_SERVICE_URI);
|
||||
Assert.hasText(role,
|
||||
"Vault Azure MSI authentication: Role (vault.azure-msi.role) must not be empty");
|
||||
Assert.hasText(role, "Vault Azure MSI authentication: Role (vault.azure-msi.role) must not be empty");
|
||||
|
||||
AzureMsiAuthenticationOptionsBuilder builder = AzureMsiAuthenticationOptions
|
||||
.builder().role(role).path(path).instanceMetadataUri(metadataServiceUri)
|
||||
.identityTokenServiceUri(identityTokenServiceUri);
|
||||
AzureMsiAuthenticationOptionsBuilder builder = AzureMsiAuthenticationOptions.builder().role(role).path(path)
|
||||
.instanceMetadataUri(metadataServiceUri).identityTokenServiceUri(identityTokenServiceUri);
|
||||
|
||||
return new AzureMsiAuthentication(builder.build(), restOperations());
|
||||
}
|
||||
@@ -407,11 +391,10 @@ public class EnvironmentVaultConfiguration extends AbstractVaultConfiguration
|
||||
protected ClientAuthentication cubbyholeAuthentication() {
|
||||
|
||||
String token = getProperty("vault.token");
|
||||
Assert.hasText(token,
|
||||
"Vault Cubbyhole authentication: Initial token (vault.token) must not be empty");
|
||||
Assert.hasText(token, "Vault Cubbyhole authentication: Initial token (vault.token) must not be empty");
|
||||
|
||||
CubbyholeAuthenticationOptionsBuilder builder = CubbyholeAuthenticationOptions
|
||||
.builder().wrapped().initialToken(VaultToken.of(token));
|
||||
CubbyholeAuthenticationOptionsBuilder builder = CubbyholeAuthenticationOptions.builder().wrapped()
|
||||
.initialToken(VaultToken.of(token));
|
||||
|
||||
return new CubbyholeAuthentication(builder.build(), restOperations());
|
||||
}
|
||||
@@ -426,11 +409,10 @@ public class EnvironmentVaultConfiguration extends AbstractVaultConfiguration
|
||||
|
||||
Assert.hasText(role, "Vault Kubernetes authentication: role must not be empty");
|
||||
|
||||
KubernetesJwtSupplier jwtSupplier = new KubernetesServiceAccountTokenFile(
|
||||
tokenFile);
|
||||
KubernetesJwtSupplier jwtSupplier = new KubernetesServiceAccountTokenFile(tokenFile);
|
||||
|
||||
KubernetesAuthenticationOptionsBuilder builder = KubernetesAuthenticationOptions
|
||||
.builder().role(role).jwtSupplier(jwtSupplier).path(path);
|
||||
KubernetesAuthenticationOptionsBuilder builder = KubernetesAuthenticationOptions.builder().role(role)
|
||||
.jwtSupplier(jwtSupplier).path(path);
|
||||
|
||||
return new KubernetesAuthentication(builder.build(), restOperations());
|
||||
}
|
||||
@@ -452,14 +434,19 @@ public class EnvironmentVaultConfiguration extends AbstractVaultConfiguration
|
||||
private Resource getResource(String key) {
|
||||
|
||||
String value = getProperty(key);
|
||||
return value != null ? applicationContext.getResource(value) : null;
|
||||
return value != null ? this.applicationContext.getResource(value) : null;
|
||||
}
|
||||
|
||||
enum AppIdUserId {
|
||||
|
||||
IP_ADDRESS, MAC_ADDRESS;
|
||||
|
||||
}
|
||||
|
||||
enum AuthenticationMethod {
|
||||
|
||||
TOKEN, APPID, APPROLE, AWS_EC2, AZURE, CERT, CUBBYHOLE, KUBERNETES;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -52,7 +52,6 @@ public interface ReactiveVaultOperations {
|
||||
/**
|
||||
* Read from a Vault path. Reading data using this method is suitable for API
|
||||
* calls/secret backends that do not require a request body.
|
||||
*
|
||||
* @param path must not be {@literal null}.
|
||||
* @return the data. May be empty if the path does not exist.
|
||||
*/
|
||||
@@ -61,7 +60,6 @@ public interface ReactiveVaultOperations {
|
||||
/**
|
||||
* Read from a Vault path. Reading data using this method is suitable for API
|
||||
* calls/secret backends that do not require a request body.
|
||||
*
|
||||
* @param path must not be {@literal null}.
|
||||
* @param responseType must not be {@literal null}.
|
||||
* @return the data. May be empty if the path does not exist.
|
||||
@@ -70,7 +68,6 @@ public interface ReactiveVaultOperations {
|
||||
|
||||
/**
|
||||
* Enumerate keys from a Vault path.
|
||||
*
|
||||
* @param path must not be {@literal null}.
|
||||
* @return the data. May be empty if the path does not exist.
|
||||
*/
|
||||
@@ -78,7 +75,6 @@ public interface ReactiveVaultOperations {
|
||||
|
||||
/**
|
||||
* Write to a Vault path.
|
||||
*
|
||||
* @param path must not be {@literal null}.
|
||||
* @return the response. May be empty if the response has no body.
|
||||
*/
|
||||
@@ -88,7 +84,6 @@ public interface ReactiveVaultOperations {
|
||||
|
||||
/**
|
||||
* Write to a Vault path.
|
||||
*
|
||||
* @param path must not be {@literal null}.
|
||||
* @param body the body, may be {@literal null} if absent.
|
||||
* @return the response. May be empty if the response has no body.
|
||||
@@ -97,7 +92,6 @@ public interface ReactiveVaultOperations {
|
||||
|
||||
/**
|
||||
* Delete a path.
|
||||
*
|
||||
* @param path must not be {@literal null}.
|
||||
*/
|
||||
Mono<Void> delete(String path);
|
||||
@@ -106,30 +100,27 @@ public interface ReactiveVaultOperations {
|
||||
* Executes a Vault {@link RestOperationsCallback}. Allows to interact with Vault
|
||||
* using {@link org.springframework.web.client.RestOperations} without requiring a
|
||||
* session.
|
||||
*
|
||||
* @param clientCallback the request.
|
||||
* @return the {@link RestOperationsCallback} return value.
|
||||
* @throws VaultException when a
|
||||
* {@link org.springframework.web.client.HttpStatusCodeException} occurs.
|
||||
* {@link org.springframework.web.client.HttpStatusCodeException} occurs.
|
||||
* @throws WebClientException exceptions from
|
||||
* {@link org.springframework.web.reactive.function.client.WebClient}.
|
||||
* {@link org.springframework.web.reactive.function.client.WebClient}.
|
||||
*/
|
||||
<V, T extends Publisher<V>> T doWithVault(
|
||||
Function<WebClient, ? extends T> clientCallback)
|
||||
<V, T extends Publisher<V>> T doWithVault(Function<WebClient, ? extends T> clientCallback)
|
||||
throws VaultException, WebClientException;
|
||||
|
||||
/**
|
||||
* Executes a Vault {@link RestOperationsCallback}. Allows to interact with Vault in
|
||||
* an authenticated session.
|
||||
*
|
||||
* @param sessionCallback the request.
|
||||
* @return the {@link RestOperationsCallback} return value.
|
||||
* @throws VaultException when a
|
||||
* {@link org.springframework.web.client.HttpStatusCodeException} occurs.
|
||||
* {@link org.springframework.web.client.HttpStatusCodeException} occurs.
|
||||
* @throws WebClientException exceptions from
|
||||
* {@link org.springframework.web.reactive.function.client.WebClient}.
|
||||
* {@link org.springframework.web.reactive.function.client.WebClient}.
|
||||
*/
|
||||
<V, T extends Publisher<V>> T doWithSession(
|
||||
Function<WebClient, ? extends T> sessionCallback)
|
||||
<V, T extends Publisher<V>> T doWithSession(Function<WebClient, ? extends T> sessionCallback)
|
||||
throws VaultException, WebClientException;
|
||||
|
||||
}
|
||||
|
||||
@@ -75,28 +75,24 @@ public class ReactiveVaultTemplate implements ReactiveVaultOperations {
|
||||
* {@link VaultTokenSupplier}. It is intended for usage with Vault Agent to inherit
|
||||
* Vault Agent's authentication without using the {@link VaultHttpHeaders#VAULT_TOKEN
|
||||
* authentication token header}.
|
||||
*
|
||||
* @param vaultEndpoint must not be {@literal null}.
|
||||
* @param connector must not be {@literal null}.
|
||||
* @since 2.2.1
|
||||
*/
|
||||
public ReactiveVaultTemplate(VaultEndpoint vaultEndpoint,
|
||||
ClientHttpConnector connector) {
|
||||
public ReactiveVaultTemplate(VaultEndpoint vaultEndpoint, ClientHttpConnector connector) {
|
||||
this(SimpleVaultEndpointProvider.of(vaultEndpoint), connector);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link ReactiveVaultTemplate} with a {@link VaultEndpoint},
|
||||
* {@link ClientHttpConnector} and {@link VaultTokenSupplier}.
|
||||
*
|
||||
* @param vaultEndpoint must not be {@literal null}.
|
||||
* @param connector must not be {@literal null}.
|
||||
* @param vaultTokenSupplier must not be {@literal null}.
|
||||
*/
|
||||
public ReactiveVaultTemplate(VaultEndpoint vaultEndpoint,
|
||||
ClientHttpConnector connector, VaultTokenSupplier vaultTokenSupplier) {
|
||||
this(SimpleVaultEndpointProvider.of(vaultEndpoint), connector,
|
||||
vaultTokenSupplier);
|
||||
public ReactiveVaultTemplate(VaultEndpoint vaultEndpoint, ClientHttpConnector connector,
|
||||
VaultTokenSupplier vaultTokenSupplier) {
|
||||
this(SimpleVaultEndpointProvider.of(vaultEndpoint), connector, vaultTokenSupplier);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -105,13 +101,11 @@ public class ReactiveVaultTemplate implements ReactiveVaultOperations {
|
||||
* {@link VaultTokenSupplier}. It is intended for usage with Vault Agent to inherit
|
||||
* Vault Agent's authentication without using the {@link VaultHttpHeaders#VAULT_TOKEN
|
||||
* authentication token header}.
|
||||
*
|
||||
* @param endpointProvider must not be {@literal null}.
|
||||
* @param connector must not be {@literal null}.
|
||||
* @since 2.2.1
|
||||
*/
|
||||
public ReactiveVaultTemplate(VaultEndpointProvider endpointProvider,
|
||||
ClientHttpConnector connector) {
|
||||
public ReactiveVaultTemplate(VaultEndpointProvider endpointProvider, ClientHttpConnector connector) {
|
||||
|
||||
Assert.notNull(endpointProvider, "VaultEndpointProvider must not be null");
|
||||
Assert.notNull(connector, "ClientHttpConnector must not be null");
|
||||
@@ -126,13 +120,12 @@ public class ReactiveVaultTemplate implements ReactiveVaultOperations {
|
||||
/**
|
||||
* Create a new {@link ReactiveVaultTemplate} with a {@link VaultEndpointProvider},
|
||||
* {@link ClientHttpConnector} and {@link VaultTokenSupplier}.
|
||||
*
|
||||
* @param endpointProvider must not be {@literal null}.
|
||||
* @param connector must not be {@literal null}.
|
||||
* @param vaultTokenSupplier must not be {@literal null}.
|
||||
*/
|
||||
public ReactiveVaultTemplate(VaultEndpointProvider endpointProvider,
|
||||
ClientHttpConnector connector, VaultTokenSupplier vaultTokenSupplier) {
|
||||
public ReactiveVaultTemplate(VaultEndpointProvider endpointProvider, ClientHttpConnector connector,
|
||||
VaultTokenSupplier vaultTokenSupplier) {
|
||||
|
||||
Assert.notNull(endpointProvider, "VaultEndpointProvider must not be null");
|
||||
Assert.notNull(connector, "ClientHttpConnector must not be null");
|
||||
@@ -148,7 +141,6 @@ public class ReactiveVaultTemplate implements ReactiveVaultOperations {
|
||||
* constructor does not use a {@link VaultTokenSupplier}. It is intended for usage
|
||||
* with Vault Agent to inherit Vault Agent's authentication without using the
|
||||
* {@link VaultHttpHeaders#VAULT_TOKEN authentication token header}.
|
||||
*
|
||||
* @param webClientBuilder must not be {@literal null}.
|
||||
* @since 2.2.1
|
||||
*/
|
||||
@@ -166,21 +158,18 @@ public class ReactiveVaultTemplate implements ReactiveVaultOperations {
|
||||
/**
|
||||
* Create a new {@link ReactiveVaultTemplate} through a {@link WebClientBuilder}, and
|
||||
* {@link VaultTokenSupplier}.
|
||||
*
|
||||
* @param webClientBuilder must not be {@literal null}.
|
||||
* @param vaultTokenSupplier must not be {@literal null}
|
||||
* @since 2.2
|
||||
*/
|
||||
public ReactiveVaultTemplate(WebClientBuilder webClientBuilder,
|
||||
VaultTokenSupplier vaultTokenSupplier) {
|
||||
public ReactiveVaultTemplate(WebClientBuilder webClientBuilder, VaultTokenSupplier vaultTokenSupplier) {
|
||||
|
||||
Assert.notNull(webClientBuilder, "WebClientBuilder must not be null");
|
||||
Assert.notNull(vaultTokenSupplier, "VaultTokenSupplier must not be null");
|
||||
|
||||
this.vaultTokenSupplier = vaultTokenSupplier;
|
||||
this.statelessClient = webClientBuilder.build();
|
||||
this.sessionClient = webClientBuilder.build().mutate().filter(getSessionFilter())
|
||||
.build();
|
||||
this.sessionClient = webClientBuilder.build().mutate().filter(getSessionFilter()).build();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -189,20 +178,17 @@ public class ReactiveVaultTemplate implements ReactiveVaultOperations {
|
||||
* {@link VaultEndpointProvider} is used to contribute host and port details for
|
||||
* relative URLs typically used by the Template API. Subclasses may override this
|
||||
* method to customize the {@link WebClient}.
|
||||
*
|
||||
* @param endpointProvider must not be {@literal null}.
|
||||
* @param connector must not be {@literal null}.
|
||||
* @return the {@link WebClient} used for Vault communication.
|
||||
* @since 2.1
|
||||
*/
|
||||
protected WebClient doCreateWebClient(VaultEndpointProvider endpointProvider,
|
||||
ClientHttpConnector connector) {
|
||||
protected WebClient doCreateWebClient(VaultEndpointProvider endpointProvider, ClientHttpConnector connector) {
|
||||
|
||||
Assert.notNull(endpointProvider, "VaultEndpointProvider must not be null");
|
||||
Assert.notNull(connector, "ClientHttpConnector must not be null");
|
||||
|
||||
return WebClientBuilder.builder().httpConnector(connector)
|
||||
.endpointProvider(endpointProvider).build();
|
||||
return WebClientBuilder.builder().httpConnector(connector).endpointProvider(endpointProvider).build();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -212,7 +198,6 @@ public class ReactiveVaultTemplate implements ReactiveVaultOperations {
|
||||
* {@link VaultEndpointProvider} is used to contribute host and port details for
|
||||
* relative URLs typically used by the Template API. Subclasses may override this
|
||||
* method to customize the {@link WebClient}.
|
||||
*
|
||||
* @param endpointProvider must not be {@literal null}.
|
||||
* @param connector must not be {@literal null}.
|
||||
* @return the {@link WebClient} used for Vault communication.
|
||||
@@ -226,19 +211,18 @@ public class ReactiveVaultTemplate implements ReactiveVaultOperations {
|
||||
|
||||
ExchangeFilterFunction filter = getSessionFilter();
|
||||
|
||||
return WebClientBuilder.builder().httpConnector(connector)
|
||||
.endpointProvider(endpointProvider).filter(filter).build();
|
||||
return WebClientBuilder.builder().httpConnector(connector).endpointProvider(endpointProvider).filter(filter)
|
||||
.build();
|
||||
}
|
||||
|
||||
private ExchangeFilterFunction getSessionFilter() {
|
||||
|
||||
return ofRequestProcessor(
|
||||
request -> vaultTokenSupplier.getVaultToken().map(token -> {
|
||||
return ofRequestProcessor(request -> this.vaultTokenSupplier.getVaultToken().map(token -> {
|
||||
|
||||
return ClientRequest.from(request).headers(headers -> {
|
||||
headers.set(VaultHttpHeaders.VAULT_TOKEN, token.getToken());
|
||||
}).build();
|
||||
}));
|
||||
return ClientRequest.from(request).headers(headers -> {
|
||||
headers.set(VaultHttpHeaders.VAULT_TOKEN, token.getToken());
|
||||
}).build();
|
||||
}));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -254,11 +238,9 @@ public class ReactiveVaultTemplate implements ReactiveVaultOperations {
|
||||
|
||||
return doWithSession(webClient -> {
|
||||
|
||||
ParameterizedTypeReference<VaultResponseSupport<T>> ref = VaultResponses
|
||||
.getTypeReference(responseType);
|
||||
ParameterizedTypeReference<VaultResponseSupport<T>> ref = VaultResponses.getTypeReference(responseType);
|
||||
|
||||
return webClient.get().uri(path).exchange()
|
||||
.flatMap(mapResponse(ref, path, HttpMethod.GET));
|
||||
return webClient.get().uri(path).exchange().flatMap(mapResponse(ref, path, HttpMethod.GET));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -268,15 +250,11 @@ public class ReactiveVaultTemplate implements ReactiveVaultOperations {
|
||||
|
||||
Assert.hasText(path, "Path must not be empty");
|
||||
|
||||
Mono<VaultListResponse> read = doRead(
|
||||
String.format("%s?list=true", path.endsWith("/") ? path : (path + "/")),
|
||||
Mono<VaultListResponse> read = doRead(String.format("%s?list=true", path.endsWith("/") ? path : (path + "/")),
|
||||
VaultListResponse.class);
|
||||
|
||||
return read
|
||||
.filter(response -> response.getData() != null
|
||||
&& response.getData().containsKey("keys"))
|
||||
.flatMapIterable(response -> (List<String>) response.getRequiredData()
|
||||
.get("keys"));
|
||||
return read.filter(response -> response.getData() != null && response.getData().containsKey("keys"))
|
||||
.flatMapIterable(response -> (List<String>) response.getRequiredData().get("keys"));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -294,8 +272,7 @@ public class ReactiveVaultTemplate implements ReactiveVaultOperations {
|
||||
else {
|
||||
exchange = uri.exchange();
|
||||
}
|
||||
return exchange
|
||||
.flatMap(mapResponse(VaultResponse.class, path, HttpMethod.POST));
|
||||
return exchange.flatMap(mapResponse(VaultResponse.class, path, HttpMethod.POST));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -309,14 +286,13 @@ public class ReactiveVaultTemplate implements ReactiveVaultOperations {
|
||||
}
|
||||
|
||||
@Override
|
||||
public <V, T extends Publisher<V>> T doWithVault(
|
||||
Function<WebClient, ? extends T> clientCallback)
|
||||
public <V, T extends Publisher<V>> T doWithVault(Function<WebClient, ? extends T> clientCallback)
|
||||
throws VaultException, WebClientException {
|
||||
|
||||
Assert.notNull(clientCallback, "Client callback must not be null");
|
||||
|
||||
try {
|
||||
return (T) clientCallback.apply(statelessClient);
|
||||
return (T) clientCallback.apply(this.statelessClient);
|
||||
}
|
||||
catch (HttpStatusCodeException e) {
|
||||
throw VaultResponses.buildException(e);
|
||||
@@ -324,14 +300,13 @@ public class ReactiveVaultTemplate implements ReactiveVaultOperations {
|
||||
}
|
||||
|
||||
@Override
|
||||
public <V, T extends Publisher<V>> T doWithSession(
|
||||
Function<WebClient, ? extends T> sessionCallback)
|
||||
public <V, T extends Publisher<V>> T doWithSession(Function<WebClient, ? extends T> sessionCallback)
|
||||
throws VaultException, WebClientException {
|
||||
|
||||
Assert.notNull(sessionCallback, "Session callback must not be null");
|
||||
|
||||
try {
|
||||
return (T) sessionCallback.apply(sessionClient);
|
||||
return (T) sessionCallback.apply(this.sessionClient);
|
||||
}
|
||||
catch (HttpStatusCodeException e) {
|
||||
throw VaultResponses.buildException(e);
|
||||
@@ -341,21 +316,18 @@ public class ReactiveVaultTemplate implements ReactiveVaultOperations {
|
||||
private <T> Mono<T> doRead(String path, Class<T> responseType) {
|
||||
|
||||
return doWithSession(client -> client.get() //
|
||||
.uri(path).exchange()
|
||||
.flatMap(mapResponse(responseType, path, HttpMethod.GET)));
|
||||
.uri(path).exchange().flatMap(mapResponse(responseType, path, HttpMethod.GET)));
|
||||
}
|
||||
|
||||
private static <T> Function<ClientResponse, Mono<? extends T>> mapResponse(
|
||||
Class<T> bodyType, String path, HttpMethod method) {
|
||||
return response -> isSuccess(response) ? response.bodyToMono(bodyType)
|
||||
: mapOtherwise(response, path, method);
|
||||
private static <T> Function<ClientResponse, Mono<? extends T>> mapResponse(Class<T> bodyType, String path,
|
||||
HttpMethod method) {
|
||||
return response -> isSuccess(response) ? response.bodyToMono(bodyType) : mapOtherwise(response, path, method);
|
||||
}
|
||||
|
||||
private static <T> Function<ClientResponse, Mono<? extends T>> mapResponse(
|
||||
ParameterizedTypeReference<T> typeReference, String path, HttpMethod method) {
|
||||
|
||||
return response -> isSuccess(response)
|
||||
? response.body(BodyExtractors.toMono(typeReference))
|
||||
return response -> isSuccess(response) ? response.body(BodyExtractors.toMono(typeReference))
|
||||
: mapOtherwise(response, path, method);
|
||||
}
|
||||
|
||||
@@ -363,8 +335,7 @@ public class ReactiveVaultTemplate implements ReactiveVaultOperations {
|
||||
return response.statusCode().is2xxSuccessful();
|
||||
}
|
||||
|
||||
private static <T> Mono<? extends T> mapOtherwise(ClientResponse response,
|
||||
String path, HttpMethod method) {
|
||||
private static <T> Mono<? extends T> mapOtherwise(ClientResponse response, String path, HttpMethod method) {
|
||||
|
||||
if (response.statusCode() == HttpStatus.NOT_FOUND && method == HttpMethod.GET) {
|
||||
return Mono.empty();
|
||||
@@ -374,22 +345,23 @@ public class ReactiveVaultTemplate implements ReactiveVaultOperations {
|
||||
|
||||
String error = VaultResponses.getError(body);
|
||||
|
||||
return Mono.error(
|
||||
VaultResponses.buildException(response.statusCode(), path, error));
|
||||
return Mono.error(VaultResponses.buildException(response.statusCode(), path, error));
|
||||
});
|
||||
}
|
||||
|
||||
private static class VaultListResponse
|
||||
extends VaultResponseSupport<Map<String, Object>> {
|
||||
private static class VaultListResponse extends VaultResponseSupport<Map<String, Object>> {
|
||||
|
||||
}
|
||||
|
||||
private enum NoTokenSupplier implements VaultTokenSupplier {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@Override
|
||||
public Mono<VaultToken> getVaultToken() {
|
||||
return Mono
|
||||
.error(new UnsupportedOperationException("Token retrieval disabled"));
|
||||
return Mono.error(new UnsupportedOperationException("Token retrieval disabled"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user