Skip to content

Commit 7861a1e

Browse files
Eidpermissions Request Validation Update (#3666)
1 parent 32bffd1 commit 7861a1e

File tree

11 files changed

+224
-117
lines changed

11 files changed

+224
-117
lines changed

src/main/java/org/prebid/server/auction/requestfactory/AmpRequestFactory.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -417,6 +417,7 @@ private Future<BidRequest> updateBidRequest(AuctionContext auctionContext) {
417417
.compose(resolvedBidRequest -> ortb2RequestFactory.validateRequest(
418418
resolvedBidRequest,
419419
auctionContext.getHttpRequest(),
420+
auctionContext.getDebugContext(),
420421
auctionContext.getDebugWarnings()));
421422
}
422423

src/main/java/org/prebid/server/auction/requestfactory/AuctionRequestFactory.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,8 @@ private Future<BidRequest> updateAndValidateBidRequest(AuctionContext auctionCon
241241

242242
return storedRequestProcessor.processAuctionRequest(account.getId(), auctionContext.getBidRequest())
243243
.compose(auctionStoredResult -> updateBidRequest(auctionStoredResult, auctionContext))
244-
.compose(bidRequest -> ortb2RequestFactory.validateRequest(bidRequest, httpRequest, debugWarnings))
244+
.compose(bidRequest -> ortb2RequestFactory.validateRequest(
245+
bidRequest, httpRequest, auctionContext.getDebugContext(), debugWarnings))
245246
.map(interstitialProcessor::process);
246247
}
247248

src/main/java/org/prebid/server/auction/requestfactory/Ortb2RequestFactory.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,9 +194,11 @@ public Future<ActivityInfrastructure> activityInfrastructureFrom(AuctionContext
194194

195195
public Future<BidRequest> validateRequest(BidRequest bidRequest,
196196
HttpRequestContext httpRequestContext,
197+
DebugContext debugContext,
197198
List<String> warnings) {
198199

199-
final ValidationResult validationResult = requestValidator.validate(bidRequest, httpRequestContext);
200+
final ValidationResult validationResult = requestValidator.validate(
201+
bidRequest, httpRequestContext, debugContext);
200202

201203
if (validationResult.hasWarnings()) {
202204
warnings.addAll(validationResult.getWarnings());

src/main/java/org/prebid/server/auction/requestfactory/VideoRequestFactory.java

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -110,21 +110,24 @@ public Future<WithPodErrors<AuctionContext>> fromRequest(RoutingContext routingC
110110
return ortb2RequestFactory.executeEntrypointHooks(routingContext, body, initialAuctionContext)
111111
.compose(httpRequest -> createBidRequest(httpRequest)
112112
.map(bidRequest -> removeEmptyEids(bidRequest, initialAuctionContext.getDebugWarnings()))
113-
.compose(bidRequest -> validateRequest(
114-
bidRequest,
115-
httpRequest,
116-
initialAuctionContext.getDebugWarnings()))
117113

118114
.map(bidRequestWithErrors -> populatePodErrors(
119115
bidRequestWithErrors.getPodErrors(), podErrors, bidRequestWithErrors))
120116

121117
.map(bidRequestWithErrors -> ortb2RequestFactory.enrichAuctionContext(
122118
initialAuctionContext, httpRequest, bidRequestWithErrors.getData(), startTime)))
123119

124-
.compose(auctionContext -> ortb2RequestFactory.fetchAccountWithoutStoredRequestLookup(auctionContext)
120+
.map(auctionContext -> auctionContext.with(debugResolver.debugContextFrom(auctionContext)))
121+
122+
.compose(auctionContext -> ortb2RequestFactory.validateRequest(
123+
auctionContext.getBidRequest(),
124+
auctionContext.getHttpRequest(),
125+
auctionContext.getDebugContext(),
126+
auctionContext.getDebugWarnings())
125127
.map(auctionContext::with))
126128

127-
.map(auctionContext -> auctionContext.with(debugResolver.debugContextFrom(auctionContext)))
129+
.compose(auctionContext -> ortb2RequestFactory.fetchAccountWithoutStoredRequestLookup(auctionContext)
130+
.map(auctionContext::with))
128131

129132
.compose(auctionContext -> geoLocationServiceWrapper.lookup(auctionContext)
130133
.map(auctionContext::with))
@@ -323,12 +326,4 @@ private WithPodErrors<BidRequest> fillImplicitParameters(HttpRequestContext http
323326

324327
return WithPodErrors.of(updatedWithDebugBidRequest, bidRequestToErrors.getPodErrors());
325328
}
326-
327-
private Future<WithPodErrors<BidRequest>> validateRequest(WithPodErrors<BidRequest> requestWithPodErrors,
328-
HttpRequestContext httpRequestContext,
329-
List<String> warnings) {
330-
331-
return ortb2RequestFactory.validateRequest(requestWithPodErrors.getData(), httpRequestContext, warnings)
332-
.map(bidRequest -> requestWithPodErrors);
333-
}
334329
}

src/main/java/org/prebid/server/validation/RequestValidator.java

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import org.apache.commons.collections4.MapUtils;
1616
import org.apache.commons.lang3.ObjectUtils;
1717
import org.apache.commons.lang3.StringUtils;
18+
import org.prebid.server.auction.model.debug.DebugContext;
1819
import org.prebid.server.bidder.BidderCatalog;
1920
import org.prebid.server.json.JacksonMapper;
2021
import org.prebid.server.log.ConditionalLogger;
@@ -96,8 +97,12 @@ public RequestValidator(BidderCatalog bidderCatalog,
9697
* Validates the {@link BidRequest} against a list of validation checks, however, reports only one problem
9798
* at a time.
9899
*/
99-
public ValidationResult validate(BidRequest bidRequest, HttpRequestContext httpRequestContext) {
100+
public ValidationResult validate(BidRequest bidRequest,
101+
HttpRequestContext httpRequestContext,
102+
DebugContext debugContext) {
103+
100104
final List<String> warnings = new ArrayList<>();
105+
final boolean isDebugEnabled = debugContext != null && debugContext.isDebugEnabled();
101106
try {
102107
if (StringUtils.isBlank(bidRequest.getId())) {
103108
throw new ValidationException("request missing required field: \"id\"");
@@ -124,7 +129,7 @@ public ValidationResult validate(BidRequest bidRequest, HttpRequestContext httpR
124129
validateAliases(aliases);
125130
validateAliasesGvlIds(extRequestPrebid, aliases);
126131
validateBidAdjustmentFactors(extRequestPrebid.getBidadjustmentfactors(), aliases);
127-
validateExtBidPrebidData(extRequestPrebid.getData(), aliases);
132+
validateExtBidPrebidData(extRequestPrebid.getData(), aliases, isDebugEnabled, warnings);
128133
validateSchains(extRequestPrebid.getSchains());
129134
}
130135

@@ -313,15 +318,20 @@ private void validateSchains(List<ExtRequestPrebidSchain> schains) throws Valida
313318
}
314319
}
315320

316-
private void validateExtBidPrebidData(ExtRequestPrebidData data, Map<String, String> aliases)
317-
throws ValidationException {
321+
private void validateExtBidPrebidData(ExtRequestPrebidData data,
322+
Map<String, String> aliases,
323+
boolean isDebugEnabled,
324+
List<String> warnings) throws ValidationException {
325+
318326
if (data != null) {
319-
validateEidPermissions(data.getEidPermissions(), aliases);
327+
validateEidPermissions(data.getEidPermissions(), aliases, isDebugEnabled, warnings);
320328
}
321329
}
322330

323331
private void validateEidPermissions(List<ExtRequestPrebidDataEidPermissions> eidPermissions,
324-
Map<String, String> aliases) throws ValidationException {
332+
Map<String, String> aliases,
333+
boolean isDebugEnabled,
334+
List<String> warnings) throws ValidationException {
325335

326336
if (eidPermissions == null) {
327337
return;
@@ -333,7 +343,7 @@ private void validateEidPermissions(List<ExtRequestPrebidDataEidPermissions> eid
333343
}
334344

335345
validateEidPermissionSource(eidPermission.getSource());
336-
validateEidPermissionBidders(eidPermission.getBidders(), aliases);
346+
validateEidPermissionBidders(eidPermission.getBidders(), aliases, isDebugEnabled, warnings);
337347
}
338348
}
339349

@@ -344,18 +354,22 @@ private void validateEidPermissionSource(String source) throws ValidationExcepti
344354
}
345355

346356
private void validateEidPermissionBidders(List<String> bidders,
347-
Map<String, String> aliases) throws ValidationException {
357+
Map<String, String> aliases,
358+
boolean isDebugEnabled,
359+
List<String> warnings) throws ValidationException {
348360

349361
if (CollectionUtils.isEmpty(bidders)) {
350362
throw new ValidationException("request.ext.prebid.data.eidpermissions[].bidders[] required values"
351363
+ " but was empty or null");
352364
}
353365

354-
for (String bidder : bidders) {
355-
if (!bidderCatalog.isValidName(bidder) && !bidderCatalog.isValidName(aliases.get(bidder))
356-
&& ObjectUtils.notEqual(bidder, ASTERISK)) {
357-
throw new ValidationException(
358-
"request.ext.prebid.data.eidPermissions[].bidders[] unrecognized biddercode: '%s'", bidder);
366+
if (isDebugEnabled) {
367+
for (String bidder : bidders) {
368+
if (!bidderCatalog.isValidName(bidder) && !bidderCatalog.isValidName(aliases.get(bidder))
369+
&& ObjectUtils.notEqual(bidder, ASTERISK)) {
370+
warnings.add("request.ext.prebid.data.eidPermissions[].bidders[] unrecognized biddercode: '%s'"
371+
.formatted(bidder));
372+
}
359373
}
360374
}
361375
}

src/test/groovy/org/prebid/server/functional/tests/EidsSpec.groovy

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,17 @@ import org.prebid.server.functional.util.PBSUtils
1616
import static org.prebid.server.functional.model.bidder.BidderName.ALIAS
1717
import static org.prebid.server.functional.model.bidder.BidderName.GENERIC
1818
import static org.prebid.server.functional.model.bidder.BidderName.OPENX
19+
import static org.prebid.server.functional.model.bidder.BidderName.UNKNOWN
1920
import static org.prebid.server.functional.model.bidder.BidderName.WILDCARD
21+
import static org.prebid.server.functional.model.request.auction.DebugCondition.DISABLED
22+
import static org.prebid.server.functional.model.request.auction.DebugCondition.ENABLED
2023
import static org.prebid.server.functional.model.response.auction.ErrorType.PREBID
2124
import static org.prebid.server.functional.testcontainers.Dependencies.getNetworkServiceContainer
2225

2326
class EidsSpec extends BaseSpec {
2427

2528
private static final String EMPTY_STRING = ""
29+
private static final String RANDOM_SOURCE_ID = PBSUtils.randomString
2630

2731
def "PBS shouldn't populate user.id from user.ext data"() {
2832
given: "Default basic BidRequest with generic bidder"
@@ -91,6 +95,68 @@ class EidsSpec extends BaseSpec {
9195
assert !bidderRequest.user.eids
9296
}
9397

98+
def "PBS eids shouldn't include warning for unknown bidder when test and debug disabled"() {
99+
given: "Default bid request with generic bidder"
100+
def bidRequest = BidRequest.defaultBidRequest.tap {
101+
user = requestUser
102+
ext.prebid.data = new ExtRequestPrebidData(eidpermissions: [new EidPermission(source: RANDOM_SOURCE_ID, bidders: [UNKNOWN])])
103+
it.ext.prebid.debug = DISABLED
104+
it.test = DISABLED
105+
}
106+
107+
when: "PBS processes auction request"
108+
def bidResponse = defaultPbsService.sendAuctionRequest(bidRequest)
109+
110+
then: "Bidder request shouldn't contain requested eids"
111+
def bidderRequest = bidder.getBidderRequest(bidRequest.id)
112+
assert !bidderRequest.user.eids
113+
114+
and: "Bid response shouldn't contain warning"
115+
assert !bidResponse.ext.warnings
116+
117+
where:
118+
requestUser << [new User(eids: [Eid.getDefaultEid(RANDOM_SOURCE_ID)]),
119+
new User(ext: new UserExt(eids: [Eid.getDefaultEid(RANDOM_SOURCE_ID)])),
120+
new User(eids: [Eid.getDefaultEid(RANDOM_SOURCE_ID)],
121+
ext: new UserExt(eids: [Eid.getDefaultEid(RANDOM_SOURCE_ID)]))]
122+
}
123+
124+
def "PBS eids should include warning for unknown bidder when request in debug mode"() {
125+
given: "Default bid request with generic bidder"
126+
def bidRequest = BidRequest.defaultBidRequest.tap {
127+
user = requestUser
128+
ext.prebid.data = new ExtRequestPrebidData(eidpermissions: [new EidPermission(source: RANDOM_SOURCE_ID, bidders: [UNKNOWN])])
129+
it.ext.prebid.debug = debug
130+
it.test = test
131+
}
132+
133+
when: "PBS processes auction request"
134+
def bidResponse = defaultPbsService.sendAuctionRequest(bidRequest)
135+
136+
then: "Bidder request shouldn't contain requested eids"
137+
def bidderRequest = bidder.getBidderRequest(bidRequest.id)
138+
assert !bidderRequest.user.eids
139+
140+
and: "Bid response should contain warning"
141+
assert bidResponse.ext.warnings[PREBID]?.code == [999]
142+
assert bidResponse.ext.warnings[PREBID]?.message ==
143+
["request.ext.prebid.data.eidPermissions[].bidders[] unrecognized biddercode: '$UNKNOWN'"]
144+
145+
where:
146+
debug | test | requestUser
147+
DISABLED | ENABLED | new User(eids: [Eid.getDefaultEid(RANDOM_SOURCE_ID)])
148+
DISABLED | ENABLED | new User(ext: new UserExt(eids: [Eid.getDefaultEid(RANDOM_SOURCE_ID)]))
149+
DISABLED | ENABLED | new User(eids: [Eid.getDefaultEid(RANDOM_SOURCE_ID)], ext: new UserExt(eids: [Eid.getDefaultEid(RANDOM_SOURCE_ID)]))
150+
151+
ENABLED | DISABLED | new User(eids: [Eid.getDefaultEid(RANDOM_SOURCE_ID)])
152+
ENABLED | DISABLED | new User(ext: new UserExt(eids: [Eid.getDefaultEid(RANDOM_SOURCE_ID)]))
153+
ENABLED | DISABLED | new User(eids: [Eid.getDefaultEid(RANDOM_SOURCE_ID)], ext: new UserExt(eids: [Eid.getDefaultEid(RANDOM_SOURCE_ID)]))
154+
155+
ENABLED | ENABLED | new User(eids: [Eid.getDefaultEid(RANDOM_SOURCE_ID)])
156+
ENABLED | ENABLED | new User(ext: new UserExt(eids: [Eid.getDefaultEid(RANDOM_SOURCE_ID)]))
157+
ENABLED | ENABLED | new User(eids: [Eid.getDefaultEid(RANDOM_SOURCE_ID)], ext: new UserExt(eids: [Eid.getDefaultEid(RANDOM_SOURCE_ID)]))
158+
}
159+
94160
def "PBs eid permissions should affect only specified on source"() {
95161
given: "PBs with openx bidder"
96162
def pbsService = pbsServiceFactory.getService(

src/test/java/org/prebid/server/auction/requestfactory/AmpRequestFactoryTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1753,7 +1753,7 @@ private void givenBidRequest(
17531753

17541754
given(ortb2ImplicitParametersResolver.resolve(any(), any(), any(), anyBoolean())).willAnswer(
17551755
answerWithFirstArgument());
1756-
given(ortb2RequestFactory.validateRequest(any(), any(), any()))
1756+
given(ortb2RequestFactory.validateRequest(any(), any(), any(), any()))
17571757
.willAnswer(invocation -> Future.succeededFuture((BidRequest) invocation.getArgument(0)));
17581758

17591759
given(ortb2RequestFactory.enrichBidRequestWithAccountAndPrivacyData(any()))

src/test/java/org/prebid/server/auction/requestfactory/AuctionRequestFactoryTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ public void setUp() {
165165
given(ortb2RequestFactory.executeRawAuctionRequestHooks(any()))
166166
.willAnswer(invocation -> Future.succeededFuture(
167167
((AuctionContext) invocation.getArgument(0)).getBidRequest()));
168-
given(ortb2RequestFactory.validateRequest(any(), any(), any()))
168+
given(ortb2RequestFactory.validateRequest(any(), any(), any(), any()))
169169
.willAnswer(invocationOnMock -> Future.succeededFuture((BidRequest) invocationOnMock.getArgument(0)));
170170
given(ortb2RequestFactory.removeEmptyEids(any(), any()))
171171
.willAnswer(invocationOnMock -> invocationOnMock.getArgument(0));
@@ -662,7 +662,7 @@ public void shouldReturnFailedFutureIfRequestValidationFailed() {
662662
// given
663663
givenValidBidRequest();
664664

665-
given(ortb2RequestFactory.validateRequest(any(), any(), any()))
665+
given(ortb2RequestFactory.validateRequest(any(), any(), any(), any()))
666666
.willReturn(Future.failedFuture(new InvalidRequestException("errors")));
667667

668668
// when

src/test/java/org/prebid/server/auction/requestfactory/Ortb2RequestFactoryTest.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -658,14 +658,15 @@ public void enrichAuctionContextShouldSetDebugOff() {
658658
@Test
659659
public void validateRequestShouldThrowInvalidRequestExceptionIfRequestIsInvalid() {
660660
// given
661-
given(requestValidator.validate(any(), any())).willReturn(ValidationResult.error("error"));
661+
given(requestValidator.validate(any(), any(), any())).willReturn(ValidationResult.error("error"));
662662

663663
final BidRequest bidRequest = givenBidRequest(identity());
664664

665665
// when
666666
final Future<BidRequest> result = target.validateRequest(
667667
bidRequest,
668668
HttpRequestContext.builder().build(),
669+
DebugContext.empty(),
669670
new ArrayList<>());
670671

671672
// then
@@ -674,24 +675,25 @@ public void validateRequestShouldThrowInvalidRequestExceptionIfRequestIsInvalid(
674675
.isInstanceOf(InvalidRequestException.class)
675676
.hasMessage("error");
676677

677-
verify(requestValidator).validate(eq(bidRequest), any());
678+
verify(requestValidator).validate(eq(bidRequest), any(), any());
678679
}
679680

680681
@Test
681682
public void validateRequestShouldReturnSameBidRequest() {
682683
// given
683-
given(requestValidator.validate(any(), any())).willReturn(ValidationResult.success());
684+
given(requestValidator.validate(any(), any(), any())).willReturn(ValidationResult.success());
684685

685686
final BidRequest bidRequest = givenBidRequest(identity());
686687

687688
// when
688689
final BidRequest result = target.validateRequest(
689690
bidRequest,
690691
HttpRequestContext.builder().build(),
692+
DebugContext.empty(),
691693
new ArrayList<>()).result();
692694

693695
// then
694-
verify(requestValidator).validate(eq(bidRequest), any());
696+
verify(requestValidator).validate(eq(bidRequest), any(), any());
695697

696698
assertThat(result).isSameAs(bidRequest);
697699
}

src/test/java/org/prebid/server/auction/requestfactory/VideoRequestFactoryTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -345,7 +345,7 @@ public void shouldReturnExpectedResultAndReturnErrors() throws JsonProcessingExc
345345
verify(ortb2RequestFactory).createAuctionContext(any(), eq(MetricName.video));
346346
verify(ortb2RequestFactory).enrichAuctionContext(any(), any(), eq(bidRequest), eq(0L));
347347
verify(ortb2RequestFactory).fetchAccountWithoutStoredRequestLookup(any());
348-
verify(ortb2RequestFactory).validateRequest(eq(bidRequest), any(), any());
348+
verify(ortb2RequestFactory).validateRequest(eq(bidRequest), any(), any(), any());
349349
verify(paramsResolver)
350350
.resolve(eq(bidRequest), any(), eq(Endpoint.openrtb2_video.value()), eq(false));
351351
verify(ortb2RequestFactory).enrichBidRequestWithAccountAndPrivacyData(
@@ -404,7 +404,7 @@ private void givenBidRequest(BidRequest bidRequest, List<PodError> podErrors) {
404404
.build());
405405
given(ortb2RequestFactory.fetchAccountWithoutStoredRequestLookup(any())).willReturn(Future.succeededFuture());
406406

407-
given(ortb2RequestFactory.validateRequest(any(), any(), any()))
407+
given(ortb2RequestFactory.validateRequest(any(), any(), any(), any()))
408408
.willAnswer(invocation -> Future.succeededFuture((BidRequest) invocation.getArgument(0)));
409409

410410
given(paramsResolver.resolve(any(), any(), any(), anyBoolean()))

0 commit comments

Comments
 (0)