HTTPS & TLS
MockServer uses port unification to simplify the configuration so all protocols (i.e. HTTP, HTTPS / SSL, SOCKS, etc) are supported on the same port. This means when a request is sent over TLS (i.e. an HTTPS request) MockServer dynamically detects that the request is encrypted.
MockServer has support for TLS (i.e. HTTPS) in three areas:
- TLS for inbound connections to support HTTPS for mocking, proxying and control-plane interactions (creating expectations, retrieving logs, etc)
- mTLS for inbound connections (also called client authentication or two-way TLS) to authenticate any client sending HTTPS requests
- TLS for outbound connections (also called forward proxy TLS) to authenticate any client sending HTTPS requests
The majority of HTTP clients perform the following steps when making an HTTPS request:
- establish TCP connection to remote server
- perform TLS handshake with remote server and verify trust chain by receiving remote server X.509 Certificate and verifying it is signed by a known Certificate Authority
- perform hostname validation by comparing hostname (or IP address) of remote server with Subject Alternative Name (SAN) or Common Name (CN) on X.509
MockServer is able to mock the behaviour of multiple hostnames (i.e. servers) and present a valid X.509 Certificates for them. MockServer achieves this by dynamically generating its X.509 Certificate using an in-memory list of hostnames and ip addresses, this is described in more detail below.
It is important to ensure that any client calling MockServer over TLS trust MockServer as a Certificate Authority (CA) (i.e. trust the MockServer CA X.509) the different approaches to establishing this trust is described below.
MockServer provides multiple ways its TLS can be configured. The following things can be configured:
- How dynamic certificate are created including, hostname (i.e. CN & SAN) and ip address (i.e. SAN)
- The Certificate Authority X.509 Certificate and Private Key used to sign all generated X.509
- Dynamic creation of a unique (i.e. local) Certificate Authority X509 Certificate and Private Key instead of using the fixed Certificate Authority X509 Certificate and Private Key in the git repo.
- Require mTLS (also called client authentication or two-way TLS) for all TLS connections / HTTPS requests to MockServer
- Configure trust store and client X.509 used during forwarded and proxied requests to endpoints requiring mTLS
Ensure MockServer Certificates Are Trusted
The MockServer CA X.509 must be considered a valid trust root to ensure MockServer's dynamically generate X.509 certificates are trusted by an HTTP Client. This means the CA X.509 needs to be added into the JVM, HTTP Client or operating system as appropriate.
The MockServer CA X.509 can be found (in PEM format) in the MockServer github repo or can be loaded from the classpath location /org/mockserver/socket/CertificateAuthorityCertificate.pem
Operating System
It is possible to add the MockServer CA X.509 as a trusted root CA to your operating system, this will make most clients applications running on your OS (such as browsers) trust dynamically generated certificates from MockServer.
This is only an acceptable risk if it is done for a short period and the configuration setting dynamicallyCreateCertificateAuthorityCertificate is enabled to generate a local unique CA X.509 and Private Key that is saved to your local disk in the folder configured using directoryToSaveDynamicSSLCertificate.
If the configuration setting dynamicallyCreateCertificateAuthorityCertificate is not enabled, and your OS trusts the MockServer CA X.509, then this would leave your machine open to man-in-the-middle attacks because the corresponding Private Key is in the MockServer github repository. This would allow hackers to compromise all sensitive communicates such as to your bank or other sensitive sites.
Web Browsers
Browsers (such as Chrome, Firefox or IE) may not always trust dynamically generated certificates from MockServer because of Certificate Transparency and Public Key Pinning both of which make it hard to dynamically generate certificates that are trusted.
Some sites will work but others (such as google sites) won't work due to certificate pinning.
Browser that rely on Certificate Transparency will likely not trust dynamically generated certificates from MockServer
Java via Classpath
The following code shows how to load a file from the classpath or a relative filesystem location:
public void doSomething() {
String mockServerCA = loadFileFromLocation("/org/mockserver/socket/CertificateAuthorityCertificate.pem");
}
public String loadFileFromLocation(String location) {
location = location.trim().replaceAll("\\\\", "/");
Path path;
if (location.toLowerCase().startsWith("file:")) {
path = Paths.get(URI.create(location));
} else {
path = Paths.get(location);
}
if (Files.exists(path)) {
// org.apache.commons.io.FileUtils
return FileUtils.readFileToString(path.toFile(), "UTF-8");
} else {
return loadFileFromClasspath(location);
}
}
private String loadFileFromClasspath(String location) {
InputStream inputStream = this.getClass().getResourceAsStream(location);
if (inputStream == null) {
inputStream = this.getClass().getClassLoader().getResourceAsStream(location);
}
if (inputStream == null) {
inputStream = ClassLoader.getSystemResourceAsStream(location);
}
if (inputStream != null) {
try {
// org.apache.commons.io.IOUtils
return IOUtils.toString(inputStream, Charsets.UTF_8);
} catch (IOException e) {
throw new RuntimeException("Could not read " + location + " from the classpath", e);
}
}
throw new RuntimeException("Could not find " + location + " on the classpath");
}
Java DefaultSSLSocketFactory
Another mechanism to ensure the MockServer X.509 is trusted is to configure the DefaultSSLSocketFactory in the JVM using the following line:
HttpsURLConnection.setDefaultSSLSocketFactory(new KeyStoreFactory(new MockServerLogger()).sslContext().getSocketFactory());
This can be used in a test case, as follows:
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.mockserver.integration.ClientAndServer;
import org.mockserver.logging.MockServerLogger;
import org.mockserver.socket.PortFactory;
import org.mockserver.socket.tls.KeyStoreFactory;
import javax.net.ssl.HttpsURLConnection;
public class ExampleTestClass {
private static ClientAndServer mockServer;
@BeforeClass
public static void startMockServer() {
// ensure all connection using HTTPS will use the SSL context defined by
// MockServer to allow dynamically generated certificates to be accepted
HttpsURLConnection.setDefaultSSLSocketFactory(new KeyStoreFactory(new MockServerLogger()).sslContext().getSocketFactory());
mockServer = ClientAndServer.startClientAndServer(PortFactory.findFreePort());
}
@AfterClass
public static void stopMockServer() {
mockServer.stop();
}
@Test
public void shouldDoSomething() {
// test system
}
}
Java Keytool
The Java keytool command can also be used to add the MockServer CA X.509 certificate to the list of trust CA Certificates for a JVM, as follows:
keytool -import -v -keystore /usr/lib/jvm/java-8-openjdk-amd64/jre/lib/security/cacerts -alias mockserver-ca -file CertificateAuthorityCertificate.pem -storepass changeit -trustcacerts -noprompt
An example bash script showing how this can be done can be found in the MockServer github repo
Hostname Validation
MockServer is able to mock the behaviour of multiple hostnames (i.e. servers) and present a valid X.509 Certificates for them. MockServer achieves this by dynamically generating its X.509 Certificate using an in-memory list of hostnames and ip addresses. When the list of hostnames or ips addresses changes a new certificate is generated. The list of hostnames is updated, when:
- configuration for SAN hostnames or SAN IP addresses is specified
- an expectation is added containing a Host header with a hostname not seen before
- a request is received containing a Host header with a hostname not seen before
- a TLS handshake using Server Name Indication (SNI) with a hostname not seen before
Note: if a request is received with a Host header for a hostname not seen before the first request will fail validation because the TLS connection has already been established before the Host header can be read, any subsequent requests with that hostname will pass hostname validation.
TLS Configuration:
The domain name for auto-generate TLS certificates
Type: string Default: localhost
Java Code:
ConfigurationProperties.sslCertificateDomainName(String domainName)
System Property:
-Dmockserver.sslCertificateDomainName=...
Environment Variable:
MOCKSERVER_SSL_CERTIFICATE_DOMAIN_NAME=...
Property File:
mockserver.sslCertificateDomainName=...
Example:
-Dmockserver.sslCertificateDomainName="localhost"
The Subject Alternative Name (SAN) domain names for auto-generate TLS certificates as a comma separated list
Type: string Default: localhost
Java Code:
ConfigurationProperties.addSslSubjectAlternativeNameDomains(String... additionalSubjectAlternativeNameDomains)
or
ConfigurationProperties.clearSslSubjectAlternativeNameDomains()
System Property:
-Dmockserver.sslSubjectAlternativeNameDomains=...
Environment Variable:
MOCKSERVER_SSL_SUBJECT_ALTERNATIVE_NAME_DOMAINS=...
Property File:
mockserver.sslSubjectAlternativeNameDomains=...
Example:
-Dmockserver.sslSubjectAlternativeNameDomains="localhost,www.foo.bar"
The Subject Alternative Name (SAN) IP addresses for auto-generate TLS certificates as a comma separated list
Type: string Default: 127.0.0.1,0.0.0.0
Java Code:
ConfigurationProperties.addSslSubjectAlternativeNameIps(String... additionalSubjectAlternativeNameIps)
or
ConfigurationProperties.clearSslSubjectAlternativeNameIps()
System Property:
-Dmockserver.sslSubjectAlternativeNameIps=...
Environment Variable:
MOCKSERVER_SSL_SUBJECT_ALTERNATIVE_NAME_IPS=...
Property File:
mockserver.sslSubjectAlternativeNameIps=...
Example:
-Dmockserver.sslSubjectAlternativeNameIps="127.0.0.1,0.0.0.0"
MockServer dynamically updates the Subject Alternative Name (SAN) values for its TLS certificate to add domain names and IP addresses from request Host headers and Host headers in expectations, this configuration setting disables this automatic update and only uses SAN value provided in TLS Subject Alternative Name Domains and TLS Subject Alternative Name IPs configuration properties.
Type: boolean Default: false
Java Code:
ConfigurationProperties.preventCertificateDynamicUpdate(boolean prevent)
System Property:
-Dmockserver.preventCertificateDynamicUpdate=...
Environment Variable:
MOCKSERVER_PREVENT_CERTIFICATE_DYNAMIC_UPDATE=...
Property File:
mockserver.preventCertificateDynamicUpdate=...
Example:
-Dmockserver.preventCertificateDynamicUpdate="true"
Location of custom file for Certificate Authority for TLS, the private key must be a PKCS#8 PEM file and must match the TLS Certificate Authority X509 Certificate.
To convert a PKCS#1 PEM file (i.e. default for Bouncy Castle) to a PKCS#8 PEM file the following command can be used: openssl pkcs8 -topk8 -inform PEM -in private_key_PKCS_1.pem -out private_key_PKCS_8.pem -nocrypt
Type: string Default: null
Java Code:
ConfigurationProperties.certificateAuthorityPrivateKey(String certificateAuthorityPrivateKey)
System Property:
-Dmockserver.certificateAuthorityPrivateKey=...
Environment Variable:
MOCKSERVER_CERTIFICATE_AUTHORITY_PRIVATE_KEY=...
Property File:
mockserver.certificateAuthorityPrivateKey=...
Example:
-Dmockserver.certificateAuthorityPrivateKey="true"
Location of custom file for Certificate Authority for TLS, the certificate must be a X509 PEM file and must match the TLS Certificate Authority Private Key.
Type: string Default: null
Java Code:
ConfigurationProperties.certificateAuthorityCertificate(String certificateAuthorityCertificate)
System Property:
-Dmockserver.certificateAuthorityCertificate=...
Environment Variable:
MOCKSERVER_CERTIFICATE_AUTHORITY_X509_CERTIFICATE=...
Property File:
mockserver.certificateAuthorityCertificate=...
Example:
-Dmockserver.certificateAuthorityCertificate="true"
Enable dynamic creation of Certificate Authority X509 Certificate and Private Key
Enable this property to increase the security of trusting the MockServer Certificate Authority X509 by ensuring a local dynamic value is used instead of the public value in the MockServer git repo.
These PEM files will be created and saved in the directory specified with configuration property directoryToSaveDynamicSSLCertificate.
A Certificate Authority X509 Certificate and Private Key will only be created if the files used to save them are not already present. Therefore, if MockServer is re-started multiple times with the same value for directoryToSaveDynamicSSLCertificate. the Certificate Authority X509 Certificate and Private Key will only be created once.
Type: boolean Default: false
Java Code:
ConfigurationProperties.dynamicallyCreateCertificateAuthorityCertificate(boolean enable)
System Property:
-Dmockserver.dynamicallyCreateCertificateAuthorityCertificate=...
Environment Variable:
MOCKSERVER_CERTIFICATE_DIRECTORY_TO_SAVE_DYNAMIC_SSL_CERTIFICATE=...
Property File:
mockserver.dynamicallyCreateCertificateAuthorityCertificate=...
Example:
-Dmockserver.dynamicallyCreateCertificateAuthorityCertificate="true"
Directory used to save the dynamically generated Certificate Authority X.509 Certificate and Private Key.
This directory will only be used if MockServer is configured to create a dynamic Certificate Authority X509 certificate and private key using dynamicallyCreateCertificateAuthorityCertificate.
Type: string Default: null
Java Code:
ConfigurationProperties.directoryToSaveDynamicSSLCertificate(String directoryToSaveDynamicSSLCertificate)
System Property:
-Dmockserver.directoryToSaveDynamicSSLCertificate=...
Environment Variable:
MOCKSERVER_CERTIFICATE_DIRECTORY_TO_SAVE_DYNAMIC_SSL_CERTIFICATE=...
Property File:
mockserver.directoryToSaveDynamicSSLCertificate=...
Example:
-Dmockserver.directoryToSaveDynamicSSLCertificate="/some/existing/path"
Require mTLS (also called client authentication and two-way TLS) for all TLS connections / HTTPS requests to MockServer
Type: boolean Default: false
Java Code:
ConfigurationProperties.tlsMutualAuthenticationRequired(boolean enable)
System Property:
-Dmockserver.tlsMutualAuthenticationRequired=...
Environment Variable:
MOCKSERVER_TLS_MUTUAL_AUTHENTICATION_REQUIRED=...
Property File:
mockserver.tlsMutualAuthenticationRequired=...
Example:
-Dmockserver.tlsMutualAuthenticationRequired="true"
File location of custom mTLS (TLS client authentication) X.509 Certificate Chain for Trusting (i.e. signature verification of) Client X.509 Certificates, the certificate chain must be a X509 PEM file.
This certificate chain will be used if MockServer performs mTLS (client authentication) for inbound TLS connections because tlsMutualAuthenticationRequired is enabled
Type: string Default: null
Java Code:
ConfigurationProperties.tlsMutualAuthenticationCertificateChain(String certificateChain)
System Property:
-Dmockserver.tlsMutualAuthenticationCertificateChain=...
Environment Variable:
MOCKSERVER_FORWARD_PROXY_TLS_X509_CERTIFICATE_CHAIN=...
Property File:
mockserver.tlsMutualAuthenticationCertificateChain=...
Example:
-Dmockserver.tlsMutualAuthenticationCertificateChain="/some/existing/path"
Configure trusted set of certificates for forwarded or proxied requests (i.e. TLS connections out of MockServer).
MockServer will only be able to establish a TLS connection to endpoints that have a trusted X509 certificate according to the trust manager type, as follows:
- ALL - Insecure will trust all X509 certificates and not perform host name verification.
- JVM - Will trust all X509 certificates trust by the JVM.
- CUSTOM - Will trust all X509 certificates specified in forwardProxyTLSCustomTrustX509Certificates configuration value.
Type: string Default: ALL
Java Code:
ConfigurationProperties.forwardProxyTLSX509CertificatesTrustManagerType(String trustManagerType)
System Property:
-Dmockserver.forwardProxyTLSX509CertificatesTrustManagerType=...
Environment Variable:
MOCKSERVER_FORWARD_PROXY_TLS_X509_CERTIFICATES_TRUST_MANAGER_TYPE=...
Property File:
mockserver.forwardProxyTLSX509CertificatesTrustManagerType=...
Example:
-Dmockserver.forwardProxyTLSX509CertificatesTrustManagerType="CUSTOM"
File location of custom file for trusted X509 Certificate Authority roots for forwarded or proxied requests (i.e. TLS connections out of MockServer), the certificate chain must be a X509 PEM file.
MockServer will only be able to establish a TLS connection to endpoints that have an X509 certificate chain that is signed by one of the provided custom certificates, i.e. where a path can be established from the endpoints X509 certificate to one or more of the custom X509 certificates provided.
This configuration only take effect if forwardProxyTLSX509CertificatesTrustManagerType is configured as CUSTOM otherwise this value is ignored.
Type: string Default: null
Java Code:
ConfigurationProperties.forwardProxyTLSCustomTrustX509Certificates(String customX509Certificates)
System Property:
-Dmockserver.forwardProxyTLSCustomTrustX509Certificates=...
Environment Variable:
MOCKSERVER_FORWARD_PROXY_TLS_CUSTOM_TRUST_X509_CERTIFICATES=...
Property File:
mockserver.forwardProxyTLSCustomTrustX509Certificates=...
Example:
-Dmockserver.forwardProxyTLSCustomTrustX509Certificates="/some/existing/path"
File location of custom Private Key for forwarded or proxied requests (i.e. TLS connections out of MockServer), the private key must be a PKCS#8 PEM file and must match the forwardProxyCertificateChain
To convert a PKCS#1 (i.e. default for Bouncy Castle) to a PKCS#8 the following command can be used: openssl pkcs8 -topk8 -inform PEM -in private_key_PKCS_1.pem -out private_key_PKCS_8.pem -nocrypt
This private key will be used if MockServer needs to perform mTLS (client authentication) for outbound TLS connections.
Type: string Default: null
Java Code:
ConfigurationProperties.forwardProxyPrivateKey(String privateKey)
System Property:
-Dmockserver.forwardProxyPrivateKey=...
Environment Variable:
MOCKSERVER_FORWARD_PROXY_TLS_PRIVATE_KEY=...
Property File:
mockserver.forwardProxyPrivateKey=...
Example:
-Dmockserver.forwardProxyPrivateKey="/some/existing/path"
File location of custom X.509 Certificate Chain for forwarded or proxied requests (i.e. TLS connections out of MockServer), the certificates must be a X509 PEM file and must match the forwardProxyPrivateKey
This certificate chain will be used if MockServer needs to perform mTLS (client authentication) for outbound TLS connections.
Type: string Default: null
Java Code:
ConfigurationProperties.forwardProxyCertificateChain(String certificateChain)
System Property:
-Dmockserver.forwardProxyCertificateChain=...
Environment Variable:
MOCKSERVER_FORWARD_PROXY_TLS_X509_CERTIFICATE_CHAIN=...
Property File:
mockserver.forwardProxyCertificateChain=...
Example:
-Dmockserver.forwardProxyCertificateChain="/some/existing/path"