From 6d856e85b1c857faca7dcd10427d9eb31a95441e Mon Sep 17 00:00:00 2001 From: Samin Rahman Date: Wed, 14 Jan 2026 14:08:10 +1100 Subject: [PATCH 1/6] Added early exit for meetPolicyRequirements and added a counter metric for requests bypassing optout check --- .../operator/vertx/UIDOperatorVerticle.java | 31 +++++++++++++------ 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/uid2/operator/vertx/UIDOperatorVerticle.java b/src/main/java/com/uid2/operator/vertx/UIDOperatorVerticle.java index 7b36e8eea..8babc1515 100644 --- a/src/main/java/com/uid2/operator/vertx/UIDOperatorVerticle.java +++ b/src/main/java/com/uid2/operator/vertx/UIDOperatorVerticle.java @@ -1654,17 +1654,28 @@ private boolean meetPolicyCheckRequirements(RoutingContext rc) { respectOptOut = OptoutCheckPolicy.fromValue(requestJsonObject.getInteger(POLICY_PARAM)) == OptoutCheckPolicy.respectOptOut(); } - final ClientKey clientKey = (ClientKey) AuthMiddleware.getAuthClient(rc); - final ClientKey oldestClientKey = this.clientKeyProvider.getOldestClientKey(clientKey.getSiteId()); - boolean newClient = oldestClientKey.getCreated() >= OPT_OUT_CHECK_CUTOFF_DATE; - - if (newClient && !respectOptOut) { - // log policy violation - LOGGER.warn(String.format("Failed to respect opt-out policy: siteId=%d, clientKeyName=%s, clientKeyCreated=%d", - oldestClientKey.getSiteId(), oldestClientKey.getName(), oldestClientKey.getCreated())); - return false; + if (respectOptOut) { + return true; + } else { + final ClientKey clientKey = (ClientKey) AuthMiddleware.getAuthClient(rc); + final ClientKey oldestClientKey = this.clientKeyProvider.getOldestClientKey(clientKey.getSiteId()); + boolean newClient = oldestClientKey.getCreated() >= OPT_OUT_CHECK_CUTOFF_DATE; + + if (!newClient) { + Counter.builder("uid2_opt_out_no_respect_total") + .description("Counter for the number of successful requests that have optout set to zero (legacy clients)") + .tag("client_name", clientKey.getName()) + .tag("client_contact", clientKey.getContact()) + .register(Metrics.globalRegistry) + .increment(); + return true; + } else { + // log policy violation + LOGGER.warn(String.format("Failed to respect opt-out policy: siteId=%d, clientKeyName=%s, clientKeyCreated=%d", + oldestClientKey.getSiteId(), oldestClientKey.getName(), oldestClientKey.getCreated())); + return false; + } } - return true; } private Tuple.Tuple2 readOptoutCheckPolicy(JsonObject req) { From 874ae8a98c28eefb81470dbdb58b6829e357e46a Mon Sep 17 00:00:00 2001 From: Samin Rahman Date: Thu, 15 Jan 2026 16:23:41 +1100 Subject: [PATCH 2/6] Renamed counter and changed tags --- .../java/com/uid2/operator/vertx/UIDOperatorVerticle.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/uid2/operator/vertx/UIDOperatorVerticle.java b/src/main/java/com/uid2/operator/vertx/UIDOperatorVerticle.java index 8babc1515..981e47c70 100644 --- a/src/main/java/com/uid2/operator/vertx/UIDOperatorVerticle.java +++ b/src/main/java/com/uid2/operator/vertx/UIDOperatorVerticle.java @@ -1662,10 +1662,9 @@ private boolean meetPolicyCheckRequirements(RoutingContext rc) { boolean newClient = oldestClientKey.getCreated() >= OPT_OUT_CHECK_CUTOFF_DATE; if (!newClient) { - Counter.builder("uid2_opt_out_no_respect_total") + Counter.builder("uid2_legacy_opt_out_bypass_total") .description("Counter for the number of successful requests that have optout set to zero (legacy clients)") - .tag("client_name", clientKey.getName()) - .tag("client_contact", clientKey.getContact()) + .tag("site_id", clientKey.getSiteId().toString()) .register(Metrics.globalRegistry) .increment(); return true; From 57d6a34d55845427410fc43aa96101d95aeea164 Mon Sep 17 00:00:00 2001 From: Release Workflow Date: Thu, 15 Jan 2026 05:27:24 +0000 Subject: [PATCH 3/6] [CI Pipeline] Released Snapshot version: 5.63.23-alpha-287-SNAPSHOT --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 0474f97a0..497a50889 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.uid2 uid2-operator - 5.63.22 + 5.63.23-alpha-287-SNAPSHOT UTF-8 From 75ec479fcd41bb26c06b6a4cc61b80dc76fe7cd1 Mon Sep 17 00:00:00 2001 From: Samin Rahman Date: Mon, 19 Jan 2026 09:03:42 +1100 Subject: [PATCH 4/6] Removed optout policy check and disable optout feature flag --- conf/docker-config.json | 1 - conf/integ-config.json | 1 - conf/local-config.json | 1 - conf/local-e2e-docker-public-config.json | 1 - conf/local-e2e-public-config.json | 2 +- ...dator-latest-e2e-docker-public-config.json | 1 - src/main/java/com/uid2/operator/Const.java | 1 - .../operator/vertx/UIDOperatorVerticle.java | 90 +-------- .../operator/UIDOperatorVerticleTest.java | 171 ------------------ 9 files changed, 3 insertions(+), 266 deletions(-) diff --git a/conf/docker-config.json b/conf/docker-config.json index d2927f044..5abdf3a04 100644 --- a/conf/docker-config.json +++ b/conf/docker-config.json @@ -42,7 +42,6 @@ "salts_expired_shutdown_hours": 12, "store_refresh_stale_shutdown_hours": 12, "operator_type": "public", - "disable_optout_token": true, "enable_remote_config": true, "uid_instance_id_prefix": "local-operator" } diff --git a/conf/integ-config.json b/conf/integ-config.json index f7b16e833..7416395ef 100644 --- a/conf/integ-config.json +++ b/conf/integ-config.json @@ -18,7 +18,6 @@ "salts_expired_shutdown_hours": 12, "store_refresh_stale_shutdown_hours": 12, "operator_type": "public", - "disable_optout_token": true, "enable_remote_config": false, "uid_instance_id_prefix": "local-operator" } \ No newline at end of file diff --git a/conf/local-config.json b/conf/local-config.json index 0d8720483..530045b05 100644 --- a/conf/local-config.json +++ b/conf/local-config.json @@ -41,7 +41,6 @@ "store_refresh_stale_shutdown_hours": 12, "operator_type": "public", "encrypted_files": false, - "disable_optout_token": true, "enable_remote_config": true, "uid_instance_id_prefix": "local-operator" } diff --git a/conf/local-e2e-docker-public-config.json b/conf/local-e2e-docker-public-config.json index 7610e9bc7..3b3416997 100644 --- a/conf/local-e2e-docker-public-config.json +++ b/conf/local-e2e-docker-public-config.json @@ -38,7 +38,6 @@ "salts_expired_shutdown_hours": 12, "store_refresh_stale_shutdown_hours": 12, "operator_type": "public", - "disable_optout_token": true, "enable_remote_config": true, "uid_instance_id_prefix": "local-public-operator" } diff --git a/conf/local-e2e-public-config.json b/conf/local-e2e-public-config.json index 80459743b..7f5801a39 100644 --- a/conf/local-e2e-public-config.json +++ b/conf/local-e2e-public-config.json @@ -44,7 +44,7 @@ "salts_expired_shutdown_hours": 12, "store_refresh_stale_shutdown_hours": 12, "operator_type": "public", - "disable_optout_token": true, + "enable_remote_config": true, "uid_instance_id_prefix": "local-public-operator" } diff --git a/conf/validator-latest-e2e-docker-public-config.json b/conf/validator-latest-e2e-docker-public-config.json index 55cd04f87..184d37b8e 100644 --- a/conf/validator-latest-e2e-docker-public-config.json +++ b/conf/validator-latest-e2e-docker-public-config.json @@ -43,7 +43,6 @@ }, "config_scan_period_ms": 300000 }, - "disable_optout_token": true, "enable_remote_config": true, "uid_instance_id_prefix": "local-public-operator" } diff --git a/src/main/java/com/uid2/operator/Const.java b/src/main/java/com/uid2/operator/Const.java index 14f878371..ef0c8b6be 100644 --- a/src/main/java/com/uid2/operator/Const.java +++ b/src/main/java/com/uid2/operator/Const.java @@ -34,7 +34,6 @@ public class Config extends com.uid2.shared.Const.Config { public static final String ConfigScanPeriodMsProp = "config_scan_period_ms"; public static final String IdentityV3Prop = "identity_v3"; - public static final String DisableOptoutTokenProp = "disable_optout_token"; public static final String EnableRemoteConfigProp = "enable_remote_config"; public static final String RuntimeConfigMetadataPathProp = "runtime_config_metadata_path"; diff --git a/src/main/java/com/uid2/operator/vertx/UIDOperatorVerticle.java b/src/main/java/com/uid2/operator/vertx/UIDOperatorVerticle.java index 981e47c70..41d44d0ff 100644 --- a/src/main/java/com/uid2/operator/vertx/UIDOperatorVerticle.java +++ b/src/main/java/com/uid2/operator/vertx/UIDOperatorVerticle.java @@ -105,7 +105,6 @@ public class UIDOperatorVerticle extends AbstractVerticle { private final IClientKeyProvider clientKeyProvider; private final Clock clock; private final boolean identityV3Enabled; - private final boolean disableOptoutToken; private final UidInstanceIdProvider uidInstanceIdProvider; protected IUIDOperatorService idService; @@ -196,7 +195,6 @@ public UIDOperatorVerticle(IConfigStore configStore, this.optOutStatusApiEnabled = config.getBoolean(Const.Config.OptOutStatusApiEnabled, true); this.optOutStatusMaxRequestSize = config.getInteger(Const.Config.OptOutStatusMaxRequestSize, 5000); this.identityV3Enabled = config.getBoolean(IdentityV3Prop, false); - this.disableOptoutToken = config.getBoolean(DisableOptoutTokenProp, false); this.uidInstanceIdProvider = uidInstanceIdProvider; } @@ -945,14 +943,6 @@ private void handleTokenGenerateV2(RoutingContext rc) { } } - final Tuple.Tuple2 optoutCheckPolicy = readOptoutCheckPolicy(req); - recordTokenGeneratePolicy(apiContact, optoutCheckPolicy.getItem1(), optoutCheckPolicy.getItem2()); - - if (!meetPolicyCheckRequirements(rc)) { - SendClientErrorResponseAndRecordStats(ResponseStatus.ClientError, 400, rc, "Required opt-out policy argument for token/generate is missing or not set to 1", siteId, TokenResponseStatsCollector.Endpoint.GenerateV2, TokenResponseStatsCollector.ResponseStatus.BadPayload, siteProvider, platformType); - return; - } - final IdentityTokens t = this.idService.generateIdentity( new IdentityRequest( new PublisherIdentity(siteId, 0, 0), @@ -964,31 +954,8 @@ private void handleTokenGenerateV2(RoutingContext rc) { identityExpiresAfter); if (t.isEmptyToken()) { - if (optoutCheckPolicy.getItem1() == OptoutCheckPolicy.DoNotRespect && !this.disableOptoutToken) { // only legacy can use this policy - final InputUtil.InputVal optOutTokenInput = input.getIdentityType() == IdentityType.Email - ? InputUtil.InputVal.validEmail(OptOutTokenIdentityForEmail, OptOutTokenIdentityForEmail) - : InputUtil.InputVal.validPhone(OptOutTokenIdentityForPhone, OptOutTokenIdentityForPhone); - - PrivacyBits pb = new PrivacyBits(); - pb.setLegacyBit(); - pb.setClientSideTokenGenerateOptout(); - - final IdentityTokens optOutTokens = this.idService.generateIdentity( - new IdentityRequest( - new PublisherIdentity(siteId, 0, 0), - optOutTokenInput.toUserIdentity(this.identityScope, pb.getAsInt(), Instant.now()), - OptoutCheckPolicy.DoNotRespect, - identityEnvironment), - refreshIdentityAfter, - refreshExpiresAfter, - identityExpiresAfter); - - ResponseUtil.SuccessV2(rc, toTokenResponseJson(optOutTokens)); - recordTokenResponseStats(siteId, TokenResponseStatsCollector.Endpoint.GenerateV2, TokenResponseStatsCollector.ResponseStatus.Success, siteProvider, optOutTokens.getAdvertisingTokenVersion(), platformType); - } else { // new participant, or legacy specified policy/optout_check=1 - ResponseUtil.SuccessNoBodyV2("optout", rc); - recordTokenResponseStats(siteId, TokenResponseStatsCollector.Endpoint.GenerateV2, TokenResponseStatsCollector.ResponseStatus.OptOut, siteProvider, null, platformType); - } + ResponseUtil.SuccessNoBodyV2("optout", rc); + recordTokenResponseStats(siteId, TokenResponseStatsCollector.Endpoint.GenerateV2, TokenResponseStatsCollector.ResponseStatus.OptOut, siteProvider, null, platformType); } else { ResponseUtil.SuccessV2(rc, toTokenResponseJson(t)); recordTokenResponseStats(siteId, TokenResponseStatsCollector.Endpoint.GenerateV2, TokenResponseStatsCollector.ResponseStatus.Success, siteProvider, t.getAdvertisingTokenVersion(), platformType); @@ -1642,59 +1609,6 @@ private UserConsentStatus validateUserConsent(JsonObject req, String apiContact) return UserConsentStatus.SUFFICIENT; } - private static final String POLICY_PARAM = "policy"; - private static final String OPTOUT_CHECK_POLICY_PARAM = "optout_check"; - - private boolean meetPolicyCheckRequirements(RoutingContext rc) { - JsonObject requestJsonObject = (JsonObject) rc.data().get(REQUEST); - boolean respectOptOut = false; - if (requestJsonObject.containsKey(OPTOUT_CHECK_POLICY_PARAM)) { - respectOptOut = OptoutCheckPolicy.fromValue(requestJsonObject.getInteger(OPTOUT_CHECK_POLICY_PARAM)) == OptoutCheckPolicy.respectOptOut(); - } else if (requestJsonObject.containsKey(POLICY_PARAM)) { - respectOptOut = OptoutCheckPolicy.fromValue(requestJsonObject.getInteger(POLICY_PARAM)) == OptoutCheckPolicy.respectOptOut(); - } - - if (respectOptOut) { - return true; - } else { - final ClientKey clientKey = (ClientKey) AuthMiddleware.getAuthClient(rc); - final ClientKey oldestClientKey = this.clientKeyProvider.getOldestClientKey(clientKey.getSiteId()); - boolean newClient = oldestClientKey.getCreated() >= OPT_OUT_CHECK_CUTOFF_DATE; - - if (!newClient) { - Counter.builder("uid2_legacy_opt_out_bypass_total") - .description("Counter for the number of successful requests that have optout set to zero (legacy clients)") - .tag("site_id", clientKey.getSiteId().toString()) - .register(Metrics.globalRegistry) - .increment(); - return true; - } else { - // log policy violation - LOGGER.warn(String.format("Failed to respect opt-out policy: siteId=%d, clientKeyName=%s, clientKeyCreated=%d", - oldestClientKey.getSiteId(), oldestClientKey.getName(), oldestClientKey.getCreated())); - return false; - } - } - } - - private Tuple.Tuple2 readOptoutCheckPolicy(JsonObject req) { - if(req.containsKey(OPTOUT_CHECK_POLICY_PARAM)) { - return new Tuple.Tuple2<>(OptoutCheckPolicy.fromValue(req.getInteger(OPTOUT_CHECK_POLICY_PARAM)), OPTOUT_CHECK_POLICY_PARAM); - } else if(req.containsKey(POLICY_PARAM)) { - return new Tuple.Tuple2<>(OptoutCheckPolicy.fromValue(req.getInteger(POLICY_PARAM)), POLICY_PARAM); - } else { - return new Tuple.Tuple2<>(OptoutCheckPolicy.defaultPolicy(), "null"); - } - } - - private void recordTokenGeneratePolicy(String apiContact, OptoutCheckPolicy policy, String policyParameterKey) { - _tokenGeneratePolicyCounters.computeIfAbsent(new Tuple.Tuple3<>(apiContact, policy, policyParameterKey), triple -> Counter - .builder("uid2_token_generate_policy_usage_total") - .description("Counter for token generate policy usage") - .tags("api_contact", triple.getItem1(), "policy", String.valueOf(triple.getItem2()), "policy_parameter", triple.getItem3()) - .register(Metrics.globalRegistry)).increment(); - } - private void recordTokenGenerateTCFUsage(String apiContact) { _tokenGenerateTCFUsage.computeIfAbsent(apiContact, contact -> Counter .builder("uid2_token_generate_tcf_usage_total") diff --git a/src/test/java/com/uid2/operator/UIDOperatorVerticleTest.java b/src/test/java/com/uid2/operator/UIDOperatorVerticleTest.java index 835d76d91..116909fff 100644 --- a/src/test/java/com/uid2/operator/UIDOperatorVerticleTest.java +++ b/src/test/java/com/uid2/operator/UIDOperatorVerticleTest.java @@ -153,11 +153,6 @@ void deployVerticle(Vertx vertx, VertxTestContext testContext, TestInfo testInfo setupConfig(config); runtimeConfig = setupRuntimeConfig(config); - // TODO: Remove this when we remove tokenGenerateOptOutTokenWithDisableOptoutTokenFF test - if (testInfo.getTestMethod().isPresent() && - testInfo.getTestMethod().get().getName().equals("tokenGenerateOptOutTokenWithDisableOptoutTokenFF")) { - config.put(Const.Config.DisableOptoutTokenProp, true); - } if (testInfo.getDisplayName().equals("cstgNoPhoneSupport(Vertx, VertxTestContext)")) { config.put("enable_phone_support", false); } @@ -201,7 +196,6 @@ private void setupConfig(JsonObject config) { config.put(Const.Config.AllowClockSkewSecondsProp, 3600); config.put(Const.Config.OptOutStatusApiEnabled, true); config.put(Const.Config.OptOutStatusMaxRequestSize, optOutStatusMaxRequestSize); - config.put(Const.Config.DisableOptoutTokenProp, false); config.put(Const.Config.ConfigScanPeriodMsProp, 10000); } @@ -1366,47 +1360,6 @@ void v3IdentityMapOutdatedRefreshFrom(Vertx vertx, VertxTestContext testContext) }); } - @Test - void tokenGenerateNewClientNoPolicySpecified(Vertx vertx, VertxTestContext testContext) { - final int clientSiteId = 201; - fakeAuth(clientSiteId, newClientCreationDateTime, Role.GENERATOR); - setupSalts(); - setupKeys(); - - JsonObject v2Payload = new JsonObject(); - v2Payload.put("email", "test@email.com"); - - sendTokenGenerate(vertx, v2Payload, 400, - json -> { - assertFalse(json.containsKey("body")); - assertEquals("client_error", json.getString("status")); - assertEquals("Required opt-out policy argument for token/generate is missing or not set to 1", json.getString("message")); - testContext.completeNow(); - }); - } - - @ParameterizedTest - @ValueSource(strings = {"policy", "optout_check"}) - void tokenGenerateNewClientWrongPolicySpecified(String policyParamterKey, Vertx vertx, VertxTestContext testContext) { - final int clientSiteId = 201; - fakeAuth(clientSiteId, newClientCreationDateTime, Role.GENERATOR); - setupSalts(); - setupKeys(); - - JsonObject v2Payload = new JsonObject(); - v2Payload.put("email", "test@email.com"); - v2Payload.put(policyParamterKey, OptoutCheckPolicy.DoNotRespect.policy); - - sendTokenGenerate(vertx, - v2Payload, 400, - json -> { - assertFalse(json.containsKey("body")); - assertEquals("client_error", json.getString("status")); - assertEquals("Required opt-out policy argument for token/generate is missing or not set to 1", json.getString("message")); - testContext.completeNow(); - }); - } - @Test void tokenGenerateNewClientNoPolicySpecifiedOlderKeySuccessful(Vertx vertx, VertxTestContext testContext) { ClientKey newClientKey = new ClientKey( @@ -1489,130 +1442,6 @@ void tokenGenerateNewClientWrongPolicySpecifiedOlderKeySuccessful(String policyP }); } - @ParameterizedTest // TODO: remove test after optout check phase 3 - @CsvSource({ - "policy,someoptout@example.com,Email", - "policy,+01234567890,Phone", - "optout_check,someoptout@example.com,Email", - "optout_check,+01234567890,Phone" - }) - void tokenGenerateOptOutToken(String policyParameterKey, String identity, IdentityType identityType, - Vertx vertx, VertxTestContext testContext) { - ClientKey oldClientKey = new ClientKey( - null, - null, - Utils.toBase64String(clientSecret), - "test-contact", - newClientCreationDateTime.minusSeconds(5), - Set.of(Role.GENERATOR), - 201, - null - ); - when(clientKeyProvider.get(any())).thenReturn(oldClientKey); - when(clientKeyProvider.getClientKey(any())).thenReturn(oldClientKey); - when(clientKeyProvider.getOldestClientKey(201)).thenReturn(oldClientKey); - when(this.optOutStore.getLatestEntry(any())).thenReturn(Instant.now()); - setupSalts(); - setupKeys(); - - JsonObject v2Payload = new JsonObject(); - v2Payload.put(identityType.name().toLowerCase(), identity); - v2Payload.put(policyParameterKey, OptoutCheckPolicy.DoNotRespect.policy); - - sendTokenGenerate(vertx, - v2Payload, 200, - json -> { - InputUtil.InputVal optOutTokenInput = identityType == IdentityType.Email ? - InputUtil.InputVal.validEmail(OptOutTokenIdentityForEmail, OptOutTokenIdentityForEmail) : - InputUtil.InputVal.validPhone(OptOutIdentityForPhone, OptOutTokenIdentityForPhone); - - assertEquals("success", json.getString("status")); - - JsonObject body = json.getJsonObject("body"); - assertNotNull(body); - - decodeV2RefreshToken(json); - - AdvertisingToken advertisingToken = validateAndGetToken(encoder, body, identityType); - RefreshToken refreshToken = encoder.decodeRefreshToken(body.getString("decrypted_refresh_token")); - final byte[] advertisingId = getAdvertisingIdFromIdentity(identityType, - optOutTokenInput.getNormalized(), - firstLevelSalt, - rotatingSalt123.currentSalt()); - final byte[] firstLevelHash = TokenUtils.getFirstLevelHashFromIdentity(optOutTokenInput.getNormalized(), firstLevelSalt); - assertArrayEquals(advertisingId, advertisingToken.userIdentity.id); - assertArrayEquals(firstLevelHash, refreshToken.userIdentity.id); - - assertFalse(PrivacyBits.fromInt(advertisingToken.userIdentity.privacyBits).isClientSideTokenGenerated()); - assertTrue(PrivacyBits.fromInt(advertisingToken.userIdentity.privacyBits).isClientSideTokenOptedOut()); - - assertTokenStatusMetrics( - 201, - TokenResponseStatsCollector.Endpoint.GenerateV2, - TokenResponseStatsCollector.ResponseStatus.Success, - TokenResponseStatsCollector.PlatformType.Other); - - sendTokenRefresh(vertx, testContext, body.getString("refresh_token"), body.getString("refresh_response_key"), 200, refreshRespJson -> { - assertEquals("optout", refreshRespJson.getString("status")); - JsonObject refreshBody = refreshRespJson.getJsonObject("body"); - assertNull(refreshBody); - assertTokenStatusMetrics( - 201, - TokenResponseStatsCollector.Endpoint.RefreshV2, - TokenResponseStatsCollector.ResponseStatus.OptOut, - TokenResponseStatsCollector.PlatformType.InApp); - testContext.completeNow(); - }, Map.of(ClientVersionHeader, tvosClientVersionHeaderValue)); - }); - } - - @ParameterizedTest // TODO: remove test after optout check phase 3 - @CsvSource({ - "policy,someoptout@example.com,Email", - "policy,+01234567890,Phone", - "optout_check,someoptout@example.com,Email", - "optout_check,+01234567890,Phone" - }) - void tokenGenerateOptOutTokenWithDisableOptoutTokenFF(String policyParameterKey, String identity, IdentityType identityType, - Vertx vertx, VertxTestContext testContext) { - ClientKey oldClientKey = new ClientKey( - null, - null, - Utils.toBase64String(clientSecret), - "test-contact", - newClientCreationDateTime.minusSeconds(5), - Set.of(Role.GENERATOR), - 201, - null - ); - when(clientKeyProvider.get(any())).thenReturn(oldClientKey); - when(clientKeyProvider.getClientKey(any())).thenReturn(oldClientKey); - when(clientKeyProvider.getOldestClientKey(201)).thenReturn(oldClientKey); - when(this.optOutStore.getLatestEntry(any())).thenReturn(Instant.now()); - setupSalts(); - setupKeys(); - - JsonObject v2Payload = new JsonObject(); - v2Payload.put(identityType.name().toLowerCase(), identity); - v2Payload.put(policyParameterKey, OptoutCheckPolicy.DoNotRespect.policy); - - sendTokenGenerate(vertx, - v2Payload, 200, - json -> { - assertEquals("optout", json.getString("status")); - - decodeV2RefreshToken(json); - - assertTokenStatusMetrics( - 201, - TokenResponseStatsCollector.Endpoint.GenerateV2, - TokenResponseStatsCollector.ResponseStatus.OptOut, - TokenResponseStatsCollector.PlatformType.Other); - - testContext.completeNow(); - }); - } - @ParameterizedTest @CsvSource({ "true,text/plain", From d8c09fc7c3247736fc340ba33fcf7ec534e5fe68 Mon Sep 17 00:00:00 2001 From: Samin Rahman Date: Mon, 19 Jan 2026 10:47:49 +1100 Subject: [PATCH 5/6] Removed OptoutCheckPolicy, its references and modified related tests --- .../uid2/operator/model/IdentityRequest.java | 7 - .../com/uid2/operator/model/MapRequest.java | 7 - .../operator/model/OptoutCheckPolicy.java | 27 -- .../operator/service/UIDOperatorService.java | 4 +- .../operator/vertx/UIDOperatorVerticle.java | 5 - .../uid2/operator/UIDOperatorServiceTest.java | 147 ++-------- .../operator/UIDOperatorVerticleTest.java | 276 +----------------- .../benchmark/IdentityMapBenchmark.java | 2 +- .../benchmark/TokenEndecBenchmark.java | 2 - 9 files changed, 37 insertions(+), 440 deletions(-) delete mode 100644 src/main/java/com/uid2/operator/model/OptoutCheckPolicy.java diff --git a/src/main/java/com/uid2/operator/model/IdentityRequest.java b/src/main/java/com/uid2/operator/model/IdentityRequest.java index 4a91f1e55..2bf2ee8b1 100644 --- a/src/main/java/com/uid2/operator/model/IdentityRequest.java +++ b/src/main/java/com/uid2/operator/model/IdentityRequest.java @@ -3,21 +3,14 @@ public final class IdentityRequest { public final PublisherIdentity publisherIdentity; public final UserIdentity userIdentity; - public final OptoutCheckPolicy optoutCheckPolicy; public final IdentityEnvironment identityEnvironment; public IdentityRequest( PublisherIdentity publisherIdentity, UserIdentity userIdentity, - OptoutCheckPolicy tokenGeneratePolicy, IdentityEnvironment identityEnvironment) { this.publisherIdentity = publisherIdentity; this.userIdentity = userIdentity; - this.optoutCheckPolicy = tokenGeneratePolicy; this.identityEnvironment = identityEnvironment; } - - public boolean shouldCheckOptOut() { - return optoutCheckPolicy.equals(OptoutCheckPolicy.RespectOptOut); - } } diff --git a/src/main/java/com/uid2/operator/model/MapRequest.java b/src/main/java/com/uid2/operator/model/MapRequest.java index 22debc6b9..1d70c7ba3 100644 --- a/src/main/java/com/uid2/operator/model/MapRequest.java +++ b/src/main/java/com/uid2/operator/model/MapRequest.java @@ -4,22 +4,15 @@ public final class MapRequest { public final UserIdentity userIdentity; - public final OptoutCheckPolicy optoutCheckPolicy; public final Instant asOf; public final IdentityEnvironment identityEnvironment; public MapRequest( UserIdentity userIdentity, - OptoutCheckPolicy optoutCheckPolicy, Instant asOf, IdentityEnvironment identityEnvironment) { this.userIdentity = userIdentity; - this.optoutCheckPolicy = optoutCheckPolicy; this.asOf = asOf; this.identityEnvironment = identityEnvironment; } - - public boolean shouldCheckOptOut() { - return optoutCheckPolicy.equals(OptoutCheckPolicy.RespectOptOut); - } } diff --git a/src/main/java/com/uid2/operator/model/OptoutCheckPolicy.java b/src/main/java/com/uid2/operator/model/OptoutCheckPolicy.java deleted file mode 100644 index 524b1619d..000000000 --- a/src/main/java/com/uid2/operator/model/OptoutCheckPolicy.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.uid2.operator.model; - -import com.uid2.operator.vertx.ClientInputValidationException; - -public enum OptoutCheckPolicy { - DoNotRespect(0), - RespectOptOut(1); - - public final int policy; - OptoutCheckPolicy(int policy) { this.policy = policy; } - - public static OptoutCheckPolicy fromValue(int value) { - switch (value) { - case 0: return DoNotRespect; - case 1: return RespectOptOut; - default: throw new ClientInputValidationException("Invalid value for OptoutCheckPolicy: " + value); - } - } - - public static OptoutCheckPolicy defaultPolicy() { - return DoNotRespect; - } - - public static OptoutCheckPolicy respectOptOut() { - return RespectOptOut; - } -} diff --git a/src/main/java/com/uid2/operator/service/UIDOperatorService.java b/src/main/java/com/uid2/operator/service/UIDOperatorService.java index e06cf5bb1..9662dc59d 100644 --- a/src/main/java/com/uid2/operator/service/UIDOperatorService.java +++ b/src/main/java/com/uid2/operator/service/UIDOperatorService.java @@ -102,7 +102,7 @@ public IdentityTokens generateIdentity(IdentityRequest request, Duration refresh request.userIdentity.identityScope, request.userIdentity.identityType, firstLevelHash, request.userIdentity.privacyBits, request.userIdentity.establishedAt, request.userIdentity.refreshedAt); - if (request.shouldCheckOptOut() && getGlobalOptOutResult(firstLevelHashIdentity, false).isOptedOut()) { + if (getGlobalOptOutResult(firstLevelHashIdentity, false).isOptedOut()) { return IdentityTokens.LogoutToken; } else { return this.generateIdentity(request.publisherIdentity, firstLevelHashIdentity, refreshIdentityAfter, refreshExpiresAfter, identityExpiresAfter, request.identityEnvironment); @@ -153,7 +153,7 @@ public RefreshResponse refreshIdentity(RefreshToken token, Duration refreshIdent @Override public MappedIdentity mapIdentity(MapRequest request) { final UserIdentity firstLevelHashIdentity = getFirstLevelHashIdentity(request.userIdentity, request.asOf); - if (request.shouldCheckOptOut() && getGlobalOptOutResult(firstLevelHashIdentity, false).isOptedOut()) { + if (getGlobalOptOutResult(firstLevelHashIdentity, false).isOptedOut()) { return MappedIdentity.LogoutIdentity; } else { return getMappedIdentity(firstLevelHashIdentity, request.asOf, request.identityEnvironment); diff --git a/src/main/java/com/uid2/operator/vertx/UIDOperatorVerticle.java b/src/main/java/com/uid2/operator/vertx/UIDOperatorVerticle.java index 41d44d0ff..539365919 100644 --- a/src/main/java/com/uid2/operator/vertx/UIDOperatorVerticle.java +++ b/src/main/java/com/uid2/operator/vertx/UIDOperatorVerticle.java @@ -111,7 +111,6 @@ public class UIDOperatorVerticle extends AbstractVerticle { private final Map _identityMapMetricSummaries = new HashMap<>(); private final Map, DistributionSummary> _refreshDurationMetricSummaries = new HashMap<>(); private final Map, Counter> _advertisingTokenExpiryStatus = new HashMap<>(); - private final Map, Counter> _tokenGeneratePolicyCounters = new HashMap<>(); private final Map _tokenGenerateTCFUsage = new HashMap<>(); private final Map> _identityMapUnmappedIdentifiers = new HashMap<>(); private final Map _identityMapRequestWithUnmapped = new HashMap<>(); @@ -486,7 +485,6 @@ private void handleClientSideTokenGenerateImpl(RoutingContext rc) throws NoSuchA new IdentityRequest( new PublisherIdentity(clientSideKeypair.getSiteId(), 0, 0), input.toUserIdentity(this.identityScope, privacyBits.getAsInt(), Instant.now()), - OptoutCheckPolicy.RespectOptOut, identityEnvironment ), refreshIdentityAfter, @@ -947,7 +945,6 @@ private void handleTokenGenerateV2(RoutingContext rc) { new IdentityRequest( new PublisherIdentity(siteId, 0, 0), input.toUserIdentity(this.identityScope, 1, Instant.now()), - OptoutCheckPolicy.respectOptOut(), identityEnvironment), refreshIdentityAfter, refreshExpiresAfter, @@ -1099,7 +1096,6 @@ private JsonObject handleIdentityMapCommon(RoutingContext rc, InputUtil.InputVal final MappedIdentity mappedIdentity = idService.mapIdentity( new MapRequest( input.toUserIdentity(this.identityScope, 0, now), - OptoutCheckPolicy.respectOptOut(), now, env)); @@ -1154,7 +1150,6 @@ private JsonObject processIdentityMapV3Response(RoutingContext rc, Map { - assertTrue(respJson.containsKey("body")); - assertFalse(respJson.containsKey("client_error")); - JsonArray unmappedArr = respJson.getJsonObject("body").getJsonArray("unmapped"); - Assertions.assertEquals(1, unmappedArr.size()); - Assertions.assertEquals(emails.getString(0), unmappedArr.getJsonObject(0).getString("identifier")); - Assertions.assertEquals("optout", unmappedArr.getJsonObject(0).getString("reason")); - testContext.completeNow(); - }); - } - - @Deprecated // We don't need a test for different behavior of new vs legacy participants - @Test - void identityMapNewClientNoPolicySpecifiedOlderKeySuccessful(Vertx vertx, VertxTestContext testContext) { - ClientKey newClientKey = new ClientKey( - null, - null, - Utils.toBase64String(clientSecret), - "test-contact", - newClientCreationDateTime, - Set.of(Role.MAPPER), - 201, - null - ); - ClientKey oldClientKey = new ClientKey( - null, - null, - Utils.toBase64String(clientSecret), - "test-contact", - newClientCreationDateTime.minusSeconds(5), - Set.of(Role.MAPPER), - 201, - null - ); - when(clientKeyProvider.get(any())).thenReturn(newClientKey); - when(clientKeyProvider.getClientKey(any())).thenReturn(newClientKey); - when(clientKeyProvider.getOldestClientKey(201)).thenReturn(oldClientKey); - setupSalts(); - setupKeys(); - - JsonObject req = new JsonObject(); - JsonArray emails = new JsonArray(); - req.put("email", emails); - emails.add("test1@uid2.com"); - // policy parameter not passed but will still succeed as old participant - - send(vertx, "v2/identity/map", req, 200, respJson -> { - assertTrue(respJson.containsKey("body")); - assertEquals("success", respJson.getString("status")); - testContext.completeNow(); - }); - } - - @Deprecated // We don't need a test for different behavior of new vs legacy participants - @ParameterizedTest - @ValueSource(strings = {"policy", "optout_check"}) - void identityMapNewClientWrongPolicySpecifiedOlderKeySuccessful(String policyParameterKey, Vertx vertx, VertxTestContext testContext) { - ClientKey newClientKey = new ClientKey( - null, - null, - Utils.toBase64String(clientSecret), - "test-contact", - newClientCreationDateTime, - Set.of(Role.MAPPER), - 201, - null - ); - ClientKey oldClientKey = new ClientKey( - null, - null, - Utils.toBase64String(clientSecret), - "test-contact", - newClientCreationDateTime.minusSeconds(5), - Set.of(Role.MAPPER), - 201, - null - ); - when(clientKeyProvider.get(any())).thenReturn(newClientKey); - when(clientKeyProvider.getClientKey(any())).thenReturn(newClientKey); - when(clientKeyProvider.getOldestClientKey(201)).thenReturn(oldClientKey); - setupSalts(); - setupKeys(); - - JsonObject req = new JsonObject(); - JsonArray emails = new JsonArray(); - req.put("email", emails); - req.put(policyParameterKey, OptoutCheckPolicy.DoNotRespect.policy); - - emails.add("test1@uid2.com"); - - send(vertx, "v2/identity/map", req, 200, respJson -> { - assertTrue(respJson.containsKey("body")); - assertEquals("success", respJson.getString("status")); - testContext.completeNow(); - }); - } @ParameterizedTest @CsvSource({ @@ -1360,87 +1247,7 @@ void v3IdentityMapOutdatedRefreshFrom(Vertx vertx, VertxTestContext testContext) }); } - @Test - void tokenGenerateNewClientNoPolicySpecifiedOlderKeySuccessful(Vertx vertx, VertxTestContext testContext) { - ClientKey newClientKey = new ClientKey( - null, - null, - Utils.toBase64String(clientSecret), - "test-contact", - newClientCreationDateTime, - Set.of(Role.GENERATOR), - 201, - null - ); - ClientKey oldClientKey = new ClientKey( - null, - null, - Utils.toBase64String(clientSecret), - "test-contact", - newClientCreationDateTime.minusSeconds(5), - Set.of(Role.GENERATOR), - 201, - null - ); - when(clientKeyProvider.get(any())).thenReturn(newClientKey); - when(clientKeyProvider.getClientKey(any())).thenReturn(newClientKey); - when(clientKeyProvider.getOldestClientKey(201)).thenReturn(oldClientKey); - setupSalts(); - setupKeys(); - - JsonObject v2Payload = new JsonObject(); - v2Payload.put("email", "test@email.com"); - - sendTokenGenerate(vertx, - v2Payload, 200, - json -> { - assertTrue(json.containsKey("body")); - assertEquals("success", json.getString("status")); - testContext.completeNow(); - }); - } - - @ParameterizedTest - @ValueSource(strings = {"policy", "optout_check"}) - void tokenGenerateNewClientWrongPolicySpecifiedOlderKeySuccessful(String policyParameterKey, Vertx vertx, VertxTestContext testContext) { - ClientKey newClientKey = new ClientKey( - null, - null, - Utils.toBase64String(clientSecret), - "test-contact", - newClientCreationDateTime, - Set.of(Role.GENERATOR), - 201, - null - ); - ClientKey oldClientKey = new ClientKey( - null, - null, - Utils.toBase64String(clientSecret), - "test-contact", - newClientCreationDateTime.minusSeconds(5), - Set.of(Role.GENERATOR), - 201, - null - ); - when(clientKeyProvider.get(any())).thenReturn(newClientKey); - when(clientKeyProvider.getClientKey(any())).thenReturn(newClientKey); - when(clientKeyProvider.getOldestClientKey(201)).thenReturn(oldClientKey); - setupSalts(); - setupKeys(); - - JsonObject v2Payload = new JsonObject(); - v2Payload.put("email", "test@email.com"); - v2Payload.put(policyParameterKey, OptoutCheckPolicy.DoNotRespect.policy); - - sendTokenGenerate(vertx, - v2Payload, 200, - json -> { - assertTrue(json.containsKey("body")); - assertEquals("success", json.getString("status")); - testContext.completeNow(); - }); - } + @ParameterizedTest @CsvSource({ @@ -1676,7 +1483,6 @@ void tokenGenerateThenRefreshNoActiveKey(Vertx vertx, VertxTestContext testConte JsonObject v2Payload = new JsonObject(); v2Payload.put("email", "test@email.com"); - v2Payload.put("optout_check", 1); sendTokenGenerate(vertx, v2Payload, 200, @@ -1895,7 +1701,6 @@ void tokenGenerateNoActiveKey(Vertx vertx, VertxTestContext testContext) { JsonObject v2Payload = new JsonObject(); v2Payload.put("email", "test@email.com"); - v2Payload.put("optout_check", 1); sendTokenGenerate(vertx, v2Payload, 500, @@ -3085,43 +2890,6 @@ void identityMapBatchRequestTooLargeForPhone(Vertx vertx, VertxTestContext testC send(vertx, "v2/identity/map", req, 413, json -> testContext.completeNow()); } - @ParameterizedTest - @CsvSource({ - "true,policy", - "true,optout_check", - - "false,policy", - "false,optout_check" - }) - void tokenGenerateRespectOptOutOption(boolean useV4Uid, String policyParameterKey, Vertx vertx, VertxTestContext testContext) { - final int clientSiteId = 201; - fakeAuth(clientSiteId, Role.GENERATOR); - setupKeys(); - setupSalts(useV4Uid); - - // the clock value shouldn't matter here - when(optOutStore.getLatestEntry(any(UserIdentity.class))) - .thenReturn(now.minus(1, ChronoUnit.HOURS)); - - JsonObject req = new JsonObject(); - req.put("email", "random-optout-user@email.io"); - req.put(policyParameterKey, 1); - - // for EUID - addAdditionalTokenGenerateParams(req); - - send(vertx, "v2/token/generate", req, 200, json -> { - try { - Assertions.assertEquals(ResponseUtil.ResponseStatus.OptOut, json.getString("status")); - Assertions.assertNull(json.getJsonObject("body")); - assertTokenStatusMetrics(clientSiteId, TokenResponseStatsCollector.Endpoint.GenerateV2, TokenResponseStatsCollector.ResponseStatus.OptOut, TokenResponseStatsCollector.PlatformType.Other); - testContext.completeNow(); - } catch (Exception e) { - testContext.failNow(e); - } - }); - } - @ParameterizedTest @ValueSource(booleans = {true, false}) void identityMapOptoutDefaultOption(boolean useV4Uid, Vertx vertx, VertxTestContext testContext) { @@ -3154,43 +2922,6 @@ void identityMapOptoutDefaultOption(boolean useV4Uid, Vertx vertx, VertxTestCont }); } - @ParameterizedTest - @CsvSource({ - "true,policy", - "true,optout_check", - - "false,policy", - "false,optout_check" - }) - void identityMapRespectOptOutOption(boolean useV4Uid, String policyParameterKey, Vertx vertx, VertxTestContext testContext) { - final int clientSiteId = 201; - fakeAuth(clientSiteId, Role.MAPPER); - setupKeys(); - setupSalts(useV4Uid); - - // the clock value shouldn't matter here - when(optOutStore.getLatestEntry(any(UserIdentity.class))) - .thenReturn(now.minus(1, ChronoUnit.HOURS)); - - JsonObject req = new JsonObject(); - JsonArray emails = new JsonArray(); - emails.add("random-optout-user@email.io"); - req.put("email", emails); - req.put(policyParameterKey, 1); - - send(vertx, "v2/identity/map", req, 200, json -> { - try { - Assertions.assertTrue(json.getJsonObject("body").getJsonArray("mapped").isEmpty()); - Assertions.assertEquals(1, json.getJsonObject("body").getJsonArray("unmapped").size()); - Assertions.assertEquals("random-optout-user@email.io", json.getJsonObject("body").getJsonArray("unmapped").getJsonObject(0).getString("identifier")); - Assertions.assertEquals("optout", json.getJsonObject("body").getJsonArray("unmapped").getJsonObject(0).getString("reason")); - testContext.completeNow(); - } catch (Exception e) { - testContext.failNow(e); - } - }); - } - @Test void requestWithoutClientKeyOrReferer(Vertx vertx, VertxTestContext testContext) { final String emailAddress = "test@uid2.com"; @@ -4291,8 +4022,7 @@ void cstgInvalidInput(String identityType, String rawUID, Vertx vertx, VertxTest setupKeys(true); JsonObject identity = new JsonObject(); - identity.put(identityType, getSha256(rawUID) + getSha256(rawUID)); - identity.put("optout_check", 1); + identity.put(identityType, getSha256(rawUID) + getSha256(rawUID)); Tuple.Tuple2 data = createClientSideTokenGenerateRequestWithPayload(identity, Instant.now().toEpochMilli(), null); sendCstg(vertx, diff --git a/src/test/java/com/uid2/operator/benchmark/IdentityMapBenchmark.java b/src/test/java/com/uid2/operator/benchmark/IdentityMapBenchmark.java index a897755d9..185bc8a53 100644 --- a/src/test/java/com/uid2/operator/benchmark/IdentityMapBenchmark.java +++ b/src/test/java/com/uid2/operator/benchmark/IdentityMapBenchmark.java @@ -127,7 +127,7 @@ public MappedIdentity IdentityMapRawThroughput() { @BenchmarkMode(Mode.Throughput) public MappedIdentity IdentityMapWithOptOutThroughput() { return uidService.mapIdentity( - new MapRequest(userIdentities[(idx++) & 65535], OptoutCheckPolicy.RespectOptOut, Instant.now(), IdentityEnvironment.TEST) + new MapRequest(userIdentities[(idx++) & 65535], Instant.now(), IdentityEnvironment.TEST) ); } diff --git a/src/test/java/com/uid2/operator/benchmark/TokenEndecBenchmark.java b/src/test/java/com/uid2/operator/benchmark/TokenEndecBenchmark.java index 2733d9cf3..e3e37b1a2 100644 --- a/src/test/java/com/uid2/operator/benchmark/TokenEndecBenchmark.java +++ b/src/test/java/com/uid2/operator/benchmark/TokenEndecBenchmark.java @@ -43,7 +43,6 @@ static IdentityTokens[] createAdvertisingTokens() { new IdentityRequest( publisher, userIdentities[i], - OptoutCheckPolicy.DoNotRespect, IdentityEnvironment.TEST), Duration.ofSeconds(BenchmarkCommon.REFRESH_IDENTITY_TOKEN_AFTER_SECONDS), Duration.ofSeconds(BenchmarkCommon.REFRESH_TOKEN_EXPIRES_AFTER_SECONDS), @@ -59,7 +58,6 @@ public IdentityTokens TokenGenerationBenchmark() { return uidService.generateIdentity(new IdentityRequest( publisher, userIdentities[(idx++) & 65535], - OptoutCheckPolicy.DoNotRespect, IdentityEnvironment.TEST), Duration.ofSeconds(BenchmarkCommon.REFRESH_IDENTITY_TOKEN_AFTER_SECONDS), Duration.ofSeconds(BenchmarkCommon.REFRESH_TOKEN_EXPIRES_AFTER_SECONDS), From e7bac4dca0c166e37868749c40ad93dbffbd5cf5 Mon Sep 17 00:00:00 2001 From: Samin Rahman Date: Tue, 20 Jan 2026 11:38:41 +1100 Subject: [PATCH 6/6] Removed reference to getOldestClientKey --- src/test/java/com/uid2/operator/UIDOperatorVerticleTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test/java/com/uid2/operator/UIDOperatorVerticleTest.java b/src/test/java/com/uid2/operator/UIDOperatorVerticleTest.java index 8f2214498..d5590329c 100644 --- a/src/test/java/com/uid2/operator/UIDOperatorVerticleTest.java +++ b/src/test/java/com/uid2/operator/UIDOperatorVerticleTest.java @@ -221,7 +221,6 @@ protected void fakeAuth(int siteId, Instant created, Role... roles) { ); when(clientKeyProvider.get(any())).thenReturn(clientKey); when(clientKeyProvider.getClientKey(any())).thenReturn(clientKey); - when(clientKeyProvider.getOldestClientKey(anyInt())).thenReturn(clientKey); } private void clearAuth() {