diff --git a/spring-vault-core/src/main/java/org/springframework/vault/authentication/ClientCertificateAuthentication.java b/spring-vault-core/src/main/java/org/springframework/vault/authentication/ClientCertificateAuthentication.java index 1115220c..c2ca78b6 100644 --- a/spring-vault-core/src/main/java/org/springframework/vault/authentication/ClientCertificateAuthentication.java +++ b/spring-vault-core/src/main/java/org/springframework/vault/authentication/ClientCertificateAuthentication.java @@ -36,11 +36,11 @@ import static org.springframework.vault.authentication.AuthenticationSteps.HttpR public class ClientCertificateAuthentication implements ClientAuthentication, AuthenticationStepsFactory { - private static final String CERT = "cert"; - private static final Log logger = LogFactory .getLog(ClientCertificateAuthentication.class); + private final ClientCertificateAuthenticationOptions options; + private final RestOperations restOperations; /** @@ -49,10 +49,25 @@ public class ClientCertificateAuthentication * @param restOperations must not be {@literal null}. */ public ClientCertificateAuthentication(RestOperations restOperations) { + this(ClientCertificateAuthenticationOptions.builder().build(), restOperations); + } + /** + * Create a {@link ClientCertificateAuthentication} using {@link RestOperations}. + * + * @param options must not be {@literal null}. + * @param restOperations must not be {@literal null}. + * @since 2.3 + */ + public ClientCertificateAuthentication(ClientCertificateAuthenticationOptions options, + RestOperations restOperations) { + + Assert.notNull(options, + "ClientCertificateAuthenticationOptions must not be null"); Assert.notNull(restOperations, "RestOperations must not be null"); this.restOperations = restOperations; + this.options = options; } /** @@ -62,7 +77,26 @@ public class ClientCertificateAuthentication * @since 2.0 */ public static AuthenticationSteps createAuthenticationSteps() { - return AuthenticationSteps.just(post(AuthenticationUtil.getLoginPath(CERT)).as(VaultResponse.class)); + return createAuthenticationSteps( + ClientCertificateAuthenticationOptions.builder().build()); + } + + /** + * Creates a {@link AuthenticationSteps} for client certificate authentication. + * + * @param options must not be {@literal null}. + * @return {@link AuthenticationSteps} for client certificate authentication. + * @since 2.3 + */ + public static AuthenticationSteps createAuthenticationSteps( + ClientCertificateAuthenticationOptions options) { + + Assert.notNull(options, + "ClientCertificateAuthenticationOptions must not be null"); + + return AuthenticationSteps + .just(post(AuthenticationUtil.getLoginPath(options.getPath())) + .as(VaultResponse.class)); } @Override @@ -72,13 +106,14 @@ public class ClientCertificateAuthentication @Override public AuthenticationSteps getAuthenticationSteps() { - return createAuthenticationSteps(); + return createAuthenticationSteps(options); } private VaultToken createTokenUsingTlsCertAuthentication() { try { - VaultResponse response = restOperations.postForObject(AuthenticationUtil.getLoginPath(CERT), + VaultResponse response = restOperations.postForObject( + AuthenticationUtil.getLoginPath(options.getPath()), Collections.emptyMap(), VaultResponse.class); Assert.state(response.getAuth() != null, "Auth field must not be null"); diff --git a/spring-vault-core/src/main/java/org/springframework/vault/authentication/ClientCertificateAuthenticationOptions.java b/spring-vault-core/src/main/java/org/springframework/vault/authentication/ClientCertificateAuthenticationOptions.java new file mode 100644 index 00000000..7a903156 --- /dev/null +++ b/spring-vault-core/src/main/java/org/springframework/vault/authentication/ClientCertificateAuthenticationOptions.java @@ -0,0 +1,92 @@ +/* + * Copyright 2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.vault.authentication; + +import org.springframework.util.Assert; + +/** + * Authentication options for {@link ClientCertificateAuthentication}. + *
+ * Authentication options provide the path. {@link ClientCertificateAuthenticationOptions} + * can be constructed using {@link #builder()}. Instances of this class are immutable once + * constructed. + * + * @author Mark Paluch + * @since 2.3 + * @see ClientCertificateAuthenticationOptions + * @see #builder() + */ +public class ClientCertificateAuthenticationOptions { + + public static final String DEFAULT_CERT_PATH = "cert"; + + /** + * Path of the cert authentication backend mount. + */ + private final String path; + + private ClientCertificateAuthenticationOptions(String path) { + this.path = path; + } + + /** + * @return a new {@link ClientCertificateAuthenticationOptionsBuilder}. + */ + public static ClientCertificateAuthenticationOptionsBuilder builder() { + return new ClientCertificateAuthenticationOptionsBuilder(); + } + + /** + * @return the path of the azure authentication backend mount. + */ + public String getPath() { + return path; + } + + /** + * Builder for {@link ClientCertificateAuthenticationOptions}. + */ + public static class ClientCertificateAuthenticationOptionsBuilder { + + private String path = DEFAULT_CERT_PATH; + + ClientCertificateAuthenticationOptionsBuilder() { + } + + /** + * Configure the mount path, defaults to {@literal azure}. + * + * @param path must not be empty or {@literal null}. + * @return {@code this} {@link ClientCertificateAuthenticationOptionsBuilder}. + */ + public ClientCertificateAuthenticationOptionsBuilder path(String path) { + + Assert.hasText(path, "Path must not be empty"); + + this.path = path; + return this; + } + + /** + * Build a new {@link ClientCertificateAuthenticationOptions} instance. + * + * @return a new {@link ClientCertificateAuthenticationOptions}. + */ + public ClientCertificateAuthenticationOptions build() { + return new ClientCertificateAuthenticationOptions(path); + } + } +} diff --git a/spring-vault-core/src/test/java/org/springframework/vault/authentication/ClientCertificateAuthenticationUnitTests.java b/spring-vault-core/src/test/java/org/springframework/vault/authentication/ClientCertificateAuthenticationUnitTests.java index 9f9790db..e5f74cd6 100644 --- a/spring-vault-core/src/test/java/org/springframework/vault/authentication/ClientCertificateAuthenticationUnitTests.java +++ b/spring-vault-core/src/test/java/org/springframework/vault/authentication/ClientCertificateAuthenticationUnitTests.java @@ -60,13 +60,17 @@ class ClientCertificateAuthenticationUnitTests { @Test void loginShouldObtainToken() { - mockRest.expect(requestTo("/auth/cert/login")).andExpect(method(HttpMethod.POST)) + mockRest.expect(requestTo("/auth/my/path/login")) + .andExpect(method(HttpMethod.POST)) .andRespond(withSuccess().contentType(MediaType.APPLICATION_JSON).body("{" + "\"auth\":{\"client_token\":\"my-token\", \"renewable\": true, \"lease_duration\": 10}" + "}")); + ClientCertificateAuthenticationOptions options = ClientCertificateAuthenticationOptions + .builder().path("my/path").build(); + ClientCertificateAuthentication sut = new ClientCertificateAuthentication( - restTemplate); + options, restTemplate); VaultToken login = sut.login(); diff --git a/src/main/asciidoc/reference/authentication.adoc b/src/main/asciidoc/reference/authentication.adoc index 626d62f6..660d65d8 100644 --- a/src/main/asciidoc/reference/authentication.adoc +++ b/src/main/asciidoc/reference/authentication.adoc @@ -599,6 +599,10 @@ class AppConfig extends AbstractVaultConfiguration { @Override public ClientAuthentication clientAuthentication() { + + ClientCertificateAuthenticationOptions options = ClientCertificateAuthenticationOptions.builder() + .path(…).build(); + return new ClientCertificateAuthentication(options, restOperations()); }