diff --git a/kork-retrofit/src/test/kotlin/com/netflix/spinnaker/kork/retrofit/RetrofitServiceProviderTest.kt b/kork-retrofit/src/test/kotlin/com/netflix/spinnaker/kork/retrofit/RetrofitServiceProviderTest.kt index a6f8e02c0..bc3f930c7 100644 --- a/kork-retrofit/src/test/kotlin/com/netflix/spinnaker/kork/retrofit/RetrofitServiceProviderTest.kt +++ b/kork-retrofit/src/test/kotlin/com/netflix/spinnaker/kork/retrofit/RetrofitServiceProviderTest.kt @@ -119,5 +119,3 @@ interface Retrofit1Service { fun getSomething(@Path("user") user: String?, callback: Callback?>?) } - - diff --git a/kork-retrofit2/src/test/kotlin/com/netflix/spinnaker/kork/retrofit/Retrofit2ServiceProviderTest.kt b/kork-retrofit2/src/test/kotlin/com/netflix/spinnaker/kork/retrofit/Retrofit2ServiceProviderTest.kt index 47b20cb71..f3bf68213 100644 --- a/kork-retrofit2/src/test/kotlin/com/netflix/spinnaker/kork/retrofit/Retrofit2ServiceProviderTest.kt +++ b/kork-retrofit2/src/test/kotlin/com/netflix/spinnaker/kork/retrofit/Retrofit2ServiceProviderTest.kt @@ -102,7 +102,7 @@ private open class TestConfiguration { @Bean open fun spinnakerRequestInterceptor(): SpinnakerRequestInterceptor { - return SpinnakerRequestInterceptor(OkHttpClientConfigurationProperties()) + return SpinnakerRequestInterceptor(true) } @Bean diff --git a/kork-web/kork-web.gradle b/kork-web/kork-web.gradle index 313f38191..55d4c224b 100644 --- a/kork-web/kork-web.gradle +++ b/kork-web/kork-web.gradle @@ -43,8 +43,11 @@ dependencies { runtimeOnly "org.hibernate.validator:hibernate-validator" testImplementation project(":kork-test") + testImplementation "com.github.tomakehurst:wiremock-jre8-standalone" testImplementation "ch.qos.logback:logback-classic" testImplementation "ch.qos.logback:logback-core" + testImplementation "com.squareup.retrofit2:retrofit" + testImplementation "org.junit.jupiter:junit-jupiter-params" testImplementation "org.spockframework:spock-core" testImplementation "org.spockframework:spock-spring" testImplementation "org.springframework.boot:spring-boot-starter-test" diff --git a/kork-web/src/main/groovy/com/netflix/spinnaker/okhttp/SpinnakerRequestInterceptor.groovy b/kork-web/src/main/groovy/com/netflix/spinnaker/okhttp/SpinnakerRequestInterceptor.groovy index 0e97ddc69..10e452deb 100644 --- a/kork-web/src/main/groovy/com/netflix/spinnaker/okhttp/SpinnakerRequestInterceptor.groovy +++ b/kork-web/src/main/groovy/com/netflix/spinnaker/okhttp/SpinnakerRequestInterceptor.groovy @@ -16,24 +16,37 @@ package com.netflix.spinnaker.okhttp +import com.netflix.spinnaker.kork.common.Header import com.netflix.spinnaker.security.AuthenticatedRequest import retrofit.RequestInterceptor class SpinnakerRequestInterceptor implements RequestInterceptor { - private final OkHttpClientConfigurationProperties okHttpClientConfigurationProperties + private final boolean propagateSpinnakerHeaders; - SpinnakerRequestInterceptor(OkHttpClientConfigurationProperties okHttpClientConfigurationProperties) { - this.okHttpClientConfigurationProperties = okHttpClientConfigurationProperties + /** + * Don't propagate X-SPINNAKER-ACCOUNTS. Only relevant when propagateSpinnakerHeaders is true. + */ + private final boolean skipAccountsHeader; + + SpinnakerRequestInterceptor(boolean propagateSpinnakerHeaders) { + this.propagateSpinnakerHeaders = propagateSpinnakerHeaders + this.skipAccountsHeader = false + } + + SpinnakerRequestInterceptor(boolean propagateSpinnakerHeaders, + boolean skipAccountsHeader) { + this.propagateSpinnakerHeaders = propagateSpinnakerHeaders + this.skipAccountsHeader = skipAccountsHeader } void intercept(RequestInterceptor.RequestFacade request) { - if (!okHttpClientConfigurationProperties.propagateSpinnakerHeaders) { + if (!propagateSpinnakerHeaders) { // noop return } AuthenticatedRequest.authenticationHeaders.each { String key, Optional value -> - if (value.present) { + if (value.present && (!skipAccountsHeader || !Header.ACCOUNTS.getHeader().equals(key))) { request.addHeader(key, value.get()) } } diff --git a/kork-web/src/main/groovy/com/netflix/spinnaker/config/OkHttpClientComponents.java b/kork-web/src/main/java/com/netflix/spinnaker/config/OkHttpClientComponents.java similarity index 98% rename from kork-web/src/main/groovy/com/netflix/spinnaker/config/OkHttpClientComponents.java rename to kork-web/src/main/java/com/netflix/spinnaker/config/OkHttpClientComponents.java index e187e079d..796bfe144 100644 --- a/kork-web/src/main/groovy/com/netflix/spinnaker/config/OkHttpClientComponents.java +++ b/kork-web/src/main/java/com/netflix/spinnaker/config/OkHttpClientComponents.java @@ -82,12 +82,12 @@ public class OkHttpClientComponents { @Bean public SpinnakerRequestInterceptor spinnakerRequestInterceptor() { - return new SpinnakerRequestInterceptor(clientProperties); + return new SpinnakerRequestInterceptor(clientProperties.getPropagateSpinnakerHeaders()); } @Bean public SpinnakerRequestHeaderInterceptor spinnakerRequestHeaderInterceptor() { - return new SpinnakerRequestHeaderInterceptor(clientProperties); + return new SpinnakerRequestHeaderInterceptor(clientProperties.getPropagateSpinnakerHeaders()); } @Bean diff --git a/kork-web/src/main/java/com/netflix/spinnaker/okhttp/SpinnakerRequestHeaderInterceptor.java b/kork-web/src/main/java/com/netflix/spinnaker/okhttp/SpinnakerRequestHeaderInterceptor.java index f10605b02..350ecb6ee 100644 --- a/kork-web/src/main/java/com/netflix/spinnaker/okhttp/SpinnakerRequestHeaderInterceptor.java +++ b/kork-web/src/main/java/com/netflix/spinnaker/okhttp/SpinnakerRequestHeaderInterceptor.java @@ -16,6 +16,7 @@ package com.netflix.spinnaker.okhttp; +import com.netflix.spinnaker.kork.common.Header; import com.netflix.spinnaker.security.AuthenticatedRequest; import java.io.IOException; import okhttp3.Interceptor; @@ -28,24 +29,34 @@ */ public class SpinnakerRequestHeaderInterceptor implements Interceptor { - private final OkHttpClientConfigurationProperties okHttpClientConfigurationProperties; + private final boolean propagateSpinnakerHeaders; + + /** Don't propagate X-SPINNAKER-ACCOUNTS. Only relevant when propagateSpinnakerHeaders is true. */ + private final boolean skipAccountsHeader; + + public SpinnakerRequestHeaderInterceptor(boolean propagateSpinnakerHeaders) { + this.propagateSpinnakerHeaders = propagateSpinnakerHeaders; + this.skipAccountsHeader = false; + } public SpinnakerRequestHeaderInterceptor( - OkHttpClientConfigurationProperties okHttpClientConfigurationProperties) { - this.okHttpClientConfigurationProperties = okHttpClientConfigurationProperties; + boolean propagateSpinnakerHeaders, boolean skipAccountsHeader) { + this.propagateSpinnakerHeaders = propagateSpinnakerHeaders; + this.skipAccountsHeader = skipAccountsHeader; } @Override public Response intercept(Chain chain) throws IOException { Request.Builder builder = chain.request().newBuilder(); - if (!okHttpClientConfigurationProperties.getPropagateSpinnakerHeaders()) { + if (!propagateSpinnakerHeaders) { return chain.proceed(builder.build()); } AuthenticatedRequest.getAuthenticationHeaders() .forEach( (key, value) -> { - if (value.isPresent()) { + if (value.isPresent() + && (!skipAccountsHeader || !Header.ACCOUNTS.getHeader().equals(key))) { builder.addHeader(key, value.get()); } }); diff --git a/kork-web/src/test/groovy/com/netflix/spinnaker/kork/web/interceptors/SpinnakerRequestHeaderInterceptorTest.groovy b/kork-web/src/test/groovy/com/netflix/spinnaker/kork/web/interceptors/SpinnakerRequestHeaderInterceptorTest.groovy deleted file mode 100644 index 59cce3aba..000000000 --- a/kork-web/src/test/groovy/com/netflix/spinnaker/kork/web/interceptors/SpinnakerRequestHeaderInterceptorTest.groovy +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2023 OpsMx, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.netflix.spinnaker.kork.web.interceptors - -import com.netflix.spinnaker.kork.common.Header -import com.netflix.spinnaker.okhttp.OkHttpClientConfigurationProperties -import com.netflix.spinnaker.okhttp.SpinnakerRequestHeaderInterceptor -import com.netflix.spinnaker.security.AuthenticatedRequest -import okhttp3.Interceptor -import okhttp3.Request -import org.mockito.MockedStatic -import org.mockito.Mockito -import spock.lang.Specification - -class SpinnakerRequestHeaderInterceptorTest extends Specification { - - def "request contains authorization header"() { - MockedStatic mockAuthenticatedRequest = Mockito.mockStatic(AuthenticatedRequest.class) - Map> authHeaders = new HashMap>(){} - authHeaders.put(Header.USER.getHeader(), Optional.of("some user")) - authHeaders.put(Header.ACCOUNTS.getHeader(), Optional.of("Some ACCOUNTS")) - def okHttpClientConfigurationProperties = new OkHttpClientConfigurationProperties(); - def headerInterceptor = new SpinnakerRequestHeaderInterceptor(okHttpClientConfigurationProperties) - def chain = Mock(Interceptor.Chain) { - request() >> new Request.Builder() - .url("http://1.1.1.1/heath-check") - .build() - } - - Mockito.when(AuthenticatedRequest.authenticationHeaders) - .thenReturn(authHeaders) - - when: "running the interceptor under test" - headerInterceptor.intercept(chain) - - then: "the expected authorization header is added to the request before proceeding" - 1 * chain.proceed({ Request request -> request.headers(Header.USER.getHeader()) == ["some user"] && - request.headers(Header.ACCOUNTS.getHeader()) == ["Some ACCOUNTS"]}) - - cleanup: - mockAuthenticatedRequest.close() - } -} diff --git a/kork-web/src/test/java/com/netflix/spinnaker/config/OkHttpClientComponentsTest.java b/kork-web/src/test/java/com/netflix/spinnaker/config/OkHttpClientComponentsTest.java new file mode 100644 index 000000000..0975280a3 --- /dev/null +++ b/kork-web/src/test/java/com/netflix/spinnaker/config/OkHttpClientComponentsTest.java @@ -0,0 +1,54 @@ +/* + * Copyright 2024 Salesforce, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License") + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.netflix.spinnaker.config; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.netflix.spinnaker.okhttp.OkHttp3MetricsInterceptor; +import com.netflix.spinnaker.okhttp.OkHttpMetricsInterceptor; +import com.netflix.spinnaker.okhttp.SpinnakerRequestHeaderInterceptor; +import com.netflix.spinnaker.okhttp.SpinnakerRequestInterceptor; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInfo; +import org.springframework.boot.context.annotation.UserConfigurations; +import org.springframework.boot.task.TaskExecutorBuilder; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; + +class OkHttpClientComponentsTest { + + private final ApplicationContextRunner runner = + new ApplicationContextRunner() + .withBean(TaskExecutorBuilder.class) + .withConfiguration(UserConfigurations.of(OkHttpClientComponents.class)); + + @BeforeEach + void init(TestInfo testInfo) { + System.out.println("--------------- Test " + testInfo.getDisplayName()); + } + + @Test + void verifyValidConfiguration() { + runner.run( + ctx -> { + assertThat(ctx).hasSingleBean(SpinnakerRequestInterceptor.class); + assertThat(ctx).hasSingleBean(SpinnakerRequestHeaderInterceptor.class); + assertThat(ctx).hasSingleBean(OkHttpMetricsInterceptor.class); + assertThat(ctx).hasSingleBean(OkHttp3MetricsInterceptor.class); + }); + } +} diff --git a/kork-web/src/test/java/com/netflix/spinnaker/okhttp/SpinnakerRequestHeaderInterceptorTest.java b/kork-web/src/test/java/com/netflix/spinnaker/okhttp/SpinnakerRequestHeaderInterceptorTest.java new file mode 100644 index 000000000..2d591f954 --- /dev/null +++ b/kork-web/src/test/java/com/netflix/spinnaker/okhttp/SpinnakerRequestHeaderInterceptorTest.java @@ -0,0 +1,162 @@ +/* + * Copyright 2023 OpsMx, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.netflix.spinnaker.okhttp; + +import static com.github.tomakehurst.wiremock.client.WireMock.equalTo; +import static com.github.tomakehurst.wiremock.client.WireMock.get; +import static com.github.tomakehurst.wiremock.client.WireMock.getRequestedFor; +import static com.github.tomakehurst.wiremock.client.WireMock.ok; +import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo; +import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig; +import static org.assertj.core.api.Assertions.assertThat; + +import com.github.tomakehurst.wiremock.junit5.WireMockExtension; +import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo; +import com.github.tomakehurst.wiremock.matching.RequestPatternBuilder; +import com.netflix.spinnaker.kork.common.Header; +import com.netflix.spinnaker.security.AuthenticatedRequest; +import java.util.Map; +import okhttp3.OkHttpClient; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInfo; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import retrofit2.Call; +import retrofit2.Retrofit; +import retrofit2.http.GET; + +class SpinnakerRequestHeaderInterceptorTest { + + public static final String REQUEST_PATH = "/foo"; + + public static final String TEST_USER = "some-user"; + + public static final String TEST_ACCOUNTS = "some-accounts"; + + public static final String TEST_REQUEST_ID = "some-request-id"; + + public static final Map TEST_SPINNAKER_HEADERS = + Map.of( + Header.USER, + TEST_USER, + Header.ACCOUNTS, + TEST_ACCOUNTS, + Header.REQUEST_ID, + TEST_REQUEST_ID); + + /** + * Use this instead of annotating the class with @WireMockTest so there's a WireMock object + * available for parameterized tests. Otherwise the arguments from e.g. ValueSource compete with + * the WireMockRuntimeInfo argument that @WireMockTest provides. + */ + @RegisterExtension + static WireMockExtension wireMock = + WireMockExtension.newInstance().options(wireMockConfig().dynamicPort()).build(); + + @BeforeEach + void setup(TestInfo testInfo, WireMockRuntimeInfo wmRuntimeInfo) { + System.out.println("--------------- Test " + testInfo.getDisplayName()); + + // set up an arbitrary response to avoid 404s, and so it's possible to + // verify the request headers wiremock receives. + wireMock.stubFor(get(REQUEST_PATH).willReturn(ok())); + } + + @AfterEach + void cleanup() { + AuthenticatedRequest.clear(); + } + + @ParameterizedTest(name = "propagateSpinnakerHeaders = {0}") + @ValueSource(booleans = {false, true}) + void propagateSpinnakerHeaders(boolean propagateSpinnakerHeaders) throws Exception { + SpinnakerRequestHeaderInterceptor spinnakerRequestHeaderInterceptor = + new SpinnakerRequestHeaderInterceptor(propagateSpinnakerHeaders); + + RetrofitService retrofitService = + makeRetrofitService(wireMock.baseUrl(), spinnakerRequestHeaderInterceptor); + + // Add some spinnaker headers to the MDC + TEST_SPINNAKER_HEADERS.forEach(AuthenticatedRequest::set); + + // Make a request + retrofitService.getRequest().execute(); + + // Verify that wiremock did/didn't receive the spinnaker headers as appropriate + TEST_SPINNAKER_HEADERS.forEach( + (Header header, String value) -> { + RequestPatternBuilder requestPatternBuilder = + getRequestedFor(urlPathEqualTo(REQUEST_PATH)); + if (propagateSpinnakerHeaders) { + requestPatternBuilder.withHeader(header.getHeader(), equalTo(value)); + } else { + requestPatternBuilder.withoutHeader(header.getHeader()); + } + wireMock.verify(requestPatternBuilder); + }); + } + + @Test + void skipAccountHeaders() throws Exception { + SpinnakerRequestHeaderInterceptor spinnakerRequestHeaderInterceptor = + new SpinnakerRequestHeaderInterceptor( + true /* propagateSpinnakerHeaders */, true /* skipAccountsHeader */); + + RetrofitService retrofitService = + makeRetrofitService(wireMock.baseUrl(), spinnakerRequestHeaderInterceptor); + + // Add some spinnaker headers to the MDC, including the accounts header + assertThat(TEST_SPINNAKER_HEADERS).containsKey(Header.ACCOUNTS); + TEST_SPINNAKER_HEADERS.forEach(AuthenticatedRequest::set); + + // Make a request + retrofitService.getRequest().execute(); + + // Verify that wiremock received all spinnaker headers except the accounts header + TEST_SPINNAKER_HEADERS.forEach( + (Header header, String value) -> { + RequestPatternBuilder requestPatternBuilder = + getRequestedFor(urlPathEqualTo(REQUEST_PATH)); + if (Header.ACCOUNTS.equals(header)) { + requestPatternBuilder.withoutHeader(header.getHeader()); + } else { + requestPatternBuilder.withHeader(header.getHeader(), equalTo(value)); + } + wireMock.verify(requestPatternBuilder); + }); + } + + private RetrofitService makeRetrofitService( + String baseUrl, SpinnakerRequestHeaderInterceptor spinnakerRequestHeaderInterceptor) { + OkHttpClient okHttpClient = + new OkHttpClient.Builder().addInterceptor(spinnakerRequestHeaderInterceptor).build(); + + return new Retrofit.Builder() + .baseUrl(baseUrl) + .client(okHttpClient) + .build() + .create(RetrofitService.class); + } + + interface RetrofitService { + @GET(REQUEST_PATH) + Call getRequest(); + } +} diff --git a/kork-web/src/test/java/com/netflix/spinnaker/okhttp/SpinnakerRequestInterceptorTest.java b/kork-web/src/test/java/com/netflix/spinnaker/okhttp/SpinnakerRequestInterceptorTest.java new file mode 100644 index 000000000..15cb88605 --- /dev/null +++ b/kork-web/src/test/java/com/netflix/spinnaker/okhttp/SpinnakerRequestInterceptorTest.java @@ -0,0 +1,158 @@ +/* + * Copyright 2024 Salesforce, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.netflix.spinnaker.okhttp; + +import static com.github.tomakehurst.wiremock.client.WireMock.equalTo; +import static com.github.tomakehurst.wiremock.client.WireMock.get; +import static com.github.tomakehurst.wiremock.client.WireMock.getRequestedFor; +import static com.github.tomakehurst.wiremock.client.WireMock.ok; +import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo; +import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig; +import static org.assertj.core.api.Assertions.assertThat; + +import com.github.tomakehurst.wiremock.junit5.WireMockExtension; +import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo; +import com.github.tomakehurst.wiremock.matching.RequestPatternBuilder; +import com.netflix.spinnaker.kork.common.Header; +import com.netflix.spinnaker.security.AuthenticatedRequest; +import java.util.Map; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInfo; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import retrofit.RestAdapter; +import retrofit.client.Response; +import retrofit.http.GET; + +class SpinnakerRequestInterceptorTest { + + public static final String REQUEST_PATH = "/foo"; + + public static final String TEST_USER = "some-user"; + + public static final String TEST_ACCOUNTS = "some-accounts"; + + public static final String TEST_REQUEST_ID = "some-request-id"; + + public static final Map TEST_SPINNAKER_HEADERS = + Map.of( + Header.USER, + TEST_USER, + Header.ACCOUNTS, + TEST_ACCOUNTS, + Header.REQUEST_ID, + TEST_REQUEST_ID); + + /** + * Use this instead of annotating the class with @WireMockTest so there's a WireMock object + * available for parameterized tests. Otherwise the arguments from e.g. ValueSource compete with + * the WireMockRuntimeInfo argument that @WireMockTest provides. + */ + @RegisterExtension + static WireMockExtension wireMock = + WireMockExtension.newInstance().options(wireMockConfig().dynamicPort()).build(); + + @BeforeEach + void setup(TestInfo testInfo, WireMockRuntimeInfo wmRuntimeInfo) { + System.out.println("--------------- Test " + testInfo.getDisplayName()); + + // set up an arbitrary response to avoid 404s, and so it's possible to + // verify the request headers wiremock receives. + wireMock.stubFor(get(REQUEST_PATH).willReturn(ok())); + } + + @AfterEach + void cleanup() { + AuthenticatedRequest.clear(); + } + + @ParameterizedTest(name = "propagateSpinnakerHeaders = {0}") + @ValueSource(booleans = {false, true}) + void propagateSpinnakerHeaders(boolean propagateSpinnakerHeaders) { + SpinnakerRequestInterceptor spinnakerRequestInterceptor = + new SpinnakerRequestInterceptor(propagateSpinnakerHeaders); + + RetrofitService retrofitService = + makeRetrofitService(wireMock.baseUrl(), spinnakerRequestInterceptor); + + // Add some spinnaker headers to the MDC + TEST_SPINNAKER_HEADERS.forEach(AuthenticatedRequest::set); + + // Make a request + retrofitService.getRequest(); + + // Verify that wiremock did/didn't receive the spinnaker headers as appropriate + TEST_SPINNAKER_HEADERS.forEach( + (Header header, String value) -> { + RequestPatternBuilder requestPatternBuilder = + getRequestedFor(urlPathEqualTo(REQUEST_PATH)); + if (propagateSpinnakerHeaders) { + requestPatternBuilder.withHeader(header.getHeader(), equalTo(value)); + } else { + requestPatternBuilder.withoutHeader(header.getHeader()); + } + wireMock.verify(requestPatternBuilder); + }); + } + + @Test + void skipAccountHeaders() { + SpinnakerRequestInterceptor spinnakerRequestInterceptor = + new SpinnakerRequestInterceptor( + true /* propagateSpinnakerHeaders */, true /* skipAccountsHeader */); + + RetrofitService retrofitService = + makeRetrofitService(wireMock.baseUrl(), spinnakerRequestInterceptor); + + // Add some spinnaker headers to the MDC, including the accounts header + assertThat(TEST_SPINNAKER_HEADERS).containsKey(Header.ACCOUNTS); + TEST_SPINNAKER_HEADERS.forEach(AuthenticatedRequest::set); + + // Make a request + retrofitService.getRequest(); + + // Verify that wiremock received all spinnaker headers except the accounts header + TEST_SPINNAKER_HEADERS.forEach( + (Header header, String value) -> { + RequestPatternBuilder requestPatternBuilder = + getRequestedFor(urlPathEqualTo(REQUEST_PATH)); + if (Header.ACCOUNTS.equals(header)) { + requestPatternBuilder.withoutHeader(header.getHeader()); + } else { + requestPatternBuilder.withHeader(header.getHeader(), equalTo(value)); + } + wireMock.verify(requestPatternBuilder); + }); + } + + private RetrofitService makeRetrofitService( + String baseUrl, SpinnakerRequestInterceptor spinnakerRequestInterceptor) { + return new RestAdapter.Builder() + .setRequestInterceptor(spinnakerRequestInterceptor) + .setEndpoint(baseUrl) + .build() + .create(RetrofitService.class); + } + + interface RetrofitService { + @GET(REQUEST_PATH) + Response getRequest(); + } +} diff --git a/kork-web/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker b/kork-web/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker deleted file mode 100644 index 1f0955d45..000000000 --- a/kork-web/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker +++ /dev/null @@ -1 +0,0 @@ -mock-maker-inline