Skip to content

Commit

Permalink
fix: default headers were being added twice to requests to the pact b…
Browse files Browse the repository at this point in the history
…roker #1242
  • Loading branch information
Ronald Holshausen committed Nov 6, 2020
1 parent a648c7a commit 940fc83
Show file tree
Hide file tree
Showing 9 changed files with 71 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -352,11 +352,11 @@ 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), mutableMapOf()).first.use {
return HttpClient.newHttpClient(options["authentication"], URI(source.pactBrokerUrl)).first.use {
loadPactFromUrl(source, options, it)
}
} else if (source is PactBrokerResult) {
return HttpClient.newHttpClient(options["authentication"], URI(source.pactBrokerUrl), mutableMapOf()).first.use {
return HttpClient.newHttpClient(options["authentication"], URI(source.pactBrokerUrl)).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 @@ -196,8 +196,8 @@ open class HalClient @JvmOverloads constructor(
HttpClient.logger.warn { "Authentication options needs to be a list of values, ignoring." }
}
val uri = URI(baseUrl)
val result = HttpClient.newHttpClient(options["authentication"], uri, defaultHeaders,
this.maxPublishRetries, this.publishRetryInterval)
val result = HttpClient.newHttpClient(options["authentication"], uri, this.maxPublishRetries,
this.publishRetryInterval)
httpClient = result.first

if (System.getProperty(PREEMPTIVE_AUTHENTICATION) == "true") {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,13 @@ object HttpClientUtils {
}

fun pathCombiner(builder: URIBuilder, url: String): URI {
return if (builder.getPath() != null) {
builder.setPath(builder.getPath() + url).build()
val path = builder.path
return if (path != null) {
if (path.endsWith("/") && url.startsWith("/")) {
builder.setPath(path.trimEnd('/') + url).build()
} else {
builder.setPath(path + url).build()
}
} else {
builder.setPath(url).build()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,11 @@ import org.apache.http.HttpHost
import org.apache.http.HttpResponse
import org.apache.http.ProtocolVersion
import org.apache.http.client.methods.CloseableHttpResponse
import org.apache.http.client.methods.HttpGet
import org.apache.http.client.methods.HttpPost
import org.apache.http.entity.ContentType
import org.apache.http.entity.StringEntity
import org.apache.http.impl.client.BasicCredentialsProvider
import org.apache.http.impl.client.CloseableHttpClient
import org.apache.http.impl.client.SystemDefaultCredentialsProvider
import org.apache.http.message.BasicHeader
import org.apache.http.message.BasicStatusLine
import spock.lang.Shared
Expand Down Expand Up @@ -67,21 +65,6 @@ class HalClientSpec extends Specification {
client.httpContext == null
}

def 'For bearer token authentication scheme adds an authorization header to all requests'() {
given:
client.options = [authentication: ['bearer', '1234']]

when:
client.setupHttpClient()
def request = client.initialiseRequest(new HttpGet('/'))

then:
client.httpClient.credentialsProvider instanceof SystemDefaultCredentialsProvider
client.httpContext == null
client.defaultHeaders == [Authorization: 'Bearer 1234']
request.getFirstHeader('Authorization').value == 'Bearer 1234'
}

@RestoreSystemProperties
def 'populates the auth cache if preemptive authentication system property is enabled'() {
given:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,4 @@ class HttpClientUtilsSpec extends Specification {
'no port' | 'http://localhost' | '/path/with spaces' | 'http://localhost/path/with%20spaces'
'Extra path' | 'http://localhost/sub' | '/extraPath/with spaces' | 'http://localhost/sub/extraPath/with%20spaces'
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -39,19 +39,19 @@ object HttpClient : KLogging() {
fun newHttpClient(
authentication: Any?,
uri: URI,
defaultHeaderStore: MutableMap<String, String>,
maxPublishRetries: Int = 5,
publishRetryInterval: Int = 3000
): Pair<CloseableHttpClient, CredentialsProvider?> {
val retryStrategy = CustomServiceUnavailableRetryStrategy(maxPublishRetries, publishRetryInterval)
val builder = HttpClients.custom().useSystemProperties().setServiceUnavailableRetryStrategy(retryStrategy)

val defaultHeaders = mutableMapOf<String, String>()
val credsProvider = when (authentication) {
is Auth -> {
when (authentication) {
is Auth.BasicAuthentication -> basicAuth(uri, authentication.username, authentication.password, builder)
is Auth.BearerAuthentication -> {
defaultHeaderStore["Authorization"] = "Bearer " + authentication.token
defaultHeaders["Authorization"] = "Bearer " + authentication.token
SystemDefaultCredentialsProvider()
}
}
Expand All @@ -68,7 +68,7 @@ object HttpClient : KLogging() {
}
"bearer" -> {
if (authentication.size > 1) {
defaultHeaderStore["Authorization"] = "Bearer " + authentication[1].toString()
defaultHeaders["Authorization"] = "Bearer " + authentication[1].toString()
} else {
logger.warn { "Bearer token authentication requires a token, ignoring." }
}
Expand All @@ -83,7 +83,7 @@ object HttpClient : KLogging() {
else -> SystemDefaultCredentialsProvider()
}

builder.setDefaultHeaders(defaultHeaderStore.map { BasicHeader(it.key, it.value) })
builder.setDefaultHeaders(defaultHeaders.map { BasicHeader(it.key, it.value) })
return builder.build() to credsProvider
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package au.com.dius.pact.core.support

import spock.lang.Specification

class HttpClientSpec extends Specification {

def 'when creating a new http client, add any authentication as default headers'() {
given:
URI uri = new URI('http://localhost')
def authentication = ['bearer', '1234abcd']

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

then:
defaultHeaders[0].name == 'Authorization'
defaultHeaders[0].value == 'Bearer 1234abcd'
}
}
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ groovy2Version=2.5.10
kotlinVersion=1.3.72
httpBuilderVersion=1.0.4
commonsLang3Version=3.4
httpClientVersion=4.5.5
httpClientVersion=4.5.13
scalaVersion=2.13.2
specs2Version=4.9.4
scalaTestVersion=3.1.2
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package au.com.dius.pact.provider.spring.junit5;

import au.com.dius.pact.provider.junit5.PactVerificationContext;
import au.com.dius.pact.provider.junit5.PactVerificationInvocationContextProvider;
import au.com.dius.pact.provider.junitsupport.IgnoreNoPactsToVerify;
import au.com.dius.pact.provider.junitsupport.Provider;
import au.com.dius.pact.provider.junitsupport.loader.PactBroker;
import au.com.dius.pact.provider.junitsupport.loader.PactBrokerAuth;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.TestTemplate;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.web.server.LocalServerPort;

/*
This is a test for issue https://github.com/pact-foundation/pact-jvm/issues/1242
*/
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@Provider("Foo Provider")
@PactBroker(scheme="https", host = "test.pactflow.io", port = "443", authentication = @PactBrokerAuth(token = "anyToken"))
@IgnoreNoPactsToVerify(ignoreIoErrors = "true")
class FooControllerTest {

@LocalServerPort
int port;

@BeforeEach
void setup(PactVerificationContext context) {
}

@TestTemplate
@ExtendWith(PactVerificationInvocationContextProvider.class)
void pactVerificationTestTemplate(PactVerificationContext context) {
}
}

0 comments on commit 940fc83

Please sign in to comment.