diff --git a/mockserver-api/src/main/xsd/pl/touk/mockserver/api/common.xsd b/mockserver-api/src/main/xsd/pl/touk/mockserver/api/common.xsd
index ac21246..953b839 100644
--- a/mockserver-api/src/main/xsd/pl/touk/mockserver/api/common.xsd
+++ b/mockserver-api/src/main/xsd/pl/touk/mockserver/api/common.xsd
@@ -18,5 +18,13 @@
+
+
+
+
+
+
+
+
diff --git a/mockserver-api/src/main/xsd/pl/touk/mockserver/api/request.xsd b/mockserver-api/src/main/xsd/pl/touk/mockserver/api/request.xsd
index 6636b53..23786bc 100644
--- a/mockserver-api/src/main/xsd/pl/touk/mockserver/api/request.xsd
+++ b/mockserver-api/src/main/xsd/pl/touk/mockserver/api/request.xsd
@@ -20,6 +20,7 @@
+
diff --git a/mockserver-tests/src/test/groovy/pl/touk/mockserver/tests/MockServerHttpsTest.groovy b/mockserver-tests/src/test/groovy/pl/touk/mockserver/tests/MockServerHttpsTest.groovy
new file mode 100644
index 0000000..91b851a
--- /dev/null
+++ b/mockserver-tests/src/test/groovy/pl/touk/mockserver/tests/MockServerHttpsTest.groovy
@@ -0,0 +1,80 @@
+package pl.touk.mockserver.tests
+
+import groovy.util.slurpersupport.GPathResult
+import org.apache.http.client.methods.CloseableHttpResponse
+import org.apache.http.client.methods.HttpPost
+import org.apache.http.conn.ssl.SSLConnectionSocketFactory
+import org.apache.http.conn.ssl.SSLContexts
+import org.apache.http.entity.ContentType
+import org.apache.http.entity.StringEntity
+import org.apache.http.impl.client.CloseableHttpClient
+import org.apache.http.impl.client.HttpClients
+import pl.touk.mockserver.api.common.Https
+import pl.touk.mockserver.api.request.AddMock
+import pl.touk.mockserver.client.RemoteMockServer
+import pl.touk.mockserver.client.Util
+import pl.touk.mockserver.server.HttpMockServer
+import spock.lang.Shared
+import spock.lang.Specification
+
+import javax.net.ssl.SSLContext
+import java.security.KeyStore
+
+class MockServerHttpsTest extends Specification {
+
+ RemoteMockServer remoteMockServer
+
+ HttpMockServer httpMockServer
+
+ @Shared
+ SSLContext sslContext = SSLContexts.custom()
+ .loadTrustMaterial(trustStore())
+ .build()
+
+ @Shared
+ CloseableHttpClient client = HttpClients.custom()
+ .setHostnameVerifier(SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER)
+ .setSslcontext(sslContext)
+ .build()
+
+ def setup() {
+ httpMockServer = new HttpMockServer(19000)
+ remoteMockServer = new RemoteMockServer('localhost', 19000)
+ }
+
+ def cleanup() {
+ httpMockServer.stop()
+ }
+
+ def 'should handle HTTPS server' () {
+ expect:
+ remoteMockServer.addMock(new AddMock(
+ name: 'testHttps',
+ path: 'testEndpoint',
+ port: 10443,
+ predicate: '''{req -> req.xml.name() == 'request'}''',
+ response: '''{req -> ""}''',
+ https: new Https(
+ keyPassword: 'changeit',
+ keystorePassword: 'changeit',
+ keystorePath: MockServerHttpsTest.classLoader.getResource('keystore.jks').path
+ ),
+ soap: false
+ ))
+ when:
+ HttpPost restPost = new HttpPost('https://localhost:10443/testEndpoint')
+ restPost.entity = new StringEntity('', ContentType.create("text/xml", "UTF-8"))
+ CloseableHttpResponse response = client.execute(restPost)
+ then:
+ GPathResult restPostResponse = Util.extractXmlResponse(response)
+ restPostResponse.name() == 'goodResponse-request'
+ and:
+ remoteMockServer.removeMock('testHttps')?.size() == 1
+ }
+
+ private KeyStore trustStore() {
+ KeyStore truststore = KeyStore.getInstance(KeyStore.defaultType)
+ truststore.load(new FileInputStream(MockServerHttpsTest.classLoader.getResource('truststore.jks').path), "changeit".toCharArray());
+ return truststore
+ }
+}
diff --git a/mockserver-tests/src/test/resources/keystore.jks b/mockserver-tests/src/test/resources/keystore.jks
new file mode 100644
index 0000000..d5e35d1
Binary files /dev/null and b/mockserver-tests/src/test/resources/keystore.jks differ
diff --git a/mockserver/src/main/groovy/pl/touk/mockserver/server/HttpMockServer.groovy b/mockserver/src/main/groovy/pl/touk/mockserver/server/HttpMockServer.groovy
index 082593a..859b712 100644
--- a/mockserver/src/main/groovy/pl/touk/mockserver/server/HttpMockServer.groovy
+++ b/mockserver/src/main/groovy/pl/touk/mockserver/server/HttpMockServer.groovy
@@ -2,6 +2,7 @@ package pl.touk.mockserver.server
import com.sun.net.httpserver.HttpExchange
import groovy.util.logging.Slf4j
+import pl.touk.mockserver.api.common.Https
import pl.touk.mockserver.api.common.ImportAlias
import pl.touk.mockserver.api.common.Method
import pl.touk.mockserver.api.request.AddMock
@@ -41,7 +42,7 @@ class HttpMockServer {
HttpMockServer(int port = 9999, ConfigObject initialConfiguration = new ConfigObject(), int threads = 10) {
executor = Executors.newFixedThreadPool(threads)
- httpServerWrapper = new HttpServerWrapper(port, executor)
+ httpServerWrapper = new HttpServerWrapper(port, executor, null)
initialConfiguration.values()?.each { ConfigObject co ->
addMock(co)
@@ -108,7 +109,7 @@ class HttpMockServer {
throw new RuntimeException('mock already registered')
}
Mock mock = mockFromRequest(request)
- HttpServerWrapper child = getOrCreateChildServer(mock.port)
+ HttpServerWrapper child = getOrCreateChildServer(mock.port, mock.https)
child.addMock(mock)
saveConfiguration(request)
mockNames << name
@@ -121,7 +122,7 @@ class HttpMockServer {
throw new RuntimeException('mock already registered')
}
Mock mock = mockFromConfig(co)
- HttpServerWrapper child = getOrCreateChildServer(mock.port)
+ HttpServerWrapper child = getOrCreateChildServer(mock.port, null)
child.addMock(mock)
configuration.put(name, co)
mockNames << name
@@ -156,6 +157,7 @@ class HttpMockServer {
mock.responseHeaders = request.responseHeaders
mock.schema = request.schema
mock.preserveHistory = request.preserveHistory != false
+ mock.https = request.https
return mock
}
@@ -173,10 +175,10 @@ class HttpMockServer {
return mock
}
- private HttpServerWrapper getOrCreateChildServer(int mockPort) {
+ private HttpServerWrapper getOrCreateChildServer(int mockPort, Https https) {
HttpServerWrapper child = childServers[mockPort]
if (!child) {
- child = new HttpServerWrapper(mockPort, executor)
+ child = new HttpServerWrapper(mockPort, executor, https)
childServers.put(mockPort, child)
}
return child
diff --git a/mockserver/src/main/groovy/pl/touk/mockserver/server/HttpServerWrapper.groovy b/mockserver/src/main/groovy/pl/touk/mockserver/server/HttpServerWrapper.groovy
index 6f8f9f4..9121c6b 100644
--- a/mockserver/src/main/groovy/pl/touk/mockserver/server/HttpServerWrapper.groovy
+++ b/mockserver/src/main/groovy/pl/touk/mockserver/server/HttpServerWrapper.groovy
@@ -2,9 +2,17 @@ package pl.touk.mockserver.server
import com.sun.net.httpserver.HttpHandler
import com.sun.net.httpserver.HttpServer
+import com.sun.net.httpserver.HttpsConfigurator
+import com.sun.net.httpserver.HttpsServer
import groovy.transform.PackageScope
import groovy.util.logging.Slf4j
+import pl.touk.mockserver.api.common.Https
+import javax.net.ssl.KeyManagerFactory
+import javax.net.ssl.SSLContext
+import javax.net.ssl.TrustManager
+import java.security.KeyStore
+import java.security.SecureRandom
import java.util.concurrent.Executor
@Slf4j
@@ -15,16 +23,37 @@ class HttpServerWrapper {
private List executors = []
- HttpServerWrapper(int port, Executor executor) {
+ HttpServerWrapper(int port, Executor executor, Https https) {
this.port = port
InetSocketAddress addr = new InetSocketAddress(Inet4Address.getByName("0.0.0.0"), port)
- httpServer = HttpServer.create(addr, 0)
+ httpServer = buildServer(addr, https)
httpServer.executor = executor
log.info("Http server starting on port $port...")
httpServer.start()
log.info('Http server is started')
}
+ private HttpServer buildServer(InetSocketAddress addr, Https https) {
+ if (https) {
+ HttpsServer httpsServer = HttpsServer.create(addr, 0)
+ httpsServer.httpsConfigurator = new HttpsConfigurator(buildSslContext(https))
+ return httpsServer
+ } else {
+ return HttpServer.create(addr, 0)
+ }
+ }
+
+ private SSLContext buildSslContext(Https https) {
+ KeyStore keyStore = KeyStore.getInstance(KeyStore.defaultType)
+ keyStore.load(new FileInputStream(https.keystorePath), https.keystorePassword.toCharArray())
+ KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.defaultAlgorithm)
+ kmf.init(keyStore, https.keyPassword.toCharArray())
+
+ SSLContext ssl = SSLContext.getInstance('TLSv1')
+ ssl.init(kmf.keyManagers, [] as TrustManager[], new SecureRandom())
+ return ssl
+ }
+
void createContext(String context, HttpHandler handler) {
httpServer.createContext(context, handler)
}
diff --git a/mockserver/src/main/groovy/pl/touk/mockserver/server/Mock.groovy b/mockserver/src/main/groovy/pl/touk/mockserver/server/Mock.groovy
index ed37f89..e132ac9 100644
--- a/mockserver/src/main/groovy/pl/touk/mockserver/server/Mock.groovy
+++ b/mockserver/src/main/groovy/pl/touk/mockserver/server/Mock.groovy
@@ -5,6 +5,7 @@ import groovy.transform.PackageScope
import groovy.util.logging.Slf4j
import org.codehaus.groovy.control.CompilerConfiguration
import org.codehaus.groovy.control.customizers.ImportCustomizer
+import pl.touk.mockserver.api.common.Https
import pl.touk.mockserver.api.common.Method
import javax.xml.XMLConstants
@@ -35,6 +36,7 @@ class Mock implements Comparable {
private Validator validator
Map imports = [:]
boolean preserveHistory = true
+ Https https
Mock(String name, String path, int port) {
if (!(name)) {