1
pom.xml
1
pom.xml
@@ -383,7 +383,6 @@
|
||||
<configuration>
|
||||
<release>${java.version}</release>
|
||||
<parameters>true</parameters>
|
||||
<release>${source.level}</release>
|
||||
<showWarnings>true</showWarnings>
|
||||
<annotationProcessorPaths>
|
||||
<path>
|
||||
|
||||
@@ -214,7 +214,7 @@ public class AppRoleAuthentication implements ClientAuthentication, Authenticati
|
||||
|
||||
ResponseEntity<VaultResponse> entity = this.restOperations.exchange(getRoleIdIdPath(this.options),
|
||||
HttpMethod.GET, createHttpEntity(token), VaultResponse.class);
|
||||
return (String) ResponseUtil.getRequiredData(entity).get("role_id");
|
||||
return (String) ResponseUtil.getRequiredValue(entity, "role_id");
|
||||
}
|
||||
catch (HttpStatusCodeException e) {
|
||||
throw new VaultLoginException("Cannot get Role id using AppRole: %s"
|
||||
@@ -233,7 +233,7 @@ public class AppRoleAuthentication implements ClientAuthentication, Authenticati
|
||||
|
||||
VaultResponse response = unwrappingEndpoints.unwrap(ResponseUtil.getRequiredBody(entity));
|
||||
|
||||
return (String) response.getRequiredData().get("role_id");
|
||||
return (String) ResponseUtil.getRequiredValue(response, "role_id");
|
||||
}
|
||||
catch (HttpStatusCodeException e) {
|
||||
throw new VaultLoginException("Cannot unwrap Role id using AppRole: %s"
|
||||
@@ -244,6 +244,7 @@ public class AppRoleAuthentication implements ClientAuthentication, Authenticati
|
||||
throw new IllegalArgumentException("Unknown RoleId configuration: " + roleId);
|
||||
}
|
||||
|
||||
@SuppressWarnings("NullAway")
|
||||
private String getSecretId(SecretId secretId) throws VaultLoginException {
|
||||
|
||||
if (secretId instanceof Provided) {
|
||||
|
||||
@@ -128,20 +128,15 @@ public class AppRoleAuthenticationOptions {
|
||||
|
||||
private String path = DEFAULT_APPROLE_AUTHENTICATION_PATH;
|
||||
|
||||
@Nullable
|
||||
private String providedRoleId;
|
||||
private @Nullable String providedRoleId;
|
||||
|
||||
@Nullable
|
||||
private RoleId roleId;
|
||||
private @Nullable RoleId roleId;
|
||||
|
||||
@Nullable
|
||||
private String providedSecretId;
|
||||
private @Nullable String providedSecretId;
|
||||
|
||||
@Nullable
|
||||
private SecretId secretId;
|
||||
private @Nullable SecretId secretId;
|
||||
|
||||
@Nullable
|
||||
private String appRole;
|
||||
private @Nullable String appRole;
|
||||
|
||||
private UnwrappingEndpoints unwrappingEndpoints = UnwrappingEndpoints.SysWrapping;
|
||||
|
||||
@@ -250,6 +245,9 @@ public class AppRoleAuthenticationOptions {
|
||||
"AppRole authentication configured for pull mode. AppRole must not be null.");
|
||||
}
|
||||
|
||||
Assert.notNull(this.roleId, "RoleId must not be null");
|
||||
Assert.notNull(this.secretId, "SecretId must not be null");
|
||||
|
||||
return new AppRoleAuthenticationOptions(this.path, this.roleId, this.secretId, this.appRole,
|
||||
this.unwrappingEndpoints);
|
||||
}
|
||||
|
||||
@@ -299,7 +299,8 @@ public class AuthenticationSteps {
|
||||
@Nullable
|
||||
String uriTemplate;
|
||||
|
||||
String @Nullable[] urlVariables;
|
||||
@Nullable
|
||||
String[] urlVariables = new String[0];
|
||||
|
||||
@Nullable
|
||||
HttpEntity<?> entity;
|
||||
@@ -379,14 +380,14 @@ public class AuthenticationSteps {
|
||||
this.uri = uri;
|
||||
}
|
||||
|
||||
private HttpRequestBuilder(HttpMethod method, @Nullable String uriTemplate, String @Nullable[] urlVariables) {
|
||||
private HttpRequestBuilder(HttpMethod method, @Nullable String uriTemplate, @Nullable String[] urlVariables) {
|
||||
this.method = method;
|
||||
this.uriTemplate = uriTemplate;
|
||||
this.urlVariables = urlVariables;
|
||||
}
|
||||
|
||||
private HttpRequestBuilder(HttpMethod method, @Nullable URI uri, @Nullable String uriTemplate,
|
||||
String @Nullable[] urlVariables, @Nullable HttpEntity<?> entity) {
|
||||
@Nullable String[] urlVariables, @Nullable HttpEntity<?> entity) {
|
||||
this.method = method;
|
||||
this.uri = uri;
|
||||
this.uriTemplate = uriTemplate;
|
||||
@@ -448,8 +449,7 @@ public class AuthenticationSteps {
|
||||
@Nullable
|
||||
final String uriTemplate;
|
||||
|
||||
|
||||
final String @Nullable[] urlVariables;
|
||||
final @Nullable String[] urlVariables;
|
||||
|
||||
@Nullable
|
||||
final HttpEntity<?> entity;
|
||||
@@ -485,7 +485,8 @@ public class AuthenticationSteps {
|
||||
return this.uriTemplate;
|
||||
}
|
||||
|
||||
String @Nullable[] getUrlVariables() {
|
||||
@Nullable
|
||||
String[] getUrlVariables() {
|
||||
return this.urlVariables;
|
||||
}
|
||||
|
||||
|
||||
@@ -92,7 +92,7 @@ public class AuthenticationStepsExecutor implements ClientAuthentication {
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "ConstantConditions" })
|
||||
private Object evaluate(Iterable<Node<?>> steps) {
|
||||
private @Nullable Object evaluate(Iterable<Node<?>> steps) {
|
||||
|
||||
Object state = null;
|
||||
|
||||
@@ -108,14 +108,17 @@ public class AuthenticationStepsExecutor implements ClientAuthentication {
|
||||
}
|
||||
|
||||
if (o instanceof MapStep) {
|
||||
Assert.state(state != null, "No state available for MapStep");
|
||||
state = doMapStep((MapStep<Object, Object>) o, state);
|
||||
}
|
||||
|
||||
if (o instanceof ZipStep) {
|
||||
Assert.state(state != null, "No state available for ZipStep");
|
||||
state = doZipStep((ZipStep<Object, Object>) o, state);
|
||||
}
|
||||
|
||||
if (o instanceof OnNextStep) {
|
||||
Assert.state(state != null, "No state available for OnNextStep");
|
||||
state = doOnNext((OnNextStep<Object>) o, state);
|
||||
}
|
||||
|
||||
@@ -143,12 +146,11 @@ public class AuthenticationStepsExecutor implements ClientAuthentication {
|
||||
}
|
||||
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
@Nullable
|
||||
private Object doHttpRequest(HttpRequestNode<Object> step, @Nullable Object state) {
|
||||
private @Nullable Object doHttpRequest(HttpRequestNode<Object> step, @Nullable Object state) {
|
||||
|
||||
HttpRequest<Object> definition = step.getDefinition();
|
||||
|
||||
if (definition.getUri() == null) {
|
||||
if (definition.getUriTemplate() != null) {
|
||||
|
||||
ResponseEntity<?> exchange = this.restOperations.exchange(definition.getUriTemplate(),
|
||||
definition.getMethod(), getEntity(definition.getEntity(), state), definition.getResponseType(),
|
||||
@@ -156,11 +158,16 @@ public class AuthenticationStepsExecutor implements ClientAuthentication {
|
||||
|
||||
return exchange.getBody();
|
||||
}
|
||||
ResponseEntity<?> exchange = this.restOperations.exchange(definition.getUri(), definition.getMethod(),
|
||||
getEntity(definition.getEntity(), state), definition.getResponseType());
|
||||
|
||||
return exchange.getBody();
|
||||
if (definition.getUri() != null) {
|
||||
|
||||
ResponseEntity<?> exchange = this.restOperations.exchange(definition.getUri(), definition.getMethod(),
|
||||
getEntity(definition.getEntity(), state), definition.getResponseType());
|
||||
|
||||
return exchange.getBody();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
static HttpEntity<?> getEntity(@Nullable HttpEntity<?> entity, @Nullable Object state) {
|
||||
@@ -185,6 +192,7 @@ public class AuthenticationStepsExecutor implements ClientAuthentication {
|
||||
return o.apply(state);
|
||||
}
|
||||
|
||||
@SuppressWarnings("NullAway")
|
||||
private Object doZipStep(ZipStep<Object, Object> o, Object state) {
|
||||
|
||||
Object result = evaluate(o.getRight());
|
||||
|
||||
@@ -155,7 +155,7 @@ public class AuthenticationStepsOperator implements VaultTokenSupplier {
|
||||
return state;
|
||||
}
|
||||
|
||||
@SuppressWarnings({"NullAway", "DataFlowIssue"})
|
||||
@SuppressWarnings({ "NullAway", "DataFlowIssue" })
|
||||
private Mono<Object> doHttpRequest(HttpRequestNode<Object> step, Object state) {
|
||||
|
||||
HttpRequest<Object> definition = step.getDefinition();
|
||||
|
||||
@@ -159,7 +159,7 @@ public class AzureMsiAuthentication implements ClientAuthentication, Authenticat
|
||||
VaultResponse response = this.vaultRestOperations
|
||||
.postForObject(AuthenticationUtil.getLoginPath(this.options.getPath()), login, VaultResponse.class);
|
||||
|
||||
Assert.state(response != null && response.getAuth() != null, "Auth field must not be null");
|
||||
Assert.state(response != null, "Auth field must not be null");
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Login successful using Azure authentication");
|
||||
@@ -185,6 +185,7 @@ public class AzureMsiAuthentication implements ClientAuthentication, Authenticat
|
||||
return loginBody;
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "NullAway", "rawtypes" })
|
||||
private String getAccessToken() {
|
||||
|
||||
ResponseEntity<Map> response = this.azureMetadataRestOperations
|
||||
@@ -200,6 +201,7 @@ public class AzureMsiAuthentication implements ClientAuthentication, Authenticat
|
||||
return vmEnvironment != null ? vmEnvironment : fetchAzureVmEnvironment();
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
private AzureVmEnvironment fetchAzureVmEnvironment() {
|
||||
|
||||
ResponseEntity<Map> response = this.azureMetadataRestOperations
|
||||
@@ -208,16 +210,23 @@ public class AzureMsiAuthentication implements ClientAuthentication, Authenticat
|
||||
return toAzureVmEnvironment(ResponseUtil.getRequiredBody(response));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
private static AzureVmEnvironment toAzureVmEnvironment(Map<String, Object> instanceMetadata) {
|
||||
|
||||
Map<String, String> compute = (Map) instanceMetadata.get("compute");
|
||||
|
||||
Assert.notNull(compute, "Metadata does not contain compute");
|
||||
|
||||
String subscriptionId = compute.get("subscriptionId");
|
||||
String resourceGroupName = compute.get("resourceGroupName");
|
||||
String vmName = compute.get("name");
|
||||
String vmScaleSetName = compute.get("vmScaleSetName");
|
||||
|
||||
Assert.notNull(subscriptionId, "Metadata does not contain subscriptionId");
|
||||
Assert.notNull(resourceGroupName, "Metadata does not contain resourceGroupName");
|
||||
Assert.notNull(vmName, "Metadata does not contain name");
|
||||
Assert.notNull(vmScaleSetName, "Metadata does not contain vmScaleSetName");
|
||||
|
||||
return new AzureVmEnvironment(subscriptionId, resourceGroupName, vmName, vmScaleSetName);
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ package org.springframework.vault.authentication;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import org.jspecify.annotations.NonNull;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.vault.VaultException;
|
||||
@@ -38,7 +39,7 @@ public class CachingVaultTokenSupplier implements VaultTokenSupplier, ReactiveSe
|
||||
|
||||
private final VaultTokenSupplier clientAuthentication;
|
||||
|
||||
private final AtomicReference<Mono<VaultToken>> tokenRef = new AtomicReference<>(EMPTY);
|
||||
private final AtomicReference<@NonNull Mono<VaultToken>> tokenRef = new AtomicReference<>(EMPTY);
|
||||
|
||||
private CachingVaultTokenSupplier(VaultTokenSupplier clientAuthentication) {
|
||||
this.clientAuthentication = clientAuthentication;
|
||||
@@ -56,6 +57,7 @@ public class CachingVaultTokenSupplier implements VaultTokenSupplier, ReactiveSe
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("NullAway")
|
||||
public Mono<VaultToken> getVaultToken() throws VaultException {
|
||||
|
||||
if (Objects.equals(this.tokenRef.get(), EMPTY)) {
|
||||
|
||||
@@ -239,7 +239,9 @@ public class LifecycleAwareSessionManager extends LifecycleAwareSessionManagerSu
|
||||
VaultResponse vaultResponse = this.restOperations.postForObject("auth/token/renew-self",
|
||||
new HttpEntity<>(VaultHttpHeaders.from(wrapper.token)), VaultResponse.class);
|
||||
|
||||
LoginToken renewed = LoginTokenUtil.from(vaultResponse.getRequiredAuth());
|
||||
Assert.notNull(vaultResponse, "VaultResponse must not be null");
|
||||
|
||||
LoginToken renewed = LoginTokenUtil.from(vaultResponse.getAuth());
|
||||
|
||||
if (isExpired(renewed)) {
|
||||
|
||||
|
||||
@@ -206,8 +206,7 @@ public class LoginToken extends VaultToken {
|
||||
*/
|
||||
public static class LoginTokenBuilder {
|
||||
|
||||
|
||||
private char @Nullable[] token;
|
||||
private char @Nullable [] token;
|
||||
|
||||
private boolean renewable;
|
||||
|
||||
|
||||
@@ -40,8 +40,8 @@ final class LoginTokenUtil {
|
||||
static LoginToken from(Map<String, Object> auth) {
|
||||
|
||||
Assert.notNull(auth, "Authentication must not be null");
|
||||
|
||||
String token = (String) auth.get("client_token");
|
||||
Assert.notNull(token, "Authentication must contain 'client_token' key");
|
||||
|
||||
return from(token.toCharArray(), auth);
|
||||
}
|
||||
@@ -52,6 +52,7 @@ final class LoginTokenUtil {
|
||||
* @return the {@link LoginToken}
|
||||
* @since 2.0
|
||||
*/
|
||||
@SuppressWarnings("NullAway")
|
||||
static LoginToken from(char[] token, Map<String, ?> auth) {
|
||||
|
||||
Assert.notNull(auth, "Authentication must not be null");
|
||||
|
||||
@@ -20,6 +20,7 @@ import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import org.jspecify.annotations.NonNull;
|
||||
import reactor.core.publisher.Mono;
|
||||
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
@@ -91,7 +92,7 @@ public class ReactiveLifecycleAwareSessionManager extends LifecycleAwareSessionM
|
||||
* The token state: Contains the currently valid token that identifies the Vault
|
||||
* session.
|
||||
*/
|
||||
private volatile AtomicReference<Mono<TokenWrapper>> token = new AtomicReference<>(EMPTY);
|
||||
private final AtomicReference<@NonNull Mono<TokenWrapper>> token = new AtomicReference<>(EMPTY);
|
||||
|
||||
/**
|
||||
* Create a {@link ReactiveLifecycleAwareSessionManager} given
|
||||
@@ -136,6 +137,7 @@ public class ReactiveLifecycleAwareSessionManager extends LifecycleAwareSessionM
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("NullAway")
|
||||
public void destroy() {
|
||||
|
||||
Mono<TokenWrapper> tokenMono = this.token.get();
|
||||
@@ -149,6 +151,7 @@ public class ReactiveLifecycleAwareSessionManager extends LifecycleAwareSessionM
|
||||
* @return a mono emitting completion upon successful revocation.
|
||||
* @since 3.0.2
|
||||
*/
|
||||
@SuppressWarnings("NullAway")
|
||||
public Mono<Void> revoke() {
|
||||
return doRevoke(this.token.get()).doOnSuccess(unused -> this.token.set(EMPTY));
|
||||
}
|
||||
@@ -216,6 +219,7 @@ public class ReactiveLifecycleAwareSessionManager extends LifecycleAwareSessionM
|
||||
* obtained. {@link Mono#empty()} if a new the token expired or
|
||||
* {@link Mono#error(Throwable)} if refresh failed.
|
||||
*/
|
||||
@SuppressWarnings("NullAway")
|
||||
public Mono<VaultToken> renewToken() {
|
||||
|
||||
this.logger.info("Renewing token");
|
||||
@@ -268,7 +272,7 @@ public class ReactiveLifecycleAwareSessionManager extends LifecycleAwareSessionM
|
||||
.doOnSubscribe(ignore -> multicastEvent(new BeforeLoginTokenRenewedEvent(tokenWrapper.getToken())))
|
||||
.handle((response, sink) -> {
|
||||
|
||||
LoginToken renewed = LoginTokenUtil.from(response.getRequiredAuth());
|
||||
LoginToken renewed = LoginTokenUtil.from(response.getAuth());
|
||||
|
||||
if (!isExpired(renewed)) {
|
||||
sink.next(new TokenWrapper(renewed, tokenWrapper.revocable));
|
||||
@@ -301,6 +305,7 @@ public class ReactiveLifecycleAwareSessionManager extends LifecycleAwareSessionM
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("NullAway")
|
||||
public Mono<VaultToken> getVaultToken() throws VaultException {
|
||||
|
||||
Mono<TokenWrapper> tokenWrapper = this.token.get();
|
||||
|
||||
@@ -15,12 +15,16 @@
|
||||
*/
|
||||
package org.springframework.vault.authentication;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.vault.support.VaultResponseSupport;
|
||||
|
||||
/**
|
||||
* Utilities to extract required responses from {@link ResponseEntity}.
|
||||
*
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
class ResponseUtil {
|
||||
@@ -49,4 +53,25 @@ class ResponseUtil {
|
||||
|
||||
return response.getRequiredData();
|
||||
}
|
||||
|
||||
public static Object getRequiredValue(ResponseEntity<? extends VaultResponseSupport<Map<String, Object>>> response,
|
||||
String key) {
|
||||
return getRequiredValue(getRequiredBody(response), key);
|
||||
}
|
||||
|
||||
public static Object getRequiredValue(@Nullable VaultResponseSupport<Map<String, Object>> response, String key) {
|
||||
|
||||
if (response == null) {
|
||||
throw new IllegalStateException("Expected non-null response body");
|
||||
}
|
||||
|
||||
Object value = response.getRequiredData().get(key);
|
||||
|
||||
if (value == null) {
|
||||
throw new IllegalStateException(String.format("Key '%s' not found in response", key));
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ import org.springframework.vault.support.VaultResponse;
|
||||
* @author Mark Paluch
|
||||
* @since 2.2
|
||||
*/
|
||||
@SuppressWarnings("NullAway")
|
||||
public enum UnwrappingEndpoints {
|
||||
|
||||
/**
|
||||
|
||||
@@ -90,6 +90,7 @@ public class UsernamePasswordAuthentication implements ClientAuthentication, Aut
|
||||
return createAuthenticationSteps(this.options);
|
||||
}
|
||||
|
||||
@SuppressWarnings("NullAway")
|
||||
private VaultToken createTokenUsingUsernamePasswordAuthentication() {
|
||||
|
||||
try {
|
||||
|
||||
@@ -69,7 +69,7 @@ class ClientConfiguration {
|
||||
}
|
||||
|
||||
static SSLContext getSSLContext(SslConfiguration.KeyStoreConfiguration keyStoreConfiguration,
|
||||
SslConfiguration.KeyConfiguration keyConfiguration, TrustManager @Nullable[] trustManagers)
|
||||
SslConfiguration.KeyConfiguration keyConfiguration, TrustManager @Nullable [] trustManagers)
|
||||
throws GeneralSecurityException, IOException {
|
||||
|
||||
KeyManager[] keyManagers = keyStoreConfiguration.isPresent()
|
||||
@@ -113,9 +113,8 @@ class ClientConfiguration {
|
||||
return keyStore;
|
||||
}
|
||||
|
||||
|
||||
static TrustManager @Nullable[] getTrustManagers(SslConfiguration sslConfiguration)
|
||||
throws GeneralSecurityException, IOException {
|
||||
static TrustManager @Nullable [] getTrustManagers(SslConfiguration sslConfiguration)
|
||||
throws GeneralSecurityException, IOException {
|
||||
|
||||
return sslConfiguration.getTrustStoreConfiguration().isPresent()
|
||||
? createTrustManagerFactory(sslConfiguration.getTrustStoreConfiguration()).getTrustManagers() : null;
|
||||
@@ -150,8 +149,7 @@ class ClientConfiguration {
|
||||
logger.debug("Loading keystore from %s".formatted(keyStoreConfiguration.getResource()));
|
||||
}
|
||||
|
||||
try (InputStream inputStream = keyStoreConfiguration.getResource()
|
||||
.getInputStream()) {
|
||||
try (InputStream inputStream = keyStoreConfiguration.getResource().getInputStream()) {
|
||||
|
||||
if (SslConfiguration.PEM_KEYSTORE_TYPE.equalsIgnoreCase(keyStoreConfiguration.getStoreType())) {
|
||||
|
||||
@@ -408,11 +406,11 @@ class ClientConfiguration {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String chooseClientAlias(String[] keyType, Principal[] issuers, Socket socket) {
|
||||
public @Nullable String chooseClientAlias(String[] keyType, Principal[] issuers, Socket socket) {
|
||||
return this.keyConfiguration.getKeyAlias();
|
||||
}
|
||||
|
||||
public String chooseEngineClientAlias(String[] keyType, Principal[] issuers, SSLEngine engine) {
|
||||
public @Nullable String chooseEngineClientAlias(String[] keyType, Principal[] issuers, SSLEngine engine) {
|
||||
return this.keyConfiguration.getKeyAlias();
|
||||
}
|
||||
|
||||
|
||||
@@ -219,6 +219,8 @@ public class RestTemplateBuilder {
|
||||
*/
|
||||
protected RestTemplate createTemplate() {
|
||||
|
||||
Assert.notNull(this.endpointProvider, "VaultEndpointProvider must not be null");
|
||||
|
||||
ClientHttpRequestFactory requestFactory = this.requestFactory.get();
|
||||
|
||||
LinkedHashMap<String, String> defaultHeaders = new LinkedHashMap<>(this.defaultHeaders);
|
||||
|
||||
@@ -208,7 +208,7 @@ public abstract class AbstractReactiveVaultConfiguration extends AbstractVaultCo
|
||||
|
||||
throw new IllegalStateException(("Cannot construct VaultTokenSupplier from %s. "
|
||||
+ "ClientAuthentication must implement AuthenticationStepsFactory or be TokenAuthentication")
|
||||
.formatted(clientAuthentication));
|
||||
.formatted(clientAuthentication));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -425,7 +425,7 @@ public class EnvironmentVaultConfiguration extends AbstractVaultConfiguration im
|
||||
private Resource getResource(String key) {
|
||||
|
||||
String value = getProperty(key);
|
||||
return value != null ? this.applicationContext.getResource(value) : null;
|
||||
return value != null && this.applicationContext != null ? this.applicationContext.getResource(value) : null;
|
||||
}
|
||||
|
||||
enum AuthenticationMethod {
|
||||
|
||||
@@ -35,7 +35,7 @@ class KeyValueUtilities {
|
||||
static Metadata getMetadata(Map<String, Object> responseMetadata) {
|
||||
|
||||
MetadataBuilder builder = Metadata.builder();
|
||||
TemporalAccessor created_time = getDate(responseMetadata, "created_time");
|
||||
TemporalAccessor created_time = getRequiredDate(responseMetadata, "created_time");
|
||||
TemporalAccessor deletion_time = getDate(responseMetadata, "deletion_time");
|
||||
|
||||
builder.createdAt(Instant.from(created_time));
|
||||
@@ -51,13 +51,12 @@ class KeyValueUtilities {
|
||||
builder.customMetadata((Map) responseMetadata.get("custom_metadata"));
|
||||
|
||||
Integer version = (Integer) responseMetadata.get("version");
|
||||
builder.version(Version.from(version));
|
||||
builder.version(version != null ? Version.from(version) : Version.unversioned());
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static TemporalAccessor getDate(Map<String, Object> responseMetadata, String key) {
|
||||
private static @Nullable TemporalAccessor getDate(Map<String, Object> responseMetadata, String key) {
|
||||
|
||||
String date = (String) responseMetadata.getOrDefault(key, "");
|
||||
if (StringUtils.hasText(date)) {
|
||||
@@ -66,6 +65,17 @@ class KeyValueUtilities {
|
||||
return null;
|
||||
}
|
||||
|
||||
private static TemporalAccessor getRequiredDate(Map<String, Object> responseMetadata, String key) {
|
||||
|
||||
TemporalAccessor date = getDate(responseMetadata, key);
|
||||
|
||||
if (date == null) {
|
||||
throw new IllegalArgumentException("Date for key '" + key + "' is null");
|
||||
}
|
||||
|
||||
return date;
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "ConstantConditions", "unchecked", "rawtypes" })
|
||||
static VaultMetadataResponse fromMap(Map<String, Object> metadataResponse) {
|
||||
|
||||
@@ -73,22 +83,37 @@ class KeyValueUtilities {
|
||||
|
||||
return VaultMetadataResponse.builder()
|
||||
.casRequired(Boolean.parseBoolean(String.valueOf(metadataResponse.get("cas_required"))))
|
||||
.createdTime(toInstant((String) metadataResponse.get("created_time")))
|
||||
.createdTime(toRequiredInstant((String) metadataResponse.get("created_time")))
|
||||
.currentVersion(Integer.parseInt(String.valueOf(metadataResponse.get("current_version"))))
|
||||
.deleteVersionAfter(duration)
|
||||
.maxVersions(Integer.parseInt(String.valueOf(metadataResponse.get("max_versions"))))
|
||||
.oldestVersion(Integer.parseInt(String.valueOf(metadataResponse.get("oldest_version"))))
|
||||
.updatedTime(toInstant((String) metadataResponse.get("updated_time")))
|
||||
.updatedTime(toRequiredInstant((String) metadataResponse.get("updated_time")))
|
||||
.versions(buildVersions((Map) metadataResponse.get("versions")))
|
||||
.build();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static Instant toInstant(String date) {
|
||||
static Instant toInstant(@Nullable String date) {
|
||||
return StringUtils.hasText(date) ? Instant.from(DateTimeFormatter.ISO_OFFSET_DATE_TIME.parse(date)) : null;
|
||||
}
|
||||
|
||||
private static List<Metadata> buildVersions(Map<String, Map<String, Object>> versions) {
|
||||
static Instant toRequiredInstant(@Nullable String date) {
|
||||
|
||||
Instant instant = toInstant(date);
|
||||
|
||||
if (instant == null) {
|
||||
throw new IllegalArgumentException("Date is null");
|
||||
}
|
||||
|
||||
return instant;
|
||||
}
|
||||
|
||||
private static List<Metadata> buildVersions(@Nullable Map<String, Map<String, Object>> versions) {
|
||||
|
||||
if (versions == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
return versions.entrySet()
|
||||
.stream()
|
||||
@@ -98,17 +123,18 @@ class KeyValueUtilities {
|
||||
|
||||
private static Versioned.Metadata buildVersion(String version, Map<String, Object> versionData) {
|
||||
|
||||
Instant createdTime = toInstant((String) versionData.get("created_time"));
|
||||
Instant createdTime = toRequiredInstant((String) versionData.get("created_time"));
|
||||
Instant deletionTime = toInstant((String) versionData.get("deletion_time"));
|
||||
boolean destroyed = (Boolean) versionData.get("destroyed");
|
||||
Boolean destroyed = (Boolean) versionData.get("destroyed");
|
||||
Versioned.Version kvVersion = Versioned.Version.from(Integer.parseInt(version));
|
||||
|
||||
return Versioned.Metadata.builder()
|
||||
.createdAt(createdTime)
|
||||
.deletedAt(deletionTime)
|
||||
.destroyed(destroyed)
|
||||
.version(kvVersion)
|
||||
.build();
|
||||
MetadataBuilder builder = Metadata.builder().createdAt(createdTime).deletedAt(deletionTime).version(kvVersion);
|
||||
|
||||
if (destroyed != null) {
|
||||
builder.destroyed(destroyed);
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
static Map<String, Object> createPatchRequest(Map<String, ?> patch, Map<String, Object> previous,
|
||||
|
||||
@@ -84,7 +84,7 @@ class PropertyMapper {
|
||||
* @return a {@link Source} that can be used to complete the mapping
|
||||
* @see #from(Object)
|
||||
*/
|
||||
public <T> Source<T> from(Supplier<T> supplier) {
|
||||
public <T> Source<T> from(Supplier<@Nullable T> supplier) {
|
||||
Assert.notNull(supplier, "Supplier must not be null");
|
||||
Source<T> source = getSource(supplier);
|
||||
if (this.sourceOperator != null) {
|
||||
@@ -332,10 +332,10 @@ class PropertyMapper {
|
||||
/**
|
||||
* Supplier that will catch and ignore any {@link NullPointerException}.
|
||||
*/
|
||||
private record NullPointerExceptionSafeSupplier<T>(Supplier<T> supplier) implements Supplier<T> {
|
||||
private record NullPointerExceptionSafeSupplier<T>(Supplier<T> supplier) implements Supplier<@Nullable T> {
|
||||
|
||||
@Override
|
||||
public T get() {
|
||||
public @Nullable T get() {
|
||||
try {
|
||||
return this.supplier.get();
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ class ReactiveVaultKeyValue2Template extends ReactiveVaultKeyValue2Accessor impl
|
||||
|
||||
return get(path).filter(it -> it.getData() != null)
|
||||
.switchIfEmpty(Mono.error(new SecretNotFoundException(
|
||||
"No data found at %s; patch only works on existing data".formatted(createDataPath(path)),
|
||||
"No data found at '%s'; patch only works on existing data".formatted(createDataPath(path)),
|
||||
createLogicalPath(path))))
|
||||
.flatMap(readResponse -> {
|
||||
|
||||
|
||||
@@ -47,6 +47,7 @@ public class ReactiveVaultSysTemplate implements ReactiveVaultSysOperations {
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("NullAway")
|
||||
public Mono<Boolean> isInitialized() {
|
||||
|
||||
return this.vaultOperations.doWithSession(webClient -> {
|
||||
@@ -54,11 +55,13 @@ public class ReactiveVaultSysTemplate implements ReactiveVaultSysOperations {
|
||||
.uri("sys/init")
|
||||
.header(VaultHttpHeaders.VAULT_NAMESPACE, "")
|
||||
.exchangeToMono(clientResponse -> clientResponse.toEntity(Map.class))
|
||||
.filter(HttpEntity::hasBody)
|
||||
.map(it -> (Boolean) it.getBody().get("initialized"));
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("NullAway")
|
||||
public Mono<VaultHealth> health() {
|
||||
|
||||
return this.vaultOperations.doWithVault(webClient -> {
|
||||
@@ -67,7 +70,9 @@ public class ReactiveVaultSysTemplate implements ReactiveVaultSysOperations {
|
||||
.uri("sys/health")
|
||||
.header(VaultHttpHeaders.VAULT_NAMESPACE, "")
|
||||
.exchangeToMono(clientResponse -> {
|
||||
return clientResponse.toEntity(VaultSysTemplate.VaultHealthImpl.class).map(HttpEntity::getBody);
|
||||
return clientResponse.toEntity(VaultSysTemplate.VaultHealthImpl.class)
|
||||
.filter(HttpEntity::hasBody)
|
||||
.map(HttpEntity::getBody);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -25,14 +25,13 @@ import org.springframework.web.client.RestOperations;
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface RestOperationsCallback<T> {
|
||||
public interface RestOperationsCallback<T extends @Nullable Object> {
|
||||
|
||||
/**
|
||||
* Callback method.
|
||||
* @param restOperations restOperations to use, must not be {@literal null}.
|
||||
* @return a result object or null if none.
|
||||
*/
|
||||
@Nullable
|
||||
T doWithRestOperations(RestOperations restOperations);
|
||||
|
||||
}
|
||||
|
||||
@@ -54,15 +54,13 @@ class VaultKeyValue1Template extends VaultKeyValueAccessor implements VaultKeyVa
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public List<String> list(String path) {
|
||||
public @Nullable List<String> list(String path) {
|
||||
return this.vaultOperations.list(createDataPath(path));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public VaultResponse get(String path) {
|
||||
public @Nullable VaultResponse get(String path) {
|
||||
|
||||
Assert.hasText(path, "Path must not be empty");
|
||||
|
||||
@@ -76,10 +74,9 @@ class VaultKeyValue1Template extends VaultKeyValueAccessor implements VaultKeyVa
|
||||
});
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> VaultResponseSupport<T> get(String path, Class<T> responseType) {
|
||||
public <T> @Nullable VaultResponseSupport<T> get(String path, Class<T> responseType) {
|
||||
|
||||
Assert.hasText(path, "Path must not be empty");
|
||||
Assert.notNull(responseType, "Response type must not be null");
|
||||
|
||||
@@ -48,10 +48,9 @@ abstract class VaultKeyValue2Accessor extends VaultKeyValueAccessor {
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public List<String> list(String path) {
|
||||
public @Nullable List<String> list(String path) {
|
||||
|
||||
VaultListResponse read = doRead(restOperations -> {
|
||||
return restOperations.exchange(
|
||||
|
||||
@@ -48,9 +48,8 @@ class VaultKeyValue2Template extends VaultKeyValue2Accessor implements VaultKeyV
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public VaultResponse get(String path) {
|
||||
public @Nullable VaultResponse get(String path) {
|
||||
|
||||
Assert.hasText(path, "Path must not be empty");
|
||||
|
||||
@@ -64,10 +63,9 @@ class VaultKeyValue2Template extends VaultKeyValue2Accessor implements VaultKeyV
|
||||
});
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public <T> VaultResponseSupport<T> get(String path, Class<T> responseType) {
|
||||
public <T> @Nullable VaultResponseSupport<T> get(String path, Class<T> responseType) {
|
||||
|
||||
Assert.hasText(path, "Path must not be empty");
|
||||
Assert.notNull(responseType, "Response type must not be null");
|
||||
@@ -90,7 +88,7 @@ class VaultKeyValue2Template extends VaultKeyValue2Accessor implements VaultKeyV
|
||||
VaultResponse readResponse = get(path);
|
||||
if (readResponse == null || readResponse.getData() == null) {
|
||||
throw new SecretNotFoundException(
|
||||
"No data found at %s; patch only works on existing data".formatted(createDataPath(path)),
|
||||
"No data found at '%s'; patch only works on existing data".formatted(createDataPath(path)),
|
||||
"%s/%s".formatted(this.path, path));
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
package org.springframework.vault.core;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
@@ -75,11 +76,12 @@ abstract class VaultKeyValueAccessor implements VaultKeyValueOperationsSupport {
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("NullAway")
|
||||
public void delete(String path) {
|
||||
|
||||
Assert.hasText(path, "Path must not be empty");
|
||||
|
||||
this.vaultOperations.doWithSession((restOperations -> {
|
||||
this.vaultOperations.doWithSession((RestOperationsCallback<@Nullable Void>) (restOperations -> {
|
||||
restOperations.exchange(createDataPath(path), HttpMethod.DELETE, null, Void.class);
|
||||
|
||||
return null;
|
||||
@@ -97,8 +99,8 @@ abstract class VaultKeyValueAccessor implements VaultKeyValueOperationsSupport {
|
||||
* @param <T> return type. Value is created by the {@code mappingFunction}.
|
||||
* @return mapped value.
|
||||
*/
|
||||
@Nullable
|
||||
<I, T> T doRead(String path, Class<I> deserializeAs, BiFunction<VaultResponseSupport<?>, I, T> mappingFunction) {
|
||||
<I, T> @Nullable T doRead(String path, Class<I> deserializeAs,
|
||||
BiFunction<VaultResponseSupport<?>, I, T> mappingFunction) {
|
||||
|
||||
ParameterizedTypeReference<VaultResponseSupport<JsonNode>> ref = VaultResponses
|
||||
.getTypeReference(JsonNode.class);
|
||||
@@ -125,8 +127,7 @@ abstract class VaultKeyValueAccessor implements VaultKeyValueOperationsSupport {
|
||||
* @param typeReference must not be {@literal null}
|
||||
* @return mapped value.
|
||||
*/
|
||||
@Nullable
|
||||
<T> T doRead(String path, ParameterizedTypeReference<T> typeReference) {
|
||||
<T> @Nullable T doRead(String path, ParameterizedTypeReference<T> typeReference) {
|
||||
|
||||
return doRead((restOperations) -> {
|
||||
return restOperations.exchange(path, HttpMethod.GET, null, typeReference);
|
||||
@@ -156,10 +157,10 @@ abstract class VaultKeyValueAccessor implements VaultKeyValueOperationsSupport {
|
||||
* @param callback must not be {@literal null}.
|
||||
* @return can be {@literal null}.
|
||||
*/
|
||||
@Nullable
|
||||
<T> T doRead(Function<RestOperations, ResponseEntity<T>> callback) {
|
||||
@SuppressWarnings("NullAway")
|
||||
<T extends @Nullable Object> @Nullable T doRead(Function<RestOperations, ResponseEntity<T>> callback) {
|
||||
|
||||
return this.vaultOperations.doWithSession((restOperations) -> {
|
||||
return this.vaultOperations.doWithSession((RestOperationsCallback<@Nullable T>) (restOperations) -> {
|
||||
|
||||
try {
|
||||
return callback.apply(restOperations).getBody();
|
||||
@@ -182,16 +183,18 @@ abstract class VaultKeyValueAccessor implements VaultKeyValueOperationsSupport {
|
||||
* @return the response of this write action.
|
||||
*/
|
||||
@Nullable
|
||||
@SuppressWarnings("NullAway")
|
||||
VaultResponse doWrite(String path, Object body) {
|
||||
|
||||
Assert.hasText(path, "Path must not be empty");
|
||||
|
||||
try {
|
||||
|
||||
return this.vaultOperations.doWithSession((restOperations) -> {
|
||||
return restOperations.exchange(path, HttpMethod.POST, new HttpEntity<>(body), VaultResponse.class)
|
||||
.getBody();
|
||||
});
|
||||
return this.vaultOperations
|
||||
.doWithSession((RestOperationsCallback<@Nullable VaultResponse>) (restOperations) -> {
|
||||
return restOperations.exchange(path, HttpMethod.POST, new HttpEntity<>(body), VaultResponse.class)
|
||||
.getBody();
|
||||
});
|
||||
}
|
||||
catch (HttpStatusCodeException e) {
|
||||
throw VaultResponses.buildException(e, path);
|
||||
@@ -229,7 +232,7 @@ abstract class VaultKeyValueAccessor implements VaultKeyValueOperationsSupport {
|
||||
return Optional.empty();
|
||||
});
|
||||
|
||||
return mapper.orElseGet(ObjectMapper::new);
|
||||
return Objects.requireNonNull(mapper).orElseGet(ObjectMapper::new);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -17,6 +17,8 @@ package org.springframework.vault.core;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.vault.support.VaultMetadataRequest;
|
||||
import org.springframework.vault.support.VaultMetadataResponse;
|
||||
@@ -46,7 +48,7 @@ class VaultKeyValueMetadataTemplate implements VaultKeyValueMetadataOperations {
|
||||
|
||||
@Override
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
public VaultMetadataResponse get(String path) {
|
||||
public @Nullable VaultMetadataResponse get(String path) {
|
||||
|
||||
VaultResponseSupport<Map> response = this.vaultOperations.read(getPath(path), Map.class);
|
||||
|
||||
|
||||
@@ -54,8 +54,7 @@ public interface VaultKeyValueOperations extends VaultKeyValueOperationsSupport
|
||||
* @param responseType must not be {@literal null}.
|
||||
* @return the data. May be {@literal null} if the path does not exist.
|
||||
*/
|
||||
@Nullable
|
||||
<T> VaultResponseSupport<T> get(String path, Class<T> responseType);
|
||||
<T> @Nullable VaultResponseSupport<T> get(String path, Class<T> responseType);
|
||||
|
||||
/**
|
||||
* Update the secret at {@code path} without removing the existing secrets. Requires a
|
||||
|
||||
@@ -122,8 +122,8 @@ public interface VaultOperations {
|
||||
VaultWrappingOperations opsForWrapping();
|
||||
|
||||
/**
|
||||
* Read from a Vault path. Reading data using this method is suitable for API
|
||||
* calls/secret backends that do not require a request body.
|
||||
* Read ({@code GET)} from a Vault path. Reading data using this method is suitable
|
||||
* for API calls/secret backends that do not require a request body.
|
||||
* @param path must not be {@literal null}.
|
||||
* @return the data. May be {@literal null} if the path does not exist.
|
||||
*/
|
||||
@@ -131,14 +131,52 @@ public interface VaultOperations {
|
||||
VaultResponse read(String path);
|
||||
|
||||
/**
|
||||
* Read from a secret backend. Reading data using this method is suitable for secret
|
||||
* backends that do not require a request body.
|
||||
* Read ({@code GET)} from a Vault path. Reading data using this method is suitable
|
||||
* for API calls/secret backends that do not require a request body.
|
||||
* @param path must not be {@literal null}.
|
||||
* @return the data.
|
||||
* @throws SecretNotFoundException if the path does not exist.
|
||||
* @since 4.0
|
||||
*/
|
||||
default VaultResponse readRequired(String path) throws SecretNotFoundException {
|
||||
|
||||
VaultResponse response = read(path);
|
||||
|
||||
if (response == null) {
|
||||
throw new SecretNotFoundException("No data found at '%s'".formatted(path), path);
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read ({@code GET)} from a secret backend. Reading data using this method is
|
||||
* suitable for secret backends that do not require a request body.
|
||||
* @param path must not be {@literal null}.
|
||||
* @param responseType must not be {@literal null}.
|
||||
* @return the data. May be {@literal null} if the path does not exist.
|
||||
*/
|
||||
@Nullable
|
||||
<T> VaultResponseSupport<T> read(String path, Class<T> responseType);
|
||||
<T extends @Nullable Object> VaultResponseSupport<T> read(String path, Class<T> responseType);
|
||||
|
||||
/**
|
||||
* Read ({@code GET)} from a secret backend. Reading data using this method is
|
||||
* suitable for secret backends that do not require a request body.
|
||||
* @param path must not be {@literal null}.
|
||||
* @param responseType must not be {@literal null}.
|
||||
* @return the data.
|
||||
* @throws SecretNotFoundException if the path does not exist.
|
||||
* @since 4.0
|
||||
*/
|
||||
default <T> VaultResponseSupport<T> readRequired(String path, Class<T> responseType) {
|
||||
|
||||
VaultResponseSupport<T> response = read(path, responseType);
|
||||
|
||||
if (response == null) {
|
||||
throw new SecretNotFoundException("No data found at '%s'".formatted(path), path);
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enumerate keys from a Vault path.
|
||||
@@ -149,7 +187,7 @@ public interface VaultOperations {
|
||||
List<String> list(String path);
|
||||
|
||||
/**
|
||||
* Write to a Vault path.
|
||||
* Write ({@code POST)} to a Vault path.
|
||||
* @param path must not be {@literal null}.
|
||||
* @return the response, may be {@literal null}.
|
||||
* @since 2.0
|
||||
@@ -160,7 +198,7 @@ public interface VaultOperations {
|
||||
}
|
||||
|
||||
/**
|
||||
* Write to a Vault path.
|
||||
* Write ({@code POST)} to a Vault path.
|
||||
* @param path must not be {@literal null}.
|
||||
* @param body the body, may be {@literal null} if absent.
|
||||
* @return the response, may be {@literal null}.
|
||||
@@ -168,6 +206,27 @@ public interface VaultOperations {
|
||||
@Nullable
|
||||
VaultResponse write(String path, @Nullable Object body);
|
||||
|
||||
/**
|
||||
* Invoke an operation on a Vault path, typically a {@code POST} request along with an
|
||||
* optional request body expecing a response.
|
||||
* @param path must not be {@literal null}.
|
||||
* @param body the body, may be {@literal null} if absent.
|
||||
* @return the response.
|
||||
* @throws IllegalStateException if the operation returns without returning a
|
||||
* response.
|
||||
* @since 4.0
|
||||
*/
|
||||
default VaultResponse invoke(String path, @Nullable Object body) {
|
||||
|
||||
VaultResponse response = write(path, body);
|
||||
|
||||
if (response == null) {
|
||||
throw new IllegalStateException("No response received from Vault, writing to '%s'".formatted(path));
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a path.
|
||||
* @param path must not be {@literal null}.
|
||||
@@ -185,8 +244,8 @@ public interface VaultOperations {
|
||||
* @throws RestClientException exceptions from
|
||||
* {@link org.springframework.web.client.RestOperations}.
|
||||
*/
|
||||
@Nullable
|
||||
<T> T doWithVault(RestOperationsCallback<T> clientCallback) throws VaultException, RestClientException;
|
||||
<T extends @Nullable Object> T doWithVault(RestOperationsCallback<T> clientCallback)
|
||||
throws VaultException, RestClientException;
|
||||
|
||||
/**
|
||||
* Executes a Vault {@link RestOperationsCallback}. Allows to interact with Vault in
|
||||
@@ -198,7 +257,7 @@ public interface VaultOperations {
|
||||
* @throws RestClientException exceptions from
|
||||
* {@link org.springframework.web.client.RestOperations}.
|
||||
*/
|
||||
@Nullable
|
||||
<T> T doWithSession(RestOperationsCallback<T> sessionCallback) throws VaultException, RestClientException;
|
||||
<T extends @Nullable Object> T doWithSession(RestOperationsCallback<T> sessionCallback)
|
||||
throws VaultException, RestClientException;
|
||||
|
||||
}
|
||||
|
||||
@@ -24,6 +24,8 @@ import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
@@ -87,12 +89,13 @@ public class VaultPkiTemplate implements VaultPkiOperations {
|
||||
return requestCertificate(roleName, "{path}/sign/{roleName}", body, VaultSignCertificateRequestResponse.class);
|
||||
}
|
||||
|
||||
@SuppressWarnings("NullAway")
|
||||
private <T> T requestCertificate(String roleName, String requestPath, Map<String, Object> request,
|
||||
Class<T> responseType) {
|
||||
|
||||
request.putIfAbsent("format", "der");
|
||||
|
||||
T response = this.vaultOperations.doWithSession(restOperations -> {
|
||||
return this.vaultOperations.doWithSession(restOperations -> {
|
||||
|
||||
try {
|
||||
return restOperations.postForObject(requestPath, request, responseType, this.path, roleName);
|
||||
@@ -101,18 +104,15 @@ public class VaultPkiTemplate implements VaultPkiOperations {
|
||||
throw VaultResponses.buildException(e);
|
||||
}
|
||||
});
|
||||
|
||||
Assert.state(response != null, "VaultCertificateResponse must not be null");
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("NullAway")
|
||||
public void revoke(String serialNumber) throws VaultException {
|
||||
|
||||
Assert.hasText(serialNumber, "Serial number must not be null or empty");
|
||||
|
||||
this.vaultOperations.doWithSession(restOperations -> {
|
||||
this.vaultOperations.doWithSession((RestOperationsCallback<@Nullable Void>) restOperations -> {
|
||||
|
||||
try {
|
||||
restOperations.postForObject("{path}/revoke", Collections.singletonMap("serial_number", serialNumber),
|
||||
@@ -127,6 +127,7 @@ public class VaultPkiTemplate implements VaultPkiOperations {
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings({ "NullAway", "DataFlowIssue" })
|
||||
public InputStream getCrl(Encoding encoding) throws VaultException {
|
||||
|
||||
Assert.notNull(encoding, "Encoding must not be null");
|
||||
@@ -150,6 +151,7 @@ public class VaultPkiTemplate implements VaultPkiOperations {
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("NullAway")
|
||||
public VaultIssuerCertificateRequestResponse getIssuerCertificate(String issuer) throws VaultException {
|
||||
|
||||
Assert.hasText(issuer, "Issuer must not be empty");
|
||||
@@ -167,6 +169,7 @@ public class VaultPkiTemplate implements VaultPkiOperations {
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings({ "NullAway", "DataFlowIssue" })
|
||||
public InputStream getIssuerCertificate(String issuer, Encoding encoding) throws VaultException {
|
||||
|
||||
Assert.hasText(issuer, "Issuer must not be empty");
|
||||
|
||||
@@ -96,7 +96,7 @@ public class VaultSysTemplate implements VaultSysOperations {
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public boolean isInitialized() {
|
||||
|
||||
return requireResponse(this.vaultOperations.doWithSession(restOperations -> {
|
||||
@@ -107,7 +107,8 @@ public class VaultSysTemplate implements VaultSysOperations {
|
||||
|
||||
Assert.state(body.getBody() != null, "Initialization response must not be null");
|
||||
|
||||
return body.getBody().get("initialized");
|
||||
Boolean initialized = body.getBody().get("initialized");
|
||||
return initialized != null && initialized.booleanValue();
|
||||
}
|
||||
catch (HttpStatusCodeException e) {
|
||||
throw VaultResponses.buildException(e);
|
||||
@@ -209,16 +210,16 @@ public class VaultSysTemplate implements VaultSysOperations {
|
||||
@SuppressWarnings("unchecked")
|
||||
public List<String> getPolicyNames() throws VaultException {
|
||||
return requireResponse(
|
||||
(List<String>) this.vaultOperations.read("sys/policy").getRequiredData().get("policies"));
|
||||
(List<String>) this.vaultOperations.readRequired("sys/policy").getRequiredData().get("policies"));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public Policy getPolicy(String name) throws VaultException {
|
||||
@SuppressWarnings("NullAway")
|
||||
public @Nullable Policy getPolicy(String name) throws VaultException {
|
||||
|
||||
Assert.hasText(name, "Name must not be null or empty");
|
||||
|
||||
return this.vaultOperations.doWithSession(restOperations -> {
|
||||
return this.vaultOperations.doWithSession((RestOperationsCallback<@Nullable Policy>) restOperations -> {
|
||||
|
||||
ResponseEntity<VaultResponse> response;
|
||||
|
||||
@@ -234,7 +235,13 @@ public class VaultSysTemplate implements VaultSysOperations {
|
||||
throw e;
|
||||
}
|
||||
|
||||
String rules = (String) response.getBody().getRequiredData().get("rules");
|
||||
VaultResponse body = response.getBody();
|
||||
|
||||
if (body == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String rules = (String) body.getRequiredData().get("rules");
|
||||
|
||||
if (ObjectUtils.isEmpty(rules)) {
|
||||
return Policy.empty();
|
||||
@@ -249,6 +256,7 @@ public class VaultSysTemplate implements VaultSysOperations {
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("NullAway")
|
||||
public void createOrUpdatePolicy(String name, Policy policy) throws VaultException {
|
||||
|
||||
Assert.hasText(name, "Name must not be null or empty");
|
||||
@@ -263,7 +271,7 @@ public class VaultSysTemplate implements VaultSysOperations {
|
||||
throw new VaultException("Cannot serialize policy to JSON", e);
|
||||
}
|
||||
|
||||
this.vaultOperations.doWithSession(restOperations -> {
|
||||
this.vaultOperations.doWithSession((RestOperationsCallback<@Nullable Void>) restOperations -> {
|
||||
|
||||
restOperations.exchange("sys/policy/{name}", HttpMethod.PUT,
|
||||
new HttpEntity<>(Collections.singletonMap("rules", rules)), VaultResponse.class, name);
|
||||
@@ -296,12 +304,12 @@ public class VaultSysTemplate implements VaultSysOperations {
|
||||
|
||||
@Override
|
||||
public VaultUnsealStatus doWithRestOperations(RestOperations restOperations) {
|
||||
return restOperations.getForObject("sys/seal-status", VaultUnsealStatusImpl.class);
|
||||
return requireResponse(restOperations.getForObject("sys/seal-status", VaultUnsealStatusImpl.class));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class Seal implements RestOperationsCallback<Void> {
|
||||
private static class Seal implements RestOperationsCallback<@Nullable Void> {
|
||||
|
||||
@Override
|
||||
public Void doWithRestOperations(RestOperations restOperations) {
|
||||
@@ -335,14 +343,14 @@ public class VaultSysTemplate implements VaultSysOperations {
|
||||
|
||||
private static class VaultMountsResponse extends VaultResponseSupport<Map<String, VaultMount>> {
|
||||
|
||||
private Map<String, VaultMount> topLevelMounts = new HashMap<>();
|
||||
private final Map<String, VaultMount> topLevelMounts = new HashMap<>();
|
||||
|
||||
@JsonIgnore
|
||||
public Map<String, VaultMount> getTopLevelMounts() {
|
||||
return this.topLevelMounts;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@SuppressWarnings({ "unchecked", "NullAway", "rawtypes" })
|
||||
@JsonAnySetter
|
||||
public void set(String name, Object value) {
|
||||
|
||||
@@ -386,7 +394,7 @@ public class VaultSysTemplate implements VaultSysOperations {
|
||||
try {
|
||||
ResponseEntity<VaultHealthImpl> healthResponse = restOperations.exchange("sys/health", HttpMethod.GET,
|
||||
emptyNamespace(null), VaultHealthImpl.class);
|
||||
return healthResponse.getBody();
|
||||
return requireResponse(healthResponse.getBody());
|
||||
}
|
||||
catch (RestClientResponseException responseError) {
|
||||
|
||||
|
||||
@@ -43,6 +43,7 @@ import org.springframework.vault.support.VaultResponse;
|
||||
import org.springframework.vault.support.VaultResponseSupport;
|
||||
import org.springframework.vault.support.VaultToken;
|
||||
import org.springframework.web.client.HttpStatusCodeException;
|
||||
import org.springframework.web.client.RestOperations;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
/**
|
||||
@@ -344,7 +345,7 @@ public class VaultTemplate implements InitializingBean, VaultOperations, Disposa
|
||||
}
|
||||
|
||||
@Override
|
||||
public VaultResponse read(String path) {
|
||||
public @Nullable VaultResponse read(String path) {
|
||||
|
||||
Assert.hasText(path, "Path must not be empty");
|
||||
|
||||
@@ -352,8 +353,8 @@ public class VaultTemplate implements InitializingBean, VaultOperations, Disposa
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public <T> VaultResponseSupport<T> read(String path, Class<T> responseType) {
|
||||
@SuppressWarnings("NullAway")
|
||||
public <T> @Nullable VaultResponseSupport<T> read(String path, Class<T> responseType) {
|
||||
|
||||
ParameterizedTypeReference<VaultResponseSupport<T>> ref = VaultResponses.getTypeReference(responseType);
|
||||
|
||||
@@ -378,13 +379,13 @@ public class VaultTemplate implements InitializingBean, VaultOperations, Disposa
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
@Nullable
|
||||
public List<String> list(String path) {
|
||||
public @Nullable List<String> list(String path) {
|
||||
|
||||
Assert.hasText(path, "Path must not be empty");
|
||||
|
||||
VaultListResponse read = doRead("%s?list=true".formatted(path.endsWith("/") ? path : (path + "/")),
|
||||
VaultListResponse.class);
|
||||
|
||||
if (read == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
@@ -393,8 +394,8 @@ public class VaultTemplate implements InitializingBean, VaultOperations, Disposa
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public VaultResponse write(String path, @Nullable Object body) {
|
||||
@SuppressWarnings("NullAway")
|
||||
public @Nullable VaultResponse write(String path, @Nullable Object body) {
|
||||
|
||||
Assert.hasText(path, "Path must not be empty");
|
||||
|
||||
@@ -402,11 +403,12 @@ public class VaultTemplate implements InitializingBean, VaultOperations, Disposa
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("NullAway")
|
||||
public void delete(String path) {
|
||||
|
||||
Assert.hasText(path, "Path must not be empty");
|
||||
|
||||
doWithSession(restOperations -> {
|
||||
doWithSession((RestOperationsCallback<@Nullable Void>) restOperations -> {
|
||||
|
||||
try {
|
||||
restOperations.delete(path);
|
||||
@@ -425,7 +427,7 @@ public class VaultTemplate implements InitializingBean, VaultOperations, Disposa
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T doWithVault(RestOperationsCallback<T> clientCallback) {
|
||||
public <T extends @Nullable Object> T doWithVault(RestOperationsCallback<T> clientCallback) {
|
||||
|
||||
Assert.notNull(clientCallback, "Client callback must not be null");
|
||||
|
||||
@@ -438,7 +440,7 @@ public class VaultTemplate implements InitializingBean, VaultOperations, Disposa
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T doWithSession(RestOperationsCallback<T> sessionCallback) {
|
||||
public <T extends @Nullable Object> T doWithSession(RestOperationsCallback<T> sessionCallback) {
|
||||
|
||||
Assert.notNull(sessionCallback, "Session callback must not be null");
|
||||
|
||||
@@ -450,10 +452,10 @@ public class VaultTemplate implements InitializingBean, VaultOperations, Disposa
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private <T> T doRead(String path, Class<T> responseType) {
|
||||
@SuppressWarnings("NullAway")
|
||||
private <T extends @Nullable Object> T doRead(String path, Class<T> responseType) {
|
||||
|
||||
return doWithSession(restOperations -> {
|
||||
return doWithSession((RestOperations restOperations) -> {
|
||||
|
||||
try {
|
||||
return restOperations.getForObject(path, responseType);
|
||||
|
||||
@@ -101,12 +101,13 @@ public class VaultTokenTemplate implements VaultTokenOperations {
|
||||
writeToken("auth/token/revoke-orphan", vaultToken, VaultTokenResponse.class);
|
||||
}
|
||||
|
||||
@SuppressWarnings("NullAway")
|
||||
private <T extends VaultResponseSupport<?>> T writeAndReturn(String path, @Nullable Object body,
|
||||
Class<T> responseType) {
|
||||
|
||||
Assert.hasText(path, "Path must not be empty");
|
||||
|
||||
T response = this.vaultOperations.doWithSession(restOperations -> {
|
||||
return this.vaultOperations.doWithSession(restOperations -> {
|
||||
try {
|
||||
ResponseEntity<T> exchange = restOperations.exchange(path, HttpMethod.POST,
|
||||
body == null ? HttpEntity.EMPTY : new HttpEntity<>(body), responseType);
|
||||
@@ -117,17 +118,14 @@ public class VaultTokenTemplate implements VaultTokenOperations {
|
||||
throw VaultResponses.buildException(e, path);
|
||||
}
|
||||
});
|
||||
|
||||
Assert.state(response != null, "Response must not be null");
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
@SuppressWarnings("NullAway")
|
||||
private void writeToken(String path, VaultToken token, Class<?> responseType) {
|
||||
|
||||
Assert.hasText(path, "Path must not be empty");
|
||||
|
||||
this.vaultOperations.doWithSession(restOperations -> {
|
||||
this.vaultOperations.doWithSession((RestOperationsCallback<@Nullable Void>) restOperations -> {
|
||||
|
||||
try {
|
||||
restOperations.exchange(path, HttpMethod.POST,
|
||||
|
||||
@@ -22,6 +22,8 @@ import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.vault.VaultException;
|
||||
@@ -62,6 +64,7 @@ public class VaultTransformTemplate implements VaultTransformOperations {
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("NullAway")
|
||||
public String encode(String roleName, String plaintext) {
|
||||
|
||||
Assert.hasText(roleName, "Role name must not be empty");
|
||||
@@ -71,7 +74,7 @@ public class VaultTransformTemplate implements VaultTransformOperations {
|
||||
|
||||
request.put("value", plaintext);
|
||||
|
||||
return (String) this.vaultOperations.write("%s/encode/%s".formatted(this.path, roleName), request)
|
||||
return (String) this.vaultOperations.invoke("%s/encode/%s".formatted(this.path, roleName), request)
|
||||
.getRequiredData()
|
||||
.get("encoded_value");
|
||||
}
|
||||
@@ -88,7 +91,7 @@ public class VaultTransformTemplate implements VaultTransformOperations {
|
||||
|
||||
applyTransformOptions(plaintext.getContext(), request);
|
||||
|
||||
Map<String, Object> data = this.vaultOperations.write("%s/encode/%s".formatted(this.path, roleName), request)
|
||||
Map<String, Object> data = this.vaultOperations.invoke("%s/encode/%s".formatted(this.path, roleName), request)
|
||||
.getRequiredData();
|
||||
|
||||
return toCiphertext(data, plaintext.getContext());
|
||||
@@ -113,10 +116,10 @@ public class VaultTransformTemplate implements VaultTransformOperations {
|
||||
batch.add(vaultRequest);
|
||||
}
|
||||
|
||||
VaultResponse vaultResponse = this.vaultOperations.write("%s/encode/%s".formatted(this.path, roleName),
|
||||
VaultResponse vaultResponse = this.vaultOperations.invoke("%s/encode/%s".formatted(this.path, roleName),
|
||||
Collections.singletonMap("batch_input", batch));
|
||||
|
||||
return toEncodedResults(vaultResponse, batchRequest);
|
||||
return toEncodedResults(requireResponse(vaultResponse), batchRequest);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -131,6 +134,7 @@ public class VaultTransformTemplate implements VaultTransformOperations {
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("NullAway")
|
||||
public String decode(String roleName, String ciphertext, VaultTransformContext transformContext) {
|
||||
|
||||
Assert.hasText(roleName, "Role name must not be empty");
|
||||
@@ -143,7 +147,7 @@ public class VaultTransformTemplate implements VaultTransformOperations {
|
||||
|
||||
applyTransformOptions(transformContext, request);
|
||||
|
||||
return (String) this.vaultOperations.write("%s/decode/%s".formatted(this.path, roleName), request)
|
||||
return (String) this.vaultOperations.invoke("%s/decode/%s".formatted(this.path, roleName), request)
|
||||
.getRequiredData()
|
||||
.get("decoded_value");
|
||||
}
|
||||
@@ -166,10 +170,10 @@ public class VaultTransformTemplate implements VaultTransformOperations {
|
||||
batch.add(vaultRequest);
|
||||
}
|
||||
|
||||
VaultResponse vaultResponse = this.vaultOperations.write("%s/decode/%s".formatted(this.path, roleName),
|
||||
VaultResponse vaultResponse = this.vaultOperations.invoke("%s/decode/%s".formatted(this.path, roleName),
|
||||
Collections.singletonMap("batch_input", batch));
|
||||
|
||||
return toDecryptionResults(vaultResponse, batchRequest);
|
||||
return toDecryptionResults(requireResponse(vaultResponse), batchRequest);
|
||||
}
|
||||
|
||||
private static void applyTransformOptions(VaultTransformContext context, Map<String, String> request) {
|
||||
@@ -253,6 +257,7 @@ public class VaultTransformTemplate implements VaultTransformOperations {
|
||||
return new VaultTransformDecodeResult(TransformPlaintext.empty().with(ciphertext.getContext()));
|
||||
}
|
||||
|
||||
@SuppressWarnings("NullAway")
|
||||
private static TransformCiphertext toCiphertext(Map<String, ?> data, VaultTransformContext context) {
|
||||
|
||||
String ciphertext = (String) data.get("encoded_value");
|
||||
@@ -279,9 +284,16 @@ public class VaultTransformTemplate implements VaultTransformOperations {
|
||||
return context;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@SuppressWarnings({ "NullAway", "unchecked" })
|
||||
private static List<Map<String, String>> getBatchData(VaultResponse vaultResponse) {
|
||||
return (List<Map<String, String>>) vaultResponse.getRequiredData().get("batch_results");
|
||||
}
|
||||
|
||||
private static <T> T requireResponse(@Nullable T response) {
|
||||
|
||||
Assert.state(response != null, "Response must not be null");
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ public class VaultTransitTemplate implements VaultTransitOperations {
|
||||
|
||||
Assert.hasText(keyName, "Key name must not be empty");
|
||||
|
||||
this.vaultOperations.write("%s/keys/%s".formatted(this.path, keyName), null);
|
||||
writeForData("%s/keys/%s".formatted(this.path, keyName), null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -79,15 +79,17 @@ public class VaultTransitTemplate implements VaultTransitOperations {
|
||||
Assert.hasText(keyName, "Key name must not be empty");
|
||||
Assert.notNull(createKeyRequest, "VaultTransitKeyCreationRequest must not be empty");
|
||||
|
||||
this.vaultOperations.write("%s/keys/%s".formatted(this.path, keyName), createKeyRequest);
|
||||
writeForData("%s/keys/%s".formatted(this.path, keyName), createKeyRequest);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
public List<String> getKeys() {
|
||||
|
||||
VaultResponse response = this.vaultOperations.read("%s/keys?list=true".formatted(this.path));
|
||||
|
||||
return response == null ? Collections.emptyList() : (List) response.getRequiredData().get("keys");
|
||||
return response == null ? Collections.emptyList()
|
||||
: (List) response.getRequiredData().getOrDefault("keys", Collections.emptyList());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -96,7 +98,7 @@ public class VaultTransitTemplate implements VaultTransitOperations {
|
||||
Assert.hasText(keyName, "Key name must not be empty");
|
||||
Assert.notNull(keyConfiguration, "VaultKeyConfiguration must not be empty");
|
||||
|
||||
this.vaultOperations.write("%s/keys/%s/config".formatted(this.path, keyName), keyConfiguration);
|
||||
writeForData("%s/keys/%s/config".formatted(this.path, keyName), keyConfiguration);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -141,10 +143,11 @@ public class VaultTransitTemplate implements VaultTransitOperations {
|
||||
|
||||
Assert.hasText(keyName, "Key name must not be empty");
|
||||
|
||||
this.vaultOperations.write("%s/keys/%s/rotate".formatted(this.path, keyName), null);
|
||||
writeForData("%s/keys/%s/rotate".formatted(this.path, keyName), null);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("NullAway")
|
||||
public String encrypt(String keyName, String plaintext) {
|
||||
|
||||
Assert.hasText(keyName, "Key name must not be empty");
|
||||
@@ -154,9 +157,7 @@ public class VaultTransitTemplate implements VaultTransitOperations {
|
||||
|
||||
request.put("plaintext", Base64.getEncoder().encodeToString(plaintext.getBytes()));
|
||||
|
||||
return (String) this.vaultOperations.write("%s/encrypt/%s".formatted(this.path, keyName), request)
|
||||
.getRequiredData()
|
||||
.get("ciphertext");
|
||||
return (String) writeForData("%s/encrypt/%s".formatted(this.path, keyName), request).get("ciphertext");
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -171,6 +172,7 @@ public class VaultTransitTemplate implements VaultTransitOperations {
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("NullAway")
|
||||
public String encrypt(String keyName, byte[] plaintext, VaultTransitContext transitContext) {
|
||||
|
||||
Assert.hasText(keyName, "Key name must not be empty");
|
||||
@@ -183,9 +185,7 @@ public class VaultTransitTemplate implements VaultTransitOperations {
|
||||
|
||||
applyTransitOptions(transitContext, request);
|
||||
|
||||
return (String) this.vaultOperations.write("%s/encrypt/%s".formatted(this.path, keyName), request)
|
||||
.getRequiredData()
|
||||
.get("ciphertext");
|
||||
return (String) writeForData("%s/encrypt/%s".formatted(this.path, keyName), request).get("ciphertext");
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -201,15 +201,12 @@ public class VaultTransitTemplate implements VaultTransitOperations {
|
||||
Map<String, String> vaultRequest = new LinkedHashMap<>(2);
|
||||
|
||||
vaultRequest.put("plaintext", Base64.getEncoder().encodeToString(request.getPlaintext()));
|
||||
|
||||
if (request.getContext() != null) {
|
||||
applyTransitOptions(request.getContext(), vaultRequest);
|
||||
}
|
||||
applyTransitOptions(request.getContext(), vaultRequest);
|
||||
|
||||
batch.add(vaultRequest);
|
||||
}
|
||||
|
||||
VaultResponse vaultResponse = this.vaultOperations.write("%s/encrypt/%s".formatted(this.path, keyName),
|
||||
VaultResponse vaultResponse = writeForResponse("%s/encrypt/%s".formatted(this.path, keyName),
|
||||
Collections.singletonMap("batch_input", batch));
|
||||
|
||||
return toBatchResults(vaultResponse, batchRequest, Plaintext::getContext);
|
||||
@@ -225,8 +222,7 @@ public class VaultTransitTemplate implements VaultTransitOperations {
|
||||
|
||||
request.put("ciphertext", ciphertext);
|
||||
|
||||
String plaintext = (String) this.vaultOperations.write("%s/decrypt/%s".formatted(this.path, keyName), request)
|
||||
.getRequiredData()
|
||||
String plaintext = (String) writeForData("%s/decrypt/%s".formatted(this.path, keyName), request)
|
||||
.get("plaintext");
|
||||
|
||||
return new String(Base64.getDecoder().decode(plaintext));
|
||||
@@ -256,8 +252,7 @@ public class VaultTransitTemplate implements VaultTransitOperations {
|
||||
|
||||
applyTransitOptions(transitContext, request);
|
||||
|
||||
String plaintext = (String) this.vaultOperations.write("%s/decrypt/%s".formatted(this.path, keyName), request)
|
||||
.getRequiredData()
|
||||
String plaintext = (String) writeForData("%s/decrypt/%s".formatted(this.path, keyName), request)
|
||||
.get("plaintext");
|
||||
|
||||
return Base64.getDecoder().decode(plaintext);
|
||||
@@ -276,21 +271,19 @@ public class VaultTransitTemplate implements VaultTransitOperations {
|
||||
Map<String, String> vaultRequest = new LinkedHashMap<>(2);
|
||||
|
||||
vaultRequest.put("ciphertext", request.getCiphertext());
|
||||
|
||||
if (request.getContext() != null) {
|
||||
applyTransitOptions(request.getContext(), vaultRequest);
|
||||
}
|
||||
applyTransitOptions(request.getContext(), vaultRequest);
|
||||
|
||||
batch.add(vaultRequest);
|
||||
}
|
||||
|
||||
VaultResponse vaultResponse = this.vaultOperations.write("%s/decrypt/%s".formatted(this.path, keyName),
|
||||
VaultResponse vaultResponse = writeForResponse("%s/decrypt/%s".formatted(this.path, keyName),
|
||||
Collections.singletonMap("batch_input", batch));
|
||||
|
||||
return toDecryptionResults(vaultResponse, batchRequest);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("NullAway")
|
||||
public String rewrap(String keyName, String ciphertext) {
|
||||
|
||||
Assert.hasText(keyName, "Key name must not be empty");
|
||||
@@ -299,12 +292,11 @@ public class VaultTransitTemplate implements VaultTransitOperations {
|
||||
Map<String, String> request = new LinkedHashMap<>();
|
||||
request.put("ciphertext", ciphertext);
|
||||
|
||||
return (String) this.vaultOperations.write("%s/rewrap/%s".formatted(this.path, keyName), request)
|
||||
.getRequiredData()
|
||||
.get("ciphertext");
|
||||
return (String) writeForData("%s/rewrap/%s".formatted(this.path, keyName), request).get("ciphertext");
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("NullAway")
|
||||
public String rewrap(String keyName, String ciphertext, VaultTransitContext transitContext) {
|
||||
|
||||
Assert.hasText(keyName, "Key name must not be empty");
|
||||
@@ -313,9 +305,7 @@ public class VaultTransitTemplate implements VaultTransitOperations {
|
||||
|
||||
Map<String, String> request = createRewrapRequest(toCiphertext(ciphertext, transitContext));
|
||||
|
||||
return (String) this.vaultOperations.write("%s/rewrap/%s".formatted(this.path, keyName), request)
|
||||
.getRequiredData()
|
||||
.get("ciphertext");
|
||||
return (String) writeForData("%s/rewrap/%s".formatted(this.path, keyName), request).get("ciphertext");
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -332,7 +322,7 @@ public class VaultTransitTemplate implements VaultTransitOperations {
|
||||
batch.add(vaultRequest);
|
||||
}
|
||||
|
||||
VaultResponse vaultResponse = this.vaultOperations.write("%s/rewrap/%s".formatted(this.path, keyName),
|
||||
VaultResponse vaultResponse = writeForResponse("%s/rewrap/%s".formatted(this.path, keyName),
|
||||
Collections.singletonMap("batch_input", batch));
|
||||
|
||||
return toBatchResults(vaultResponse, batchRequest, Ciphertext::getContext);
|
||||
@@ -350,6 +340,7 @@ public class VaultTransitTemplate implements VaultTransitOperations {
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("NullAway")
|
||||
public Hmac getHmac(String keyName, VaultHmacRequest hmacRequest) {
|
||||
|
||||
Assert.hasText(keyName, "Key name must not be empty");
|
||||
@@ -357,9 +348,7 @@ public class VaultTransitTemplate implements VaultTransitOperations {
|
||||
|
||||
Map<String, Object> request = toRequestBody(hmacRequest);
|
||||
|
||||
String hmac = (String) this.vaultOperations.write("%s/hmac/%s".formatted(this.path, keyName), request)
|
||||
.getRequiredData()
|
||||
.get("hmac");
|
||||
String hmac = (String) writeForData("%s/hmac/%s".formatted(this.path, keyName), request).get("hmac");
|
||||
|
||||
return Hmac.of(hmac);
|
||||
}
|
||||
@@ -390,6 +379,7 @@ public class VaultTransitTemplate implements VaultTransitOperations {
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("NullAway")
|
||||
public Signature sign(String keyName, VaultSignRequest signRequest) {
|
||||
|
||||
Assert.hasText(keyName, "Key name must not be empty");
|
||||
@@ -397,9 +387,7 @@ public class VaultTransitTemplate implements VaultTransitOperations {
|
||||
|
||||
Map<String, Object> request = toRequestBody(signRequest);
|
||||
|
||||
String signature = (String) this.vaultOperations.write("%s/sign/%s".formatted(this.path, keyName), request)
|
||||
.getRequiredData()
|
||||
.get("signature");
|
||||
String signature = (String) writeForData("%s/sign/%s".formatted(this.path, keyName), request).get("signature");
|
||||
|
||||
return Signature.of(signature);
|
||||
}
|
||||
@@ -438,8 +426,7 @@ public class VaultTransitTemplate implements VaultTransitOperations {
|
||||
|
||||
Map<String, Object> request = toRequestBody(verificationRequest);
|
||||
|
||||
Map<String, Object> response = this.vaultOperations.write("%s/verify/%s".formatted(this.path, keyName), request)
|
||||
.getRequiredData();
|
||||
Map<String, Object> response = writeForData("%s/verify/%s".formatted(this.path, keyName), request);
|
||||
|
||||
if (response.containsKey("valid") && Boolean.valueOf("" + response.get("valid"))) {
|
||||
return SignatureValidation.valid();
|
||||
@@ -448,6 +435,21 @@ public class VaultTransitTemplate implements VaultTransitOperations {
|
||||
return SignatureValidation.invalid();
|
||||
}
|
||||
|
||||
private Map<String, Object> writeForData(String path, @Nullable Object request) {
|
||||
return writeForResponse(path, request).getRequiredData();
|
||||
}
|
||||
|
||||
private VaultResponse writeForResponse(String path, @Nullable Object request) {
|
||||
|
||||
VaultResponse response = this.vaultOperations.write(path, request);
|
||||
|
||||
if (response == null) {
|
||||
throw new IllegalStateException("Write to '%s' did not return a response".formatted(path));
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
static Map<String, Object> toRequestBody(VaultSignatureVerificationRequest verificationRequest) {
|
||||
|
||||
Map<String, Object> request = new LinkedHashMap<>(5);
|
||||
@@ -483,6 +485,7 @@ public class VaultTransitTemplate implements VaultTransitOperations {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("NullAway")
|
||||
static <T> List<VaultEncryptionResult> toBatchResults(VaultResponse vaultResponse, List<T> batchRequests,
|
||||
Function<T, VaultTransitContext> contextExtractor) {
|
||||
|
||||
@@ -565,11 +568,12 @@ public class VaultTransitTemplate implements VaultTransitOperations {
|
||||
return context != null ? Ciphertext.of(ciphertext).with(context) : Ciphertext.of(ciphertext);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@SuppressWarnings({ "NullAway", "unchecked" })
|
||||
static List<Map<String, String>> getBatchData(VaultResponse vaultResponse) {
|
||||
return (List<Map<String, String>>) vaultResponse.getRequiredData().get("batch_results");
|
||||
}
|
||||
|
||||
@SuppressWarnings("NullAway")
|
||||
static class VaultTransitKeyImpl implements VaultTransitKey {
|
||||
|
||||
@Nullable
|
||||
@@ -625,7 +629,6 @@ public class VaultTransitTemplate implements VaultTransitOperations {
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
@@ -827,10 +830,10 @@ public class VaultTransitTemplate implements VaultTransitOperations {
|
||||
|
||||
private Map<String, String> keys = Collections.emptyMap();
|
||||
|
||||
@Nullable
|
||||
private String name;
|
||||
private final String name;
|
||||
|
||||
public RawTransitKeyImpl() {
|
||||
public RawTransitKeyImpl(@JsonProperty("name") String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -839,7 +842,6 @@ public class VaultTransitTemplate implements VaultTransitOperations {
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
@@ -848,10 +850,6 @@ public class VaultTransitTemplate implements VaultTransitOperations {
|
||||
this.keys = keys;
|
||||
}
|
||||
|
||||
public void setName(@Nullable String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o)
|
||||
|
||||
@@ -65,7 +65,7 @@ public class VaultVersionedKeyValueTemplate extends VaultKeyValue2Accessor imple
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
public Versioned<Map<String, Object>> get(String path, Version version) {
|
||||
|
||||
Assert.hasText(path, "Path must not be empty");
|
||||
@@ -86,29 +86,31 @@ public class VaultVersionedKeyValueTemplate extends VaultKeyValue2Accessor imple
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@SuppressWarnings("NullAway")
|
||||
private <T> Versioned<T> doRead(String path, Version version, Class<T> responseType) {
|
||||
|
||||
String secretPath = version.isVersioned()
|
||||
? "%s?version=%d".formatted(createDataPath(path), version.getVersion()) : createDataPath(path);
|
||||
|
||||
VersionedResponse response = this.vaultOperations.doWithSession(restOperations -> {
|
||||
VersionedResponse response = this.vaultOperations
|
||||
.doWithSession((RestOperationsCallback<@Nullable VersionedResponse>) restOperations -> {
|
||||
|
||||
try {
|
||||
return restOperations.exchange(secretPath, HttpMethod.GET, null, VersionedResponse.class).getBody();
|
||||
}
|
||||
catch (HttpStatusCodeException e) {
|
||||
try {
|
||||
return restOperations.exchange(secretPath, HttpMethod.GET, null, VersionedResponse.class).getBody();
|
||||
}
|
||||
catch (HttpStatusCodeException e) {
|
||||
|
||||
if (HttpStatusUtil.isNotFound(e.getStatusCode())) {
|
||||
if (e.getResponseBodyAsString().contains("deletion_time")) {
|
||||
return VaultResponses.unwrap(e.getResponseBodyAsString(), VersionedResponse.class);
|
||||
if (HttpStatusUtil.isNotFound(e.getStatusCode())) {
|
||||
if (e.getResponseBodyAsString().contains("deletion_time")) {
|
||||
return VaultResponses.unwrap(e.getResponseBodyAsString(), VersionedResponse.class);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
return null;
|
||||
throw VaultResponses.buildException(e, path);
|
||||
}
|
||||
|
||||
throw VaultResponses.buildException(e, path);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
if (response == null) {
|
||||
return null;
|
||||
@@ -132,7 +134,7 @@ public class VaultVersionedKeyValueTemplate extends VaultKeyValue2Accessor imple
|
||||
|
||||
if (body instanceof Versioned<?> versioned) {
|
||||
|
||||
data.put("data", versioned.getData());
|
||||
data.put("data", versioned.getRequiredData());
|
||||
data.put("options", requestOptions);
|
||||
|
||||
requestOptions.put("cas", versioned.getVersion().getVersion());
|
||||
|
||||
@@ -83,7 +83,7 @@ public class VaultWrappingTemplate implements VaultWrappingOperations {
|
||||
return null;
|
||||
}
|
||||
|
||||
return getWrappedMetadata(response.getData(), token);
|
||||
return getWrappedMetadata(response.getRequiredData(), token);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -107,11 +107,11 @@ public class VaultWrappingTemplate implements VaultWrappingOperations {
|
||||
});
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private <T extends VaultResponseSupport<?>> T doUnwrap(VaultToken token,
|
||||
BiFunction<RestOperations, HttpEntity<?>, T> requestFunction) {
|
||||
@SuppressWarnings("NullAway")
|
||||
private <T extends VaultResponseSupport<?>> @Nullable T doUnwrap(VaultToken token,
|
||||
BiFunction<RestOperations, HttpEntity<?>, @Nullable T> requestFunction) {
|
||||
|
||||
return this.vaultOperations.doWithVault(restOperations -> {
|
||||
return this.vaultOperations.doWithVault((RestOperationsCallback<@Nullable T>) restOperations -> {
|
||||
|
||||
try {
|
||||
return requestFunction.apply(restOperations, new HttpEntity<>(VaultHttpHeaders.from(token)));
|
||||
@@ -133,11 +133,12 @@ public class VaultWrappingTemplate implements VaultWrappingOperations {
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("NullAway")
|
||||
public WrappedMetadata rewrap(VaultToken token) {
|
||||
|
||||
Assert.notNull(token, "token VaultToken not be null");
|
||||
|
||||
VaultResponse response = this.vaultOperations.write("sys/wrapping/rewrap",
|
||||
VaultResponse response = this.vaultOperations.invoke("sys/wrapping/rewrap",
|
||||
Collections.singletonMap("token", token.getToken()));
|
||||
|
||||
Map<String, String> wrapInfo = response.getWrapInfo();
|
||||
@@ -146,6 +147,7 @@ public class VaultWrappingTemplate implements VaultWrappingOperations {
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("NullAway")
|
||||
public WrappedMetadata wrap(Object body, Duration duration) {
|
||||
|
||||
Assert.notNull(body, "Body must not be null");
|
||||
@@ -175,15 +177,17 @@ public class VaultWrappingTemplate implements VaultWrappingOperations {
|
||||
return new WrappedMetadata(token, ttl, Instant.from(creation_time), path);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static TemporalAccessor getDate(Map<String, ?> responseMetadata, String key) {
|
||||
|
||||
String date = (String) ((Map) responseMetadata).getOrDefault(key, "");
|
||||
|
||||
return StringUtils.hasText(date) ? DateTimeFormatter.ISO_OFFSET_DATE_TIME.parse(date) : null;
|
||||
if (StringUtils.hasText(date)) {
|
||||
return DateTimeFormatter.ISO_OFFSET_DATE_TIME.parse(date);
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("Cannot obtain date");
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static Duration getTtl(Map<String, ?> wrapInfo) {
|
||||
|
||||
Object creationTtl = wrapInfo.get("ttl");
|
||||
@@ -196,13 +200,12 @@ public class VaultWrappingTemplate implements VaultWrappingOperations {
|
||||
creationTtl = Integer.parseInt((String) creationTtl);
|
||||
}
|
||||
|
||||
Duration ttl = null;
|
||||
|
||||
if (creationTtl instanceof Integer) {
|
||||
ttl = Duration.ofSeconds((Integer) creationTtl);
|
||||
return Duration.ofSeconds((Integer) creationTtl);
|
||||
|
||||
}
|
||||
return ttl;
|
||||
|
||||
throw new IllegalArgumentException("Cannot obtain TTL");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -199,7 +199,7 @@ public class LeaseAwareVaultPropertySource extends EnumerablePropertySource<Vaul
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getProperty(String name) {
|
||||
public @Nullable Object getProperty(String name) {
|
||||
return this.properties.get(name);
|
||||
}
|
||||
|
||||
@@ -207,7 +207,7 @@ public class LeaseAwareVaultPropertySource extends EnumerablePropertySource<Vaul
|
||||
public String[] getPropertyNames() {
|
||||
|
||||
Set<String> strings = this.properties.keySet();
|
||||
return strings.toArray(new String[strings.size()]);
|
||||
return strings.toArray(new String[0]);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
@@ -185,7 +185,7 @@ public class VaultPropertySource extends EnumerablePropertySource<VaultOperation
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getProperty(String name) {
|
||||
public @Nullable Object getProperty(String name) {
|
||||
return this.properties.get(name);
|
||||
}
|
||||
|
||||
@@ -193,7 +193,7 @@ public class VaultPropertySource extends EnumerablePropertySource<VaultOperation
|
||||
public String[] getPropertyNames() {
|
||||
|
||||
Set<String> strings = this.properties.keySet();
|
||||
return strings.toArray(new String[strings.size()]);
|
||||
return strings.toArray(new String[0]);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
@@ -206,8 +206,7 @@ public class VaultPropertySource extends EnumerablePropertySource<VaultOperation
|
||||
* @return the resulting {@link Map} or {@literal null} if properties were not found.
|
||||
* @throws VaultException on problems retrieving properties
|
||||
*/
|
||||
@Nullable
|
||||
protected Map<String, Object> doGetProperties(String path) throws VaultException {
|
||||
protected @Nullable Map<String, Object> doGetProperties(String path) throws VaultException {
|
||||
|
||||
VaultResponse vaultResponse;
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ public enum LeaseEndpoints {
|
||||
public void revoke(Lease lease, RestOperations operations) {
|
||||
|
||||
operations.exchange("sys/revoke", HttpMethod.PUT, LeaseEndpoints.getLeaseRevocationBody(lease), Map.class,
|
||||
lease.getLeaseId());
|
||||
lease.getRequiredLeaseId());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -72,7 +72,7 @@ public enum LeaseEndpoints {
|
||||
public void revoke(Lease lease, RestOperations operations) {
|
||||
|
||||
operations.exchange("sys/leases/revoke", HttpMethod.PUT, LeaseEndpoints.getLeaseRevocationBody(lease),
|
||||
Map.class, lease.getLeaseId());
|
||||
Map.class, lease.getRequiredLeaseId());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -97,7 +97,7 @@ public enum LeaseEndpoints {
|
||||
@Override
|
||||
public void revoke(Lease lease, RestOperations operations) {
|
||||
|
||||
String endpoint = "sys/leases/revoke-prefix/" + lease.getLeaseId();
|
||||
String endpoint = "sys/leases/revoke-prefix/" + lease.getRequiredLeaseId();
|
||||
operations.put(endpoint, null);
|
||||
}
|
||||
|
||||
@@ -129,6 +129,7 @@ public enum LeaseEndpoints {
|
||||
*/
|
||||
abstract Lease renew(Lease lease, RestOperations operations);
|
||||
|
||||
@SuppressWarnings("NullAway")
|
||||
private static Lease toLease(Map<String, Object> body) {
|
||||
|
||||
String leaseId = (String) body.get("lease_id");
|
||||
@@ -141,7 +142,7 @@ public enum LeaseEndpoints {
|
||||
private static HttpEntity<Object> getLeaseRenewalBody(Lease lease) {
|
||||
|
||||
Map<String, String> leaseRenewalData = new HashMap<>();
|
||||
leaseRenewalData.put("lease_id", lease.getLeaseId());
|
||||
leaseRenewalData.put("lease_id", lease.getRequiredLeaseId());
|
||||
leaseRenewalData.put("increment", Long.toString(lease.getLeaseDuration().getSeconds()));
|
||||
|
||||
return new HttpEntity<>(leaseRenewalData);
|
||||
@@ -150,7 +151,7 @@ public enum LeaseEndpoints {
|
||||
private static HttpEntity<Object> getLeaseRevocationBody(Lease lease) {
|
||||
|
||||
Map<String, String> leaseRenewalData = new HashMap<>();
|
||||
leaseRenewalData.put("lease_id", lease.getLeaseId());
|
||||
leaseRenewalData.put("lease_id", lease.getRequiredLeaseId());
|
||||
|
||||
return new HttpEntity<>(leaseRenewalData);
|
||||
}
|
||||
|
||||
@@ -61,6 +61,7 @@ import org.springframework.vault.authentication.event.AuthenticationListener;
|
||||
import org.springframework.vault.authentication.event.LoginTokenExpiredEvent;
|
||||
import org.springframework.vault.authentication.event.LoginTokenRenewalFailedEvent;
|
||||
import org.springframework.vault.client.VaultResponses;
|
||||
import org.springframework.vault.core.RestOperationsCallback;
|
||||
import org.springframework.vault.core.VaultOperations;
|
||||
import org.springframework.vault.core.lease.domain.Lease;
|
||||
import org.springframework.vault.core.lease.domain.RequestedSecret;
|
||||
@@ -560,6 +561,8 @@ public class SecretLeaseContainer extends SecretLeaseEventPublisher
|
||||
|
||||
void restartSecrets() {
|
||||
|
||||
Assert.state(this.taskScheduler != null, "TaskScheduler is not set");
|
||||
|
||||
int status = this.status;
|
||||
if (status == STATUS_STARTED) {
|
||||
|
||||
@@ -865,14 +868,14 @@ public class SecretLeaseContainer extends SecretLeaseEventPublisher
|
||||
* @param requestedSecret must not be {@literal null}.
|
||||
* @param lease must not be {@literal null}.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@SuppressWarnings("NullAway")
|
||||
protected void doRevokeLease(RequestedSecret requestedSecret, Lease lease) {
|
||||
|
||||
try {
|
||||
|
||||
onBeforeLeaseRevocation(requestedSecret, lease);
|
||||
|
||||
this.operations.doWithSession(restOperations -> {
|
||||
this.operations.doWithSession((RestOperationsCallback<@Nullable Void>) restOperations -> {
|
||||
this.leaseEndpoints.revoke(lease, restOperations);
|
||||
return null;
|
||||
});
|
||||
@@ -1112,6 +1115,8 @@ public class SecretLeaseContainer extends SecretLeaseEventPublisher
|
||||
*/
|
||||
private void restartSecrets() {
|
||||
|
||||
Assert.state(taskScheduler != null, "TaskScheduler is not set");
|
||||
|
||||
if (!isRunning()) {
|
||||
logger.debug("Ignore token event as the container is not running");
|
||||
}
|
||||
|
||||
@@ -94,13 +94,27 @@ public class Lease {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the lease Id
|
||||
* @return the lease Id.
|
||||
*/
|
||||
@Nullable
|
||||
public String getLeaseId() {
|
||||
public @Nullable String getLeaseId() {
|
||||
return this.leaseId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the required lease Id.
|
||||
* @since 4.0
|
||||
*/
|
||||
public String getRequiredLeaseId() {
|
||||
|
||||
String leaseId = getLeaseId();
|
||||
|
||||
if (leaseId == null) {
|
||||
throw new IllegalStateException("No leaseId available.");
|
||||
}
|
||||
|
||||
return leaseId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the lease duration in seconds.
|
||||
*/
|
||||
|
||||
@@ -48,6 +48,7 @@ public class SecretLeaseRotatedEvent extends SecretLeaseCreatedEvent {
|
||||
return this.previousLease;
|
||||
}
|
||||
|
||||
@SuppressWarnings("NullAway")
|
||||
public Lease getCurrentLease() {
|
||||
return getLease();
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ public class KeyValueDelegate {
|
||||
|
||||
MountInfo mountInfo = this.mountInfo.get(path);
|
||||
|
||||
if (!mountInfo.isKeyValue(KeyValueBackend.versioned())) {
|
||||
if (mountInfo == null || !mountInfo.isKeyValue(KeyValueBackend.versioned())) {
|
||||
return this.operations.read(path);
|
||||
}
|
||||
|
||||
@@ -111,7 +111,7 @@ public class KeyValueDelegate {
|
||||
response.setData(nested);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@SuppressWarnings({ "unchecked", "NullAway" })
|
||||
private MountInfo doGetMountInfo(String path) {
|
||||
|
||||
VaultResponse response = this.operations.read("sys/internal/ui/mounts/%s".formatted(path));
|
||||
|
||||
@@ -82,7 +82,7 @@ public class DefaultVaultTypeMapper extends DefaultTypeMapper<Map<String, Object
|
||||
}
|
||||
|
||||
private DefaultVaultTypeMapper(@Nullable String typeKey, TypeAliasAccessor<Map<String, Object>> accessor,
|
||||
MappingContext<? extends PersistentEntity<?, ?>, ?> mappingContext,
|
||||
@Nullable MappingContext<? extends PersistentEntity<?, ?>, ?> mappingContext,
|
||||
List<? extends TypeInformationMapper> mappers) {
|
||||
|
||||
super(accessor, mappingContext, mappers);
|
||||
|
||||
@@ -38,6 +38,7 @@ import org.springframework.data.mapping.model.ParameterValueProvider;
|
||||
import org.springframework.data.mapping.model.PersistentEntityParameterValueProvider;
|
||||
import org.springframework.data.mapping.model.PropertyValueProvider;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.lang.Contract;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
@@ -105,7 +106,11 @@ public class MappingVaultConverter extends AbstractVaultConverter {
|
||||
Class<? extends S> rawType = typeToUse.getType();
|
||||
|
||||
if (this.conversions.hasCustomReadTarget(source.getClass(), rawType)) {
|
||||
return this.conversionService.convert(source, rawType);
|
||||
|
||||
S result = this.conversionService.convert(source, rawType);
|
||||
|
||||
Assert.state(result != null, "Conversion result must not be null");
|
||||
return result;
|
||||
}
|
||||
|
||||
if (SecretDocument.class.isAssignableFrom(rawType)) {
|
||||
@@ -124,22 +129,26 @@ public class MappingVaultConverter extends AbstractVaultConverter {
|
||||
return (S) source;
|
||||
}
|
||||
|
||||
if (secretDocument == null) {
|
||||
throw new MappingException("Unsupported source type: " + source.getClass().getName());
|
||||
}
|
||||
|
||||
return read((VaultPersistentEntity<S>) this.mappingContext.getRequiredPersistentEntity(typeToUse),
|
||||
secretDocument);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@SuppressWarnings("unchecked")
|
||||
private SecretDocument getSecretDocument(Object source) {
|
||||
private @Nullable SecretDocument getSecretDocument(Object source) {
|
||||
|
||||
SecretDocument secretDocument = null;
|
||||
if (source instanceof Map) {
|
||||
secretDocument = new SecretDocument((Map) source);
|
||||
return new SecretDocument((Map) source);
|
||||
}
|
||||
else if (source instanceof SecretDocument) {
|
||||
secretDocument = (SecretDocument) source;
|
||||
|
||||
if (source instanceof SecretDocument) {
|
||||
return (SecretDocument) source;
|
||||
}
|
||||
return secretDocument;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private ParameterValueProvider<VaultPersistentProperty> getParameterProvider(VaultPersistentEntity<?> entity,
|
||||
@@ -152,9 +161,8 @@ public class MappingVaultConverter extends AbstractVaultConverter {
|
||||
|
||||
return new ParameterValueProvider<VaultPersistentProperty>() {
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public <T> T getParameterValue(Parameter<T, VaultPersistentProperty> parameter) {
|
||||
public <T> @Nullable T getParameterValue(Parameter<T, VaultPersistentProperty> parameter) {
|
||||
Object value = parameterProvider.getParameterValue(parameter);
|
||||
return value != null ? readValue(value, parameter.getType()) : null;
|
||||
}
|
||||
@@ -246,7 +254,7 @@ public class MappingVaultConverter extends AbstractVaultConverter {
|
||||
* @return the converted {@link Collection} or array, will never be {@literal null}.
|
||||
*/
|
||||
@Nullable
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
@SuppressWarnings({ "rawtypes" })
|
||||
private Object readCollectionOrArray(TypeInformation<?> targetType, List sourceValue) {
|
||||
|
||||
Assert.notNull(targetType, "Target type must not be null");
|
||||
@@ -258,7 +266,7 @@ public class MappingVaultConverter extends AbstractVaultConverter {
|
||||
Class<?> rawComponentType = componentType.getType();
|
||||
|
||||
collectionType = Collection.class.isAssignableFrom(collectionType) ? collectionType : List.class;
|
||||
Collection<Object> items = targetType.getType().isArray() ? new ArrayList<>(sourceValue.size())
|
||||
Collection<@Nullable Object> items = targetType.getType().isArray() ? new ArrayList<>(sourceValue.size())
|
||||
: CollectionFactory.createCollection(collectionType, rawComponentType, sourceValue.size());
|
||||
|
||||
if (sourceValue.isEmpty()) {
|
||||
@@ -289,7 +297,7 @@ public class MappingVaultConverter extends AbstractVaultConverter {
|
||||
* @param sourceMap must not be {@literal null}
|
||||
* @return the converted {@link Map}.
|
||||
*/
|
||||
protected Map<Object, Object> readMap(TypeInformation<?> type, Map<String, Object> sourceMap) {
|
||||
protected Map<@Nullable Object, @Nullable Object> readMap(TypeInformation<?> type, Map<String, Object> sourceMap) {
|
||||
|
||||
Assert.notNull(sourceMap, "Source map must not be null");
|
||||
|
||||
@@ -301,7 +309,8 @@ public class MappingVaultConverter extends AbstractVaultConverter {
|
||||
Class<?> rawKeyType = keyType != null ? keyType.getType() : null;
|
||||
Class<?> rawValueType = valueType != null ? valueType.getType() : null;
|
||||
|
||||
Map<Object, Object> map = CollectionFactory.createMap(mapType, rawKeyType, sourceMap.keySet().size());
|
||||
Map<@Nullable Object, @Nullable Object> map = CollectionFactory.createMap(mapType, rawKeyType,
|
||||
sourceMap.keySet().size());
|
||||
|
||||
for (Entry<String, Object> entry : sourceMap.entrySet()) {
|
||||
|
||||
@@ -386,6 +395,8 @@ public class MappingVaultConverter extends AbstractVaultConverter {
|
||||
|
||||
SecretDocument result = this.conversionService.convert(obj, SecretDocument.class);
|
||||
|
||||
Assert.state(result != null, "Custom conversion must not return null");
|
||||
|
||||
if (result.getId() != null) {
|
||||
sink.setId(result.getId());
|
||||
}
|
||||
@@ -511,7 +522,7 @@ public class MappingVaultConverter extends AbstractVaultConverter {
|
||||
* @param sink the {@link List} to write to.
|
||||
* @return the converted {@link List}.
|
||||
*/
|
||||
private List<Object> writeCollectionInternal(Collection<?> source, @Nullable TypeInformation<?> type,
|
||||
private List<Object> writeCollectionInternal(Collection<@Nullable ?> source, @Nullable TypeInformation<?> type,
|
||||
List<Object> sink) {
|
||||
|
||||
TypeInformation<?> componentType = null;
|
||||
@@ -609,7 +620,7 @@ public class MappingVaultConverter extends AbstractVaultConverter {
|
||||
protected void addCustomTypeKeyIfNecessary(@Nullable TypeInformation<?> type, Object value,
|
||||
SecretDocumentAccessor accessor) {
|
||||
|
||||
Class<?> reference = type != null ? type.getActualType().getType() : Object.class;
|
||||
Class<?> reference = type != null ? type.getRequiredActualType().getType() : Object.class;
|
||||
Class<?> valueType = ClassUtils.getUserClass(value.getClass());
|
||||
|
||||
boolean notTheSameClass = !valueType.equals(reference);
|
||||
@@ -626,8 +637,9 @@ public class MappingVaultConverter extends AbstractVaultConverter {
|
||||
* @param targetType
|
||||
* @return the converted value. Can be {@literal null}.
|
||||
*/
|
||||
@Nullable
|
||||
private Object getPotentiallyConvertedSimpleWrite(@Nullable Object value, Class<?> targetType) {
|
||||
|
||||
@Contract("null, _ -> null; !null, _ -> !null")
|
||||
private @Nullable Object getPotentiallyConvertedSimpleWrite(@Nullable Object value, Class<?> targetType) {
|
||||
|
||||
if (value == null) {
|
||||
return null;
|
||||
|
||||
@@ -100,16 +100,14 @@ public class SecretDocument {
|
||||
* @param vaultResponse must not be {@literal null}.
|
||||
* @return the {@link SecretDocument}.
|
||||
*/
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
public static SecretDocument from(@Nullable String id, VaultResponse vaultResponse) {
|
||||
return new SecretDocument(id, vaultResponse.getData());
|
||||
return new SecretDocument(id, vaultResponse.getRequiredData());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the identifier or {@literal null} if the identifier is not set.
|
||||
*/
|
||||
@Nullable
|
||||
public String getId() {
|
||||
public @Nullable String getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ import org.springframework.vault.repository.mapping.VaultPersistentProperty;
|
||||
* @author Mark Paluch
|
||||
* @since 2.0
|
||||
*/
|
||||
class SecretDocumentAccessor {
|
||||
public class SecretDocumentAccessor {
|
||||
|
||||
private final SecretDocument document;
|
||||
|
||||
@@ -204,8 +204,7 @@ class SecretDocumentAccessor {
|
||||
* @return
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Nullable
|
||||
private static Map<String, Object> getAsMap(Object source) {
|
||||
private @Nullable static Map<String, Object> getAsMap(@Nullable Object source) {
|
||||
|
||||
if (source instanceof Map) {
|
||||
return (Map<String, Object>) source;
|
||||
|
||||
@@ -75,6 +75,7 @@ public class VaultBytesKeyGenerator implements BytesKeyGenerator {
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("NullAway")
|
||||
public byte[] generateKey() {
|
||||
|
||||
VaultResponse response = this.vaultOperations.write("%s/random/%d".formatted(this.transitPath, getKeyLength()),
|
||||
|
||||
@@ -64,8 +64,7 @@ public abstract class AbstractResult<V> {
|
||||
* Returns the cause of the failed operation if the operation completed with an error.
|
||||
* @return the cause of the failure or {@literal null} if succeeded.
|
||||
*/
|
||||
@Nullable
|
||||
public Exception getCause() {
|
||||
public @Nullable Exception getCause() {
|
||||
return this.exception;
|
||||
}
|
||||
|
||||
@@ -76,8 +75,9 @@ public abstract class AbstractResult<V> {
|
||||
* @return the result value.
|
||||
* @throws VaultException if the operation completed with an error.
|
||||
*/
|
||||
@Nullable
|
||||
public V get() {
|
||||
|
||||
@SuppressWarnings("NullAway")
|
||||
public @Nullable V get() {
|
||||
|
||||
if (isSuccessful()) {
|
||||
return get0();
|
||||
@@ -89,7 +89,6 @@ public abstract class AbstractResult<V> {
|
||||
/**
|
||||
* @return the actual result if this result completed successfully.
|
||||
*/
|
||||
@Nullable
|
||||
protected abstract V get0();
|
||||
protected abstract @Nullable V get0();
|
||||
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ public class CertificateBundle extends Certificate {
|
||||
@JsonProperty("certificate") String certificate, @JsonProperty("issuing_ca") String issuingCaCertificate,
|
||||
@JsonProperty("ca_chain") List<String> caChain, @JsonProperty("private_key") String privateKey,
|
||||
@Nullable @JsonProperty("private_key_type") String privateKeyType,
|
||||
@JsonProperty("revocation_time") Long revocationTime) {
|
||||
@Nullable @JsonProperty("revocation_time") Long revocationTime) {
|
||||
|
||||
super(serialNumber, certificate, issuingCaCertificate, caChain, revocationTime);
|
||||
this.privateKey = privateKey;
|
||||
|
||||
@@ -24,6 +24,7 @@ import java.util.regex.Pattern;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.lang.Contract;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
@@ -45,8 +46,8 @@ public class DurationParser {
|
||||
* @return the duration object. Can be {@literal null} if {@code duration} is empty.
|
||||
* @throws IllegalArgumentException if unable to parse the requested duration.
|
||||
*/
|
||||
@Nullable
|
||||
public static Duration parseDuration(String duration) {
|
||||
@Contract("null -> null")
|
||||
public static @Nullable Duration parseDuration(@Nullable String duration) {
|
||||
|
||||
if (ObjectUtils.isEmpty(duration)) {
|
||||
return null;
|
||||
@@ -69,13 +70,13 @@ public class DurationParser {
|
||||
|
||||
result = switch (typ) {
|
||||
case "ns" -> result.plus(Duration.ofNanos(num));
|
||||
case "us" -> result.plus(Duration.ofNanos(num * 1000));
|
||||
case "us" -> result.plus(Duration.ofNanos(num * 1000L));
|
||||
case "ms" -> result.plus(Duration.ofMillis(num));
|
||||
case "s" -> result.plus(Duration.ofSeconds(num));
|
||||
case "m" -> result.plus(Duration.ofMinutes(num));
|
||||
case "h" -> result.plus(Duration.ofHours(num));
|
||||
case "d" -> result.plus(Duration.ofDays(num));
|
||||
case "w" -> result.plus(Duration.ofDays(num * 7));
|
||||
case "w" -> result.plus(Duration.ofDays(num * 7L));
|
||||
default -> result;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ import java.util.regex.Pattern;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.lang.Contract;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -143,7 +144,6 @@ public class PemObject {
|
||||
StringBuilder keyBuilder = null;
|
||||
while (true) {
|
||||
String line = reader.readLine();
|
||||
;
|
||||
if (line == null) {
|
||||
Assert.isTrue(title == null, "missing end tag " + title);
|
||||
return null;
|
||||
@@ -299,7 +299,8 @@ public class PemObject {
|
||||
return name;
|
||||
}
|
||||
|
||||
public static PemObjectType of(String identifier) {
|
||||
@Contract("null -> fail")
|
||||
public static PemObjectType of(@Nullable String identifier) {
|
||||
|
||||
Assert.hasText(identifier, "Identifier must not be empty");
|
||||
|
||||
|
||||
@@ -48,8 +48,8 @@ import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.type.TypeFactory;
|
||||
import com.fasterxml.jackson.databind.util.Converter;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.vault.support.Policy.PolicyDeserializer;
|
||||
@@ -138,8 +138,7 @@ public class Policy {
|
||||
* @param path must not be {@literal null}.
|
||||
* @return the {@link Rule} or {@literal null}, if not found.
|
||||
*/
|
||||
@Nullable
|
||||
public Rule getRule(String path) {
|
||||
public @Nullable Rule getRule(String path) {
|
||||
|
||||
Assert.notNull(path, "Path must not be null");
|
||||
|
||||
|
||||
@@ -161,7 +161,7 @@ public class SslConfiguration {
|
||||
* @return the created {@link SslConfiguration}.
|
||||
* @see java.security.KeyStore
|
||||
*/
|
||||
public static SslConfiguration forTrustStore(Resource trustStore, char @Nullable[] trustStorePassword) {
|
||||
public static SslConfiguration forTrustStore(Resource trustStore, char @Nullable [] trustStorePassword) {
|
||||
|
||||
Assert.notNull(trustStore, "TrustStore must not be null");
|
||||
Assert.isTrue(trustStore.exists(), () -> "TrustStore %s does not exist".formatted(trustStore));
|
||||
@@ -192,7 +192,7 @@ public class SslConfiguration {
|
||||
* @return the created {@link SslConfiguration}.
|
||||
* @see java.security.KeyStore
|
||||
*/
|
||||
public static SslConfiguration forKeyStore(Resource keyStore, char @Nullable[] keyStorePassword) {
|
||||
public static SslConfiguration forKeyStore(Resource keyStore, char @Nullable [] keyStorePassword) {
|
||||
return forKeyStore(new KeyStoreConfiguration(keyStore, keyStorePassword, DEFAULT_KEYSTORE_TYPE),
|
||||
KeyConfiguration.unconfigured());
|
||||
}
|
||||
@@ -237,7 +237,7 @@ public class SslConfiguration {
|
||||
* @since 2.2
|
||||
* @see java.security.KeyStore
|
||||
*/
|
||||
public static SslConfiguration forKeyStore(Resource keyStore, char @Nullable[] keyStorePassword,
|
||||
public static SslConfiguration forKeyStore(Resource keyStore, char @Nullable [] keyStorePassword,
|
||||
KeyConfiguration keyConfiguration) {
|
||||
|
||||
Assert.notNull(keyStore, "KeyStore must not be null");
|
||||
@@ -260,8 +260,8 @@ public class SslConfiguration {
|
||||
* @return the created {@link SslConfiguration}.
|
||||
* @see java.security.KeyStore
|
||||
*/
|
||||
public static SslConfiguration create(Resource keyStore, char @Nullable[] keyStorePassword, Resource trustStore,
|
||||
char @Nullable[] trustStorePassword) {
|
||||
public static SslConfiguration create(Resource keyStore, char @Nullable [] keyStorePassword, Resource trustStore,
|
||||
char @Nullable [] trustStorePassword) {
|
||||
|
||||
Assert.notNull(keyStore, "KeyStore must not be null");
|
||||
Assert.isTrue(keyStore.exists(), () -> "KeyStore %s does not exist".formatted(keyStore));
|
||||
@@ -441,12 +441,11 @@ public class SslConfiguration {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static String stringOrNull(char @Nullable[] storePassword) {
|
||||
private static String stringOrNull(char @Nullable [] storePassword) {
|
||||
return storePassword != null ? new String(storePassword) : null;
|
||||
}
|
||||
|
||||
|
||||
private static char @Nullable[] charsOrNull(@Nullable String trustStorePassword) {
|
||||
private static char @Nullable [] charsOrNull(@Nullable String trustStorePassword) {
|
||||
return trustStorePassword != null ? trustStorePassword.toCharArray() : null;
|
||||
}
|
||||
|
||||
@@ -465,11 +464,10 @@ public class SslConfiguration {
|
||||
*/
|
||||
private final Resource resource;
|
||||
|
||||
|
||||
/**
|
||||
* Password used to access the key store/trust store.
|
||||
*/
|
||||
private final char @Nullable[] storePassword;
|
||||
private final char @Nullable [] storePassword;
|
||||
|
||||
/**
|
||||
* Key store/trust store type.
|
||||
@@ -479,7 +477,7 @@ public class SslConfiguration {
|
||||
/**
|
||||
* Create a new {@link KeyStoreConfiguration}.
|
||||
*/
|
||||
public KeyStoreConfiguration(Resource resource, char @Nullable[] storePassword, String storeType) {
|
||||
public KeyStoreConfiguration(Resource resource, char @Nullable [] storePassword, String storeType) {
|
||||
|
||||
Assert.notNull(resource, "Resource must not be null");
|
||||
Assert.isTrue(resource instanceof AbsentResource || resource.exists(),
|
||||
@@ -517,7 +515,7 @@ public class SslConfiguration {
|
||||
* @return the {@link KeyStoreConfiguration} for {@code resource}.
|
||||
* @since 2.0
|
||||
*/
|
||||
public static KeyStoreConfiguration of(Resource resource, char @Nullable[] storePassword) {
|
||||
public static KeyStoreConfiguration of(Resource resource, char @Nullable [] storePassword) {
|
||||
return of(resource, storePassword, DEFAULT_KEYSTORE_TYPE);
|
||||
}
|
||||
|
||||
@@ -531,7 +529,8 @@ public class SslConfiguration {
|
||||
* @return the {@link KeyStoreConfiguration} for {@code resource}.
|
||||
* @since 2.3
|
||||
*/
|
||||
public static KeyStoreConfiguration of(Resource resource, char @Nullable[] storePassword, String keyStoreType) {
|
||||
public static KeyStoreConfiguration of(Resource resource, char @Nullable [] storePassword,
|
||||
String keyStoreType) {
|
||||
return new KeyStoreConfiguration(resource, storePassword, keyStoreType);
|
||||
}
|
||||
|
||||
@@ -560,12 +559,11 @@ public class SslConfiguration {
|
||||
return this.resource;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the key store/trust store password. Empty {@code char} array if not
|
||||
* set.
|
||||
*/
|
||||
public char @Nullable[] getStorePassword() {
|
||||
public char @Nullable [] getStorePassword() {
|
||||
return this.storePassword;
|
||||
}
|
||||
|
||||
@@ -601,11 +599,11 @@ public class SslConfiguration {
|
||||
|
||||
private static final KeyConfiguration UNCONFIGURED = new KeyConfiguration(null, null);
|
||||
|
||||
private final char @Nullable[] keyPassword;
|
||||
private final char @Nullable [] keyPassword;
|
||||
|
||||
private final @Nullable String keyAlias;
|
||||
|
||||
private KeyConfiguration(char @Nullable[] keyPassword, @Nullable String keyAlias) {
|
||||
private KeyConfiguration(char @Nullable [] keyPassword, @Nullable String keyAlias) {
|
||||
|
||||
if (keyPassword == null) {
|
||||
this.keyPassword = null;
|
||||
@@ -634,15 +632,14 @@ public class SslConfiguration {
|
||||
* .
|
||||
* @return the {@link KeyConfiguration}.
|
||||
*/
|
||||
public static KeyConfiguration of(char @Nullable[] keyPassword, @Nullable String keyAlias) {
|
||||
public static KeyConfiguration of(char @Nullable [] keyPassword, @Nullable String keyAlias) {
|
||||
return new KeyConfiguration(keyPassword, keyAlias);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the key password to use.
|
||||
*/
|
||||
public char @Nullable[] getKeyPassword() {
|
||||
public char @Nullable [] getKeyPassword() {
|
||||
return this.keyPassword;
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ import java.util.Map;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.vault.support.Versioned.Metadata;
|
||||
|
||||
/**
|
||||
@@ -43,7 +44,7 @@ public class VaultMetadataResponse {
|
||||
|
||||
private final Map<String, String> customMetadata;
|
||||
|
||||
private final Duration deleteVersionAfter;
|
||||
private final @Nullable Duration deleteVersionAfter;
|
||||
|
||||
private final int maxVersions;
|
||||
|
||||
@@ -54,8 +55,8 @@ public class VaultMetadataResponse {
|
||||
private final List<Versioned.Metadata> versions;
|
||||
|
||||
private VaultMetadataResponse(boolean casRequired, Instant createdTime, int currentVersion,
|
||||
Map<String, String> customMetadata, Duration deleteVersionAfter, int maxVersions, int oldestVersion,
|
||||
Instant updatedTime, List<Metadata> versions) {
|
||||
Map<String, String> customMetadata, @Nullable Duration deleteVersionAfter, int maxVersions,
|
||||
int oldestVersion, Instant updatedTime, List<Metadata> versions) {
|
||||
|
||||
this.casRequired = casRequired;
|
||||
this.createdTime = createdTime;
|
||||
@@ -97,8 +98,7 @@ public class VaultMetadataResponse {
|
||||
* @return the duration after which a secret is to be deleted. {@link Period#ZERO} for
|
||||
* unlimited duration. Versions prior to Vault 1.2 may return {@code null}.
|
||||
*/
|
||||
@Nullable
|
||||
public Duration getDeleteVersionAfter() {
|
||||
public @Nullable Duration getDeleteVersionAfter() {
|
||||
return this.deleteVersionAfter;
|
||||
}
|
||||
|
||||
@@ -146,21 +146,21 @@ public class VaultMetadataResponse {
|
||||
|
||||
private boolean casRequired;
|
||||
|
||||
private Map<String, String> customMetadata;
|
||||
private Map<String, String> customMetadata = Collections.emptyMap();
|
||||
|
||||
private Instant createdTime;
|
||||
private @Nullable Instant createdTime;
|
||||
|
||||
private int currentVersion;
|
||||
|
||||
private Duration deleteVersionAfter;
|
||||
private @Nullable Duration deleteVersionAfter;
|
||||
|
||||
private int maxVersions;
|
||||
|
||||
private int oldestVersion;
|
||||
|
||||
private Instant updatedTime;
|
||||
private @Nullable Instant updatedTime;
|
||||
|
||||
private List<Versioned.Metadata> versions;
|
||||
private List<Versioned.Metadata> versions = Collections.emptyList();
|
||||
|
||||
public VaultMetadataResponseBuilder casRequired(boolean casRequired) {
|
||||
this.casRequired = casRequired;
|
||||
@@ -182,7 +182,7 @@ public class VaultMetadataResponse {
|
||||
return this;
|
||||
}
|
||||
|
||||
public VaultMetadataResponseBuilder deleteVersionAfter(Duration deleteVersionAfter) {
|
||||
public VaultMetadataResponseBuilder deleteVersionAfter(@Nullable Duration deleteVersionAfter) {
|
||||
this.deleteVersionAfter = deleteVersionAfter;
|
||||
return this;
|
||||
}
|
||||
@@ -208,6 +208,10 @@ public class VaultMetadataResponse {
|
||||
}
|
||||
|
||||
public VaultMetadataResponse build() {
|
||||
|
||||
Assert.notNull(this.createdTime, "Created time must not be null");
|
||||
Assert.notNull(this.updatedTime, "Updated time must not be null");
|
||||
|
||||
return new VaultMetadataResponse(this.casRequired, this.createdTime, this.currentVersion,
|
||||
this.customMetadata, this.deleteVersionAfter, this.maxVersions, this.oldestVersion,
|
||||
this.updatedTime, this.versions);
|
||||
|
||||
@@ -21,6 +21,7 @@ import java.util.Map;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.lang.Contract;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -119,11 +120,9 @@ public class VaultMount {
|
||||
*/
|
||||
public static class VaultMountBuilder {
|
||||
|
||||
@Nullable
|
||||
private String type;
|
||||
private @Nullable String type;
|
||||
|
||||
@Nullable
|
||||
private String description;
|
||||
private @Nullable String description;
|
||||
|
||||
private Map<String, Object> config = Collections.emptyMap();
|
||||
|
||||
@@ -137,7 +136,8 @@ public class VaultMount {
|
||||
* @param type the backend type, must not be empty or {@literal null}.
|
||||
* @return {@literal this} {@link VaultMountBuilder}.
|
||||
*/
|
||||
public VaultMountBuilder type(String type) {
|
||||
@Contract("null -> fail")
|
||||
public VaultMountBuilder type(@Nullable String type) {
|
||||
|
||||
Assert.hasText(type, "Type must not be empty or null");
|
||||
|
||||
@@ -146,11 +146,11 @@ public class VaultMount {
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure a human readable description of this mount.
|
||||
* @param description a human readable description of this mount.
|
||||
* Configure a human-readable description of this mount.
|
||||
* @param description a human-readable description of this mount.
|
||||
* @return {@literal this} {@link VaultMountBuilder}.
|
||||
*/
|
||||
public VaultMountBuilder description(String description) {
|
||||
public VaultMountBuilder description(@Nullable String description) {
|
||||
|
||||
this.description = description;
|
||||
return this;
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.springframework.vault.support;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -33,18 +34,15 @@ import org.jspecify.annotations.Nullable;
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public class VaultResponseSupport<T> {
|
||||
|
||||
@Nullable
|
||||
private Map<String, Object> auth;
|
||||
private Map<String, Object> auth = Collections.emptyMap();
|
||||
|
||||
@Nullable
|
||||
private T data;
|
||||
|
||||
@Nullable
|
||||
private Map<String, Object> metadata;
|
||||
private Map<String, Object> metadata = Collections.emptyMap();
|
||||
|
||||
@JsonProperty("wrap_info")
|
||||
@Nullable
|
||||
private Map<String, String> wrapInfo;
|
||||
private Map<String, String> wrapInfo = Collections.emptyMap();
|
||||
|
||||
@JsonProperty("lease_duration")
|
||||
private long leaseDuration;
|
||||
@@ -59,8 +57,7 @@ public class VaultResponseSupport<T> {
|
||||
|
||||
private boolean renewable;
|
||||
|
||||
@Nullable
|
||||
private List<String> warnings;
|
||||
private List<String> warnings = Collections.emptyList();
|
||||
|
||||
/**
|
||||
* Apply metadata such as auth or warnings without copying data.
|
||||
@@ -82,28 +79,14 @@ public class VaultResponseSupport<T> {
|
||||
/**
|
||||
* @return authentication payload.
|
||||
*/
|
||||
@Nullable
|
||||
public Map<String, Object> getAuth() {
|
||||
return this.auth;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the authentication payload.
|
||||
* @throws IllegalStateException if {@code auth} is null.
|
||||
*/
|
||||
public Map<String, Object> getRequiredAuth() {
|
||||
|
||||
if (this.auth != null) {
|
||||
return this.auth;
|
||||
}
|
||||
|
||||
throw new IllegalStateException("Auth field is empty");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param auth the authentication payload.
|
||||
*/
|
||||
public void setAuth(@Nullable Map<String, Object> auth) {
|
||||
public void setAuth(Map<String, Object> auth) {
|
||||
this.auth = auth;
|
||||
}
|
||||
|
||||
@@ -138,7 +121,6 @@ public class VaultResponseSupport<T> {
|
||||
/**
|
||||
* @return request metadata.
|
||||
*/
|
||||
@Nullable
|
||||
public Map<String, Object> getMetadata() {
|
||||
return this.metadata;
|
||||
}
|
||||
@@ -146,7 +128,7 @@ public class VaultResponseSupport<T> {
|
||||
/**
|
||||
* @param metadata request metadata.
|
||||
*/
|
||||
public void setMetadata(@Nullable Map<String, Object> metadata) {
|
||||
public void setMetadata(Map<String, Object> metadata) {
|
||||
this.metadata = metadata;
|
||||
}
|
||||
|
||||
@@ -196,7 +178,6 @@ public class VaultResponseSupport<T> {
|
||||
/**
|
||||
* @return response wrapping details.
|
||||
*/
|
||||
@Nullable
|
||||
public Map<String, String> getWrapInfo() {
|
||||
return this.wrapInfo;
|
||||
}
|
||||
@@ -204,7 +185,7 @@ public class VaultResponseSupport<T> {
|
||||
/**
|
||||
* @param wrapInfo response wrapping details.
|
||||
*/
|
||||
public void setWrapInfo(@Nullable Map<String, String> wrapInfo) {
|
||||
public void setWrapInfo(Map<String, String> wrapInfo) {
|
||||
this.wrapInfo = wrapInfo;
|
||||
}
|
||||
|
||||
@@ -226,7 +207,6 @@ public class VaultResponseSupport<T> {
|
||||
/**
|
||||
* @return the warnings.
|
||||
*/
|
||||
@Nullable
|
||||
public List<String> getWarnings() {
|
||||
return this.warnings;
|
||||
}
|
||||
@@ -234,7 +214,7 @@ public class VaultResponseSupport<T> {
|
||||
/**
|
||||
* @param warnings the warnings.
|
||||
*/
|
||||
public void setWarnings(@Nullable List<String> warnings) {
|
||||
public void setWarnings(List<String> warnings) {
|
||||
this.warnings = warnings;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,9 @@ package org.springframework.vault.support;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.lang.Contract;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -42,7 +45,8 @@ public class VaultToken {
|
||||
* @param token must not be empty or {@literal null}.
|
||||
* @return the created {@link VaultToken}
|
||||
*/
|
||||
public static VaultToken of(String token) {
|
||||
@Contract("null -> fail")
|
||||
public static VaultToken of(@Nullable String token) {
|
||||
|
||||
Assert.hasText(token, "Token must not be empty");
|
||||
|
||||
|
||||
@@ -39,8 +39,7 @@ public class VaultTokenRequest {
|
||||
|
||||
private static final VaultTokenRequest EMPTY = VaultTokenRequest.builder().build();
|
||||
|
||||
@Nullable
|
||||
private final String id;
|
||||
private final @Nullable String id;
|
||||
|
||||
private final List<String> policies;
|
||||
|
||||
@@ -54,25 +53,23 @@ public class VaultTokenRequest {
|
||||
|
||||
private final boolean renewable;
|
||||
|
||||
@Nullable
|
||||
private final String ttl;
|
||||
private final @Nullable String ttl;
|
||||
|
||||
@JsonProperty("explicit_max_ttl")
|
||||
@Nullable
|
||||
private final String explicitMaxTtl;
|
||||
private final @Nullable String explicitMaxTtl;
|
||||
|
||||
@JsonProperty("display_name")
|
||||
private final String displayName;
|
||||
|
||||
@JsonProperty("entity_alias")
|
||||
private final String entityAlias;
|
||||
private final @Nullable String entityAlias;
|
||||
|
||||
@JsonProperty("num_uses")
|
||||
private final int numUses;
|
||||
|
||||
VaultTokenRequest(@Nullable String id, List<String> policies, Map<String, String> meta, boolean noParent,
|
||||
boolean noDefaultPolicy, boolean renewable, @Nullable String ttl, @Nullable String explicitMaxTtl,
|
||||
String displayName, String entityAlias, int numUses) {
|
||||
String displayName, @Nullable String entityAlias, int numUses) {
|
||||
|
||||
this.id = id;
|
||||
this.policies = policies;
|
||||
@@ -174,7 +171,7 @@ public class VaultTokenRequest {
|
||||
* works in combination with role name.
|
||||
* @since 3.1
|
||||
*/
|
||||
public String getEntityAlias() {
|
||||
public @Nullable String getEntityAlias() {
|
||||
return this.entityAlias;
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ public class VaultTokenResponse extends VaultResponse {
|
||||
* @return the {@link VaultToken}.
|
||||
*/
|
||||
public VaultToken getToken() {
|
||||
return VaultToken.of((String) getRequiredAuth().get("client_token"));
|
||||
return VaultToken.of((String) getAuth().get("client_token"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -17,7 +17,8 @@ package org.springframework.vault.support;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ public class Versioned<T> {
|
||||
|
||||
private final @Nullable Metadata metadata;
|
||||
|
||||
private Versioned(T data, Version version) {
|
||||
private Versioned(@Nullable T data, Version version) {
|
||||
|
||||
this.version = version;
|
||||
this.metadata = null;
|
||||
@@ -345,7 +345,7 @@ public class Versioned<T> {
|
||||
* {@literal null}.
|
||||
* @return {@code this} {@link MetadataBuilder}.
|
||||
*/
|
||||
public MetadataBuilder deletedAt(Instant deletedAt) {
|
||||
public MetadataBuilder deletedAt(@Nullable Instant deletedAt) {
|
||||
this.deletedAt = deletedAt;
|
||||
return this;
|
||||
}
|
||||
@@ -387,7 +387,7 @@ public class Versioned<T> {
|
||||
* @return {@code this} {@link MetadataBuilder}.
|
||||
* @since 3.1
|
||||
*/
|
||||
public MetadataBuilder customMetadata(Map<String, String> customMetadata) {
|
||||
public MetadataBuilder customMetadata(@Nullable Map<String, String> customMetadata) {
|
||||
|
||||
this.customMetadata = customMetadata != null && !CollectionUtils.isEmpty(customMetadata)
|
||||
? new LinkedHashMap<>(customMetadata) : null;
|
||||
|
||||
@@ -34,7 +34,7 @@ public class WrappedMetadata {
|
||||
|
||||
private final Instant creationTime;
|
||||
|
||||
private final String path;
|
||||
private final @Nullable String path;
|
||||
|
||||
private final Duration ttl;
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@ public class LeaseEndpointsUnitTests {
|
||||
when(restOperations.exchange(eq("sys/renew"), eq(HttpMethod.PUT), any(HttpEntity.class), eq(Map.class)))
|
||||
.thenReturn(new ResponseEntity<>(vaultResponseBody, HttpStatus.OK));
|
||||
|
||||
when(oldLease.getLeaseId()).thenReturn("old_lease");
|
||||
when(oldLease.getRequiredLeaseId()).thenReturn("old_lease");
|
||||
when(oldLease.getLeaseDuration()).thenReturn(Duration.ofSeconds(70));
|
||||
|
||||
Lease renewedLease = LeaseEndpoints.Legacy.renew(oldLease, restOperations);
|
||||
@@ -76,7 +76,7 @@ public class LeaseEndpointsUnitTests {
|
||||
Map<String, String> actualRequestBodyParams = httpEntityCaptor.getValue().getBody();
|
||||
assertThat(actualRequestBodyParams).containsOnly(entry("lease_id", "old_lease"), entry("increment", "70"));
|
||||
|
||||
assertThat(renewedLease.getLeaseId()).isEqualTo("new_lease");
|
||||
assertThat(renewedLease.getRequiredLeaseId()).isEqualTo("new_lease");
|
||||
assertThat(renewedLease.getLeaseDuration()).isEqualTo(Duration.ofSeconds(90));
|
||||
assertThat(renewedLease.isRenewable()).isFalse();
|
||||
|
||||
@@ -87,7 +87,7 @@ public class LeaseEndpointsUnitTests {
|
||||
@DisplayName("LeaseEndpoints.Legacy uses PUT /sys/revoke to revoke a lease")
|
||||
void legacyRevokesUsingSysRevoke() {
|
||||
|
||||
when(oldLease.getLeaseId()).thenReturn("old_lease");
|
||||
when(oldLease.getRequiredLeaseId()).thenReturn("old_lease");
|
||||
|
||||
LeaseEndpoints.Legacy.revoke(oldLease, restOperations);
|
||||
|
||||
@@ -112,7 +112,7 @@ public class LeaseEndpointsUnitTests {
|
||||
when(restOperations.exchange(eq("sys/leases/renew"), eq(HttpMethod.PUT), any(HttpEntity.class), eq(Map.class)))
|
||||
.thenReturn(new ResponseEntity<>(vaultResponseBody, HttpStatus.OK));
|
||||
|
||||
when(oldLease.getLeaseId()).thenReturn("old_lease");
|
||||
when(oldLease.getRequiredLeaseId()).thenReturn("old_lease");
|
||||
when(oldLease.getLeaseDuration()).thenReturn(Duration.ofSeconds(70));
|
||||
|
||||
Lease renewedLease = LeaseEndpoints.Leases.renew(oldLease, restOperations);
|
||||
@@ -123,7 +123,7 @@ public class LeaseEndpointsUnitTests {
|
||||
Map<String, String> actualRequestBodyParams = httpEntityCaptor.getValue().getBody();
|
||||
assertThat(actualRequestBodyParams).containsOnly(entry("lease_id", "old_lease"), entry("increment", "70"));
|
||||
|
||||
assertThat(renewedLease.getLeaseId()).isEqualTo("new_lease");
|
||||
assertThat(renewedLease.getRequiredLeaseId()).isEqualTo("new_lease");
|
||||
assertThat(renewedLease.getLeaseDuration()).isEqualTo(Duration.ofSeconds(90));
|
||||
assertThat(renewedLease.isRenewable()).isFalse();
|
||||
|
||||
@@ -135,7 +135,7 @@ public class LeaseEndpointsUnitTests {
|
||||
@DisplayName("LeaseEndpoints.SysLeases uses PUT /sys/leases/revoke to revoke a lease")
|
||||
void sysLeasesRevokesUsingSysLeasesRevoke() {
|
||||
|
||||
when(oldLease.getLeaseId()).thenReturn("old_lease");
|
||||
when(oldLease.getRequiredLeaseId()).thenReturn("old_lease");
|
||||
|
||||
LeaseEndpoints.Leases.revoke(oldLease, restOperations);
|
||||
|
||||
@@ -159,7 +159,7 @@ public class LeaseEndpointsUnitTests {
|
||||
when(restOperations.exchange(eq("sys/leases/renew"), eq(HttpMethod.PUT), any(HttpEntity.class), eq(Map.class)))
|
||||
.thenReturn(new ResponseEntity<>(vaultResponseBody, HttpStatus.OK));
|
||||
|
||||
when(oldLease.getLeaseId()).thenReturn("old_lease");
|
||||
when(oldLease.getRequiredLeaseId()).thenReturn("old_lease");
|
||||
when(oldLease.getLeaseDuration()).thenReturn(Duration.ofSeconds(70));
|
||||
|
||||
Lease renewedLease = LeaseEndpoints.Leases.renew(oldLease, restOperations);
|
||||
@@ -170,7 +170,7 @@ public class LeaseEndpointsUnitTests {
|
||||
Map<String, String> actualRequestBodyParams = httpEntityCaptor.getValue().getBody();
|
||||
assertThat(actualRequestBodyParams).containsOnly(entry("lease_id", "old_lease"), entry("increment", "70"));
|
||||
|
||||
assertThat(renewedLease.getLeaseId()).isEqualTo("new_lease");
|
||||
assertThat(renewedLease.getRequiredLeaseId()).isEqualTo("new_lease");
|
||||
assertThat(renewedLease.getLeaseDuration()).isEqualTo(Duration.ofSeconds(90));
|
||||
assertThat(renewedLease.isRenewable()).isFalse();
|
||||
|
||||
@@ -181,7 +181,7 @@ public class LeaseEndpointsUnitTests {
|
||||
@DisplayName("LeaseEndpoints.Leases uses PUT /sys/leases/revoke to revoke a lease")
|
||||
void leasesRevokesUsingSysLeasesRevoke() {
|
||||
|
||||
when(oldLease.getLeaseId()).thenReturn("old_lease");
|
||||
when(oldLease.getRequiredLeaseId()).thenReturn("old_lease");
|
||||
|
||||
LeaseEndpoints.Leases.revoke(oldLease, restOperations);
|
||||
|
||||
@@ -205,7 +205,7 @@ public class LeaseEndpointsUnitTests {
|
||||
when(restOperations.exchange(eq("sys/leases/renew"), eq(HttpMethod.PUT), any(HttpEntity.class), eq(Map.class)))
|
||||
.thenReturn(new ResponseEntity<>(vaultResponseBody, HttpStatus.OK));
|
||||
|
||||
when(oldLease.getLeaseId()).thenReturn("old_lease");
|
||||
when(oldLease.getRequiredLeaseId()).thenReturn("old_lease");
|
||||
when(oldLease.getLeaseDuration()).thenReturn(Duration.ofSeconds(70));
|
||||
|
||||
Lease renewedLease = LeaseEndpoints.LeasesRevokedByPrefix.renew(oldLease, restOperations);
|
||||
@@ -216,7 +216,7 @@ public class LeaseEndpointsUnitTests {
|
||||
Map<String, String> actualRequestBodyParams = httpEntityCaptor.getValue().getBody();
|
||||
assertThat(actualRequestBodyParams).containsOnly(entry("lease_id", "old_lease"), entry("increment", "70"));
|
||||
|
||||
assertThat(renewedLease.getLeaseId()).isEqualTo("new_lease");
|
||||
assertThat(renewedLease.getRequiredLeaseId()).isEqualTo("new_lease");
|
||||
assertThat(renewedLease.getLeaseDuration()).isEqualTo(Duration.ofSeconds(90));
|
||||
assertThat(renewedLease.isRenewable()).isFalse();
|
||||
|
||||
@@ -227,7 +227,7 @@ public class LeaseEndpointsUnitTests {
|
||||
@DisplayName("LeaseEndpoints.LeasesRevokedByPrefix uses PUT /sys/leases/revoke-prefix/{prefix} to revoke a lease")
|
||||
void leasesRevokedByPrefixRevokesUsingSysLeasesRevokePrefix() {
|
||||
|
||||
when(oldLease.getLeaseId()).thenReturn("my/old/lease");
|
||||
when(oldLease.getRequiredLeaseId()).thenReturn("my/old/lease");
|
||||
|
||||
LeaseEndpoints.LeasesRevokedByPrefix.revoke(oldLease, restOperations);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user