Skip to content

Commit ff61c81

Browse files
committed
Fix prebid#3592. Bad Input Error if pbjs s2s config contains alias configuration for a disabled adapter
1 parent 19d25f3 commit ff61c81

File tree

14 files changed

+240
-116
lines changed

14 files changed

+240
-116
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
@@ -415,6 +415,7 @@ private Future<BidRequest> updateBidRequest(AuctionContext auctionContext) {
415415
.map(bidRequest -> paramsResolver.resolve(bidRequest, auctionContext, ENDPOINT, true))
416416
.map(bidRequest -> ortb2RequestFactory.removeEmptyEids(bidRequest, auctionContext.getDebugWarnings()))
417417
.compose(resolvedBidRequest -> ortb2RequestFactory.validateRequest(
418+
account,
418419
resolvedBidRequest,
419420
auctionContext.getHttpRequest(),
420421
auctionContext.getDebugWarnings()));

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+
account, bidRequest, httpRequest, debugWarnings))
245246
.map(interstitialProcessor::process);
246247
}
247248

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -192,11 +192,11 @@ public Future<ActivityInfrastructure> activityInfrastructureFrom(AuctionContext
192192
auctionContext.getDebugContext().getTraceLevel()));
193193
}
194194

195-
public Future<BidRequest> validateRequest(BidRequest bidRequest,
195+
public Future<BidRequest> validateRequest(Account account, BidRequest bidRequest,
196196
HttpRequestContext httpRequestContext,
197197
List<String> warnings) {
198198

199-
final ValidationResult validationResult = requestValidator.validate(bidRequest, httpRequestContext);
199+
final ValidationResult validationResult = requestValidator.validate(account, bidRequest, httpRequestContext);
200200

201201
if (validationResult.hasWarnings()) {
202202
warnings.addAll(validationResult.getWarnings());

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

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
import org.prebid.server.model.HttpRequestContext;
3434
import org.prebid.server.proto.openrtb.ext.request.ExtPublisher;
3535
import org.prebid.server.proto.openrtb.ext.request.ExtPublisherPrebid;
36+
import org.prebid.server.settings.model.Account;
3637
import org.prebid.server.util.HttpUtil;
3738
import org.prebid.server.util.ObjectUtil;
3839

@@ -111,6 +112,7 @@ public Future<WithPodErrors<AuctionContext>> fromRequest(RoutingContext routingC
111112
.compose(httpRequest -> createBidRequest(httpRequest)
112113
.map(bidRequest -> removeEmptyEids(bidRequest, initialAuctionContext.getDebugWarnings()))
113114
.compose(bidRequest -> validateRequest(
115+
initialAuctionContext.getAccount(),
114116
bidRequest,
115117
httpRequest,
116118
initialAuctionContext.getDebugWarnings()))
@@ -324,11 +326,13 @@ private WithPodErrors<BidRequest> fillImplicitParameters(HttpRequestContext http
324326
return WithPodErrors.of(updatedWithDebugBidRequest, bidRequestToErrors.getPodErrors());
325327
}
326328

327-
private Future<WithPodErrors<BidRequest>> validateRequest(WithPodErrors<BidRequest> requestWithPodErrors,
329+
private Future<WithPodErrors<BidRequest>> validateRequest(Account account,
330+
WithPodErrors<BidRequest> requestWithPodErrors,
328331
HttpRequestContext httpRequestContext,
329332
List<String> warnings) {
330333

331-
return ortb2RequestFactory.validateRequest(requestWithPodErrors.getData(), httpRequestContext, warnings)
334+
return ortb2RequestFactory.validateRequest(
335+
account, requestWithPodErrors.getData(), httpRequestContext, warnings)
332336
.map(bidRequest -> requestWithPodErrors);
333337
}
334338
}

src/main/java/org/prebid/server/metric/MetricName.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ public enum MetricName {
6363
nobid,
6464
gotbids,
6565
badinput,
66+
disabled_bidder,
67+
unknown_bidder,
6668
blocklisted_account,
6769
blocklisted_app,
6870
badserverresponse,

src/main/java/org/prebid/server/metric/Metrics.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,22 @@ public void updateAdapterRequestErrorMetric(String bidder, MetricName errorMetri
329329
forAdapter(bidder).request().incCounter(errorMetric);
330330
}
331331

332+
public void updateAdapterRequestDisabledBidderMetric(String bidder, Account account) {
333+
forAdapter(bidder).request().incCounter(MetricName.disabled_bidder);
334+
if (accountMetricsVerbosityResolver.forAccount(account)
335+
.isAtLeast(AccountMetricsVerbosityLevel.detailed)) {
336+
forAccount(account.getId()).adapter().forAdapter(bidder).request().incCounter(MetricName.disabled_bidder);
337+
}
338+
}
339+
340+
public void updateAdapterRequestUnknownBidderMetric(String bidder, Account account) {
341+
forAdapter(bidder).request().incCounter(MetricName.unknown_bidder);
342+
if (accountMetricsVerbosityResolver.forAccount(account)
343+
.isAtLeast(AccountMetricsVerbosityLevel.detailed)) {
344+
forAccount(account.getId()).adapter().forAdapter(bidder).request().incCounter(MetricName.unknown_bidder);
345+
}
346+
}
347+
332348
public void updateAnalyticEventMetric(String analyticCode, MetricName eventType, MetricName result) {
333349
forAnalyticReporter(analyticCode).forEventType(eventType).incCounter(result);
334350
}

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

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
import org.prebid.server.proto.openrtb.ext.request.ExtUserPrebid;
4141
import org.prebid.server.proto.openrtb.ext.request.ImpMediaType;
4242
import org.prebid.server.proto.openrtb.ext.response.BidType;
43+
import org.prebid.server.settings.model.Account;
4344
import org.prebid.server.util.HttpUtil;
4445
import org.prebid.server.validation.model.ValidationResult;
4546

@@ -96,7 +97,7 @@ 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(Account account, BidRequest bidRequest, HttpRequestContext httpRequestContext) {
100101
final List<String> warnings = new ArrayList<>();
101102
try {
102103
if (StringUtils.isBlank(bidRequest.getId())) {
@@ -121,7 +122,7 @@ public ValidationResult validate(BidRequest bidRequest, HttpRequestContext httpR
121122
validateTargeting(targeting);
122123
}
123124
aliases = ObjectUtils.defaultIfNull(extRequestPrebid.getAliases(), Collections.emptyMap());
124-
validateAliases(aliases);
125+
validateAliases(aliases, warnings, metrics, account);
125126
validateAliasesGvlIds(extRequestPrebid, aliases);
126127
validateBidAdjustmentFactors(extRequestPrebid.getBidadjustmentfactors(), aliases);
127128
validateExtBidPrebidData(extRequestPrebid.getData(), aliases);
@@ -491,18 +492,22 @@ private static void validateGranularityRangeIncrement(ExtGranularityRange range)
491492
* Validates aliases. Throws {@link ValidationException} in cases when alias points to invalid bidder or when alias
492493
* is equals to itself.
493494
*/
494-
private void validateAliases(Map<String, String> aliases) throws ValidationException {
495+
private void validateAliases(Map<String, String> aliases, List<String> warnings,
496+
Metrics metrics, Account account) throws ValidationException {
497+
495498
for (final Map.Entry<String, String> aliasToBidder : aliases.entrySet()) {
496499
final String alias = aliasToBidder.getKey();
497500
final String coreBidder = aliasToBidder.getValue();
498501
if (!bidderCatalog.isValidName(coreBidder)) {
499-
throw new ValidationException(
502+
warnings.add(
500503
"request.ext.prebid.aliases.%s refers to unknown bidder: %s".formatted(alias, coreBidder));
501-
}
502-
if (!bidderCatalog.isActive(coreBidder)) {
503-
throw new ValidationException(
504+
metrics.updateAdapterRequestUnknownBidderMetric(coreBidder, account);
505+
} else if (!bidderCatalog.isActive(coreBidder)) {
506+
warnings.add(
504507
"request.ext.prebid.aliases.%s refers to disabled bidder: %s".formatted(alias, coreBidder));
508+
metrics.updateAdapterRequestDisabledBidderMetric(coreBidder, account);
505509
}
510+
506511
if (alias.equals(coreBidder)) {
507512
throw new ValidationException("""
508513
request.ext.prebid.aliases.%s defines a no-op alias. \

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

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import static org.prebid.server.functional.model.bidder.BidderName.ALIAS
1010
import static org.prebid.server.functional.model.bidder.BidderName.BOGUS
1111
import static org.prebid.server.functional.model.bidder.BidderName.GENERIC
1212
import static org.prebid.server.functional.model.bidder.CompressionType.GZIP
13+
import static org.prebid.server.functional.model.response.auction.ErrorType.PREBID
1314
import static org.prebid.server.functional.testcontainers.Dependencies.getNetworkServiceContainer
1415
import static org.prebid.server.functional.util.HttpUtil.CONTENT_ENCODING_HEADER
1516

@@ -111,21 +112,28 @@ class AliasSpec extends BaseSpec {
111112
invalidId << [PBSUtils.randomNegativeNumber, 0]
112113
}
113114

114-
def "PBS should emit error when alias didn't participate in request"() {
115+
def "PBS should emit warning when alias didn't participate in request"() {
115116
given: "Default bid request with alias"
116117
def randomString = PBSUtils.randomString
117118
def bidRequest = BidRequest.defaultBidRequest.tap {
118119
ext.prebid.aliases = [(randomString): BOGUS]
119120
}
120121

121122
when: "PBS processes auction request"
122-
defaultPbsService.sendAuctionRequest(bidRequest)
123+
def response = defaultPbsService.sendAuctionRequest(bidRequest)
123124

124-
then: "Request should fail with an error"
125-
def exception = thrown(PrebidServerException)
126-
assert exception.statusCode == BAD_REQUEST.code()
127-
assert exception.responseBody == "Invalid request format: request.ext.prebid.aliases.$randomString " +
128-
"refers to unknown bidder: $BOGUS.value"
125+
then: "Request shouldn't fail with an error"
126+
def bidderRequests = bidder.getBidderRequests(bidRequest.id)
127+
assert bidderRequests.size() == 1
128+
129+
and: "Bid response shouldn't contain errors"
130+
assert !response.ext.errors
131+
132+
and: "Response should contain warnings"
133+
def auctionWarnings = response.ext?.warnings?.get(PREBID)
134+
assert auctionWarnings.size() == 1
135+
assert auctionWarnings[0].code == 999
136+
assert auctionWarnings[0].message == "request.ext.prebid.aliases.$randomString refers to unknown bidder: bogus"
129137
}
130138

131139
def "PBS aliased bidder config should be independently from parent"() {

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1753,8 +1753,8 @@ private void givenBidRequest(
17531753

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

17591759
given(ortb2RequestFactory.enrichBidRequestWithAccountAndPrivacyData(any()))
17601760
.willAnswer(invocation -> Future.succeededFuture(((AuctionContext) invocation.getArgument(0))

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -165,8 +165,8 @@ 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()))
169-
.willAnswer(invocationOnMock -> Future.succeededFuture((BidRequest) invocationOnMock.getArgument(0)));
168+
given(ortb2RequestFactory.validateRequest(any(), any(), any(), any()))
169+
.willAnswer(invocationOnMock -> Future.succeededFuture((BidRequest) invocationOnMock.getArgument(1)));
170170
given(ortb2RequestFactory.removeEmptyEids(any(), any()))
171171
.willAnswer(invocationOnMock -> invocationOnMock.getArgument(0));
172172
given(ortb2RequestFactory.updateTimeout(any())).willAnswer(invocation -> invocation.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: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@
104104
public class Ortb2RequestFactoryTest extends VertxTest {
105105

106106
private static final List<String> BLOCKLISTED_ACCOUNTS = singletonList("bad_acc");
107+
private static final String ACCOUNT_ID = "accountId";
107108

108109
@Mock
109110
private UidsCookieService uidsCookieService;
@@ -658,12 +659,13 @@ public void enrichAuctionContextShouldSetDebugOff() {
658659
@Test
659660
public void validateRequestShouldThrowInvalidRequestExceptionIfRequestIsInvalid() {
660661
// given
661-
given(requestValidator.validate(any(), any())).willReturn(ValidationResult.error("error"));
662+
given(requestValidator.validate(any(), any(), any())).willReturn(ValidationResult.error("error"));
662663

663664
final BidRequest bidRequest = givenBidRequest(identity());
664665

665666
// when
666667
final Future<BidRequest> result = target.validateRequest(
668+
Account.empty(ACCOUNT_ID),
667669
bidRequest,
668670
HttpRequestContext.builder().build(),
669671
new ArrayList<>());
@@ -674,24 +676,25 @@ public void validateRequestShouldThrowInvalidRequestExceptionIfRequestIsInvalid(
674676
.isInstanceOf(InvalidRequestException.class)
675677
.hasMessage("error");
676678

677-
verify(requestValidator).validate(eq(bidRequest), any());
679+
verify(requestValidator).validate(any(), eq(bidRequest), any());
678680
}
679681

680682
@Test
681683
public void validateRequestShouldReturnSameBidRequest() {
682684
// given
683-
given(requestValidator.validate(any(), any())).willReturn(ValidationResult.success());
685+
given(requestValidator.validate(any(), any(), any())).willReturn(ValidationResult.success());
684686

685687
final BidRequest bidRequest = givenBidRequest(identity());
686688

687689
// when
688690
final BidRequest result = target.validateRequest(
691+
Account.empty(ACCOUNT_ID),
689692
bidRequest,
690693
HttpRequestContext.builder().build(),
691694
new ArrayList<>()).result();
692695

693696
// then
694-
verify(requestValidator).validate(eq(bidRequest), any());
697+
verify(requestValidator).validate(any(), eq(bidRequest), any());
695698

696699
assertThat(result).isSameAs(bidRequest);
697700
}

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(any(), eq(bidRequest), 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)