11package org.prebid.server.functional.tests.privacy
22
33import io.netty.handler.codec.http.HttpResponseStatus
4+ import org.prebid.server.functional.model.config.AccountConfig
5+ import org.prebid.server.functional.model.config.AccountGdprConfig
6+ import org.prebid.server.functional.model.config.AccountPrivacyConfig
7+ import org.prebid.server.functional.model.config.PurposeConfig
8+ import org.prebid.server.functional.model.db.Account
9+ import org.prebid.server.functional.model.request.GppSectionId
410import org.prebid.server.functional.model.request.cookiesync.CookieSyncRequest
511import org.prebid.server.functional.model.response.cookiesync.UserSyncInfo
612import org.prebid.server.functional.service.PrebidServerException
@@ -13,7 +19,10 @@ import org.prebid.server.functional.util.privacy.TcfConsent
1319import org.prebid.server.functional.util.privacy.gpp.TcfEuV2Consent
1420import org.prebid.server.functional.util.privacy.gpp.UsV1Consent
1521
22+ import static org.prebid.server.functional.model.bidder.BidderName.ALIAS
1623import static org.prebid.server.functional.model.bidder.BidderName.GENERIC
24+ import static org.prebid.server.functional.model.config.Purpose.P1
25+ import static org.prebid.server.functional.model.config.PurposeEnforcement.NO
1726import static org.prebid.server.functional.model.request.GppSectionId.TCF_EU_V2
1827import static org.prebid.server.functional.model.request.GppSectionId.USP_V1
1928import static org.prebid.server.functional.model.response.cookiesync.UserSyncInfo.Type.IFRAME
@@ -28,15 +37,26 @@ class GppCookieSyncSpec extends BaseSpec {
2837 private static final UserSyncInfo.Type USER_SYNC_TYPE = REDIRECT
2938 private static final boolean CORS_SUPPORT = false
3039 private static final String USER_SYNC_URL = " $networkServiceContainer . rootUri /generic-usersync"
40+ private static final GppSectionId FIRST_GPP_SECTION = PBSUtils . getRandomEnum(GppSectionId . class)
41+ private static final GppSectionId SECOND_GPP_SECTION = PBSUtils . getRandomEnum(GppSectionId . class, [FIRST_GPP_SECTION ])
42+
3143 private static final Map<String , String > GENERIC_CONFIG = [
3244 " adapters.${ GENERIC.value} .meta-info.vendor-id" : GENERIC_VENDOR_ID as String ,
3345 " adapters.${ GENERIC.value} .usersync.${ USER_SYNC_TYPE.value} .url" : USER_SYNC_URL ,
3446 " adapters.${ GENERIC.value} .usersync.${ USER_SYNC_TYPE.value} .support-cors" : CORS_SUPPORT . toString()]
47+ private static final Map<String , String > GENERIC_WITH_SKIP_CONFIG = [
48+ " adapters.${ GENERIC.value} .meta-info.vendor-id" : GENERIC_VENDOR_ID as String ,
49+ " adapters.${ GENERIC.value} .usersync.${ USER_SYNC_TYPE.value} .url" : " $networkServiceContainer . rootUri /generic-usersync&redir={{redirect_url}}" . toString(),
50+ " adapters.${ GENERIC.value} .usersync.skipwhen.gdpr" : ' true' ,
51+ " adapters.${ GENERIC.value} .usersync.skipwhen.gpp_sid" : " ${ FIRST_GPP_SECTION.value} , ${ SECOND_GPP_SECTION.value} " . toString(),
52+ " adapters.${ GENERIC.value} .usersync.${ USER_SYNC_TYPE.value} .support-cors" : CORS_SUPPORT . toString()]
3553
3654 private static PrebidServerService prebidServerService = pbsServiceFactory. getService(GENERIC_CONFIG )
55+ private static PrebidServerService prebidServerServiceWithSkipConfig = pbsServiceFactory. getService(GENERIC_WITH_SKIP_CONFIG + GENERIC_ALIAS_CONFIG )
3756
3857 def cleanupSpec () {
3958 pbsServiceFactory. removeContainer(GENERIC_CONFIG )
59+ pbsServiceFactory. removeContainer(GENERIC_WITH_SKIP_CONFIG + GENERIC_ALIAS_CONFIG )
4060 }
4161
4262 def " PBS cookie sync request should set GDPR to 1 when gpp_sid contains 2" () {
@@ -171,8 +191,8 @@ class GppCookieSyncSpec extends BaseSpec {
171191 it. gpp = new TcfEuV2Consent.Builder (). build()
172192 it. gdpr = null
173193 it. gdprConsent = new TcfConsent.Builder (). setPurposesLITransparency(DEVICE_ACCESS )
174- .setVendorLegitimateInterest([GENERIC_VENDOR_ID ])
175- .build()
194+ .setVendorLegitimateInterest([GENERIC_VENDOR_ID ])
195+ .build()
176196 }
177197
178198 when : " PBS processes cookie sync request"
@@ -261,4 +281,236 @@ class GppCookieSyncSpec extends BaseSpec {
261281 where :
262282 userSyncFormat << [REDIRECT , IFRAME ]
263283 }
284+
285+ def " PBS should emit proper error message when request contain gdpr config and global skip gdpr config for adapter" () {
286+ given : " Default CookieSyncRequest with gdpr config"
287+ def cookieSyncRequest = CookieSyncRequest . defaultCookieSyncRequest. tap {
288+ it. gppSid = TCF_EU_V2 . intValue
289+ it. gdpr = 1
290+ it. gdprConsent = new TcfConsent.Builder (). build()
291+ }
292+
293+ when : " PBS processes cookie sync request"
294+ def response = prebidServerServiceWithSkipConfig. sendCookieSyncRequest(cookieSyncRequest)
295+
296+ then : " Response userSync url shouldn't contain cookies and userSync"
297+ def bidderStatus = response. getBidderUserSync(GENERIC )
298+ assert ! bidderStatus. userSync
299+ assert ! bidderStatus. noCookie
300+
301+ and : " Response should contain proper error message"
302+ assert bidderStatus. error == " Rejected by regulation scope"
303+ }
304+
305+ def " PBS should emit proper error message when alias request contain gdpr config and global skip gdpr config for adapter" () {
306+ given : " Default CookieSyncRequest with gdpr config"
307+ def cookieSyncRequest = CookieSyncRequest . defaultCookieSyncRequest. tap {
308+ it. bidders = [ALIAS ]
309+ it. gppSid = TCF_EU_V2 . intValue
310+ it. gdpr = 1
311+ it. gdprConsent = new TcfConsent.Builder (). build()
312+ }
313+
314+ when : " PBS processes cookie sync request"
315+ def response = prebidServerServiceWithSkipConfig. sendCookieSyncRequest(cookieSyncRequest)
316+
317+ then : " Response userSync url shouldn't contain cookies and userSync"
318+ def bidderStatus = response. getBidderUserSync(GENERIC )
319+ assert ! bidderStatus. userSync
320+ assert ! bidderStatus. noCookie
321+
322+ and : " Response should contain proper error message"
323+ assert bidderStatus. error == " Rejected by regulation scope"
324+ }
325+
326+ def " PBS should emit proper error message when request contain gpp config and specific global skip gpp config for adapter" () {
327+ given : " Default CookieSyncRequest with gpp and gppSid"
328+ def cookieSyncRequest = CookieSyncRequest . defaultCookieSyncRequest. tap {
329+ it. gppSid = TCF_EU_V2 . intValue
330+ it. gpp = new UsV1Consent.Builder (). build()
331+ it. gppSid = gppSid
332+ }
333+
334+ when : " PBS processes cookie sync request"
335+ def response = prebidServerServiceWithSkipConfig. sendCookieSyncRequest(cookieSyncRequest)
336+
337+ then : " Response userSync url shouldn't contain cookies and userSync"
338+ def bidderStatus = response. getBidderUserSync(GENERIC )
339+ assert ! bidderStatus. userSync
340+ assert ! bidderStatus. noCookie
341+
342+ and : " Response should contain proper error message"
343+ assert bidderStatus. error == " Rejected by regulation scope"
344+
345+ where :
346+ gppSid << [" ${ FIRST_GPP_SECTION.value} " ,
347+ " ${ SECOND_GPP_SECTION.value} " ,
348+ " ${ FIRST_GPP_SECTION.value} , ${ SECOND_GPP_SECTION.value} " ,
349+ " ${ SECOND_GPP_SECTION.value} , ${ FIRST_GPP_SECTION.value} " ,
350+ " ${ SECOND_GPP_SECTION.value} , ${ FIRST_GPP_SECTION.value} " ,
351+ " ${ PBSUtils.getRandomEnum(GppSectionId.class, [FIRST_GPP_SECTION, SECOND_GPP_SECTION]).value} , ${ SECOND_GPP_SECTION.value} " ,
352+ " ${ FIRST_GPP_SECTION.value} , ${ PBSUtils.getRandomEnum(GppSectionId.class, [FIRST_GPP_SECTION, SECOND_GPP_SECTION]).value} "
353+ ]
354+ }
355+
356+ def " PBS should emit proper error message when alias request contain gpp config and specific global skip gpp config for adapter" () {
357+ given : " Default CookieSyncRequest with gpp and gppSid"
358+ def cookieSyncRequest = CookieSyncRequest . defaultCookieSyncRequest. tap {
359+ it. gppSid = TCF_EU_V2 . intValue
360+ it. bidders = [ALIAS ]
361+ it. gpp = new UsV1Consent.Builder (). build()
362+ it. gppSid = gppSid
363+ }
364+
365+ when : " PBS processes cookie sync request"
366+ def response = prebidServerServiceWithSkipConfig. sendCookieSyncRequest(cookieSyncRequest)
367+
368+ then : " Response userSync url shouldn't contain cookies and userSync"
369+ def bidderStatus = response. getBidderUserSync(GENERIC )
370+ assert ! bidderStatus. userSync
371+ assert ! bidderStatus. noCookie
372+
373+ and : " Response should contain proper error message"
374+ assert bidderStatus. error == " Rejected by regulation scope"
375+
376+ where :
377+ gppSid << [" ${ FIRST_GPP_SECTION.value} " ,
378+ " ${ SECOND_GPP_SECTION.value} " ,
379+ " ${ FIRST_GPP_SECTION.value} , ${ SECOND_GPP_SECTION.value} " ,
380+ " ${ SECOND_GPP_SECTION.value} , ${ FIRST_GPP_SECTION.value} " ,
381+ " ${ SECOND_GPP_SECTION.value} , ${ FIRST_GPP_SECTION.value} " ,
382+ " ${ PBSUtils.getRandomEnum(GppSectionId.class, [FIRST_GPP_SECTION, SECOND_GPP_SECTION]).value} , ${ SECOND_GPP_SECTION.value} " ,
383+ " ${ FIRST_GPP_SECTION.value} , ${ PBSUtils.getRandomEnum(GppSectionId.class, [FIRST_GPP_SECTION, SECOND_GPP_SECTION]).value} "
384+ ]
385+ }
386+
387+ def " PBS shouldn't emit error message when request doesn't contain gdpr config and global skip gdpr config for adapter" () {
388+ given : " Default CookieSyncRequest with gdpr config"
389+ def gppSid = TCF_EU_V2
390+ def cookieSyncRequest = CookieSyncRequest . defaultCookieSyncRequest. tap {
391+ it. gppSid = gppSid. intValue
392+ it. gdpr = 0
393+ it. gdprConsent = new TcfConsent.Builder (). build()
394+ }
395+
396+ when : " PBS processes cookie sync request"
397+ def response = prebidServerServiceWithSkipConfig. sendCookieSyncRequest(cookieSyncRequest)
398+
399+ then : " Response userSync url should contain cookies and userSync"
400+ def bidderStatus = response. getBidderUserSync(GENERIC )
401+ assert HttpUtil . findUrlParameterValue(bidderStatus. userSync?. url, " gpp" ) == " "
402+ assert HttpUtil . findUrlParameterValue(bidderStatus. userSync?. url, " gpp_sid" ) == gppSid. value
403+
404+ and : " Response shouldn't contains any error"
405+ assert ! bidderStatus. error
406+ }
407+
408+ def " PBS shouldn't emit error message when request does contain gdpr config and global skip gdpr config disabled for adapter" () {
409+ given : " Pbs config with usersync.#userSyncFormat.url"
410+ def pbsConfig = [
411+ " adapters.${ GENERIC.value} .meta-info.vendor-id" : GENERIC_VENDOR_ID as String ,
412+ " adapters.${ GENERIC.value} .usersync.${ USER_SYNC_TYPE.value} .url" : USER_SYNC_URL ,
413+ " adapters.${ GENERIC.value} .usersync.skipwhen.gdpr" : ' false' ,
414+ " adapters.${ GENERIC.value} .usersync.${ USER_SYNC_TYPE.value} .support-cors" : CORS_SUPPORT . toString()]
415+ def prebidServerService = pbsServiceFactory. getService(pbsConfig)
416+
417+ and : " Default CookieSyncRequest with gdpr config"
418+ def cookieSyncRequest = CookieSyncRequest . defaultCookieSyncRequest. tap {
419+ it. gppSid = TCF_EU_V2
420+ it. gdpr = 1
421+ it. gdprConsent = new TcfConsent.Builder (). setPurposesLITransparency(DEVICE_ACCESS )
422+ .setVendorLegitimateInterest([GENERIC_VENDOR_ID ])
423+ .build()
424+ it. account = PBSUtils . randomNumber
425+ }
426+
427+ and : " Save account config with requireConsent into DB"
428+ def purposes = [(P1 ): new PurposeConfig (enforcePurpose : NO , enforceVendors : false )]
429+ def accountGdprConfig = new AccountGdprConfig (purposes : purposes)
430+ def privacyConfig = new AccountPrivacyConfig (gdpr : accountGdprConfig)
431+ def account = new Account (uuid : cookieSyncRequest. account, config : new AccountConfig (privacy : privacyConfig))
432+ accountDao. save(account)
433+
434+ when : " PBS processes cookie sync request"
435+ def response = prebidServerService. sendCookieSyncRequest(cookieSyncRequest)
436+
437+ then : " Response should contain proper userSync url"
438+ def bidderStatus = response. getBidderUserSync(GENERIC )
439+ assert bidderStatus. userSync?. url == USER_SYNC_URL
440+
441+ and : " Response shouldn't contains any error"
442+ assert ! bidderStatus. error
443+
444+ cleanup : " Stop and remove pbs container"
445+ pbsServiceFactory. removeContainer(pbsConfig)
446+ }
447+
448+ def " PBS shouldn't emit error message when request does contain gdpr config and global skip gdpr config default for adapter" () {
449+ given : " Default CookieSyncRequest with gdpr config"
450+ def cookieSyncRequest = CookieSyncRequest . defaultCookieSyncRequest. tap {
451+ it. gppSid = TCF_EU_V2
452+ it. gdpr = 1
453+ it. gdprConsent = new TcfConsent.Builder (). setPurposesLITransparency(DEVICE_ACCESS )
454+ .setVendorLegitimateInterest([GENERIC_VENDOR_ID ])
455+ .build()
456+ it. account = PBSUtils . randomNumber
457+ }
458+
459+ and : " Save account config with requireConsent into DB"
460+ def purposes = [(P1 ): new PurposeConfig (enforcePurpose : NO , enforceVendors : false )]
461+ def accountGdprConfig = new AccountGdprConfig (purposes : purposes)
462+ def privacyConfig = new AccountPrivacyConfig (gdpr : accountGdprConfig)
463+ def account = new Account (uuid : cookieSyncRequest. account, config : new AccountConfig (privacy : privacyConfig))
464+ accountDao. save(account)
465+
466+ when : " PBS processes cookie sync request"
467+ def response = prebidServerService. sendCookieSyncRequest(cookieSyncRequest)
468+
469+ then : " Response should contain proper userSync url"
470+ def bidderStatus = response. getBidderUserSync(GENERIC )
471+ assert bidderStatus. userSync?. url == USER_SYNC_URL
472+
473+ and : " Response shouldn't contains any error"
474+ assert ! bidderStatus. error
475+ }
476+
477+ def " PBS shouldn't emit error message when request doesn't contain matched gpp config and specific global skip gpp config for adapter" () {
478+ given : " Default CookieSyncRequest with gpp and gppSid"
479+ def gpp = new UsV1Consent.Builder (). build()
480+ def gppSid = " ${ PBSUtils.getRandomEnum(GppSectionId.class, [FIRST_GPP_SECTION, SECOND_GPP_SECTION]).value} "
481+ def cookieSyncRequest = CookieSyncRequest . defaultCookieSyncRequest. tap {
482+ it. gppSid = TCF_EU_V2 . intValue
483+ it. gpp = gpp
484+ it. gppSid = gppSid
485+ }
486+
487+ when : " PBS processes cookie sync request"
488+ def response = prebidServerServiceWithSkipConfig. sendCookieSyncRequest(cookieSyncRequest)
489+
490+ then : " Response userSync url should contain gpp and gppSid"
491+ def bidderStatus = response. getBidderUserSync(GENERIC )
492+ assert HttpUtil . findUrlParameterValue(bidderStatus. userSync?. url, " gpp" ) == gpp. toString()
493+ assert HttpUtil . findUrlParameterValue(bidderStatus. userSync?. url, " gpp_sid" ) == gppSid
494+
495+ and : " Response shouldn't contains any error"
496+ assert ! bidderStatus. error
497+ }
498+
499+ def " PBS should also include validation warning when request matches skip config and has validation issue at same time" () {
500+ def cookieSyncRequest = CookieSyncRequest . defaultCookieSyncRequest. tap {
501+ it. gppSid = PBSUtils . getRandomNumberWithExclusion(TCF_EU_V2 . intValue)
502+ it. gdpr = 1
503+ it. gdprConsent = new TcfConsent.Builder (). build()
504+ }
505+
506+ when : " PBS processes cookie sync request"
507+ def response = prebidServerServiceWithSkipConfig. sendCookieSyncRequest(cookieSyncRequest)
508+
509+ then : " Response should contain a warning"
510+ assert response. warnings == [" GPP scope does not match TCF2 scope" ]
511+
512+ then : " Privacy for bidder should be enforced"
513+ def bidderStatus = response. getBidderUserSync(GENERIC )
514+ assert bidderStatus. error == " Rejected by regulation scope"
515+ }
264516}
0 commit comments