github.com/prebid/prebid-server/v2@v2.18.0/gdpr/impl_test.go (about) 1 package gdpr 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 "testing" 8 9 "github.com/prebid/go-gdpr/consentconstants" 10 "github.com/prebid/go-gdpr/vendorlist" 11 "github.com/prebid/go-gdpr/vendorlist2" 12 "github.com/prebid/prebid-server/v2/config" 13 "github.com/prebid/prebid-server/v2/openrtb_ext" 14 15 "github.com/stretchr/testify/assert" 16 ) 17 18 func TestDisallowOnEmptyConsent(t *testing.T) { 19 emptyConsent := "" 20 perms := permissionsImpl{ 21 cfg: &tcf2Config{}, 22 fetchVendorList: failedListFetcher, 23 gdprDefaultValue: "0", 24 hostVendorID: 3, 25 vendorIDs: nil, 26 gdprSignal: SignalYes, 27 consent: emptyConsent, 28 } 29 30 allowSync, err := perms.BidderSyncAllowed(context.Background(), openrtb_ext.BidderAppnexus) 31 assertBoolsEqual(t, false, allowSync) 32 assertNilErr(t, err) 33 allowSync, err = perms.HostCookiesAllowed(context.Background()) 34 assertBoolsEqual(t, false, allowSync) 35 assertNilErr(t, err) 36 } 37 38 func TestAllowOnSignalNo(t *testing.T) { 39 emptyConsent := "" 40 perms := permissionsImpl{ 41 gdprSignal: SignalNo, 42 consent: emptyConsent, 43 } 44 45 allowSync, err := perms.HostCookiesAllowed(context.Background()) 46 assert.Equal(t, true, allowSync) 47 assert.Nil(t, err) 48 49 allowSync, err = perms.BidderSyncAllowed(context.Background(), openrtb_ext.BidderAppnexus) 50 assert.Equal(t, true, allowSync) 51 assert.Nil(t, err) 52 } 53 54 func TestAllowedSyncs(t *testing.T) { 55 vendor2AndPurpose1Consent := "CPGWbY_PGWbY_GYAAAENABCAAIAAAAAAAAAAACEAAAAA" 56 vendorListData := MarshalVendorList(vendorList{ 57 VendorListVersion: 2, 58 Vendors: map[string]*vendor{ 59 "2": { 60 ID: 2, 61 Purposes: []int{1}, 62 }, 63 }, 64 }) 65 66 tcf2AggConfig := tcf2Config{ 67 HostConfig: config.TCF2{ 68 Purpose1: config.TCF2Purpose{ 69 EnforcePurpose: true, 70 EnforceVendors: true, 71 }, 72 }, 73 } 74 tcf2AggConfig.HostConfig.PurposeConfigs = map[consentconstants.Purpose]*config.TCF2Purpose{ 75 consentconstants.Purpose(1): &tcf2AggConfig.HostConfig.Purpose1, 76 } 77 78 perms := permissionsImpl{ 79 cfg: &tcf2AggConfig, 80 hostVendorID: 2, 81 vendorIDs: map[openrtb_ext.BidderName]uint16{ 82 openrtb_ext.BidderAppnexus: 2, 83 }, 84 fetchVendorList: listFetcher(map[uint16]map[uint16]vendorlist.VendorList{ 85 2: { 86 1: parseVendorListDataV2(t, vendorListData), 87 }, 88 }), 89 purposeEnforcerBuilder: NewPurposeEnforcerBuilder(&tcf2AggConfig), 90 gdprSignal: SignalYes, 91 consent: vendor2AndPurpose1Consent, 92 } 93 94 allowSync, err := perms.HostCookiesAllowed(context.Background()) 95 assertNilErr(t, err) 96 assertBoolsEqual(t, true, allowSync) 97 98 allowSync, err = perms.BidderSyncAllowed(context.Background(), openrtb_ext.BidderAppnexus) 99 assertNilErr(t, err) 100 assertBoolsEqual(t, true, allowSync) 101 } 102 103 func TestProhibitedPurposes(t *testing.T) { 104 vendor2NoPurpose1Consent := "CPGWkCaPGWkCaApAAAENABCAAAAAAAAAAAAAABEAAAAA" 105 vendorListData := MarshalVendorList(vendorList{ 106 VendorListVersion: 2, 107 Vendors: map[string]*vendor{ 108 "2": { 109 ID: 2, 110 Purposes: []int{1}, 111 }, 112 }, 113 }) 114 115 tcf2AggConfig := tcf2Config{ 116 HostConfig: config.TCF2{ 117 Purpose1: config.TCF2Purpose{ 118 EnforcePurpose: true, 119 }, 120 }, 121 } 122 tcf2AggConfig.HostConfig.PurposeConfigs = map[consentconstants.Purpose]*config.TCF2Purpose{ 123 consentconstants.Purpose(1): &tcf2AggConfig.HostConfig.Purpose1, 124 } 125 126 perms := permissionsImpl{ 127 cfg: &tcf2AggConfig, 128 hostVendorID: 2, 129 vendorIDs: map[openrtb_ext.BidderName]uint16{ 130 openrtb_ext.BidderAppnexus: 2, 131 }, 132 fetchVendorList: listFetcher(map[uint16]map[uint16]vendorlist.VendorList{ 133 2: { 134 1: parseVendorListDataV2(t, vendorListData), 135 }, 136 }), 137 purposeEnforcerBuilder: NewPurposeEnforcerBuilder(&tcf2AggConfig), 138 gdprSignal: SignalYes, 139 consent: vendor2NoPurpose1Consent, 140 } 141 142 allowSync, err := perms.HostCookiesAllowed(context.Background()) 143 assertNilErr(t, err) 144 assertBoolsEqual(t, false, allowSync) 145 146 allowSync, err = perms.BidderSyncAllowed(context.Background(), openrtb_ext.BidderAppnexus) 147 assertNilErr(t, err) 148 assertBoolsEqual(t, false, allowSync) 149 } 150 151 func TestProhibitedVendors(t *testing.T) { 152 purpose1NoVendorConsent := "CPGWkCaPGWkCaApAAAENABCAAIAAAAAAAAAAABAAAAAA" 153 vendorListData := MarshalVendorList(vendorList{ 154 VendorListVersion: 2, 155 Vendors: map[string]*vendor{ 156 "2": { 157 ID: 2, 158 Purposes: []int{1}, 159 }, 160 }, 161 }) 162 163 tcf2AggConfig := tcf2Config{ 164 HostConfig: config.TCF2{ 165 Purpose1: config.TCF2Purpose{ 166 EnforcePurpose: true, 167 EnforceVendors: true, 168 }, 169 }, 170 } 171 tcf2AggConfig.HostConfig.PurposeConfigs = map[consentconstants.Purpose]*config.TCF2Purpose{ 172 consentconstants.Purpose(1): &tcf2AggConfig.HostConfig.Purpose1, 173 } 174 175 perms := permissionsImpl{ 176 cfg: &tcf2AggConfig, 177 hostVendorID: 2, 178 vendorIDs: map[openrtb_ext.BidderName]uint16{ 179 openrtb_ext.BidderAppnexus: 2, 180 }, 181 fetchVendorList: listFetcher(map[uint16]map[uint16]vendorlist.VendorList{ 182 2: { 183 1: parseVendorListDataV2(t, vendorListData), 184 }, 185 }), 186 purposeEnforcerBuilder: NewPurposeEnforcerBuilder(&tcf2AggConfig), 187 gdprSignal: SignalYes, 188 consent: purpose1NoVendorConsent, 189 } 190 191 allowSync, err := perms.HostCookiesAllowed(context.Background()) 192 assertNilErr(t, err) 193 assertBoolsEqual(t, false, allowSync) 194 195 allowSync, err = perms.BidderSyncAllowed(context.Background(), openrtb_ext.BidderPubmatic) 196 assertNilErr(t, err) 197 assertBoolsEqual(t, false, allowSync) 198 } 199 200 func TestMalformedConsent(t *testing.T) { 201 perms := permissionsImpl{ 202 hostVendorID: 2, 203 fetchVendorList: listFetcher(nil), 204 gdprSignal: SignalYes, 205 consent: "BON", 206 } 207 208 sync, err := perms.HostCookiesAllowed(context.Background()) 209 assertErr(t, err, true) 210 assertBoolsEqual(t, false, sync) 211 } 212 213 func TestAllowActivities(t *testing.T) { 214 bidderAllowedByConsent := openrtb_ext.BidderAppnexus 215 aliasedBidderAllowedByConsent := openrtb_ext.BidderName("appnexus1") 216 bidderBlockedByConsent := openrtb_ext.BidderRubicon 217 vendor2AndPurpose2Consent := "CPGWbY_PGWbY_GYAAAENABCAAEAAAAAAAAAAACEAAAAA" 218 219 tests := []struct { 220 description string 221 bidderName openrtb_ext.BidderName 222 bidderCoreName openrtb_ext.BidderName 223 publisherID string 224 gdpr Signal 225 consent string 226 passID bool 227 weakVendorEnforcement bool 228 aliasGVLIDs map[string]uint16 229 }{ 230 { 231 description: "Allow PI - Non standard publisher", 232 bidderName: bidderBlockedByConsent, 233 bidderCoreName: bidderBlockedByConsent, 234 publisherID: "appNexusAppID", 235 gdpr: SignalYes, 236 consent: vendor2AndPurpose2Consent, 237 passID: true, 238 }, 239 { 240 description: "Allow PI - known vendor with No GDPR", 241 bidderName: bidderBlockedByConsent, 242 bidderCoreName: bidderBlockedByConsent, 243 gdpr: SignalNo, 244 consent: vendor2AndPurpose2Consent, 245 passID: true, 246 }, 247 { 248 description: "Allow PI - known vendor with Yes GDPR", 249 bidderName: bidderAllowedByConsent, 250 bidderCoreName: bidderAllowedByConsent, 251 gdpr: SignalYes, 252 consent: vendor2AndPurpose2Consent, 253 passID: true, 254 }, 255 { 256 description: "Allow PI - known Alias vendor GVLID with Yes GDPR", 257 bidderName: aliasedBidderAllowedByConsent, 258 bidderCoreName: bidderAllowedByConsent, 259 gdpr: SignalYes, 260 consent: vendor2AndPurpose2Consent, 261 passID: true, 262 aliasGVLIDs: map[string]uint16{"appnexus1": 2}, 263 }, 264 { 265 description: "Don't allow PI - known alias vendor with Yes GDPR, alias vendor does not consent to purpose 2", 266 bidderName: aliasedBidderAllowedByConsent, 267 bidderCoreName: bidderAllowedByConsent, 268 gdpr: SignalYes, 269 consent: vendor2AndPurpose2Consent, 270 passID: false, 271 aliasGVLIDs: map[string]uint16{"appnexus1": 1}, 272 }, 273 { 274 description: "Allow PI - known vendor with Ambiguous GDPR and empty consent", 275 bidderName: bidderAllowedByConsent, 276 bidderCoreName: bidderAllowedByConsent, 277 gdpr: SignalAmbiguous, 278 consent: "", 279 passID: true, 280 }, 281 { 282 description: "Allow PI - known vendor with Ambiguous GDPR and non-empty consent", 283 bidderName: bidderAllowedByConsent, 284 bidderCoreName: bidderAllowedByConsent, 285 gdpr: SignalAmbiguous, 286 consent: vendor2AndPurpose2Consent, 287 passID: true, 288 }, 289 { 290 description: "Don't allow PI - known vendor with Yes GDPR and empty consent", 291 bidderName: bidderAllowedByConsent, 292 bidderCoreName: bidderAllowedByConsent, 293 gdpr: SignalYes, 294 consent: "", 295 passID: false, 296 }, 297 { 298 description: "Don't allow PI - default vendor with Yes GDPR and non-empty consent", 299 bidderName: bidderBlockedByConsent, 300 bidderCoreName: bidderBlockedByConsent, 301 gdpr: SignalYes, 302 consent: vendor2AndPurpose2Consent, 303 passID: false, 304 }, 305 } 306 vendorListData := MarshalVendorList(vendorList{ 307 VendorListVersion: 1, 308 Vendors: map[string]*vendor{ 309 "2": { 310 ID: 2, 311 Purposes: []int{2}, 312 }, 313 }, 314 }) 315 tcf2AggConfig := allPurposesEnabledTCF2Config() 316 317 perms := permissionsImpl{ 318 cfg: &tcf2AggConfig, 319 hostVendorID: 2, 320 nonStandardPublishers: map[string]struct{}{"appNexusAppID": {}}, 321 vendorIDs: map[openrtb_ext.BidderName]uint16{ 322 openrtb_ext.BidderAppnexus: 2, 323 }, 324 fetchVendorList: listFetcher(map[uint16]map[uint16]vendorlist.VendorList{ 325 2: { 326 1: parseVendorListDataV2(t, vendorListData), 327 }, 328 }), 329 purposeEnforcerBuilder: NewPurposeEnforcerBuilder(&tcf2AggConfig), 330 } 331 332 for _, tt := range tests { 333 perms.aliasGVLIDs = tt.aliasGVLIDs 334 perms.consent = tt.consent 335 perms.gdprSignal = tt.gdpr 336 perms.publisherID = tt.publisherID 337 338 permissions, err := perms.AuctionActivitiesAllowed(context.Background(), tt.bidderCoreName, tt.bidderName) 339 340 assert.Nil(t, err, tt.description) 341 assert.Equal(t, tt.passID, permissions.PassID, tt.description) 342 } 343 } 344 345 func TestAllowActivitiesBidderWithoutGVLID(t *testing.T) { 346 bidderWithoutGVLID := openrtb_ext.BidderPangle 347 purpose2Consent := "CPuDXznPuDXznMOAAAENCZCAAEAAAAAAAAAAAAAAAAAA" 348 noPurposeConsent := "CPuDXznPuDXznMOAAAENCZCAAAAAAAAAAAAAAAAAAAAA" 349 350 tests := []struct { 351 name string 352 enforceAlgoID config.TCF2EnforcementAlgo 353 vendorExceptions map[string]struct{} 354 basicEnforcementVendors map[string]struct{} 355 consent string 356 allowBidRequest bool 357 passID bool 358 }{ 359 { 360 name: "full_enforcement_no_exceptions_user_consents_to_purpose_2", 361 enforceAlgoID: config.TCF2FullEnforcement, 362 consent: purpose2Consent, 363 }, 364 { 365 name: "full_enforcement_vendor_exception_user_consents_to_purpose_2", 366 enforceAlgoID: config.TCF2FullEnforcement, 367 vendorExceptions: map[string]struct{}{string(bidderWithoutGVLID): {}}, 368 consent: purpose2Consent, 369 allowBidRequest: true, 370 passID: true, 371 }, 372 { 373 name: "basic_enforcement_no_exceptions_user_consents_to_purpose_2", 374 consent: purpose2Consent, 375 }, 376 { 377 name: "basic_enforcement_vendor_exception_user_consents_to_purpose_2", 378 vendorExceptions: map[string]struct{}{string(bidderWithoutGVLID): {}}, 379 consent: purpose2Consent, 380 allowBidRequest: true, 381 passID: true, 382 }, 383 { 384 name: "full_enforcement_soft_vendor_exception_user_consents_to_purpose_2", // allow bid request and pass ID 385 enforceAlgoID: config.TCF2FullEnforcement, 386 basicEnforcementVendors: map[string]struct{}{string(bidderWithoutGVLID): {}}, 387 consent: purpose2Consent, 388 allowBidRequest: true, 389 passID: true, 390 }, 391 { 392 name: "basic_enforcement_soft_vendor_exception_user_consents_to_purpose_2", // allow bid request and pass ID 393 enforceAlgoID: config.TCF2BasicEnforcement, 394 basicEnforcementVendors: map[string]struct{}{string(bidderWithoutGVLID): {}}, 395 consent: purpose2Consent, 396 allowBidRequest: true, 397 passID: true, 398 }, 399 { 400 name: "full_enforcement_soft_vendor_exception_user_consents_to_purpose_4", 401 enforceAlgoID: config.TCF2FullEnforcement, 402 basicEnforcementVendors: map[string]struct{}{string(bidderWithoutGVLID): {}}, 403 consent: noPurposeConsent, 404 allowBidRequest: false, 405 passID: false, 406 }, 407 { 408 name: "basic_enforcement_soft_vendor_exception_user_consents_to_purpose_4", 409 enforceAlgoID: config.TCF2BasicEnforcement, 410 basicEnforcementVendors: map[string]struct{}{string(bidderWithoutGVLID): {}}, 411 consent: noPurposeConsent, 412 allowBidRequest: false, 413 passID: false, 414 }, 415 } 416 417 for _, tt := range tests { 418 t.Run(tt.name, func(t *testing.T) { 419 tcf2AggConfig := allPurposesEnabledTCF2Config() 420 tcf2AggConfig.AccountConfig.BasicEnforcementVendorsMap = tt.basicEnforcementVendors 421 tcf2AggConfig.HostConfig.Purpose2.VendorExceptionMap = tt.vendorExceptions 422 tcf2AggConfig.HostConfig.Purpose2.EnforceAlgoID = tt.enforceAlgoID 423 tcf2AggConfig.HostConfig.PurposeConfigs[consentconstants.Purpose(2)] = &tcf2AggConfig.HostConfig.Purpose2 424 425 perms := permissionsImpl{ 426 cfg: &tcf2AggConfig, 427 consent: tt.consent, 428 gdprSignal: SignalYes, 429 hostVendorID: 2, 430 nonStandardPublishers: map[string]struct{}{}, 431 vendorIDs: map[openrtb_ext.BidderName]uint16{}, 432 fetchVendorList: listFetcher(map[uint16]map[uint16]vendorlist.VendorList{ 433 2: { 434 153: parseVendorListDataV2(t, MarshalVendorList(vendorList{GVLSpecificationVersion: 2, VendorListVersion: 153, Vendors: map[string]*vendor{}})), 435 }, 436 }), 437 purposeEnforcerBuilder: NewPurposeEnforcerBuilder(&tcf2AggConfig), 438 } 439 440 permissions, err := perms.AuctionActivitiesAllowed(context.Background(), bidderWithoutGVLID, bidderWithoutGVLID) 441 assert.NoError(t, err) 442 assert.Equal(t, tt.allowBidRequest, permissions.AllowBidRequest) 443 assert.Equal(t, tt.passID, permissions.PassID) 444 }) 445 } 446 } 447 448 func buildVendorList34() vendorList { 449 return vendorList{ 450 VendorListVersion: 2, 451 Vendors: map[string]*vendor{ 452 "2": { 453 ID: 2, 454 Purposes: []int{1}, 455 }, 456 "6": { 457 ID: 6, 458 Purposes: []int{1, 2, 4}, 459 LegIntPurposes: []int{7}, 460 SpecialFeatures: []int{1}, 461 FlexiblePurposes: []int{1, 2, 4, 7}, 462 }, 463 "8": { 464 ID: 8, 465 Purposes: []int{1, 7}, 466 LegIntPurposes: []int{2, 4}, 467 }, 468 "10": { 469 ID: 10, 470 Purposes: []int{2, 4, 7}, 471 SpecialFeatures: []int{1}, 472 }, 473 "20": { 474 ID: 20, 475 Purposes: []int{1}, 476 LegIntPurposes: []int{2, 7}, 477 FlexiblePurposes: []int{2, 7}, 478 }, 479 "32": { 480 ID: 32, 481 Purposes: []int{1, 2, 4, 7}, 482 }, 483 }, 484 } 485 } 486 487 func allPurposesEnabledTCF2Config() (TCF2AggConfig tcf2Config) { 488 TCF2AggConfig = tcf2Config{ 489 HostConfig: config.TCF2{ 490 Enabled: true, 491 Purpose1: config.TCF2Purpose{EnforceAlgoID: config.TCF2FullEnforcement, EnforcePurpose: true, EnforceVendors: true}, 492 Purpose2: config.TCF2Purpose{EnforceAlgoID: config.TCF2FullEnforcement, EnforcePurpose: true, EnforceVendors: true}, 493 Purpose3: config.TCF2Purpose{EnforceAlgoID: config.TCF2FullEnforcement, EnforcePurpose: true, EnforceVendors: true}, 494 Purpose4: config.TCF2Purpose{EnforceAlgoID: config.TCF2FullEnforcement, EnforcePurpose: true, EnforceVendors: true}, 495 Purpose5: config.TCF2Purpose{EnforceAlgoID: config.TCF2FullEnforcement, EnforcePurpose: true, EnforceVendors: true}, 496 Purpose6: config.TCF2Purpose{EnforceAlgoID: config.TCF2FullEnforcement, EnforcePurpose: true, EnforceVendors: true}, 497 Purpose7: config.TCF2Purpose{EnforceAlgoID: config.TCF2FullEnforcement, EnforcePurpose: true, EnforceVendors: true}, 498 Purpose8: config.TCF2Purpose{EnforceAlgoID: config.TCF2FullEnforcement, EnforcePurpose: true, EnforceVendors: true}, 499 Purpose9: config.TCF2Purpose{EnforceAlgoID: config.TCF2FullEnforcement, EnforcePurpose: true, EnforceVendors: true}, 500 Purpose10: config.TCF2Purpose{EnforceAlgoID: config.TCF2FullEnforcement, EnforcePurpose: true, EnforceVendors: true}, 501 SpecialFeature1: config.TCF2SpecialFeature{Enforce: true}, 502 }, 503 AccountConfig: config.AccountGDPR{ 504 PurposeConfigs: map[consentconstants.Purpose]*config.AccountGDPRPurpose{ 505 consentconstants.Purpose(1): {}, 506 consentconstants.Purpose(2): {}, 507 consentconstants.Purpose(3): {}, 508 consentconstants.Purpose(4): {}, 509 consentconstants.Purpose(5): {}, 510 consentconstants.Purpose(6): {}, 511 consentconstants.Purpose(7): {}, 512 consentconstants.Purpose(8): {}, 513 consentconstants.Purpose(9): {}, 514 consentconstants.Purpose(10): {}, 515 }, 516 }, 517 } 518 TCF2AggConfig.HostConfig.PurposeConfigs = map[consentconstants.Purpose]*config.TCF2Purpose{ 519 consentconstants.Purpose(1): &TCF2AggConfig.HostConfig.Purpose1, 520 consentconstants.Purpose(2): &TCF2AggConfig.HostConfig.Purpose2, 521 consentconstants.Purpose(3): &TCF2AggConfig.HostConfig.Purpose3, 522 consentconstants.Purpose(4): &TCF2AggConfig.HostConfig.Purpose4, 523 consentconstants.Purpose(5): &TCF2AggConfig.HostConfig.Purpose5, 524 consentconstants.Purpose(6): &TCF2AggConfig.HostConfig.Purpose6, 525 consentconstants.Purpose(7): &TCF2AggConfig.HostConfig.Purpose7, 526 consentconstants.Purpose(8): &TCF2AggConfig.HostConfig.Purpose8, 527 consentconstants.Purpose(9): &TCF2AggConfig.HostConfig.Purpose9, 528 consentconstants.Purpose(10): &TCF2AggConfig.HostConfig.Purpose10, 529 } 530 return 531 } 532 533 type testDef struct { 534 description string 535 bidder openrtb_ext.BidderName 536 consent string 537 allowBidRequest bool 538 passGeo bool 539 passID bool 540 weakVendorEnforcement bool 541 bidderCoreName openrtb_ext.BidderName 542 aliasGVLIDs map[string]uint16 543 } 544 545 func TestAllowActivitiesGeoAndID(t *testing.T) { 546 vendorListData := MarshalVendorList(buildVendorList34()) 547 548 perms := permissionsImpl{ 549 hostVendorID: 2, 550 nonStandardPublishers: map[string]struct{}{"appNexusAppID": {}}, 551 vendorIDs: map[openrtb_ext.BidderName]uint16{ 552 openrtb_ext.BidderAppnexus: 2, 553 openrtb_ext.BidderPubmatic: 6, 554 openrtb_ext.BidderRubicon: 8, 555 openrtb_ext.BidderOpenx: 20, 556 openrtb_ext.BidderAudienceNetwork: 55, 557 }, 558 fetchVendorList: listFetcher(map[uint16]map[uint16]vendorlist.VendorList{ 559 2: { 560 34: parseVendorListDataV2(t, vendorListData), 561 74: parseVendorListDataV2(t, vendorListData), 562 }, 563 }), 564 gdprSignal: SignalYes, 565 } 566 567 // COzTVhaOzTVhaGvAAAENAiCIAP_AAH_AAAAAAEEUACCKAAA : full consents to purposes and vendors 2, 6, 8 and special feature 1 opt-in 568 testDefs := []testDef{ 569 { 570 description: "Appnexus vendor test, insufficient purposes claimed", 571 bidder: openrtb_ext.BidderAppnexus, 572 bidderCoreName: openrtb_ext.BidderAppnexus, 573 consent: "COzTVhaOzTVhaGvAAAENAiCIAP_AAH_AAAAAAEEUACCKAAA", 574 allowBidRequest: false, 575 passGeo: false, 576 passID: false, 577 }, 578 { 579 description: "Pubmatic Alias vendor test, insufficient purposes claimed", 580 bidder: "pubmatic1", 581 bidderCoreName: openrtb_ext.BidderPubmatic, 582 consent: "COzTVhaOzTVhaGvAAAENAiCIAP_AAH_AAAAAAEEUACCKAAA", 583 allowBidRequest: false, 584 passGeo: false, 585 passID: false, 586 aliasGVLIDs: map[string]uint16{"pubmatic1": 1}, 587 }, 588 { 589 description: "Appnexus vendor test, insufficient purposes claimed, basic enforcement", 590 bidder: openrtb_ext.BidderAppnexus, 591 bidderCoreName: openrtb_ext.BidderAppnexus, 592 consent: "COzTVhaOzTVhaGvAAAENAiCIAP_AAH_AAAAAAEEUACCKAAA", 593 allowBidRequest: true, 594 passGeo: true, 595 passID: true, 596 weakVendorEnforcement: true, 597 }, 598 { 599 description: "Unknown vendor test, insufficient purposes claimed, basic enforcement", 600 bidder: openrtb_ext.BidderAudienceNetwork, 601 bidderCoreName: openrtb_ext.BidderAudienceNetwork, 602 consent: "COzTVhaOzTVhaGvAAAENAiCIAP_AAH_AAAAAAEEUACCKAAA", 603 allowBidRequest: true, 604 passGeo: true, 605 passID: true, 606 weakVendorEnforcement: true, 607 }, 608 { 609 description: "Pubmatic vendor test, flex purposes claimed", 610 bidder: openrtb_ext.BidderPubmatic, 611 bidderCoreName: openrtb_ext.BidderPubmatic, 612 consent: "COzTVhaOzTVhaGvAAAENAiCIAP_AAH_AAAAAAEEUACCKAAA", 613 allowBidRequest: true, 614 passGeo: true, 615 passID: true, 616 }, 617 { 618 description: "Pubmatic Alias vendor test, flex purposes claimed", 619 bidder: "pubmatic1", 620 bidderCoreName: openrtb_ext.BidderPubmatic, 621 consent: "COzTVhaOzTVhaGvAAAENAiCIAP_AAH_AAAAAAEEUACCKAAA", 622 allowBidRequest: true, 623 passGeo: true, 624 passID: true, 625 aliasGVLIDs: map[string]uint16{"pubmatic1": 6}, 626 }, 627 { 628 description: "Rubicon vendor test, Specific purposes/LIs claimed, no geo claimed", 629 bidder: openrtb_ext.BidderRubicon, 630 bidderCoreName: openrtb_ext.BidderRubicon, 631 consent: "COzTVhaOzTVhaGvAAAENAiCIAP_AAH_AAAAAAEEUACCKAAA", 632 allowBidRequest: true, 633 passGeo: false, 634 passID: true, 635 }, 636 { 637 // This requires publisher restrictions on any claimed purposes, 2-10. Vendor must declare all claimed purposes 638 // as flex with legit interest as primary. 639 // Using vendor 20 for this. 640 description: "OpenX vendor test, Specific purposes/LIs claimed, no geo claimed, Publisher restrictions apply", 641 bidder: openrtb_ext.BidderOpenx, 642 bidderCoreName: openrtb_ext.BidderOpenx, 643 consent: "CPAavcCPAavcCAGABCFRBKCsAP_AAH_AAAqIHFNf_X_fb3_j-_59_9t0eY1f9_7_v-0zjgeds-8Nyd_X_L8X5mM7vB36pq4KuR4Eu3LBAQdlHOHcTUmw6IkVqTPsbk2Mr7NKJ7PEinMbe2dYGH9_n9XT_ZKY79_____7__-_____7_f__-__3_vp9V---wOJAIMBAUAgAEMAAQIFCIQAAQhiQAAAABBCIBQJIAEqgAWVwEdoIEACAxAQgQAgBBQgwCAAQAAJKAgBACwQCAAiAQAAgAEAIAAEIAILACQEAAAEAJCAAiACECAgiAAg5DAgIgCCAFABAAAuJDACAMooASBAPGQGAAKAAqACGAEwALgAjgBlgDUAHZAPsA_ACMAFLAK2AbwBMQCbAFogLYAYEAw8BkQDOQGeAM-EQHwAVABWAC4AIYAZAAywBqADZAHYAPwAgABGAClgFPANYAdUA-QCGwEOgIvASIAmwBOwCkQFyAMCAYSAw8Bk4DOQGfCQAYADgBzgN_CQTgAEAALgAoACoAGQAOAAeABAACIAFQAMIAaABqADyAIYAigBMgCqAKwAWAAuABvADmAHoAQ0AiACJgEsAS4AmgBSgC3AGGAMgAZcA1ADVAGyAO8AewA-IB9gH6AQAAjABQQClgFPAL8AYoA1gBtADcAG8AOIAegA-QCGwEOgIqAReAkQBMQCZQE2AJ2AUOApEBYoC2AFyALvAYEAwYBhIDDQGHgMiAZIAycBlwDOQGfANIAadA1gDWQoAEAYQaBIACoAKwAXABDADIAGWANQAbIA7AB-AEAAIKARgApYBT4C0ALSAawA3gB1QD5AIbAQ6Ai8BIgCbAE7AKRAXIAwIBhIDDwGMAMnAZyAzwBnwcAEAA4Bv4qA2ABQAFQAQwAmABcAEcAMsAagA7AB-AEYAKXAWgBaQDeAJBATEAmwBTYC2AFyAMCAYeAyIBnIDPAGfANyHQWQAFwAUABUADIAHAAQAAiABdADAAMYAaABqADwAH0AQwBFACZAFUAVgAsABcADEAGYAN4AcwA9ACGAERAJYAmABNACjAFKALEAW4AwwBkADKAGiANQAbIA3wB3gD2gH2AfoBGACVAFBAKeAWKAtAC0gFzALyAX4AxQBuADiQHTAdQA9ACGwEOgIiAReAkEBIgCbAE7AKHAU0AqwBYsC2ALZAXAAuQBdoC7wGEgMNAYeAxIBjADHgGSAMnAZUAywBlwDOQGfANEgaQBpIDSwGnANYAbGPABAIqAb-QgZgALAAoABkAEQALgAYgBDACYAFUALgAYgAzABvAD0AI4AWIAygBqADfAHfAPsA_ACMAFBAKGAU-AtAC0gF-AMUAdQA9ACQQEiAJsAU0AsUBaMC2ALaAXAAuQBdoDDwGJAMiAZOAzkBngDPgGiANJAaWA4AlAyAAQAAsACgAGQAOAAigBgAGIAPAAiABMACqAFwAMQAZgA2gCGgEQARIAowBSgC3AGEAMoAaoA2QB3gD8AIwAU-AtAC0gGKANwAcQA6gCHQEXgJEATYAsUBbAC7QGHgMiAZOAywBnIDPAGfANIAawA4AmACARUA38pBBAAXABQAFQAMgAcABAACKAGAAYwA0ADUAHkAQwBFACYAFIAKoAWAAuABiADMAHMAQwAiABRgClAFiALcAZQA0QBqgDZAHfAPsA_ACMAFBAKGAVsAuYBeQDaAG4APQAh0BF4CRAE2AJ2AUOApoBWwCxQFsALgAXIAu0BhoDDwGMAMiAZIAycBlwDOQGeAM-gaQBpMDWANZAbGVABAA-Ab-A.YAAAAAAAAAAA", 644 allowBidRequest: true, 645 passGeo: false, 646 passID: true, 647 }, 648 } 649 650 for _, td := range testDefs { 651 652 tcf2AggConfig := allPurposesEnabledTCF2Config() 653 if td.weakVendorEnforcement { 654 tcf2AggConfig.AccountConfig.BasicEnforcementVendorsMap = map[string]struct{}{string(td.bidder): {}} 655 } 656 perms.cfg = &tcf2AggConfig 657 perms.aliasGVLIDs = td.aliasGVLIDs 658 perms.consent = td.consent 659 perms.purposeEnforcerBuilder = NewPurposeEnforcerBuilder(&tcf2AggConfig) 660 661 permissions, err := perms.AuctionActivitiesAllowed(context.Background(), td.bidderCoreName, td.bidder) 662 assert.NoErrorf(t, err, "Error processing AuctionActivitiesAllowed for %s", td.description) 663 assert.EqualValuesf(t, td.allowBidRequest, permissions.AllowBidRequest, "AllowBid failure on %s", td.description) 664 assert.EqualValuesf(t, td.passGeo, permissions.PassGeo, "PassGeo failure on %s", td.description) 665 assert.EqualValuesf(t, td.passID, permissions.PassID, "PassID failure on %s", td.description) 666 } 667 } 668 669 func TestAllowActivitiesWhitelist(t *testing.T) { 670 // user specifies consent and LI for all purposes, and purpose and LI vendor consent for vendors 2, 6 and 8 671 const fullConsentToPurposesAndVendorsTwoSixEight = "COzTVhaOzTVhaGvAAAENAiCIAP_AAH_AAAAAAEEUACCKAAA" 672 673 vendorListData := MarshalVendorList(buildVendorList34()) 674 tcf2AggConfig := allPurposesEnabledTCF2Config() 675 676 perms := permissionsImpl{ 677 cfg: &tcf2AggConfig, 678 hostVendorID: 2, 679 nonStandardPublishers: map[string]struct{}{"appNexusAppID": {}}, 680 vendorIDs: map[openrtb_ext.BidderName]uint16{ 681 openrtb_ext.BidderAppnexus: 2, 682 openrtb_ext.BidderPubmatic: 6, 683 openrtb_ext.BidderRubicon: 8, 684 }, 685 fetchVendorList: listFetcher(map[uint16]map[uint16]vendorlist.VendorList{ 686 2: { 687 34: parseVendorListDataV2(t, vendorListData), 688 }, 689 }), 690 purposeEnforcerBuilder: NewPurposeEnforcerBuilder(&tcf2AggConfig), 691 aliasGVLIDs: map[string]uint16{}, 692 consent: fullConsentToPurposesAndVendorsTwoSixEight, 693 gdprSignal: SignalYes, 694 publisherID: "appNexusAppID", 695 } 696 697 // Assert that an item that otherwise would not be allowed PI access, gets approved because it is found in the GDPR.NonStandardPublishers array 698 permissions, err := perms.AuctionActivitiesAllowed(context.Background(), openrtb_ext.BidderAppnexus, openrtb_ext.BidderAppnexus) 699 assert.NoErrorf(t, err, "Error processing AuctionActivitiesAllowed") 700 assert.EqualValuesf(t, true, permissions.PassGeo, "PassGeo failure") 701 assert.EqualValuesf(t, true, permissions.PassID, "PassID failure") 702 } 703 704 func TestAllowActivitiesPubRestrict(t *testing.T) { 705 vendorListData := MarshalVendorList(buildVendorList34()) 706 tcf2AggConfig := allPurposesEnabledTCF2Config() 707 708 perms := permissionsImpl{ 709 cfg: &tcf2AggConfig, 710 hostVendorID: 2, 711 vendorIDs: map[openrtb_ext.BidderName]uint16{ 712 openrtb_ext.BidderAppnexus: 2, 713 openrtb_ext.BidderPubmatic: 32, 714 openrtb_ext.BidderRubicon: 8, 715 }, 716 fetchVendorList: listFetcher(map[uint16]map[uint16]vendorlist.VendorList{ 717 2: { 718 15: parseVendorListDataV2(t, vendorListData), 719 }, 720 }), 721 purposeEnforcerBuilder: NewPurposeEnforcerBuilder(&tcf2AggConfig), 722 gdprSignal: SignalYes, 723 } 724 725 // COwAdDhOwAdDhN4ABAENAPCgAAQAAv___wAAAFP_AAp_4AI6ACACAA - vendors 1-10 legit interest only, 726 // Pub restriction on purpose 7, consent only ... no allowPI will pass, no special feature 1 consent 727 testDefs := []testDef{ 728 { 729 description: "Appnexus vendor test, insufficient purposes claimed", 730 bidder: openrtb_ext.BidderAppnexus, 731 bidderCoreName: openrtb_ext.BidderAppnexus, 732 consent: "COwAdDhOwAdDhN4ABAENAPCgAAQAAv___wAAAFP_AAp_4AI6ACACAA", 733 passGeo: false, 734 passID: false, 735 aliasGVLIDs: map[string]uint16{}, 736 }, 737 { 738 description: "Pubmatic vendor test, flex purposes claimed", 739 bidder: openrtb_ext.BidderPubmatic, 740 bidderCoreName: openrtb_ext.BidderPubmatic, 741 consent: "COwAdDhOwAdDhN4ABAENAPCgAAQAAv___wAAAFP_AAp_4AI6ACACAA", 742 passGeo: false, 743 passID: false, 744 aliasGVLIDs: map[string]uint16{}, 745 }, 746 { 747 description: "Pubmatic Alias vendor test, flex purposes claimed", 748 bidder: "pubmatic1", 749 bidderCoreName: openrtb_ext.BidderPubmatic, 750 consent: "COwAdDhOwAdDhN4ABAENAPCgAAQAAv___wAAAFP_AAp_4AI6ACACAA", 751 passGeo: false, 752 passID: false, 753 aliasGVLIDs: map[string]uint16{"pubmatic1": 32}, 754 }, 755 { 756 description: "Rubicon vendor test, Specific purposes/LIs claimed, no geo claimed", 757 bidder: openrtb_ext.BidderRubicon, 758 bidderCoreName: openrtb_ext.BidderRubicon, 759 consent: "COwAdDhOwAdDhN4ABAENAPCgAAQAAv___wAAAFP_AAp_4AI6ACACAA", 760 passGeo: false, 761 passID: true, 762 aliasGVLIDs: map[string]uint16{}, 763 }, 764 } 765 766 for _, td := range testDefs { 767 perms.aliasGVLIDs = td.aliasGVLIDs 768 perms.consent = td.consent 769 770 permissions, err := perms.AuctionActivitiesAllowed(context.Background(), td.bidderCoreName, td.bidder) 771 assert.NoErrorf(t, err, "Error processing AuctionActivitiesAllowed for %s", td.description) 772 assert.EqualValuesf(t, td.passGeo, permissions.PassGeo, "PassGeo failure on %s", td.description) 773 assert.EqualValuesf(t, td.passID, permissions.PassID, "PassID failure on %s", td.description) 774 } 775 } 776 777 func TestAllowSync(t *testing.T) { 778 const fullConsentToPurposesAndVendorsTwoSixEight = "COzTVhaOzTVhaGvAAAENAiCIAP_AAH_AAAAAAEEUACCKAAA" 779 780 vendorListData := MarshalVendorList(buildVendorList34()) 781 tcf2AggConfig := allPurposesEnabledTCF2Config() 782 783 perms := permissionsImpl{ 784 cfg: &tcf2AggConfig, 785 hostVendorID: 2, 786 vendorIDs: map[openrtb_ext.BidderName]uint16{ 787 openrtb_ext.BidderAppnexus: 2, 788 openrtb_ext.BidderPubmatic: 6, 789 openrtb_ext.BidderRubicon: 8, 790 }, 791 fetchVendorList: listFetcher(map[uint16]map[uint16]vendorlist.VendorList{ 792 2: { 793 34: parseVendorListDataV2(t, vendorListData), 794 }, 795 }), 796 purposeEnforcerBuilder: NewPurposeEnforcerBuilder(&tcf2AggConfig), 797 gdprSignal: SignalYes, 798 consent: fullConsentToPurposesAndVendorsTwoSixEight, 799 } 800 801 allowSync, err := perms.HostCookiesAllowed(context.Background()) 802 assert.NoErrorf(t, err, "Error processing HostCookiesAllowed") 803 assert.EqualValuesf(t, true, allowSync, "HostCookiesAllowed failure") 804 805 allowSync, err = perms.BidderSyncAllowed(context.Background(), openrtb_ext.BidderRubicon) 806 assert.NoErrorf(t, err, "Error processing BidderSyncAllowed") 807 assert.EqualValuesf(t, true, allowSync, "BidderSyncAllowed failure") 808 } 809 810 func TestProhibitedPurposeSync(t *testing.T) { 811 const fullConsentToPurposesAndVendorsTwoSixEight = "COzTVhaOzTVhaGvAAAENAiCIAP_AAH_AAAAAAEEUACCKAAA" 812 813 vendorList34 := buildVendorList34() 814 vendorList34.Vendors["8"].Purposes = []int{7} 815 vendorListData := MarshalVendorList(vendorList34) 816 817 tcf2AggConfig := allPurposesEnabledTCF2Config() 818 819 perms := permissionsImpl{ 820 cfg: &tcf2AggConfig, 821 hostVendorID: 8, 822 vendorIDs: map[openrtb_ext.BidderName]uint16{ 823 openrtb_ext.BidderAppnexus: 2, 824 openrtb_ext.BidderPubmatic: 6, 825 openrtb_ext.BidderRubicon: 8, 826 }, 827 fetchVendorList: listFetcher(map[uint16]map[uint16]vendorlist.VendorList{ 828 2: { 829 34: parseVendorListDataV2(t, vendorListData), 830 }, 831 }), 832 purposeEnforcerBuilder: NewPurposeEnforcerBuilder(&tcf2AggConfig), 833 gdprSignal: SignalYes, 834 consent: fullConsentToPurposesAndVendorsTwoSixEight, 835 } 836 837 allowSync, err := perms.HostCookiesAllowed(context.Background()) 838 assert.NoErrorf(t, err, "Error processing HostCookiesAllowed") 839 assert.EqualValuesf(t, false, allowSync, "HostCookiesAllowed failure") 840 841 allowSync, err = perms.BidderSyncAllowed(context.Background(), openrtb_ext.BidderRubicon) 842 assert.NoErrorf(t, err, "Error processing BidderSyncAllowed") 843 assert.EqualValuesf(t, false, allowSync, "BidderSyncAllowed failure") 844 } 845 846 func TestProhibitedVendorSync(t *testing.T) { 847 const fullConsentToPurposesAndVendorsTwoSixEight = "COzTVhaOzTVhaGvAAAENAiCIAP_AAH_AAAAAAEEUACCKAAA" 848 849 vendorListData := MarshalVendorList(buildVendorList34()) 850 tcf2AggConfig := allPurposesEnabledTCF2Config() 851 852 perms := permissionsImpl{ 853 cfg: &tcf2AggConfig, 854 hostVendorID: 10, 855 vendorIDs: map[openrtb_ext.BidderName]uint16{ 856 openrtb_ext.BidderAppnexus: 2, 857 openrtb_ext.BidderPubmatic: 6, 858 openrtb_ext.BidderRubicon: 8, 859 openrtb_ext.BidderOpenx: 10, 860 }, 861 fetchVendorList: listFetcher(map[uint16]map[uint16]vendorlist.VendorList{ 862 2: { 863 34: parseVendorListDataV2(t, vendorListData), 864 }, 865 }), 866 purposeEnforcerBuilder: NewPurposeEnforcerBuilder(&tcf2AggConfig), 867 gdprSignal: SignalYes, 868 consent: fullConsentToPurposesAndVendorsTwoSixEight, 869 } 870 871 // COzTVhaOzTVhaGvAAAENAiCIAP_AAH_AAAAAAEEUACCKAAA : full consents to purposes for vendors 2, 6, 8 872 allowSync, err := perms.HostCookiesAllowed(context.Background()) 873 assert.NoErrorf(t, err, "Error processing HostCookiesAllowed") 874 assert.EqualValuesf(t, false, allowSync, "HostCookiesAllowed failure") 875 876 // Permission disallowed due to consent string not including vendor 10. 877 allowSync, err = perms.BidderSyncAllowed(context.Background(), openrtb_ext.BidderOpenx) 878 assert.NoErrorf(t, err, "Error processing BidderSyncAllowed") 879 assert.EqualValuesf(t, false, allowSync, "BidderSyncAllowed failure") 880 } 881 882 func parseVendorListDataV2(t *testing.T, data string) vendorlist.VendorList { 883 t.Helper() 884 parsed, err := vendorlist2.ParseEagerly([]byte(data)) 885 if err != nil { 886 t.Fatalf("Failed to parse vendor list data. %v", err) 887 } 888 return parsed 889 } 890 891 func listFetcher(specVersionLists map[uint16]map[uint16]vendorlist.VendorList) func(context.Context, uint16, uint16) (vendorlist.VendorList, error) { 892 return func(ctx context.Context, specVersion, listVersion uint16) (vendorlist.VendorList, error) { 893 if lists, ok := specVersionLists[specVersion]; ok { 894 if data, ok := lists[listVersion]; ok { 895 return data, nil 896 } 897 } 898 return nil, fmt.Errorf("spec version %d vendor list %d not found", specVersion, listVersion) 899 } 900 } 901 902 func failedListFetcher(ctx context.Context, specVersion, listVersion uint16) (vendorlist.VendorList, error) { 903 return nil, errors.New("vendor list can't be fetched") 904 } 905 906 func assertNilErr(t *testing.T, err error) { 907 t.Helper() 908 if err != nil { 909 t.Errorf("Unexpected error: %v", err) 910 } 911 } 912 913 func assertErr(t *testing.T, err error, badConsent bool) { 914 t.Helper() 915 if err == nil { 916 t.Errorf("Expected error did not occur.") 917 return 918 } 919 _, isBadConsent := err.(*ErrorMalformedConsent) 920 assertBoolsEqual(t, badConsent, isBadConsent) 921 } 922 923 func assertBoolsEqual(t *testing.T, expected bool, actual bool) { 924 t.Helper() 925 if expected != actual { 926 t.Errorf("Expected %t, got %t", expected, actual) 927 } 928 } 929 930 func TestAllowActivitiesBidRequests(t *testing.T) { 931 purpose2AndVendorConsent := "CPF_61ePF_61eFxAAAENAiCAAEAAAAAAAAAAADAQAAAAAA" 932 purpose2ConsentWithoutVendorConsent := "CPF_61ePF_61eFxAAAENAiCAAEAAAAAAAAAAABIAAAAA" 933 934 purpose2AndVendorLI := "CPF_61ePF_61eFxAAAENAiCAAAAAAEAAAAAAAAAAIAIAAA" 935 purpose2LIWithoutVendorLI := "CPF_61ePF_61eFxAAAENAiCAAAAAAEAAAAAAABIAAAAA" 936 937 testDefs := []struct { 938 description string 939 purpose2EnforcePurpose bool 940 purpose2EnforceVendors bool 941 bidder openrtb_ext.BidderName 942 bidderCoreName openrtb_ext.BidderName 943 consent string 944 allowBidRequest bool 945 passGeo bool 946 passID bool 947 aliasGVLIDs map[string]uint16 948 }{ 949 { 950 description: "Bid blocked - p2 enabled, user consents to p2 but not vendor, vendor consents to p2", 951 purpose2EnforcePurpose: true, 952 purpose2EnforceVendors: true, 953 bidder: openrtb_ext.BidderPubmatic, 954 bidderCoreName: openrtb_ext.BidderPubmatic, 955 consent: purpose2ConsentWithoutVendorConsent, 956 allowBidRequest: false, 957 passGeo: false, 958 passID: false, 959 }, 960 { 961 description: "Bid allowed - p2 enabled, user consents to p2 and vendor, alias vendor consents to p2", 962 purpose2EnforcePurpose: true, 963 purpose2EnforceVendors: true, 964 bidder: "pubmatic1", 965 bidderCoreName: openrtb_ext.BidderPubmatic, 966 consent: purpose2AndVendorConsent, 967 allowBidRequest: true, 968 passGeo: false, 969 passID: true, 970 aliasGVLIDs: map[string]uint16{"pubmatic1": 6}, 971 }, 972 { 973 description: "Bid blocked - p2 enabled, user consents to p2 and vendor, alias vendor does not consent to p2", 974 purpose2EnforcePurpose: true, 975 purpose2EnforceVendors: true, 976 bidder: "pubmatic1", 977 bidderCoreName: openrtb_ext.BidderPubmatic, 978 consent: purpose2AndVendorConsent, 979 allowBidRequest: false, 980 passGeo: false, 981 passID: false, 982 aliasGVLIDs: map[string]uint16{"pubmatic1": 1}, 983 }, 984 { 985 description: "Bid allowed - p2 enabled not enforcing vendors, user consents to p2 but not vendor, vendor consents to p2", 986 purpose2EnforcePurpose: true, 987 purpose2EnforceVendors: false, 988 bidder: openrtb_ext.BidderPubmatic, 989 bidderCoreName: openrtb_ext.BidderPubmatic, 990 consent: purpose2ConsentWithoutVendorConsent, 991 allowBidRequest: true, 992 passGeo: false, 993 passID: false, 994 }, 995 { 996 description: "Bid allowed - p2 disabled and enforcing vendors, user consents to p2 but not vendor, vendor consents to p2", 997 purpose2EnforcePurpose: false, 998 purpose2EnforceVendors: true, 999 bidder: openrtb_ext.BidderPubmatic, 1000 bidderCoreName: openrtb_ext.BidderPubmatic, 1001 consent: purpose2ConsentWithoutVendorConsent, 1002 allowBidRequest: false, 1003 passGeo: false, 1004 passID: false, 1005 }, 1006 { 1007 description: "Bid allowed - p2 disabled not enforcing vendors, user consents to p2 but not vendor, vendor consents to p2", 1008 purpose2EnforcePurpose: false, 1009 purpose2EnforceVendors: false, 1010 bidder: openrtb_ext.BidderPubmatic, 1011 bidderCoreName: openrtb_ext.BidderPubmatic, 1012 consent: purpose2ConsentWithoutVendorConsent, 1013 allowBidRequest: true, 1014 passGeo: false, 1015 passID: false, 1016 }, 1017 { 1018 description: "Bid allowed - p2 disabled and enforcing vendors, user consents to p2 and vendor, vendor consents to p2", 1019 purpose2EnforcePurpose: false, 1020 purpose2EnforceVendors: true, 1021 bidder: openrtb_ext.BidderPubmatic, 1022 bidderCoreName: openrtb_ext.BidderPubmatic, 1023 consent: purpose2AndVendorConsent, 1024 allowBidRequest: true, 1025 passGeo: false, 1026 passID: true, 1027 }, 1028 { 1029 description: "Bid allowed - p2 enabled, user consents to p2 and vendor, vendor consents to p2", 1030 purpose2EnforcePurpose: true, 1031 purpose2EnforceVendors: true, 1032 bidder: openrtb_ext.BidderPubmatic, 1033 bidderCoreName: openrtb_ext.BidderPubmatic, 1034 consent: purpose2AndVendorConsent, 1035 allowBidRequest: true, 1036 passGeo: false, 1037 passID: true, 1038 }, 1039 { 1040 description: "Bid blocked - p2 enabled, user consents to p2 LI but not vendor, vendor consents to p2", 1041 purpose2EnforcePurpose: true, 1042 purpose2EnforceVendors: true, 1043 bidder: openrtb_ext.BidderRubicon, 1044 bidderCoreName: openrtb_ext.BidderRubicon, 1045 consent: purpose2LIWithoutVendorLI, 1046 allowBidRequest: false, 1047 passGeo: false, 1048 passID: false, 1049 }, 1050 { 1051 description: "Bid allowed - p2 enabled, user consents to p2 LI and vendor, vendor consents to p2", 1052 purpose2EnforcePurpose: true, 1053 purpose2EnforceVendors: true, 1054 bidder: openrtb_ext.BidderRubicon, 1055 bidderCoreName: openrtb_ext.BidderRubicon, 1056 consent: purpose2AndVendorLI, 1057 allowBidRequest: true, 1058 passGeo: false, 1059 passID: true, 1060 }, 1061 { 1062 description: "Bid allowed - p2 enabled not enforcing vendors, user consents to p2 LI but not vendor, vendor consents to p2", 1063 purpose2EnforcePurpose: true, 1064 purpose2EnforceVendors: false, 1065 bidder: openrtb_ext.BidderPubmatic, 1066 bidderCoreName: openrtb_ext.BidderPubmatic, 1067 consent: purpose2AndVendorLI, 1068 allowBidRequest: true, 1069 passGeo: false, 1070 passID: false, 1071 }, 1072 } 1073 1074 for _, td := range testDefs { 1075 vendorListData := MarshalVendorList(buildVendorList34()) 1076 1077 perms := permissionsImpl{ 1078 hostVendorID: 2, 1079 vendorIDs: map[openrtb_ext.BidderName]uint16{ 1080 openrtb_ext.BidderPubmatic: 6, 1081 openrtb_ext.BidderRubicon: 8, 1082 }, 1083 fetchVendorList: listFetcher(map[uint16]map[uint16]vendorlist.VendorList{ 1084 2: { 1085 34: parseVendorListDataV2(t, vendorListData), 1086 }, 1087 }), 1088 aliasGVLIDs: td.aliasGVLIDs, 1089 consent: td.consent, 1090 gdprSignal: SignalYes, 1091 } 1092 1093 tcf2AggConfig := allPurposesEnabledTCF2Config() 1094 tcf2AggConfig.HostConfig.Purpose2.EnforcePurpose = td.purpose2EnforcePurpose 1095 tcf2AggConfig.HostConfig.Purpose2.EnforceVendors = td.purpose2EnforceVendors 1096 p2Config := tcf2AggConfig.HostConfig.PurposeConfigs[consentconstants.Purpose(2)] 1097 p2Config.EnforcePurpose = td.purpose2EnforcePurpose 1098 p2Config.EnforceVendors = td.purpose2EnforceVendors 1099 tcf2AggConfig.HostConfig.PurposeConfigs[consentconstants.Purpose(2)] = p2Config 1100 tcf2AggConfig.HostConfig.PurposeConfigs[consentconstants.Purpose(2)] = &tcf2AggConfig.HostConfig.Purpose2 1101 perms.cfg = &tcf2AggConfig 1102 perms.purposeEnforcerBuilder = NewPurposeEnforcerBuilder(&tcf2AggConfig) 1103 1104 permissions, err := perms.AuctionActivitiesAllowed(context.Background(), td.bidderCoreName, td.bidder) 1105 assert.NoErrorf(t, err, "Error processing AuctionActivitiesAllowed for %s", td.description) 1106 assert.EqualValuesf(t, td.allowBidRequest, permissions.AllowBidRequest, "AllowBid failure on %s", td.description) 1107 assert.EqualValuesf(t, td.passGeo, permissions.PassGeo, "PassGeo failure on %s", td.description) 1108 assert.EqualValuesf(t, td.passID, permissions.PassID, "PassID failure on %s", td.description) 1109 } 1110 } 1111 1112 func TestAllowActivitiesVendorException(t *testing.T) { 1113 appnexus := string(openrtb_ext.BidderAppnexus) 1114 noPurposeOrVendorConsentAndPubRestrictsP2 := "CPF_61ePF_61eFxAAAENAiCAAAAAAAAAAAAAACEAAAACEAAgAgAA" 1115 noPurposeOrVendorConsentAndPubRestrictsNone := "CPF_61ePF_61eFxAAAENAiCAAAAAAAAAAAAAACEAAAAA" 1116 1117 testDefs := []struct { 1118 description string 1119 p2VendorExceptionMap map[string]struct{} 1120 sf1VendorExceptionMap map[openrtb_ext.BidderName]struct{} 1121 bidder openrtb_ext.BidderName 1122 consent string 1123 allowBidRequest bool 1124 passGeo bool 1125 passID bool 1126 bidderCoreName openrtb_ext.BidderName 1127 }{ 1128 { 1129 description: "Bid/ID blocked by publisher - p2 enabled with p2 vendor exception, pub restricts p2 for vendor", 1130 p2VendorExceptionMap: map[string]struct{}{appnexus: {}}, 1131 bidder: openrtb_ext.BidderAppnexus, 1132 bidderCoreName: openrtb_ext.BidderAppnexus, 1133 consent: noPurposeOrVendorConsentAndPubRestrictsP2, 1134 allowBidRequest: false, 1135 passGeo: false, 1136 passID: false, 1137 }, 1138 { 1139 description: "Bid/ID allowed by vendor exception - p2 enabled with p2 vendor exception, pub restricts none", 1140 p2VendorExceptionMap: map[string]struct{}{appnexus: {}}, 1141 sf1VendorExceptionMap: map[openrtb_ext.BidderName]struct{}{}, 1142 bidder: openrtb_ext.BidderAppnexus, 1143 bidderCoreName: openrtb_ext.BidderAppnexus, 1144 consent: noPurposeOrVendorConsentAndPubRestrictsNone, 1145 allowBidRequest: true, 1146 passGeo: false, 1147 passID: true, 1148 }, 1149 { 1150 description: "Geo blocked - sf1 enabled but no consent", 1151 p2VendorExceptionMap: map[string]struct{}{}, 1152 sf1VendorExceptionMap: map[openrtb_ext.BidderName]struct{}{}, 1153 bidder: openrtb_ext.BidderAppnexus, 1154 bidderCoreName: openrtb_ext.BidderAppnexus, 1155 consent: noPurposeOrVendorConsentAndPubRestrictsNone, 1156 allowBidRequest: false, 1157 passGeo: false, 1158 passID: false, 1159 }, 1160 { 1161 description: "Geo allowed by vendor exception - sf1 enabled with sf1 vendor exception", 1162 p2VendorExceptionMap: map[string]struct{}{}, 1163 sf1VendorExceptionMap: map[openrtb_ext.BidderName]struct{}{openrtb_ext.BidderAppnexus: {}}, 1164 bidder: openrtb_ext.BidderAppnexus, 1165 bidderCoreName: openrtb_ext.BidderAppnexus, 1166 consent: noPurposeOrVendorConsentAndPubRestrictsNone, 1167 allowBidRequest: false, 1168 passGeo: true, 1169 passID: false, 1170 }, 1171 } 1172 1173 for _, td := range testDefs { 1174 vendorListData := MarshalVendorList(buildVendorList34()) 1175 perms := permissionsImpl{ 1176 hostVendorID: 2, 1177 vendorIDs: map[openrtb_ext.BidderName]uint16{ 1178 openrtb_ext.BidderAppnexus: 32, 1179 }, 1180 fetchVendorList: listFetcher(map[uint16]map[uint16]vendorlist.VendorList{ 1181 2: { 1182 34: parseVendorListDataV2(t, vendorListData), 1183 }, 1184 }), 1185 aliasGVLIDs: map[string]uint16{}, 1186 consent: td.consent, 1187 gdprSignal: SignalYes, 1188 } 1189 1190 tcf2AggConfig := allPurposesEnabledTCF2Config() 1191 tcf2AggConfig.HostConfig.Purpose2.VendorExceptionMap = td.p2VendorExceptionMap 1192 tcf2AggConfig.HostConfig.SpecialFeature1.Enforce = true 1193 tcf2AggConfig.HostConfig.SpecialFeature1.VendorExceptionMap = td.sf1VendorExceptionMap 1194 tcf2AggConfig.HostConfig.PurposeConfigs[consentconstants.Purpose(2)] = &tcf2AggConfig.HostConfig.Purpose2 1195 tcf2AggConfig.HostConfig.PurposeConfigs[consentconstants.Purpose(3)] = &tcf2AggConfig.HostConfig.Purpose3 1196 perms.cfg = &tcf2AggConfig 1197 perms.purposeEnforcerBuilder = NewPurposeEnforcerBuilder(&tcf2AggConfig) 1198 1199 permissions, err := perms.AuctionActivitiesAllowed(context.Background(), td.bidderCoreName, td.bidder) 1200 assert.NoErrorf(t, err, "Error processing AuctionActivitiesAllowed for %s", td.description) 1201 assert.EqualValuesf(t, td.allowBidRequest, permissions.AllowBidRequest, "AllowBid failure on %s", td.description) 1202 assert.EqualValuesf(t, td.passGeo, permissions.PassGeo, "PassGeo failure on %s", td.description) 1203 assert.EqualValuesf(t, td.passID, permissions.PassID, "PassID failure on %s", td.description) 1204 } 1205 } 1206 1207 func TestBidderSyncAllowedVendorException(t *testing.T) { 1208 appnexus := string(openrtb_ext.BidderAppnexus) 1209 noPurposeOrVendorConsentAndPubRestrictsP1 := "CPF_61ePF_61eFxAAAENAiCAAAAAAAAAAAAAAQAAAAAAAAAAIIACACA" 1210 noPurposeOrVendorConsentAndPubRestrictsNone := "CPF_61ePF_61eFxAAAENAiCAAAAAAAAAAAAAACEAAAAA" 1211 1212 testDefs := []struct { 1213 description string 1214 p1VendorExceptionMap map[string]struct{} 1215 bidder openrtb_ext.BidderName 1216 consent string 1217 allowSync bool 1218 }{ 1219 { 1220 description: "Sync blocked by no consent - p1 enabled, no p1 vendor exception, pub restricts none", 1221 p1VendorExceptionMap: map[string]struct{}{}, 1222 bidder: openrtb_ext.BidderAppnexus, 1223 consent: noPurposeOrVendorConsentAndPubRestrictsNone, 1224 allowSync: false, 1225 }, 1226 { 1227 description: "Sync blocked by publisher - p1 enabled with p1 vendor exception, pub restricts p1 for vendor", 1228 p1VendorExceptionMap: map[string]struct{}{appnexus: {}}, 1229 bidder: openrtb_ext.BidderAppnexus, 1230 consent: noPurposeOrVendorConsentAndPubRestrictsP1, 1231 allowSync: false, 1232 }, 1233 { 1234 description: "Sync allowed by vendor exception - p1 enabled with p1 vendor exception, pub restricts none", 1235 p1VendorExceptionMap: map[string]struct{}{appnexus: {}}, 1236 bidder: openrtb_ext.BidderAppnexus, 1237 consent: noPurposeOrVendorConsentAndPubRestrictsNone, 1238 allowSync: true, 1239 }, 1240 } 1241 1242 for _, td := range testDefs { 1243 vendorListData := MarshalVendorList(buildVendorList34()) 1244 perms := permissionsImpl{ 1245 hostVendorID: 2, 1246 vendorIDs: map[openrtb_ext.BidderName]uint16{ 1247 openrtb_ext.BidderAppnexus: 32, 1248 }, 1249 fetchVendorList: listFetcher(map[uint16]map[uint16]vendorlist.VendorList{ 1250 2: { 1251 34: parseVendorListDataV2(t, vendorListData), 1252 }, 1253 }), 1254 consent: td.consent, 1255 gdprSignal: SignalYes, 1256 } 1257 1258 tcf2AggConfig := allPurposesEnabledTCF2Config() 1259 tcf2AggConfig.HostConfig.Purpose1.VendorExceptionMap = td.p1VendorExceptionMap 1260 tcf2AggConfig.HostConfig.PurposeConfigs[consentconstants.Purpose(1)] = &tcf2AggConfig.HostConfig.Purpose1 1261 perms.cfg = &tcf2AggConfig 1262 perms.purposeEnforcerBuilder = NewPurposeEnforcerBuilder(&tcf2AggConfig) 1263 1264 allowSync, err := perms.BidderSyncAllowed(context.Background(), td.bidder) 1265 assert.NoErrorf(t, err, "Error processing BidderSyncAllowed for %s", td.description) 1266 assert.EqualValuesf(t, td.allowSync, allowSync, "AllowSync failure on %s", td.description) 1267 } 1268 } 1269 1270 func TestDefaultPermissions(t *testing.T) { 1271 tests := []struct { 1272 description string 1273 purpose2Enforced bool 1274 feature1Enforced bool 1275 wantPermissions AuctionPermissions 1276 }{ 1277 { 1278 description: "Neither enforced", 1279 wantPermissions: AuctionPermissions{ 1280 AllowBidRequest: true, 1281 PassGeo: true, 1282 PassID: false, 1283 }, 1284 }, 1285 { 1286 description: "Purpose 2 enforced only", 1287 purpose2Enforced: true, 1288 wantPermissions: AuctionPermissions{ 1289 AllowBidRequest: false, 1290 PassGeo: true, 1291 PassID: false, 1292 }, 1293 }, 1294 { 1295 description: "Feature 1 enforced only", 1296 feature1Enforced: true, 1297 wantPermissions: AuctionPermissions{ 1298 AllowBidRequest: true, 1299 PassGeo: false, 1300 PassID: false, 1301 }, 1302 }, 1303 { 1304 description: "Both enforced", 1305 purpose2Enforced: true, 1306 feature1Enforced: true, 1307 wantPermissions: AuctionPermissions{ 1308 AllowBidRequest: false, 1309 PassGeo: false, 1310 PassID: false, 1311 }, 1312 }, 1313 } 1314 1315 for _, tt := range tests { 1316 perms := permissionsImpl{} 1317 1318 tcf2AggConfig := allPurposesEnabledTCF2Config() 1319 tcf2AggConfig.HostConfig.Purpose2.EnforcePurpose = tt.purpose2Enforced 1320 tcf2AggConfig.HostConfig.SpecialFeature1.Enforce = tt.feature1Enforced 1321 tcf2AggConfig.HostConfig.PurposeConfigs[consentconstants.Purpose(2)] = &tcf2AggConfig.HostConfig.Purpose2 1322 perms.cfg = &tcf2AggConfig 1323 1324 result := perms.defaultPermissions() 1325 1326 assert.Equal(t, result, tt.wantPermissions, tt.description) 1327 } 1328 } 1329 1330 func TestVendorListSelection(t *testing.T) { 1331 policyVersion3WithVendor2AndPurpose1Consent := "CPGWbY_PGWbY_GYAAAENABDAAIAAAAAAAAAAACEAAAAA" 1332 policyVersion4WithVendor2AndPurpose1Consent := "CPGWbY_PGWbY_GYAAAENABEAAIAAAAAAAAAAACEAAAAA" 1333 1334 specVersion2vendorListData := MarshalVendorList(vendorList{ 1335 GVLSpecificationVersion: 2, 1336 VendorListVersion: 2, 1337 Vendors: map[string]*vendor{ 1338 "2": { 1339 ID: 2, 1340 Purposes: []int{}, 1341 }, 1342 }, 1343 }) 1344 specVersion3vendorListData := MarshalVendorList(vendorList{ 1345 GVLSpecificationVersion: 3, 1346 VendorListVersion: 2, 1347 Vendors: map[string]*vendor{ 1348 "2": { 1349 ID: 2, 1350 Purposes: []int{1}, 1351 }, 1352 }, 1353 }) 1354 1355 tcf2AggConfig := tcf2Config{ 1356 HostConfig: config.TCF2{ 1357 Purpose1: config.TCF2Purpose{ 1358 EnforcePurpose: true, 1359 EnforceVendors: true, 1360 }, 1361 }, 1362 } 1363 tcf2AggConfig.HostConfig.PurposeConfigs = map[consentconstants.Purpose]*config.TCF2Purpose{ 1364 consentconstants.Purpose(1): &tcf2AggConfig.HostConfig.Purpose1, 1365 } 1366 1367 perms := permissionsImpl{ 1368 cfg: &tcf2AggConfig, 1369 hostVendorID: 2, 1370 vendorIDs: map[openrtb_ext.BidderName]uint16{ 1371 openrtb_ext.BidderAppnexus: 2, 1372 }, 1373 fetchVendorList: listFetcher(map[uint16]map[uint16]vendorlist.VendorList{ 1374 2: { 1375 1: parseVendorListDataV2(t, specVersion2vendorListData), 1376 }, 1377 3: { 1378 1: parseVendorListDataV2(t, specVersion3vendorListData), 1379 }, 1380 }), 1381 purposeEnforcerBuilder: NewPurposeEnforcerBuilder(&tcf2AggConfig), 1382 gdprSignal: SignalYes, 1383 } 1384 1385 tests := []struct { 1386 name string 1387 consent string 1388 expectedAllowSync bool 1389 expectedErr bool 1390 }{ 1391 { 1392 name: "consent_tcf_policy_version_3_uses_gvl_spec_version_2", 1393 consent: policyVersion3WithVendor2AndPurpose1Consent, 1394 expectedAllowSync: false, 1395 }, 1396 { 1397 name: "consent_tcf_policy_version_4_uses_gvl_spec_version_3", 1398 consent: policyVersion4WithVendor2AndPurpose1Consent, 1399 expectedAllowSync: true, 1400 }, 1401 } 1402 1403 for _, tt := range tests { 1404 t.Run(tt.name, func(t *testing.T) { 1405 perms.consent = tt.consent 1406 allowSync, err := perms.HostCookiesAllowed(context.Background()) 1407 assert.Equal(t, tt.expectedAllowSync, allowSync) 1408 if tt.expectedErr { 1409 assert.Error(t, err) 1410 } else { 1411 assert.Nil(t, err) 1412 } 1413 }) 1414 } 1415 }