From a6933224ef4bf6425670ff62067c47b7fafd942c Mon Sep 17 00:00:00 2001 From: Isabek Tashiev Date: Mon, 17 Aug 2020 23:35:57 +0300 Subject: [PATCH 1/2] Accept SSL certificates by providing a URL to use cert from within a jar [resolves #313] --- .../PostgresqlConnectionConfiguration.java | 40 ++++++++++++------- .../PostgresqlConnectionFactoryProvider.java | 11 ++--- .../java/io/r2dbc/postgresql/util/Assert.java | 20 ++++++++++ .../ReactorNettyClientIntegrationTests.java | 4 +- .../util/PostgresqlServerExtension.java | 29 +++++--------- 5 files changed, 64 insertions(+), 40 deletions(-) diff --git a/src/main/java/io/r2dbc/postgresql/PostgresqlConnectionConfiguration.java b/src/main/java/io/r2dbc/postgresql/PostgresqlConnectionConfiguration.java index bc874035..390a1821 100644 --- a/src/main/java/io/r2dbc/postgresql/PostgresqlConnectionConfiguration.java +++ b/src/main/java/io/r2dbc/postgresql/PostgresqlConnectionConfiguration.java @@ -34,7 +34,9 @@ import javax.net.ssl.HostnameVerifier; import java.io.File; +import java.net.MalformedURLException; import java.net.Socket; +import java.net.URL; import java.time.Duration; import java.util.ArrayList; import java.util.Collections; @@ -331,12 +333,12 @@ public static final class Builder { private String socket; @Nullable - private String sslCert = null; + private URL sslCert = null; private HostnameVerifier sslHostnameVerifier = DefaultHostnameVerifier.INSTANCE; @Nullable - private String sslKey = null; + private URL sslKey = null; private SSLMode sslMode = SSLMode.DISABLE; @@ -344,7 +346,7 @@ public static final class Builder { private CharSequence sslPassword = null; @Nullable - private String sslRootCert = null; + private URL sslRootCert = null; private Function sslContextBuilderCustomizer = Function.identity(); @@ -637,8 +639,8 @@ public Builder sslContextBuilderCustomizer(Function createSslProvider() { SslContextBuilder sslContextBuilder = SslContextBuilder.forClient(); if (this.sslMode.verifyCertificate()) { if (this.sslRootCert != null) { - sslContextBuilder.trustManager(new File(this.sslRootCert)); + sslContextBuilder.trustManager(new File(this.sslRootCert.getFile())); } } else { sslContextBuilder.trustManager(InsecureTrustManagerFactory.INSTANCE); } - String sslKey = this.sslKey; - String sslCert = this.sslCert; + URL sslKey = this.sslKey; + URL sslCert = this.sslCert; // Emulate Libpq behavior // Determining the default file location @@ -801,20 +803,28 @@ private Supplier createSslProvider() { if (sslCert == null) { String pathname = defaultDir + "postgresql.crt"; if (new File(pathname).exists()) { - sslCert = pathname; + try { + sslCert = new URL(pathname); + } catch (MalformedURLException e) { + throw new RuntimeException(e); + } } } if (sslKey == null) { String pathname = defaultDir + "postgresql.pk8"; if (new File(pathname).exists()) { - sslKey = pathname; + try { + sslKey = new URL(pathname); + } catch (MalformedURLException e) { + throw new RuntimeException(e); + } } } if (sslKey != null && sslCert != null) { String sslPassword = this.sslPassword == null ? null : this.sslPassword.toString(); - sslContextBuilder.keyManager(new File(sslCert), new File(sslKey), sslPassword); + sslContextBuilder.keyManager(new File(sslCert.getFile()), new File(sslKey.getFile()), sslPassword); } return () -> SslProvider.builder() diff --git a/src/main/java/io/r2dbc/postgresql/PostgresqlConnectionFactoryProvider.java b/src/main/java/io/r2dbc/postgresql/PostgresqlConnectionFactoryProvider.java index 459fb6a1..b2fd5e00 100644 --- a/src/main/java/io/r2dbc/postgresql/PostgresqlConnectionFactoryProvider.java +++ b/src/main/java/io/r2dbc/postgresql/PostgresqlConnectionFactoryProvider.java @@ -26,6 +26,7 @@ import io.r2dbc.spi.Option; import javax.net.ssl.HostnameVerifier; +import java.net.URL; import java.util.LinkedHashMap; import java.util.Map; import java.util.function.Function; @@ -107,9 +108,9 @@ public final class PostgresqlConnectionFactoryProvider implements ConnectionFact public static final Option> SSL_CONTEXT_BUILDER_CUSTOMIZER = Option.valueOf("sslContextBuilderCustomizer"); /** - * Full path for the certificate file. + * File path for the certificate file. */ - public static final Option SSL_CERT = Option.valueOf("sslCert"); + public static final Option SSL_CERT = Option.valueOf("sslCert"); /** * Class name of hostname verifier. Defaults to {@link DefaultHostnameVerifier}. @@ -119,7 +120,7 @@ public final class PostgresqlConnectionFactoryProvider implements ConnectionFact /** * Full path for the key file. */ - public static final Option SSL_KEY = Option.valueOf("sslKey"); + public static final Option SSL_KEY = Option.valueOf("sslKey"); /** * Ssl mode. Default: disabled @@ -132,9 +133,9 @@ public final class PostgresqlConnectionFactoryProvider implements ConnectionFact public static final Option SSL_PASSWORD = Option.valueOf("sslPassword"); /** - * File name of the SSL root certificate. + * File path of the SSL root certificate. */ - public static final Option SSL_ROOT_CERT = Option.valueOf("sslRootCert"); + public static final Option SSL_ROOT_CERT = Option.valueOf("sslRootCert"); /** * Enable TCP KeepAlive. diff --git a/src/main/java/io/r2dbc/postgresql/util/Assert.java b/src/main/java/io/r2dbc/postgresql/util/Assert.java index 09ec36f7..7ca73a8e 100644 --- a/src/main/java/io/r2dbc/postgresql/util/Assert.java +++ b/src/main/java/io/r2dbc/postgresql/util/Assert.java @@ -19,6 +19,7 @@ import reactor.util.annotation.Nullable; import java.io.File; +import java.net.URL; /** * Assertion library for the implementation. @@ -147,4 +148,23 @@ public static void isTrue(boolean expression, String message) { } } + /** + * Checks that the provided URL exists or null. + * + * @param url url to check + * @param message the message to use in exception if type is not as required + * @return existing url + * @throws IllegalArgumentException if {@code value} is not of the required type + * @throws IllegalArgumentException if {@code value}, {@code type}, or {@code message} is {@code null} + */ + public static URL requireUrlExistsOrNull(@Nullable URL url, String message) { + if (url == null) { + throw new IllegalArgumentException(message); + } + if (!new File(url.getFile()).exists()) { + throw new IllegalArgumentException(message); + } + return url; + } + } diff --git a/src/test/java/io/r2dbc/postgresql/client/ReactorNettyClientIntegrationTests.java b/src/test/java/io/r2dbc/postgresql/client/ReactorNettyClientIntegrationTests.java index cce3c76c..ebd73d4b 100644 --- a/src/test/java/io/r2dbc/postgresql/client/ReactorNettyClientIntegrationTests.java +++ b/src/test/java/io/r2dbc/postgresql/client/ReactorNettyClientIntegrationTests.java @@ -727,8 +727,8 @@ void verifyCa() { void verifyCaWithCustomizer() { client( c -> c.sslContextBuilderCustomizer(sslContextBuilder -> { - return sslContextBuilder.trustManager(new File(SERVER.getServerCrt())) - .keyManager(new File(SERVER.getClientCrt()), new File(SERVER.getClientKey())); + return sslContextBuilder.trustManager(new File(SERVER.getServerCrt().getFile())) + .keyManager(new File(SERVER.getClientCrt().getFile()), new File(SERVER.getClientKey().getFile())); }) .sslMode(SSLMode.VERIFY_CA), c -> c diff --git a/src/test/java/io/r2dbc/postgresql/util/PostgresqlServerExtension.java b/src/test/java/io/r2dbc/postgresql/util/PostgresqlServerExtension.java index bfbd5d30..acfe573a 100644 --- a/src/test/java/io/r2dbc/postgresql/util/PostgresqlServerExtension.java +++ b/src/test/java/io/r2dbc/postgresql/util/PostgresqlServerExtension.java @@ -33,10 +33,7 @@ import java.io.File; import java.io.FileReader; import java.io.IOException; -import java.net.URISyntaxException; import java.net.URL; -import java.nio.file.Path; -import java.nio.file.Paths; import java.util.Properties; import java.util.function.Supplier; @@ -134,12 +131,12 @@ private void initializeConnectors() { this.jdbcOperations = new JdbcTemplate(this.dataSource); } - public String getClientCrt() { - return getResourcePath("client.crt").toAbsolutePath().toString(); + public URL getClientCrt() { + return getResourceUrl("client.crt"); } - public String getClientKey() { - return getResourcePath("client.key").toAbsolutePath().toString(); + public URL getClientKey() { + return getResourceUrl("client.key"); } public PostgresqlConnectionConfiguration.Builder configBuilder() { @@ -171,12 +168,12 @@ public int getPort() { return this.postgres.getPort(); } - public String getServerCrt() { - return getResourcePath("server.crt").toAbsolutePath().toString(); + public URL getServerCrt() { + return getResourceUrl("server.crt"); } - public String getServerKey() { - return getResourcePath("server.key").toAbsolutePath().toString(); + public URL getServerKey() { + return getResourceUrl("server.key"); } public String getUsername() { @@ -207,22 +204,18 @@ private > T container() { return container; } - private Path getResourcePath(String name) { + private URL getResourceUrl(String name) { URL resource = getClass().getClassLoader().getResource(name); if (resource == null) { throw new IllegalStateException("Resource not found: " + name); } - try { - return Paths.get(resource.toURI()); - } catch (URISyntaxException e) { - throw new IllegalStateException("Cannot convert to path for: " + name, e); - } + return resource; } private MountableFile getHostPath(String name, int mode) { - return forHostPath(getResourcePath(name), mode); + return forHostPath(getResourceUrl(name).getPath(), mode); } /** From ad39491be9e51c6c5f959be5eb78be88da431ac3 Mon Sep 17 00:00:00 2001 From: Isabek Tashiev Date: Sat, 7 Nov 2020 13:46:25 +0200 Subject: [PATCH 2/2] Accept SSL certificates by providing a URL to use cert from within a jar [resolves #313] --- .../PostgresqlConnectionConfiguration.java | 42 ++++++------- .../PostgresqlConnectionFactoryProvider.java | 6 +- .../java/io/r2dbc/postgresql/util/Assert.java | 53 ++++++++-------- ...resqlConnectionConfigurationUnitTests.java | 60 +++++++++++++++++++ ...sqlConnectionFactoryProviderUnitTests.java | 35 +++++++++++ .../ReactorNettyClientIntegrationTests.java | 20 +++++-- .../util/PostgresqlServerExtension.java | 41 +++++++++---- 7 files changed, 194 insertions(+), 63 deletions(-) diff --git a/src/main/java/io/r2dbc/postgresql/PostgresqlConnectionConfiguration.java b/src/main/java/io/r2dbc/postgresql/PostgresqlConnectionConfiguration.java index 390a1821..938349ef 100644 --- a/src/main/java/io/r2dbc/postgresql/PostgresqlConnectionConfiguration.java +++ b/src/main/java/io/r2dbc/postgresql/PostgresqlConnectionConfiguration.java @@ -639,8 +639,8 @@ public Builder sslContextBuilderCustomizer(Function createSslProvider() { if (sslCert == null) { String pathname = defaultDir + "postgresql.crt"; - if (new File(pathname).exists()) { - try { - sslCert = new URL(pathname); - } catch (MalformedURLException e) { - throw new RuntimeException(e); - } - } + sslCert = getUrlFromPath(pathname); } if (sslKey == null) { String pathname = defaultDir + "postgresql.pk8"; - if (new File(pathname).exists()) { - try { - sslKey = new URL(pathname); - } catch (MalformedURLException e) { - throw new RuntimeException(e); - } - } + sslKey = getUrlFromPath(pathname); } if (sslKey != null && sslCert != null) { @@ -833,6 +821,20 @@ private Supplier createSslProvider() { .build(); } + private URL getUrlFromPath(String pathname) { + final File file = new File(pathname); + + if (file.exists()) { + try { + return file.toURI().toURL(); + } catch (MalformedURLException e) { + throw new IllegalArgumentException(String.format("Malformed error occurred during creating URL from %s", pathname)); + } + } + + return null; + } + } static class FixedFetchSize implements ToIntFunction { diff --git a/src/main/java/io/r2dbc/postgresql/PostgresqlConnectionFactoryProvider.java b/src/main/java/io/r2dbc/postgresql/PostgresqlConnectionFactoryProvider.java index b2fd5e00..31ebcc8a 100644 --- a/src/main/java/io/r2dbc/postgresql/PostgresqlConnectionFactoryProvider.java +++ b/src/main/java/io/r2dbc/postgresql/PostgresqlConnectionFactoryProvider.java @@ -110,7 +110,7 @@ public final class PostgresqlConnectionFactoryProvider implements ConnectionFact /** * File path for the certificate file. */ - public static final Option SSL_CERT = Option.valueOf("sslCert"); + public static final Option SSL_CERT = Option.valueOf("sslCert"); /** * Class name of hostname verifier. Defaults to {@link DefaultHostnameVerifier}. @@ -120,7 +120,7 @@ public final class PostgresqlConnectionFactoryProvider implements ConnectionFact /** * Full path for the key file. */ - public static final Option SSL_KEY = Option.valueOf("sslKey"); + public static final Option SSL_KEY = Option.valueOf("sslKey"); /** * Ssl mode. Default: disabled @@ -135,7 +135,7 @@ public final class PostgresqlConnectionFactoryProvider implements ConnectionFact /** * File path of the SSL root certificate. */ - public static final Option SSL_ROOT_CERT = Option.valueOf("sslRootCert"); + public static final Option SSL_ROOT_CERT = Option.valueOf("sslRootCert"); /** * Enable TCP KeepAlive. diff --git a/src/main/java/io/r2dbc/postgresql/util/Assert.java b/src/main/java/io/r2dbc/postgresql/util/Assert.java index 7ca73a8e..fce81da3 100644 --- a/src/main/java/io/r2dbc/postgresql/util/Assert.java +++ b/src/main/java/io/r2dbc/postgresql/util/Assert.java @@ -19,6 +19,7 @@ import reactor.util.annotation.Nullable; import java.io.File; +import java.net.MalformedURLException; import java.net.URL; /** @@ -26,6 +27,8 @@ */ public final class Assert { + private static final String CLASSPATH_PREFIX = "classpath:"; + private Assert() { } @@ -115,25 +118,6 @@ public static T requireType(Object value, Class type, String message) { return (T) value; } - /** - * Checks that the provided file exists or null. - * - * @param file file to check - * @param message the message to use in exception if type is not as required - * @return existing file or null - * @throws IllegalArgumentException if {@code value} is not of the required type - * @throws IllegalArgumentException if {@code value}, {@code type}, or {@code message} is {@code null} - */ - public static String requireFileExistsOrNull(@Nullable String file, String message) { - if (file == null) { - throw new IllegalArgumentException(message); - } - if (!new File(file).exists()) { - throw new IllegalArgumentException(message); - } - return file; - } - /** * Assert a boolean expression, throwing an {@link IllegalArgumentException} * if the expression evaluates to {@code false}. @@ -151,19 +135,40 @@ public static void isTrue(boolean expression, String message) { /** * Checks that the provided URL exists or null. * - * @param url url to check + * @param path path to check * @param message the message to use in exception if type is not as required * @return existing url * @throws IllegalArgumentException if {@code value} is not of the required type * @throws IllegalArgumentException if {@code value}, {@code type}, or {@code message} is {@code null} */ - public static URL requireUrlExistsOrNull(@Nullable URL url, String message) { - if (url == null) { + public static URL requireUrlExistsOrNull(@Nullable String path, String message) { + if (path == null) { throw new IllegalArgumentException(message); } - if (!new File(url.getFile()).exists()) { - throw new IllegalArgumentException(message); + + if (path.startsWith(CLASSPATH_PREFIX)) { + path = path.substring(CLASSPATH_PREFIX.length()); } + + ClassLoader classLoader = Assert.class.getClassLoader(); + URL url = classLoader != null ? classLoader.getResource(path) : ClassLoader.getSystemResource(path); + + if (url == null) { + File file = new File(path); + + if (file.exists()) { + try { + url = file.toURI().toURL(); + } catch (MalformedURLException ignored) { + + } + } + } + + if (url == null) { + throw new IllegalArgumentException(String.format("URL resource %s does not exist", path)); + } + return url; } diff --git a/src/test/java/io/r2dbc/postgresql/PostgresqlConnectionConfigurationUnitTests.java b/src/test/java/io/r2dbc/postgresql/PostgresqlConnectionConfigurationUnitTests.java index 3a08c16f..a45b55f8 100644 --- a/src/test/java/io/r2dbc/postgresql/PostgresqlConnectionConfigurationUnitTests.java +++ b/src/test/java/io/r2dbc/postgresql/PostgresqlConnectionConfigurationUnitTests.java @@ -172,4 +172,64 @@ void constructorNoSslCustomizer() { .withMessage("sslContextBuilderCustomizer must not be null"); } + @Test + void constructorNoSslCert() { + assertThatIllegalArgumentException().isThrownBy(() -> PostgresqlConnectionConfiguration.builder() + .host("test-host") + .password("test-password") + .sslCert(null) + .build()) + .withMessage("sslCert must not be null"); + } + + @Test + void constructorNotExistSslCert() { + assertThatIllegalArgumentException().isThrownBy(() -> PostgresqlConnectionConfiguration.builder() + .host("test-host") + .password("test-password") + .sslCert("no-client.crt") + .build()) + .withMessage("URL resource no-client.crt does not exist"); + } + + @Test + void constructorNoSslKey() { + assertThatIllegalArgumentException().isThrownBy(() -> PostgresqlConnectionConfiguration.builder() + .host("test-host") + .password("test-password") + .sslKey(null) + .build()) + .withMessage("sslKey must not be null"); + } + + @Test + void constructorNotExistSslKey() { + assertThatIllegalArgumentException().isThrownBy(() -> PostgresqlConnectionConfiguration.builder() + .host("test-host") + .password("test-password") + .sslKey("no-client.key") + .build()) + .withMessage("URL resource no-client.key does not exist"); + } + + @Test + void constructorNullSslRootCert() { + assertThatIllegalArgumentException().isThrownBy(() -> PostgresqlConnectionConfiguration.builder() + .host("test-host") + .password("test-password") + .sslRootCert(null) + .build()) + .withMessage("sslRootCert must not be null"); + } + + @Test + void constructorNotExistSslRootCert() { + assertThatIllegalArgumentException().isThrownBy(() -> PostgresqlConnectionConfiguration.builder() + .host("test-host") + .password("test-password") + .sslRootCert("no-server.crt") + .build()) + .withMessage("URL resource no-server.crt does not exist"); + } + } diff --git a/src/test/java/io/r2dbc/postgresql/PostgresqlConnectionFactoryProviderUnitTests.java b/src/test/java/io/r2dbc/postgresql/PostgresqlConnectionFactoryProviderUnitTests.java index efa9278c..417c1068 100644 --- a/src/test/java/io/r2dbc/postgresql/PostgresqlConnectionFactoryProviderUnitTests.java +++ b/src/test/java/io/r2dbc/postgresql/PostgresqlConnectionFactoryProviderUnitTests.java @@ -35,8 +35,11 @@ import static io.r2dbc.postgresql.PostgresqlConnectionFactoryProvider.POSTGRESQL_DRIVER; import static io.r2dbc.postgresql.PostgresqlConnectionFactoryProvider.PREPARED_STATEMENT_CACHE_QUERIES; import static io.r2dbc.postgresql.PostgresqlConnectionFactoryProvider.SOCKET; +import static io.r2dbc.postgresql.PostgresqlConnectionFactoryProvider.SSL_CERT; import static io.r2dbc.postgresql.PostgresqlConnectionFactoryProvider.SSL_CONTEXT_BUILDER_CUSTOMIZER; +import static io.r2dbc.postgresql.PostgresqlConnectionFactoryProvider.SSL_KEY; import static io.r2dbc.postgresql.PostgresqlConnectionFactoryProvider.SSL_MODE; +import static io.r2dbc.postgresql.PostgresqlConnectionFactoryProvider.SSL_ROOT_CERT; import static io.r2dbc.postgresql.PostgresqlConnectionFactoryProvider.TCP_KEEPALIVE; import static io.r2dbc.postgresql.PostgresqlConnectionFactoryProvider.TCP_NODELAY; import static io.r2dbc.spi.ConnectionFactoryOptions.DRIVER; @@ -151,6 +154,38 @@ void supportsSsl() { assertThat(sslConfig.getSslMode()).isEqualTo(SSLMode.VERIFY_FULL); } + @Test + void supportsSslCertificates() { + PostgresqlConnectionFactory factory = this.provider.create(builder() + .option(DRIVER, POSTGRESQL_DRIVER) + .option(HOST, "test-host") + .option(PASSWORD, "test-password") + .option(USER, "test-user") + .option(SSL, true) + .option(SSL_KEY, "client.key") + .option(SSL_CERT, "client.crt") + .option(SSL_ROOT_CERT, "server.crt") + .build()); + + assertThat(factory).isNotNull(); + } + + @Test + void supportsSslCertificatesByClasspath() { + PostgresqlConnectionFactory factory = this.provider.create(builder() + .option(DRIVER, POSTGRESQL_DRIVER) + .option(HOST, "test-host") + .option(PASSWORD, "test-password") + .option(USER, "test-user") + .option(SSL, true) + .option(SSL_KEY, "classpath:client.key") + .option(SSL_CERT, "classpath:client.crt") + .option(SSL_ROOT_CERT, "classpath:server.crt") + .build()); + + assertThat(factory).isNotNull(); + } + @Test void supportsSslMode() { PostgresqlConnectionFactory factory = this.provider.create(builder() diff --git a/src/test/java/io/r2dbc/postgresql/client/ReactorNettyClientIntegrationTests.java b/src/test/java/io/r2dbc/postgresql/client/ReactorNettyClientIntegrationTests.java index ebd73d4b..495cc184 100644 --- a/src/test/java/io/r2dbc/postgresql/client/ReactorNettyClientIntegrationTests.java +++ b/src/test/java/io/r2dbc/postgresql/client/ReactorNettyClientIntegrationTests.java @@ -684,6 +684,20 @@ void require() { .verifyComplete()); } + @Test + void requireCertificatesWithClasspath() { + client( + c -> c + .sslMode(SSLMode.REQUIRE) + .sslRootCert("classpath:server.crt") + .sslKey("classpath:client.key") + .sslCert("classpath:client.crt"), + c -> c + .as(StepVerifier::create) + .expectNextCount(1) + .verifyComplete()); + } + @Test void requireConnectsWithoutCertificate() { client( @@ -726,10 +740,8 @@ void verifyCa() { @Test void verifyCaWithCustomizer() { client( - c -> c.sslContextBuilderCustomizer(sslContextBuilder -> { - return sslContextBuilder.trustManager(new File(SERVER.getServerCrt().getFile())) - .keyManager(new File(SERVER.getClientCrt().getFile()), new File(SERVER.getClientKey().getFile())); - }) + c -> c.sslContextBuilderCustomizer(sslContextBuilder -> sslContextBuilder.trustManager(SERVER.getServerCrtFile()) + .keyManager(SERVER.getClientCrtFile(), SERVER.getClientKeyFile())) .sslMode(SSLMode.VERIFY_CA), c -> c .as(StepVerifier::create) diff --git a/src/test/java/io/r2dbc/postgresql/util/PostgresqlServerExtension.java b/src/test/java/io/r2dbc/postgresql/util/PostgresqlServerExtension.java index acfe573a..38e19361 100644 --- a/src/test/java/io/r2dbc/postgresql/util/PostgresqlServerExtension.java +++ b/src/test/java/io/r2dbc/postgresql/util/PostgresqlServerExtension.java @@ -131,14 +131,6 @@ private void initializeConnectors() { this.jdbcOperations = new JdbcTemplate(this.dataSource); } - public URL getClientCrt() { - return getResourceUrl("client.crt"); - } - - public URL getClientKey() { - return getResourceUrl("client.key"); - } - public PostgresqlConnectionConfiguration.Builder configBuilder() { return PostgresqlConnectionConfiguration.builder().database(getDatabase()).host(getHost()).port(getPort()).username(getUsername()).password(getPassword()); } @@ -168,12 +160,37 @@ public int getPort() { return this.postgres.getPort(); } - public URL getServerCrt() { - return getResourceUrl("server.crt"); + public String getClientCrt() { + return "client.crt"; + } + + public String getClientKey() { + return "client.key"; + } + + public String getServerCrt() { + return "server.crt"; + } + + public File getClientKeyFile() { + return getFile("client.key"); + } + + public File getServerCrtFile() { + return getFile("server.crt"); + } + + public File getClientCrtFile() { + return getFile("client.crt"); + } + + private File getFile(String filepath) { + final URL resourceUrl = getResourceUrl(filepath); + return new File(resourceUrl.getFile()); } - public URL getServerKey() { - return getResourceUrl("server.key"); + public String getServerKey() { + return "server.key"; } public String getUsername() {