Remove VaultClient in favor of RestOperations.
Remove VaultClient from VaultTemplate and switch implementations to use RestOperations directly. VaultClient provided an additional abstraction level over RestTemplate with a large API surface adding only little value. Implementations work directly with RestOperations. Relative URI expansion is handled by DefaultUriTemplateHandler configured with the VaultEndpoint base URI. Closes gh-49. Original pull request: gh-57.
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
* Copyright 2016-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -13,7 +13,7 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.vault.client;
|
||||
package org.springframework.vault;
|
||||
|
||||
import org.springframework.core.NestedRuntimeException;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
* Copyright 2016-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -22,11 +22,12 @@ import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.vault.client.VaultClient;
|
||||
import org.springframework.vault.client.VaultException;
|
||||
import org.springframework.vault.client.VaultResponseEntity;
|
||||
import org.springframework.vault.VaultException;
|
||||
import org.springframework.vault.client.VaultResponses;
|
||||
import org.springframework.vault.support.VaultResponse;
|
||||
import org.springframework.vault.support.VaultToken;
|
||||
import org.springframework.web.client.HttpStatusCodeException;
|
||||
import org.springframework.web.client.RestOperations;
|
||||
|
||||
/**
|
||||
* AppId implementation of {@link ClientAuthentication}. {@link AppIdAuthentication} uses
|
||||
@@ -35,7 +36,7 @@ import org.springframework.vault.support.VaultToken;
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @see AppIdAuthenticationOptions
|
||||
* @see VaultClient
|
||||
* @see RestOperations
|
||||
* @see <a href="https://www.vaultproject.io/docs/auth/app-id.html">Auth Backend: App
|
||||
* ID</a>
|
||||
*/
|
||||
@@ -45,22 +46,23 @@ public class AppIdAuthentication implements ClientAuthentication {
|
||||
|
||||
private final AppIdAuthenticationOptions options;
|
||||
|
||||
private final VaultClient vaultClient;
|
||||
private final RestOperations restOperations;
|
||||
|
||||
/**
|
||||
* Creates a {@link AppIdAuthentication} using {@link AppIdAuthenticationOptions} and
|
||||
* {@link VaultClient}.
|
||||
* {@link RestOperations}.
|
||||
*
|
||||
* @param options must not be {@literal null}.
|
||||
* @param vaultClient must not be {@literal null}.
|
||||
* @param restOperations must not be {@literal null}.
|
||||
*/
|
||||
public AppIdAuthentication(AppIdAuthenticationOptions options, VaultClient vaultClient) {
|
||||
public AppIdAuthentication(AppIdAuthenticationOptions options,
|
||||
RestOperations restOperations) {
|
||||
|
||||
Assert.notNull(options, "AppIdAuthenticationOptions must not be null");
|
||||
Assert.notNull(vaultClient, "VaultClient must not be null");
|
||||
Assert.notNull(restOperations, "RestOperations must not be null");
|
||||
|
||||
this.options = options;
|
||||
this.vaultClient = vaultClient;
|
||||
this.restOperations = restOperations;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -73,18 +75,18 @@ public class AppIdAuthentication implements ClientAuthentication {
|
||||
Map<String, String> login = getAppIdLogin(options.getAppId(), options
|
||||
.getUserIdMechanism().createUserId());
|
||||
|
||||
VaultResponseEntity<VaultResponse> entity = vaultClient.postForEntity(
|
||||
String.format("auth/%s/login", options.getPath()), login,
|
||||
VaultResponse.class);
|
||||
try {
|
||||
VaultResponse response = restOperations.postForObject("/auth/{mount}/login",
|
||||
login, VaultResponse.class, options.getPath());
|
||||
|
||||
if (!entity.isSuccessful()) {
|
||||
throw new VaultException(String.format("Cannot login using app-id: %s",
|
||||
entity.getMessage()));
|
||||
logger.debug("Login successful using AppId authentication");
|
||||
|
||||
return LoginTokenUtil.from(response.getAuth());
|
||||
}
|
||||
catch (HttpStatusCodeException e) {
|
||||
throw new VaultException(String.format("Cannot login using app-id: %s",
|
||||
VaultResponses.getError(e.getResponseBodyAsString())));
|
||||
}
|
||||
|
||||
logger.debug("Login successful using AppId authentication");
|
||||
|
||||
return LoginTokenUtil.from(entity.getBody().getAuth());
|
||||
}
|
||||
|
||||
private Map<String, String> getAppIdLogin(String appId, String userId) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
* Copyright 2016-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -22,11 +22,12 @@ import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.vault.client.VaultClient;
|
||||
import org.springframework.vault.client.VaultException;
|
||||
import org.springframework.vault.client.VaultResponseEntity;
|
||||
import org.springframework.vault.VaultException;
|
||||
import org.springframework.vault.client.VaultResponses;
|
||||
import org.springframework.vault.support.VaultResponse;
|
||||
import org.springframework.vault.support.VaultToken;
|
||||
import org.springframework.web.client.HttpStatusCodeException;
|
||||
import org.springframework.web.client.RestOperations;
|
||||
|
||||
/**
|
||||
* AppRole implementation of {@link ClientAuthentication}. RoleId and SecretId (optional)
|
||||
@@ -37,7 +38,7 @@ import org.springframework.vault.support.VaultToken;
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @see AppRoleAuthenticationOptions
|
||||
* @see VaultClient
|
||||
* @see RestOperations
|
||||
* @see <a href="https://www.vaultproject.io/docs/auth/approle.html">Auth Backend:
|
||||
* AppRole</a>
|
||||
*/
|
||||
@@ -47,23 +48,23 @@ public class AppRoleAuthentication implements ClientAuthentication {
|
||||
|
||||
private final AppRoleAuthenticationOptions options;
|
||||
|
||||
private final VaultClient vaultClient;
|
||||
private final RestOperations restOperations;
|
||||
|
||||
/**
|
||||
* Creates a {@link AppRoleAuthentication} using {@link AppRoleAuthenticationOptions}
|
||||
* and {@link VaultClient}.
|
||||
* and {@link RestOperations}.
|
||||
*
|
||||
* @param options must not be {@literal null}.
|
||||
* @param vaultClient must not be {@literal null}.
|
||||
* @param restOperations must not be {@literal null}.
|
||||
*/
|
||||
public AppRoleAuthentication(AppRoleAuthenticationOptions options,
|
||||
VaultClient vaultClient) {
|
||||
RestOperations restOperations) {
|
||||
|
||||
Assert.notNull(options, "AppRoleAuthenticationOptions must not be null");
|
||||
Assert.notNull(vaultClient, "VaultClient must not be null");
|
||||
Assert.notNull(restOperations, "RestOperations must not be null");
|
||||
|
||||
this.options = options;
|
||||
this.vaultClient = vaultClient;
|
||||
this.restOperations = restOperations;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -76,18 +77,18 @@ public class AppRoleAuthentication implements ClientAuthentication {
|
||||
Map<String, String> login = getAppRoleLogin(options.getRoleId(),
|
||||
options.getSecretId());
|
||||
|
||||
VaultResponseEntity<VaultResponse> entity = vaultClient.postForEntity(
|
||||
String.format("auth/%s/login", options.getPath()), login,
|
||||
VaultResponse.class);
|
||||
try {
|
||||
VaultResponse response = restOperations.postForObject("/auth/{mount}/login",
|
||||
login, VaultResponse.class, options.getPath());
|
||||
|
||||
if (!entity.isSuccessful()) {
|
||||
throw new VaultException(String.format("Cannot login using AppRole: %s",
|
||||
entity.getMessage()));
|
||||
logger.debug("Login successful using AppRole authentication");
|
||||
|
||||
return LoginTokenUtil.from(response.getAuth());
|
||||
}
|
||||
catch (HttpStatusCodeException e) {
|
||||
throw new VaultException(String.format("Cannot login using AppRole: %s",
|
||||
VaultResponses.getError(e.getResponseBodyAsString())));
|
||||
}
|
||||
|
||||
logger.debug("Login successful using AppRole authentication");
|
||||
|
||||
return LoginTokenUtil.from(entity.getBody().getAuth());
|
||||
}
|
||||
|
||||
private Map<String, String> getAppRoleLogin(String roleId, String secretId) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
* Copyright 2016-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -25,13 +25,13 @@ import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.vault.client.VaultClient;
|
||||
import org.springframework.vault.client.VaultException;
|
||||
import org.springframework.vault.client.VaultResponseEntity;
|
||||
import org.springframework.vault.VaultException;
|
||||
import org.springframework.vault.client.VaultResponses;
|
||||
import org.springframework.vault.support.VaultResponse;
|
||||
import org.springframework.vault.support.VaultToken;
|
||||
import org.springframework.web.client.HttpStatusCodeException;
|
||||
import org.springframework.web.client.RestClientException;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import org.springframework.web.client.RestOperations;
|
||||
|
||||
/**
|
||||
* AWS-EC2 login implementation.
|
||||
@@ -42,6 +42,7 @@ import org.springframework.web.client.RestTemplate;
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @see AwsEc2AuthenticationOptions
|
||||
* @see RestOperations
|
||||
* @see <a href="https://www.vaultproject.io/docs/auth/aws-ec2.html">Auth Backend:
|
||||
* aws-ec2</a>
|
||||
*/
|
||||
@@ -51,41 +52,42 @@ public class AwsEc2Authentication implements ClientAuthentication {
|
||||
|
||||
private final AwsEc2AuthenticationOptions options;
|
||||
|
||||
private final VaultClient vaultClient;
|
||||
private final RestOperations vaultRestOperations;
|
||||
|
||||
private final RestTemplate restTemplate;
|
||||
private final RestOperations awsMetadataRestOperations;
|
||||
|
||||
private final AtomicReference<char[]> nonce = new AtomicReference<char[]>();
|
||||
|
||||
/**
|
||||
* Creates a new {@link AwsEc2Authentication}.
|
||||
*
|
||||
* @param vaultClient must not be {@literal null}.
|
||||
*
|
||||
* @param vaultRestOperations must not be {@literal null}.
|
||||
*/
|
||||
public AwsEc2Authentication(VaultClient vaultClient) {
|
||||
this(AwsEc2AuthenticationOptions.DEFAULT, vaultClient, vaultClient
|
||||
.getRestTemplate());
|
||||
public AwsEc2Authentication(RestOperations vaultRestOperations) {
|
||||
this(AwsEc2AuthenticationOptions.DEFAULT, vaultRestOperations,
|
||||
vaultRestOperations);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link AwsEc2Authentication} specifying
|
||||
* {@link AwsEc2AuthenticationOptions}, {@link VaultClient} and a {@link RestTemplate}
|
||||
* .
|
||||
*
|
||||
* {@link AwsEc2AuthenticationOptions}, a Vault and an AWS-Metadata-specific
|
||||
* {@link RestOperations} .
|
||||
*
|
||||
* @param options must not be {@literal null}.
|
||||
* @param vaultClient must not be {@literal null}.
|
||||
* @param restTemplate must not be {@literal null}.
|
||||
* @param vaultRestOperations must not be {@literal null}.
|
||||
* @param awsMetadataRestOperations must not be {@literal null}.
|
||||
*/
|
||||
public AwsEc2Authentication(AwsEc2AuthenticationOptions options,
|
||||
VaultClient vaultClient, RestTemplate restTemplate) {
|
||||
RestOperations vaultRestOperations, RestOperations awsMetadataRestOperations) {
|
||||
|
||||
Assert.notNull(options, "AwsEc2AuthenticationOptions must not be null");
|
||||
Assert.notNull(vaultClient, "VaultEndpoint must not be null");
|
||||
Assert.notNull(restTemplate, "RestTemplate must not be null");
|
||||
Assert.notNull(vaultRestOperations, "Vault RestOperations must not be null");
|
||||
Assert.notNull(awsMetadataRestOperations,
|
||||
"AWS Metadata RestOperations must not be null");
|
||||
|
||||
this.options = options;
|
||||
this.vaultClient = vaultClient;
|
||||
this.restTemplate = restTemplate;
|
||||
this.vaultRestOperations = vaultRestOperations;
|
||||
this.awsMetadataRestOperations = awsMetadataRestOperations;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -96,35 +98,34 @@ public class AwsEc2Authentication implements ClientAuthentication {
|
||||
@SuppressWarnings("unchecked")
|
||||
private VaultToken createTokenUsingAwsEc2() {
|
||||
|
||||
String path = String.format("auth/%s/login", options.getPath());
|
||||
|
||||
Map<String, String> login = getEc2Login();
|
||||
|
||||
VaultResponseEntity<VaultResponse> entity = this.vaultClient.postForEntity(path,
|
||||
login, VaultResponse.class);
|
||||
try {
|
||||
|
||||
if (!entity.isSuccessful()) {
|
||||
VaultResponse response = this.vaultRestOperations.postForObject(
|
||||
"/auth/{mount}/login", login, VaultResponse.class, options.getPath());
|
||||
|
||||
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",
|
||||
metadata.get("instance_id"),
|
||||
metadata.get("instance_id")));
|
||||
}
|
||||
else {
|
||||
logger.debug("Login successful using AWS-EC2 authentication");
|
||||
}
|
||||
}
|
||||
|
||||
return LoginTokenUtil.from(response.getAuth());
|
||||
}
|
||||
catch (HttpStatusCodeException e) {
|
||||
throw new VaultException(String.format("Cannot login using AWS-EC2: %s",
|
||||
entity.getMessage()));
|
||||
VaultResponses.getError(e.getResponseBodyAsString())));
|
||||
}
|
||||
|
||||
VaultResponse body = entity.getBody();
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
|
||||
if (body.getAuth().get("metadata") instanceof Map) {
|
||||
Map<Object, Object> metadata = (Map<Object, Object>) body.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 {
|
||||
logger.debug("Login successful using AWS-EC2 authentication");
|
||||
}
|
||||
}
|
||||
|
||||
return LoginTokenUtil.from(entity.getBody().getAuth());
|
||||
}
|
||||
|
||||
protected Map<String, String> getEc2Login() {
|
||||
@@ -142,8 +143,8 @@ public class AwsEc2Authentication implements ClientAuthentication {
|
||||
login.put("nonce", new String(this.nonce.get()));
|
||||
|
||||
try {
|
||||
String pkcs7 = restTemplate.getForObject(options.getIdentityDocumentUri(),
|
||||
String.class);
|
||||
String pkcs7 = awsMetadataRestOperations.getForObject(
|
||||
options.getIdentityDocumentUri(), String.class);
|
||||
if (StringUtils.hasText(pkcs7)) {
|
||||
login.put("pkcs7", pkcs7.replaceAll("\\r", "").replace("\\n", ""));
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
* Copyright 2016-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
package org.springframework.vault.authentication;
|
||||
|
||||
import org.springframework.vault.client.VaultException;
|
||||
import org.springframework.vault.VaultException;
|
||||
import org.springframework.vault.support.VaultToken;
|
||||
|
||||
/**
|
||||
@@ -33,5 +33,5 @@ public interface ClientAuthentication {
|
||||
*
|
||||
* @return a {@link VaultToken}.
|
||||
*/
|
||||
public VaultToken login() throws VaultException;
|
||||
VaultToken login() throws VaultException;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
* Copyright 2016-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -21,11 +21,12 @@ import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.vault.client.VaultClient;
|
||||
import org.springframework.vault.client.VaultException;
|
||||
import org.springframework.vault.client.VaultResponseEntity;
|
||||
import org.springframework.vault.VaultException;
|
||||
import org.springframework.vault.client.VaultResponses;
|
||||
import org.springframework.vault.support.VaultResponse;
|
||||
import org.springframework.vault.support.VaultToken;
|
||||
import org.springframework.web.client.HttpStatusCodeException;
|
||||
import org.springframework.web.client.RestOperations;
|
||||
|
||||
/**
|
||||
* TLS Client Certificate {@link ClientAuthentication}.
|
||||
@@ -37,18 +38,18 @@ public class ClientCertificateAuthentication implements ClientAuthentication {
|
||||
private final static Log logger = LogFactory
|
||||
.getLog(ClientCertificateAuthentication.class);
|
||||
|
||||
private final VaultClient vaultClient;
|
||||
private final RestOperations restOperations;
|
||||
|
||||
/**
|
||||
* Creates a {@link ClientCertificateAuthentication} using {@link VaultClient}.
|
||||
* Creates a {@link ClientCertificateAuthentication} using {@link RestOperations}.
|
||||
*
|
||||
* @param vaultClient must not be {@literal null}.
|
||||
* @param restOperations must not be {@literal null}.
|
||||
*/
|
||||
public ClientCertificateAuthentication(VaultClient vaultClient) {
|
||||
public ClientCertificateAuthentication(RestOperations restOperations) {
|
||||
|
||||
Assert.notNull(vaultClient, "VaultClient must not be null");
|
||||
Assert.notNull(restOperations, "RestOperations must not be null");
|
||||
|
||||
this.vaultClient = vaultClient;
|
||||
this.restOperations = restOperations;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -58,17 +59,18 @@ public class ClientCertificateAuthentication implements ClientAuthentication {
|
||||
|
||||
private VaultToken createTokenUsingTlsCertAuthentication(String path) {
|
||||
|
||||
VaultResponseEntity<VaultResponse> entity = vaultClient.postForEntity(
|
||||
String.format("auth/%s/login", path), Collections.emptyMap(),
|
||||
VaultResponse.class);
|
||||
try {
|
||||
VaultResponse response = restOperations.postForObject("/auth/{mount}/login",
|
||||
Collections.emptyMap(), VaultResponse.class, path);
|
||||
|
||||
if (!entity.isSuccessful()) {
|
||||
throw new VaultException(String.format(
|
||||
"Cannot login using TLS certificates: %s", entity.getMessage()));
|
||||
logger.debug("Login successful using TLS certificates");
|
||||
|
||||
return LoginTokenUtil.from(response.getAuth());
|
||||
}
|
||||
catch (HttpStatusCodeException e) {
|
||||
throw new VaultException(String.format(
|
||||
"Cannot login using TLS certificates: %s",
|
||||
VaultResponses.getError(e.getResponseBodyAsString())));
|
||||
}
|
||||
|
||||
logger.debug("Login successful using TLS certificates");
|
||||
|
||||
return LoginTokenUtil.from(entity.getBody().getAuth());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
* Copyright 2016-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -20,12 +20,17 @@ import java.util.Map;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.vault.client.VaultClient;
|
||||
import org.springframework.vault.client.VaultException;
|
||||
import org.springframework.vault.client.VaultResponseEntity;
|
||||
import org.springframework.vault.VaultException;
|
||||
import org.springframework.vault.client.VaultHttpHeaders;
|
||||
import org.springframework.vault.client.VaultResponses;
|
||||
import org.springframework.vault.support.VaultResponse;
|
||||
import org.springframework.vault.support.VaultToken;
|
||||
import org.springframework.web.client.HttpStatusCodeException;
|
||||
import org.springframework.web.client.RestOperations;
|
||||
|
||||
/**
|
||||
* Cubbyhole {@link ClientAuthentication} implementation.
|
||||
@@ -37,7 +42,7 @@ import org.springframework.vault.support.VaultToken;
|
||||
* interact with Vault. The login token can be retrieved either from a wrapped response or
|
||||
* from the {@code data} section.
|
||||
* <h2>Wrapped token response usage</h2> <strong>Create a Token</strong>
|
||||
*
|
||||
*
|
||||
* <pre>
|
||||
* <code>
|
||||
* $ vault token-create -wrap-ttl="10m"
|
||||
@@ -51,7 +56,7 @@ import org.springframework.vault.support.VaultToken;
|
||||
* </pre>
|
||||
*
|
||||
* <strong>Setup {@link CubbyholeAuthentication}</strong>
|
||||
*
|
||||
*
|
||||
* <pre>
|
||||
* <code>
|
||||
* CubbyholeAuthenticationOptions options = CubbyholeAuthenticationOptions
|
||||
@@ -59,7 +64,7 @@ import org.springframework.vault.support.VaultToken;
|
||||
* .initialToken(VaultToken.of("397ccb93-ff6c-b17b-9389-380b01ca2645"))
|
||||
* .wrapped()
|
||||
* .build();
|
||||
* CubbyholeAuthentication authentication = new CubbyholeAuthentication(options, vaultClient);
|
||||
* CubbyholeAuthentication authentication = new CubbyholeAuthentication(options, restOperations);
|
||||
* </code>
|
||||
* </pre>
|
||||
*
|
||||
@@ -75,7 +80,7 @@ import org.springframework.vault.support.VaultToken;
|
||||
* token_duration 0s
|
||||
* token_renewable false
|
||||
* token_policies [root]
|
||||
*
|
||||
*
|
||||
* $ token-create -use-limit=2 -orphan -no-default-policy -policy=none
|
||||
* Key Value
|
||||
* --- -----
|
||||
@@ -84,7 +89,7 @@ import org.springframework.vault.support.VaultToken;
|
||||
* token_duration 0s
|
||||
* token_renewable false
|
||||
* token_policies [none]
|
||||
*
|
||||
*
|
||||
* $ export VAULT_TOKEN=895cb88b-aef4-0e33-ba65-d50007290780
|
||||
* $ vault write cubbyhole/token token=f9e30681-d46a-cdaf-aaa0-2ae0a9ad0819
|
||||
* </code>
|
||||
@@ -99,12 +104,13 @@ import org.springframework.vault.support.VaultToken;
|
||||
* .initialToken(VaultToken.of("895cb88b-aef4-0e33-ba65-d50007290780"))
|
||||
* .path("cubbyhole/token")
|
||||
* .build();
|
||||
* CubbyholeAuthentication authentication = new CubbyholeAuthentication(options, vaultClient);
|
||||
* CubbyholeAuthentication authentication = new CubbyholeAuthentication(options, restOperations);
|
||||
* </code>
|
||||
* </pre>
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @see CubbyholeAuthenticationOptions
|
||||
* @see RestOperations
|
||||
* @see <a href="https://www.vaultproject.io/docs/auth/token.html">Auth Backend: Token</a>
|
||||
* @see <a href="https://www.vaultproject.io/docs/secrets/cubbyhole/index.html">Cubbyhole
|
||||
* Secret Backend</a>
|
||||
@@ -118,55 +124,61 @@ public class CubbyholeAuthentication implements ClientAuthentication {
|
||||
|
||||
private final CubbyholeAuthenticationOptions options;
|
||||
|
||||
private final VaultClient vaultClient;
|
||||
private final RestOperations restOperations;
|
||||
|
||||
/**
|
||||
* Create a new {@link CubbyholeAuthentication} given
|
||||
* {@link CubbyholeAuthenticationOptions} and {@link VaultClient}.
|
||||
*
|
||||
* {@link CubbyholeAuthenticationOptions} and {@link RestOperations}.
|
||||
*
|
||||
* @param options must not be {@literal null}.
|
||||
* @param vaultClient must not be {@literal null}.
|
||||
* @param restOperations must not be {@literal null}.
|
||||
*/
|
||||
public CubbyholeAuthentication(CubbyholeAuthenticationOptions options,
|
||||
VaultClient vaultClient) {
|
||||
RestOperations restOperations) {
|
||||
|
||||
Assert.notNull(options, "CubbyholeAuthenticationOptions must not be null");
|
||||
Assert.notNull(vaultClient, "VaultClient must not be null");
|
||||
Assert.notNull(restOperations, "RestOperations must not be null");
|
||||
|
||||
this.options = options;
|
||||
this.vaultClient = vaultClient;
|
||||
this.restOperations = restOperations;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VaultToken login() throws VaultException {
|
||||
|
||||
VaultResponseEntity<VaultResponse> entity = vaultClient.getForEntity(
|
||||
options.getPath(), options.getInitialToken(), VaultResponse.class);
|
||||
try {
|
||||
|
||||
if (entity.isSuccessful() && entity.hasBody()) {
|
||||
ResponseEntity<VaultResponse> entity = restOperations.exchange(
|
||||
options.getPath(),
|
||||
HttpMethod.GET,
|
||||
new HttpEntity<Object>(VaultHttpHeaders.from(options
|
||||
.getInitialToken())), VaultResponse.class);
|
||||
|
||||
VaultResponse body = entity.getBody();
|
||||
Map<String, Object> data = body.getData();
|
||||
Map<String, Object> data = entity.getBody().getData();
|
||||
|
||||
VaultToken token = getToken(entity, data);
|
||||
VaultToken token = getToken(data);
|
||||
if (token != null) {
|
||||
|
||||
logger.debug("Login successful using Cubbyhole authentication");
|
||||
return token;
|
||||
}
|
||||
|
||||
throw new VaultException(String.format(
|
||||
"Cannot retrieve Token from cubbyhole: %s", entity.getStatusCode()));
|
||||
}
|
||||
catch (HttpStatusCodeException e) {
|
||||
throw new VaultException(String.format(
|
||||
"Cannot retrieve Token from cubbyhole: %s %s", e.getStatusCode(),
|
||||
VaultResponses.getError(e.getResponseBodyAsString())));
|
||||
}
|
||||
|
||||
throw new VaultException(String.format(
|
||||
"Cannot retrieve Token from cubbyhole: %s %s", entity.getStatusCode(),
|
||||
entity.getMessage()));
|
||||
}
|
||||
|
||||
private VaultToken getToken(VaultResponseEntity<VaultResponse> entity,
|
||||
Map<String, Object> data) {
|
||||
private VaultToken getToken(Map<String, Object> data) {
|
||||
|
||||
if (options.isWrappedToken()) {
|
||||
|
||||
VaultResponse response = vaultClient.unwrap((String) data.get("response"),
|
||||
VaultResponse response = VaultResponses.unwrap((String) data.get("response"),
|
||||
VaultResponse.class);
|
||||
return LoginTokenUtil.from(response.getAuth());
|
||||
}
|
||||
@@ -175,7 +187,7 @@ public class CubbyholeAuthentication implements ClientAuthentication {
|
||||
throw new VaultException(
|
||||
String.format(
|
||||
"Cannot retrieve Token from cubbyhole: Response at %s does not contain a token",
|
||||
entity.getUri()));
|
||||
options.getPath()));
|
||||
}
|
||||
|
||||
if (data.size() == 1) {
|
||||
@@ -186,6 +198,6 @@ public class CubbyholeAuthentication implements ClientAuthentication {
|
||||
throw new VaultException(
|
||||
String.format(
|
||||
"Cannot retrieve Token from cubbyhole: Response at %s does not contain an unique token",
|
||||
entity.getUri()));
|
||||
options.getPath()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
* Copyright 2016-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -23,7 +23,7 @@ import org.springframework.vault.support.VaultToken;
|
||||
* <p>
|
||||
* Authentication options provide the path below cubbyhole and the cubbyhole mode.
|
||||
* Instances of this class are immutable once constructed.
|
||||
*
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @see CubbyholeAuthentication
|
||||
* @see #builder()
|
||||
@@ -99,7 +99,7 @@ public class CubbyholeAuthenticationOptions {
|
||||
|
||||
/**
|
||||
* Configure the initial {@link VaultToken} to access Cubbyhole.
|
||||
*
|
||||
*
|
||||
* @param initialToken must not be {@literal null}.
|
||||
* @return {@code this} {@link CubbyholeAuthenticationOptionsBuilder}.
|
||||
*/
|
||||
@@ -141,7 +141,7 @@ 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() {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
* Copyright 2016-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -25,16 +25,19 @@ import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.core.task.AsyncTaskExecutor;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.scheduling.TaskScheduler;
|
||||
import org.springframework.scheduling.Trigger;
|
||||
import org.springframework.scheduling.TriggerContext;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.NumberUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.vault.client.VaultClient;
|
||||
import org.springframework.vault.client.VaultException;
|
||||
import org.springframework.vault.client.VaultResponseEntity;
|
||||
import org.springframework.vault.VaultException;
|
||||
import org.springframework.vault.client.VaultHttpHeaders;
|
||||
import org.springframework.vault.client.VaultResponses;
|
||||
import org.springframework.vault.support.VaultToken;
|
||||
import org.springframework.web.client.HttpStatusCodeException;
|
||||
import org.springframework.web.client.RestClientException;
|
||||
import org.springframework.web.client.RestOperations;
|
||||
|
||||
/**
|
||||
* Lifecycle-aware Session Manager. This {@link SessionManager} obtains tokens from a
|
||||
@@ -63,29 +66,32 @@ public class LifecycleAwareSessionManager implements SessionManager, DisposableB
|
||||
.getLog(LifecycleAwareSessionManager.class);
|
||||
|
||||
private final ClientAuthentication clientAuthentication;
|
||||
private final VaultClient vaultClient;
|
||||
|
||||
private final RestOperations restOperations;
|
||||
|
||||
private final AsyncTaskExecutor taskExecutor;
|
||||
|
||||
private final Object lock = new Object();
|
||||
|
||||
private volatile VaultToken token;
|
||||
|
||||
/**
|
||||
* Create a {@link LifecycleAwareSessionManager} given {@link ClientAuthentication},
|
||||
* {@link AsyncTaskExecutor} and {@link VaultClient}.
|
||||
*
|
||||
* {@link AsyncTaskExecutor} and {@link RestOperations}.
|
||||
*
|
||||
* @param clientAuthentication must not be {@literal null}.
|
||||
* @param taskExecutor must not be {@literal null}.
|
||||
* @param vaultClient must not be {@literal null}.
|
||||
* @param restOperations must not be {@literal null}.
|
||||
*/
|
||||
public LifecycleAwareSessionManager(ClientAuthentication clientAuthentication,
|
||||
AsyncTaskExecutor taskExecutor, VaultClient vaultClient) {
|
||||
AsyncTaskExecutor taskExecutor, RestOperations restOperations) {
|
||||
|
||||
Assert.notNull(clientAuthentication, "ClientAuthentication must not be null");
|
||||
Assert.notNull(taskExecutor, "AsyncTaskExecutor must not be null");
|
||||
Assert.notNull(vaultClient, "VaultClient must not be null");
|
||||
Assert.notNull(restOperations, "RestOperations must not be null");
|
||||
|
||||
this.clientAuthentication = clientAuthentication;
|
||||
this.vaultClient = vaultClient;
|
||||
this.restOperations = restOperations;
|
||||
this.taskExecutor = taskExecutor;
|
||||
}
|
||||
|
||||
@@ -96,12 +102,14 @@ public class LifecycleAwareSessionManager implements SessionManager, DisposableB
|
||||
this.token = null;
|
||||
|
||||
if (token instanceof LoginToken) {
|
||||
VaultResponseEntity<Map> response = vaultClient.postForEntity(
|
||||
"auth/token/revoke-self", token, null, Map.class);
|
||||
|
||||
if (!response.isSuccessful()) {
|
||||
try {
|
||||
restOperations.postForObject("/auth/token/revoke-self",
|
||||
new HttpEntity<Object>(VaultHttpHeaders.from(token)), Map.class);
|
||||
}
|
||||
catch (HttpStatusCodeException e) {
|
||||
logger.warn(String.format("Cannot revoke VaultToken: %s",
|
||||
buildExceptionMessage(response)));
|
||||
VaultResponses.getError(e.getResponseBodyAsString())));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -111,7 +119,7 @@ public class LifecycleAwareSessionManager implements SessionManager, DisposableB
|
||||
* 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.
|
||||
*/
|
||||
@@ -124,23 +132,27 @@ public class LifecycleAwareSessionManager implements SessionManager, DisposableB
|
||||
return false;
|
||||
}
|
||||
|
||||
VaultResponseEntity<Map> response = vaultClient.postForEntity(
|
||||
"auth/token/renew-self", token, null, Map.class);
|
||||
try {
|
||||
restOperations.postForObject("/auth/token/renew-self",
|
||||
new HttpEntity<Object>(
|
||||
VaultHttpHeaders.from(token)), Map.class);
|
||||
return true;
|
||||
}
|
||||
catch (HttpStatusCodeException e) {
|
||||
|
||||
if (!response.isSuccessful()) {
|
||||
|
||||
if (response.getStatusCode().is4xxClientError()) {
|
||||
if (e.getStatusCode().is4xxClientError()) {
|
||||
logger.debug(String
|
||||
.format("Cannot refresh token, resetting token and performing re-login: %s",
|
||||
buildExceptionMessage(response)));
|
||||
VaultResponses.getError(e.getResponseBodyAsString())));
|
||||
token = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
throw new VaultException(buildExceptionMessage(response));
|
||||
throw new VaultException(VaultResponses.getError(e.getResponseBodyAsString()));
|
||||
}
|
||||
catch (RestClientException e) {
|
||||
throw new VaultException("Cannot refresh token", e);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -229,17 +241,6 @@ public class LifecycleAwareSessionManager implements SessionManager, DisposableB
|
||||
taskScheduler.schedule(task, new OneShotTrigger(seconds));
|
||||
}
|
||||
|
||||
private static String buildExceptionMessage(VaultResponseEntity<?> response) {
|
||||
|
||||
if (StringUtils.hasText(response.getMessage())) {
|
||||
return String.format("Status %s URI %s: %s", response.getStatusCode(),
|
||||
response.getUri(), response.getMessage());
|
||||
}
|
||||
|
||||
return String.format("Status %s URI %s", response.getStatusCode(),
|
||||
response.getUri());
|
||||
}
|
||||
|
||||
/**
|
||||
* This one-shot trigger creates only one execution time to trigger an execution only
|
||||
* once.
|
||||
|
||||
@@ -1,145 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.vault.client;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import org.springframework.core.ParameterizedTypeReference;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.client.HttpStatusCodeException;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
/**
|
||||
* Base class for Vault accessing helpers, defining common properties such as the
|
||||
* {@link RestTemplate} to operate on.
|
||||
* <p>
|
||||
* Not intended to be used directly. See {@link VaultClient}.
|
||||
*
|
||||
* @author Spencer Gibb
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public abstract class VaultAccessor {
|
||||
|
||||
private final RestTemplate restTemplate;
|
||||
|
||||
/**
|
||||
* Create a {@link VaultAccessor} with a {@link RestTemplate}.
|
||||
*
|
||||
* @param restTemplate must not be {@literal null}.
|
||||
*/
|
||||
protected VaultAccessor(RestTemplate restTemplate) {
|
||||
|
||||
Assert.notNull(restTemplate, "RestTemplate must not be null");
|
||||
|
||||
this.restTemplate = restTemplate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a {@link RestTemplateCallback} in the scope of the {@link RestTemplate}.
|
||||
*
|
||||
* @param uri must not be {@literal null}.
|
||||
* @param callback must not be {@literal null}.
|
||||
* @param <T> return type
|
||||
* @return the {@link RestTemplateCallback} return value.
|
||||
*/
|
||||
protected <T> T doWithRestTemplate(URI uri, RestTemplateCallback<T> callback) {
|
||||
|
||||
Assert.notNull(uri, "URI must not be null");
|
||||
Assert.notNull(callback, "RestTemplateCallback must not be null");
|
||||
|
||||
return callback.doWithRestTemplate(uri, getRestTemplate());
|
||||
}
|
||||
|
||||
public <T, S extends T> VaultResponseEntity<S> exchange(URI uri,
|
||||
HttpMethod httpMethod, HttpEntity<?> httpEntity, Class<T> returnType) {
|
||||
|
||||
Assert.notNull(uri, "URI must not be null");
|
||||
Assert.notNull(httpMethod, "HttpMethod must not be null");
|
||||
Assert.notNull(returnType, "Return type must not be null");
|
||||
|
||||
try {
|
||||
ResponseEntity<T> response = this.getRestTemplate().exchange(uri, httpMethod,
|
||||
httpEntity, returnType);
|
||||
|
||||
return new VaultResponseEntity<S>((S) response.getBody(),
|
||||
response.getStatusCode(), uri, response.getStatusCode()
|
||||
.getReasonPhrase());
|
||||
}
|
||||
catch (HttpStatusCodeException e) {
|
||||
return handleCodeException(uri, e);
|
||||
}
|
||||
}
|
||||
|
||||
public <T, S extends T> VaultResponseEntity<S> exchange(URI uri,
|
||||
HttpMethod httpMethod, HttpEntity<?> httpEntity,
|
||||
ParameterizedTypeReference<T> returnType) {
|
||||
|
||||
Assert.notNull(uri, "URI must not be null");
|
||||
Assert.notNull(httpMethod, "HttpMethod must not be null");
|
||||
Assert.notNull(returnType, "Return type must not be null");
|
||||
|
||||
try {
|
||||
ResponseEntity<T> response = this.getRestTemplate().exchange(uri, httpMethod,
|
||||
httpEntity, returnType);
|
||||
|
||||
return new VaultResponseEntity<S>((S) response.getBody(),
|
||||
response.getStatusCode(), uri, response.getStatusCode()
|
||||
.getReasonPhrase());
|
||||
}
|
||||
catch (HttpStatusCodeException e) {
|
||||
return handleCodeException(uri, e);
|
||||
}
|
||||
}
|
||||
|
||||
private <T> VaultResponseEntity<T> handleCodeException(URI uri,
|
||||
HttpStatusCodeException e) {
|
||||
|
||||
String message = e.getResponseBodyAsString();
|
||||
|
||||
if (MediaType.APPLICATION_JSON.includes(e.getResponseHeaders().getContentType())) {
|
||||
message = VaultErrorMessage.getError(message);
|
||||
}
|
||||
|
||||
return new VaultResponseEntity<T>(null, e.getStatusCode(), uri, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the underlying {@link RestTemplate}.
|
||||
*/
|
||||
public RestTemplate getRestTemplate() {
|
||||
return restTemplate;
|
||||
}
|
||||
|
||||
/**
|
||||
* A callback for executing arbitrary operations on the {@link RestTemplate}.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public interface RestTemplateCallback<T> {
|
||||
|
||||
/**
|
||||
* @param uri must not be {@literal null}.
|
||||
* @param restTemplate must not be {@literal null}.
|
||||
* @return a result object or null if none.
|
||||
*/
|
||||
T doWithRestTemplate(URI uri, RestTemplate restTemplate);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,398 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.vault.client;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URI;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.core.ParameterizedTypeReference;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpInputMessage;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpRequest;
|
||||
import org.springframework.http.client.ClientHttpRequestExecution;
|
||||
import org.springframework.http.client.ClientHttpRequestFactory;
|
||||
import org.springframework.http.client.ClientHttpRequestInterceptor;
|
||||
import org.springframework.http.client.ClientHttpResponse;
|
||||
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.vault.core.VaultTemplate;
|
||||
import org.springframework.vault.support.VaultToken;
|
||||
import org.springframework.web.client.RestClientException;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
/**
|
||||
* Implementation of the low-level Vault client. This client uses the Vault HTTP API to
|
||||
* issue requests using different {@link HttpMethod HTTP methods}. {@link VaultClient} is
|
||||
* configured with an {@link VaultEndpoint} and {@link RestTemplate}. It does not maintain
|
||||
* any session or token state. See {@link VaultTemplate} and
|
||||
* {@link org.springframework.vault.authentication.SessionManager} for authenticated and
|
||||
* stateful Vault access. {@link VaultClient} encapsulates base URI and path construction
|
||||
* and uses {@link VaultAccessor} for request and error handling by returning
|
||||
* {@link VaultResponseEntity} for requests.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @see VaultResponseEntity
|
||||
* @see VaultTemplate
|
||||
*/
|
||||
public class VaultClient extends VaultAccessor {
|
||||
|
||||
public static final String VAULT_TOKEN = "X-Vault-Token";
|
||||
|
||||
private static final MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
|
||||
|
||||
private final VaultEndpoint endpoint;
|
||||
|
||||
/**
|
||||
* Creates a new {@link VaultClient} with a default a {@link RestTemplate} and
|
||||
* {@link VaultEndpoint}.
|
||||
*
|
||||
* @see VaultEndpoint
|
||||
*/
|
||||
public VaultClient() {
|
||||
this(new RestTemplate(), new VaultEndpoint());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link VaultClient} for a {@link ClientHttpRequestFactory} and
|
||||
* {@link VaultEndpoint}.
|
||||
*
|
||||
* @param requestFactory must not be {@literal null}.
|
||||
* @param endpoint must not be {@literal null}.
|
||||
*/
|
||||
public VaultClient(ClientHttpRequestFactory requestFactory, VaultEndpoint endpoint) {
|
||||
|
||||
super(newRestTemplate(requestFactory));
|
||||
|
||||
Assert.notNull(endpoint, "VaultEndpoint must not be null");
|
||||
this.endpoint = endpoint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link RestTemplate} using an interceptor given a
|
||||
* {@link ClientHttpRequestFactory}. This forces {@link RestTemplate} to create the
|
||||
* body representation instead of streaming the body to the TCP channel. Streaming the
|
||||
* body without knowing the size in advance will skip the
|
||||
* {@link HttpHeaders#CONTENT_LENGTH} makes Vault upset.
|
||||
*
|
||||
* @param requestFactory must not be {@literal null}.
|
||||
* @return the {@link RestTemplate}
|
||||
*/
|
||||
private static RestTemplate newRestTemplate(ClientHttpRequestFactory requestFactory) {
|
||||
|
||||
Assert.notNull(requestFactory, "ClientHttpRequestFactory must not be null");
|
||||
|
||||
RestTemplate restTemplate = new RestTemplate(requestFactory);
|
||||
restTemplate.getInterceptors().add(new ClientHttpRequestInterceptor() {
|
||||
|
||||
@Override
|
||||
public ClientHttpResponse intercept(HttpRequest request, byte[] body,
|
||||
ClientHttpRequestExecution execution) throws IOException {
|
||||
return execution.execute(request, body);
|
||||
}
|
||||
});
|
||||
|
||||
return restTemplate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link VaultClient} for a {@link RestTemplate} and
|
||||
* {@link VaultEndpoint}.
|
||||
*
|
||||
* @param restTemplate must not be {@literal null}.
|
||||
* @param endpoint must not be {@literal null}.
|
||||
*/
|
||||
public VaultClient(RestTemplate restTemplate, VaultEndpoint endpoint) {
|
||||
|
||||
super(restTemplate);
|
||||
|
||||
Assert.notNull(endpoint, "VaultEndpoint must not be null");
|
||||
this.endpoint = endpoint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a resource by GETting from the path, and returns the response as
|
||||
* {@link VaultResponseEntity}.
|
||||
*
|
||||
* @param path the path.
|
||||
* @param responseType the type of the return value
|
||||
* @return the response as entity.
|
||||
* @see VaultResponseEntity
|
||||
*/
|
||||
public <T, S extends T> VaultResponseEntity<S> getForEntity(String path,
|
||||
Class<T> responseType) {
|
||||
return exchange(path, HttpMethod.GET, new HttpEntity<Object>(null), responseType,
|
||||
null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a resource by GETting from the path, and returns the response as
|
||||
* {@link VaultResponseEntity}.
|
||||
*
|
||||
* @param path the path.
|
||||
* @param vaultToken the {@link VaultToken}.
|
||||
* @param responseType the type of the return value
|
||||
* @return the response as entity.
|
||||
* @see VaultResponseEntity
|
||||
*/
|
||||
public <T, S extends T> VaultResponseEntity<S> getForEntity(String path,
|
||||
VaultToken vaultToken, Class<T> responseType) {
|
||||
|
||||
return exchange(path, HttpMethod.GET, new HttpEntity<Object>(null,
|
||||
createHeaders(vaultToken)), responseType, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Issue a POST request using the given object to the path, and returns the response
|
||||
* as {@link VaultResponseEntity}.
|
||||
*
|
||||
* @param path the path.
|
||||
* @param request the Object to be POSTed, may be {@code null}.
|
||||
* @param responseType the type of the return value
|
||||
* @return the response as entity.
|
||||
* @see VaultResponseEntity
|
||||
*/
|
||||
public <T, S extends T> VaultResponseEntity<S> postForEntity(String path,
|
||||
Object request, Class<T> responseType) {
|
||||
return exchange(path, HttpMethod.POST, new HttpEntity<Object>(request),
|
||||
responseType, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Issue a POST request using the given object to the path, and returns the response
|
||||
* as {@link VaultResponseEntity}.
|
||||
*
|
||||
* @param path the path.
|
||||
* @param vaultToken the {@link VaultToken}.
|
||||
* @param request the Object to be POSTed, may be {@code null}.
|
||||
* @param responseType the type of the return value
|
||||
* @return the response as entity.
|
||||
* @see VaultResponseEntity
|
||||
*/
|
||||
public <T, S extends T> VaultResponseEntity<S> postForEntity(String path,
|
||||
VaultToken vaultToken, Object request, Class<T> responseType) {
|
||||
return exchange(path, HttpMethod.POST, new HttpEntity<Object>(request,
|
||||
createHeaders(vaultToken)), responseType, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new resource by PUTting the given object to the path, and returns the
|
||||
* response as {@link VaultResponseEntity}.
|
||||
*
|
||||
* @param path the path.
|
||||
* @param request the Object to be PUT.
|
||||
* @param responseType the type of the return value
|
||||
* @return the response as entity.
|
||||
* @see VaultResponseEntity
|
||||
*/
|
||||
public <T, S extends T> VaultResponseEntity<S> putForEntity(String path,
|
||||
Object request, Class<T> responseType) {
|
||||
return exchange(path, HttpMethod.PUT, new HttpEntity<Object>(request),
|
||||
responseType, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new resource by PUTting the given object to the path, and returns the
|
||||
* response as {@link VaultResponseEntity}.
|
||||
*
|
||||
* @param path the path.
|
||||
* @param vaultToken the {@link VaultToken}.
|
||||
* @param request the Object to be PUT.
|
||||
* @param responseType the type of the return value
|
||||
* @return the response as entity.
|
||||
* @see VaultResponseEntity
|
||||
*/
|
||||
public <T, S extends T> VaultResponseEntity<S> putForEntity(String path,
|
||||
VaultToken vaultToken, Object request, Class<T> responseType) {
|
||||
return exchange(path, HttpMethod.PUT, new HttpEntity<Object>(request,
|
||||
createHeaders(vaultToken)), responseType, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a resource by DELETEing from the path, and returns the response as
|
||||
* {@link VaultResponseEntity}.
|
||||
*
|
||||
* @param path the path.
|
||||
* @param vaultToken the {@link VaultToken}.
|
||||
* @param responseType the type of the return value
|
||||
* @return the response as entity.
|
||||
* @see VaultResponseEntity
|
||||
*/
|
||||
public <T, S extends T> VaultResponseEntity<S> deleteForEntity(String path,
|
||||
VaultToken vaultToken, Class<T> responseType) {
|
||||
|
||||
return exchange(path, HttpMethod.DELETE, new HttpEntity<Object>(null,
|
||||
createHeaders(vaultToken)), responseType, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the HTTP method to the given URI template, writing the given request entity
|
||||
* to the request, and returns the response as {@link VaultResponseEntity}. URI
|
||||
* Template variables are using the given URI variables, if any.
|
||||
*
|
||||
* @param pathTemplate the path template.
|
||||
* @param method the HTTP method (GET, POST, etc).
|
||||
* @param requestEntity the entity (headers and/or body) to write to the request, may
|
||||
* be {@code null}.
|
||||
* @param responseType the type of the return value.
|
||||
* @param uriVariables the variables to expand in the template.
|
||||
* @return the response as entity.
|
||||
*/
|
||||
public <T, S extends T> VaultResponseEntity<S> exchange(String pathTemplate,
|
||||
HttpMethod method, HttpEntity<?> requestEntity, Class<T> responseType,
|
||||
Map<String, ?> uriVariables) throws RestClientException {
|
||||
|
||||
Assert.hasText(pathTemplate, "Path template must not be null or empty");
|
||||
Assert.isTrue(!pathTemplate.startsWith("/"),
|
||||
"Path template must not start with a slash (/)");
|
||||
|
||||
URI uri = uriVariables != null ? buildUri(pathTemplate, uriVariables)
|
||||
: getEndpoint().createUri(pathTemplate);
|
||||
|
||||
return exchange(uri, method, requestEntity, responseType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the HTTP method to the given path template, writing the given request
|
||||
* entity to the request, and returns the response as {@link VaultResponseEntity}. The
|
||||
* given {@link ParameterizedTypeReference} is used to pass generic type information:
|
||||
*
|
||||
* <pre class="code">
|
||||
* ParameterizedTypeReference<List<MyBean>> myBean = new ParameterizedTypeReference<List<MyBean>>() {
|
||||
* };
|
||||
* ResponseEntity<List<MyBean>> response = client.exchange("http://example.com",
|
||||
* HttpMethod.GET, null, myBean, null);
|
||||
* </pre>
|
||||
*
|
||||
* @param pathTemplate the path template.
|
||||
* @param method the HTTP method (GET, POST, etc).
|
||||
* @param requestEntity the entity (headers and/or body) to write to the request, may
|
||||
* be {@code null}.
|
||||
* @param responseType the type of the return value.
|
||||
* @param uriVariables the variables to expand in the template.
|
||||
* @return the response as entity.
|
||||
*/
|
||||
public <T, S extends T> VaultResponseEntity<S> exchange(String pathTemplate,
|
||||
HttpMethod method, HttpEntity<?> requestEntity,
|
||||
ParameterizedTypeReference<T> responseType, Map<String, ?> uriVariables)
|
||||
throws RestClientException {
|
||||
|
||||
Assert.hasText(pathTemplate, "Path template must not be null or empty");
|
||||
Assert.isTrue(!pathTemplate.startsWith("/"),
|
||||
"Path template must not start with a slash (/)");
|
||||
|
||||
URI uri = uriVariables != null ? buildUri(pathTemplate, uriVariables)
|
||||
: getEndpoint().createUri(pathTemplate);
|
||||
|
||||
return exchange(uri, method, requestEntity, responseType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a {@link RestTemplateCallback}. Allows to interact with the underlying
|
||||
* {@link RestTemplate} and benefit from optional parameter expansion.
|
||||
*
|
||||
* @param pathTemplate the path template.
|
||||
* @param uriVariables the variables to expand in the template
|
||||
* @param callback the request.
|
||||
* @return the {@link RestTemplateCallback} return value.
|
||||
*/
|
||||
public <T> T doWithRestTemplate(String pathTemplate, Map<String, ?> uriVariables,
|
||||
RestTemplateCallback<T> callback) {
|
||||
|
||||
Assert.hasText(pathTemplate, "Path template must not be null or empty");
|
||||
Assert.isTrue(!pathTemplate.startsWith("/"),
|
||||
"Path template must not start with a slash (/)");
|
||||
|
||||
URI uri = uriVariables != null ? buildUri(pathTemplate, uriVariables)
|
||||
: getEndpoint().createUri(pathTemplate);
|
||||
|
||||
return super.doWithRestTemplate(uri, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the configured {@link VaultEndpoint}.
|
||||
*/
|
||||
public VaultEndpoint getEndpoint() {
|
||||
return endpoint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the Vault {@link URI} based on the given {@link VaultEndpoint} and
|
||||
* {@code pathTemplate}. URI template variables will be expanded using
|
||||
* {@code uriVariables}.
|
||||
*
|
||||
* @param pathTemplate must not be empty or {@literal null}.
|
||||
* @param uriVariables must not be {@literal null}.
|
||||
* @return the resolved {@link URI}.
|
||||
* @see org.springframework.web.util.UriComponentsBuilder
|
||||
*/
|
||||
protected URI buildUri(String pathTemplate, Map<String, ?> uriVariables) {
|
||||
|
||||
Assert.hasText(pathTemplate, "Path must not be empty");
|
||||
|
||||
return getRestTemplate().getUriTemplateHandler().expand(
|
||||
getEndpoint().createUriString(pathTemplate), uriVariables);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create {@link HttpHeaders} for a {@link VaultToken}.
|
||||
*
|
||||
* @param vaultToken must not be {@literal null}.
|
||||
* @return {@link HttpHeaders} for a {@link VaultToken}.
|
||||
*/
|
||||
public static HttpHeaders createHeaders(VaultToken vaultToken) {
|
||||
|
||||
Assert.notNull(vaultToken, "Vault Token must not be null");
|
||||
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.add(VAULT_TOKEN, vaultToken.getToken());
|
||||
return headers;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T unwrap(final String wrappedResponse, Class<T> responseType) {
|
||||
|
||||
Assert.hasText(wrappedResponse, "Wrapped response must not be empty");
|
||||
|
||||
try {
|
||||
return (T) converter.read(responseType, new HttpInputMessage() {
|
||||
@Override
|
||||
public InputStream getBody() throws IOException {
|
||||
return new ByteArrayInputStream(wrappedResponse.getBytes());
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpHeaders getHeaders() {
|
||||
return new HttpHeaders();
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.vault.client;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.http.HttpRequest;
|
||||
import org.springframework.http.client.ClientHttpRequestExecution;
|
||||
import org.springframework.http.client.ClientHttpRequestFactory;
|
||||
import org.springframework.http.client.ClientHttpRequestInterceptor;
|
||||
import org.springframework.http.client.ClientHttpResponse;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import org.springframework.web.util.DefaultUriTemplateHandler;
|
||||
|
||||
/**
|
||||
* Vault Client factory to create {@link RestTemplate} configured to the needs of
|
||||
* accessing Vault.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @see VaultEndpoint
|
||||
* @see RestTemplate
|
||||
*/
|
||||
public class VaultClients {
|
||||
|
||||
/**
|
||||
* Create a {@link RestTemplate} configured with {@link VaultEndpoint} and
|
||||
* {@link ClientHttpRequestFactory}. The template accepts relative URIs without a
|
||||
* leading slash that are expanded to use {@link VaultEndpoint}. {@link RestTemplate}
|
||||
* is configured with a {@link ClientHttpRequestInterceptor} to enforce serialization
|
||||
* to a byte array prior continuing the request. Eager serialization leads to a known
|
||||
* request body size that is required to send a
|
||||
* {@link org.springframework.http.HttpHeaders#CONTENT_LENGTH} request header.
|
||||
* Otherwise, Vault will deny body processing.
|
||||
*
|
||||
* @param endpoint must not be {@literal null}.
|
||||
* @param requestFactory must not be {@literal null}.
|
||||
* @return the {@link RestTemplate}.
|
||||
* @see org.springframework.http.client.Netty4ClientHttpRequestFactory
|
||||
*/
|
||||
public static RestTemplate createRestTemplate(VaultEndpoint endpoint,
|
||||
ClientHttpRequestFactory requestFactory) {
|
||||
|
||||
RestTemplate restTemplate = new RestTemplate(requestFactory);
|
||||
|
||||
restTemplate.setUriTemplateHandler(createUriTemplateHandler(endpoint));
|
||||
restTemplate.getInterceptors().add(new ClientHttpRequestInterceptor() {
|
||||
|
||||
@Override
|
||||
public ClientHttpResponse intercept(HttpRequest request, byte[] body,
|
||||
ClientHttpRequestExecution execution) throws IOException {
|
||||
return execution.execute(request, body);
|
||||
}
|
||||
});
|
||||
|
||||
return restTemplate;
|
||||
}
|
||||
|
||||
private static DefaultUriTemplateHandler createUriTemplateHandler(
|
||||
VaultEndpoint endpoint) {
|
||||
|
||||
String baseUrl = String.format("%s://%s:%s/%s/", endpoint.getScheme(),
|
||||
endpoint.getHost(), endpoint.getPort(), "v1");
|
||||
|
||||
DefaultUriTemplateHandler defaultUriTemplateHandler = new PrefixAwareUriTemplateHandler();
|
||||
defaultUriTemplateHandler.setBaseUrl(baseUrl);
|
||||
return defaultUriTemplateHandler;
|
||||
}
|
||||
|
||||
public static class PrefixAwareUriTemplateHandler extends DefaultUriTemplateHandler {
|
||||
|
||||
@Override
|
||||
protected URI expandInternal(String uriTemplate, Map<String, ?> uriVariables) {
|
||||
return super.expandInternal(prepareUriTemplate(uriTemplate), uriVariables);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected URI expandInternal(String uriTemplate, Object... uriVariables) {
|
||||
return super.expandInternal(prepareUriTemplate(uriTemplate), uriVariables);
|
||||
}
|
||||
|
||||
/**
|
||||
* Strip/add leading slashes from {@code uriTemplate} depending on whetner the
|
||||
* base url has a trailing slash.
|
||||
*
|
||||
* @param uriTemplate
|
||||
* @return
|
||||
*/
|
||||
private String prepareUriTemplate(String uriTemplate) {
|
||||
|
||||
if (getBaseUrl() != null) {
|
||||
if (uriTemplate.startsWith("/") && getBaseUrl().endsWith("/")) {
|
||||
return uriTemplate.substring(1);
|
||||
}
|
||||
|
||||
if (!uriTemplate.startsWith("/") && !getBaseUrl().endsWith("/")) {
|
||||
return "/" + uriTemplate;
|
||||
}
|
||||
|
||||
return uriTemplate;
|
||||
}
|
||||
|
||||
if (!uriTemplate.startsWith("/")) {
|
||||
return "/" + uriTemplate;
|
||||
}
|
||||
|
||||
return uriTemplate;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -51,7 +51,8 @@ public class VaultEndpoint implements Serializable {
|
||||
private String scheme = "https";
|
||||
|
||||
/**
|
||||
* Create a {@link VaultEndpoint} given a {@code host} and {@code port}.
|
||||
* 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
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.vault.client;
|
||||
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.vault.support.VaultToken;
|
||||
|
||||
/**
|
||||
* Class providing utility methods to create Vault HTTP headers.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public abstract class VaultHttpHeaders {
|
||||
|
||||
/**
|
||||
* The HTTP {@code X-Vault-Token} header field name.
|
||||
*/
|
||||
public static final String VAULT_TOKEN = "X-Vault-Token";
|
||||
|
||||
private VaultHttpHeaders() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create {@link HttpHeaders} given {@link VaultToken}. The resulting object can be
|
||||
* used to authenticate HTTP requests.
|
||||
* @param vaultToken must not be {@literal null}.
|
||||
* @return {@link HttpHeaders} containing the {@link VaultToken}.
|
||||
*/
|
||||
public static HttpHeaders from(VaultToken vaultToken) {
|
||||
|
||||
Assert.notNull(vaultToken, "VaultToken must not be null");
|
||||
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.add(VAULT_TOKEN, vaultToken.getToken());
|
||||
|
||||
return headers;
|
||||
}
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.vault.client;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import org.springframework.http.HttpStatus;
|
||||
|
||||
/**
|
||||
* Encapsulates the client response used in {@link VaultAccessor}. Consists of the body,
|
||||
* status code the location and a message. The {@code body} is empty for all
|
||||
* non-successful results. This class is immutable.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class VaultResponseEntity<T> {
|
||||
|
||||
private final T body;
|
||||
|
||||
private final HttpStatus statusCode;
|
||||
|
||||
private final URI uri;
|
||||
|
||||
private final String message;
|
||||
|
||||
protected VaultResponseEntity(T body, HttpStatus statusCode, URI uri, String message) {
|
||||
this.body = body;
|
||||
this.statusCode = statusCode;
|
||||
this.uri = uri;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@literal true} if the request was completed successfully.
|
||||
*/
|
||||
public boolean isSuccessful() {
|
||||
return statusCode.is2xxSuccessful();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@literal true} if the request returned a body.
|
||||
*/
|
||||
public boolean hasBody() {
|
||||
return body != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the body of this entity.
|
||||
*/
|
||||
public T getBody() {
|
||||
return body;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the {@link HttpStatus} of this entity.
|
||||
*/
|
||||
public HttpStatus getStatusCode() {
|
||||
return statusCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the request {@link URI} of this entity.
|
||||
*/
|
||||
public URI getUri() {
|
||||
return uri;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the message of this entity. {@literal null} for successful responses but
|
||||
* provided usually when the response yielded an error.
|
||||
*/
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
/*
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.vault.client;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import org.springframework.core.ParameterizedTypeReference;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpInputMessage;
|
||||
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.vault.VaultException;
|
||||
import org.springframework.vault.support.VaultResponseSupport;
|
||||
import org.springframework.web.client.HttpStatusCodeException;
|
||||
|
||||
/**
|
||||
* Utility methods to unwrap Vault responses and build {@link VaultException}.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public abstract class VaultResponses {
|
||||
|
||||
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
|
||||
|
||||
private static final MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(
|
||||
OBJECT_MAPPER);
|
||||
|
||||
/**
|
||||
* Build a {@link VaultException} given {@link HttpStatusCodeException}.
|
||||
* @param e must not be {@literal null}.
|
||||
* @return the {@link VaultException}.
|
||||
*/
|
||||
public static VaultException buildException(HttpStatusCodeException e) {
|
||||
|
||||
Assert.notNull(e, "HttpStatusCodeException must not be null");
|
||||
|
||||
String message = VaultResponses.getError(e.getResponseBodyAsString());
|
||||
|
||||
if (StringUtils.hasText(message)) {
|
||||
return new VaultException(String.format("Status %s: %s", e.getStatusCode(),
|
||||
message));
|
||||
}
|
||||
|
||||
return new VaultException(String.format("Status %s", e.getStatusCode()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a {@link VaultException} given {@link HttpStatusCodeException} and request
|
||||
* {@code path}.
|
||||
* @param e must not be {@literal null}.
|
||||
* @param path
|
||||
* @return the {@link VaultException}.
|
||||
*/
|
||||
public static VaultException buildException(HttpStatusCodeException e, String path) {
|
||||
|
||||
Assert.notNull(e, "HttpStatusCodeException must not be null");
|
||||
|
||||
String message = VaultResponses.getError(e.getResponseBodyAsString());
|
||||
|
||||
if (StringUtils.hasText(message)) {
|
||||
return new VaultException(String.format("Status %s %s: %s",
|
||||
e.getStatusCode(), path, message));
|
||||
}
|
||||
|
||||
return new VaultException(String.format("Status %s %s", e.getStatusCode(), path));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link ParameterizedTypeReference} for {@code responseType}.
|
||||
* @param responseType must not be {@literal null}.
|
||||
* @return the {@link ParameterizedTypeReference} for {@code responseType}.
|
||||
*/
|
||||
public static <T> ParameterizedTypeReference<VaultResponseSupport<T>> getTypeReference(
|
||||
final Class<T> responseType) {
|
||||
|
||||
Assert.notNull(responseType, "Response type must not be null");
|
||||
|
||||
final Type supportType = new ParameterizedType() {
|
||||
|
||||
@Override
|
||||
public Type[] getActualTypeArguments() {
|
||||
return new Type[] { responseType };
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getRawType() {
|
||||
return VaultResponseSupport.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getOwnerType() {
|
||||
return VaultResponseSupport.class;
|
||||
}
|
||||
};
|
||||
|
||||
return new ParameterizedTypeReference<VaultResponseSupport<T>>() {
|
||||
@Override
|
||||
public Type getType() {
|
||||
return supportType;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain the error message from a JSON response.
|
||||
*
|
||||
* @param json must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
public static String getError(String json) {
|
||||
|
||||
Assert.notNull(json, "Error JSON must not be null!");
|
||||
|
||||
if (json.contains("\"errors\":")) {
|
||||
|
||||
try {
|
||||
Map<String, Object> map = OBJECT_MAPPER.readValue(json.getBytes(),
|
||||
Map.class);
|
||||
if (map.containsKey("errors")) {
|
||||
|
||||
Collection<String> errors = (Collection<String>) map.get("errors");
|
||||
if (errors.size() == 1) {
|
||||
return errors.iterator().next();
|
||||
}
|
||||
return errors.toString();
|
||||
}
|
||||
|
||||
}
|
||||
catch (IOException o_O) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
return json;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> T unwrap(final String wrappedResponse, Class<T> responseType) {
|
||||
|
||||
Assert.hasText(wrappedResponse, "Wrapped response must not be empty");
|
||||
|
||||
try {
|
||||
return (T) converter.read(responseType, new HttpInputMessage() {
|
||||
@Override
|
||||
public InputStream getBody() throws IOException {
|
||||
return new ByteArrayInputStream(wrappedResponse.getBytes());
|
||||
}
|
||||
|
||||
@Override
|
||||
public HttpHeaders getHeaders() {
|
||||
return new HttpHeaders();
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
* Copyright 2016-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -30,13 +30,12 @@ import org.springframework.util.Assert;
|
||||
import org.springframework.vault.authentication.ClientAuthentication;
|
||||
import org.springframework.vault.authentication.LifecycleAwareSessionManager;
|
||||
import org.springframework.vault.authentication.SessionManager;
|
||||
import org.springframework.vault.client.VaultClient;
|
||||
import org.springframework.vault.client.VaultClients;
|
||||
import org.springframework.vault.client.VaultEndpoint;
|
||||
import org.springframework.vault.core.DefaultVaultClientFactory;
|
||||
import org.springframework.vault.core.VaultClientFactory;
|
||||
import org.springframework.vault.core.VaultTemplate;
|
||||
import org.springframework.vault.support.ClientOptions;
|
||||
import org.springframework.vault.support.SslConfiguration;
|
||||
import org.springframework.web.client.RestOperations;
|
||||
|
||||
/**
|
||||
* Base class for Spring Vault configuration using JavaConfig.
|
||||
@@ -59,18 +58,55 @@ 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();
|
||||
|
||||
/**
|
||||
* Create a {@link VaultTemplate}.
|
||||
*
|
||||
* @return the {@link VaultTemplate}.
|
||||
* @see #vaultEndpoint()
|
||||
* @see #clientHttpRequestFactoryWrapper()
|
||||
* @see #sessionManager()
|
||||
*/
|
||||
@Bean
|
||||
public VaultTemplate vaultTemplate() {
|
||||
return new VaultTemplate(vaultEndpoint(), clientHttpRequestFactoryWrapper()
|
||||
.getClientHttpRequestFactory(), sessionManager());
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a {@link LifecycleAwareSessionManager} using
|
||||
* {@link #clientAuthentication()}. This {@link SessionManager} uses
|
||||
* {@link #asyncTaskExecutor()}.
|
||||
*
|
||||
* @return the {@link SessionManager} for Vault session management.
|
||||
* @see SessionManager
|
||||
* @see LifecycleAwareSessionManager
|
||||
* @see #restOperations()
|
||||
* @see #clientAuthentication()
|
||||
* @see #asyncTaskExecutor() ()
|
||||
*/
|
||||
@Bean
|
||||
public SessionManager sessionManager() {
|
||||
|
||||
ClientAuthentication clientAuthentication = clientAuthentication();
|
||||
|
||||
Assert.notNull(clientAuthentication, "ClientAuthentication must not be null");
|
||||
|
||||
return new LifecycleAwareSessionManager(clientAuthentication,
|
||||
asyncTaskExecutor(), restOperations());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link AsyncTaskExecutor} used by {@link LifecycleAwareSessionManager}.
|
||||
* Annotate with {@link Bean} in case you want to expose a {@link AsyncTaskExecutor}
|
||||
* instance to the {@link org.springframework.context.ApplicationContext}. This might
|
||||
* be useful to supply managed executor instances or {@link AsyncTaskExecutor}s using
|
||||
* a queue/pooled threads.
|
||||
*
|
||||
*
|
||||
* @return the {@link AsyncTaskExecutor} to use. Must not be {@literal null}.
|
||||
* @see AsyncTaskExecutor
|
||||
*/
|
||||
@@ -79,25 +115,33 @@ public abstract class AbstractVaultConfiguration implements ApplicationContextAw
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a {@link LifecycleAwareSessionManager} using
|
||||
* {@link #clientAuthentication()} and {@link #vaultClient()}. This
|
||||
* {@link SessionManager} uses {@link #asyncTaskExecutor()}.
|
||||
*
|
||||
* @return the {@link SessionManager} for Vault session management.
|
||||
* @see SessionManager
|
||||
* @see LifecycleAwareSessionManager
|
||||
* @see #clientAuthentication()
|
||||
* @see #asyncTaskExecutor() ()
|
||||
* @see #vaultClient()
|
||||
* Construct a {@link RestOperations} object configured for Vault usage.
|
||||
*
|
||||
* @return the {@link RestOperations} to be used for Vault access.
|
||||
* @see #vaultEndpoint()
|
||||
* @see #clientHttpRequestFactoryWrapper()
|
||||
*/
|
||||
public RestOperations restOperations() {
|
||||
return VaultClients.createRestTemplate(vaultEndpoint(),
|
||||
clientHttpRequestFactoryWrapper().getClientHttpRequestFactory());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link ClientFactoryWrapper} containing a {@link ClientHttpRequestFactory}
|
||||
* . {@link ClientHttpRequestFactory} is not exposed as root bean because
|
||||
* {@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()
|
||||
* @see #sslConfiguration()
|
||||
*/
|
||||
@Bean
|
||||
public SessionManager sessionManager() {
|
||||
|
||||
ClientAuthentication clientAuthentication = clientAuthentication();
|
||||
Assert.notNull(clientAuthentication, "ClientAuthentication must not be null");
|
||||
|
||||
return new LifecycleAwareSessionManager(clientAuthentication,
|
||||
asyncTaskExecutor(), vaultClient());
|
||||
public ClientFactoryWrapper clientHttpRequestFactoryWrapper() {
|
||||
return new ClientFactoryWrapper(ClientHttpRequestFactoryFactory.create(
|
||||
clientOptions(), sslConfiguration()));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -117,64 +161,11 @@ public abstract class AbstractVaultConfiguration implements ApplicationContextAw
|
||||
return SslConfiguration.NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link ClientFactoryWrapper} containing a {@link ClientHttpRequestFactory}
|
||||
* . {@link ClientHttpRequestFactory} is not exposed as root bean because
|
||||
* {@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()
|
||||
* @see #sslConfiguration()
|
||||
*/
|
||||
@Bean
|
||||
public ClientFactoryWrapper clientHttpRequestFactoryWrapper() {
|
||||
return new ClientFactoryWrapper(ClientHttpRequestFactoryFactory.create(
|
||||
clientOptions(), sslConfiguration()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the {@link VaultClient}
|
||||
* @see #clientHttpRequestFactoryWrapper()
|
||||
* @see #vaultEndpoint()
|
||||
*/
|
||||
@Bean
|
||||
public VaultClient vaultClient() {
|
||||
return new VaultClient(clientHttpRequestFactoryWrapper()
|
||||
.getClientHttpRequestFactory(), vaultEndpoint());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the {@link VaultClientFactory} to be used with {@link VaultTemplate}. Uses
|
||||
* by default {@link DefaultVaultClientFactory} with the configured
|
||||
* {@link #vaultClient()} instance.
|
||||
*
|
||||
* @return the {@link VaultClientFactory}.
|
||||
*/
|
||||
@Bean
|
||||
public VaultClientFactory vaultClientFactory() {
|
||||
return new DefaultVaultClientFactory(vaultClient());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link VaultTemplate}.
|
||||
*
|
||||
* @return the {@link VaultTemplate}.
|
||||
* @see #vaultClientFactory()
|
||||
* @see #sessionManager()
|
||||
*/
|
||||
@Bean
|
||||
public VaultTemplate vaultTemplate() {
|
||||
return new VaultTemplate(vaultClientFactory(), sessionManager());
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.vault.core;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.vault.client.VaultClient;
|
||||
import org.springframework.vault.client.VaultEndpoint;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
/**
|
||||
* Default implementation of {@link VaultClientFactory}. Returns the provided
|
||||
* {@link VaultClient}.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class DefaultVaultClientFactory implements VaultClientFactory {
|
||||
|
||||
private final VaultClient vaultClient;
|
||||
|
||||
/**
|
||||
* Creates a new {@link DefaultVaultClientFactory} returning always the same
|
||||
* {@link VaultClient}.
|
||||
*
|
||||
* @param vaultClient must not be {@literal null}.
|
||||
*/
|
||||
public DefaultVaultClientFactory(VaultClient vaultClient) {
|
||||
|
||||
Assert.notNull(vaultClient, "VaultClient must not be null");
|
||||
|
||||
this.vaultClient = vaultClient;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link DefaultVaultClientFactory} using a default {@link VaultClient}
|
||||
* and {@link VaultEndpoint}. Will use Vault at {@code https://localhost:8200} .
|
||||
*
|
||||
* @see VaultClient
|
||||
* @see VaultEndpoint
|
||||
*/
|
||||
public DefaultVaultClientFactory() {
|
||||
this(new VaultClient(new RestTemplate(), new VaultEndpoint()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public VaultClient getVaultClient() {
|
||||
return vaultClient;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
* Copyright 2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -15,17 +15,20 @@
|
||||
*/
|
||||
package org.springframework.vault.core;
|
||||
|
||||
import org.springframework.vault.client.VaultClient;
|
||||
import org.springframework.web.client.RestOperations;
|
||||
|
||||
/**
|
||||
* The strategy to produce a {@link VaultClient} instance(s).
|
||||
* A callback for executing arbitrary operations on {@link RestOperations}.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public interface VaultClientFactory {
|
||||
public interface RestOperationsCallback<T> {
|
||||
|
||||
/**
|
||||
* @return a {@link VaultClient}.
|
||||
* Callback method.
|
||||
*
|
||||
* @param restOperations restOperations to use, must not be {@literal null}.
|
||||
* @return a result object or null if none.
|
||||
*/
|
||||
VaultClient getVaultClient();
|
||||
}
|
||||
T doWithRestOperations(RestOperations restOperations);
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
* Copyright 2016-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,36 +16,26 @@
|
||||
package org.springframework.vault.core;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.core.ParameterizedTypeReference;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.vault.client.VaultClient;
|
||||
import org.springframework.vault.client.VaultResponseEntity;
|
||||
import org.springframework.vault.client.VaultAccessor.RestTemplateCallback;
|
||||
import org.springframework.vault.VaultException;
|
||||
import org.springframework.vault.support.VaultResponse;
|
||||
import org.springframework.vault.support.VaultResponseSupport;
|
||||
import org.springframework.web.client.RestClientException;
|
||||
|
||||
/**
|
||||
* Interface that specifies a basic set of Vault operations, implemented by
|
||||
* {@link VaultTemplate}. This is the main entry point to interact with Vault in an
|
||||
* authenticated and unauthenticated context with configured {@link VaultClient}
|
||||
* instances.
|
||||
* authenticated and unauthenticated context.
|
||||
* <p>
|
||||
* {@link VaultOperations} resolves {@link VaultClient} instances and allows execution of
|
||||
* callback methods on various levels. Callbacks can execute requests within a
|
||||
* {@link VaultOperations#doWithVault(SessionCallback) session}, the
|
||||
* {@link VaultOperations#doWithVault(ClientCallback) client (without requiring a
|
||||
* session)} and a
|
||||
* {@link VaultOperations#doWithRestTemplate(String, Map, RestTemplateCallback) low-level}
|
||||
* {@link org.springframework.web.client.RestTemplate} level.
|
||||
* {@link VaultOperations} allows execution of callback methods. Callbacks can execute
|
||||
* requests within a {@link VaultOperations#doWithSession(RestOperationsCallback) session
|
||||
* context} and the {@link VaultOperations#doWithVault(RestOperationsCallback) without a
|
||||
* session}.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @see VaultOperations#doWithVault(ClientCallback)
|
||||
* @see VaultOperations#doWithVault(SessionCallback)
|
||||
* @see VaultOperations#doWithRestTemplate(String, Map, RestTemplateCallback)
|
||||
* @see VaultClient
|
||||
* @see VaultOperations#doWithSession(RestOperationsCallback)
|
||||
* @see VaultOperations#doWithVault(RestOperationsCallback)
|
||||
* @see org.springframework.web.client.RestOperations
|
||||
* @see VaultTemplate
|
||||
* @see VaultTokenOperations
|
||||
* @see org.springframework.vault.authentication.SessionManager
|
||||
@@ -70,7 +60,7 @@ public interface VaultOperations {
|
||||
/**
|
||||
* Returns {@link VaultTransitOperations} if the transit backend is mounted on a
|
||||
* different path than {@code transit}.
|
||||
*
|
||||
*
|
||||
* @param path the mount path
|
||||
* @return the operations interface to interact with the Vault transit backend.
|
||||
*/
|
||||
@@ -134,169 +124,32 @@ public interface VaultOperations {
|
||||
void delete(String path);
|
||||
|
||||
/**
|
||||
* Executes a Vault {@link ClientCallback}. Allows to interact with Vault using
|
||||
* {@link VaultClient} without requiring a session.
|
||||
* 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 ClientCallback} return value.
|
||||
* @return the {@link RestOperationsCallback} return value.
|
||||
* @throws VaultException when a
|
||||
* {@link org.springframework.web.client.HttpStatusCodeException} occurs.
|
||||
* @throws RestClientException exceptions from
|
||||
* {@link org.springframework.web.client.RestOperations}.
|
||||
*/
|
||||
<T> T doWithVault(ClientCallback<T> clientCallback);
|
||||
<T> T doWithVault(RestOperationsCallback<T> clientCallback) throws VaultException,
|
||||
RestClientException;
|
||||
|
||||
/**
|
||||
* Executes a Vault {@link SessionCallback}. Allows to interact with Vault in an
|
||||
* authenticated session.
|
||||
* Executes a Vault {@link RestOperationsCallback}. Allows to interact with Vault in
|
||||
* an authenticated session.
|
||||
*
|
||||
* @param sessionCallback the request.
|
||||
* @return the {@link SessionCallback} return value.
|
||||
* @return the {@link RestOperationsCallback} return value.
|
||||
* @throws VaultException when a
|
||||
* {@link org.springframework.web.client.HttpStatusCodeException} occurs.
|
||||
* @throws RestClientException exceptions from
|
||||
* {@link org.springframework.web.client.RestOperations}.
|
||||
*/
|
||||
<T> T doWithVault(SessionCallback<T> sessionCallback);
|
||||
<T> T doWithSession(RestOperationsCallback<T> sessionCallback) throws VaultException,
|
||||
RestClientException;
|
||||
|
||||
/**
|
||||
* Executes {@link RestTemplateCallback}. Expands the {@code pathTemplate} to an
|
||||
* {@link java.net.URI} and allows low-level interaction with the underlying
|
||||
* {@link org.springframework.web.client.RestTemplate}.
|
||||
*
|
||||
* @param pathTemplate the path of the resource, e.g. {@code transit/ key}/foo}, must
|
||||
* not be empty or {@literal null}.
|
||||
* @param variables the variables for expansion of the {@code pathTemplate}, must not
|
||||
* be {@literal null}.
|
||||
* @param callback the request callback.
|
||||
* @return the {@link RestTemplateCallback} return value.
|
||||
*/
|
||||
<T> T doWithRestTemplate(String pathTemplate, Map<String, ?> variables,
|
||||
RestTemplateCallback<T> callback);
|
||||
|
||||
/**
|
||||
* A callback for executing arbitrary operations on the {@link VaultClient}.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public interface ClientCallback<T> {
|
||||
|
||||
/**
|
||||
* Callback method.
|
||||
*
|
||||
* @param client session to use, must not be {@literal null}.
|
||||
* @return a result object or null if none.
|
||||
*/
|
||||
T doWithVault(VaultClient client);
|
||||
}
|
||||
|
||||
/**
|
||||
* A callback for executing arbitrary operations on the {@link VaultSession}.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public interface SessionCallback<T> {
|
||||
|
||||
/**
|
||||
* Callback method.
|
||||
*
|
||||
* @param session session to use, must not be {@literal null}.
|
||||
* @return a result object or null if none.
|
||||
*/
|
||||
T doWithVault(VaultSession session);
|
||||
}
|
||||
|
||||
/**
|
||||
* An authenticated Vault session. {@link VaultSession} exposes request accessor
|
||||
* methods to be executed in an authenticated context.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public interface VaultSession {
|
||||
|
||||
/**
|
||||
* Retrieve a resource by GETting from the path, and returns the response as
|
||||
* {@link VaultResponseEntity}.
|
||||
*
|
||||
* @param path the path.
|
||||
* @param responseType the type of the return value
|
||||
* @return the response as entity.
|
||||
* @see VaultResponseEntity
|
||||
*/
|
||||
<T, S extends T> VaultResponseEntity<S> getForEntity(String path,
|
||||
Class<T> responseType);
|
||||
|
||||
/**
|
||||
* Issue a POST request using the given object to the path, and returns the
|
||||
* response as {@link VaultResponseEntity}.
|
||||
*
|
||||
* @param path the path.
|
||||
* @param request the Object to be POSTed, may be {@code null}.
|
||||
* @param responseType the type of the return value
|
||||
* @return the response as entity.
|
||||
* @see VaultResponseEntity
|
||||
*/
|
||||
<T, S extends T> VaultResponseEntity<S> postForEntity(String path,
|
||||
Object request, Class<T> responseType);
|
||||
|
||||
/**
|
||||
* Create a new resource by PUTting the given object to the path, and returns the
|
||||
* response as {@link VaultResponseEntity}.
|
||||
*
|
||||
* @param path the path.
|
||||
* @param request the Object to be PUT.
|
||||
* @param responseType the type of the return value
|
||||
* @return the response as entity.
|
||||
* @see VaultResponseEntity
|
||||
*/
|
||||
<T, S extends T> VaultResponseEntity<S> putForEntity(String path, Object request,
|
||||
Class<T> responseType);
|
||||
|
||||
/**
|
||||
* Delete a resource by DELETEing from the path, and returns the response as
|
||||
* {@link VaultResponseEntity}.
|
||||
*
|
||||
* @param path the path.
|
||||
* @param responseType the type of the return value
|
||||
* @return the response as entity.
|
||||
* @see VaultResponseEntity
|
||||
*/
|
||||
<T, S extends T> VaultResponseEntity<S> deleteForEntity(String path,
|
||||
Class<T> responseType);
|
||||
|
||||
/**
|
||||
* Execute the HTTP method to the given URI template, writing the given request
|
||||
* entity to the request, and returns the response as {@link VaultResponseEntity}.
|
||||
* <p>
|
||||
* URI Template variables are using the given URI variables, if any.
|
||||
*
|
||||
* @param pathTemplate the path template.
|
||||
* @param method the HTTP method (GET, POST, etc).
|
||||
* @param requestEntity the entity (headers and/or body) to write to the request,
|
||||
* may be {@code null}.
|
||||
* @param responseType the type of the return value.
|
||||
* @param uriVariables the variables to expand in the template.
|
||||
* @return the response as entity.
|
||||
*/
|
||||
<T, S extends T> VaultResponseEntity<S> exchange(String pathTemplate,
|
||||
HttpMethod method, HttpEntity<?> requestEntity, Class<T> responseType,
|
||||
Map<String, ?> uriVariables);
|
||||
|
||||
/**
|
||||
* Execute the HTTP method to the given path template, writing the given request
|
||||
* entity to the request, and returns the response as {@link VaultResponseEntity}.
|
||||
* The given {@link ParameterizedTypeReference} is used to pass generic type
|
||||
* information:
|
||||
*
|
||||
* <pre class="code">
|
||||
* ParameterizedTypeReference<List<MyBean>> myBean = new ParameterizedTypeReference<List<MyBean>>() {
|
||||
* };
|
||||
* ResponseEntity<List<MyBean>> response = session.exchange("http://example.com",
|
||||
* HttpMethod.GET, null, myBean, null);
|
||||
* </pre>
|
||||
*
|
||||
* @param pathTemplate the path template.
|
||||
* @param method the HTTP method (GET, POST, etc).
|
||||
* @param requestEntity the entity (headers and/or body) to write to the request,
|
||||
* may be {@code null}.
|
||||
* @param responseType the type of the return value.
|
||||
* @param uriVariables the variables to expand in the template.
|
||||
* @return the response as entity.
|
||||
*/
|
||||
<T, S extends T> VaultResponseEntity<S> exchange(String pathTemplate,
|
||||
HttpMethod method, HttpEntity<?> requestEntity,
|
||||
ParameterizedTypeReference<T> responseType, Map<String, ?> uriVariables);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
package org.springframework.vault.core;
|
||||
|
||||
import org.springframework.vault.client.VaultException;
|
||||
import org.springframework.vault.VaultException;
|
||||
import org.springframework.vault.support.CertificateBundle;
|
||||
import org.springframework.vault.support.VaultCertificateRequest;
|
||||
import org.springframework.vault.support.VaultCertificateResponse;
|
||||
|
||||
@@ -20,10 +20,12 @@ import java.util.Map;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.vault.client.VaultException;
|
||||
import org.springframework.vault.client.VaultResponseEntity;
|
||||
import org.springframework.vault.VaultException;
|
||||
import org.springframework.vault.client.VaultResponses;
|
||||
import org.springframework.vault.support.VaultCertificateRequest;
|
||||
import org.springframework.vault.support.VaultCertificateResponse;
|
||||
import org.springframework.web.client.HttpStatusCodeException;
|
||||
import org.springframework.web.client.RestOperations;
|
||||
|
||||
/**
|
||||
* Default implementation of {@link VaultPkiOperations}.
|
||||
@@ -86,33 +88,22 @@ public class VaultPkiTemplate implements VaultPkiOperations {
|
||||
request.put("exclude_cn_from_sans", true);
|
||||
}
|
||||
|
||||
VaultResponseEntity<VaultCertificateResponse> entity = vaultOperations
|
||||
.doWithVault(new VaultOperations.SessionCallback<VaultResponseEntity<VaultCertificateResponse>>() {
|
||||
return vaultOperations
|
||||
.doWithSession(new RestOperationsCallback<VaultCertificateResponse>() {
|
||||
@Override
|
||||
public VaultResponseEntity<VaultCertificateResponse> doWithVault(
|
||||
VaultOperations.VaultSession session) {
|
||||
public VaultCertificateResponse doWithRestOperations(
|
||||
RestOperations restOperations) {
|
||||
|
||||
return session.postForEntity(
|
||||
String.format("%s/issue/%s", path, roleName), request,
|
||||
VaultCertificateResponse.class);
|
||||
try {
|
||||
return restOperations.postForObject(
|
||||
"{path}/issue/{roleName}", request,
|
||||
VaultCertificateResponse.class, path, roleName);
|
||||
}
|
||||
catch (HttpStatusCodeException e) {
|
||||
throw VaultResponses.buildException(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (entity.isSuccessful() && entity.hasBody()) {
|
||||
return entity.getBody();
|
||||
}
|
||||
|
||||
throw new VaultException(buildExceptionMessage(entity));
|
||||
}
|
||||
|
||||
private static String buildExceptionMessage(VaultResponseEntity<?> response) {
|
||||
|
||||
if (StringUtils.hasText(response.getMessage())) {
|
||||
return String.format("Status %s URI %s: %s", response.getStatusCode(),
|
||||
response.getUri(), response.getMessage());
|
||||
}
|
||||
|
||||
return String.format("Status %s URI %s", response.getStatusCode(),
|
||||
response.getUri());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
* Copyright 2016-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,7 +17,7 @@ package org.springframework.vault.core;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.vault.client.VaultException;
|
||||
import org.springframework.vault.VaultException;
|
||||
import org.springframework.vault.support.VaultHealth;
|
||||
import org.springframework.vault.support.VaultInitializationRequest;
|
||||
import org.springframework.vault.support.VaultInitializationResponse;
|
||||
@@ -26,7 +26,7 @@ import org.springframework.vault.support.VaultUnsealStatus;
|
||||
|
||||
/**
|
||||
* Interface that specifies a basic set of administrative Vault operations.
|
||||
*
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public interface VaultSysOperations {
|
||||
@@ -40,7 +40,7 @@ public interface VaultSysOperations {
|
||||
|
||||
/**
|
||||
* Initialize Vault with a {@link VaultInitializationRequest}.
|
||||
*
|
||||
*
|
||||
* @param vaultInitializationRequest must not be {@literal null}.
|
||||
* @return the {@link VaultInitializationResponse}.
|
||||
* @see <a href="https://www.vaultproject.io/docs/http/sys-init.html">PUT
|
||||
@@ -51,7 +51,7 @@ public interface VaultSysOperations {
|
||||
|
||||
/**
|
||||
* Seal vault.
|
||||
*
|
||||
*
|
||||
* @see <a href="https://www.vaultproject.io/docs/http/sys-seal.html">PUT
|
||||
* /sys/seal</a>
|
||||
*/
|
||||
@@ -59,7 +59,7 @@ public interface VaultSysOperations {
|
||||
|
||||
/**
|
||||
* Unseal vault. See {@link VaultUnsealStatus#getProgress()} for progress.
|
||||
*
|
||||
*
|
||||
* @param keyShare must not be empty and not {@literal null}.
|
||||
* @return the {@link VaultUnsealStatus}.
|
||||
* @see <a href="https://www.vaultproject.io/docs/http/sys-unseal.html">PUT
|
||||
@@ -76,7 +76,7 @@ public interface VaultSysOperations {
|
||||
|
||||
/**
|
||||
* Mounts a secret backend {@link VaultMount} to {@code path}.
|
||||
*
|
||||
*
|
||||
* @param path must not be empty or {@literal null}.
|
||||
* @param vaultMount must not be {@literal null}.
|
||||
* @see <a href="https://www.vaultproject.io/docs/http/sys-mounts.html">POST
|
||||
@@ -93,7 +93,7 @@ public interface VaultSysOperations {
|
||||
|
||||
/**
|
||||
* Unmounts the secret backend mount at {@code path}.
|
||||
*
|
||||
*
|
||||
* @param path must not be empty or {@literal null}.
|
||||
* @see <a href="https://www.vaultproject.io/docs/http/sys-mounts.html">DELETE
|
||||
* /sys/mounts/{mount}</a>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
* Copyright 2016-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -15,7 +15,6 @@
|
||||
*/
|
||||
package org.springframework.vault.core;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
@@ -30,16 +29,12 @@ import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import lombok.Data;
|
||||
|
||||
import org.springframework.core.ParameterizedTypeReference;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.vault.client.VaultAccessor;
|
||||
import org.springframework.vault.client.VaultClient;
|
||||
import org.springframework.vault.client.VaultException;
|
||||
import org.springframework.vault.client.VaultResponseEntity;
|
||||
import org.springframework.vault.core.VaultOperations.ClientCallback;
|
||||
import org.springframework.vault.core.VaultOperations.SessionCallback;
|
||||
import org.springframework.vault.VaultException;
|
||||
import org.springframework.vault.client.VaultResponses;
|
||||
import org.springframework.vault.support.VaultHealth;
|
||||
import org.springframework.vault.support.VaultInitializationRequest;
|
||||
import org.springframework.vault.support.VaultInitializationResponse;
|
||||
@@ -48,11 +43,11 @@ import org.springframework.vault.support.VaultResponseSupport;
|
||||
import org.springframework.vault.support.VaultToken;
|
||||
import org.springframework.vault.support.VaultUnsealStatus;
|
||||
import org.springframework.web.client.HttpStatusCodeException;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import org.springframework.web.client.RestOperations;
|
||||
|
||||
/**
|
||||
* Default implementation of {@link VaultSysOperations}.
|
||||
*
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class VaultSysTemplate implements VaultSysOperations {
|
||||
@@ -61,9 +56,9 @@ public class VaultSysTemplate implements VaultSysOperations {
|
||||
|
||||
private static final Seal SEAL = new Seal();
|
||||
|
||||
private static final GetMounts GET_MOUNTS = new GetMounts("sys/mounts");
|
||||
private static final GetMounts GET_MOUNTS = new GetMounts("/sys/mounts");
|
||||
|
||||
private static final GetMounts GET_AUTH_MOUNTS = new GetMounts("sys/auth");
|
||||
private static final GetMounts GET_AUTH_MOUNTS = new GetMounts("/sys/auth");
|
||||
|
||||
private static final Health HEALTH = new Health();
|
||||
|
||||
@@ -84,19 +79,20 @@ public class VaultSysTemplate implements VaultSysOperations {
|
||||
@Override
|
||||
public boolean isInitialized() {
|
||||
|
||||
return vaultOperations.doWithVault(new ClientCallback<Boolean>() {
|
||||
return vaultOperations.doWithVault(new RestOperationsCallback<Boolean>() {
|
||||
|
||||
@Override
|
||||
public Boolean doWithVault(VaultClient client) {
|
||||
public Boolean doWithRestOperations(RestOperations restOperations) {
|
||||
|
||||
VaultResponseEntity<Map<String, Boolean>> response = client.getForEntity(
|
||||
"sys/init", Map.class);
|
||||
try {
|
||||
Map<String, Boolean> body = restOperations.getForObject("/sys/init",
|
||||
Map.class);
|
||||
|
||||
if (response.isSuccessful() && response.hasBody()) {
|
||||
return response.getBody().get("initialized");
|
||||
return body.get("initialized");
|
||||
}
|
||||
catch (HttpStatusCodeException e) {
|
||||
throw VaultResponses.buildException(e);
|
||||
}
|
||||
|
||||
throw new VaultException(buildExceptionMessage(response));
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -108,20 +104,24 @@ public class VaultSysTemplate implements VaultSysOperations {
|
||||
Assert.notNull(vaultInitializationRequest, "VaultInitialization must not be null");
|
||||
|
||||
return vaultOperations
|
||||
.doWithVault(new ClientCallback<VaultInitializationResponse>() {
|
||||
.doWithVault(new RestOperationsCallback<VaultInitializationResponse>() {
|
||||
|
||||
@Override
|
||||
public VaultInitializationResponse doWithVault(VaultClient client) {
|
||||
public VaultInitializationResponse doWithRestOperations(
|
||||
RestOperations restOperations) {
|
||||
|
||||
VaultResponseEntity<VaultInitializationResponseImpl> response = client
|
||||
.putForEntity("sys/init", vaultInitializationRequest,
|
||||
VaultInitializationResponseImpl.class);
|
||||
try {
|
||||
ResponseEntity<VaultInitializationResponseImpl> exchange = restOperations
|
||||
.exchange("/sys/init", HttpMethod.PUT,
|
||||
new HttpEntity<Object>(
|
||||
vaultInitializationRequest),
|
||||
VaultInitializationResponseImpl.class);
|
||||
|
||||
if (response.isSuccessful() && response.hasBody()) {
|
||||
return response.getBody();
|
||||
return exchange.getBody();
|
||||
}
|
||||
catch (HttpStatusCodeException e) {
|
||||
throw VaultResponses.buildException(e);
|
||||
}
|
||||
|
||||
throw new VaultException(buildExceptionMessage(response));
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -134,23 +134,23 @@ public class VaultSysTemplate implements VaultSysOperations {
|
||||
@Override
|
||||
public VaultUnsealStatus unseal(final String keyShare) {
|
||||
|
||||
return vaultOperations.doWithVault(new ClientCallback<VaultUnsealStatus>() {
|
||||
return vaultOperations
|
||||
.doWithVault(new RestOperationsCallback<VaultUnsealStatus>() {
|
||||
@Override
|
||||
public VaultUnsealStatus doWithRestOperations(
|
||||
RestOperations restOperations) {
|
||||
|
||||
@Override
|
||||
public VaultUnsealStatus doWithVault(VaultClient client) {
|
||||
ResponseEntity<VaultUnsealStatusImpl> response = restOperations
|
||||
.exchange(
|
||||
"/sys/unseal",
|
||||
HttpMethod.PUT,
|
||||
new HttpEntity<Object>(Collections.singletonMap(
|
||||
"key", keyShare)),
|
||||
VaultUnsealStatusImpl.class);
|
||||
|
||||
VaultResponseEntity<VaultUnsealStatusImpl> response = client
|
||||
.putForEntity("sys/unseal",
|
||||
Collections.singletonMap("key", keyShare),
|
||||
VaultUnsealStatusImpl.class);
|
||||
|
||||
if (response.isSuccessful() && response.hasBody()) {
|
||||
return response.getBody();
|
||||
}
|
||||
|
||||
throw new VaultException(buildExceptionMessage(response));
|
||||
}
|
||||
});
|
||||
return response.getBody();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -164,12 +164,12 @@ public class VaultSysTemplate implements VaultSysOperations {
|
||||
Assert.hasText(path, "Path must not be empty");
|
||||
Assert.notNull(vaultMount, "VaultMount must not be null");
|
||||
|
||||
vaultOperations.write(String.format("sys/mounts/%s", path), vaultMount);
|
||||
vaultOperations.write(String.format("/sys/mounts/%s", path), vaultMount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, VaultMount> getMounts() {
|
||||
return vaultOperations.doWithVault(GET_MOUNTS);
|
||||
return vaultOperations.doWithSession(GET_MOUNTS);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -177,7 +177,7 @@ public class VaultSysTemplate implements VaultSysOperations {
|
||||
|
||||
Assert.hasText(path, "Path must not be empty");
|
||||
|
||||
vaultOperations.delete(String.format("sys/mounts/%s", path));
|
||||
vaultOperations.delete(String.format("/sys/mounts/%s", path));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -187,12 +187,12 @@ public class VaultSysTemplate implements VaultSysOperations {
|
||||
Assert.hasText(path, "Path must not be empty");
|
||||
Assert.notNull(vaultMount, "VaultMount must not be null");
|
||||
|
||||
vaultOperations.write(String.format("sys/auth/%s", path), vaultMount);
|
||||
vaultOperations.write(String.format("/sys/auth/%s", path), vaultMount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, VaultMount> getAuthMounts() throws VaultException {
|
||||
return vaultOperations.doWithVault(GET_AUTH_MOUNTS);
|
||||
return vaultOperations.doWithSession(GET_AUTH_MOUNTS);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -200,59 +200,36 @@ public class VaultSysTemplate implements VaultSysOperations {
|
||||
|
||||
Assert.hasText(path, "Path must not be empty");
|
||||
|
||||
vaultOperations.delete(String.format("sys/auth/%s", path));
|
||||
vaultOperations.delete(String.format("/sys/auth/%s", path));
|
||||
}
|
||||
|
||||
@Override
|
||||
public VaultHealth health() {
|
||||
return vaultOperations.doWithRestTemplate("sys/health",
|
||||
Collections.<String, Object>emptyMap(), HEALTH);
|
||||
return vaultOperations.doWithVault(HEALTH);
|
||||
}
|
||||
|
||||
private static String buildExceptionMessage(VaultResponseEntity<?> response) {
|
||||
|
||||
if (StringUtils.hasText(response.getMessage())) {
|
||||
return String.format("Status %s URI %s: %s", response.getStatusCode(),
|
||||
response.getUri(), response.getMessage());
|
||||
}
|
||||
|
||||
return String.format("Status %s URI %s", response.getStatusCode(),
|
||||
response.getUri());
|
||||
}
|
||||
|
||||
private static class GetUnsealStatus implements ClientCallback<VaultUnsealStatus> {
|
||||
private static class GetUnsealStatus implements
|
||||
RestOperationsCallback<VaultUnsealStatus> {
|
||||
|
||||
@Override
|
||||
public VaultUnsealStatus doWithVault(VaultClient client) {
|
||||
|
||||
VaultResponseEntity<VaultUnsealStatusImpl> response = client.getForEntity(
|
||||
"sys/seal-status", VaultUnsealStatusImpl.class);
|
||||
|
||||
if (response.isSuccessful() && response.hasBody()) {
|
||||
return response.getBody();
|
||||
}
|
||||
|
||||
throw new VaultException(buildExceptionMessage(response));
|
||||
public VaultUnsealStatus doWithRestOperations(RestOperations restOperations) {
|
||||
return restOperations.getForObject("/sys/seal-status",
|
||||
VaultUnsealStatusImpl.class);
|
||||
}
|
||||
}
|
||||
|
||||
private static class Seal implements SessionCallback<Void> {
|
||||
private static class Seal implements RestOperationsCallback<Void> {
|
||||
|
||||
@Override
|
||||
public Void doWithVault(VaultOperations.VaultSession session) {
|
||||
|
||||
VaultResponseEntity<Map> response = session.putForEntity("sys/seal", null,
|
||||
Map.class);
|
||||
|
||||
if (!response.isSuccessful()) {
|
||||
throw new VaultException(buildExceptionMessage(response));
|
||||
}
|
||||
|
||||
public Void doWithRestOperations(RestOperations restOperations) {
|
||||
restOperations.put("/sys/seal", null);
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class GetMounts implements SessionCallback<Map<String, VaultMount>> {
|
||||
private static class GetMounts implements
|
||||
RestOperationsCallback<Map<String, VaultMount>> {
|
||||
|
||||
private static final ParameterizedTypeReference<VaultMountsResponse> MOUNT_TYPE_REF = new ParameterizedTypeReference<VaultMountsResponse>() {
|
||||
};
|
||||
@@ -264,24 +241,19 @@ public class VaultSysTemplate implements VaultSysOperations {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, VaultMount> doWithVault(VaultOperations.VaultSession session) {
|
||||
public Map<String, VaultMount> doWithRestOperations(RestOperations restOperations) {
|
||||
|
||||
VaultResponseEntity<VaultMountsResponse> response = session.exchange(path,
|
||||
ResponseEntity<VaultMountsResponse> exchange = restOperations.exchange(path,
|
||||
HttpMethod.GET, null, MOUNT_TYPE_REF,
|
||||
Collections.<String, Object>emptyMap());
|
||||
Collections.<String, Object> emptyMap());
|
||||
|
||||
if (response.isSuccessful() && response.hasBody()) {
|
||||
VaultMountsResponse body = exchange.getBody();
|
||||
|
||||
VaultMountsResponse body = response.getBody();
|
||||
|
||||
if (body.getData() != null) {
|
||||
return response.getBody().getData();
|
||||
}
|
||||
|
||||
return response.getBody().getTopLevelMounts();
|
||||
if (body.getData() != null) {
|
||||
return body.getData();
|
||||
}
|
||||
|
||||
throw new VaultException(buildExceptionMessage(response));
|
||||
return body.getTopLevelMounts();
|
||||
}
|
||||
|
||||
private static class VaultMountsResponse extends
|
||||
@@ -317,16 +289,14 @@ public class VaultSysTemplate implements VaultSysOperations {
|
||||
|
||||
}
|
||||
|
||||
private static class Health implements
|
||||
VaultAccessor.RestTemplateCallback<VaultHealth> {
|
||||
private static class Health implements RestOperationsCallback<VaultHealth> {
|
||||
|
||||
@Override
|
||||
public VaultHealth doWithRestTemplate(URI uri, RestTemplate restTemplate) {
|
||||
public VaultHealth doWithRestOperations(RestOperations restOperations) {
|
||||
|
||||
try {
|
||||
|
||||
ResponseEntity<VaultHealthImpl> healthResponse = restTemplate.exchange(
|
||||
uri, HttpMethod.GET, null, VaultHealthImpl.class);
|
||||
ResponseEntity<VaultHealthImpl> healthResponse = restOperations.exchange(
|
||||
"/sys/health", HttpMethod.GET, null, VaultHealthImpl.class);
|
||||
return healthResponse.getBody();
|
||||
}
|
||||
catch (HttpStatusCodeException responseError) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
* Copyright 2016-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -15,8 +15,7 @@
|
||||
*/
|
||||
package org.springframework.vault.core;
|
||||
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -24,40 +23,48 @@ import java.util.Map;
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.core.ParameterizedTypeReference;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpRequest;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.http.client.ClientHttpRequestExecution;
|
||||
import org.springframework.http.client.ClientHttpRequestFactory;
|
||||
import org.springframework.http.client.ClientHttpRequestInterceptor;
|
||||
import org.springframework.http.client.ClientHttpResponse;
|
||||
import org.springframework.http.client.SimpleClientHttpRequestFactory;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.vault.authentication.ClientAuthentication;
|
||||
import org.springframework.vault.authentication.SessionManager;
|
||||
import org.springframework.vault.authentication.SimpleSessionManager;
|
||||
import org.springframework.vault.client.VaultClient;
|
||||
import org.springframework.vault.client.VaultException;
|
||||
import org.springframework.vault.client.VaultResponseEntity;
|
||||
import org.springframework.vault.client.VaultAccessor.RestTemplateCallback;
|
||||
import org.springframework.vault.client.VaultClients;
|
||||
import org.springframework.vault.client.VaultEndpoint;
|
||||
import org.springframework.vault.client.VaultHttpHeaders;
|
||||
import org.springframework.vault.client.VaultResponses;
|
||||
import org.springframework.vault.support.VaultResponse;
|
||||
import org.springframework.vault.support.VaultResponseSupport;
|
||||
import org.springframework.web.client.HttpStatusCodeException;
|
||||
import org.springframework.web.client.RestOperations;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
/**
|
||||
* This class encapsulates main Vault interaction. {@link VaultTemplate} will log into
|
||||
* Vault on initialization and use the token throughout the whole lifetime.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @see VaultClientFactory
|
||||
* @see SessionManager
|
||||
*/
|
||||
public class VaultTemplate implements InitializingBean, VaultOperations, DisposableBean {
|
||||
|
||||
private VaultClientFactory vaultClientFactory;
|
||||
|
||||
private SessionManager sessionManager;
|
||||
|
||||
private RestTemplate sessionTemplate;
|
||||
|
||||
private RestTemplate plainTemplate;
|
||||
|
||||
private final boolean dedicatedSessionManager;
|
||||
|
||||
/**
|
||||
* Creates a new {@link VaultTemplate} without setting {@link VaultClientFactory} and
|
||||
* Creates a new {@link VaultTemplate} without setting {@link RestOperations} and
|
||||
* {@link SessionManager}.
|
||||
*/
|
||||
public VaultTemplate() {
|
||||
@@ -65,56 +72,79 @@ public class VaultTemplate implements InitializingBean, VaultOperations, Disposa
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link VaultTemplate} with a {@link VaultClient} and
|
||||
* Creates a new {@link VaultTemplate} with a {@link VaultEndpoint} and
|
||||
* {@link ClientAuthentication}.
|
||||
*
|
||||
* @param vaultClient must not be {@literal null}.
|
||||
* @param vaultEndpoint must not be {@literal null}.
|
||||
* @param clientAuthentication must not be {@literal null}.
|
||||
*/
|
||||
public VaultTemplate(VaultClient vaultClient,
|
||||
public VaultTemplate(VaultEndpoint vaultEndpoint,
|
||||
ClientAuthentication clientAuthentication) {
|
||||
|
||||
Assert.notNull(vaultClient, "VaultClientFactory must not be null");
|
||||
Assert.notNull(vaultEndpoint, "VaultEndpoint must not be null");
|
||||
Assert.notNull(clientAuthentication, "ClientAuthentication must not be null");
|
||||
|
||||
this.vaultClientFactory = new DefaultVaultClientFactory(vaultClient);
|
||||
this.sessionManager = new SimpleSessionManager(clientAuthentication);
|
||||
this.dedicatedSessionManager = true;
|
||||
|
||||
ClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
|
||||
|
||||
this.sessionTemplate = createSessionTemplate(vaultEndpoint, requestFactory);
|
||||
this.plainTemplate = VaultClients.createRestTemplate(vaultEndpoint,
|
||||
requestFactory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link VaultTemplate} with a {@link VaultClientFactory} and
|
||||
* {@link SessionManager}.
|
||||
*
|
||||
* @param vaultClientFactory must not be {@literal null}.
|
||||
* Creates a new {@link VaultTemplate} with a {@link VaultEndpoint},
|
||||
* {@link ClientHttpRequestFactory} and {@link SessionManager}.
|
||||
*
|
||||
* @param vaultEndpoint must not be {@literal null}.
|
||||
* @param clientHttpRequestFactory must not be {@literal null}.
|
||||
* @param sessionManager must not be {@literal null}.
|
||||
*/
|
||||
public VaultTemplate(VaultClientFactory vaultClientFactory,
|
||||
public VaultTemplate(VaultEndpoint vaultEndpoint,
|
||||
ClientHttpRequestFactory clientHttpRequestFactory,
|
||||
SessionManager sessionManager) {
|
||||
|
||||
Assert.notNull(vaultClientFactory, "VaultClientFactory must not be null");
|
||||
Assert.notNull(vaultEndpoint, "VaultEndpoint must not be null");
|
||||
Assert.notNull(clientHttpRequestFactory,
|
||||
"ClientHttpRequestFactory must not be null");
|
||||
Assert.notNull(sessionManager, "SessionManager must not be null");
|
||||
|
||||
this.vaultClientFactory = vaultClientFactory;
|
||||
this.sessionManager = sessionManager;
|
||||
this.dedicatedSessionManager = false;
|
||||
|
||||
this.sessionTemplate = createSessionTemplate(vaultEndpoint,
|
||||
clientHttpRequestFactory);
|
||||
this.plainTemplate = VaultClients.createRestTemplate(vaultEndpoint,
|
||||
clientHttpRequestFactory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link VaultClientFactory}.
|
||||
*
|
||||
* @param vaultClientFactory must not be {@literal null}.
|
||||
*/
|
||||
public void setVaultClientFactory(VaultClientFactory vaultClientFactory) {
|
||||
private RestTemplate createSessionTemplate(VaultEndpoint endpoint,
|
||||
ClientHttpRequestFactory requestFactory) {
|
||||
|
||||
Assert.notNull(vaultClientFactory, "VaultClientFactory must not be null");
|
||||
RestTemplate restTemplate = VaultClients.createRestTemplate(endpoint,
|
||||
requestFactory);
|
||||
|
||||
this.vaultClientFactory = vaultClientFactory;
|
||||
restTemplate.getInterceptors().add(new ClientHttpRequestInterceptor() {
|
||||
|
||||
@Override
|
||||
public ClientHttpResponse intercept(HttpRequest request, byte[] body,
|
||||
ClientHttpRequestExecution execution) throws IOException {
|
||||
|
||||
request.getHeaders().add(VaultHttpHeaders.VAULT_TOKEN,
|
||||
sessionManager.getSessionToken().getToken());
|
||||
|
||||
return execution.execute(request, body);
|
||||
}
|
||||
});
|
||||
|
||||
return restTemplate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link SessionManager}.
|
||||
*
|
||||
*
|
||||
* @param sessionManager must not be {@literal null}.
|
||||
*/
|
||||
public void setSessionManager(SessionManager sessionManager) {
|
||||
@@ -127,7 +157,6 @@ public class VaultTemplate implements InitializingBean, VaultOperations, Disposa
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
|
||||
Assert.notNull(vaultClientFactory, "VaultClientFactory must not be null");
|
||||
Assert.notNull(sessionManager, "SessionManager must not be null");
|
||||
}
|
||||
|
||||
@@ -137,7 +166,6 @@ public class VaultTemplate implements InitializingBean, VaultOperations, Disposa
|
||||
if (dedicatedSessionManager && sessionManager instanceof DisposableBean) {
|
||||
((DisposableBean) sessionManager).destroy();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -170,40 +198,6 @@ public class VaultTemplate implements InitializingBean, VaultOperations, Disposa
|
||||
return new VaultPkiTemplate(this, path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T doWithVault(ClientCallback<T> clientCallback) {
|
||||
|
||||
Assert.notNull(clientCallback, "ClientCallback must not be null!");
|
||||
Assert.state(vaultClientFactory != null, "VaultClientFactory must not be null");
|
||||
Assert.state(sessionManager != null, "SessionManager must not be null");
|
||||
|
||||
return clientCallback.doWithVault(vaultClientFactory.getVaultClient());
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T doWithVault(SessionCallback<T> sessionCallback) {
|
||||
|
||||
Assert.notNull(sessionCallback, "SessionCallback must not be null!");
|
||||
Assert.state(vaultClientFactory != null, "VaultClientFactory must not be null");
|
||||
Assert.state(sessionManager != null, "SessionManager must not be null");
|
||||
|
||||
VaultClient vaultClient = vaultClientFactory.getVaultClient();
|
||||
|
||||
return sessionCallback.doWithVault(new DefaultVaultSession(sessionManager,
|
||||
vaultClient));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T doWithRestTemplate(String pathTemplate, Map<String, ?> uriVariables,
|
||||
RestTemplateCallback<T> callback) {
|
||||
|
||||
Assert.notNull(callback, "RestTemplateCallback must not be null!");
|
||||
Assert.state(vaultClientFactory != null, "VaultClientFactory must not be null");
|
||||
|
||||
return vaultClientFactory.getVaultClient().doWithRestTemplate(pathTemplate,
|
||||
uriVariables, callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public VaultResponse read(String path) {
|
||||
|
||||
@@ -216,27 +210,23 @@ public class VaultTemplate implements InitializingBean, VaultOperations, Disposa
|
||||
@Override
|
||||
public <T> VaultResponseSupport<T> read(final String path, final Class<T> responseType) {
|
||||
|
||||
final ParameterizedTypeReference<VaultResponseSupport<T>> ref = getTypeReference(responseType);
|
||||
final ParameterizedTypeReference<VaultResponseSupport<T>> ref = VaultResponses
|
||||
.getTypeReference(responseType);
|
||||
|
||||
return doWithVault(new SessionCallback<VaultResponseSupport<T>>() {
|
||||
try {
|
||||
ResponseEntity<VaultResponseSupport<T>> exchange = sessionTemplate.exchange(
|
||||
path, HttpMethod.GET, null, ref);
|
||||
|
||||
@Override
|
||||
public VaultResponseSupport<T> doWithVault(VaultSession session) {
|
||||
return exchange.getBody();
|
||||
}
|
||||
catch (HttpStatusCodeException e) {
|
||||
|
||||
VaultResponseEntity<VaultResponseSupport<T>> entity = session.exchange(
|
||||
path, HttpMethod.GET, null, ref, null);
|
||||
|
||||
if (entity.isSuccessful() && entity.hasBody()) {
|
||||
return entity.getBody();
|
||||
}
|
||||
|
||||
if (entity.getStatusCode() == HttpStatus.NOT_FOUND) {
|
||||
return null;
|
||||
}
|
||||
|
||||
throw new VaultException(buildExceptionMessage(entity));
|
||||
if (e.getStatusCode() == HttpStatus.NOT_FOUND) {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
throw VaultResponses.buildException(e, path);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -259,23 +249,12 @@ public class VaultTemplate implements InitializingBean, VaultOperations, Disposa
|
||||
|
||||
Assert.hasText(path, "Path must not be empty");
|
||||
|
||||
return doWithVault(new SessionCallback<VaultResponse>() {
|
||||
|
||||
@Override
|
||||
public VaultResponse doWithVault(VaultSession session) {
|
||||
VaultResponseEntity<VaultResponse> entity = session.postForEntity(path,
|
||||
body, VaultResponse.class);
|
||||
|
||||
if (entity.isSuccessful()) {
|
||||
if (entity.hasBody()) {
|
||||
return entity.getBody();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
throw new VaultException(buildExceptionMessage(entity));
|
||||
}
|
||||
});
|
||||
try {
|
||||
return sessionTemplate.postForObject(path, body, VaultResponse.class);
|
||||
}
|
||||
catch (HttpStatusCodeException e) {
|
||||
throw VaultResponses.buildException(e, path);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -283,161 +262,67 @@ public class VaultTemplate implements InitializingBean, VaultOperations, Disposa
|
||||
|
||||
Assert.hasText(path, "Path must not be empty");
|
||||
|
||||
doWithVault(new SessionCallback<VaultResponse>() {
|
||||
try {
|
||||
sessionTemplate.delete(path);
|
||||
}
|
||||
catch (HttpStatusCodeException e) {
|
||||
|
||||
@Override
|
||||
public VaultResponse doWithVault(VaultSession session) {
|
||||
VaultResponseEntity<VaultResponse> entity = session.deleteForEntity(path,
|
||||
VaultResponse.class);
|
||||
|
||||
if (entity.isSuccessful()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
throw new VaultException(buildExceptionMessage(entity));
|
||||
if (e.getStatusCode() == HttpStatus.NOT_FOUND) {
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
throw VaultResponses.buildException(e, path);
|
||||
}
|
||||
}
|
||||
|
||||
private <T> ParameterizedTypeReference<VaultResponseSupport<T>> getTypeReference(
|
||||
final Class<T> responseType) {
|
||||
final Type supportType = new ParameterizedType() {
|
||||
@Override
|
||||
public <T> T doWithVault(RestOperationsCallback<T> clientCallback) {
|
||||
|
||||
@Override
|
||||
public Type[] getActualTypeArguments() {
|
||||
return new Type[] { responseType };
|
||||
}
|
||||
Assert.notNull(clientCallback, "Client callback must not be null");
|
||||
|
||||
@Override
|
||||
public Type getRawType() {
|
||||
return VaultResponseSupport.class;
|
||||
}
|
||||
try {
|
||||
return clientCallback.doWithRestOperations(plainTemplate);
|
||||
}
|
||||
catch (HttpStatusCodeException e) {
|
||||
throw VaultResponses.buildException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getOwnerType() {
|
||||
return VaultResponseSupport.class;
|
||||
}
|
||||
};
|
||||
@Override
|
||||
public <T> T doWithSession(RestOperationsCallback<T> sessionCallback) {
|
||||
|
||||
return new ParameterizedTypeReference<VaultResponseSupport<T>>() {
|
||||
@Override
|
||||
public Type getType() {
|
||||
return supportType;
|
||||
}
|
||||
};
|
||||
Assert.notNull(sessionCallback, "Session callback must not be null");
|
||||
|
||||
try {
|
||||
return sessionCallback.doWithRestOperations(sessionTemplate);
|
||||
}
|
||||
catch (HttpStatusCodeException e) {
|
||||
throw VaultResponses.buildException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private <T> T doRead(final String path, final Class<T> responseType) {
|
||||
|
||||
return doWithVault(new SessionCallback<T>() {
|
||||
return doWithSession(new RestOperationsCallback<T>() {
|
||||
|
||||
@Override
|
||||
public T doWithVault(VaultSession session) {
|
||||
public T doWithRestOperations(RestOperations restOperations) {
|
||||
|
||||
VaultResponseEntity<T> entity = session.getForEntity(path, responseType);
|
||||
|
||||
if (entity.isSuccessful() && entity.hasBody()) {
|
||||
return entity.getBody();
|
||||
try {
|
||||
return restOperations.getForObject(path, responseType);
|
||||
}
|
||||
catch (HttpStatusCodeException e) {
|
||||
|
||||
if (entity.getStatusCode() == HttpStatus.NOT_FOUND) {
|
||||
return null;
|
||||
if (e.getStatusCode() == HttpStatus.NOT_FOUND) {
|
||||
return null;
|
||||
}
|
||||
|
||||
throw VaultResponses.buildException(e, path);
|
||||
}
|
||||
|
||||
throw new VaultException(buildExceptionMessage(entity));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static String buildExceptionMessage(VaultResponseEntity<?> response) {
|
||||
|
||||
if (StringUtils.hasText(response.getMessage())) {
|
||||
return String.format("Status %s URI %s: %s", response.getStatusCode(),
|
||||
response.getUri(), response.getMessage());
|
||||
}
|
||||
|
||||
return String.format("Status %s URI %s", response.getStatusCode(),
|
||||
response.getUri());
|
||||
}
|
||||
|
||||
private static class DefaultVaultSession implements VaultSession {
|
||||
|
||||
private final SessionManager sessionManager;
|
||||
|
||||
private final VaultClient vaultClient;
|
||||
|
||||
DefaultVaultSession(SessionManager sessionManager, VaultClient vaultClient) {
|
||||
this.sessionManager = sessionManager;
|
||||
this.vaultClient = vaultClient;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T, S extends T> VaultResponseEntity<S> getForEntity(String path,
|
||||
Class<T> responseType) {
|
||||
return vaultClient.getForEntity(path, sessionManager.getSessionToken(),
|
||||
responseType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T, S extends T> VaultResponseEntity<S> putForEntity(String path,
|
||||
Object request, Class<T> responseType) {
|
||||
return vaultClient.putForEntity(path, sessionManager.getSessionToken(),
|
||||
request, responseType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T, S extends T> VaultResponseEntity<S> postForEntity(String path,
|
||||
Object request, Class<T> responseType) {
|
||||
return vaultClient.postForEntity(path, sessionManager.getSessionToken(),
|
||||
request, responseType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T, S extends T> VaultResponseEntity<S> deleteForEntity(String path,
|
||||
Class<T> responseType) {
|
||||
return vaultClient.deleteForEntity(path, sessionManager.getSessionToken(),
|
||||
responseType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T, S extends T> VaultResponseEntity<S> exchange(String pathTemplate,
|
||||
HttpMethod method, HttpEntity<?> requestEntity, Class<T> responseType,
|
||||
Map<String, ?> uriVariables) {
|
||||
|
||||
HttpEntity<?> requestEntityToUse = getHttpEntity(requestEntity);
|
||||
return vaultClient.exchange(pathTemplate, method, requestEntityToUse,
|
||||
responseType, uriVariables);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T, S extends T> VaultResponseEntity<S> exchange(String pathTemplate,
|
||||
HttpMethod method, HttpEntity<?> requestEntity,
|
||||
ParameterizedTypeReference<T> responseType, Map<String, ?> uriVariables) {
|
||||
|
||||
HttpEntity<?> requestEntityToUse = getHttpEntity(requestEntity);
|
||||
return vaultClient.exchange(pathTemplate, method, requestEntityToUse,
|
||||
responseType, uriVariables);
|
||||
}
|
||||
|
||||
private HttpEntity<?> getHttpEntity(HttpEntity<?> requestEntity) {
|
||||
|
||||
HttpHeaders httpHeaders = VaultClient.createHeaders(sessionManager
|
||||
.getSessionToken());
|
||||
HttpEntity<?> requestEntityToUse = requestEntity;
|
||||
|
||||
if (requestEntityToUse != null) {
|
||||
|
||||
httpHeaders.putAll(requestEntity.getHeaders());
|
||||
requestEntityToUse = new HttpEntity<Object>(requestEntityToUse.getBody(),
|
||||
httpHeaders);
|
||||
}
|
||||
else {
|
||||
requestEntityToUse = new HttpEntity<Object>(httpHeaders);
|
||||
}
|
||||
return requestEntityToUse;
|
||||
}
|
||||
}
|
||||
|
||||
private static class VaultListResponse extends
|
||||
VaultResponseSupport<Map<String, Object>> {
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
* Copyright 2016-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -15,14 +15,14 @@
|
||||
*/
|
||||
package org.springframework.vault.core;
|
||||
|
||||
import org.springframework.vault.client.VaultException;
|
||||
import org.springframework.vault.VaultException;
|
||||
import org.springframework.vault.support.VaultToken;
|
||||
import org.springframework.vault.support.VaultTokenRequest;
|
||||
import org.springframework.vault.support.VaultTokenResponse;
|
||||
|
||||
/**
|
||||
* Interface that specifies token-related operations.
|
||||
*
|
||||
*
|
||||
* @author Mark Paluch
|
||||
* @see <a href="https://www.vaultproject.io/docs/auth/token.html">Auth Backend: Token</a>
|
||||
*/
|
||||
@@ -30,7 +30,7 @@ public interface VaultTokenOperations {
|
||||
|
||||
/**
|
||||
* Create a new token.
|
||||
*
|
||||
*
|
||||
* @return a {@link VaultTokenResponse}
|
||||
* @see <a href="https://www.vaultproject.io/docs/auth/token.html">POST
|
||||
* /auth/token/create</a>
|
||||
@@ -39,7 +39,7 @@ public interface VaultTokenOperations {
|
||||
|
||||
/**
|
||||
* Create a new token for the given {@link VaultTokenRequest}.
|
||||
*
|
||||
*
|
||||
* @param request must not be {@literal null}.
|
||||
* @return a {@link VaultTokenResponse}
|
||||
* @see <a href="https://www.vaultproject.io/docs/auth/token.html">POST
|
||||
@@ -68,7 +68,7 @@ public interface VaultTokenOperations {
|
||||
|
||||
/**
|
||||
* Renew a {@link VaultToken}.
|
||||
*
|
||||
*
|
||||
* @param vaultToken must not be {@literal null}.
|
||||
* @return a {@link VaultTokenResponse}
|
||||
* @see <a href="https://www.vaultproject.io/docs/auth/token.html">POST
|
||||
@@ -78,7 +78,7 @@ public interface VaultTokenOperations {
|
||||
|
||||
/**
|
||||
* Revoke a {@link VaultToken}.
|
||||
*
|
||||
*
|
||||
* @param vaultToken must not be {@literal null}.
|
||||
* @see <a href="https://www.vaultproject.io/docs/auth/token.html">POST
|
||||
* /auth/token/revoke/{token}</a>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
* Copyright 2016-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -15,19 +15,21 @@
|
||||
*/
|
||||
package org.springframework.vault.core;
|
||||
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.vault.client.VaultException;
|
||||
import org.springframework.vault.client.VaultResponseEntity;
|
||||
import org.springframework.vault.core.VaultOperations.SessionCallback;
|
||||
import org.springframework.vault.core.VaultOperations.VaultSession;
|
||||
import org.springframework.vault.client.VaultResponses;
|
||||
import org.springframework.vault.support.VaultResponseSupport;
|
||||
import org.springframework.vault.support.VaultToken;
|
||||
import org.springframework.vault.support.VaultTokenRequest;
|
||||
import org.springframework.vault.support.VaultTokenResponse;
|
||||
import org.springframework.web.client.HttpStatusCodeException;
|
||||
import org.springframework.web.client.RestOperations;
|
||||
|
||||
/**
|
||||
* Default implementation of {@link VaultTokenOperations}.
|
||||
*
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class VaultTokenTemplate implements VaultTokenOperations {
|
||||
@@ -56,7 +58,7 @@ public class VaultTokenTemplate implements VaultTokenOperations {
|
||||
|
||||
Assert.notNull(request, "VaultTokenRequest must not be null");
|
||||
|
||||
return vaultOperations.doWithVault(new CreateToken("auth/token/create", request));
|
||||
return write("/auth/token/create", request, VaultTokenResponse.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -69,8 +71,7 @@ public class VaultTokenTemplate implements VaultTokenOperations {
|
||||
|
||||
Assert.notNull(request, "VaultTokenRequest must not be null");
|
||||
|
||||
return vaultOperations.doWithVault(new CreateToken("auth/token/create-orphan",
|
||||
request));
|
||||
return write("/auth/token/create-orphan", request, VaultTokenResponse.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -78,8 +79,8 @@ public class VaultTokenTemplate implements VaultTokenOperations {
|
||||
|
||||
Assert.notNull(vaultToken, "VaultToken must not be null");
|
||||
|
||||
return vaultOperations.doWithVault(new RenewToken(String.format(
|
||||
"auth/token/renew/%s", vaultToken.getToken())));
|
||||
return write(String.format("/auth/token/renew/%s", vaultToken.getToken()), null,
|
||||
VaultTokenResponse.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -87,8 +88,8 @@ public class VaultTokenTemplate implements VaultTokenOperations {
|
||||
|
||||
Assert.notNull(vaultToken, "VaultToken must not be null");
|
||||
|
||||
vaultOperations.doWithVault(new RevokeToken(String.format("auth/token/revoke/%s",
|
||||
vaultToken.getToken())));
|
||||
write(String.format("/auth/token/revoke/%s", vaultToken.getToken()), null,
|
||||
VaultTokenResponse.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -96,87 +97,29 @@ public class VaultTokenTemplate implements VaultTokenOperations {
|
||||
|
||||
Assert.notNull(vaultToken, "VaultToken must not be null");
|
||||
|
||||
vaultOperations.doWithVault(new RevokeToken(String.format(
|
||||
"auth/token/revoke-orphan/%s", vaultToken.getToken())));
|
||||
write(String.format("/auth/token/revoke-orphan/%s", vaultToken.getToken()), null,
|
||||
VaultTokenResponse.class);
|
||||
}
|
||||
|
||||
private static String buildExceptionMessage(VaultResponseEntity<?> response) {
|
||||
public <T extends VaultResponseSupport<?>> T write(final String path,
|
||||
final Object body, final Class<T> responseType) {
|
||||
|
||||
if (StringUtils.hasText(response.getMessage())) {
|
||||
return String.format("Status %s URI %s: %s", response.getStatusCode(),
|
||||
response.getUri(), response.getMessage());
|
||||
}
|
||||
Assert.hasText(path, "Path must not be empty");
|
||||
|
||||
return String.format("Status %s URI %s", response.getStatusCode(),
|
||||
response.getUri());
|
||||
}
|
||||
return vaultOperations.doWithSession(new RestOperationsCallback<T>() {
|
||||
|
||||
private static class CreateToken implements SessionCallback<VaultTokenResponse> {
|
||||
@Override
|
||||
public T doWithRestOperations(RestOperations restOperations) {
|
||||
try {
|
||||
ResponseEntity<T> exchange = restOperations.exchange(path,
|
||||
HttpMethod.POST, new HttpEntity<Object>(body), responseType);
|
||||
|
||||
private final String path;
|
||||
|
||||
private final VaultTokenRequest request;
|
||||
|
||||
public CreateToken(String path, VaultTokenRequest request) {
|
||||
this.path = path;
|
||||
this.request = request;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VaultTokenResponse doWithVault(VaultSession session) {
|
||||
|
||||
VaultResponseEntity<VaultTokenResponse> response = session.postForEntity(
|
||||
path, request, VaultTokenResponse.class);
|
||||
|
||||
if (response.isSuccessful() && response.hasBody()) {
|
||||
return response.getBody();
|
||||
return exchange.getBody();
|
||||
}
|
||||
catch (HttpStatusCodeException e) {
|
||||
throw VaultResponses.buildException(e, path);
|
||||
}
|
||||
}
|
||||
|
||||
throw new VaultException(buildExceptionMessage(response));
|
||||
}
|
||||
}
|
||||
|
||||
private static class RevokeToken implements SessionCallback<Void> {
|
||||
|
||||
private final String path;
|
||||
|
||||
RevokeToken(String path) {
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void doWithVault(VaultSession session) {
|
||||
|
||||
VaultResponseEntity<VaultTokenResponse> response = session.postForEntity(
|
||||
path, null, VaultTokenResponse.class);
|
||||
|
||||
if (response.isSuccessful()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
throw new VaultException(buildExceptionMessage(response));
|
||||
}
|
||||
}
|
||||
|
||||
private static class RenewToken implements SessionCallback<VaultTokenResponse> {
|
||||
|
||||
private final String path;
|
||||
|
||||
RenewToken(String path) {
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VaultTokenResponse doWithVault(VaultSession session) {
|
||||
|
||||
VaultResponseEntity<VaultTokenResponse> response = session.postForEntity(
|
||||
path, null, VaultTokenResponse.class);
|
||||
|
||||
if (response.isSuccessful() && response.hasBody()) {
|
||||
return response.getBody();
|
||||
}
|
||||
|
||||
throw new VaultException(buildExceptionMessage(response));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.core.env.EnumerablePropertySource;
|
||||
import org.springframework.core.env.PropertySource;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.vault.client.VaultException;
|
||||
import org.springframework.vault.VaultException;
|
||||
import org.springframework.vault.core.VaultOperations;
|
||||
import org.springframework.vault.core.VaultTemplate;
|
||||
import org.springframework.vault.core.util.PropertyTransformer;
|
||||
@@ -135,6 +135,7 @@ public class VaultPropertySource extends EnumerablePropertySource<VaultOperation
|
||||
|
||||
@Override
|
||||
public String[] getPropertyNames() {
|
||||
|
||||
Set<String> strings = this.properties.keySet();
|
||||
return strings.toArray(new String[strings.size()]);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
* Copyright 2016-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -25,7 +25,7 @@ import java.security.spec.KeySpec;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.vault.client.VaultException;
|
||||
import org.springframework.vault.VaultException;
|
||||
|
||||
/**
|
||||
* Value object representing a certificate bundle consisting of a private key, the
|
||||
@@ -62,7 +62,7 @@ public class CertificateBundle {
|
||||
/**
|
||||
* Create a {@link CertificateBundle} given a private key with certificates and the
|
||||
* serial number.
|
||||
*
|
||||
*
|
||||
* @param serialNumber must not be empty or {@literal null}.
|
||||
* @param certificate must not be empty or {@literal null}.
|
||||
* @param issuingCaCertificate must not be empty or {@literal null}.
|
||||
@@ -112,7 +112,7 @@ public class CertificateBundle {
|
||||
/**
|
||||
* Retrieve the private key as {@link KeySpec}. Only supported if private key is
|
||||
* DER-encoded.
|
||||
*
|
||||
*
|
||||
* @return the private {@link KeySpec}. {@link java.security.KeyFactory} can generate
|
||||
* a {@link java.security.PrivateKey} from this {@link KeySpec}.
|
||||
*/
|
||||
@@ -130,7 +130,7 @@ public class CertificateBundle {
|
||||
/**
|
||||
* Retrieve the certificate as {@link X509Certificate}. Only supported if certificate
|
||||
* is DER-encoded.
|
||||
*
|
||||
*
|
||||
* @return the {@link X509Certificate}.
|
||||
*/
|
||||
public X509Certificate getX509Certificate() {
|
||||
@@ -173,7 +173,7 @@ public class CertificateBundle {
|
||||
* Create a {@link KeyStore} from this {@link CertificateBundle} containing the
|
||||
* private key and certificate chain. Only supported if certificate and private key
|
||||
* are DER-encoded.
|
||||
*
|
||||
*
|
||||
* @param keyAlias the key alias to use.
|
||||
* @return the {@link KeyStore} containing the private key and certificate chain.
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
* Copyright 2016-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -21,20 +21,20 @@ import java.util.Map;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.vault.client.VaultClient;
|
||||
import org.springframework.vault.client.VaultEndpoint;
|
||||
import org.springframework.vault.client.VaultException;
|
||||
import org.springframework.vault.core.VaultOperations;
|
||||
import org.springframework.vault.VaultException;
|
||||
import org.springframework.vault.core.RestOperationsCallback;
|
||||
import org.springframework.vault.support.VaultToken;
|
||||
import org.springframework.vault.util.IntegrationTestSupport;
|
||||
import org.springframework.vault.util.Settings;
|
||||
import org.springframework.vault.util.TestRestTemplateFactory;
|
||||
import org.springframework.web.client.RestOperations;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Integration tests for {@link AppIdAuthentication}.
|
||||
*
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class AppIdAuthenticationIntegrationTests extends IntegrationTestSupport {
|
||||
@@ -46,24 +46,23 @@ public class AppIdAuthenticationIntegrationTests extends IntegrationTestSupport
|
||||
prepare().mountAuth("app-id");
|
||||
}
|
||||
|
||||
prepare().getVaultOperations().doWithVault(
|
||||
new VaultOperations.SessionCallback<Object>() {
|
||||
|
||||
prepare().getVaultOperations().doWithSession(
|
||||
new RestOperationsCallback<Object>() {
|
||||
@Override
|
||||
public Object doWithVault(VaultOperations.VaultSession session) {
|
||||
public Object doWithRestOperations(RestOperations restOperations) {
|
||||
|
||||
Map<String, String> appIdData = new HashMap<String, String>();
|
||||
appIdData.put("value", "dummy"); // policy
|
||||
appIdData.put("display_name", "this is my test application");
|
||||
|
||||
session.postForEntity("auth/app-id/map/app-id/myapp", appIdData,
|
||||
Map.class);
|
||||
restOperations.postForEntity("auth/app-id/map/app-id/myapp",
|
||||
appIdData, Map.class);
|
||||
|
||||
Map<String, String> userIdData = new HashMap<String, String>();
|
||||
userIdData.put("value", "myapp"); // name of the app-id
|
||||
userIdData.put("cidr_block", "0.0.0.0/0");
|
||||
|
||||
session.postForEntity(
|
||||
restOperations.postForEntity(
|
||||
"auth/app-id/map/user-id/static-userid-value",
|
||||
userIdData, Map.class);
|
||||
|
||||
@@ -80,10 +79,11 @@ public class AppIdAuthenticationIntegrationTests extends IntegrationTestSupport
|
||||
.userIdMechanism(new StaticUserId("static-userid-value")) //
|
||||
.build();
|
||||
|
||||
VaultClient vaultClient = new VaultClient(TestRestTemplateFactory.create(Settings
|
||||
.createSslConfiguration()), new VaultEndpoint());
|
||||
RestTemplate restTemplate = TestRestTemplateFactory.create(Settings
|
||||
.createSslConfiguration());
|
||||
|
||||
AppIdAuthentication authentication = new AppIdAuthentication(options, vaultClient);
|
||||
AppIdAuthentication authentication = new AppIdAuthentication(options,
|
||||
restTemplate);
|
||||
VaultToken login = authentication.login();
|
||||
|
||||
assertThat(login.getToken()).isNotEmpty();
|
||||
@@ -97,9 +97,9 @@ public class AppIdAuthenticationIntegrationTests extends IntegrationTestSupport
|
||||
.userIdMechanism(new StaticUserId("wrong")) //
|
||||
.build();
|
||||
|
||||
VaultClient vaultClient = new VaultClient(TestRestTemplateFactory.create(Settings
|
||||
.createSslConfiguration()), new VaultEndpoint());
|
||||
RestTemplate restTemplate = TestRestTemplateFactory.create(Settings
|
||||
.createSslConfiguration());
|
||||
|
||||
new AppIdAuthentication(options, vaultClient).login();
|
||||
new AppIdAuthentication(options, restTemplate).login();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
* Copyright 2016-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -21,9 +21,8 @@ import org.junit.Test;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.web.client.MockRestServiceServer;
|
||||
import org.springframework.vault.client.VaultClient;
|
||||
import org.springframework.vault.client.VaultEndpoint;
|
||||
import org.springframework.vault.client.VaultException;
|
||||
import org.springframework.vault.VaultException;
|
||||
import org.springframework.vault.client.VaultClients.PrefixAwareUriTemplateHandler;
|
||||
import org.springframework.vault.support.VaultToken;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
@@ -36,20 +35,21 @@ import static org.springframework.test.web.client.response.MockRestResponseCreat
|
||||
|
||||
/**
|
||||
* Unit tests for {@link AppIdAuthentication}.
|
||||
*
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class AppIdAuthenticationUnitTests {
|
||||
|
||||
private VaultClient vaultClient;
|
||||
private RestTemplate restTemplate;
|
||||
private MockRestServiceServer mockRest;
|
||||
|
||||
@Before
|
||||
public void before() throws Exception {
|
||||
|
||||
RestTemplate restTemplate = new RestTemplate();
|
||||
mockRest = MockRestServiceServer.createServer(restTemplate);
|
||||
vaultClient = new VaultClient(restTemplate, new VaultEndpoint());
|
||||
restTemplate.setUriTemplateHandler(new PrefixAwareUriTemplateHandler());
|
||||
this.mockRest = MockRestServiceServer.createServer(restTemplate);
|
||||
this.restTemplate = restTemplate;
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -60,19 +60,15 @@ public class AppIdAuthenticationUnitTests {
|
||||
.userIdMechanism(new StaticUserId("world")) //
|
||||
.build();
|
||||
|
||||
mockRest.expect(requestTo("https://localhost:8200/v1/auth/app-id/login"))
|
||||
//
|
||||
mockRest.expect(requestTo("/auth/app-id/login"))
|
||||
.andExpect(method(HttpMethod.POST))
|
||||
//
|
||||
.andExpect(jsonPath("$.app_id").value("hello"))
|
||||
//
|
||||
.andExpect(jsonPath("$.user_id").value("world"))
|
||||
//
|
||||
.andRespond(withSuccess().contentType(MediaType.APPLICATION_JSON)
|
||||
.body("{" + "\"auth\":{\"client_token\":\"my-token\"}" + "}"));
|
||||
|
||||
AppIdAuthentication authentication = new AppIdAuthentication(options,
|
||||
vaultClient);
|
||||
restTemplate);
|
||||
|
||||
VaultToken login = authentication.login();
|
||||
assertThat(login).isInstanceOf(LoginToken.class);
|
||||
@@ -87,9 +83,9 @@ public class AppIdAuthenticationUnitTests {
|
||||
.userIdMechanism(new StaticUserId("world")) //
|
||||
.build();
|
||||
|
||||
mockRest.expect(requestTo("https://localhost:8200/v1/auth/app-id/login")) //
|
||||
mockRest.expect(requestTo("/auth/app-id/login")) //
|
||||
.andRespond(withServerError());
|
||||
|
||||
new AppIdAuthentication(options, vaultClient).login();
|
||||
new AppIdAuthentication(options, restTemplate).login();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
* Copyright 2016-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -22,10 +22,12 @@ import java.util.Map;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.vault.client.VaultException;
|
||||
import org.springframework.vault.VaultException;
|
||||
import org.springframework.vault.core.RestOperationsCallback;
|
||||
import org.springframework.vault.core.VaultOperations;
|
||||
import org.springframework.vault.support.VaultResponse;
|
||||
import org.springframework.vault.util.IntegrationTestSupport;
|
||||
import org.springframework.web.client.RestOperations;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.hamcrest.CoreMatchers.anyOf;
|
||||
@@ -54,26 +56,25 @@ public class AppRoleAuthenticationIntegrationTests extends IntegrationTestSuppor
|
||||
prepare().mountAuth("approle");
|
||||
}
|
||||
|
||||
getVaultOperations().doWithVault(new VaultOperations.SessionCallback<Object>() {
|
||||
|
||||
getVaultOperations().doWithSession(new RestOperationsCallback<Object>() {
|
||||
@Override
|
||||
public Object doWithVault(VaultOperations.VaultSession session) {
|
||||
public Object doWithRestOperations(RestOperations restOperations) {
|
||||
|
||||
Map<String, String> withSecretId = new HashMap<String, String>();
|
||||
withSecretId.put("policies", "dummy"); // policy
|
||||
withSecretId.put("bound_cidr_list", "0.0.0.0/0");
|
||||
withSecretId.put("bind_secret_id", "true");
|
||||
|
||||
session.postForEntity("auth/approle/role/with-secret-id", withSecretId,
|
||||
Map.class);
|
||||
restOperations.postForEntity("auth/approle/role/with-secret-id",
|
||||
withSecretId, Map.class);
|
||||
|
||||
Map<String, String> noSecretIdRole = new HashMap<String, String>();
|
||||
noSecretIdRole.put("policies", "dummy"); // policy
|
||||
noSecretIdRole.put("bound_cidr_list", "0.0.0.0/0");
|
||||
noSecretIdRole.put("bind_secret_id", "false");
|
||||
|
||||
session.postForEntity("auth/approle/role/no-secret-id", noSecretIdRole,
|
||||
Map.class);
|
||||
restOperations.postForEntity("auth/approle/role/no-secret-id",
|
||||
noSecretIdRole, Map.class);
|
||||
|
||||
return null;
|
||||
}
|
||||
@@ -87,7 +88,7 @@ public class AppRoleAuthenticationIntegrationTests extends IntegrationTestSuppor
|
||||
AppRoleAuthenticationOptions options = AppRoleAuthenticationOptions.builder()
|
||||
.roleId(roleId).build();
|
||||
AppRoleAuthentication authentication = new AppRoleAuthentication(options,
|
||||
prepare().getVaultClient());
|
||||
prepare().getRestTemplate());
|
||||
|
||||
assertThat(authentication.login()).isNotNull();
|
||||
}
|
||||
@@ -103,7 +104,7 @@ public class AppRoleAuthenticationIntegrationTests extends IntegrationTestSuppor
|
||||
AppRoleAuthenticationOptions options = AppRoleAuthenticationOptions.builder()
|
||||
.roleId(roleId).secretId(secretId).build();
|
||||
AppRoleAuthentication authentication = new AppRoleAuthentication(options,
|
||||
prepare().getVaultClient());
|
||||
prepare().getRestTemplate());
|
||||
|
||||
assertThat(authentication.login()).isNotNull();
|
||||
}
|
||||
@@ -116,7 +117,7 @@ public class AppRoleAuthenticationIntegrationTests extends IntegrationTestSuppor
|
||||
AppRoleAuthenticationOptions options = AppRoleAuthenticationOptions.builder()
|
||||
.roleId(roleId).build();
|
||||
AppRoleAuthentication authentication = new AppRoleAuthentication(options,
|
||||
prepare().getVaultClient());
|
||||
prepare().getRestTemplate());
|
||||
|
||||
assertThat(authentication.login()).isNotNull();
|
||||
}
|
||||
@@ -129,7 +130,7 @@ public class AppRoleAuthenticationIntegrationTests extends IntegrationTestSuppor
|
||||
AppRoleAuthenticationOptions options = AppRoleAuthenticationOptions.builder()
|
||||
.roleId(roleId).secretId("this-is-a-wrong-secret-id").build();
|
||||
AppRoleAuthentication authentication = new AppRoleAuthentication(options,
|
||||
prepare().getVaultClient());
|
||||
prepare().getRestTemplate());
|
||||
|
||||
assertThat(authentication.login()).isNotNull();
|
||||
}
|
||||
@@ -147,7 +148,7 @@ public class AppRoleAuthenticationIntegrationTests extends IntegrationTestSuppor
|
||||
AppRoleAuthenticationOptions options = AppRoleAuthenticationOptions.builder()
|
||||
.roleId(roleId).secretId(secretId).build();
|
||||
AppRoleAuthentication authentication = new AppRoleAuthentication(options,
|
||||
prepare().getVaultClient());
|
||||
prepare().getRestTemplate());
|
||||
|
||||
assertThat(authentication.login()).isNotNull();
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
* Copyright 2016-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -21,9 +21,8 @@ import org.junit.Test;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.web.client.MockRestServiceServer;
|
||||
import org.springframework.vault.client.VaultClient;
|
||||
import org.springframework.vault.client.VaultEndpoint;
|
||||
import org.springframework.vault.client.VaultException;
|
||||
import org.springframework.vault.VaultException;
|
||||
import org.springframework.vault.client.VaultClients.PrefixAwareUriTemplateHandler;
|
||||
import org.springframework.vault.support.VaultToken;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
@@ -36,20 +35,22 @@ import static org.springframework.test.web.client.response.MockRestResponseCreat
|
||||
|
||||
/**
|
||||
* Unit tests for {@link AppRoleAuthentication}.
|
||||
*
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class AppRoleAuthenticationUnitTests {
|
||||
|
||||
private VaultClient vaultClient;
|
||||
private RestTemplate restTemplate;
|
||||
private MockRestServiceServer mockRest;
|
||||
|
||||
@Before
|
||||
public void before() throws Exception {
|
||||
|
||||
RestTemplate restTemplate = new RestTemplate();
|
||||
mockRest = MockRestServiceServer.createServer(restTemplate);
|
||||
vaultClient = new VaultClient(restTemplate, new VaultEndpoint());
|
||||
restTemplate.setUriTemplateHandler(new PrefixAwareUriTemplateHandler());
|
||||
|
||||
this.mockRest = MockRestServiceServer.createServer(restTemplate);
|
||||
this.restTemplate = restTemplate;
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -60,19 +61,15 @@ public class AppRoleAuthenticationUnitTests {
|
||||
.secretId("world") //
|
||||
.build();
|
||||
|
||||
mockRest.expect(requestTo("https://localhost:8200/v1/auth/approle/login"))
|
||||
//
|
||||
mockRest.expect(requestTo("/auth/approle/login"))
|
||||
.andExpect(method(HttpMethod.POST))
|
||||
//
|
||||
.andExpect(jsonPath("$.role_id").value("hello"))
|
||||
//
|
||||
.andExpect(jsonPath("$.secret_id").value("world"))
|
||||
//
|
||||
.andRespond(
|
||||
withSuccess().contentType(MediaType.APPLICATION_JSON).body(
|
||||
"{" + "\"auth\":{\"client_token\":\"my-token\"}" + "}"));
|
||||
|
||||
AppRoleAuthentication sut = new AppRoleAuthentication(options, vaultClient);
|
||||
AppRoleAuthentication sut = new AppRoleAuthentication(options, restTemplate);
|
||||
|
||||
VaultToken login = sut.login();
|
||||
|
||||
@@ -87,14 +84,10 @@ public class AppRoleAuthenticationUnitTests {
|
||||
.roleId("hello") //
|
||||
.build();
|
||||
|
||||
mockRest.expect(requestTo("https://localhost:8200/v1/auth/approle/login"))
|
||||
//
|
||||
mockRest.expect(requestTo("/auth/approle/login"))
|
||||
.andExpect(method(HttpMethod.POST))
|
||||
//
|
||||
.andExpect(jsonPath("$.role_id").value("hello"))
|
||||
//
|
||||
.andExpect(jsonPath("$.secret_id").doesNotExist())
|
||||
//
|
||||
.andRespond(
|
||||
withSuccess()
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
@@ -102,7 +95,7 @@ public class AppRoleAuthenticationUnitTests {
|
||||
+ "\"auth\":{\"client_token\":\"my-token\", \"lease_duration\": 10, \"renewable\": true}"
|
||||
+ "}"));
|
||||
|
||||
AppRoleAuthentication sut = new AppRoleAuthentication(options, vaultClient);
|
||||
AppRoleAuthentication sut = new AppRoleAuthentication(options, restTemplate);
|
||||
|
||||
VaultToken login = sut.login();
|
||||
|
||||
@@ -119,9 +112,9 @@ public class AppRoleAuthenticationUnitTests {
|
||||
.roleId("hello") //
|
||||
.build();
|
||||
|
||||
mockRest.expect(requestTo("https://localhost:8200/v1/auth/approle/login")) //
|
||||
mockRest.expect(requestTo("/auth/approle/login")) //
|
||||
.andRespond(withServerError());
|
||||
|
||||
new AppRoleAuthentication(options, vaultClient).login();
|
||||
new AppRoleAuthentication(options, restTemplate).login();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
* Copyright 2016-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -24,9 +24,8 @@ import org.junit.Test;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.web.client.MockRestServiceServer;
|
||||
import org.springframework.vault.client.VaultClient;
|
||||
import org.springframework.vault.client.VaultEndpoint;
|
||||
import org.springframework.vault.client.VaultException;
|
||||
import org.springframework.vault.VaultException;
|
||||
import org.springframework.vault.client.VaultClients.PrefixAwareUriTemplateHandler;
|
||||
import org.springframework.vault.support.VaultToken;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
@@ -44,15 +43,17 @@ import static org.springframework.test.web.client.response.MockRestResponseCreat
|
||||
*/
|
||||
public class AwsEc2AuthenticationUnitTests {
|
||||
|
||||
private VaultClient vaultClient;
|
||||
private RestTemplate restTemplate;
|
||||
private MockRestServiceServer mockRest;
|
||||
|
||||
@Before
|
||||
public void before() throws Exception {
|
||||
|
||||
RestTemplate restTemplate = new RestTemplate();
|
||||
mockRest = MockRestServiceServer.createServer(restTemplate);
|
||||
vaultClient = new VaultClient(restTemplate, new VaultEndpoint());
|
||||
restTemplate.setUriTemplateHandler(new PrefixAwareUriTemplateHandler());
|
||||
|
||||
this.mockRest = MockRestServiceServer.createServer(restTemplate);
|
||||
this.restTemplate = restTemplate;
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -63,7 +64,7 @@ public class AwsEc2AuthenticationUnitTests {
|
||||
.andExpect(method(HttpMethod.GET)) //
|
||||
.andRespond(withSuccess().body("Hello, world"));
|
||||
|
||||
AwsEc2Authentication authentication = new AwsEc2Authentication(vaultClient);
|
||||
AwsEc2Authentication authentication = new AwsEc2Authentication(restTemplate);
|
||||
|
||||
assertThat(authentication.getEc2Login()).containsEntry("pkcs7", "Hello, world")
|
||||
.containsKey("nonce").hasSize(2);
|
||||
@@ -81,7 +82,7 @@ public class AwsEc2AuthenticationUnitTests {
|
||||
.andRespond(withSuccess().body("Hello, world"));
|
||||
|
||||
AwsEc2Authentication authentication = new AwsEc2Authentication(options,
|
||||
vaultClient, vaultClient.getRestTemplate());
|
||||
restTemplate, restTemplate);
|
||||
|
||||
assertThat(authentication.getEc2Login()) //
|
||||
.containsEntry("pkcs7", "Hello, world") //
|
||||
@@ -92,12 +93,9 @@ public class AwsEc2AuthenticationUnitTests {
|
||||
@Test
|
||||
public void shouldLogin() throws Exception {
|
||||
|
||||
mockRest.expect(requestTo("https://localhost:8200/v1/auth/aws-ec2/login"))
|
||||
//
|
||||
mockRest.expect(requestTo("/auth/aws-ec2/login"))
|
||||
.andExpect(method(HttpMethod.POST))
|
||||
//
|
||||
.andExpect(jsonPath("$.pkcs7").value("value"))
|
||||
//
|
||||
.andRespond(
|
||||
withSuccess()
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
@@ -105,7 +103,7 @@ public class AwsEc2AuthenticationUnitTests {
|
||||
+ "\"auth\":{\"client_token\":\"my-token\", \"lease_duration\":20}"
|
||||
+ "}"));
|
||||
|
||||
AwsEc2Authentication authentication = new AwsEc2Authentication(vaultClient) {
|
||||
AwsEc2Authentication authentication = new AwsEc2Authentication(restTemplate) {
|
||||
@Override
|
||||
protected Map<String, String> getEc2Login() {
|
||||
return Collections.singletonMap("pkcs7", "value");
|
||||
@@ -127,16 +125,16 @@ public class AwsEc2AuthenticationUnitTests {
|
||||
requestTo("http://169.254.169.254/latest/dynamic/instance-identity/pkcs7")) //
|
||||
.andRespond(withServerError());
|
||||
|
||||
new AwsEc2Authentication(vaultClient).login();
|
||||
new AwsEc2Authentication(restTemplate).login();
|
||||
}
|
||||
|
||||
@Test(expected = VaultException.class)
|
||||
public void loginShouldFail() throws Exception {
|
||||
|
||||
mockRest.expect(requestTo("https://localhost:8200/v1/auth/aws-ec2/login")) //
|
||||
mockRest.expect(requestTo("/auth/aws-ec2/login")) //
|
||||
.andRespond(withServerError());
|
||||
|
||||
new AwsEc2Authentication(vaultClient) {
|
||||
new AwsEc2Authentication(restTemplate) {
|
||||
@Override
|
||||
protected Map<String, String> getEc2Login() {
|
||||
return Collections.singletonMap("pkcs7", "value");
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
* Copyright 2016-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -27,15 +27,17 @@ import org.junit.Test;
|
||||
import org.springframework.core.NestedRuntimeException;
|
||||
import org.springframework.core.io.FileSystemResource;
|
||||
import org.springframework.http.client.ClientHttpRequestFactory;
|
||||
import org.springframework.vault.client.VaultClient;
|
||||
import org.springframework.vault.client.VaultEndpoint;
|
||||
import org.springframework.vault.client.VaultClients;
|
||||
import org.springframework.vault.config.ClientHttpRequestFactoryFactory;
|
||||
import org.springframework.vault.core.VaultOperations;
|
||||
import org.springframework.vault.core.RestOperationsCallback;
|
||||
import org.springframework.vault.support.ClientOptions;
|
||||
import org.springframework.vault.support.SslConfiguration;
|
||||
import org.springframework.vault.support.VaultToken;
|
||||
import org.springframework.vault.util.IntegrationTestSupport;
|
||||
import org.springframework.vault.util.Settings;
|
||||
import org.springframework.vault.util.TestRestTemplateFactory;
|
||||
import org.springframework.web.client.RestOperations;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.springframework.vault.util.Settings.createSslConfiguration;
|
||||
@@ -43,7 +45,7 @@ import static org.springframework.vault.util.Settings.findWorkDir;
|
||||
|
||||
/**
|
||||
* Integration tests for {@link ClientCertificateAuthentication}.
|
||||
*
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class ClientCertificateAuthenticationIntegrationTests extends
|
||||
@@ -56,21 +58,18 @@ public class ClientCertificateAuthenticationIntegrationTests extends
|
||||
prepare().mountAuth("cert");
|
||||
}
|
||||
|
||||
prepare().getVaultOperations().doWithVault(
|
||||
new VaultOperations.SessionCallback<Object>() {
|
||||
prepare().getVaultOperations().doWithSession(
|
||||
new RestOperationsCallback<Object>() {
|
||||
@Override
|
||||
public Object doWithVault(VaultOperations.VaultSession session) {
|
||||
|
||||
public Object doWithRestOperations(RestOperations restOperations) {
|
||||
File workDir = findWorkDir();
|
||||
|
||||
String certificate = Files.contentOf(new File(workDir,
|
||||
"ca/certs/client.cert.pem"), Charset.forName("US-ASCII"));
|
||||
|
||||
session.postForEntity("auth/cert/certs/my-role",
|
||||
return restOperations.postForEntity("auth/cert/certs/my-role",
|
||||
Collections.singletonMap("certificate", certificate),
|
||||
Map.class);
|
||||
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -80,11 +79,11 @@ public class ClientCertificateAuthenticationIntegrationTests extends
|
||||
|
||||
ClientHttpRequestFactory clientHttpRequestFactory = ClientHttpRequestFactoryFactory
|
||||
.create(new ClientOptions(), prepareCertAuthenticationMethod());
|
||||
VaultClient vaultClient = new VaultClient(clientHttpRequestFactory,
|
||||
new VaultEndpoint());
|
||||
|
||||
RestTemplate restTemplate = VaultClients.createRestTemplate(
|
||||
TestRestTemplateFactory.TEST_VAULT_ENDPOINT, clientHttpRequestFactory);
|
||||
ClientCertificateAuthentication authentication = new ClientCertificateAuthentication(
|
||||
vaultClient);
|
||||
restTemplate);
|
||||
VaultToken login = authentication.login();
|
||||
|
||||
assertThat(login.getToken()).isNotEmpty();
|
||||
@@ -97,10 +96,10 @@ public class ClientCertificateAuthenticationIntegrationTests extends
|
||||
|
||||
ClientHttpRequestFactory clientHttpRequestFactory = ClientHttpRequestFactoryFactory
|
||||
.create(new ClientOptions(), Settings.createSslConfiguration());
|
||||
VaultClient vaultClient = new VaultClient(clientHttpRequestFactory,
|
||||
new VaultEndpoint());
|
||||
RestTemplate restTemplate = VaultClients.createRestTemplate(
|
||||
TestRestTemplateFactory.TEST_VAULT_ENDPOINT, clientHttpRequestFactory);
|
||||
|
||||
new ClientCertificateAuthentication(vaultClient).login();
|
||||
new ClientCertificateAuthentication(restTemplate).login();
|
||||
}
|
||||
|
||||
private SslConfiguration prepareCertAuthenticationMethod() {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
* Copyright 2016-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -21,9 +21,8 @@ import org.junit.Test;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.web.client.MockRestServiceServer;
|
||||
import org.springframework.vault.client.VaultClient;
|
||||
import org.springframework.vault.client.VaultEndpoint;
|
||||
import org.springframework.vault.client.VaultException;
|
||||
import org.springframework.vault.VaultException;
|
||||
import org.springframework.vault.client.VaultClients.PrefixAwareUriTemplateHandler;
|
||||
import org.springframework.vault.support.VaultToken;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
@@ -35,29 +34,29 @@ import static org.springframework.test.web.client.response.MockRestResponseCreat
|
||||
|
||||
/**
|
||||
* Unit tests for {@link ClientCertificateAuthentication}.
|
||||
*
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class ClientCertificateAuthenticationUnitTests {
|
||||
|
||||
private VaultClient vaultClient;
|
||||
private RestTemplate restTemplate;
|
||||
private MockRestServiceServer mockRest;
|
||||
|
||||
@Before
|
||||
public void before() throws Exception {
|
||||
|
||||
RestTemplate restTemplate = new RestTemplate();
|
||||
mockRest = MockRestServiceServer.createServer(restTemplate);
|
||||
vaultClient = new VaultClient(restTemplate, new VaultEndpoint());
|
||||
restTemplate.setUriTemplateHandler(new PrefixAwareUriTemplateHandler());
|
||||
|
||||
this.mockRest = MockRestServiceServer.createServer(restTemplate);
|
||||
this.restTemplate = restTemplate;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void loginShouldObtainToken() throws Exception {
|
||||
|
||||
mockRest.expect(requestTo("https://localhost:8200/v1/auth/cert/login"))
|
||||
//
|
||||
mockRest.expect(requestTo("/auth/cert/login"))
|
||||
.andExpect(method(HttpMethod.POST))
|
||||
//
|
||||
.andRespond(
|
||||
withSuccess()
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
@@ -66,7 +65,7 @@ public class ClientCertificateAuthenticationUnitTests {
|
||||
+ "}"));
|
||||
|
||||
ClientCertificateAuthentication sut = new ClientCertificateAuthentication(
|
||||
vaultClient);
|
||||
restTemplate);
|
||||
|
||||
VaultToken login = sut.login();
|
||||
|
||||
@@ -79,9 +78,9 @@ public class ClientCertificateAuthenticationUnitTests {
|
||||
@Test(expected = VaultException.class)
|
||||
public void loginShouldFail() throws Exception {
|
||||
|
||||
mockRest.expect(requestTo("https://localhost:8200/v1/auth/cert/login")) //
|
||||
mockRest.expect(requestTo("/auth/cert/login")) //
|
||||
.andRespond(withServerError());
|
||||
|
||||
new ClientCertificateAuthentication(vaultClient).login();
|
||||
new ClientCertificateAuthentication(restTemplate).login();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
* Copyright 2016-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -22,17 +22,16 @@ import org.junit.Test;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.vault.client.VaultClient;
|
||||
import org.springframework.vault.client.VaultEndpoint;
|
||||
import org.springframework.vault.client.VaultException;
|
||||
import org.springframework.vault.client.VaultResponseEntity;
|
||||
import org.springframework.vault.core.VaultOperations.SessionCallback;
|
||||
import org.springframework.vault.core.VaultOperations.VaultSession;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.vault.VaultException;
|
||||
import org.springframework.vault.core.RestOperationsCallback;
|
||||
import org.springframework.vault.support.VaultResponse;
|
||||
import org.springframework.vault.support.VaultToken;
|
||||
import org.springframework.vault.util.IntegrationTestSupport;
|
||||
import org.springframework.vault.util.Settings;
|
||||
import org.springframework.vault.util.TestRestTemplateFactory;
|
||||
import org.springframework.web.client.RestOperations;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.fail;
|
||||
@@ -40,7 +39,7 @@ import static org.junit.Assume.assumeNotNull;
|
||||
|
||||
/**
|
||||
* Integration tests for {@link CubbyholeAuthentication}.
|
||||
*
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class CubbyholeAuthenticationIntegrationTests extends IntegrationTestSupport {
|
||||
@@ -48,20 +47,21 @@ public class CubbyholeAuthenticationIntegrationTests extends IntegrationTestSupp
|
||||
@Test
|
||||
public void shouldCreateWrappedToken() throws Exception {
|
||||
|
||||
VaultResponseEntity<VaultResponse> response = prepare().getVaultOperations()
|
||||
.doWithVault(new SessionCallback<VaultResponseEntity<VaultResponse>>() {
|
||||
@Override
|
||||
public VaultResponseEntity<VaultResponse> doWithVault(
|
||||
VaultSession session) {
|
||||
ResponseEntity<VaultResponse> response = prepare().getVaultOperations()
|
||||
.doWithSession(
|
||||
new RestOperationsCallback<ResponseEntity<VaultResponse>>() {
|
||||
@Override
|
||||
public ResponseEntity<VaultResponse> doWithRestOperations(
|
||||
RestOperations restOperations) {
|
||||
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.add("X-Vault-Wrap-TTL", "10m");
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.add("X-Vault-Wrap-TTL", "10m");
|
||||
|
||||
return session.exchange("auth/token/create", HttpMethod.POST,
|
||||
new HttpEntity<Object>(headers), VaultResponse.class,
|
||||
null);
|
||||
}
|
||||
});
|
||||
return restOperations.exchange("auth/token/create",
|
||||
HttpMethod.POST, new HttpEntity<Object>(headers),
|
||||
VaultResponse.class);
|
||||
}
|
||||
});
|
||||
|
||||
Map<String, String> wrapInfo = response.getBody().getWrapInfo();
|
||||
|
||||
@@ -72,12 +72,11 @@ public class CubbyholeAuthenticationIntegrationTests extends IntegrationTestSupp
|
||||
|
||||
CubbyholeAuthenticationOptions options = CubbyholeAuthenticationOptions.builder()
|
||||
.initialToken(VaultToken.of(initialToken)).wrapped().build();
|
||||
|
||||
VaultClient vaultClient = new VaultClient(TestRestTemplateFactory.create(Settings
|
||||
.createSslConfiguration()), new VaultEndpoint());
|
||||
RestTemplate restTemplate = TestRestTemplateFactory.create(Settings
|
||||
.createSslConfiguration());
|
||||
|
||||
CubbyholeAuthentication authentication = new CubbyholeAuthentication(options,
|
||||
vaultClient);
|
||||
restTemplate);
|
||||
VaultToken login = authentication.login();
|
||||
assertThat(login.getToken()).doesNotContain(Settings.token().getToken());
|
||||
}
|
||||
@@ -88,11 +87,11 @@ public class CubbyholeAuthenticationIntegrationTests extends IntegrationTestSupp
|
||||
CubbyholeAuthenticationOptions options = CubbyholeAuthenticationOptions.builder()
|
||||
.initialToken(VaultToken.of("Hello")).wrapped().build();
|
||||
|
||||
VaultClient vaultClient = new VaultClient(TestRestTemplateFactory.create(Settings
|
||||
.createSslConfiguration()), new VaultEndpoint());
|
||||
|
||||
RestTemplate restTemplate = TestRestTemplateFactory.create(Settings
|
||||
.createSslConfiguration());
|
||||
CubbyholeAuthentication authentication = new CubbyholeAuthentication(options,
|
||||
vaultClient);
|
||||
restTemplate);
|
||||
|
||||
try {
|
||||
authentication.login();
|
||||
fail("Missing VaultException");
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
* Copyright 2016-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -21,9 +21,9 @@ import org.junit.Test;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.test.web.client.MockRestServiceServer;
|
||||
import org.springframework.vault.client.VaultClient;
|
||||
import org.springframework.vault.client.VaultEndpoint;
|
||||
import org.springframework.vault.client.VaultException;
|
||||
import org.springframework.vault.VaultException;
|
||||
import org.springframework.vault.client.VaultHttpHeaders;
|
||||
import org.springframework.vault.client.VaultClients.PrefixAwareUriTemplateHandler;
|
||||
import org.springframework.vault.support.VaultToken;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
@@ -36,31 +36,30 @@ import static org.springframework.test.web.client.response.MockRestResponseCreat
|
||||
|
||||
/**
|
||||
* Unit tests for {@link CubbyholeAuthentication}.
|
||||
*
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class CubbyholeAuthenticationUnitTests {
|
||||
|
||||
private VaultClient vaultClient;
|
||||
private RestTemplate restTemplate;
|
||||
private MockRestServiceServer mockRest;
|
||||
|
||||
@Before
|
||||
public void before() throws Exception {
|
||||
|
||||
RestTemplate restTemplate = new RestTemplate();
|
||||
mockRest = MockRestServiceServer.createServer(restTemplate);
|
||||
vaultClient = new VaultClient(restTemplate, new VaultEndpoint());
|
||||
restTemplate.setUriTemplateHandler(new PrefixAwareUriTemplateHandler());
|
||||
|
||||
this.mockRest = MockRestServiceServer.createServer(restTemplate);
|
||||
this.restTemplate = restTemplate;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldLoginUsingWrappedLogin() throws Exception {
|
||||
|
||||
mockRest.expect(requestTo("https://localhost:8200/v1/cubbyhole/response"))
|
||||
//
|
||||
mockRest.expect(requestTo("/cubbyhole/response"))
|
||||
.andExpect(method(HttpMethod.GET))
|
||||
//
|
||||
.andExpect(header(VaultClient.VAULT_TOKEN, "hello"))
|
||||
//
|
||||
.andExpect(header(VaultHttpHeaders.VAULT_TOKEN, "hello"))
|
||||
.andRespond(
|
||||
withSuccess()
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
@@ -72,7 +71,7 @@ public class CubbyholeAuthenticationUnitTests {
|
||||
.initialToken(VaultToken.of("hello")).wrapped().build();
|
||||
|
||||
CubbyholeAuthentication authentication = new CubbyholeAuthentication(options,
|
||||
vaultClient);
|
||||
restTemplate);
|
||||
|
||||
VaultToken login = authentication.login();
|
||||
|
||||
@@ -83,10 +82,9 @@ public class CubbyholeAuthenticationUnitTests {
|
||||
@Test
|
||||
public void shouldLoginUsingStoredLogin() throws Exception {
|
||||
|
||||
mockRest.expect(requestTo("https://localhost:8200/v1/cubbyhole/token")) //
|
||||
.andExpect(method(HttpMethod.GET)) //
|
||||
.andExpect(header(VaultClient.VAULT_TOKEN, "hello"))
|
||||
//
|
||||
mockRest.expect(requestTo("/cubbyhole/token"))
|
||||
.andExpect(method(HttpMethod.GET))
|
||||
.andExpect(header(VaultHttpHeaders.VAULT_TOKEN, "hello"))
|
||||
.andRespond(
|
||||
withSuccess()
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
@@ -96,7 +94,7 @@ public class CubbyholeAuthenticationUnitTests {
|
||||
.initialToken(VaultToken.of("hello")).path("cubbyhole/token").build();
|
||||
|
||||
CubbyholeAuthentication authentication = new CubbyholeAuthentication(options,
|
||||
vaultClient);
|
||||
restTemplate);
|
||||
|
||||
VaultToken login = authentication.login();
|
||||
|
||||
@@ -107,12 +105,9 @@ public class CubbyholeAuthenticationUnitTests {
|
||||
@Test
|
||||
public void shouldFailUsingStoredLoginNoData() throws Exception {
|
||||
|
||||
mockRest.expect(requestTo("https://localhost:8200/v1/cubbyhole/token"))
|
||||
//
|
||||
mockRest.expect(requestTo("/cubbyhole/token"))
|
||||
.andExpect(method(HttpMethod.GET))
|
||||
//
|
||||
.andExpect(header(VaultClient.VAULT_TOKEN, "hello"))
|
||||
//
|
||||
.andExpect(header(VaultHttpHeaders.VAULT_TOKEN, "hello"))
|
||||
.andRespond(
|
||||
withSuccess().contentType(MediaType.APPLICATION_JSON).body(
|
||||
"{\"data\":{} }"));
|
||||
@@ -121,7 +116,7 @@ public class CubbyholeAuthenticationUnitTests {
|
||||
.initialToken(VaultToken.of("hello")).path("cubbyhole/token").build();
|
||||
|
||||
CubbyholeAuthentication authentication = new CubbyholeAuthentication(options,
|
||||
vaultClient);
|
||||
restTemplate);
|
||||
|
||||
try {
|
||||
authentication.login();
|
||||
@@ -135,12 +130,9 @@ public class CubbyholeAuthenticationUnitTests {
|
||||
@Test
|
||||
public void shouldFailUsingStoredMultipleEntries() throws Exception {
|
||||
|
||||
mockRest.expect(requestTo("https://localhost:8200/v1/cubbyhole/token"))
|
||||
//
|
||||
mockRest.expect(requestTo("/cubbyhole/token"))
|
||||
.andExpect(method(HttpMethod.GET))
|
||||
//
|
||||
.andExpect(header(VaultClient.VAULT_TOKEN, "hello"))
|
||||
//
|
||||
.andExpect(header(VaultHttpHeaders.VAULT_TOKEN, "hello"))
|
||||
.andRespond(
|
||||
withSuccess().contentType(MediaType.APPLICATION_JSON).body(
|
||||
"{\"data\":{\"key1\":1, \"key2\":2} }"));
|
||||
@@ -149,7 +141,7 @@ public class CubbyholeAuthenticationUnitTests {
|
||||
.initialToken(VaultToken.of("hello")).path("cubbyhole/token").build();
|
||||
|
||||
CubbyholeAuthentication authentication = new CubbyholeAuthentication(options,
|
||||
vaultClient);
|
||||
restTemplate);
|
||||
|
||||
try {
|
||||
authentication.login();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
* Copyright 2016-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -24,18 +24,20 @@ import org.junit.Test;
|
||||
import org.springframework.core.task.AsyncTaskExecutor;
|
||||
import org.springframework.core.task.SimpleAsyncTaskExecutor;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.vault.client.VaultResponseEntity;
|
||||
import org.springframework.vault.core.VaultOperations;
|
||||
import org.springframework.vault.core.RestOperationsCallback;
|
||||
import org.springframework.vault.core.VaultTokenOperations;
|
||||
import org.springframework.vault.support.VaultToken;
|
||||
import org.springframework.vault.support.VaultTokenRequest;
|
||||
import org.springframework.vault.util.IntegrationTestSupport;
|
||||
import org.springframework.web.client.HttpStatusCodeException;
|
||||
import org.springframework.web.client.RestOperations;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.fail;
|
||||
|
||||
/**
|
||||
* Integration tests for {@link LifecycleAwareSessionManager}.
|
||||
*
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class LifecycleAwareSessionManagerIntegrationTests extends IntegrationTestSupport {
|
||||
@@ -49,7 +51,7 @@ public class LifecycleAwareSessionManagerIntegrationTests extends IntegrationTes
|
||||
TokenAuthentication tokenAuthentication = new TokenAuthentication(loginToken);
|
||||
|
||||
LifecycleAwareSessionManager sessionManager = new LifecycleAwareSessionManager(
|
||||
tokenAuthentication, taskExecutor, prepare().getVaultClient());
|
||||
tokenAuthentication, taskExecutor, prepare().getRestTemplate());
|
||||
|
||||
assertThat(sessionManager.getSessionToken()).isSameAs(loginToken);
|
||||
}
|
||||
@@ -73,7 +75,7 @@ public class LifecycleAwareSessionManagerIntegrationTests extends IntegrationTes
|
||||
|
||||
final AtomicInteger counter = new AtomicInteger();
|
||||
LifecycleAwareSessionManager sessionManager = new LifecycleAwareSessionManager(
|
||||
tokenAuthentication, taskExecutor, prepare().getVaultClient()) {
|
||||
tokenAuthentication, taskExecutor, prepare().getRestTemplate()) {
|
||||
@Override
|
||||
public VaultToken getSessionToken() {
|
||||
|
||||
@@ -95,24 +97,28 @@ public class LifecycleAwareSessionManagerIntegrationTests extends IntegrationTes
|
||||
TokenAuthentication tokenAuthentication = new TokenAuthentication(loginToken);
|
||||
|
||||
LifecycleAwareSessionManager sessionManager = new LifecycleAwareSessionManager(
|
||||
tokenAuthentication, taskExecutor, prepare().getVaultClient());
|
||||
tokenAuthentication, taskExecutor, prepare().getRestTemplate());
|
||||
|
||||
sessionManager.getSessionToken();
|
||||
sessionManager.destroy();
|
||||
|
||||
prepare().getVaultOperations().doWithVault(
|
||||
new VaultOperations.SessionCallback<Object>() {
|
||||
|
||||
prepare().getVaultOperations().doWithSession(
|
||||
new RestOperationsCallback<Object>() {
|
||||
@Override
|
||||
public Object doWithVault(VaultOperations.VaultSession session) {
|
||||
public Object doWithRestOperations(RestOperations restOperations) {
|
||||
|
||||
VaultResponseEntity<Map> entity = session.getForEntity(
|
||||
String.format("auth/token/lookup/%s",
|
||||
loginToken.getToken()), Map.class);
|
||||
try {
|
||||
restOperations.getForEntity(
|
||||
"auth/token/lookup/{token}", Map.class,
|
||||
loginToken.getToken());
|
||||
fail("Missing HttpStatusCodeException");
|
||||
}
|
||||
catch (HttpStatusCodeException e) {
|
||||
// Compatibility across Vault versions.
|
||||
assertThat(e.getStatusCode()).isIn(HttpStatus.BAD_REQUEST,
|
||||
HttpStatus.NOT_FOUND, HttpStatus.FORBIDDEN);
|
||||
}
|
||||
|
||||
// Compatibility across Vault versions.
|
||||
assertThat(entity.getStatusCode()).isIn(HttpStatus.BAD_REQUEST,
|
||||
HttpStatus.NOT_FOUND, HttpStatus.FORBIDDEN);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
* Copyright 2016-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -15,8 +15,6 @@
|
||||
*/
|
||||
package org.springframework.vault.authentication;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@@ -26,12 +24,14 @@ import org.mockito.Mock;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
|
||||
import org.springframework.core.task.AsyncTaskExecutor;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.scheduling.Trigger;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
|
||||
import org.springframework.vault.client.VaultClient;
|
||||
import org.springframework.vault.client.VaultResponseEntity;
|
||||
import org.springframework.vault.client.VaultHttpHeaders;
|
||||
import org.springframework.vault.support.VaultToken;
|
||||
import org.springframework.web.client.HttpServerErrorException;
|
||||
import org.springframework.web.client.RestOperations;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
@@ -44,7 +44,7 @@ import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link LifecycleAwareSessionManager}.
|
||||
*
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
@@ -60,14 +60,14 @@ public class LifecycleAwareSessionManagerUnitTests {
|
||||
private ThreadPoolTaskScheduler taskScheduler;
|
||||
|
||||
@Mock
|
||||
private VaultClient vaultClient;
|
||||
private RestOperations restOperations;
|
||||
|
||||
private LifecycleAwareSessionManager sessionManager;
|
||||
|
||||
@Before
|
||||
public void before() throws Exception {
|
||||
sessionManager = new LifecycleAwareSessionManager(clientAuthentication,
|
||||
taskExecutor, vaultClient);
|
||||
taskExecutor, restOperations);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -83,17 +83,14 @@ public class LifecycleAwareSessionManagerUnitTests {
|
||||
|
||||
when(clientAuthentication.login()).thenReturn(LoginToken.of("login"));
|
||||
|
||||
when(
|
||||
vaultClient.postForEntity(eq("auth/token/revoke-self"),
|
||||
eq(LoginToken.of("login")), ArgumentMatchers.any(),
|
||||
any(Class.class))).thenReturn(
|
||||
new ResponseEntity<Object>(null, HttpStatus.OK, null, null));
|
||||
|
||||
sessionManager.renewToken();
|
||||
sessionManager.destroy();
|
||||
|
||||
verify(vaultClient).postForEntity(eq("auth/token/revoke-self"),
|
||||
eq(LoginToken.of("login")), ArgumentMatchers.any(), any(Class.class));
|
||||
verify(restOperations)
|
||||
.postForObject(
|
||||
eq("/auth/token/revoke-self"),
|
||||
eq(new HttpEntity<Object>(VaultHttpHeaders.from(LoginToken
|
||||
.of("login")))), any(Class.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -104,7 +101,7 @@ public class LifecycleAwareSessionManagerUnitTests {
|
||||
sessionManager.renewToken();
|
||||
sessionManager.destroy();
|
||||
|
||||
verifyZeroInteractions(vaultClient);
|
||||
verifyZeroInteractions(restOperations);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -113,17 +110,18 @@ public class LifecycleAwareSessionManagerUnitTests {
|
||||
when(clientAuthentication.login()).thenReturn(LoginToken.of("login"));
|
||||
|
||||
when(
|
||||
vaultClient.postForEntity(eq("auth/token/revoke-self"),
|
||||
eq(LoginToken.of("login")), ArgumentMatchers.any(),
|
||||
any(Class.class))).thenReturn(
|
||||
new ResponseEntity<Object>(null, HttpStatus.INTERNAL_SERVER_ERROR, null,
|
||||
null));
|
||||
restOperations.postForObject(anyString(), any(),
|
||||
ArgumentMatchers.<Class> any())).thenThrow(
|
||||
new HttpServerErrorException(HttpStatus.INTERNAL_SERVER_ERROR));
|
||||
|
||||
sessionManager.renewToken();
|
||||
sessionManager.destroy();
|
||||
|
||||
verify(vaultClient).postForEntity(eq("auth/token/revoke-self"),
|
||||
eq(LoginToken.of("login")), ArgumentMatchers.any(), any(Class.class));
|
||||
verify(restOperations)
|
||||
.postForObject(
|
||||
eq("/auth/token/revoke-self"),
|
||||
eq(new HttpEntity<Object>(VaultHttpHeaders.from(LoginToken
|
||||
.of("login")))), any(Class.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -140,11 +138,6 @@ public class LifecycleAwareSessionManagerUnitTests {
|
||||
public void shouldRunTokenRenewal() {
|
||||
|
||||
when(clientAuthentication.login()).thenReturn(LoginToken.renewable("login", 5));
|
||||
when(
|
||||
vaultClient.postForEntity(eq("auth/token/renew-self"),
|
||||
eq(LoginToken.renewable("login", 5)), ArgumentMatchers.any(),
|
||||
any(Class.class))).thenReturn(
|
||||
new ResponseEntity<Object>(null, HttpStatus.OK, null, null));
|
||||
|
||||
ArgumentCaptor<Runnable> runnableCaptor = ArgumentCaptor.forClass(Runnable.class);
|
||||
|
||||
@@ -152,9 +145,11 @@ public class LifecycleAwareSessionManagerUnitTests {
|
||||
verify(taskExecutor).execute(runnableCaptor.capture());
|
||||
|
||||
runnableCaptor.getValue().run();
|
||||
verify(vaultClient).postForEntity(eq("auth/token/renew-self"),
|
||||
eq(LoginToken.renewable("login", 5)), ArgumentMatchers.any(),
|
||||
any(Class.class));
|
||||
|
||||
verify(restOperations).postForObject(
|
||||
eq("/auth/token/renew-self"),
|
||||
eq(new HttpEntity<Object>(VaultHttpHeaders.from(LoginToken.renewable(
|
||||
"login", 5)))), any(Class.class));
|
||||
verify(clientAuthentication, times(1)).login();
|
||||
}
|
||||
|
||||
@@ -162,11 +157,6 @@ public class LifecycleAwareSessionManagerUnitTests {
|
||||
public void shouldReScheduleTokenRenewalAfterSucessfulRenewal() {
|
||||
|
||||
when(clientAuthentication.login()).thenReturn(LoginToken.renewable("login", 5));
|
||||
when(
|
||||
vaultClient.postForEntity(eq("auth/token/renew-self"),
|
||||
eq(LoginToken.renewable("login", 5)), ArgumentMatchers.any(),
|
||||
any(Class.class))).thenReturn(
|
||||
new ResponseEntity<Object>(null, HttpStatus.OK, null, null));
|
||||
|
||||
ArgumentCaptor<Runnable> runnableCaptor = ArgumentCaptor.forClass(Runnable.class);
|
||||
|
||||
@@ -182,7 +172,7 @@ public class LifecycleAwareSessionManagerUnitTests {
|
||||
public void shouldUseTaskScheduler() {
|
||||
|
||||
sessionManager = new LifecycleAwareSessionManager(clientAuthentication,
|
||||
taskScheduler, vaultClient);
|
||||
taskScheduler, restOperations);
|
||||
|
||||
when(clientAuthentication.login()).thenReturn(LoginToken.renewable("login", 5));
|
||||
|
||||
@@ -200,11 +190,9 @@ public class LifecycleAwareSessionManagerUnitTests {
|
||||
|
||||
when(clientAuthentication.login()).thenReturn(LoginToken.renewable("login", 5));
|
||||
when(
|
||||
vaultClient.postForEntity(eq("auth/token/renew-self"),
|
||||
eq(LoginToken.renewable("login", 5)), ArgumentMatchers.any(),
|
||||
any(Class.class))).thenReturn(
|
||||
new ResponseEntity<Object>(null, HttpStatus.INTERNAL_SERVER_ERROR, null,
|
||||
null));
|
||||
restOperations.postForObject(anyString(), any(),
|
||||
ArgumentMatchers.<Class> any())).thenThrow(
|
||||
new HttpServerErrorException(HttpStatus.INTERNAL_SERVER_ERROR));
|
||||
|
||||
ArgumentCaptor<Runnable> runnableCaptor = ArgumentCaptor.forClass(Runnable.class);
|
||||
|
||||
@@ -233,20 +221,13 @@ public class LifecycleAwareSessionManagerUnitTests {
|
||||
|
||||
when(clientAuthentication.login()).thenReturn(LoginToken.renewable("login", 5));
|
||||
when(
|
||||
vaultClient.postForEntity(anyString(), any(VaultToken.class),
|
||||
ArgumentMatchers.any(), any(Class.class))).thenReturn(
|
||||
new ResponseEntity<Object>(null, HttpStatus.BAD_REQUEST, null, null));
|
||||
restOperations.postForObject(anyString(),
|
||||
ArgumentMatchers.<Object> any(), ArgumentMatchers.<Class> any()))
|
||||
.thenThrow(new HttpServerErrorException(HttpStatus.BAD_REQUEST));
|
||||
|
||||
sessionManager.getSessionToken();
|
||||
|
||||
assertThat(sessionManager.renewToken()).isFalse();
|
||||
verify(clientAuthentication, times(1)).login();
|
||||
}
|
||||
|
||||
static class ResponseEntity<T> extends VaultResponseEntity<T> {
|
||||
|
||||
protected ResponseEntity(T body, HttpStatus statusCode, URI uri, String message) {
|
||||
super(body, statusCode, uri, message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
* Copyright 2016-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -28,7 +28,7 @@ import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.vault.client.VaultException;
|
||||
import org.springframework.vault.VaultException;
|
||||
import org.springframework.vault.support.CertificateBundle;
|
||||
import org.springframework.vault.support.VaultCertificateRequest;
|
||||
import org.springframework.vault.support.VaultCertificateResponse;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
* Copyright 2016-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -23,21 +23,25 @@ import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.vault.client.VaultClient;
|
||||
import org.springframework.vault.client.VaultException;
|
||||
import org.springframework.vault.client.VaultResponseEntity;
|
||||
import org.springframework.vault.VaultException;
|
||||
import org.springframework.vault.client.VaultHttpHeaders;
|
||||
import org.springframework.vault.support.VaultTokenRequest;
|
||||
import org.springframework.vault.support.VaultTokenResponse;
|
||||
import org.springframework.vault.util.IntegrationTestSupport;
|
||||
import org.springframework.web.client.RestOperations;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Integration tests for {@link VaultTokenTemplate} through {@link VaultTokenOperations}.
|
||||
*
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@@ -137,12 +141,12 @@ public class VaultTokenTemplateIntegrationTests extends IntegrationTestSupport {
|
||||
final VaultTokenResponse tokenResponse = tokenOperations.create();
|
||||
tokenOperations.revoke(tokenResponse.getToken());
|
||||
|
||||
VaultResponseEntity<String> response = lookupSelf(tokenResponse);
|
||||
|
||||
assertThat(response.getStatusCode()).isIn(
|
||||
/* <= Vault 0.6.0 */HttpStatus.BAD_REQUEST,
|
||||
/* >= Vault 0.6.1 */HttpStatus.FORBIDDEN);
|
||||
assertThat(response.getMessage()).isEqualTo("permission denied");
|
||||
try {
|
||||
lookupSelf(tokenResponse);
|
||||
}
|
||||
catch (VaultException e) {
|
||||
assertThat(e).hasMessageContaining("permission denied");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -150,20 +154,28 @@ public class VaultTokenTemplateIntegrationTests extends IntegrationTestSupport {
|
||||
|
||||
final VaultTokenResponse tokenResponse = tokenOperations.create();
|
||||
|
||||
VaultResponseEntity<String> response = lookupSelf(tokenResponse);
|
||||
ResponseEntity<String> response = lookupSelf(tokenResponse);
|
||||
|
||||
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
}
|
||||
|
||||
private VaultResponseEntity<String> lookupSelf(final VaultTokenResponse tokenResponse) {
|
||||
private ResponseEntity<String> lookupSelf(final VaultTokenResponse tokenResponse) {
|
||||
|
||||
return vaultOperations
|
||||
.doWithVault(new VaultOperations.ClientCallback<VaultResponseEntity<String>>() {
|
||||
.doWithVault(new RestOperationsCallback<ResponseEntity<String>>() {
|
||||
@Override
|
||||
public VaultResponseEntity<String> doWithVault(VaultClient client) {
|
||||
return client.getForEntity("auth/token/lookup-self",
|
||||
tokenResponse.getToken(), String.class);
|
||||
public ResponseEntity<String> doWithRestOperations(
|
||||
RestOperations restOperations) {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.add(VaultHttpHeaders.VAULT_TOKEN, tokenResponse
|
||||
.getToken()
|
||||
.getToken());
|
||||
|
||||
return restOperations.exchange("auth/token/lookup-self",
|
||||
HttpMethod.GET, new HttpEntity<Object>(headers),
|
||||
String.class);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
* Copyright 2016-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -22,7 +22,7 @@ import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.vault.client.VaultException;
|
||||
import org.springframework.vault.VaultException;
|
||||
import org.springframework.vault.support.VaultMount;
|
||||
import org.springframework.vault.support.VaultTransitContext;
|
||||
import org.springframework.vault.support.VaultTransitKey;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
* Copyright 2016-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,7 +16,7 @@
|
||||
package org.springframework.vault.demo;
|
||||
|
||||
import org.springframework.vault.authentication.TokenAuthentication;
|
||||
import org.springframework.vault.client.VaultClient;
|
||||
import org.springframework.vault.client.VaultEndpoint;
|
||||
import org.springframework.vault.core.VaultTemplate;
|
||||
import org.springframework.vault.support.VaultResponseSupport;
|
||||
|
||||
@@ -27,7 +27,7 @@ public class VaultApp {
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
VaultTemplate vaultTemplate = new VaultTemplate(new VaultClient(),
|
||||
VaultTemplate vaultTemplate = new VaultTemplate(new VaultEndpoint(),
|
||||
new TokenAuthentication("00000000-0000-0000-0000-000000000000"));
|
||||
|
||||
Secrets secrets = new Secrets();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
* Copyright 2016-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -15,11 +15,8 @@
|
||||
*/
|
||||
package org.springframework.vault.util;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.vault.client.VaultClient;
|
||||
import org.springframework.vault.core.VaultOperations;
|
||||
import org.springframework.vault.core.VaultSysOperations;
|
||||
import org.springframework.vault.support.VaultInitializationRequest;
|
||||
@@ -27,27 +24,28 @@ import org.springframework.vault.support.VaultInitializationResponse;
|
||||
import org.springframework.vault.support.VaultMount;
|
||||
import org.springframework.vault.support.VaultToken;
|
||||
import org.springframework.vault.support.VaultTokenRequest;
|
||||
import org.springframework.vault.support.VaultTokenRequest.VaultTokenRequestBuilder;
|
||||
import org.springframework.vault.support.VaultTokenResponse;
|
||||
import org.springframework.vault.support.VaultUnsealStatus;
|
||||
import org.springframework.vault.support.VaultTokenRequest.VaultTokenRequestBuilder;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
/**
|
||||
* Vault preparation utility class. This class allows preparing Vault for integration
|
||||
* tests.
|
||||
*
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class PrepareVault {
|
||||
|
||||
private final VaultClient vaultClient;
|
||||
private final RestTemplate restTemplate;
|
||||
|
||||
private final VaultOperations vaultOperations;
|
||||
|
||||
private final VaultSysOperations adminOperations;
|
||||
|
||||
public PrepareVault(VaultClient vaultClient, VaultOperations vaultOperations) {
|
||||
public PrepareVault(RestTemplate restTemplate, VaultOperations vaultOperations) {
|
||||
|
||||
this.vaultClient = vaultClient;
|
||||
this.restTemplate = restTemplate;
|
||||
this.vaultOperations = vaultOperations;
|
||||
this.adminOperations = vaultOperations.opsForSys();
|
||||
}
|
||||
@@ -89,7 +87,7 @@ public class PrepareVault {
|
||||
|
||||
VaultTokenRequestBuilder builder = VaultTokenRequest.builder().id(tokenId);
|
||||
|
||||
if(StringUtils.hasText(policy)){
|
||||
if (StringUtils.hasText(policy)) {
|
||||
builder.withPolicy(policy);
|
||||
}
|
||||
|
||||
@@ -160,7 +158,7 @@ public class PrepareVault {
|
||||
return vaultOperations;
|
||||
}
|
||||
|
||||
public VaultClient getVaultClient() {
|
||||
return vaultClient;
|
||||
public RestTemplate getRestTemplate() {
|
||||
return restTemplate;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
* Copyright 2016-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -15,17 +15,14 @@
|
||||
*/
|
||||
package org.springframework.vault.util;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.http.HttpRequest;
|
||||
import org.springframework.http.client.ClientHttpRequestExecution;
|
||||
import org.springframework.http.client.ClientHttpRequestFactory;
|
||||
import org.springframework.http.client.ClientHttpRequestInterceptor;
|
||||
import org.springframework.http.client.ClientHttpResponse;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.vault.client.VaultClients;
|
||||
import org.springframework.vault.client.VaultEndpoint;
|
||||
import org.springframework.vault.config.ClientHttpRequestFactoryFactory;
|
||||
import org.springframework.vault.support.ClientOptions;
|
||||
import org.springframework.vault.support.SslConfiguration;
|
||||
@@ -36,11 +33,13 @@ import org.springframework.web.client.RestTemplate;
|
||||
* {@link ClientHttpRequestFactory} once it was initialized. Changes to timeouts or the
|
||||
* SSL configuration won't be applied once a {@link ClientHttpRequestFactory} was created
|
||||
* for the first time.
|
||||
*
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class TestRestTemplateFactory {
|
||||
|
||||
public static final VaultEndpoint TEST_VAULT_ENDPOINT = new VaultEndpoint();
|
||||
|
||||
private static final AtomicReference<ClientHttpRequestFactory> factoryCache = new AtomicReference<ClientHttpRequestFactory>();
|
||||
|
||||
/**
|
||||
@@ -79,17 +78,7 @@ public class TestRestTemplateFactory {
|
||||
|
||||
Assert.notNull(requestFactory, "ClientHttpRequestFactory must not be null!");
|
||||
|
||||
RestTemplate template = new RestTemplate();
|
||||
template.setRequestFactory(requestFactory);
|
||||
template.getInterceptors().add(new ClientHttpRequestInterceptor() {
|
||||
@Override
|
||||
public ClientHttpResponse intercept(HttpRequest request, byte[] body,
|
||||
ClientHttpRequestExecution execution) throws IOException {
|
||||
return execution.execute(request, body);
|
||||
}
|
||||
});
|
||||
|
||||
return template;
|
||||
return VaultClients.createRestTemplate(TEST_VAULT_ENDPOINT, requestFactory);
|
||||
}
|
||||
|
||||
private static void initializeClientHttpRequestFactory(
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
* Copyright 2016-2017 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -24,16 +24,15 @@ import org.junit.rules.ExternalResource;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.vault.authentication.SessionManager;
|
||||
import org.springframework.vault.client.VaultClient;
|
||||
import org.springframework.vault.client.VaultEndpoint;
|
||||
import org.springframework.vault.core.DefaultVaultClientFactory;
|
||||
import org.springframework.vault.core.VaultTemplate;
|
||||
import org.springframework.vault.support.SslConfiguration;
|
||||
import org.springframework.vault.support.VaultToken;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
/**
|
||||
* Vault rule to ensure a running and prepared Vault.
|
||||
*
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
public class VaultRule extends ExternalResource {
|
||||
@@ -46,7 +45,7 @@ public class VaultRule extends ExternalResource {
|
||||
|
||||
/**
|
||||
* Create a new {@link VaultRule} with default SSL configuration and endpoint.
|
||||
*
|
||||
*
|
||||
* @see Settings#createSslConfiguration()
|
||||
* @see VaultEndpoint
|
||||
*/
|
||||
@@ -66,16 +65,15 @@ public class VaultRule extends ExternalResource {
|
||||
Assert.notNull(sslConfiguration, "SslConfiguration must not be null");
|
||||
Assert.notNull(vaultEndpoint, "VaultEndpoint must not be null");
|
||||
|
||||
VaultClient vaultClient = new VaultClient(
|
||||
TestRestTemplateFactory.create(sslConfiguration), vaultEndpoint);
|
||||
DefaultVaultClientFactory clientFactory = new DefaultVaultClientFactory(
|
||||
vaultClient);
|
||||
RestTemplate restTemplate = TestRestTemplateFactory.create(sslConfiguration);
|
||||
|
||||
VaultTemplate vaultTemplate = new VaultTemplate(clientFactory,
|
||||
new PreparingSessionManager());
|
||||
VaultTemplate vaultTemplate = new VaultTemplate(
|
||||
TestRestTemplateFactory.TEST_VAULT_ENDPOINT,
|
||||
restTemplate.getRequestFactory(), new PreparingSessionManager());
|
||||
|
||||
this.token = Settings.token();
|
||||
this.prepareVault = new PrepareVault(vaultClient, vaultTemplate);
|
||||
this.prepareVault = new PrepareVault(
|
||||
TestRestTemplateFactory.create(sslConfiguration), vaultTemplate);
|
||||
this.vaultEndpoint = vaultEndpoint;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ Mark Paluch;
|
||||
:toc: macro
|
||||
:toc-placement!:
|
||||
|
||||
(C) 2016 The original authors.
|
||||
(C) 2016-2017 The original authors.
|
||||
|
||||
NOTE: _Copies of this document may be made for your own use and for distribution to others, provided that you do not charge any fee for such copies and further provided that each copy contains this Copyright Notice, whether distributed in print or electronically._
|
||||
|
||||
|
||||
@@ -7,21 +7,21 @@ methods. Spring Vault supports multiple authentications mechanisms.
|
||||
|
||||
== Externalizing login credentials
|
||||
|
||||
Obtaining first-time access to a secured system is known as secure introduction.
|
||||
Obtaining first-time access to a secured system is known as secure introduction.
|
||||
Any client requires ephemeral or permanent credentials to access Vault. Externalizing credentials
|
||||
is a good pattern to keep code maintainability high but comes at a risk of increased disclosure.
|
||||
|
||||
Disclosure of login credentials to any party allows login to Vault and access secrets that
|
||||
are permitted by the underlying role. Picking the appropriate client authentication and
|
||||
injecting credentials into the application is subject to risk evaluation.
|
||||
|
||||
Spring's http://docs.spring.io/spring-framework/docs/current/spring-framework-reference/html/beans.html#beans-property-source-abstraction[PropertySource abstraction] is a natural fit
|
||||
|
||||
Spring's http://docs.spring.io/spring-framework/docs/current/spring-framework-reference/html/beans.html#beans-property-source-abstraction[PropertySource abstraction] is a natural fit
|
||||
to keep configuration outside the application code. You can use system properties, environment
|
||||
variables or property files to store login credentials. Each approach comes with its own properties.
|
||||
Keep in mind that the command line and environment properties can be introspected with appropriate
|
||||
OS access levels.
|
||||
|
||||
.Externalizing `vault.token` to a properties file
|
||||
|
||||
.Externalizing `vault.token` to a properties file
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
@@ -39,7 +39,7 @@ public class Config extends AbstractVaultConfiguration {
|
||||
|
||||
NOTE: Spring allows multiple ways to obtain `Environment`. When using `VaultPropertySource`, injection via `@Autowired Environment environment` will not provide the `Environment` as the environment bean is still in construction and autowiring comes at a later stage. Your configuration class should rather implement `ApplicationContextAware` and obtain the `Environment` from `ApplicationContext`.
|
||||
|
||||
See https://github.com/spring-projects/spring-vault/blob/master/spring-vault-core/src/test/java/org/springframework/vault/demo/SecurePropertyUsage.java[`SecurePropertyUsage.java`]
|
||||
See https://github.com/spring-projects/spring-vault/blob/master/spring-vault-core/src/test/java/org/springframework/vault/demo/SecurePropertyUsage.java[`SecurePropertyUsage.java`]
|
||||
for a sample on referencing properties in components and other property sources.
|
||||
|
||||
[[vault.authentication.token]]
|
||||
@@ -104,7 +104,7 @@ class AppConfig extends AbstractVaultConfiguration {
|
||||
.userIdMechanism(new IpAddressUserId())
|
||||
.build();
|
||||
|
||||
return new AppIdAuthentication(options, vaultClient());
|
||||
return new AppIdAuthentication(options, restOperations());
|
||||
}
|
||||
|
||||
// …
|
||||
@@ -143,7 +143,7 @@ class AppConfig extends AbstractVaultConfiguration {
|
||||
.userIdMechanism(new MacAddressUserId())
|
||||
.build();
|
||||
|
||||
return new AppIdAuthentication(options, vaultClient());
|
||||
return new AppIdAuthentication(options, restOperations());
|
||||
}
|
||||
|
||||
// …
|
||||
@@ -217,7 +217,7 @@ class AppConfig extends AbstractVaultConfiguration {
|
||||
.secretId("…")
|
||||
.build();
|
||||
|
||||
return new AppRoleAuthentication(options, vaultClient());
|
||||
return new AppRoleAuthentication(options, restOperations());
|
||||
}
|
||||
|
||||
// …
|
||||
@@ -250,7 +250,7 @@ class AppConfig extends AbstractVaultConfiguration {
|
||||
|
||||
@Override
|
||||
public ClientAuthentication clientAuthentication() {
|
||||
return new AwsEc2Authentication(vaultClient());
|
||||
return new AwsEc2Authentication(restOperations());
|
||||
}
|
||||
|
||||
// …
|
||||
@@ -299,7 +299,7 @@ class AppConfig extends AbstractVaultConfiguration {
|
||||
|
||||
@Override
|
||||
public ClientAuthentication clientAuthentication() {
|
||||
return new ClientCertificateAuthentication(options, vaultClient());
|
||||
return new ClientCertificateAuthentication(options, restOperations());
|
||||
}
|
||||
|
||||
// …
|
||||
@@ -355,7 +355,7 @@ class AppConfig extends AbstractVaultConfiguration {
|
||||
.wrapped()
|
||||
.build();
|
||||
|
||||
return new CubbyholeAuthentication(options, vaultClient());
|
||||
return new CubbyholeAuthentication(options, restOperations());
|
||||
}
|
||||
|
||||
// …
|
||||
@@ -410,7 +410,7 @@ class AppConfig extends AbstractVaultConfiguration {
|
||||
.path("cubbyhole/token")
|
||||
.build();
|
||||
|
||||
return new CubbyholeAuthentication(options, vaultClient());
|
||||
return new CubbyholeAuthentication(options, restOperations());
|
||||
}
|
||||
|
||||
// …
|
||||
|
||||
@@ -101,7 +101,7 @@ And a main application to run
|
||||
package org.springframework.vault.example;
|
||||
|
||||
import org.springframework.vault.authentication.TokenAuthentication;
|
||||
import org.springframework.vault.client.VaultClient;
|
||||
import org.springframework.vault.client.VaultEndpoint;
|
||||
import org.springframework.vault.core.VaultTemplate;
|
||||
import org.springframework.vault.support.VaultResponseSupport;
|
||||
|
||||
@@ -109,7 +109,7 @@ public class VaultApp {
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
VaultTemplate vaultTemplate = new VaultTemplate(new VaultClient(),
|
||||
VaultTemplate vaultTemplate = new VaultTemplate(new VaultEndpoint(),
|
||||
new TokenAuthentication("00000000-0000-0000-0000-000000000000"));
|
||||
|
||||
Secrets secrets = new Secrets();
|
||||
@@ -130,7 +130,7 @@ public class VaultApp {
|
||||
Even in this simple example, there are few things to take notice of
|
||||
|
||||
* You can instantiate the central class of Spring Vault,
|
||||
<<vault-template,`VaultTemplate`>>, using the `org.springframework.vault.client.VaultClient`
|
||||
<<vault-template,`VaultTemplate`>>, using the `org.springframework.vault.client.VaultEndpoint`
|
||||
object and the `ClientAuthentication`.
|
||||
You are not required to spin up a Spring Context to use Spring Vault.
|
||||
* Vault is expected to be configured with a root token of
|
||||
@@ -173,7 +173,7 @@ While there are many convenience methods on `VaultTemplate` to help you easily
|
||||
perform common tasks if you should need to access the Vault API directly to access
|
||||
functionality not explicitly exposed by the `VaultTemplate` you can use one of
|
||||
several execute callback methods to access underlying APIs. The execute callbacks
|
||||
will give you a reference to either a `RestTemplate` or a `VaultClient` object.
|
||||
will give you a reference to a `RestOperations` object.
|
||||
Please see the section <<vault.core.executioncallback,Execution Callbacks>> for more information.
|
||||
|
||||
Now let's look at a examples of how to work with Vault in the context of the Spring container.
|
||||
@@ -181,12 +181,11 @@ Now let's look at a examples of how to work with Vault in the context of the Spr
|
||||
[[vault.core.template.beans]]
|
||||
=== Registering and configuring Spring Vault beans
|
||||
|
||||
Using Spring Vault does not require a Spring Context. However, instances of `VaultTemplate`,
|
||||
`VaultClient` and `SessionManagers` registered inside a managed context will participate
|
||||
Using Spring Vault does not require a Spring Context. However, instances of `VaultTemplate` and `SessionManager` registered inside a managed context will participate
|
||||
in http://docs.spring.io/spring/docs/current/spring-framework-reference/html/beans.html#beans-factory-nature[lifecycle events]
|
||||
provided by the Spring IoC container. This is useful to dispose active Vault sessions upon
|
||||
application shutdown. You also benefit from reusing the same `VaultTemplate` and `VaultClient`
|
||||
instances across your application.
|
||||
application shutdown. You also benefit from reusing the same `VaultTemplate`
|
||||
instance across your application.
|
||||
|
||||
Spring Vault comes with a supporting configuration class that provides bean definitions
|
||||
for use inside a Spring context. Application configuration
|
||||
@@ -243,16 +242,16 @@ public class AppConfig extends AbstractVaultConfiguration {
|
||||
*/
|
||||
@Override
|
||||
public VaultEndpoint vaultEndpoint() {
|
||||
return VaultEndpoint.from(vaultUri); <1>
|
||||
return VaultEndpoint.from(vaultUri); <1>
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure a Client Certificate authentication.
|
||||
* {@link VaultClient} can be obtained from {@link #vaultClient()}.
|
||||
* {@link RestOperations} can be obtained from {@link #restOperations()}.
|
||||
*/
|
||||
@Override
|
||||
public ClientAuthentication clientAuthentication() {
|
||||
return new ClientCertificateAuthentication(vaultClient()); <2>
|
||||
return new ClientCertificateAuthentication(restOperations()); <2>
|
||||
}
|
||||
}
|
||||
----
|
||||
@@ -416,36 +415,30 @@ to perform uncommon operations that we've not exposed as methods on `VaultTempla
|
||||
|
||||
Here is a list of execute callback methods.
|
||||
|
||||
* `<T> T` *doWithVault* `(ClientCallback<T> clientCallback)` Executes the given
|
||||
`ClientCallback`, allows to interact with Vault using `VaultClient` without requiring a session.
|
||||
|
||||
* `<T> T` *doWithVault* `(SessionCallback<T> sessionCallback)` Executes the given
|
||||
`SessionCallback`, allows to interact with Vault in an authenticated session.
|
||||
|
||||
* `<T> T` *doWithRestTemplate* `(String pathTemplate, Map<String, ?> variables, RestTemplateCallback<T> callback)`
|
||||
Expands the `pathTemplate` to an `java.net.URI` and allows low-level interaction
|
||||
with the underlying `org.springframework.web.client.RestTemplate`.
|
||||
* `<T> T` *doWithVault* `(RestOperationsCallback<T> callback)` Executes the given
|
||||
`RestOperationsCallback`, allows to interact with Vault using `RestOperations` without requiring a session.
|
||||
|
||||
* `<T> T` *doWithSession* `(RestOperationsCallback<T> callback)` Executes the given
|
||||
`RestOperationsCallback`, allows to interact with Vault in an authenticated session.
|
||||
|
||||
Here is an example that uses the `ClientCallback` to initialize Vault:
|
||||
|
||||
====
|
||||
[source,java]
|
||||
----
|
||||
return vaultTemplate.doWithVault(new ClientCallback<VaultInitializationResponse>() {
|
||||
vaultOperations.doWithVault(new RestOperationsCallback<VaultInitializationResponse>() {
|
||||
|
||||
@Override
|
||||
public VaultInitializationResponse doWithVault(VaultClient client) {
|
||||
@Override
|
||||
public VaultInitializationResponse doWithRestOperations(RestOperations restOperations) {
|
||||
|
||||
VaultResponseEntity<VaultInitializationResponse> response = client.putForEntity("sys/init",
|
||||
vaultInitializationRequest, VaultInitializationResponse.class);
|
||||
ResponseEntity<VaultInitializationResponse> exchange = restOperations
|
||||
.exchange("/sys/init", HttpMethod.PUT,
|
||||
new HttpEntity<Object>(request),
|
||||
VaultInitializationResponse.class);
|
||||
|
||||
if (response.isSuccessful() && response.hasBody()) {
|
||||
return response.getBody();
|
||||
}
|
||||
return exchange.getBody();
|
||||
}
|
||||
});
|
||||
|
||||
return null.
|
||||
}
|
||||
});
|
||||
----
|
||||
====
|
||||
|
||||
Reference in New Issue
Block a user