diff --git a/src/main/java/org/prebid/server/cache/CoreCacheService.java b/src/main/java/org/prebid/server/cache/CoreCacheService.java index bcf839cd383..5d5034e23ce 100644 --- a/src/main/java/org/prebid/server/cache/CoreCacheService.java +++ b/src/main/java/org/prebid/server/cache/CoreCacheService.java @@ -5,6 +5,7 @@ import com.fasterxml.jackson.databind.node.TextNode; import com.iab.openrtb.response.Bid; import io.vertx.core.Future; +import io.vertx.core.MultiMap; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.prebid.server.auction.model.AuctionContext; @@ -61,8 +62,6 @@ public class CoreCacheService { private static final Logger logger = LoggerFactory.getLogger(CoreCacheService.class); - private static final Map> DEBUG_HEADERS = - HttpUtil.toDebugHeaders(CacheServiceUtil.CACHE_HEADERS); private static final String BID_WURL_ATTRIBUTE = "wurl"; private final HttpClient httpClient; @@ -76,11 +75,16 @@ public class CoreCacheService { private final UUIDIdGenerator idGenerator; private final JacksonMapper mapper; + private final MultiMap cacheHeaders; + private final Map> debugHeaders; + public CoreCacheService( HttpClient httpClient, URL endpointUrl, String cachedAssetUrlTemplate, long expectedCacheTimeMs, + String apiKey, + boolean isApiKeySecured, VastModifier vastModifier, EventsService eventsService, Metrics metrics, @@ -98,6 +102,11 @@ public CoreCacheService( this.clock = Objects.requireNonNull(clock); this.idGenerator = Objects.requireNonNull(idGenerator); this.mapper = Objects.requireNonNull(mapper); + + cacheHeaders = isApiKeySecured + ? HttpUtil.headers().add(HttpUtil.X_PBC_API_KEY_HEADER, Objects.requireNonNull(apiKey)) + : HttpUtil.headers(); + debugHeaders = HttpUtil.toDebugHeaders(cacheHeaders); } public String getEndpointHost() { @@ -121,7 +130,10 @@ public String cacheVideoDebugLog(CachedDebugLog cachedDebugLog, Integer videoCac final List cachedCreatives = Collections.singletonList( makeDebugCacheCreative(cachedDebugLog, cacheKey, videoCacheTtl)); final BidCacheRequest bidCacheRequest = toBidCacheRequest(cachedCreatives); - httpClient.post(endpointUrl.toString(), HttpUtil.headers(), mapper.encodeToString(bidCacheRequest), + httpClient.post( + endpointUrl.toString(), + cacheHeaders, + mapper.encodeToString(bidCacheRequest), expectedCacheTimeMs); return cacheKey; } @@ -155,7 +167,7 @@ private Future makeRequest(BidCacheRequest bidCacheRequest, final long startTime = clock.millis(); return httpClient.post( endpointUrl.toString(), - CacheServiceUtil.CACHE_HEADERS, + cacheHeaders, mapper.encodeToString(bidCacheRequest), remainingTimeout) .map(response -> toBidCacheResponse( @@ -286,7 +298,7 @@ private Future doCacheOpenrtb(List bids, final CacheHttpRequest httpRequest = CacheHttpRequest.of(url, body); final long startTime = clock.millis(); - return httpClient.post(url, CacheServiceUtil.CACHE_HEADERS, body, remainingTimeout) + return httpClient.post(url, cacheHeaders, body, remainingTimeout) .map(response -> processResponseOpenrtb(response, httpRequest, cachedCreatives.size(), @@ -348,7 +360,7 @@ private DebugHttpCall makeDebugHttpCall(String endpoint, .responseStatus(httpResponse != null ? httpResponse.getStatusCode() : null) .responseBody(httpResponse != null ? httpResponse.getBody() : null) .responseTimeMillis(responseTime(startTime)) - .requestHeaders(DEBUG_HEADERS) + .requestHeaders(debugHeaders) .build(); } diff --git a/src/main/java/org/prebid/server/spring/config/ServiceConfiguration.java b/src/main/java/org/prebid/server/spring/config/ServiceConfiguration.java index 5676d7fd43e..71e014fcc23 100644 --- a/src/main/java/org/prebid/server/spring/config/ServiceConfiguration.java +++ b/src/main/java/org/prebid/server/spring/config/ServiceConfiguration.java @@ -160,6 +160,8 @@ CoreCacheService cacheService( @Value("${cache.path}") String path, @Value("${cache.query}") String query, @Value("${auction.cache.expected-request-time-ms}") long expectedCacheTimeMs, + @Value("${pbc.api.key:#{null}}") String apiKey, + @Value("${cache.api-key-secured:false}") boolean apiKeySecured, VastModifier vastModifier, EventsService eventsService, HttpClient httpClient, @@ -172,6 +174,8 @@ CoreCacheService cacheService( CacheServiceUtil.getCacheEndpointUrl(scheme, host, path), CacheServiceUtil.getCachedAssetUrlTemplate(scheme, host, path, query), expectedCacheTimeMs, + apiKey, + apiKeySecured, vastModifier, eventsService, metrics, diff --git a/src/test/java/org/prebid/server/cache/CoreCacheServiceTest.java b/src/test/java/org/prebid/server/cache/CoreCacheServiceTest.java index 8a55773a0c0..a8ce602aeb5 100644 --- a/src/test/java/org/prebid/server/cache/CoreCacheServiceTest.java +++ b/src/test/java/org/prebid/server/cache/CoreCacheServiceTest.java @@ -8,6 +8,7 @@ import com.iab.openrtb.request.Video; import com.iab.openrtb.response.Bid; import io.vertx.core.Future; +import io.vertx.core.MultiMap; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -40,6 +41,7 @@ import org.prebid.server.proto.openrtb.ext.response.BidType; import org.prebid.server.proto.openrtb.ext.response.ExtBidPrebid; import org.prebid.server.settings.model.Account; +import org.prebid.server.util.HttpUtil; import org.prebid.server.vast.VastModifier; import org.prebid.server.vertx.httpclient.HttpClient; import org.prebid.server.vertx.httpclient.model.HttpClientResponse; @@ -107,6 +109,8 @@ public void setUp() throws MalformedURLException, JsonProcessingException { new URL("http://cache-service/cache"), "http://cache-service-host/cache?uuid=", 100L, + null, + false, vastModifier, eventsService, metrics, @@ -371,6 +375,40 @@ public void cacheBidsOpenrtbShouldReturnExpectedDebugInfo() throws JsonProcessin .build()); } + @Test + public void cacheBidsOpenrtbShouldUseApiKeyWhenProvided() throws MalformedURLException { + // given + target = new CoreCacheService( + httpClient, + new URL("http://cache-service/cache"), + "http://cache-service-host/cache?uuid=", + 100L, + "ApiKey", + true, + vastModifier, + eventsService, + metrics, + clock, + idGenerator, + jacksonMapper); + final BidInfo bidinfo = givenBidInfo(builder -> builder.id("bidId1")); + + // when + final Future future = target.cacheBidsOpenrtb( + singletonList(bidinfo), + givenAuctionContext(), + CacheContext.builder() + .shouldCacheBids(true) + .build(), + eventsContext); + + // then + assertThat(future.result().getHttpCall().getRequestHeaders().get(HttpUtil.X_PBC_API_KEY_HEADER.toString())) + .containsExactly("ApiKey"); + assertThat(captureBidCacheRequestHeaders().get(HttpUtil.X_PBC_API_KEY_HEADER.toString())) + .isEqualTo("ApiKey"); + } + @Test public void cacheBidsOpenrtbShouldReturnExpectedCacheBids() { // given @@ -694,7 +732,7 @@ public void cachePutObjectsShouldReturnResultWithEmptyListWhenPutObjectsIsEmpty( } @Test - public void cachePutObjectsShouldModifyVastAndCachePutObjects() throws IOException { + public void cachePutObjectsShould() throws IOException { // given final BidPutObject firstBidPutObject = BidPutObject.builder() .type("json") @@ -762,6 +800,45 @@ public void cachePutObjectsShouldModifyVastAndCachePutObjects() throws IOExcepti .containsExactly(modifiedFirstBidPutObject, modifiedSecondBidPutObject, modifiedThirdBidPutObject); } + @Test + public void cachePutObjectsShouldUseApiKeyWhenProvided() throws MalformedURLException { + // given + target = new CoreCacheService( + httpClient, + new URL("http://cache-service/cache"), + "http://cache-service-host/cache?uuid=", + 100L, + "ApiKey", + true, + vastModifier, + eventsService, + metrics, + clock, + idGenerator, + jacksonMapper); + + final BidPutObject firstBidPutObject = BidPutObject.builder() + .type("json") + .bidid("bidId1") + .bidder("bidder1") + .timestamp(1L) + .value(new TextNode("vast")) + .build(); + + // when + target.cachePutObjects( + asList(firstBidPutObject), + true, + singleton("bidder1"), + "account", + "pbjs", + timeout); + + // then + assertThat(captureBidCacheRequestHeaders().get(HttpUtil.X_PBC_API_KEY_HEADER.toString())) + .isEqualTo("ApiKey"); + } + private AuctionContext givenAuctionContext(UnaryOperator accountCustomizer, UnaryOperator bidRequestCustomizer) { @@ -850,6 +927,12 @@ private BidCacheRequest captureBidCacheRequest() throws IOException { return mapper.readValue(captor.getValue(), BidCacheRequest.class); } + private MultiMap captureBidCacheRequestHeaders() { + final ArgumentCaptor captor = ArgumentCaptor.forClass(MultiMap.class); + verify(httpClient).post(anyString(), captor.capture(), anyString(), anyLong()); + return captor.getValue(); + } + private Map> givenDebugHeaders() { final Map> headers = new HashMap<>(); headers.put("Accept", singletonList("application/json"));