Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import com.iab.openrtb.request.User;
import io.vertx.core.Future;
import io.vertx.core.MultiMap;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.ListUtils;
import org.prebid.server.activity.Activity;
import org.prebid.server.activity.ComponentType;
Expand Down Expand Up @@ -40,18 +39,15 @@
import org.prebid.server.proto.openrtb.ext.request.ExtRequestPrebidDataEidPermissions;
import org.prebid.server.util.HttpUtil;
import org.prebid.server.util.ListUtil;
import org.prebid.server.util.StreamUtil;
import org.prebid.server.vertx.httpclient.HttpClient;
import org.prebid.server.vertx.httpclient.model.HttpClientResponse;

import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ThreadLocalRandom;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class LiveIntentOmniChannelIdentityProcessedAuctionRequestHook implements ProcessedAuctionRequestHook {

Expand Down Expand Up @@ -202,14 +198,22 @@ private AuctionRequestPayload updatedPayload(AuctionRequestPayload requestPayloa
}

private BidRequest updateAllowedBidders(BidRequest bidRequest, List<Eid> resolvedEids) {
if (targetBidders.isEmpty()) {
if (targetBidders.isEmpty() || resolvedEids == null || resolvedEids.isEmpty()) {
return bidRequest;
}

final ExtRequest ext = bidRequest.getExt();
final ExtRequestPrebid extPrebid = ext != null ? ext.getPrebid() : null;
final ExtRequestPrebidData extPrebidData = extPrebid != null ? extPrebid.getData() : null;

final List<ExtRequestPrebidDataEidPermissions> existingPerms = extPrebidData != null
? ListUtils.emptyIfNull(extPrebidData.getEidPermissions())
: List.of();

if (existingPerms.isEmpty()) {
return bidRequest;
}

final ExtRequestPrebid updatedExtPrebid = Optional.ofNullable(extPrebid)
.map(ExtRequestPrebid::toBuilder)
.orElseGet(ExtRequestPrebid::builder)
Expand All @@ -225,35 +229,37 @@ private BidRequest updateAllowedBidders(BidRequest bidRequest, List<Eid> resolve
}

private ExtRequestPrebidData updatePrebidData(ExtRequestPrebidData extPrebidData, List<Eid> resolvedEids) {
final List<String> prebidDataBidders = extPrebidData != null ? extPrebidData.getBidders() : null;
final List<String> updatedPrebidDataBidders = prebidDataBidders != null
? (List<String>) CollectionUtils.union(targetBidders, prebidDataBidders)
: targetBidders;
final List<String> originalBidders = extPrebidData != null ? extPrebidData.getBidders() : null;

final Set<String> resolvedSources = resolvedEids.stream().map(Eid::getSource).collect(Collectors.toSet());
final Set<String> resolvedSources = resolvedEids.stream()
.map(Eid::getSource)
.collect(Collectors.toSet());

final List<ExtRequestPrebidDataEidPermissions> initialPermissions = Optional.ofNullable(extPrebidData)
.map(ExtRequestPrebidData::getEidPermissions)
.orElse(Collections.emptyList());
final List<ExtRequestPrebidDataEidPermissions> updatedPermissions = Stream.concat(
initialPermissions.stream()
.map(permission -> updateEidPermission(permission, resolvedSources)),
resolvedSources.stream()
.map(source -> ExtRequestPrebidDataEidPermissions.of(source, targetBidders)))
.filter(StreamUtil.distinctBy(ExtRequestPrebidDataEidPermissions::getSource))
.orElse(List.of());

final List<ExtRequestPrebidDataEidPermissions> updatedPermissions = initialPermissions.stream()
.map(permission -> restrictEidPermission(permission, resolvedSources))
.filter(Objects::nonNull)
.toList();

return ExtRequestPrebidData.of(updatedPrebidDataBidders, updatedPermissions);
return ExtRequestPrebidData.of(originalBidders, updatedPermissions);
}

private ExtRequestPrebidDataEidPermissions updateEidPermission(ExtRequestPrebidDataEidPermissions permission,
Set<String> resolvedSources) {
private ExtRequestPrebidDataEidPermissions restrictEidPermission(ExtRequestPrebidDataEidPermissions permission,
Set<String> resolvedSources) {

if (!resolvedSources.contains(permission.getSource())) {
return permission;
}

final List<String> current = ListUtils.emptyIfNull(permission.getBidders());
final List<String> finalBidders = ListUtils.intersection(current, targetBidders);

return resolvedSources.contains(permission.getSource())
? ExtRequestPrebidDataEidPermissions.of(
permission.getSource(),
(List<String>) CollectionUtils.union(permission.getBidders(), targetBidders))
: permission;
return finalBidders.isEmpty()
? null
: ExtRequestPrebidDataEidPermissions.of(permission.getSource(), finalBidders);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -375,14 +375,33 @@ public void callShouldReturnFailureWhenRequestingEidsIsFailed() {
}

@Test
public void biddersConfiguredRestrictionShouldBeRespected() {
public void shouldRestrictExistingEidPermissionsByIntersectionAndKeepGlobalBiddersUnchanged() {
// given
final Uid givenUid = Uid.builder().id("id1").atype(2).build();
final Eid givenEid = Eid.builder().source("some.source.com").uids(singletonList(givenUid)).build();
final User givenUser = User.builder().eids(singletonList(givenEid)).build();
final BidRequest givenBidRequest = BidRequest.builder().id("request").user(givenUser).build();

final ExtRequestPrebidData expectedData = ExtRequestPrebidData.of(configuredBidders, List.of(
ExtRequestPrebidDataEidPermissions.of("liveintent.com", configuredBidders)));
// existing global bidders and eid permissions including liveintent.com
final ExtRequestPrebidData givenData = ExtRequestPrebidData.of(
List.of("bidderX"),
List.of(
ExtRequestPrebidDataEidPermissions.of("some.other-source.com", List.of("bidderY")),
ExtRequestPrebidDataEidPermissions.of("liveintent.com", List.of("bidder2", "bidder3"))
));

final BidRequest givenBidRequest = BidRequest.builder()
.id("request")
.user(givenUser)
.ext(ExtRequest.of(ExtRequestPrebid.builder().data(givenData).build()))
.build();

// expected: global bidders unchanged, liveintent.com bidders intersected with configuredBidders => [bidder2]
final ExtRequestPrebidData expectedData = ExtRequestPrebidData.of(
List.of("bidderX"),
List.of(
ExtRequestPrebidDataEidPermissions.of("some.other-source.com", List.of("bidderY")),
ExtRequestPrebidDataEidPermissions.of("liveintent.com", List.of("bidder2"))
));

final Eid expectedEid = Eid.builder().source("liveintent.com").build();

Expand Down Expand Up @@ -418,7 +437,7 @@ public void biddersConfiguredRestrictionShouldBeRespected() {
}

@Test
public void biddersConfiguredRestrictionShouldBeMergedWithProvided() {
public void shouldNotAddNewEidPermissionsOrModifyGlobalBiddersWhenSourceNotPresent() {
// given
final Uid givenUid = Uid.builder().id("id1").atype(2).build();
final Eid givenEid = Eid.builder().source("some.source.com").uids(singletonList(givenUid)).build();
Expand All @@ -429,12 +448,10 @@ public void biddersConfiguredRestrictionShouldBeMergedWithProvided() {
ExtRequestPrebidDataEidPermissions.of("some.source.com", List.of("bidder3"))))
).build())).build();

final List<String> expectedBidders = List.of("bidder3", "bidder2", "bidder1");

final ExtRequestPrebidData expectedData = ExtRequestPrebidData.of(expectedBidders, List.of(
// expected: unchanged, because there is no existing permission for liveintent.com
final ExtRequestPrebidData expectedData = ExtRequestPrebidData.of(List.of("bidder3"), List.of(
ExtRequestPrebidDataEidPermissions.of("some.other-source.com", List.of("bidder3")),
ExtRequestPrebidDataEidPermissions.of("some.source.com", List.of("bidder3")),
ExtRequestPrebidDataEidPermissions.of("liveintent.com", configuredBidders)));
ExtRequestPrebidDataEidPermissions.of("some.source.com", List.of("bidder3"))));

final Eid expectedEid = Eid.builder().source("liveintent.com").build();

Expand Down Expand Up @@ -468,4 +485,64 @@ public void biddersConfiguredRestrictionShouldBeMergedWithProvided() {
eq(MAPPER.encodeToString(givenBidRequest)),
eq(5L));
}

@Test
public void shouldRemovePermissionWhenIntersectionIsEmpty() {
// given
final Uid givenUid = Uid.builder().id("id1").atype(2).build();
final Eid givenEid = Eid.builder().source("some.source.com").uids(singletonList(givenUid)).build();
final User givenUser = User.builder().eids(singletonList(givenEid)).build();

final ExtRequestPrebidData givenData = ExtRequestPrebidData.of(
List.of("bidderGlobal"),
List.of(
ExtRequestPrebidDataEidPermissions.of("liveintent.com", List.of("not-allowed")),
ExtRequestPrebidDataEidPermissions.of("keep.com", List.of("bidderGlobal"))
));

final BidRequest givenBidRequest = BidRequest.builder()
.id("request")
.user(givenUser)
.ext(ExtRequest.of(ExtRequestPrebid.builder().data(givenData).build()))
.build();

// Respond with liveintent.com so that restriction is applied and becomes empty -> remove entry
final Eid expectedEid = Eid.builder().source("liveintent.com").build();
final String responseBody = MAPPER.encodeToString(IdResResponse.of(List.of(expectedEid)));
given(httpClient.post(any(), any(), any(), anyLong()))
.willReturn(Future.succeededFuture(HttpClientResponse.of(200, null, responseBody)));

given(auctionInvocationContext.auctionContext()).willReturn(auctionContext);
given(auctionContext.getActivityInfrastructure()).willReturn(activityInfrastructure);
given(activityInfrastructure.isAllowed(any(), any())).willReturn(true);
given(userFpdActivityMask.maskUser(any(), eq(false), eq(false)))
.willAnswer(invocation -> invocation.getArgument(0));
given(userFpdActivityMask.maskDevice(any(), eq(false), eq(false)))
.willAnswer(invocation -> invocation.getArgument(0));

// when
final InvocationResult<AuctionRequestPayload> result =
target.call(AuctionRequestPayloadImpl.of(givenBidRequest), auctionInvocationContext).result();

// then
final ExtRequestPrebidData expectedData = ExtRequestPrebidData.of(
List.of("bidderGlobal"),
List.of(
ExtRequestPrebidDataEidPermissions.of("keep.com", List.of("bidderGlobal"))
));

assertThat(result.status()).isEqualTo(InvocationStatus.success);
assertThat(result.payloadUpdate().apply(AuctionRequestPayloadImpl.of(givenBidRequest)))
.extracting(AuctionRequestPayload::bidRequest)
.extracting(BidRequest::getExt)
.extracting(ExtRequest::getPrebid)
.extracting(ExtRequestPrebid::getData)
.isEqualTo(expectedData);

verify(httpClient).post(
eq("https://test.com/idres"),
argThat(headers -> headers.contains("Authorization", "Bearer auth_token", true)),
eq(MAPPER.encodeToString(givenBidRequest)),
eq(5L));
}
}
Loading