Skip to content

Commit 8f91278

Browse files
authored
Module update: LI EID permissions (prebid#4315)
1 parent a974b78 commit 8f91278

3 files changed

Lines changed: 156 additions & 49 deletions

File tree

extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/model/config/LiveIntentOmniChannelProperties.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import lombok.Data;
44

5-
import java.util.List;
5+
import java.util.Set;
66

77
@Data
88
public final class LiveIntentOmniChannelProperties {
@@ -15,5 +15,5 @@ public final class LiveIntentOmniChannelProperties {
1515

1616
float treatmentRate;
1717

18-
List<String> targetBidders;
18+
Set<String> targetBidders;
1919
}

extra/modules/live-intent-omni-channel-identity/src/main/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/hooks/LiveIntentOmniChannelIdentityProcessedAuctionRequestHook.java

Lines changed: 39 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import io.vertx.core.MultiMap;
1010
import org.apache.commons.collections4.CollectionUtils;
1111
import org.apache.commons.collections4.ListUtils;
12+
import org.apache.commons.collections4.SetUtils;
1213
import org.prebid.server.activity.Activity;
1314
import org.prebid.server.activity.ComponentType;
1415
import org.prebid.server.activity.infrastructure.ActivityInfrastructure;
@@ -40,18 +41,15 @@
4041
import org.prebid.server.proto.openrtb.ext.request.ExtRequestPrebidDataEidPermissions;
4142
import org.prebid.server.util.HttpUtil;
4243
import org.prebid.server.util.ListUtil;
43-
import org.prebid.server.util.StreamUtil;
4444
import org.prebid.server.vertx.httpclient.HttpClient;
4545
import org.prebid.server.vertx.httpclient.model.HttpClientResponse;
4646

47-
import java.util.Collections;
4847
import java.util.List;
4948
import java.util.Objects;
5049
import java.util.Optional;
5150
import java.util.Set;
5251
import java.util.concurrent.ThreadLocalRandom;
5352
import java.util.stream.Collectors;
54-
import java.util.stream.Stream;
5553

5654
public class LiveIntentOmniChannelIdentityProcessedAuctionRequestHook implements ProcessedAuctionRequestHook {
5755

@@ -65,7 +63,7 @@ public class LiveIntentOmniChannelIdentityProcessedAuctionRequestHook implements
6563
private final HttpClient httpClient;
6664
private final UserFpdActivityMask userFpdActivityMask;
6765
private final double logSamplingRate;
68-
private final List<String> targetBidders;
66+
private final Set<String> targetBidders;
6967

7068
public LiveIntentOmniChannelIdentityProcessedAuctionRequestHook(LiveIntentOmniChannelProperties config,
7169
UserFpdActivityMask userFpdActivityMask,
@@ -79,7 +77,7 @@ public LiveIntentOmniChannelIdentityProcessedAuctionRequestHook(LiveIntentOmniCh
7977
this.httpClient = Objects.requireNonNull(httpClient);
8078
this.logSamplingRate = logSamplingRate;
8179
this.userFpdActivityMask = Objects.requireNonNull(userFpdActivityMask);
82-
this.targetBidders = ListUtils.emptyIfNull(config.getTargetBidders());
80+
this.targetBidders = SetUtils.emptyIfNull(config.getTargetBidders());
8381
}
8482

8583
@Override
@@ -202,14 +200,22 @@ private AuctionRequestPayload updatedPayload(AuctionRequestPayload requestPayloa
202200
}
203201

204202
private BidRequest updateAllowedBidders(BidRequest bidRequest, List<Eid> resolvedEids) {
205-
if (targetBidders.isEmpty()) {
203+
if (CollectionUtils.isEmpty(targetBidders) || CollectionUtils.isEmpty(resolvedEids)) {
206204
return bidRequest;
207205
}
208206

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

211+
final List<ExtRequestPrebidDataEidPermissions> existingPerms = extPrebidData != null
212+
? extPrebidData.getEidPermissions()
213+
: null;
214+
215+
if (CollectionUtils.isEmpty(existingPerms)) {
216+
return bidRequest;
217+
}
218+
213219
final ExtRequestPrebid updatedExtPrebid = Optional.ofNullable(extPrebid)
214220
.map(ExtRequestPrebid::toBuilder)
215221
.orElseGet(ExtRequestPrebid::builder)
@@ -225,35 +231,38 @@ private BidRequest updateAllowedBidders(BidRequest bidRequest, List<Eid> resolve
225231
}
226232

227233
private ExtRequestPrebidData updatePrebidData(ExtRequestPrebidData extPrebidData, List<Eid> resolvedEids) {
228-
final List<String> prebidDataBidders = extPrebidData != null ? extPrebidData.getBidders() : null;
229-
final List<String> updatedPrebidDataBidders = prebidDataBidders != null
230-
? (List<String>) CollectionUtils.union(targetBidders, prebidDataBidders)
231-
: targetBidders;
232-
233-
final Set<String> resolvedSources = resolvedEids.stream().map(Eid::getSource).collect(Collectors.toSet());
234-
235-
final List<ExtRequestPrebidDataEidPermissions> initialPermissions = Optional.ofNullable(extPrebidData)
236-
.map(ExtRequestPrebidData::getEidPermissions)
237-
.orElse(Collections.emptyList());
238-
final List<ExtRequestPrebidDataEidPermissions> updatedPermissions = Stream.concat(
239-
initialPermissions.stream()
240-
.map(permission -> updateEidPermission(permission, resolvedSources)),
241-
resolvedSources.stream()
242-
.map(source -> ExtRequestPrebidDataEidPermissions.of(source, targetBidders)))
243-
.filter(StreamUtil.distinctBy(ExtRequestPrebidDataEidPermissions::getSource))
234+
final List<String> originalBidders = extPrebidData != null ? extPrebidData.getBidders() : null;
235+
236+
final Set<String> resolvedSources = resolvedEids.stream()
237+
.map(Eid::getSource)
238+
.collect(Collectors.toSet());
239+
240+
final List<ExtRequestPrebidDataEidPermissions> updatedPermissions = extPrebidData.getEidPermissions().stream()
241+
.map(permission -> restrictEidPermission(permission, resolvedSources))
242+
.filter(Objects::nonNull)
244243
.toList();
245244

246-
return ExtRequestPrebidData.of(updatedPrebidDataBidders, updatedPermissions);
245+
return ExtRequestPrebidData.of(originalBidders, updatedPermissions);
247246
}
248247

249-
private ExtRequestPrebidDataEidPermissions updateEidPermission(ExtRequestPrebidDataEidPermissions permission,
250-
Set<String> resolvedSources) {
248+
private ExtRequestPrebidDataEidPermissions restrictEidPermission(ExtRequestPrebidDataEidPermissions permission,
249+
Set<String> resolvedSources) {
251250

252-
return resolvedSources.contains(permission.getSource())
253-
? ExtRequestPrebidDataEidPermissions.of(
254-
permission.getSource(),
255-
(List<String>) CollectionUtils.union(permission.getBidders(), targetBidders))
256-
: permission;
251+
if (!resolvedSources.contains(permission.getSource())) {
252+
return permission;
253+
}
254+
255+
final List<String> finalBidders = ListUtils.emptyIfNull(permission.getBidders()).stream()
256+
.filter(targetBidders::contains)
257+
.toList();
258+
259+
return CollectionUtils.isEmpty(finalBidders)
260+
? null
261+
: ExtRequestPrebidDataEidPermissions
262+
.builder()
263+
.bidders(finalBidders)
264+
.source(permission.getSource())
265+
.build();
257266
}
258267

259268
@Override

extra/modules/live-intent-omni-channel-identity/src/test/java/org/prebid/server/hooks/modules/liveintent/omni/channel/identity/v1/LiveIntentOmniChannelIdentityProcessedAuctionRequestHookTest.java

Lines changed: 115 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import org.prebid.server.vertx.httpclient.model.HttpClientResponse;
3737

3838
import java.util.List;
39+
import java.util.Set;
3940
import java.util.concurrent.TimeoutException;
4041

4142
import static java.util.Collections.singletonList;
@@ -74,11 +75,11 @@ public class LiveIntentOmniChannelIdentityProcessedAuctionRequestHookTest {
7475

7576
private LiveIntentOmniChannelIdentityProcessedAuctionRequestHook target;
7677

77-
private List<String> configuredBidders;
78+
private Set<String> configuredBidders;
7879

7980
@BeforeEach
8081
public void setUp() {
81-
configuredBidders = List.of("bidder1", "bidder2");
82+
configuredBidders = Set.of("bidder1", "bidder2");
8283
given(properties.getRequestTimeoutMs()).willReturn(5L);
8384
given(properties.getIdentityResolutionEndpoint()).willReturn("https://test.com/idres");
8485
given(properties.getAuthToken()).willReturn("auth_token");
@@ -375,14 +376,38 @@ public void callShouldReturnFailureWhenRequestingEidsIsFailed() {
375376
}
376377

377378
@Test
378-
public void biddersConfiguredRestrictionShouldBeRespected() {
379+
public void shouldRestrictExistingEidPermissionsByIntersectionAndKeepGlobalBiddersUnchanged() {
380+
// given
379381
final Uid givenUid = Uid.builder().id("id1").atype(2).build();
380382
final Eid givenEid = Eid.builder().source("some.source.com").uids(singletonList(givenUid)).build();
381383
final User givenUser = User.builder().eids(singletonList(givenEid)).build();
382-
final BidRequest givenBidRequest = BidRequest.builder().id("request").user(givenUser).build();
383384

384-
final ExtRequestPrebidData expectedData = ExtRequestPrebidData.of(configuredBidders, List.of(
385-
ExtRequestPrebidDataEidPermissions.of("liveintent.com", configuredBidders)));
385+
final ExtRequestPrebidDataEidPermissions otherBidder = ExtRequestPrebidDataEidPermissions.builder()
386+
.source("some.other-source.com")
387+
.bidders(singletonList("bidderY"))
388+
.build();
389+
390+
final ExtRequestPrebidDataEidPermissions liBidder2 = ExtRequestPrebidDataEidPermissions.builder()
391+
.source("liveintent.com")
392+
.bidders(singletonList("bidder2"))
393+
.build();
394+
final ExtRequestPrebidDataEidPermissions liBidder23 = ExtRequestPrebidDataEidPermissions.builder()
395+
.source("liveintent.com")
396+
.bidders(List.of("bidder2", "bidder3"))
397+
.build();
398+
399+
final ExtRequestPrebidData givenData = ExtRequestPrebidData.of(singletonList("bidderX"),
400+
List.of(otherBidder, liBidder23));
401+
402+
final BidRequest givenBidRequest = BidRequest.builder()
403+
.id("request")
404+
.user(givenUser)
405+
.ext(ExtRequest.of(ExtRequestPrebid.builder().data(givenData).build()))
406+
.build();
407+
408+
final ExtRequestPrebidData expectedData = ExtRequestPrebidData.of(
409+
List.of("bidderX"),
410+
List.of(otherBidder, liBidder2));
386411

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

@@ -418,23 +443,31 @@ public void biddersConfiguredRestrictionShouldBeRespected() {
418443
}
419444

420445
@Test
421-
public void biddersConfiguredRestrictionShouldBeMergedWithProvided() {
446+
public void shouldNotAddNewEidPermissionsOrModifyGlobalBiddersWhenSourceNotPresent() {
422447
// given
423448
final Uid givenUid = Uid.builder().id("id1").atype(2).build();
424449
final Eid givenEid = Eid.builder().source("some.source.com").uids(singletonList(givenUid)).build();
425450
final User givenUser = User.builder().eids(singletonList(givenEid)).build();
426-
final BidRequest givenBidRequest = BidRequest.builder().id("request").user(givenUser).ext(ExtRequest.of(
427-
ExtRequestPrebid.builder().data(ExtRequestPrebidData.of(List.of("bidder3"), List.of(
428-
ExtRequestPrebidDataEidPermissions.of("some.other-source.com", List.of("bidder3")),
429-
ExtRequestPrebidDataEidPermissions.of("some.source.com", List.of("bidder3"))))
430-
).build())).build();
451+
final ExtRequestPrebidDataEidPermissions bidder1 = ExtRequestPrebidDataEidPermissions.builder()
452+
.source("some.other-source.com")
453+
.bidders(singletonList("bidder3"))
454+
.build();
455+
final ExtRequestPrebidDataEidPermissions bidder2 = ExtRequestPrebidDataEidPermissions.builder()
456+
.source("some.source.com")
457+
.bidders(singletonList("bidder3"))
458+
.build();
431459

432-
final List<String> expectedBidders = List.of("bidder3", "bidder2", "bidder1");
460+
final List<ExtRequestPrebidDataEidPermissions> bidders = List.of(bidder1, bidder2);
433461

434-
final ExtRequestPrebidData expectedData = ExtRequestPrebidData.of(expectedBidders, List.of(
435-
ExtRequestPrebidDataEidPermissions.of("some.other-source.com", List.of("bidder3")),
436-
ExtRequestPrebidDataEidPermissions.of("some.source.com", List.of("bidder3")),
437-
ExtRequestPrebidDataEidPermissions.of("liveintent.com", configuredBidders)));
462+
final BidRequest givenBidRequest = BidRequest.builder()
463+
.id("request")
464+
.user(givenUser)
465+
.ext(ExtRequest.of(ExtRequestPrebid.builder()
466+
.data(ExtRequestPrebidData.of(singletonList("bidder3"), bidders))
467+
.build()))
468+
.build();
469+
470+
final ExtRequestPrebidData expectedData = ExtRequestPrebidData.of(List.of("bidder3"), bidders);
438471

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

@@ -468,4 +501,69 @@ public void biddersConfiguredRestrictionShouldBeMergedWithProvided() {
468501
eq(MAPPER.encodeToString(givenBidRequest)),
469502
eq(5L));
470503
}
504+
505+
@Test
506+
public void shouldRemovePermissionWhenIntersectionIsEmpty() {
507+
// given
508+
final Uid givenUid = Uid.builder().id("id1").atype(2).build();
509+
final Eid givenEid = Eid.builder().source("some.source.com").uids(singletonList(givenUid)).build();
510+
final User givenUser = User.builder().eids(singletonList(givenEid)).build();
511+
512+
final ExtRequestPrebidData givenData = ExtRequestPrebidData.of(
513+
List.of("bidderGlobal"),
514+
List.of(
515+
ExtRequestPrebidDataEidPermissions.builder()
516+
.source("liveintent.com")
517+
.bidders(singletonList("not-allowed"))
518+
.build(),
519+
ExtRequestPrebidDataEidPermissions.builder()
520+
.source("keep.com")
521+
.bidders(singletonList("bidderGlobal"))
522+
.build()));
523+
524+
final BidRequest givenBidRequest = BidRequest.builder()
525+
.id("request")
526+
.user(givenUser)
527+
.ext(ExtRequest.of(ExtRequestPrebid.builder().data(givenData).build()))
528+
.build();
529+
530+
final Eid expectedEid = Eid.builder().source("liveintent.com").build();
531+
final String responseBody = MAPPER.encodeToString(IdResResponse.of(List.of(expectedEid)));
532+
given(httpClient.post(any(), any(), any(), anyLong()))
533+
.willReturn(Future.succeededFuture(HttpClientResponse.of(200, null, responseBody)));
534+
535+
given(auctionInvocationContext.auctionContext()).willReturn(auctionContext);
536+
given(auctionContext.getActivityInfrastructure()).willReturn(activityInfrastructure);
537+
given(activityInfrastructure.isAllowed(any(), any())).willReturn(true);
538+
given(userFpdActivityMask.maskUser(any(), eq(false), eq(false)))
539+
.willAnswer(invocation -> invocation.getArgument(0));
540+
given(userFpdActivityMask.maskDevice(any(), eq(false), eq(false)))
541+
.willAnswer(invocation -> invocation.getArgument(0));
542+
543+
// when
544+
final InvocationResult<AuctionRequestPayload> result =
545+
target.call(AuctionRequestPayloadImpl.of(givenBidRequest), auctionInvocationContext).result();
546+
547+
// then
548+
final ExtRequestPrebidData expectedData = ExtRequestPrebidData.of(
549+
List.of("bidderGlobal"),
550+
List.of(ExtRequestPrebidDataEidPermissions.builder()
551+
.source("keep.com")
552+
.bidders(singletonList("bidderGlobal"))
553+
.build()));
554+
555+
assertThat(result.status()).isEqualTo(InvocationStatus.success);
556+
assertThat(result.payloadUpdate().apply(AuctionRequestPayloadImpl.of(givenBidRequest)))
557+
.extracting(AuctionRequestPayload::bidRequest)
558+
.extracting(BidRequest::getExt)
559+
.extracting(ExtRequest::getPrebid)
560+
.extracting(ExtRequestPrebid::getData)
561+
.isEqualTo(expectedData);
562+
563+
verify(httpClient).post(
564+
eq("https://test.com/idres"),
565+
argThat(headers -> headers.contains("Authorization", "Bearer auth_token", true)),
566+
eq(MAPPER.encodeToString(givenBidRequest)),
567+
eq(5L));
568+
}
471569
}

0 commit comments

Comments
 (0)