pass builder as constructor parameter directly

With increasing number of options the constructors become quite overloaded.
We now pass the builder as only argument instead.
This commit is contained in:
Stefan Kalscheuer 2021-06-08 19:28:25 +02:00
parent 9ef709e3eb
commit f783286909
4 changed files with 150 additions and 41 deletions

View File

@ -16,6 +16,7 @@
package de.stklcode.jvault.connector; package de.stklcode.jvault.connector;
import de.stklcode.jvault.connector.builder.HTTPVaultConnectorBuilder;
import de.stklcode.jvault.connector.exception.AuthorizationRequiredException; import de.stklcode.jvault.connector.exception.AuthorizationRequiredException;
import de.stklcode.jvault.connector.exception.InvalidRequestException; import de.stklcode.jvault.connector.exception.InvalidRequestException;
import de.stklcode.jvault.connector.exception.VaultConnectorException; import de.stklcode.jvault.connector.exception.VaultConnectorException;
@ -107,23 +108,6 @@ public class HTTPVaultConnector implements VaultConnector {
+ prefix); + prefix);
} }
/**
* Create connector using hostname, schema, port, path and trusted certificate.
*
* @param hostname The hostname
* @param useTLS If TRUE, use HTTPS, otherwise HTTP
* @param port The port
* @param prefix HTTP API prefix (default: /v1/)
* @param trustedCaCert Trusted CA certificate
*/
public HTTPVaultConnector(final String hostname,
final boolean useTLS,
final Integer port,
final String prefix,
final X509Certificate trustedCaCert) {
this(hostname, useTLS, DEFAULT_TLS_VERSION, port, prefix, trustedCaCert, 0, null);
}
/** /**
* Create connector using hostname, schema, port, path and trusted certificate. * Create connector using hostname, schema, port, path and trusted certificate.
* *
@ -144,14 +128,34 @@ public class HTTPVaultConnector implements VaultConnector {
final X509Certificate trustedCaCert, final X509Certificate trustedCaCert,
final int numberOfRetries, final int numberOfRetries,
final Integer timeout) { final Integer timeout) {
this(((useTLS) ? "https" : "http") this(
((useTLS) ? "https" : "http")
+ "://" + hostname + "://" + hostname
+ ((port != null) ? ":" + port : "") + ((port != null) ? ":" + port : "")
+ prefix, + prefix,
trustedCaCert, trustedCaCert,
numberOfRetries, numberOfRetries,
timeout, timeout,
tlsVersion); tlsVersion
);
}
/**
* Create connector using a {@link HTTPVaultConnectorBuilder}.
*
* @param builder The builder.
*/
public HTTPVaultConnector(final HTTPVaultConnectorBuilder builder) {
this.request = new RequestHelper(
((builder.isWithTLS()) ? "https" : "http") + "://" +
builder.getHost() +
((builder.getPort() != null) ? ":" + builder.getPort() : "") +
builder.getPrefix(),
builder.getNumberOfRetries(),
builder.getTimeout(),
builder.getTlsVersion(),
builder.getTrustedCA()
);
} }
/** /**

View File

@ -84,6 +84,15 @@ public final class HTTPVaultConnectorBuilder implements VaultConnectorBuilder {
return this; return this;
} }
/**
* Get hostname.
*
* @return Hostname or IP address
*/
public String getHost() {
return this.host;
}
/** /**
* Set port (default: 8200). * Set port (default: 8200).
* *
@ -95,6 +104,15 @@ public final class HTTPVaultConnectorBuilder implements VaultConnectorBuilder {
return this; return this;
} }
/**
* Set port..
*
* @return Vault TCP port
*/
public Integer getPort() {
return this.port;
}
/** /**
* Set TLS usage (default: TRUE). * Set TLS usage (default: TRUE).
* *
@ -106,6 +124,24 @@ public final class HTTPVaultConnectorBuilder implements VaultConnectorBuilder {
return this; return this;
} }
/**
* Get TLS usage flag.
*
* @return use TLS or not
*/
public boolean isWithTLS() {
return this.tls;
}
/**
* Get TLS version.
*
* @return TLS version.
*/
public String getTlsVersion() {
return this.tlsVersion;
}
/** /**
* Set TLS usage (default: TRUE). * Set TLS usage (default: TRUE).
* *
@ -152,7 +188,7 @@ public final class HTTPVaultConnectorBuilder implements VaultConnectorBuilder {
/** /**
* Set API prefix. Default is "/v1/" and changes should not be necessary for current state of development. * Set API prefix. Default is "/v1/" and changes should not be necessary for current state of development.
* *
* @param prefix Vault API prefix (default: "/v1/" * @param prefix Vault API prefix (default: "/v1/")
* @return self * @return self
*/ */
public HTTPVaultConnectorBuilder withPrefix(final String prefix) { public HTTPVaultConnectorBuilder withPrefix(final String prefix) {
@ -160,6 +196,15 @@ public final class HTTPVaultConnectorBuilder implements VaultConnectorBuilder {
return this; return this;
} }
/**
* Get API prefix.
*
* @return Vault API prefix.
*/
public String getPrefix() {
return this.prefix;
}
/** /**
* Add a trusted CA certificate for HTTPS connections. * Add a trusted CA certificate for HTTPS connections.
* *
@ -189,6 +234,15 @@ public final class HTTPVaultConnectorBuilder implements VaultConnectorBuilder {
return this; return this;
} }
/**
* Get the trusted CA certificate for HTTPS connections.
*
* @return path to certificate file, if specified.
*/
public X509Certificate getTrustedCA() {
return this.trustedCA;
}
/** /**
* Set token for automatic authentication, using {@link #buildAndAuth()}. * Set token for automatic authentication, using {@link #buildAndAuth()}.
* *
@ -252,6 +306,15 @@ public final class HTTPVaultConnectorBuilder implements VaultConnectorBuilder {
return this; return this;
} }
/**
* Get the number of retries to attempt on 5xx errors.
*
* @return The number of retries to attempt on 5xx errors (default: 0)
*/
public int getNumberOfRetries() {
return this.numberOfRetries;
}
/** /**
* Define a custom timeout for the HTTP connection. * Define a custom timeout for the HTTP connection.
* *
@ -264,9 +327,18 @@ public final class HTTPVaultConnectorBuilder implements VaultConnectorBuilder {
return this; return this;
} }
/**
* Get custom timeout for the HTTP connection.
*
* @return Timeout value in milliseconds.
*/
public Integer getTimeout() {
return this.timeout;
}
@Override @Override
public HTTPVaultConnector build() { public HTTPVaultConnector build() {
return new HTTPVaultConnector(host, tls, tlsVersion, port, prefix, trustedCA, numberOfRetries, timeout); return new HTTPVaultConnector(this);
} }
@Override @Override

View File

@ -19,6 +19,7 @@ package de.stklcode.jvault.connector;
import com.github.tomakehurst.wiremock.WireMockServer; import com.github.tomakehurst.wiremock.WireMockServer;
import com.github.tomakehurst.wiremock.client.WireMock; import com.github.tomakehurst.wiremock.client.WireMock;
import com.github.tomakehurst.wiremock.core.WireMockConfiguration; import com.github.tomakehurst.wiremock.core.WireMockConfiguration;
import de.stklcode.jvault.connector.builder.VaultConnectorBuilder;
import de.stklcode.jvault.connector.exception.*; import de.stklcode.jvault.connector.exception.*;
import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeAll;
@ -157,11 +158,6 @@ class HTTPVaultConnectorOfflineTest {
assertThat("Unexpected base URL with custom prefix", getRequestHelperPrivate(connector, "baseURL"), is(expectedCustomPrefix)); assertThat("Unexpected base URL with custom prefix", getRequestHelperPrivate(connector, "baseURL"), is(expectedCustomPrefix));
assertThat("Trusted CA cert set, but not specified", getRequestHelperPrivate(connector, "trustedCaCert"), is(nullValue())); assertThat("Trusted CA cert set, but not specified", getRequestHelperPrivate(connector, "trustedCaCert"), is(nullValue()));
// Provide custom SSL context.
connector = new HTTPVaultConnector(hostname, true, port, prefix, trustedCaCert);
assertThat("Unexpected base URL with custom prefix", getRequestHelperPrivate(connector, "baseURL"), is(expectedCustomPrefix));
assertThat("Trusted CA cert not filled correctly", getRequestHelperPrivate(connector, "trustedCaCert"), is(trustedCaCert));
// Specify number of retries. // Specify number of retries.
connector = new HTTPVaultConnector(url, trustedCaCert, retries); connector = new HTTPVaultConnector(url, trustedCaCert, retries);
assertThat("Number of retries not set correctly", getRequestHelperPrivate(connector, "retries"), is(retries)); assertThat("Number of retries not set correctly", getRequestHelperPrivate(connector, "retries"), is(retries));

View File

@ -18,6 +18,7 @@ package de.stklcode.jvault.connector.builder;
import com.github.stefanbirkner.systemlambda.SystemLambda; import com.github.stefanbirkner.systemlambda.SystemLambda;
import de.stklcode.jvault.connector.HTTPVaultConnector; import de.stklcode.jvault.connector.HTTPVaultConnector;
import de.stklcode.jvault.connector.exception.ConnectionException;
import de.stklcode.jvault.connector.exception.TlsException; import de.stklcode.jvault.connector.exception.TlsException;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir; import org.junit.jupiter.api.io.TempDir;
@ -25,13 +26,9 @@ import org.junit.jupiter.api.io.TempDir;
import java.io.File; import java.io.File;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.nio.file.NoSuchFileException; import java.nio.file.NoSuchFileException;
import java.util.concurrent.Callable;
import static com.github.stefanbirkner.systemlambda.SystemLambda.withEnvironmentVariable; import static com.github.stefanbirkner.systemlambda.SystemLambda.withEnvironmentVariable;
import static org.hamcrest.CoreMatchers.*; import static org.junit.jupiter.api.Assertions.*;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertThrows;
/** /**
* JUnit test for HTTP Vault connector factory * JUnit test for HTTP Vault connector factory
@ -47,6 +44,35 @@ class HTTPVaultConnectorBuilderTest {
@TempDir @TempDir
File tempDir; File tempDir;
/**
* Test the builder.
*/
@Test
void builderTest() throws Exception {
/* Minimal configuration */
HTTPVaultConnector connector = VaultConnectorBuilder.http().withHost("vault.example.com").build();
assertEquals("https://vault.example.com:8200/v1/", getRequestHelperPrivate(connector, "baseURL"), "URL not set correctly");
assertNull(getRequestHelperPrivate(connector, "trustedCaCert"), "Trusted CA cert set when no cert provided");
assertEquals(0, getRequestHelperPrivate(connector, "retries"), "Number of retries unexpectedly set");
/* Specify all options */
HTTPVaultConnectorBuilder builder = VaultConnectorBuilder.http()
.withHost("vault2.example.com")
.withoutTLS()
.withPort(1234)
.withPrefix("/foo/")
.withTimeout(5678)
.withNumberOfRetries(9);
connector = builder.build();
assertEquals("http://vault2.example.com:1234/foo/", getRequestHelperPrivate(connector, "baseURL"), "URL not set correctly");
assertNull(getRequestHelperPrivate(connector, "trustedCaCert"), "Trusted CA cert set when no cert provided");
assertEquals(9, getRequestHelperPrivate(connector, "retries"), "Unexpected number of retries");
assertEquals(5678, getRequestHelperPrivate(connector, "timeout"), "Number timeout value");
assertThrows(ConnectionException.class, builder::buildAndAuth, "Immediate authentication should throw exception without token");
}
/** /**
* Test building from environment variables * Test building from environment variables
*/ */
@ -60,9 +86,9 @@ class HTTPVaultConnectorBuilderTest {
); );
HTTPVaultConnector connector = builder.build(); HTTPVaultConnector connector = builder.build();
assertThat("URL nor set correctly", getRequestHelperPrivate(connector, "baseURL"), is(equalTo(VAULT_ADDR + "/v1/"))); assertEquals(VAULT_ADDR + "/v1/", getRequestHelperPrivate(connector, "baseURL"), "URL not set correctly");
assertThat("Trusted CA cert set when no cert provided", getRequestHelperPrivate(connector, "trustedCaCert"), is(nullValue())); assertNull(getRequestHelperPrivate(connector, "trustedCaCert"), "Trusted CA cert set when no cert provided");
assertThat("Non-default number of retries, when none set", getRequestHelperPrivate(connector, "retries"), is(0)); assertEquals(0, getRequestHelperPrivate(connector, "retries"), "Non-default number of retries, when none set");
return null; return null;
}); });
@ -75,9 +101,9 @@ class HTTPVaultConnectorBuilderTest {
); );
HTTPVaultConnector connector = builder.build(); HTTPVaultConnector connector = builder.build();
assertThat("URL nor set correctly", getRequestHelperPrivate(connector, "baseURL"), is(equalTo(VAULT_ADDR + "/v1/"))); assertEquals(VAULT_ADDR + "/v1/", getRequestHelperPrivate(connector, "baseURL"), "URL not set correctly");
assertThat("Trusted CA cert set when no cert provided", getRequestHelperPrivate(connector, "trustedCaCert"), is(nullValue())); assertNull(getRequestHelperPrivate(connector, "trustedCaCert"), "Trusted CA cert set when no cert provided");
assertThat("Number of retries not set correctly", getRequestHelperPrivate(connector, "retries"), is(VAULT_MAX_RETRIES)); assertEquals(VAULT_MAX_RETRIES, getRequestHelperPrivate(connector, "retries"), "Number of retries not set correctly");
return null; return null;
}); });
@ -90,8 +116,8 @@ class HTTPVaultConnectorBuilderTest {
() -> VaultConnectorBuilder.http().fromEnv(), () -> VaultConnectorBuilder.http().fromEnv(),
"Creation with unknown cert path failed." "Creation with unknown cert path failed."
); );
assertThat(e.getCause(), is(instanceOf(NoSuchFileException.class))); assertTrue(e.getCause() instanceof NoSuchFileException);
assertThat(((NoSuchFileException) e.getCause()).getFile(), is(VAULT_CACERT)); assertEquals(VAULT_CACERT, ((NoSuchFileException) e.getCause()).getFile());
return null; return null;
}); });
@ -102,7 +128,18 @@ class HTTPVaultConnectorBuilderTest {
() -> VaultConnectorBuilder.http().fromEnv(), () -> VaultConnectorBuilder.http().fromEnv(),
"Factory creation from minimal environment failed" "Factory creation from minimal environment failed"
); );
assertThat("Token nor set correctly", getPrivate(builder, "token"), is(equalTo(VAULT_TOKEN))); assertEquals(VAULT_TOKEN, getPrivate(builder, "token"), "Token not set correctly");
return null;
});
/* Invalid URL */
withVaultEnv("This is not a valid URL!", null, VAULT_MAX_RETRIES.toString(), VAULT_TOKEN).execute(() -> {
assertThrows(
ConnectionException.class,
() -> VaultConnectorBuilder.http().fromEnv(),
"Invalid URL from environment should raise an exception"
);
return null; return null;
}); });
@ -121,7 +158,7 @@ class HTTPVaultConnectorBuilderTest {
private Object getPrivate(Object target, String fieldName) throws NoSuchFieldException, IllegalAccessException { private Object getPrivate(Object target, String fieldName) throws NoSuchFieldException, IllegalAccessException {
Field field = target.getClass().getDeclaredField(fieldName); Field field = target.getClass().getDeclaredField(fieldName);
if (field.isAccessible()) { if (field.canAccess(target)) {
return field.get(target); return field.get(target);
} }
field.setAccessible(true); field.setAccessible(true);