#234 mutual tls

Merged tommysitu
Coverage Reach
core/Hoverfly.java core/model/Request.java core/model/Response.java core/model/RequestFieldMatcher.java core/model/RequestDetails.java core/model/HoverflyMetaData.java core/model/Simulation.java core/model/JournalEntry.java core/model/DelaySettings.java core/model/Journal.java core/model/RequestResponsePair.java core/model/HoverflyData.java core/model/GlobalActions.java core/config/HoverflyConfiguration.java core/config/LocalHoverflyConfig.java core/config/HoverflyConfigValidator.java core/config/RemoteHoverflyConfig.java core/config/LogLevel.java core/config/LocalMiddleware.java core/SslConfigurer.java core/TempFileManager.java core/ProxyConfigurer.java core/SimulationSource.java core/SystemConfigFactory.java core/LoggingOutputStream.java core/HoverflyConfig.java core/HoverflyUtils.java core/SystemConfig.java core/HoverflyMode.java core/SystemInfo.java api/OkHttpHoverflyClient.java api/view/HoverflyInfoView.java api/view/ResponseDiffForRequestView.java api/view/DiffReport.java api/view/SimpleRequestDefinitionView.java api/view/StateView.java api/view/DiffReportEntry.java api/view/DiffView.java api/command/ModeCommand.java api/command/SortParams.java api/command/DestinationCommand.java api/command/JournalSearchCommand.java api/model/ModeArguments.java api/HoverflyClient.java api/AuthHeaderInterceptor.java api/HoverflyClientException.java dsl/StubServiceBuilder.java dsl/RequestMatcherBuilder.java dsl/matchers/HoverflyMatchers.java dsl/ResponseBuilder.java dsl/SingleQuoteHttpBodyConverter.java dsl/HttpBodyConverter.java dsl/ResponseCreators.java dsl/AbstractDelaySettingsBuilder.java dsl/StubServiceDelaySettingsBuilder.java dsl/ResponseDelaySettingsBuilder.java dsl/HoverflyDsl.java dsl/HoverflyDslException.java rule/HoverflyRule.java rule/NoDiffAssertionRule.java rule/HoverflyRuleUtils.java verification/HoverflyVerifications.java verification/VerificationUtils.java verification/VerificationData.java verification/HoverflyVerificationError.java

No flags found

Use flags to group coverage reports by test type, project and/or folders.
Then setup custom commit statuses and notifications for each flag.

e.g., #unittest #integration

#production #enterprise

#frontend #backend

Learn more about Codecov Flags here.


@@ -14,21 +14,20 @@
Loading
14 14
15 15
import io.specto.hoverfly.junit.core.Hoverfly;
16 16
import io.specto.hoverfly.junit.core.HoverflyConfig;
17 -
import org.slf4j.Logger;
18 -
import org.slf4j.LoggerFactory;
19 -
20 17
import java.net.InetSocketAddress;
21 18
import java.util.Arrays;
22 19
import java.util.LinkedList;
23 20
import java.util.List;
21 +
import org.slf4j.Logger;
22 +
import org.slf4j.LoggerFactory;
24 23
25 24
/**
26 25
 * Config builder interface for settings specific to {@link Hoverfly} managed internally
27 26
 */
28 27
public class LocalHoverflyConfig extends HoverflyConfig {
29 28
30 29
    private String caCertPath;
31 -
    private String caCertKeyPath;
30 +
    private String caKeyPath;
32 31
    private boolean tlsVerificationDisabled;
33 32
    private boolean plainHttpTunneling;
34 33
    private LocalMiddleware localMiddleware;
@@ -37,6 +36,10 @@
Loading
37 36
    private LogLevel logLevel;
38 37
    private List<String> commands = new LinkedList<>();
39 38
    private String binaryLocation;
39 +
    private String clientCertPath;
40 +
    private String clientKeyPath;
41 +
    private String clientAuthDestination;
42 +
    private String clientCaCertPath;
40 43
41 44
    /**
42 45
     * Sets the certificate file to override the default Hoverfly's CA cert
@@ -58,7 +61,7 @@
Loading
58 61
     */
59 62
    @Deprecated
60 63
    public LocalHoverflyConfig sslKeyPath(String sslKeyPath) {
61 -
        this.caCertKeyPath = sslKeyPath;
64 +
        this.caKeyPath = sslKeyPath;
62 65
        return this;
63 66
    }
64 67
@@ -68,9 +71,9 @@
Loading
68 71
     * @param keyPath key file in classpath. Must be any PEM encoded key, with .key or .pem extensions
69 72
     * @return the {@link LocalHoverflyConfig} for further customizations
70 73
     */
71 -
    public LocalHoverflyConfig caCert(String certPath, String keyPath) {
74 +
    public LocalHoverflyConfig overrideDefaultCaCert(String certPath, String keyPath) {
72 75
        this.caCertPath = certPath;
73 -
        this.caCertKeyPath = keyPath;
76 +
        this.caKeyPath = keyPath;
74 77
        return this;
75 78
    }
76 79
@@ -107,7 +110,7 @@
Loading
107 110
    /**
108 111
     * Set upstream proxy for hoverfly to connect to target host
109 112
     * @param proxyAddress socket address of the upstream proxy, eg. 127.0.0.1:8500
110 -
     * @return the {@link HoverflyConfig} for further customizations
113 +
     * @return the {@link LocalHoverflyConfig} for further customizations
111 114
     */
112 115
    public LocalHoverflyConfig upstreamProxy(InetSocketAddress proxyAddress) {
113 116
        this.upstreamProxy = proxyAddress.getHostString() + ":" + proxyAddress.getPort();
@@ -122,7 +125,7 @@
Loading
122 125
    /**
123 126
     * Set the name of the logger to use when logging the output of the Hoverfly binary.
124 127
     * @param loggerName Name of the logger to use when logging the output of the Hoverfly binary.
125 -
     * @return the {@link HoverflyConfig} for further customizations
128 +
     * @return the {@link LocalHoverflyConfig} for further customizations
126 129
     */
127 130
    public LocalHoverflyConfig logger(final String loggerName) {
128 131
        this.hoverflyLogger = LoggerFactory.getLogger(loggerName);
@@ -131,7 +134,7 @@
Loading
131 134
132 135
    /**
133 136
     * Change the Hoverfly binary to output directly to {@link System#out}.
134 -
     * @return the {@link HoverflyConfig} for further customizations
137 +
     * @return the {@link LocalHoverflyConfig} for further customizations
135 138
     */
136 139
    public LocalHoverflyConfig logToStdOut() {
137 140
        this.hoverflyLogger = null;
@@ -141,7 +144,7 @@
Loading
141 144
    /**
142 145
     * Set the log level of Hoverfly. The default level is INFO.
143 146
     * @param logLevel {@link LogLevel} to set
144 -
     * @return the {@link HoverflyConfig} for further customizations
147 +
     * @return the {@link LocalHoverflyConfig} for further customizations
145 148
     */
146 149
    public LocalHoverflyConfig logLevel(LogLevel logLevel) {
147 150
        this.logLevel = logLevel;
@@ -151,32 +154,66 @@
Loading
151 154
    /**
152 155
     * Set additional commands for starting Hoverfly.
153 156
     * @param commands More Hoverfly command flags.
154 -
     * @return the {@link HoverflyConfig} for further customizations
157 +
     * @return the {@link LocalHoverflyConfig} for further customizations
155 158
     */
156 159
    public LocalHoverflyConfig addCommands(String... commands) {
157 160
158 161
        this.commands.addAll(Arrays.asList(commands));
159 162
        return this;
160 163
    }
161 164
165 +
    public HoverflyConfig binaryLocation(String binaryLocation) {
166 +
        this.binaryLocation = binaryLocation;
167 +
        return this;
168 +
    }
169 +
170 +
    /**
171 +
     * Set client certificate and key for mutual TLS authentication with target server
172 +
     * @param clientCertPath certificate file in classpath. Must be a PEM encoded certificate, with .crt or .pem extensions
173 +
     * @param clientKeyPath key file in classpath. Must be unencrypted and PEM encoded key, with .key or .pem extensions
174 +
     * @param destinations the destination filter to what target urls to enable mutual TLS authentication. Enable for all remote hosts if not provided.
175 +
     * @return the {@link LocalHoverflyConfig} for further customizations
176 +
     */
177 +
    public LocalHoverflyConfig enableClientAuth(String clientCertPath, String clientKeyPath, String... destinations) {
178 +
        this.clientCertPath = clientCertPath;
179 +
        this.clientKeyPath = clientKeyPath;
180 +
        if (destinations != null) {
181 +
            if (destinations.length == 0) {
182 +
                this.clientAuthDestination = ".";
183 +
            } else {
184 +
                this.clientAuthDestination = String.join("|", destinations);
185 +
            }
186 +
        }
187 +
        return this;
188 +
    }
189 +
190 +
    /**
191 +
     * Set client CA certificate for mutual TLS authentication
192 +
     * @param clientCaCertPath CA certificate file in classpath. Must be any PEM encoded certificate, with .crt or .pem extensions
193 +
     * @return the {@link LocalHoverflyConfig} for further customizations
194 +
     */
195 +
    public LocalHoverflyConfig clientAuthCaCertPath(String clientCaCertPath) {
196 +
        this.clientCaCertPath = clientCaCertPath;
197 +
        return this;
198 +
    }
199 +
162 200
    @Override
163 201
    public HoverflyConfiguration build() {
164 202
        HoverflyConfiguration configs = new HoverflyConfiguration(proxyPort, adminPort, proxyLocalHost, destination,
165 203
                proxyCaCert, captureHeaders, webServer, hoverflyLogger, logLevel, statefulCapture, incrementalCapture, simulationPreprocessor);
166 204
        configs.setSslCertificatePath(caCertPath);
167 -
        configs.setSslKeyPath(caCertKeyPath);
205 +
        configs.setSslKeyPath(caKeyPath);
168 206
        configs.setTlsVerificationDisabled(tlsVerificationDisabled);
169 207
        configs.setPlainHttpTunneling(plainHttpTunneling);
170 208
        configs.setLocalMiddleware(localMiddleware);
171 209
        configs.setUpstreamProxy(upstreamProxy);
172 210
        configs.setCommands(commands);
173 211
        configs.setBinaryLocation(binaryLocation);
212 +
        configs.setClientCertPath(clientCertPath);
213 +
        configs.setClientKeyPath(clientKeyPath);
214 +
        configs.setClientAuthDestination(clientAuthDestination);
215 +
        configs.setClientCaCertPath(clientCaCertPath);
174 216
        HoverflyConfigValidator validator = new HoverflyConfigValidator();
175 217
        return validator.validate(configs);
176 218
    }
177 -
178 -
    public HoverflyConfig binaryLocation(String binaryLocation) {
179 -
        this.binaryLocation = binaryLocation;
180 -
        return this;
181 -
    }
182 219
}

@@ -70,7 +70,6 @@
Loading
70 70
/**
71 71
 * A wrapper class for the Hoverfly binary.  Manage the lifecycle of the processes, and then manage Hoverfly itself by using it's API endpoints.
72 72
 */
73 -
// TODO extract interface and create LocalHoverfly and RemoteHoverfly
74 73
public class Hoverfly implements AutoCloseable {
75 74
76 75
    private static final Logger LOGGER = LoggerFactory.getLogger(Hoverfly.class);
@@ -195,6 +194,26 @@
Loading
195 194
            commands.add("-key");
196 195
            commands.add("ca.key");
197 196
        }
197 +
198 +
        if (hoverflyConfig.isClientAuthEnabled()) {
199 +
            tempFileManager.copyClassPathResource(hoverflyConfig.getClientCertPath(), "client-auth.crt");
200 +
            tempFileManager.copyClassPathResource(hoverflyConfig.getClientKeyPath(), "client-auth.key");
201 +
            commands.add("-client-authentication-client-cert");
202 +
            commands.add("client-auth.crt");
203 +
204 +
            commands.add("-client-authentication-client-key");
205 +
            commands.add("client-auth.key");
206 +
207 +
            commands.add("-client-authentication-destination");
208 +
            commands.add(hoverflyConfig.getClientAuthDestination());
209 +
210 +
            if (StringUtils.isNotBlank(hoverflyConfig.getClientCaCertPath())) {
211 +
                tempFileManager.copyClassPathResource(hoverflyConfig.getClientCaCertPath(), "client-ca.crt");
212 +
                commands.add("-client-authentication-ca-cert");
213 +
                commands.add("client-ca.crt");
214 +
            }
215 +
        }
216 +
198 217
        if (hoverflyConfig.isPlainHttpTunneling()) {
199 218
            commands.add("-plain-http-tunneling");
200 219
        }

@@ -45,8 +45,16 @@
Loading
45 45
            boolean isKeyBlank = StringUtils.isBlank(hoverflyConfig.getSslKeyPath());
46 46
            boolean isCertBlank = StringUtils.isBlank(hoverflyConfig.getSslCertificatePath());
47 47
            if (isKeyBlank && !isCertBlank || !isKeyBlank && isCertBlank) {
48 -
                throw new IllegalArgumentException("Both SSL key and certificate files are required to override the default Hoverfly SSL.");
48 +
                throw new IllegalArgumentException("Both ca cert and key files are required to override the default Hoverfly ca cert.");
49 49
            }
50 +
51 +
            // Validate client auth cert and key
52 +
            boolean isClientKeyBlank = StringUtils.isBlank(hoverflyConfig.getClientKeyPath());
53 +
            boolean isClientCertBlank = StringUtils.isBlank(hoverflyConfig.getClientCertPath());
54 +
            if (isClientKeyBlank && !isClientCertBlank || !isClientKeyBlank && isClientCertBlank) {
55 +
                throw new IllegalArgumentException("Both client cert and key files are required to enable mutual TLS authentication.");
56 +
            }
57 +
50 58
            // Validate proxy port
51 59
            if (hoverflyConfig.getProxyPort() == 0) {
52 60
                hoverflyConfig.setProxyPort(findUnusedPort());

@@ -41,6 +41,10 @@
Loading
41 41
    private String binaryNameFormat;
42 42
    private List<String> commands;
43 43
    private String binaryLocation;
44 +
    private String clientCertPath;
45 +
    private String clientKeyPath;
46 +
    private String clientAuthDestination;
47 +
    private String clientCaCertPath;
44 48
45 49
    /**
46 50
     * Create configurations for external hoverfly
@@ -295,4 +299,40 @@
Loading
295 299
    public String getBinaryLocation() {
296 300
        return binaryLocation;
297 301
    }
302 +
303 +
    public String getClientCertPath() {
304 +
        return clientCertPath;
305 +
    }
306 +
307 +
    public void setClientCertPath(String clientCertPath) {
308 +
        this.clientCertPath = clientCertPath;
309 +
    }
310 +
311 +
    public String getClientKeyPath() {
312 +
        return clientKeyPath;
313 +
    }
314 +
315 +
    public void setClientKeyPath(String clientKeyPath) {
316 +
        this.clientKeyPath = clientKeyPath;
317 +
    }
318 +
319 +
    public String getClientAuthDestination() {
320 +
        return clientAuthDestination;
321 +
    }
322 +
323 +
    public void setClientAuthDestination(String clientAuthDestination) {
324 +
        this.clientAuthDestination = clientAuthDestination;
325 +
    }
326 +
327 +
    public String getClientCaCertPath() {
328 +
        return clientCaCertPath;
329 +
    }
330 +
331 +
    public void setClientCaCertPath(String clientCaCertPath) {
332 +
        this.clientCaCertPath = clientCaCertPath;
333 +
    }
334 +
335 +
    public boolean isClientAuthEnabled() {
336 +
        return isNotBlank(clientCertPath) && isNotBlank(clientKeyPath) && isNotBlank(clientAuthDestination);
337 +
    }
298 338
}

@@ -65,7 +65,7 @@
Loading
65 65
    }
66 66
67 67
    /**
68 -
     * Sets the JVM trust store so Hoverfly's SSL certificate is trusted
68 +
     * Sets the JVM trust store so Hoverfly's CA certificate is trusted
69 69
     */
70 70
    void setDefaultSslContext(String pemFilename) {
71 71
        setDefaultSslContext(findResourceOnClasspath(pemFilename));
@@ -82,7 +82,7 @@
Loading
82 82
            SSLContext.setDefault(sslContext);
83 83
            HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
84 84
        } catch (Exception e) {
85 -
            throw new IllegalStateException("Failed to set SSLContext from hoverfly certificate " + pemFile.toString(), e);
85 +
            throw new IllegalStateException("Failed to import Hoverfly certificate '" + pemFile.toString() + "' into keystore", e);
86 86
        }
87 87
    }
88 88

Learn more Showing 1 files with coverage changes found.

Changes in src/main/java/io/specto/hoverfly/junit/core/config/LocalHoverflyConfig.java
-2
+2
Loading file...
Files Complexity Coverage
src/main/java/io/specto/hoverfly/junit +22.00% 83.68% 0.02% 85.21%
Project Totals (65 files) 83.68% 85.21%
Loading