Skip to content
Merged
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
1 change: 1 addition & 0 deletions docs/config-app.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ Removes and downloads file again if depending service cant process probably corr
- `auction.cache.expected-request-time-ms` - approximate value in milliseconds for Cache Service interacting.
- `auction.cache.only-winning-bids` - if equals to `true` only the winning bids would be cached. Has lower priority than request-specific flags.
- `auction.generate-bid-id` - whether to generate seatbid[].bid[].ext.prebid.bidid in the OpenRTB response.
- `auction.enforce-random-bid-id` - whether to enforce generating a robust random seatbid[].bid[].id in the OpenRTB response if the initial value is less than 17 characters.
- `auction.validations.banner-creative-max-size` - enables creative max size validation for banners. Possible values: `skip`, `enforce`, `warn`. Default is `skip`.
- `auction.validations.secure-markup` - enables secure markup validation. Possible values: `skip`, `enforce`, `warn`. Default is `skip`.
- `auction.host-schain-node` - defines global schain node that will be appended to `request.source.ext.schain.nodes` passed to bidders
Expand Down
23 changes: 18 additions & 5 deletions src/main/java/org/prebid/server/auction/BidResponseCreator.java
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,6 @@
import org.prebid.server.hooks.v1.bidder.AllProcessedBidResponsesPayload;
import org.prebid.server.hooks.v1.bidder.BidderResponsePayload;
import org.prebid.server.identity.IdGenerator;
import org.prebid.server.identity.IdGeneratorType;
import org.prebid.server.json.DecodeException;
import org.prebid.server.json.JacksonMapper;
import org.prebid.server.log.ConditionalLogger;
Expand Down Expand Up @@ -139,6 +138,7 @@ public class BidResponseCreator {
public static final String DEFAULT_DEBUG_KEY = "prebid";
private static final String TARGETING_ENV_APP_VALUE = "mobile-app";
private static final String TARGETING_ENV_AMP_VALUE = "amp";
private static final int MIN_BID_ID_LENGTH = 17;

private final double logSamplingRate;
private final CoreCacheService coreCacheService;
Expand All @@ -148,9 +148,11 @@ public class BidResponseCreator {
private final StoredRequestProcessor storedRequestProcessor;
private final WinningBidComparatorFactory winningBidComparatorFactory;
private final IdGenerator bidIdGenerator;
private final IdGenerator enforcedBidIdGenerator;
private final HookStageExecutor hookStageExecutor;
private final CategoryMappingService categoryMappingService;
private final int truncateAttrChars;
private final boolean enforceRandomBidId;
private final Clock clock;
private final JacksonMapper mapper;
private final Metrics metrics;
Expand All @@ -169,9 +171,11 @@ public BidResponseCreator(double logSamplingRate,
StoredRequestProcessor storedRequestProcessor,
WinningBidComparatorFactory winningBidComparatorFactory,
IdGenerator bidIdGenerator,
IdGenerator enforcedBidIdGenerator,
HookStageExecutor hookStageExecutor,
CategoryMappingService categoryMappingService,
int truncateAttrChars,
boolean enforceRandomBidId,
Clock clock,
JacksonMapper mapper,
Metrics metrics,
Expand All @@ -185,9 +189,11 @@ public BidResponseCreator(double logSamplingRate,
this.storedRequestProcessor = Objects.requireNonNull(storedRequestProcessor);
this.winningBidComparatorFactory = Objects.requireNonNull(winningBidComparatorFactory);
this.bidIdGenerator = Objects.requireNonNull(bidIdGenerator);
this.enforcedBidIdGenerator = Objects.requireNonNull(enforcedBidIdGenerator);
this.hookStageExecutor = Objects.requireNonNull(hookStageExecutor);
this.categoryMappingService = Objects.requireNonNull(categoryMappingService);
this.truncateAttrChars = validateTruncateAttrChars(truncateAttrChars);
this.enforceRandomBidId = enforceRandomBidId;
this.clock = Objects.requireNonNull(clock);
this.mapper = Objects.requireNonNull(mapper);
this.mediaTypeCacheTtl = Objects.requireNonNull(mediaTypeCacheTtl);
Expand Down Expand Up @@ -303,12 +309,12 @@ private Bid updateBid(Bid bid,
final Account account = auctionContext.getAccount();
final List<String> debugWarnings = auctionContext.getDebugWarnings();

final String generatedBidId = bidIdGenerator.getType() != IdGeneratorType.none
? bidIdGenerator.generateId()
: null;
final String effectiveBidId = ObjectUtils.defaultIfNull(generatedBidId, bid.getId());
final String generatedBidId = bidIdGenerator.generateId();
final String enforcedRandomBidId = enforcedBidId(bid);
final String effectiveBidId = ObjectUtils.defaultIfNull(generatedBidId, enforcedRandomBidId);

return bid.toBuilder()
.id(enforcedRandomBidId)
.adm(updateBidAdm(bid,
bidType,
bidder,
Expand All @@ -328,6 +334,13 @@ private Bid updateBid(Bid bid,
.build();
}

private String enforcedBidId(Bid bid) {
final int bidIdLength = Optional.ofNullable(bid.getId()).map(String::length).orElse(0);
return enforceRandomBidId && bidIdLength < MIN_BID_ID_LENGTH
? enforcedBidIdGenerator.generateId()
: bid.getId();
}

private String updateBidAdm(Bid bid,
BidType bidType,
String bidder,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -824,6 +824,7 @@ BidResponseCreator bidResponseCreator(
HookStageExecutor hookStageExecutor,
CategoryMappingService categoryMappingService,
@Value("${settings.targeting.truncate-attr-chars}") int truncateAttrChars,
@Value("${auction.enforce-random-bid-id:false}") boolean enforceRandomBidId,
Clock clock,
JacksonMapper mapper,
Metrics metrics,
Expand All @@ -840,9 +841,11 @@ BidResponseCreator bidResponseCreator(
storedRequestProcessor,
winningBidComparatorFactory,
bidIdGenerator,
new UUIDIdGenerator(),
hookStageExecutor,
categoryMappingService,
truncateAttrChars,
enforceRandomBidId,
clock,
mapper,
metrics,
Expand Down
134 changes: 132 additions & 2 deletions src/test/groovy/org/prebid/server/functional/tests/AuctionSpec.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,17 @@ import static org.prebid.server.functional.util.SystemProperties.PBS_VERSION
class AuctionSpec extends BaseSpec {

private static final String USER_SYNC_URL = "$networkServiceContainer.rootUri/generic-usersync"
private static final boolean CORS_SUPPORT = false
private static final Boolean CORS_SUPPORT = false
private static final UserSyncInfo.Type USER_SYNC_TYPE = REDIRECT
private static final int DEFAULT_TIMEOUT = getRandomTimeout()
private static final Integer DEFAULT_TIMEOUT = getRandomTimeout()
private static final Integer MIN_BID_ID_LENGTH = 17
private static final Integer DEFAULT_UUID_LENGTH = 36
private static final Map<String, String> PBS_CONFIG = ["auction.biddertmax.max" : MAX_TIMEOUT as String,
"auction.default-timeout-ms": DEFAULT_TIMEOUT as String]
private static final Map<String, String> GENERIC_CONFIG = [
"adapters.${GENERIC.value}.usersync.${USER_SYNC_TYPE.value}.url" : USER_SYNC_URL,
"adapters.${GENERIC.value}.usersync.${USER_SYNC_TYPE.value}.support-cors": CORS_SUPPORT.toString()]

@Shared
PrebidServerService prebidServerService = pbsServiceFactory.getService(PBS_CONFIG)

Expand Down Expand Up @@ -591,4 +594,131 @@ class AuctionSpec extends BaseSpec {
def bidderRequest = bidder.getBidderRequest(bidRequest.id)
assert !bidderRequest?.device?.ext?.cdep
}

def "PBS should override short bid.id with random uuid when enforce-random-bid-id is enabled"() {
given: "PBS with enabled generate-bid-id"
def pbsConfig = ['auction.enforce-random-bid-id': 'true']
def pbsService = pbsServiceFactory.getService(pbsConfig)

and: "Default bid request"
def bidRequest = BidRequest.defaultBidRequest.tap {
enableEvents()
}

and: "Default bid response"
def originalBidId = PBSUtils.getRandomString(PBSUtils.getRandomNumber(1, MIN_BID_ID_LENGTH - 1))
def bidResponse = BidResponse.getDefaultBidResponse(bidRequest).tap {
seatbid.first.bid.first.id = originalBidId
}
bidder.setResponse(bidRequest.id, bidResponse)

and: "Save account in DB"
def account = new Account(uuid: bidRequest.accountId, eventsEnabled: true)
accountDao.save(account)

when: "PBS processes auction request"
def response = pbsService.sendAuctionRequest(bidRequest)

then: "Should include imp from original request"
def bidderRequest = bidder.getBidderRequest(bidRequest.id)
assert bidderRequest.imp.id.sort() == bidRequest.imp.id.sort()

and: "Bid response should contain changed bid.id for wins event"
def bidIds = response.seatbid.bid.id.flatten()
def bidResponseEvents = response.seatbid.first.bid.first.ext.prebid.events
assert bidResponseEvents.win.contains("win&b=${bidIds.first}")
assert bidResponseEvents.imp.contains("imp&b=${bidIds.first}")

and: "BidResponse should contain different bid.id"
assert bidIds.sort() != [originalBidId]

and: "BidResponse should contain generated UUID"
assert PBSUtils.isUUID(response.seatbid.first.bid.first.id)

cleanup: "Stop and remove pbs container"
pbsServiceFactory.removeContainer(pbsConfig)
}

def "PBS shouldn't override short bid.id when enforce-random-bid-id in default or disabled"() {
given: "PBS with disabled generate-bid-id"
def pbsConfig = ["auction.enforce-random-bid-id": enforceRandomBidId]
def pbsService = pbsServiceFactory.getService(pbsConfig)

and: "Default bid request"
def bidRequest = BidRequest.defaultBidRequest.tap {
enableEvents()
}

and: "Default bid response"
def originalBidId = PBSUtils.getRandomString(PBSUtils.getRandomNumber(0, MIN_BID_ID_LENGTH))
def bidResponse = BidResponse.getDefaultBidResponse(bidRequest).tap {
seatbid.first.bid.first.id = originalBidId
}
bidder.setResponse(bidRequest.id, bidResponse)

and: "Save account in DB"
def account = new Account(uuid: bidRequest.accountId, eventsEnabled: true)
accountDao.save(account)

when: "PBS processes auction request"
def response = pbsService.sendAuctionRequest(bidRequest)

then: "Should include imp from original request"
def bidderRequest = bidder.getBidderRequest(bidRequest.id)
assert bidderRequest.imp.id.sort() == bidRequest.imp.id.sort()

and: "Bid response should contain changed bid.id for wins event"
def bidResponseEvents = response.seatbid.first.bid.first.ext.prebid.events
assert bidResponseEvents.win.contains("win&b=${originalBidId}")
assert bidResponseEvents.imp.contains("imp&b=${originalBidId}")

and: "BidResponse should contain original bid.id"
assert response.seatbid.bid.id.flatten().sort() == [originalBidId]

cleanup: "Stop and remove pbs container"
pbsServiceFactory.removeContainer(pbsConfig)

where:
enforceRandomBidId << [null, 'false']
}

def "PBS shouldn't override long enough bid.id with random uuid when enforce-random-bid-id is enabled"() {
given: "PBS with enabled generate-bid-id"
def pbsConfig = ['auction.enforce-random-bid-id': 'true']
def pbsService = pbsServiceFactory.getService(pbsConfig)

and: "Default bid request"
def bidRequest = BidRequest.defaultBidRequest.tap {
enableEvents()
}

and: "Default bid response"
def originalBidId = PBSUtils.getRandomString(PBSUtils.getRandomNumber(MIN_BID_ID_LENGTH, DEFAULT_UUID_LENGTH))
def bidResponse = BidResponse.getDefaultBidResponse(bidRequest).tap {
seatbid.first.bid.first.id = originalBidId
}
bidder.setResponse(bidRequest.id, bidResponse)

and: "Save account in DB"
def account = new Account(uuid: bidRequest.accountId, eventsEnabled: true)
accountDao.save(account)

when: "PBS processes auction request"
def response = pbsService.sendAuctionRequest(bidRequest)

then: "Should include imp from original request"
def bidderRequest = bidder.getBidderRequest(bidRequest.id)
assert bidderRequest.imp.id.sort() == bidRequest.imp.id.sort()

and: "Bid response should contain changed bid.id for wins event"
def bidResponseEvents = response.seatbid.first.bid.first.ext.prebid.events
assert bidResponseEvents.win.contains("win&b=${originalBidId}")
assert bidResponseEvents.imp.contains("imp&b=${originalBidId}")

and: "BidResponse should contain original bid.id"
assert response.seatbid.bid.id.flatten().sort() == [originalBidId]

cleanup: "Stop and remove pbs container"
pbsServiceFactory.removeContainer(pbsConfig)
}
}
12 changes: 12 additions & 0 deletions src/test/groovy/org/prebid/server/functional/util/PBSUtils.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -155,4 +155,16 @@ class PBSUtils implements ObjectMapperWrapper {
def version = versionParts.join('.')
return (version >= minVersion && version <= maxVersion) ? version : getRandomVersion(minVersion, maxVersion)
}

static Boolean isUUID(String str) {
if (str == null) {
return false
}
try {
UUID.fromString(str)
return true
} catch (IllegalArgumentException e) {
return false
}
}
}
Loading
Loading