Add https publishing

Change-Id: I7611b7379c0f42d02342adc1eec56c0d79caa432
This commit is contained in:
Piotr Fus 2018-01-29 20:26:55 +01:00
parent 96a294828b
commit 0323749ff4
7 changed files with 129 additions and 7 deletions

View file

@ -18,5 +18,13 @@
<xs:attribute name="alias" type="xs:string"/> <xs:attribute name="alias" type="xs:string"/>
<xs:attribute name="fullClassName" type="xs:string"/> <xs:attribute name="fullClassName" type="xs:string"/>
</xs:complexType> </xs:complexType>
<xs:complexType name="https">
<xs:sequence>
<xs:element name="keystorePath" type="xs:string" />
<xs:element name="keystorePassword" type="xs:string" />
<xs:element name="keyPassword" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:schema> </xs:schema>

View file

@ -20,6 +20,7 @@
<xs:element name="soap" type="xs:boolean" minOccurs="0"/> <xs:element name="soap" type="xs:boolean" minOccurs="0"/>
<xs:element name="statusCode" type="xs:int" minOccurs="0"/> <xs:element name="statusCode" type="xs:int" minOccurs="0"/>
<xs:element name="method" type="common:method" minOccurs="0"/> <xs:element name="method" type="common:method" minOccurs="0"/>
<xs:element name="https" type="common:https" minOccurs="0" />
<xs:element name="responseHeaders" type="xs:string" minOccurs="0"/> <xs:element name="responseHeaders" type="xs:string" minOccurs="0"/>
<xs:element name="schema" type="xs:string" minOccurs="0"/> <xs:element name="schema" type="xs:string" minOccurs="0"/>
<xs:element name="imports" type="common:importAlias" minOccurs="0" maxOccurs="unbounded"/> <xs:element name="imports" type="common:importAlias" minOccurs="0" maxOccurs="unbounded"/>

View file

@ -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 -> "<goodResponse-${req.xml.name()}/>"}''',
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('<request/>', 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
}
}

Binary file not shown.

View file

@ -2,6 +2,7 @@ package pl.touk.mockserver.server
import com.sun.net.httpserver.HttpExchange import com.sun.net.httpserver.HttpExchange
import groovy.util.logging.Slf4j 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.ImportAlias
import pl.touk.mockserver.api.common.Method import pl.touk.mockserver.api.common.Method
import pl.touk.mockserver.api.request.AddMock import pl.touk.mockserver.api.request.AddMock
@ -41,7 +42,7 @@ class HttpMockServer {
HttpMockServer(int port = 9999, ConfigObject initialConfiguration = new ConfigObject(), int threads = 10) { HttpMockServer(int port = 9999, ConfigObject initialConfiguration = new ConfigObject(), int threads = 10) {
executor = Executors.newFixedThreadPool(threads) executor = Executors.newFixedThreadPool(threads)
httpServerWrapper = new HttpServerWrapper(port, executor) httpServerWrapper = new HttpServerWrapper(port, executor, null)
initialConfiguration.values()?.each { ConfigObject co -> initialConfiguration.values()?.each { ConfigObject co ->
addMock(co) addMock(co)
@ -108,7 +109,7 @@ class HttpMockServer {
throw new RuntimeException('mock already registered') throw new RuntimeException('mock already registered')
} }
Mock mock = mockFromRequest(request) Mock mock = mockFromRequest(request)
HttpServerWrapper child = getOrCreateChildServer(mock.port) HttpServerWrapper child = getOrCreateChildServer(mock.port, mock.https)
child.addMock(mock) child.addMock(mock)
saveConfiguration(request) saveConfiguration(request)
mockNames << name mockNames << name
@ -121,7 +122,7 @@ class HttpMockServer {
throw new RuntimeException('mock already registered') throw new RuntimeException('mock already registered')
} }
Mock mock = mockFromConfig(co) Mock mock = mockFromConfig(co)
HttpServerWrapper child = getOrCreateChildServer(mock.port) HttpServerWrapper child = getOrCreateChildServer(mock.port, null)
child.addMock(mock) child.addMock(mock)
configuration.put(name, co) configuration.put(name, co)
mockNames << name mockNames << name
@ -156,6 +157,7 @@ class HttpMockServer {
mock.responseHeaders = request.responseHeaders mock.responseHeaders = request.responseHeaders
mock.schema = request.schema mock.schema = request.schema
mock.preserveHistory = request.preserveHistory != false mock.preserveHistory = request.preserveHistory != false
mock.https = request.https
return mock return mock
} }
@ -173,10 +175,10 @@ class HttpMockServer {
return mock return mock
} }
private HttpServerWrapper getOrCreateChildServer(int mockPort) { private HttpServerWrapper getOrCreateChildServer(int mockPort, Https https) {
HttpServerWrapper child = childServers[mockPort] HttpServerWrapper child = childServers[mockPort]
if (!child) { if (!child) {
child = new HttpServerWrapper(mockPort, executor) child = new HttpServerWrapper(mockPort, executor, https)
childServers.put(mockPort, child) childServers.put(mockPort, child)
} }
return child return child

View file

@ -2,9 +2,17 @@ package pl.touk.mockserver.server
import com.sun.net.httpserver.HttpHandler import com.sun.net.httpserver.HttpHandler
import com.sun.net.httpserver.HttpServer import com.sun.net.httpserver.HttpServer
import com.sun.net.httpserver.HttpsConfigurator
import com.sun.net.httpserver.HttpsServer
import groovy.transform.PackageScope import groovy.transform.PackageScope
import groovy.util.logging.Slf4j 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 import java.util.concurrent.Executor
@Slf4j @Slf4j
@ -15,16 +23,37 @@ class HttpServerWrapper {
private List<ContextExecutor> executors = [] private List<ContextExecutor> executors = []
HttpServerWrapper(int port, Executor executor) { HttpServerWrapper(int port, Executor executor, Https https) {
this.port = port this.port = port
InetSocketAddress addr = new InetSocketAddress(Inet4Address.getByName("0.0.0.0"), port) InetSocketAddress addr = new InetSocketAddress(Inet4Address.getByName("0.0.0.0"), port)
httpServer = HttpServer.create(addr, 0) httpServer = buildServer(addr, https)
httpServer.executor = executor httpServer.executor = executor
log.info("Http server starting on port $port...") log.info("Http server starting on port $port...")
httpServer.start() httpServer.start()
log.info('Http server is started') 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) { void createContext(String context, HttpHandler handler) {
httpServer.createContext(context, handler) httpServer.createContext(context, handler)
} }

View file

@ -5,6 +5,7 @@ import groovy.transform.PackageScope
import groovy.util.logging.Slf4j import groovy.util.logging.Slf4j
import org.codehaus.groovy.control.CompilerConfiguration import org.codehaus.groovy.control.CompilerConfiguration
import org.codehaus.groovy.control.customizers.ImportCustomizer import org.codehaus.groovy.control.customizers.ImportCustomizer
import pl.touk.mockserver.api.common.Https
import pl.touk.mockserver.api.common.Method import pl.touk.mockserver.api.common.Method
import javax.xml.XMLConstants import javax.xml.XMLConstants
@ -35,6 +36,7 @@ class Mock implements Comparable<Mock> {
private Validator validator private Validator validator
Map<String, String> imports = [:] Map<String, String> imports = [:]
boolean preserveHistory = true boolean preserveHistory = true
Https https
Mock(String name, String path, int port) { Mock(String name, String path, int port) {
if (!(name)) { if (!(name)) {