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
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ public class AmpRequestFactory {
private final DebugResolver debugResolver;
private final JacksonMapper mapper;
private final GeoLocationServiceWrapper geoLocationServiceWrapper;
private final TcfDefinerService tcfDefinerService;

public AmpRequestFactory(Ortb2RequestFactory ortb2RequestFactory,
StoredRequestProcessor storedRequestProcessor,
Expand All @@ -115,7 +116,8 @@ public AmpRequestFactory(Ortb2RequestFactory ortb2RequestFactory,
AmpPrivacyContextFactory ampPrivacyContextFactory,
DebugResolver debugResolver,
JacksonMapper mapper,
GeoLocationServiceWrapper geoLocationServiceWrapper) {
GeoLocationServiceWrapper geoLocationServiceWrapper,
TcfDefinerService tcfDefinerService) {

this.ortb2RequestFactory = Objects.requireNonNull(ortb2RequestFactory);
this.storedRequestProcessor = Objects.requireNonNull(storedRequestProcessor);
Expand All @@ -130,6 +132,7 @@ public AmpRequestFactory(Ortb2RequestFactory ortb2RequestFactory,
this.ampPrivacyContextFactory = Objects.requireNonNull(ampPrivacyContextFactory);
this.mapper = Objects.requireNonNull(mapper);
this.geoLocationServiceWrapper = Objects.requireNonNull(geoLocationServiceWrapper);
this.tcfDefinerService = Objects.requireNonNull(tcfDefinerService);
}

/**
Expand Down Expand Up @@ -217,7 +220,7 @@ private Future<BidRequest> parseBidRequest(AuctionContext auctionContext, HttpRe
return Future.succeededFuture(bidRequest);
}

private static ConsentParam consentParamFromQueryStringParams(HttpRequestContext httpRequest) {
private ConsentParam consentParamFromQueryStringParams(HttpRequestContext httpRequest) {
final ConsentType specifiedConsentType = ConsentType.from(httpRequest.getQueryParams().get(CONSENT_TYPE_PARAM));
final CaseInsensitiveMultiMap queryParams = httpRequest.getQueryParams();

Expand All @@ -229,12 +232,12 @@ private static ConsentParam consentParamFromQueryStringParams(HttpRequestContext
: toConsentParam(gdprConsentParam, GDPR_CONSENT_PARAM, specifiedConsentType);
}

private static ConsentParam toConsentParam(String consent, String fromParam, ConsentType specifiedConsentType) {
private ConsentParam toConsentParam(String consent, String fromParam, ConsentType specifiedConsentType) {
return ConsentParam.of(
consent,
fromParam,
specifiedConsentType,
TcfDefinerService.isConsentStringValid(consent),
tcfDefinerService.isConsentStringValid(consent),
Ccpa.isValid(consent));
}

Expand All @@ -259,10 +262,10 @@ private static Site createSite(HttpRequestContext httpRequest) {

return !StringUtils.isAllBlank(accountId, canonicalUrl, domain)
? Site.builder()
.publisher(Publisher.builder().id(accountId).build())
.page(canonicalUrl)
.domain(domain)
.build()
.publisher(Publisher.builder().id(accountId).build())
.page(canonicalUrl)
.domain(domain)
.build()
: null;
}

Expand All @@ -278,9 +281,9 @@ private static User createUser(ConsentParam consentParam, String addtlConsent) {

final ExtUser extUser = consentedProvidersSettings != null
? ExtUser.builder()
.deprecatedConsentedProvidersSettings(consentedProvidersSettings)
.consentedProvidersSettings(consentedProvidersSettings)
.build()
.deprecatedConsentedProvidersSettings(consentedProvidersSettings)
.consentedProvidersSettings(consentedProvidersSettings)
.build()
: null;

return User.builder().consent(consent).ext(extUser).build();
Expand All @@ -301,12 +304,12 @@ private static Regs createRegs(ConsentParam consentParam,

return gdpr != null || usPrivacy != null || gppSid != null || gpp != null || gpc != null
? Regs.builder()
.gdpr(gdpr)
.usPrivacy(usPrivacy)
.gppSid(gppSid)
.gpp(gpp)
.ext(gpc != null ? ExtRegs.of(null, null, gpc, null) : null)
.build()
.gdpr(gdpr)
.usPrivacy(usPrivacy)
.gppSid(gppSid)
.gpp(gpp)
.ext(gpc != null ? ExtRegs.of(null, null, gpc, null) : null)
.build()
: null;
}

Expand Down Expand Up @@ -359,8 +362,8 @@ private GppSidExtraction gppSidFromQueryStringParams(HttpRequestContext httpRequ
try {
final List<Integer> gppSid = StringUtils.isNotBlank(gppSidParam)
? Arrays.stream(gppSidParam.split(","))
.map(Integer::valueOf)
.toList()
.map(Integer::valueOf)
.toList()
: null;

return GppSidExtraction.success(gppSid);
Expand Down
1 change: 1 addition & 0 deletions src/main/java/org/prebid/server/metric/MetricName.java
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ public enum MetricName {
specified,
opt_out("opt-out"),
invalid,
no_disclosed_vendors("no-disclosed-vendors"),
in_geo("in-geo"),
out_geo("out-geo"),
unknown_geo("unknown-geo"),
Expand Down
4 changes: 4 additions & 0 deletions src/main/java/org/prebid/server/metric/Metrics.java
Original file line number Diff line number Diff line change
Expand Up @@ -519,6 +519,10 @@ public void updatePrivacyTcfInvalidMetric() {
privacy().tcf().incCounter(MetricName.invalid);
}

public void updatePrivacyTcfNoDisclosedVendorsMetric() {
privacy().tcf().incCounter(MetricName.no_disclosed_vendors);
}

public void updatePrivacyTcfRequestsMetric(int version) {
final UpdatableMetrics versionMetrics = privacy().tcf().fromVersion(version);
versionMetrics.incCounter(MetricName.requests);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package org.prebid.server.privacy.gdpr;

import com.iabtcf.decoder.TCString;
import org.prebid.server.settings.model.GdprConfig;

import java.time.Instant;
import java.time.Month;
import java.time.Year;
import java.time.ZoneOffset;

public class DisclosedVendorsStrictness {

private static final Instant TCF_2_3_ENFORCEMENT_CUTOFF_DATE = Year.of(2026)
.atMonth(Month.MARCH)
.atDay(1)
.atStartOfDay()
.toInstant(ZoneOffset.UTC);

private final boolean strictnessEnabled;

public DisclosedVendorsStrictness(GdprConfig gdprConfig) {
this.strictnessEnabled = gdprConfig == null || gdprConfig.isStrictDisclosedVendorsTreatment();
}

public boolean isValid(TCString consent) {
return !strictnessEnabled
|| isCreatedBeforeTcfV2M3EnforcementCutoff(consent)
|| !consent.getDisclosedVendors().isEmpty();
}

private boolean isCreatedBeforeTcfV2M3EnforcementCutoff(TCString consent) {
final Instant created = consent.getCreated();
final Instant lastUpdated = consent.getLastUpdated();
final Instant latest = lastUpdated.isAfter(created) ? lastUpdated : created;

return latest.isBefore(TCF_2_3_ENFORCEMENT_CUTOFF_DATE);
}

public boolean isVendorDisclosed(TCString consent, Integer vendorId) {
return !strictnessEnabled
|| (vendorId != null
&& (isCreatedBeforeTcfV2M3EnforcementCutoff(consent)
|| consent.getDisclosedVendors().contains(vendorId)));
}
}
28 changes: 14 additions & 14 deletions src/main/java/org/prebid/server/privacy/gdpr/Tcf2Service.java
Original file line number Diff line number Diff line change
Expand Up @@ -358,17 +358,17 @@ private Purposes mergeAccountPurposes(AccountGdprConfig accountGdprConfig) {

return accountPurposes != null
? Purposes.builder()
.p1(mergeItem(accountPurposes.getP1(), defaultPurposes.getP1()))
.p2(mergeItem(accountPurposes.getP2(), defaultPurposes.getP2()))
.p3(mergeItem(accountPurposes.getP3(), defaultPurposes.getP3()))
.p4(mergeItem(accountPurposes.getP4(), defaultPurposes.getP4()))
.p5(mergeItem(accountPurposes.getP5(), defaultPurposes.getP5()))
.p6(mergeItem(accountPurposes.getP6(), defaultPurposes.getP6()))
.p7(mergeItem(accountPurposes.getP7(), defaultPurposes.getP7()))
.p8(mergeItem(accountPurposes.getP8(), defaultPurposes.getP8()))
.p9(mergeItem(accountPurposes.getP9(), defaultPurposes.getP9()))
.p10(mergeItem(accountPurposes.getP10(), defaultPurposes.getP10()))
.build()
.p1(mergeItem(accountPurposes.getP1(), defaultPurposes.getP1()))
.p2(mergeItem(accountPurposes.getP2(), defaultPurposes.getP2()))
.p3(mergeItem(accountPurposes.getP3(), defaultPurposes.getP3()))
.p4(mergeItem(accountPurposes.getP4(), defaultPurposes.getP4()))
.p5(mergeItem(accountPurposes.getP5(), defaultPurposes.getP5()))
.p6(mergeItem(accountPurposes.getP6(), defaultPurposes.getP6()))
.p7(mergeItem(accountPurposes.getP7(), defaultPurposes.getP7()))
.p8(mergeItem(accountPurposes.getP8(), defaultPurposes.getP8()))
.p9(mergeItem(accountPurposes.getP9(), defaultPurposes.getP9()))
.p10(mergeItem(accountPurposes.getP10(), defaultPurposes.getP10()))
.build()
: defaultPurposes;
}

Expand All @@ -379,9 +379,9 @@ private SpecialFeatures mergeAccountSpecialFeatures(AccountGdprConfig accountGdp

return accountSpecialFeatures != null
? SpecialFeatures.builder()
.sf1(mergeItem(accountSpecialFeatures.getSf1(), defaultSpecialFeatures.getSf1()))
.sf2(mergeItem(accountSpecialFeatures.getSf2(), defaultSpecialFeatures.getSf2()))
.build()
.sf1(mergeItem(accountSpecialFeatures.getSf1(), defaultSpecialFeatures.getSf1()))
.sf2(mergeItem(accountSpecialFeatures.getSf2(), defaultSpecialFeatures.getSf2()))
.build()
: defaultSpecialFeatures;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ public class TcfDefinerService {
private final boolean gdprEnabled;
private final String gdprDefaultValue;
private final boolean consentStringMeansInScope;
private final DisclosedVendorsStrictness disclosedVendorsStrictness;
private final Tcf2Service tcf2Service;
private final Set<String> eeaCountries;
private final GeoLocationServiceWrapper geoLocationServiceWrapper;
Expand All @@ -70,6 +71,7 @@ public class TcfDefinerService {

public TcfDefinerService(GdprConfig gdprConfig,
Set<String> eeaCountries,
DisclosedVendorsStrictness disclosedVendorsStrictness,
Tcf2Service tcf2Service,
GeoLocationServiceWrapper geoLocationServiceWrapper,
BidderCatalog bidderCatalog,
Expand All @@ -81,6 +83,7 @@ public TcfDefinerService(GdprConfig gdprConfig,
this.gdprDefaultValue = gdprConfig != null ? gdprConfig.getDefaultValue() : null;
this.consentStringMeansInScope = gdprConfig != null
&& BooleanUtils.isTrue(gdprConfig.getConsentStringMeansInScope());
this.disclosedVendorsStrictness = Objects.requireNonNull(disclosedVendorsStrictness);
this.tcf2Service = Objects.requireNonNull(tcf2Service);
this.eeaCountries = Objects.requireNonNull(eeaCountries);
this.geoLocationServiceWrapper = Objects.requireNonNull(geoLocationServiceWrapper);
Expand Down Expand Up @@ -345,6 +348,15 @@ private TCStringParsingResult parseConsentString(String consentString, RequestLo
return TCStringParsingResult.of(TCStringEmpty.create(), warnings);
}

if (!disclosedVendorsStrictness.isValid(tcString)) {
final String message = "Invalid TCF string: `disclosedVendors` list is empty.";
warnings.add(message);
logWarn(consentString, message, requestLogInfo);
metrics.updatePrivacyTcfNoDisclosedVendorsMetric();

return TCStringParsingResult.of(TCStringEmpty.create(), warnings);
}

return toValidResult(consentString, TCStringParsingResult.of(tcString, warnings));
}

Expand Down Expand Up @@ -417,10 +429,9 @@ private static boolean isConsentValid(TCString consent) {
return consent != null && !(consent instanceof TCStringEmpty);
}

public static boolean isConsentStringValid(String consentString) {
public boolean isConsentStringValid(String consentString) {
try {
TCString.decode(consentString);
return true;
return disclosedVendorsStrictness.isValid(TCString.decode(consentString));
} catch (RuntimeException e) {
return false;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,6 @@ public static VendorIdResolver of(BidderCatalog bidderCatalog) {
}

public Integer resolve(String aliasOrBidder) {
return aliases != null ? aliases.resolveAliasVendorId(aliasOrBidder) : null;
return aliases.resolveAliasVendorId(aliasOrBidder);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@ public int getVersion() {

@Override
public Instant getCreated() {
return null;
return Instant.MAX;
}

@Override
public Instant getLastUpdated() {
return null;
return Instant.MAX;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.prebid.server.privacy.gdpr.tcfstrategies.purpose;

import org.prebid.server.privacy.gdpr.DisclosedVendorsStrictness;
import org.prebid.server.privacy.gdpr.model.PrivacyEnforcementAction;
import org.prebid.server.privacy.gdpr.tcfstrategies.purpose.typestrategies.BasicEnforcePurposeStrategy;
import org.prebid.server.privacy.gdpr.tcfstrategies.purpose.typestrategies.FullEnforcePurposeStrategy;
Expand All @@ -8,11 +9,16 @@

public class Purpose01Strategy extends PurposeStrategy {

public Purpose01Strategy(FullEnforcePurposeStrategy fullEnforcePurposeStrategy,
public Purpose01Strategy(DisclosedVendorsStrictness disclosedVendorsStrictness,
FullEnforcePurposeStrategy fullEnforcePurposeStrategy,
BasicEnforcePurposeStrategy basicEnforcePurposeStrategy,
NoEnforcePurposeStrategy noEnforcePurposeStrategy) {

super(fullEnforcePurposeStrategy, basicEnforcePurposeStrategy, noEnforcePurposeStrategy);
super(
disclosedVendorsStrictness,
fullEnforcePurposeStrategy,
basicEnforcePurposeStrategy,
noEnforcePurposeStrategy);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.prebid.server.privacy.gdpr.tcfstrategies.purpose;

import org.prebid.server.privacy.gdpr.DisclosedVendorsStrictness;
import org.prebid.server.privacy.gdpr.model.PrivacyEnforcementAction;
import org.prebid.server.privacy.gdpr.tcfstrategies.purpose.typestrategies.BasicEnforcePurposeStrategy;
import org.prebid.server.privacy.gdpr.tcfstrategies.purpose.typestrategies.FullEnforcePurposeStrategy;
Expand All @@ -8,11 +9,16 @@

public class Purpose02Strategy extends PurposeStrategy {

public Purpose02Strategy(FullEnforcePurposeStrategy fullEnforcePurposeStrategy,
public Purpose02Strategy(DisclosedVendorsStrictness disclosedVendorsStrictness,
FullEnforcePurposeStrategy fullEnforcePurposeStrategy,
BasicEnforcePurposeStrategy basicEnforcePurposeStrategy,
NoEnforcePurposeStrategy noEnforcePurposeStrategy) {

super(fullEnforcePurposeStrategy, basicEnforcePurposeStrategy, noEnforcePurposeStrategy);
super(
disclosedVendorsStrictness,
fullEnforcePurposeStrategy,
basicEnforcePurposeStrategy,
noEnforcePurposeStrategy);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.prebid.server.privacy.gdpr.tcfstrategies.purpose;

import org.prebid.server.privacy.gdpr.DisclosedVendorsStrictness;
import org.prebid.server.privacy.gdpr.model.PrivacyEnforcementAction;
import org.prebid.server.privacy.gdpr.tcfstrategies.purpose.typestrategies.BasicEnforcePurposeStrategy;
import org.prebid.server.privacy.gdpr.tcfstrategies.purpose.typestrategies.FullEnforcePurposeStrategy;
Expand All @@ -8,11 +9,16 @@

public class Purpose03Strategy extends PurposeStrategy {

public Purpose03Strategy(FullEnforcePurposeStrategy fullEnforcePurposeStrategy,
public Purpose03Strategy(DisclosedVendorsStrictness disclosedVendorsStrictness,
FullEnforcePurposeStrategy fullEnforcePurposeStrategy,
BasicEnforcePurposeStrategy basicEnforcePurposeStrategy,
NoEnforcePurposeStrategy noEnforcePurposeStrategy) {

super(fullEnforcePurposeStrategy, basicEnforcePurposeStrategy, noEnforcePurposeStrategy);
super(
disclosedVendorsStrictness,
fullEnforcePurposeStrategy,
basicEnforcePurposeStrategy,
noEnforcePurposeStrategy);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.prebid.server.privacy.gdpr.tcfstrategies.purpose;

import org.prebid.server.privacy.gdpr.DisclosedVendorsStrictness;
import org.prebid.server.privacy.gdpr.model.PrivacyEnforcementAction;
import org.prebid.server.privacy.gdpr.tcfstrategies.purpose.typestrategies.BasicEnforcePurposeStrategy;
import org.prebid.server.privacy.gdpr.tcfstrategies.purpose.typestrategies.FullEnforcePurposeStrategy;
Expand All @@ -8,11 +9,16 @@

public class Purpose04Strategy extends PurposeStrategy {

public Purpose04Strategy(FullEnforcePurposeStrategy fullEnforcePurposeStrategy,
public Purpose04Strategy(DisclosedVendorsStrictness disclosedVendorsStrictness,
FullEnforcePurposeStrategy fullEnforcePurposeStrategy,
BasicEnforcePurposeStrategy basicEnforcePurposeStrategy,
NoEnforcePurposeStrategy noEnforcePurposeStrategy) {

super(fullEnforcePurposeStrategy, basicEnforcePurposeStrategy, noEnforcePurposeStrategy);
super(
disclosedVendorsStrictness,
fullEnforcePurposeStrategy,
basicEnforcePurposeStrategy,
noEnforcePurposeStrategy);
}

@Override
Expand Down
Loading
Loading