Skip to content

Commit

Permalink
feat: allow insecure TLS when accessing the broker with Maven #1413
Browse files Browse the repository at this point in the history
  • Loading branch information
Ronald Holshausen committed Aug 15, 2021
1 parent 60a6243 commit cf21bb8
Show file tree
Hide file tree
Showing 15 changed files with 128 additions and 52 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ package au.com.dius.pact.core.model

import au.com.dius.pact.core.model.messaging.MessagePact
import au.com.dius.pact.core.pactbroker.PactBrokerClient
import au.com.dius.pact.core.pactbroker.PactBrokerClientConfig
import au.com.dius.pact.core.pactbroker.PactBrokerResult
import au.com.dius.pact.core.pactbroker.util.HttpClientUtils
import au.com.dius.pact.core.pactbroker.util.HttpClientUtils.isJsonResponse
import au.com.dius.pact.core.support.Auth
import au.com.dius.pact.core.support.Utils
import au.com.dius.pact.core.support.CustomServiceUnavailableRetryStrategy
import au.com.dius.pact.core.support.HttpClient
import au.com.dius.pact.core.support.Json
Expand Down Expand Up @@ -40,6 +42,7 @@ import java.net.URI
import java.net.URL
import java.net.URLDecoder
import kotlin.collections.set
import kotlin.text.isNotEmpty

private val logger = KotlinLogging.logger {}

Expand All @@ -52,7 +55,9 @@ fun loadPactFromUrl(
): Pair<JsonValue.Object, PactSource> {
return when (source) {
is BrokerUrlSource -> {
val brokerClient = PactBrokerClient(source.pactBrokerUrl, options.toMutableMap())
val insecureTLS = Utils.lookupInMap(options, "insecureTLS", Boolean::class.java, false)
val brokerClient = PactBrokerClient(source.pactBrokerUrl, options.toMutableMap(),
PactBrokerClientConfig(insecureTLS = insecureTLS))
val pactResponse = brokerClient.fetchPact(source.url, source.encodePath)
pactResponse.pactFile to source.copy(attributes = pactResponse.links, options = options, tag = source.tag)
}
Expand Down Expand Up @@ -352,11 +357,21 @@ object DefaultPactReader : PactReader, KLogging() {
} else if (source is InputStream || source is Reader || source is File) {
return loadPactFromFile(source)
} else if (source is BrokerUrlSource) {
return HttpClient.newHttpClient(options["authentication"], URI(source.pactBrokerUrl)).first.use {
val insecureTLS = Utils.lookupInMap(options, "insecureTLS", Boolean::class.java, false)
return HttpClient.newHttpClient(
options["authentication"],
URI(source.pactBrokerUrl),
insecureTLS = insecureTLS
).first.use {
loadPactFromUrl(source, options, it)
}
} else if (source is PactBrokerResult) {
return HttpClient.newHttpClient(options["authentication"], URI(source.pactBrokerUrl)).first.use {
val insecureTLS = Utils.lookupInMap(options, "insecureTLS", Boolean::class.java, false)
return HttpClient.newHttpClient(
options["authentication"],
URI(source.pactBrokerUrl),
insecureTLS = insecureTLS
).first.use {
loadPactFromUrl(BrokerUrlSource.fromResult(source, options, source.tag), options, it)
}
} else if (source is URL || source is UrlPactSource) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,8 @@ interface IHalClient {
*/
open class HalClient @JvmOverloads constructor(
val baseUrl: String,
var options: Map<String, Any> = mapOf()
var options: Map<String, Any> = mapOf(),
val config: PactBrokerClientConfig
) : IHalClient {

var httpClient: CloseableHttpClient? = null
Expand Down Expand Up @@ -200,7 +201,7 @@ open class HalClient @JvmOverloads constructor(
}
val uri = URI(baseUrl)
val result = HttpClient.newHttpClient(options["authentication"], uri, this.maxPublishRetries,
this.publishRetryInterval)
this.publishRetryInterval, config.insecureTLS)
httpClient = result.first

if (System.getProperty(PREEMPTIVE_AUTHENTICATION) == "true") {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,9 +162,10 @@ interface IPactBrokerClient {
): Result<Boolean, String>
}

data class PactBrokerClientConfig(
data class PactBrokerClientConfig @JvmOverloads constructor(
val retryCountWhileUnknown: Int = 0,
val retryWhileUnknownInterval: Int = 10
val retryWhileUnknownInterval: Int = 10,
val insecureTLS: Boolean = false
)

/**
Expand All @@ -174,10 +175,11 @@ open class PactBrokerClient(
val pactBrokerUrl: String,
@Deprecated("Move use of options to PactBrokerClientConfig")
override val options: MutableMap<String, Any>,
val config: PactBrokerClientConfig = PactBrokerClientConfig()
val config: PactBrokerClientConfig
) : IPactBrokerClient {

constructor(pactBrokerUrl: String) : this(pactBrokerUrl, mutableMapOf())
@Deprecated("Use the version that takes PactBrokerClientConfig")
constructor(pactBrokerUrl: String) : this(pactBrokerUrl, mutableMapOf(), PactBrokerClientConfig())

/**
* Fetches all consumers for the given provider
Expand Down Expand Up @@ -353,7 +355,7 @@ open class PactBrokerClient(
return PactResponse(halDoc, HalClient.asMap(halDoc["_links"].asObject()))
}

open fun newHalClient(): IHalClient = HalClient(pactBrokerUrl, options)
open fun newHalClient(): IHalClient = HalClient(pactBrokerUrl, options, config)

override fun publishVerificationResults(
docAttributes: Map<String, Any?>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class HalClientSpec extends Specification {

def setup() {
mockClient = Mock(CloseableHttpClient)
client = Spy(HalClient, constructorArgs: ['http://localhost:1234/'])
client = Spy(HalClient, constructorArgs: ['http://localhost:1234/', [:], new PactBrokerClientConfig()])
client.pathInfo = null
}

Expand Down Expand Up @@ -499,7 +499,8 @@ class HalClientSpec extends Specification {
@Issue('1399')
def 'navigating with a base URL containing a path'() {
given:
HalClient client = Spy(HalClient, constructorArgs: ['http://localhost:1234/subpath/one/two'])
HalClient client = Spy(HalClient, constructorArgs: ['http://localhost:1234/subpath/one/two', [:],
new PactBrokerClientConfig()])
client.pathInfo = null
client.httpClient = mockClient
def mockResponse = Mock(CloseableHttpResponse) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,22 @@ import mu.KLogging
import org.apache.http.auth.AuthScope
import org.apache.http.auth.UsernamePasswordCredentials
import org.apache.http.client.CredentialsProvider
import org.apache.http.config.RegistryBuilder
import org.apache.http.conn.socket.ConnectionSocketFactory
import org.apache.http.conn.socket.PlainConnectionSocketFactory
import org.apache.http.conn.ssl.NoopHostnameVerifier
import org.apache.http.conn.ssl.SSLConnectionSocketFactory
import org.apache.http.conn.ssl.TrustStrategy
import org.apache.http.impl.client.BasicCredentialsProvider
import org.apache.http.impl.client.CloseableHttpClient
import org.apache.http.impl.client.HttpClientBuilder
import org.apache.http.impl.client.HttpClients
import org.apache.http.impl.client.SystemDefaultCredentialsProvider
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager
import org.apache.http.message.BasicHeader
import org.apache.http.ssl.SSLContextBuilder
import java.net.URI
import java.security.cert.X509Certificate

sealed class Auth {
data class BasicAuthentication(val username: String, val password: String) : Auth()
Expand All @@ -40,7 +49,8 @@ object HttpClient : KLogging() {
authentication: Any?,
uri: URI,
maxPublishRetries: Int = 5,
publishRetryInterval: Int = 3000
publishRetryInterval: Int = 3000,
insecureTLS: Boolean = false
): Pair<CloseableHttpClient, CredentialsProvider?> {
val retryStrategy = CustomServiceUnavailableRetryStrategy(maxPublishRetries, publishRetryInterval)
val builder = HttpClients.custom().useSystemProperties().setServiceUnavailableRetryStrategy(retryStrategy)
Expand Down Expand Up @@ -84,6 +94,11 @@ object HttpClient : KLogging() {
}

builder.setDefaultHeaders(defaultHeaders.map { BasicHeader(it.key, it.value) })

if (insecureTLS) {
setupInsecureTLS(builder)
}

return builder.build() to credsProvider
}

Expand All @@ -99,4 +114,27 @@ object HttpClient : KLogging() {
builder.setDefaultCredentialsProvider(credsProvider)
return credsProvider
}

private fun setupInsecureTLS(builder: HttpClientBuilder) {
logger.warn {
"""
*****************************************************************
Setting Insecure TLS
This will disable hostname validation and trust all certificates!
*****************************************************************
"""
}

val trustStrategy = TrustStrategy { _: Array<X509Certificate>, _: String -> true }
val sslContext = SSLContextBuilder().loadTrustMaterial(null, trustStrategy).build()
builder.setSSLContext(sslContext)
val hostnameVerifier = NoopHostnameVerifier()
val sslSocketFactory = SSLConnectionSocketFactory(sslContext, hostnameVerifier)
val socketFactoryRegistry = RegistryBuilder.create<ConnectionSocketFactory>()
.register("http", PlainConnectionSocketFactory.getSocketFactory())
.register("https", sslSocketFactory)
.build()
val connMgr = PoolingHttpClientConnectionManager(socketFactoryRegistry)
builder.setConnectionManager(connMgr)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ class HttpClientSpec extends Specification {
def authentication = ['bearer', '1234abcd']

when:
def result = HttpClient.INSTANCE.newHttpClient(authentication, uri, 1, 1)
def result = HttpClient.INSTANCE.newHttpClient(authentication, uri, 1, 1, false)
def defaultHeaders = result.component1().closeables[0].this$0.defaultHeaders

then:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package au.com.dius.pact.provider.maven

import au.com.dius.pact.core.pactbroker.PactBrokerClientConfig
import org.apache.maven.plugin.AbstractMojo
import org.apache.maven.plugins.annotations.Component
import org.apache.maven.plugins.annotations.Parameter
Expand Down Expand Up @@ -32,6 +33,15 @@ abstract class PactBaseMojo : AbstractMojo() {
@Component
protected lateinit var decrypter: SettingsDecrypter

@Parameter(property = "retriesWhenUnknown", defaultValue = "0")
private var retriesWhenUnknown: Int? = 0

@Parameter(property = "retryInterval", defaultValue = "10")
private var retryInterval: Int? = 10

@Parameter(property = "pactBrokerInsecureTLS", defaultValue = "false")
private var pactBrokerInsecureTLS: Boolean? = false

protected fun brokerClientOptions(): MutableMap<String, Any> {
val options = mutableMapOf<String, Any>()
if (!pactBrokerToken.isNullOrEmpty()) {
Expand All @@ -49,4 +59,12 @@ abstract class PactBaseMojo : AbstractMojo() {
}
return options
}

protected fun brokerClientConfig(): PactBrokerClientConfig {
return PactBrokerClientConfig(
retriesWhenUnknown ?: 0,
retryInterval ?: 10,
pactBrokerInsecureTLS ?: false
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ data class PactBroker @JvmOverloads constructor(
val authentication: PactBrokerAuth? = null,
val serverId: String? = null,
var enablePending: EnablePending? = null,
val fallbackTag: String? = null
val fallbackTag: String? = null,
val insecureTLS: Boolean? = false
)

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package au.com.dius.pact.provider.maven

import au.com.dius.pact.core.pactbroker.Latest
import au.com.dius.pact.core.pactbroker.PactBrokerClient
import au.com.dius.pact.core.pactbroker.PactBrokerClientConfig
import au.com.dius.pact.core.support.isNotEmpty
import com.github.ajalt.mordant.TermColors
import org.apache.maven.plugin.MojoExecutionException
Expand All @@ -29,12 +28,6 @@ open class PactCanIDeployMojo : PactBaseMojo() {
@Parameter(property = "toTag", defaultValue = "")
private var to: String? = ""

@Parameter(property = "retriesWhenUnknown", defaultValue = "0")
private var retriesWhenUnknown: Int? = 0

@Parameter(property = "retryInterval", defaultValue = "10")
private var retryInterval: Int? = 10

override fun execute() {
val t = TermColors()

Expand Down Expand Up @@ -67,10 +60,6 @@ open class PactCanIDeployMojo : PactBaseMojo() {
}
}

private fun brokerClientConfig(): PactBrokerClientConfig {
return PactBrokerClientConfig(retriesWhenUnknown ?: 0, retryInterval ?: 10)
}

private fun setupLatestParam(): Latest {
var latest: Latest = Latest.UseLatest(false)
if (this.latest.isNotEmpty()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ open class PactCreateVersionTagMojo : PactBaseMojo() {

private fun createBrokerClient() {
if (brokerClient == null)
brokerClient = PactBrokerClient(pactBrokerUrl!!, brokerClientOptions())
brokerClient = PactBrokerClient(pactBrokerUrl!!, brokerClientOptions(), brokerClientConfig())
}

private fun createVersionTag() =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,10 @@ open class PactProviderMojo : PactBaseMojo() {
options["authentication"] = listOf("basic", serverDetails.username, result.server.password)
}

if (pactBroker?.insecureTLS == true) {
options["insecureTLS"] = true
}

when {
pactBroker?.enablePending != null -> {
if (pactBroker.enablePending!!.providerTags.isEmpty()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ open class PactPublishMojo : PactBaseMojo() {
}

if (brokerClient == null) {
brokerClient = PactBrokerClient(pactBrokerUrl!!, brokerClientOptions())
brokerClient = PactBrokerClient(pactBrokerUrl!!, brokerClientOptions(), brokerClientConfig())
}

val pactDirectory = File(pactDirectory)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import au.com.dius.pact.core.model.FileSource
import au.com.dius.pact.core.model.Interaction
import au.com.dius.pact.core.pactbroker.ConsumerVersionSelector
import au.com.dius.pact.core.pactbroker.PactBrokerClient
import au.com.dius.pact.core.pactbroker.PactBrokerClientConfig
import au.com.dius.pact.core.support.Utils
import com.github.michaelbull.result.Err
import com.github.michaelbull.result.Ok
Expand Down Expand Up @@ -99,8 +100,10 @@ open class ProviderInfo @JvmOverloads constructor (
}
}

open fun pactBrokerClient(pactBrokerUrl: String, options: Map<String, Any>) =
PactBrokerClient(pactBrokerUrl, options.toMutableMap())
open fun pactBrokerClient(pactBrokerUrl: String, options: Map<String, Any>): PactBrokerClient {
val insecureTLS = Utils.lookupInMap(options, "insecureTLS", Boolean::class.java, false)
return PactBrokerClient(pactBrokerUrl, options.toMutableMap(), PactBrokerClientConfig(insecureTLS = insecureTLS))
}

@Suppress("TooGenericExceptionThrown")
open fun setupConsumerListFromPactFiles(consumersGroup: ConsumersGroup): MutableList<IConsumerInfo> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import au.com.dius.pact.core.model.Interaction
import au.com.dius.pact.core.model.Pact
import au.com.dius.pact.core.pactbroker.IPactBrokerClient
import au.com.dius.pact.core.pactbroker.PactBrokerClient
import au.com.dius.pact.core.pactbroker.PactBrokerClientConfig
import au.com.dius.pact.core.pactbroker.TestResult
import au.com.dius.pact.core.support.expressions.SystemPropertyResolver
import au.com.dius.pact.core.support.expressions.ValueResolver
Expand Down Expand Up @@ -81,7 +82,8 @@ object DefaultVerificationReporter : VerificationReporter, KLogging() {
): Result<Boolean, List<String>> {
return when (val source = pact.source) {
is BrokerUrlSource -> {
val brokerClient = client ?: PactBrokerClient(source.pactBrokerUrl, source.options.toMutableMap())
val brokerClient = client ?: PactBrokerClient(source.pactBrokerUrl, source.options.toMutableMap(),
PactBrokerClientConfig())
publishResult(brokerClient, source, result, version, pact, tags)
}
else -> {
Expand Down
Loading

0 comments on commit cf21bb8

Please sign in to comment.