diff --git a/.github/workflows/publish-e2e-test-suites-docker-image.yaml b/.github/workflows/publish-e2e-test-suites-docker-image.yaml
index 76d0d0d..782e6c9 100644
--- a/.github/workflows/publish-e2e-test-suites-docker-image.yaml
+++ b/.github/workflows/publish-e2e-test-suites-docker-image.yaml
@@ -1,11 +1,11 @@
-name: Publish E2E Test Suites
-run-name: ${{ format('Publish E2E Test Suites{0} {1} Release', ':', inputs.release_type) }}
+name: Release UID2 E2E Image
+run-name: ${{ inputs.release_type == 'Snapshot' && 'Publish Pre-release' || format('Release {0}', inputs.release_type)}} Docker Image by @${{ github.actor }}
on:
workflow_dispatch:
inputs:
release_type:
type: choice
- description: 'The type of release'
+ description: The type of release
options:
- Snapshot
- Patch
@@ -15,6 +15,13 @@ on:
description: If set, the version number will not be incremented and the given number will be used.
type: string
default: ''
+ vulnerability_severity:
+ description: The severity to fail the workflow if such vulnerability is detected. DO NOT override it unless a Jira ticket is raised.
+ type: choice
+ options:
+ - CRITICAL,HIGH
+ - CRITICAL,HIGH,MEDIUM
+ - CRITICAL (DO NOT use if JIRA ticket not raised)
jobs:
Image:
@@ -22,7 +29,7 @@ jobs:
with:
release_type: ${{ inputs.release_type }}
version_number_input: ${{ inputs.version_number_input }}
- java_version: '21'
- force_release: 'yes'
+ vulnerability_severity: ${{ inputs.vulnerability_severity }}
+ java_version: 21
skip_tests: true
secrets: inherit
diff --git a/Dockerfile b/Dockerfile
index 4df4d39..7f0e319 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -11,42 +11,35 @@ COPY ./src ./src
######################
# Configure env vars #
######################
-ENV UID2_E2E_ENV "github-test-pipeline"
-
-ENV UID2_E2E_SITE_ID ""
-ENV UID2_E2E_API_KEY ""
-ENV UID2_E2E_API_SECRET ""
-ENV UID2_E2E_API_KEY_OLD ""
-ENV UID2_E2E_API_SECRET_OLD ""
-ENV UID2_E2E_API_KEY_SHARING_RECIPIENT ""
-ENV UID2_E2E_API_SECRET_SHARING_RECIPIENT ""
-ENV UID2_E2E_API_KEY_NON_SHARING_RECIPIENT ""
-ENV UID2_E2E_API_SECRET_NON_SHARING_RECIPIENT ""
-ENV UID2_E2E_SUBSCRIPTION_ID ""
-ENV UID2_E2E_SERVER_PUBLIC_KEY ""
-ENV UID2_E2E_ORIGIN ""
-ENV UID2_E2E_INVALID_ORIGIN ""
-
-ENV UID2_E2E_IDENTITY_SCOPE ""
-ENV UID2_E2E_PHONE_SUPPORT ""
-
-ENV UID2_E2E_PIPELINE_OPERATOR_URL ""
-ENV UID2_E2E_PIPELINE_OPERATOR_TYPE ""
-ENV UID2_E2E_PIPELINE_OPERATOR_CLOUD_PROVIDER ""
-
-ENV UID2_E2E_CORE_API_TOKEN ""
-ENV UID2_E2E_OPTOUT_TO_CALL_CORE_API_TOKEN ""
-ENV UID2_E2E_CORE_URL ""
-ENV UID2_E2E_OPTOUT_URL ""
-
-CMD \
- if [ "$UID2_E2E_PIPELINE_OPERATOR_TYPE" != "PUBLIC" ] && [ "$UID2_E2E_PIPELINE_OPERATOR_TYPE" != "PRIVATE" ] ; \
- then \
- echo "ERROR: Incorrect operator type: $UID2_E2E_PIPELINE_OPERATOR_TYPE. Exiting." ; \
- exit 1 ; \
- elif [ "$UID2_E2E_PIPELINE_OPERATOR_TYPE" = "PUBLIC" ] ; \
- then \
- mvn test -Dtest="E2EPublicOperatorTestSuite" ; \
- else \
- mvn test -Dtest="E2EPrivateOperatorTestSuite" ; \
- fi
\ No newline at end of file
+ENV E2E_SUITES ""
+ENV E2E_ARGS_JSON ""
+
+ENV E2E_ENV ""
+ENV E2E_IDENTITY_SCOPE ""
+ENV E2E_PHONE_SUPPORT ""
+
+ENV UID2_CORE_E2E_OPERATOR_API_KEY ""
+ENV UID2_CORE_E2E_OPTOUT_API_KEY ""
+ENV UID2_CORE_E2E_CORE_URL ""
+ENV UID2_CORE_E2E_OPTOUT_URL ""
+
+ENV UID2_OPERATOR_E2E_CLIENT_SITE_ID ""
+ENV UID2_OPERATOR_E2E_CLIENT_API_KEY ""
+ENV UID2_OPERATOR_E2E_CLIENT_API_SECRET ""
+ENV UID2_OPERATOR_E2E_CLIENT_API_KEY_BEFORE_OPTOUT_CUTOFF ""
+ENV UID2_OPERATOR_E2E_CLIENT_API_SECRET_BEFORE_OPTOUT_CUTOFF ""
+ENV UID2_OPERATOR_E2E_CLIENT_API_KEY_SHARING_RECIPIENT ""
+ENV UID2_OPERATOR_E2E_CLIENT_API_SECRET_SHARING_RECIPIENT ""
+ENV UID2_OPERATOR_E2E_CLIENT_API_KEY_NON_SHARING_RECIPIENT ""
+ENV UID2_OPERATOR_E2E_CLIENT_API_SECRET_NON_SHARING_RECIPIENT ""
+ENV UID2_OPERATOR_E2E_CSTG_SUBSCRIPTION_ID ""
+ENV UID2_OPERATOR_E2E_CSTG_SERVER_PUBLIC_KEY ""
+ENV UID2_OPERATOR_E2E_CSTG_ORIGIN ""
+ENV UID2_OPERATOR_E2E_CSTG_INVALID_ORIGIN ""
+
+ENV UID2_PIPELINE_E2E_CORE_URL ""
+ENV UID2_PIPELINE_E2E_OPERATOR_URL ""
+ENV UID2_PIPELINE_E2E_OPERATOR_TYPE ""
+ENV UID2_PIPELINE_E2E_OPERATOR_CLOUD_PROVIDER ""
+
+CMD mvn test -Dtest="${E2E_SUITES}"
diff --git a/README.md b/README.md
index fa1d372..065e8f5 100644
--- a/README.md
+++ b/README.md
@@ -8,16 +8,68 @@ Any changes to [uid2-operator](https://github.com/IABTechLab/uid2-operator) need
There are different test suites that can be run depending on the environment and operator type:
-| Test Suite | Description |
-|---------------------------------------|--------------------------------------------------------------|
-| `E2ELocalFullTestSuite` | Used when running both public and private operators locally. |
-| `E2EPipelinePrivateOperatorTestSuite` | Used when testing private operators in a pipeline. |
-| `E2EPipelinePublicOperatorTestSuite` | Used when testing public operators in a pipeline. |
-| `E2EPrivateOperatorTestSuite` | Used when testing real private operators. |
-| `E2EPublicOperatorTestSuite` | Used when testing real public operators. |
+| Test Suite | Description |
+|-------------------------------|-------------------------------------|
+| `E2ELocalFullTestSuite` | Used to test all apps locally |
+| `E2ECoreTestSuite` | Used when testing Core |
+| `E2EPublicOperatorTestSuite` | Used when testing public Operators |
+| `E2EPrivateOperatorTestSuite` | Used when testing private Operators |
+
+## Environment Variables
+
+* `E2E_SUITES` - **Docker image only** - The test suites to run, comma separated
+ * e.g. `E2EPrivateOperatorTestSuite,E2ECoreTestSuite`
+* `E2E_ARGS_JSON` - The below environment variables can be put into this environment variable as a JSON
+ * Any environment variables declared explicitly will override args in `E2E_ARGS_JSON`
+
+### General
+
+| Name | Value |
+|----------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------|
+| `E2E_ENV` | The E2E environment - this determines which apps get instantiated
Certain tests run for `local` environments only
Check `AppsMap` for details |
+| `E2E_IDENTITY_SCOPE` | The identity scope - one of [UID2, EUID] |
+| `E2E_PHONE_SUPPORT` | True if APIs support phone numbers, false otherwise |
+
+### Core
+
+| Name | Value |
+|----------------------------------|------------------------------------------------------|
+| `UID2_CORE_E2E_OPERATOR_API_KEY` | The API key for an Operator to communicate with Core |
+| `UID2_CORE_E2E_OPTOUT_API_KEY` | The API key for Optout to communicate with Core |
+| `UID2_CORE_E2E_CORE_URL` | The Core URL to include in attestation requests |
+| `UID2_CORE_E2E_OPTOUT_URL` | The Optout URL to include in attestation requests |
+
+### Operator
+
+| Name | Value |
+|-------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------|
+| `UID2_OPERATOR_E2E_CLIENT_SITE_ID` | The site ID of the client communicating with Operator |
+| `UID2_OPERATOR_E2E_CLIENT_API_KEY` | The API key for a client to communicate with Operator |
+| `UID2_OPERATOR_E2E_CLIENT_API_SECRET` | The API secret for a client to communicate with Operator |
+| `UID2_OPERATOR_E2E_CLIENT_API_KEY_BEFORE_OPTOUT_CUTOFF` | **Optout cutoff tests** - The API key before the optout policy cutoff for a client to communicate with Operator |
+| `UID2_OPERATOR_E2E_CLIENT_API_SECRET_BEFORE_OPTOUT_CUTOFF` | **Optout cutoff tests** - The API secret before the optout policy cutoff for a client to communicate with Operator |
+| `UID2_OPERATOR_E2E_CLIENT_API_KEY_SHARING_RECIPIENT` | **Sharing tests** - The API key with SHARER role for a client to communicate with Operator |
+| `UID2_OPERATOR_E2E_CLIENT_API_SECRET_SHARING_RECIPIENT` | **Sharing tests** - The API with SHARER role secret for a client to communicate with Operator |
+| `UID2_OPERATOR_E2E_CLIENT_API_KEY_NON_SHARING_RECIPIENT` | **Sharing tests** - The API key without SHARER role for a client to communicate with Operator |
+| `UID2_OPERATOR_E2E_CLIENT_API_SECRET_NON_SHARING_RECIPIENT` | **Sharing tests** - The API without SHARER role secret for a client to communicate with Operator |
+| `UID2_OPERATOR_E2E_CSTG_SUBSCRIPTION_ID` | **CSTG tests** - The subscription ID |
+| `UID2_OPERATOR_E2E_CSTG_SERVER_PUBLIC_KEY` | **CSTG tests** - The server public key |
+| `UID2_OPERATOR_E2E_CSTG_ORIGIN` | **CSTG tests** - A valid origin |
+| `UID2_OPERATOR_E2E_CSTG_INVALID_ORIGIN` | **CSTG tests** - An invalid origin |
+
+### Pipeline
+
+| Name | Value |
+|---------------------------------------------|---------------------------------------------------------------------------------------------------------------|
+| `UID2_PIPELINE_E2E_CORE_URL` | The Core URL |
+| `UID2_PIPELINE_E2E_OPERATOR_URL` | The Operator URL |
+| `UID2_PIPELINE_E2E_OPERATOR_TYPE` | The type of Operator - one of [PUBLIC, PRIVATE] |
+| `UID2_PIPELINE_E2E_OPERATOR_CLOUD_PROVIDER` | Empty for public Operators, the cloud provider for private Operators - one of [aws-nitro, gcp-oidc, azure-cc] |
## Running the Dockerfile
-`docker build -f Dockerfile -t uid2-e2e . && docker run --env = ... uid2-e2e`
-* Set each environment variable specified in the Dockerfile as `--env =`
+```shell
+docker build -f Dockerfile -t uid2-e2e .
+docker run --env = ... uid2-e2e
+ ```
* If running the E2E tests against localhost, include the option `--network=host`
diff --git a/src/test/java/app/AppsMap.java b/src/test/java/app/AppsMap.java
index 58571ae..30c6306 100644
--- a/src/test/java/app/AppsMap.java
+++ b/src/test/java/app/AppsMap.java
@@ -1,6 +1,5 @@
package app;
-import common.EnvUtil;
import app.component.App;
import java.lang.reflect.InvocationTargetException;
@@ -10,8 +9,6 @@
public final class AppsMap {
private static final Map APP_MAP;
- private static final String ENV = EnvUtil.getEnv("UID2_E2E_ENV");
-
private static final Apps APPS;
static {
@@ -24,10 +21,11 @@ public final class AppsMap {
"uid2-prod", "app.Uid2ProdApps",
"euid-integ", "app.EuidIntegApps",
"euid-prod", "app.EuidProdApps",
+ "github-test-pipeline-local", "app.GitHubTestPipelineApps",
"github-test-pipeline", "app.GitHubTestPipelineApps"
);
- APPS = (Apps) Class.forName(APP_MAP.get(ENV)).getDeclaredConstructor().newInstance();
+ APPS = (Apps) Class.forName(APP_MAP.get(App.ENV)).getDeclaredConstructor().newInstance();
} catch (ClassNotFoundException | NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}
diff --git a/src/test/java/app/GitHubTestPipelineApps.java b/src/test/java/app/GitHubTestPipelineApps.java
index 816278b..46df6d4 100644
--- a/src/test/java/app/GitHubTestPipelineApps.java
+++ b/src/test/java/app/GitHubTestPipelineApps.java
@@ -1,5 +1,7 @@
package app;
+import common.Const;
+import common.EnabledCondition;
import common.EnvUtil;
import app.component.Core;
import app.component.Operator;
@@ -7,19 +9,20 @@
import java.util.Set;
public class GitHubTestPipelineApps extends Apps {
- private static final String OPERATOR_URL = EnvUtil.getEnv("UID2_E2E_PIPELINE_OPERATOR_URL");
- private static final Operator.Type OPERATOR_TYPE = Operator.Type.valueOf(EnvUtil.getEnv("UID2_E2E_PIPELINE_OPERATOR_TYPE"));
- private static final Operator.CloudProvider OPERATOR_CLOUD_PROVIDER = Operator.CloudProvider.valueOf(EnvUtil.getEnv("UID2_E2E_PIPELINE_OPERATOR_CLOUD_PROVIDER"));
+ private static final String CORE_URL = EnvUtil.getEnv(Const.Config.Pipeline.CORE_URL, EnabledCondition.isLocal());
- private static final String CORE_URL = EnvUtil.getEnv("UID2_E2E_CORE_URL");
+ private static final String OPERATOR_URL = EnvUtil.getEnv(Const.Config.Pipeline.OPERATOR_URL);
+ private static final Operator.Type OPERATOR_TYPE = Operator.Type.valueOf(EnvUtil.getEnv(Const.Config.Pipeline.OPERATOR_TYPE));
+ private static final Operator.CloudProvider OPERATOR_CLOUD_PROVIDER = Operator.CloudProvider.valueOf(EnvUtil.getEnv(Const.Config.Pipeline.OPERATOR_CLOUD_PROVIDER));
private static final String OPERATOR_NAME = OPERATOR_TYPE == Operator.Type.PUBLIC
? "GitHub Test Pipeline - Public Operator"
: "GitHub Test Pipeline - Private %s Operator".formatted(OPERATOR_CLOUD_PROVIDER.toString());
public GitHubTestPipelineApps() {
- super(Set.of(
- new Operator(OPERATOR_URL, OPERATOR_NAME, OPERATOR_TYPE),
- new Core(CORE_URL, "GitHub Test Pipeline - Core")
- ));
+ super(EnabledCondition.isLocal() ?
+ Set.of(
+ new Operator(OPERATOR_URL, OPERATOR_NAME, OPERATOR_TYPE),
+ new Core(CORE_URL, "GitHub Test Pipeline - Core")) :
+ Set.of(new Operator(OPERATOR_URL, OPERATOR_NAME, OPERATOR_TYPE)));
}
}
diff --git a/src/test/java/app/LocalApps.java b/src/test/java/app/LocalApps.java
index 9978fc7..1062daf 100644
--- a/src/test/java/app/LocalApps.java
+++ b/src/test/java/app/LocalApps.java
@@ -5,9 +5,9 @@
import java.util.Set;
public final class LocalApps extends Apps {
+ // TODO: Add optout
public LocalApps() {
super(Set.of(
- // TODO: Add optout, monitorstack
new Localstack("http://localhost", 5001, "Local - Localstack"),
new Admin("http://localhost", 8089, "Local - Admin"),
new Core("http://localhost", 8088, "Local - Core"),
diff --git a/src/test/java/app/component/App.java b/src/test/java/app/component/App.java
index b8688dd..3f552d3 100644
--- a/src/test/java/app/component/App.java
+++ b/src/test/java/app/component/App.java
@@ -1,8 +1,17 @@
package app.component;
+import com.uid2.client.IdentityScope;
+import common.Const;
+import common.EnvUtil;
import common.HttpClient;
+import lombok.Getter;
+@Getter
public abstract class App {
+ public static final String ENV = EnvUtil.getEnv(Const.Config.ENV);
+ public static final IdentityScope IDENTITY_SCOPE = IdentityScope.valueOf(EnvUtil.getEnv(Const.Config.IDENTITY_SCOPE));
+ public static final boolean PHONE_SUPPORT = Boolean.parseBoolean(EnvUtil.getEnv(Const.Config.PHONE_SUPPORT));
+
private final String host;
private final Integer port;
private final String name;
@@ -13,18 +22,6 @@ public App(String host, Integer port, String name) {
this.name = name;
}
- public String getHost() {
- return host;
- }
-
- public Integer getPort() {
- return port;
- }
-
- public String getName() {
- return name;
- }
-
public String getBaseUrl() {
return getPort() == null ? getHost() : "%s:%d".formatted(getHost(), getPort());
}
diff --git a/src/test/java/app/component/Core.java b/src/test/java/app/component/Core.java
index 1eff522..eb2299b 100644
--- a/src/test/java/app/component/Core.java
+++ b/src/test/java/app/component/Core.java
@@ -1,5 +1,6 @@
package app.component;
+import common.Const;
import common.EnvUtil;
import common.HttpClient;
import common.Mapper;
@@ -9,10 +10,10 @@
import java.util.Map;
public class Core extends App {
- private static final String CORE_API_TOKEN = EnvUtil.getEnv("UID2_E2E_CORE_API_TOKEN");
- private static final String OPTOUT_TO_CALL_CORE_API_TOKEN = EnvUtil.getEnv("UID2_E2E_OPTOUT_TO_CALL_CORE_API_TOKEN");
- public static final String CORE_URL = EnvUtil.getEnv("UID2_E2E_CORE_URL");
- public static final String OPTOUT_URL = EnvUtil.getEnv("UID2_E2E_OPTOUT_URL");
+ private static final String OPERATOR_API_KEY = EnvUtil.getEnv(Const.Config.Core.OPERATOR_API_KEY);
+ private static final String OPTOUT_API_KEY = EnvUtil.getEnv(Const.Config.Core.OPTOUT_API_KEY);
+ public static final String CORE_URL = EnvUtil.getEnv(Const.Config.Core.CORE_URL);
+ public static final String OPTOUT_URL = EnvUtil.getEnv(Const.Config.Core.OPTOUT_URL);
public Core(String host, Integer port, String name) {
super(host, port, name);
@@ -23,7 +24,7 @@ public Core(String host, String name) {
}
public JsonNode attest(String attestationRequest) throws Exception {
- String response = HttpClient.post(getBaseUrl() + "/attest", attestationRequest, CORE_API_TOKEN);
+ String response = HttpClient.post(getBaseUrl() + "/attest", attestationRequest, OPERATOR_API_KEY);
return Mapper.OBJECT_MAPPER.readTree(response);
}
@@ -35,12 +36,12 @@ public JsonNode getWithCoreApiToken(String path, boolean encrypted) throws Excep
Map headers = new HashMap<>();
if (encrypted)
headers.put("Encrypted", "true");
- String response = HttpClient.get(getBaseUrl() + path, CORE_API_TOKEN, headers);
+ String response = HttpClient.get(getBaseUrl() + path, OPERATOR_API_KEY, headers);
return Mapper.OBJECT_MAPPER.readTree(response);
}
public JsonNode getWithOptOutApiToken(String path) throws Exception {
- String response = HttpClient.get(getBaseUrl() + path, OPTOUT_TO_CALL_CORE_API_TOKEN);
+ String response = HttpClient.get(getBaseUrl() + path, OPTOUT_API_KEY);
return Mapper.OBJECT_MAPPER.readTree(response);
}
}
diff --git a/src/test/java/app/component/Operator.java b/src/test/java/app/component/Operator.java
index d7aa520..0050949 100644
--- a/src/test/java/app/component/Operator.java
+++ b/src/test/java/app/component/Operator.java
@@ -1,13 +1,12 @@
package app.component;
-import common.EnvUtil;
-import common.HttpClient;
-import common.Mapper;
import com.fasterxml.jackson.databind.JsonNode;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.uid2.client.IdentityScope;
import com.uid2.client.*;
+import common.*;
+import lombok.Getter;
import okhttp3.Request;
import okhttp3.RequestBody;
@@ -16,7 +15,6 @@
import javax.crypto.spec.SecretKeySpec;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
-import java.net.URLEncoder;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.security.*;
@@ -45,9 +43,9 @@ public String toString() {
public enum CloudProvider {
PUBLIC(""),
- AWS("AWS"),
- GCP("GCP-OIDC"),
- AZURE("Azure-CC");
+ AWS("aws-nitro"),
+ GCP("gcp-oidc"),
+ AZURE("azure-cc");
private final String name;
@@ -64,32 +62,37 @@ public String toString() {
private record V2Envelope(String envelope, byte[] nonce) {
}
- private static final SecureRandom SECURE_RANDOM = new SecureRandom();
-
// When running via the pipeline, environment variables are defined in the uid2-shared-actions repo.
// When running via IntelliJ, environment variables are defined in the uid2-dev-workspace repo under .idea/runConfigurations.
- //
// Test data is defined in the uid2-admin repo.
- public static final String CLIENT_API_KEY = EnvUtil.getEnv("UID2_E2E_API_KEY");
- public static final String CLIENT_API_SECRET = EnvUtil.getEnv("UID2_E2E_API_SECRET");
- private static final String CLIENT_API_KEY_BEFORE_OPTOUT_CUTOFF = EnvUtil.getEnv("UID2_E2E_API_KEY_OLD");
- private static final String CLIENT_API_SECRET_BEFORE_OPTOUT_CUTOFF = EnvUtil.getEnv("UID2_E2E_API_SECRET_OLD");
- public static final String CLIENT_API_KEY_SHARING_RECIPIENT = EnvUtil.getEnv("UID2_E2E_API_KEY_SHARING_RECIPIENT");
- public static final String CLIENT_API_SECRET_SHARING_RECIPIENT = EnvUtil.getEnv("UID2_E2E_API_SECRET_SHARING_RECIPIENT");
- public static final String CLIENT_API_KEY_NON_SHARING_RECIPIENT = EnvUtil.getEnv("UID2_E2E_API_KEY_NON_SHARING_RECIPIENT");
- public static final String CLIENT_API_SECRET_NON_SHARING_RECIPIENT = EnvUtil.getEnv("UID2_E2E_API_SECRET_NON_SHARING_RECIPIENT");
- private static final String CLIENT_SIDE_TOKEN_GENERATE_SUBSCRIPTION_ID = EnvUtil.getEnv("UID2_E2E_SUBSCRIPTION_ID");
- private static final String CLIENT_SIDE_TOKEN_GENERATE_SERVER_PUBLIC_KEY = EnvUtil.getEnv("UID2_E2E_SERVER_PUBLIC_KEY");
- private static final String CLIENT_SIDE_TOKEN_GENERATE_ORIGIN = EnvUtil.getEnv("UID2_E2E_ORIGIN");
- private static final String CLIENT_SIDE_TOKEN_GENERATE_INVALID_ORIGIN = EnvUtil.getEnv("UID2_E2E_INVALID_ORIGIN");
- public static final IdentityScope IDENTITY_SCOPE = IdentityScope.valueOf(EnvUtil.getEnv("UID2_E2E_IDENTITY_SCOPE"));
+ private static final SecureRandom SECURE_RANDOM = new SecureRandom();
private static final int TIMESTAMP_LENGTH = 8;
private static final int PUBLIC_KEY_PREFIX_LENGTH = 9;
private static final int AUTHENTICATION_TAG_LENGTH_BITS = 128;
private static final int IV_BYTES = 12;
private static final String TC_STRING = "CPhJRpMPhJRpMABAMBFRACBoALAAAEJAAIYgAKwAQAKgArABAAqAAA";
+ public static final String CLIENT_API_KEY = EnvUtil.getEnv(Const.Config.Operator.CLIENT_API_KEY);
+ public static final String CLIENT_API_SECRET = EnvUtil.getEnv(Const.Config.Operator.CLIENT_API_SECRET);
+
+ // Optout cutoff
+ public static final String CLIENT_API_KEY_BEFORE_OPTOUT_CUTOFF = EnvUtil.getEnv(Const.Config.Operator.CLIENT_API_KEY_BEFORE_OPTOUT_CUTOFF);
+ public static final String CLIENT_API_SECRET_BEFORE_OPTOUT_CUTOFF = EnvUtil.getEnv(Const.Config.Operator.CLIENT_API_SECRET_BEFORE_OPTOUT_CUTOFF);
+
+ // Local only - Sharing
+ public static final String CLIENT_API_KEY_SHARING_RECIPIENT = EnvUtil.getEnv(Const.Config.Operator.CLIENT_API_KEY_SHARING_RECIPIENT, EnabledCondition.isLocal());
+ public static final String CLIENT_API_SECRET_SHARING_RECIPIENT = EnvUtil.getEnv(Const.Config.Operator.CLIENT_API_SECRET_SHARING_RECIPIENT, EnabledCondition.isLocal());
+ public static final String CLIENT_API_KEY_NON_SHARING_RECIPIENT = EnvUtil.getEnv(Const.Config.Operator.CLIENT_API_KEY_NON_SHARING_RECIPIENT, EnabledCondition.isLocal());
+ public static final String CLIENT_API_SECRET_NON_SHARING_RECIPIENT = EnvUtil.getEnv(Const.Config.Operator.CLIENT_API_SECRET_NON_SHARING_RECIPIENT, EnabledCondition.isLocal());
+
+ // Local only - CSTG
+ public static final String CSTG_SUBSCRIPTION_ID = EnvUtil.getEnv(Const.Config.Operator.CSTG_SUBSCRIPTION_ID, EnabledCondition.isLocal());
+ public static final String CSTG_SERVER_PUBLIC_KEY = EnvUtil.getEnv(Const.Config.Operator.CSTG_SERVER_PUBLIC_KEY, EnabledCondition.isLocal());
+ public static final String CSTG_ORIGIN = EnvUtil.getEnv(Const.Config.Operator.CSTG_ORIGIN, EnabledCondition.isLocal());
+ public static final String CSTG_INVALID_ORIGIN = EnvUtil.getEnv(Const.Config.Operator.CSTG_INVALID_ORIGIN, EnabledCondition.isLocal());
+
+ @Getter
private final Type type;
private final PublisherUid2Client publisherClient;
private final PublisherUid2Client oldPublisherClient;
@@ -122,10 +125,6 @@ public Operator(String host, String name, Type type) {
this(host, null, name, type);
}
- public Type getType() {
- return type;
- }
-
public TokenGenerateResponse v2TokenGenerate(String type, String identity, boolean asOldParticipant) {
TokenGenerateInput token;
@@ -156,7 +155,7 @@ public JsonNode v2TokenGenerateUsingPayload(String payload, boolean asOldPartici
}
public JsonNode v2ClientSideTokenGenerate(String requestBody, boolean useValidOrigin) throws Exception {
- final byte[] serverPublicKeyBytes = base64ToByteArray(CLIENT_SIDE_TOKEN_GENERATE_SERVER_PUBLIC_KEY.substring(PUBLIC_KEY_PREFIX_LENGTH));
+ final byte[] serverPublicKeyBytes = base64ToByteArray(CSTG_SERVER_PUBLIC_KEY.substring(PUBLIC_KEY_PREFIX_LENGTH));
final PublicKey serverPublicKey = KeyFactory.getInstance("EC")
.generatePublic(new X509EncodedKeySpec(serverPublicKeyBytes));
@@ -164,11 +163,11 @@ public JsonNode v2ClientSideTokenGenerate(String requestBody, boolean useValidOr
final KeyPair keyPair = generateKeyPair();
final SecretKey sharedSecret = generateSharedSecret(serverPublicKey, keyPair);
- final JsonObject cstgEnvelope = createCstgEnvelope(requestBody, CLIENT_SIDE_TOKEN_GENERATE_SUBSCRIPTION_ID, keyPair.getPublic(), sharedSecret);
+ final JsonObject cstgEnvelope = createCstgEnvelope(requestBody, keyPair.getPublic(), sharedSecret);
final Request.Builder requestBuilder = new Request.Builder()
.url(getBaseUrl() + "/v2/token/client-generate")
- .addHeader("Origin", useValidOrigin ? CLIENT_SIDE_TOKEN_GENERATE_ORIGIN : CLIENT_SIDE_TOKEN_GENERATE_INVALID_ORIGIN)
+ .addHeader("Origin", useValidOrigin ? CSTG_ORIGIN : CSTG_INVALID_ORIGIN)
.post(RequestBody.create(cstgEnvelope.toString(), HttpClient.JSON));
final String encryptedResponse = HttpClient.execute(requestBuilder.build(), HttpClient.HttpMethod.POST);
@@ -202,7 +201,7 @@ private static SecretKey generateSharedSecret(PublicKey serverPublicKey, KeyPair
}
}
- private static JsonObject createCstgEnvelope(String request, String subscriptionId, PublicKey clientPublicKey, SecretKey sharedSecret) {
+ private static JsonObject createCstgEnvelope(String request, PublicKey clientPublicKey, SecretKey sharedSecret) {
final long now = Clock.systemUTC().millis();
final byte[] iv = new byte[IV_BYTES];
@@ -222,7 +221,7 @@ private static JsonObject createCstgEnvelope(String request, String subscription
body.addProperty("iv", byteArrayToBase64(iv));
body.addProperty("public_key", byteArrayToBase64(clientPublicKey.getEncoded()));
body.addProperty("timestamp", now);
- body.addProperty("subscription_id", subscriptionId);
+ body.addProperty("subscription_id", CSTG_SUBSCRIPTION_ID);
return body;
}
diff --git a/src/test/java/app/component/Optout.java b/src/test/java/app/component/Optout.java
deleted file mode 100644
index b749b04..0000000
--- a/src/test/java/app/component/Optout.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package app.component;
-
-
-import common.EnvUtil;
-import common.HttpClient;
-import common.Mapper;
-import com.fasterxml.jackson.databind.JsonNode;
-
-public class Optout extends App {
- private static final String CORE_API_TOKEN = EnvUtil.getEnv("UID2_E2E_OPTOUT_TO_CALL_CORE_API_TOKEN");
- public Optout(String host, Integer port, String name) {
- super(host, port, name);
- }
-
- public JsonNode getPath(String path) throws Exception {
- String response = HttpClient.get(getBaseUrl() + path, CORE_API_TOKEN);
- return Mapper.OBJECT_MAPPER.readTree(response);
- }
-
-}
diff --git a/src/test/java/common/Const.java b/src/test/java/common/Const.java
new file mode 100644
index 0000000..11020ea
--- /dev/null
+++ b/src/test/java/common/Const.java
@@ -0,0 +1,53 @@
+package common;
+
+public final class Const {
+ public static final class Config {
+ public static final String SUITES = "E2E_SUITES";
+ public static final String ARGS_JSON = "E2E_ARGS_JSON";
+
+ public static final String ENV = "E2E_ENV";
+ public static final String IDENTITY_SCOPE = "E2E_IDENTITY_SCOPE";
+ public static final String PHONE_SUPPORT = "E2E_PHONE_SUPPORT";
+
+ // Local only - Args used for Core E2Es
+ public static final class Core {
+ public static final String OPERATOR_API_KEY = "UID2_CORE_E2E_OPERATOR_API_KEY";
+ public static final String OPTOUT_API_KEY = "UID2_CORE_E2E_OPTOUT_API_KEY";
+ public static final String CORE_URL = "UID2_CORE_E2E_CORE_URL";
+ public static final String OPTOUT_URL = "UID2_CORE_E2E_OPTOUT_URL";
+ }
+
+ // Args used for Operator E2Es
+ public static final class Operator {
+ public static final String CLIENT_SITE_ID = "UID2_OPERATOR_E2E_CLIENT_SITE_ID";
+ public static final String CLIENT_API_KEY = "UID2_OPERATOR_E2E_CLIENT_API_KEY";
+ public static final String CLIENT_API_SECRET = "UID2_OPERATOR_E2E_CLIENT_API_SECRET";
+
+ // Optout cutoff
+ public static final String CLIENT_API_KEY_BEFORE_OPTOUT_CUTOFF = "UID2_OPERATOR_E2E_CLIENT_API_KEY_BEFORE_OPTOUT_CUTOFF";
+ public static final String CLIENT_API_SECRET_BEFORE_OPTOUT_CUTOFF = "UID2_OPERATOR_E2E_CLIENT_API_SECRET_BEFORE_OPTOUT_CUTOFF";
+
+ // Local only - Sharing
+ public static final String CLIENT_API_KEY_SHARING_RECIPIENT = "UID2_OPERATOR_E2E_CLIENT_API_KEY_SHARING_RECIPIENT";
+ public static final String CLIENT_API_SECRET_SHARING_RECIPIENT = "UID2_OPERATOR_E2E_CLIENT_API_SECRET_SHARING_RECIPIENT";
+
+ public static final String CLIENT_API_KEY_NON_SHARING_RECIPIENT = "UID2_OPERATOR_E2E_CLIENT_API_KEY_NON_SHARING_RECIPIENT";
+ public static final String CLIENT_API_SECRET_NON_SHARING_RECIPIENT = "UID2_OPERATOR_E2E_CLIENT_API_SECRET_NON_SHARING_RECIPIENT";
+
+ // Local only - CSTG
+ public static final String CSTG_SUBSCRIPTION_ID = "UID2_OPERATOR_E2E_CSTG_SUBSCRIPTION_ID";
+ public static final String CSTG_SERVER_PUBLIC_KEY = "UID2_OPERATOR_E2E_CSTG_SERVER_PUBLIC_KEY";
+ public static final String CSTG_ORIGIN = "UID2_OPERATOR_E2E_CSTG_ORIGIN";
+ public static final String CSTG_INVALID_ORIGIN = "UID2_OPERATOR_E2E_CSTG_INVALID_ORIGIN";
+ }
+
+ // Args used for pipeline setup
+ public static final class Pipeline {
+ public static final String CORE_URL = "UID2_PIPELINE_E2E_CORE_URL";
+
+ public static final String OPERATOR_URL = "UID2_PIPELINE_E2E_OPERATOR_URL";
+ public static final String OPERATOR_TYPE = "UID2_PIPELINE_E2E_OPERATOR_TYPE";
+ public static final String OPERATOR_CLOUD_PROVIDER = "UID2_PIPELINE_E2E_OPERATOR_CLOUD_PROVIDER";
+ }
+ }
+}
diff --git a/src/test/java/common/EnabledCondition.java b/src/test/java/common/EnabledCondition.java
index c14919c..44494d3 100644
--- a/src/test/java/common/EnabledCondition.java
+++ b/src/test/java/common/EnabledCondition.java
@@ -1,7 +1,7 @@
package common;
public final class EnabledCondition {
- private static final String ENV = EnvUtil.getEnv("UID2_E2E_ENV");
+ private static final String ENV = EnvUtil.getEnv(Const.Config.ENV);
private EnabledCondition() {
}
diff --git a/src/test/java/common/EnvUtil.java b/src/test/java/common/EnvUtil.java
index c287607..e950c33 100644
--- a/src/test/java/common/EnvUtil.java
+++ b/src/test/java/common/EnvUtil.java
@@ -1,21 +1,51 @@
package common;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.core.type.TypeReference;
import org.apache.commons.lang3.StringUtils;
import org.junit.platform.commons.logging.Logger;
import org.junit.platform.commons.logging.LoggerFactory;
+import java.util.HashMap;
+import java.util.Map;
+
public final class EnvUtil {
private static final Logger LOGGER = LoggerFactory.getLogger(EnvUtil.class);
+ private static final Map ARGS = new HashMap<>();
+
+ static {
+ try {
+ String args = getEnv(Const.Config.ARGS_JSON, false);
+
+ if (StringUtils.isNotBlank(args)) {
+ TypeReference> typeRef = new TypeReference<>() {
+ };
+ ARGS.putAll(Mapper.OBJECT_MAPPER.readValue(args, typeRef));
+ }
+ } catch (JsonProcessingException e) {
+ LOGGER.error(e::getMessage);
+ System.exit(1);
+ }
+ }
private EnvUtil() {
}
- public static String getEnv(String env) {
+ public static String getEnv(String env, boolean required) {
String value = System.getenv(env);
if (StringUtils.isBlank(value)) {
+ value = ARGS.get(env);
+ }
+
+ if (StringUtils.isBlank(value) && required) {
LOGGER.error(() -> "Missing environment variable: " + env);
System.exit(1);
}
+
return value;
}
+
+ public static String getEnv(String env) {
+ return getEnv(env, true);
+ }
}
diff --git a/src/test/java/suite/E2ECoreTestSuite.java b/src/test/java/suite/E2ECoreTestSuite.java
new file mode 100644
index 0000000..742cbfa
--- /dev/null
+++ b/src/test/java/suite/E2ECoreTestSuite.java
@@ -0,0 +1,16 @@
+package suite;
+
+import org.junit.platform.suite.api.SelectClasses;
+import org.junit.platform.suite.api.Suite;
+import suite.basic.BasicTest;
+import suite.core.CoreRefreshTest;
+import suite.core.CoreTest;
+
+@Suite
+@SelectClasses({
+ BasicTest.class,
+ CoreTest.class,
+ CoreRefreshTest.class
+})
+public class E2ECoreTestSuite {
+}
diff --git a/src/test/java/suite/E2ELocalFullTestSuite.java b/src/test/java/suite/E2ELocalFullTestSuite.java
index 553171d..cc301d5 100644
--- a/src/test/java/suite/E2ELocalFullTestSuite.java
+++ b/src/test/java/suite/E2ELocalFullTestSuite.java
@@ -5,8 +5,7 @@
import suite.basic.BasicTest;
import suite.core.CoreRefreshTest;
import suite.core.CoreTest;
-import suite.operator.V2ApiOperatorPublicOnlyTest;
-import suite.operator.V2ApiOperatorTest;
+import suite.operator.*;
import suite.optout.OptoutTest;
import suite.validator.V2ApiValidatorTest;
@@ -17,6 +16,7 @@
CoreRefreshTest.class,
V2ApiOperatorTest.class,
V2ApiOperatorPublicOnlyTest.class,
+ V2ApiOperatorLocalOnlyTest.class,
OptoutTest.class,
V2ApiValidatorTest.class
})
diff --git a/src/test/java/suite/E2EPublicOperatorTestSuite.java b/src/test/java/suite/E2EPublicOperatorTestSuite.java
index c125aa0..7a483d5 100644
--- a/src/test/java/suite/E2EPublicOperatorTestSuite.java
+++ b/src/test/java/suite/E2EPublicOperatorTestSuite.java
@@ -5,8 +5,7 @@
import suite.basic.BasicTest;
import suite.core.CoreRefreshTest;
import suite.core.CoreTest;
-import suite.operator.V2ApiOperatorPublicOnlyTest;
-import suite.operator.V2ApiOperatorTest;
+import suite.operator.*;
import suite.optout.OptoutTest;
@Suite
@@ -16,6 +15,7 @@
CoreRefreshTest.class,
V2ApiOperatorTest.class,
V2ApiOperatorPublicOnlyTest.class,
+ V2ApiOperatorLocalOnlyTest.class,
OptoutTest.class
})
public class E2EPublicOperatorTestSuite {
diff --git a/src/test/java/suite/core/CoreRefreshTest.java b/src/test/java/suite/core/CoreRefreshTest.java
index 191d054..02478d6 100644
--- a/src/test/java/suite/core/CoreRefreshTest.java
+++ b/src/test/java/suite/core/CoreRefreshTest.java
@@ -4,6 +4,7 @@
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import common.JsonAssert;
+import org.junit.jupiter.api.condition.EnabledIf;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
@@ -11,6 +12,7 @@
import static org.junit.jupiter.api.Assertions.*;
+@EnabledIf("common.EnabledCondition#isLocal")
public class CoreRefreshTest {
@ParameterizedTest(name = "Refresh test - UrlPath: {1} - JsonPath: {2}")
@MethodSource({"suite.core.TestData#refreshArgs", "suite.core.TestData#refreshArgsEncrypted"})
diff --git a/src/test/java/suite/core/CoreTest.java b/src/test/java/suite/core/CoreTest.java
index 864275c..4ee9c0e 100644
--- a/src/test/java/suite/core/CoreTest.java
+++ b/src/test/java/suite/core/CoreTest.java
@@ -6,11 +6,13 @@
import com.uid2.shared.attest.JwtService;
import com.uid2.shared.attest.JwtValidationResponse;
import io.vertx.core.json.JsonObject;
+import org.junit.jupiter.api.condition.EnabledIf;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import static org.junit.jupiter.api.Assertions.*;
+@EnabledIf("common.EnabledCondition#isLocal")
public class CoreTest {
@ParameterizedTest(name = "/attest - {0}")
@MethodSource({
diff --git a/src/test/java/suite/operator/TestData.java b/src/test/java/suite/operator/TestData.java
index 08e6df6..38a6df8 100644
--- a/src/test/java/suite/operator/TestData.java
+++ b/src/test/java/suite/operator/TestData.java
@@ -1,7 +1,7 @@
package suite.operator;
import app.AppsMap;
-import common.EnvUtil;
+import app.component.App;
import app.component.Operator;
import com.uid2.client.DecryptionStatus;
import org.junit.jupiter.params.provider.Arguments;
@@ -17,11 +17,6 @@
public final class TestData {
public static final int RAW_UID2_LENGTH = 44;
- private static final boolean PHONE_SUPPORT = Boolean.parseBoolean(EnvUtil.getEnv("UID2_E2E_PHONE_SUPPORT"));
-
- private static final Client CLIENT = new Client(Operator.CLIENT_API_KEY, Operator.CLIENT_API_SECRET);
- private static final Client SHARING_RECIPIENT = new Client(Operator.CLIENT_API_KEY_SHARING_RECIPIENT, Operator.CLIENT_API_SECRET_SHARING_RECIPIENT);
- private static final Client NON_SHARING_RECIPIENT = new Client(Operator.CLIENT_API_KEY_NON_SHARING_RECIPIENT, Operator.CLIENT_API_SECRET_NON_SHARING_RECIPIENT);
private TestData() {
}
@@ -39,50 +34,6 @@ public static Set baseArgs() {
return args;
}
- public static Stream sharingArgs() {
- final var privateOperator = named("PRIVATE OPERATOR", getOperator(Operator.Type.PRIVATE).orElse(null));
- final var publicOperator = named("PUBLIC OPERATOR", getOperator(Operator.Type.PUBLIC).orElse(null));
-
- final var client = named("CLIENT", CLIENT);
- final var sharingRecipient = named("SHARING RECIPIENT", SHARING_RECIPIENT);
- final var nonSharingRecipient = named("NON-SHARING RECIPIENT", NON_SHARING_RECIPIENT);
-
- return Stream.of(
- // CLIENT shares with CLIENT.
- Arguments.of(client, privateOperator, client, privateOperator, DecryptionStatus.SUCCESS),
- Arguments.of(client, privateOperator, client, publicOperator, DecryptionStatus.SUCCESS),
- Arguments.of(client, publicOperator, client, privateOperator, DecryptionStatus.SUCCESS),
- Arguments.of(client, publicOperator, client, publicOperator, DecryptionStatus.SUCCESS),
-
- // CLIENT shares with SHARING RECIPIENT.
- // Private operator only has site data for CLIENT, so SHARING RECIPIENT must decrypt using public operator.
- Arguments.of(client, privateOperator, sharingRecipient, publicOperator, DecryptionStatus.SUCCESS),
- Arguments.of(client, publicOperator, sharingRecipient, publicOperator, DecryptionStatus.SUCCESS),
-
- // CLIENT does not share with NON-SHARING RECIPIENT.
- // Private operator only has site data for CLIENT, so NON-SHARING RECIPIENT must decrypt using public operator.
- Arguments.of(client, privateOperator, nonSharingRecipient, publicOperator, DecryptionStatus.NOT_AUTHORIZED_FOR_KEY),
- Arguments.of(client, publicOperator, nonSharingRecipient, publicOperator, DecryptionStatus.NOT_AUTHORIZED_FOR_KEY),
-
- // SHARING RECIPIENT shares with CLIENT.
- // Private operator only has site data for CLIENT, so SHARING RECIPIENT must encrypt using public operator.
- Arguments.of(sharingRecipient, publicOperator, client, privateOperator, DecryptionStatus.SUCCESS),
- Arguments.of(sharingRecipient, publicOperator, client, publicOperator, DecryptionStatus.SUCCESS),
-
- // NON-SHARING RECIPIENT does not share with CLIENT.
- // Private operator only has site data for CLIENT, so NON-SHARING RECIPIENT must encrypt using public operator.
- Arguments.of(nonSharingRecipient, publicOperator, client, publicOperator, DecryptionStatus.NOT_AUTHORIZED_FOR_KEY),
- Arguments.of(nonSharingRecipient, publicOperator, client, privateOperator, DecryptionStatus.NOT_AUTHORIZED_FOR_KEY)
- );
- }
-
- private static Optional getOperator(Operator.Type type) {
- return AppsMap.getApps(Operator.class)
- .stream()
- .filter(operator -> operator.getType() == type)
- .findFirst();
- }
-
public static Set tokenEmailArgs() {
Set operators = AppsMap.getApps(Operator.class);
Set> inputs = Set.of(
@@ -136,7 +87,7 @@ public static Set tokenPhoneArgs() {
);
Set args = new HashSet<>();
- if (PHONE_SUPPORT) {
+ if (App.PHONE_SUPPORT) {
for (Operator operator : operators) {
for (List input : inputs) {
args.add(Arguments.of(input.get(0), operator, operator.getName(), input.get(1), input.get(2)));
@@ -150,7 +101,7 @@ public static Set tokenPhoneArgsSpecialOptout() {
Set operators = AppsMap.getApps(Operator.class);
Set args = new HashSet<>();
- if (PHONE_SUPPORT) {
+ if (App.PHONE_SUPPORT) {
for (Operator operator : operators) {
args.add(Arguments.of("optout special phone", operator, operator.getName(), "phone", "+00000000000", true));
args.add(Arguments.of("optout special phone", operator, operator.getName(), "phone", "+00000000000", false));
@@ -163,7 +114,7 @@ public static Set tokenPhoneArgsSpecialRefreshOptout() {
Set operators = AppsMap.getApps(Operator.class);
Set args = new HashSet<>();
- if (PHONE_SUPPORT) {
+ if (App.PHONE_SUPPORT) {
for (Operator operator : operators) {
args.add(Arguments.of("optout special refresh phone", operator, operator.getName(), "phone", "+00000000002"));
}
@@ -256,7 +207,7 @@ public static Set tokenValidatePhoneArgs() {
);
Set args = new HashSet<>();
- if (PHONE_SUPPORT) {
+ if (App.PHONE_SUPPORT) {
for (Operator operator : operators) {
for (List input : inputs) {
args.add(Arguments.of(input.get(0), operator, operator.getName(), input.get(1), input.get(2)));
@@ -273,7 +224,7 @@ public static Set tokenValidatePhoneHashArgs() {
);
Set args = new HashSet<>();
- if (PHONE_SUPPORT) {
+ if (App.PHONE_SUPPORT) {
for (Operator operator : operators) {
for (List input : inputs) {
args.add(Arguments.of(input.get(0), operator, operator.getName(), input.get(1), input.get(2)));
@@ -307,7 +258,7 @@ public static Set identityMapPhoneArgs() {
);
Set args = new HashSet<>();
- if (PHONE_SUPPORT) {
+ if (App.PHONE_SUPPORT) {
for (Operator operator : operators) {
for (List input : inputs) {
args.add(Arguments.of(input.get(0), operator, operator.getName(), input.get(1), input.get(2)));
@@ -407,7 +358,7 @@ public static Set clientSideTokenGenerateArgs() {
inputs.add(List.of("email hash", "{\"email_hash\":\"eVvLS/Vg+YZ6+z3i0NOpSXYyQAfEXqCZ7BTpAjFUBUc=\"}"));
- if (PHONE_SUPPORT) {
+ if (App.PHONE_SUPPORT) {
inputs.add(List.of("phone hash", "{\"phone_hash\":\"eVvLS/Vg+YZ6+z3i0NOpSXYyQAfEXqCZ7BTpAjFUBUc=\"}"));
}
@@ -452,7 +403,7 @@ public static Set tokenGeneratePhoneArgsBadPolicy() {
);
Set args = new HashSet<>();
- if (PHONE_SUPPORT) {
+ if (App.PHONE_SUPPORT) {
for (Operator operator : operators) {
for (List input : inputs) {
args.add(Arguments.of(input.get(0), operator, operator.getName(), input.get(1)));
@@ -476,7 +427,7 @@ public static Set identityMapBatchPhoneArgs() {
);
Set args = new HashSet<>();
- if (PHONE_SUPPORT) {
+ if (App.PHONE_SUPPORT) {
for (Operator operator : operators) {
for (List input : inputs) {
args.add(Arguments.of(input.get(0), operator, operator.getName(), input.get(1)));
@@ -504,7 +455,7 @@ public static Set identityMapBatchPhoneArgsBadPolicy() {
);
Set args = new HashSet<>();
- if (PHONE_SUPPORT) {
+ if (App.PHONE_SUPPORT) {
for (Operator operator : operators) {
for (List input : inputs) {
args.add(Arguments.of(input.get(0), operator, operator.getName(), input.get(1), true));
@@ -543,7 +494,7 @@ public static Set identityMapBatchBadPhoneArgs() {
);
Set args = new HashSet<>();
- if (PHONE_SUPPORT) {
+ if (App.PHONE_SUPPORT) {
for (Operator operator : operators) {
for (List input : inputs) {
args.add(Arguments.of(input.get(0), operator, operator.getName(), input.get(1)));
@@ -568,6 +519,50 @@ public static Set identityBucketsArgs() {
return args;
}
+ public static Stream sharingArgs() {
+ var privateOperator = named("PRIVATE OPERATOR", getOperator(Operator.Type.PRIVATE).orElse(null));
+ var publicOperator = named("PUBLIC OPERATOR", getOperator(Operator.Type.PUBLIC).orElse(null));
+
+ var client = named("CLIENT", new Client(Operator.CLIENT_API_KEY, Operator.CLIENT_API_SECRET));
+ var sharingRecipient = named("SHARING RECIPIENT", new Client(Operator.CLIENT_API_KEY_SHARING_RECIPIENT, Operator.CLIENT_API_SECRET_SHARING_RECIPIENT));
+ var nonSharingRecipient = named("NON-SHARING RECIPIENT", new Client(Operator.CLIENT_API_KEY_NON_SHARING_RECIPIENT, Operator.CLIENT_API_SECRET_NON_SHARING_RECIPIENT));
+
+ return Stream.of(
+ // CLIENT shares with CLIENT.
+ Arguments.of(client, privateOperator, client, privateOperator, DecryptionStatus.SUCCESS),
+ Arguments.of(client, privateOperator, client, publicOperator, DecryptionStatus.SUCCESS),
+ Arguments.of(client, publicOperator, client, privateOperator, DecryptionStatus.SUCCESS),
+ Arguments.of(client, publicOperator, client, publicOperator, DecryptionStatus.SUCCESS),
+
+ // CLIENT shares with SHARING RECIPIENT.
+ // Private operator only has site data for CLIENT, so SHARING RECIPIENT must decrypt using public operator.
+ Arguments.of(client, privateOperator, sharingRecipient, publicOperator, DecryptionStatus.SUCCESS),
+ Arguments.of(client, publicOperator, sharingRecipient, publicOperator, DecryptionStatus.SUCCESS),
+
+ // CLIENT does not share with NON-SHARING RECIPIENT.
+ // Private operator only has site data for CLIENT, so NON-SHARING RECIPIENT must decrypt using public operator.
+ Arguments.of(client, privateOperator, nonSharingRecipient, publicOperator, DecryptionStatus.NOT_AUTHORIZED_FOR_KEY),
+ Arguments.of(client, publicOperator, nonSharingRecipient, publicOperator, DecryptionStatus.NOT_AUTHORIZED_FOR_KEY),
+
+ // SHARING RECIPIENT shares with CLIENT.
+ // Private operator only has site data for CLIENT, so SHARING RECIPIENT must encrypt using public operator.
+ Arguments.of(sharingRecipient, publicOperator, client, privateOperator, DecryptionStatus.SUCCESS),
+ Arguments.of(sharingRecipient, publicOperator, client, publicOperator, DecryptionStatus.SUCCESS),
+
+ // NON-SHARING RECIPIENT does not share with CLIENT.
+ // Private operator only has site data for CLIENT, so NON-SHARING RECIPIENT must encrypt using public operator.
+ Arguments.of(nonSharingRecipient, publicOperator, client, publicOperator, DecryptionStatus.NOT_AUTHORIZED_FOR_KEY),
+ Arguments.of(nonSharingRecipient, publicOperator, client, privateOperator, DecryptionStatus.NOT_AUTHORIZED_FOR_KEY)
+ );
+ }
+
+ private static Optional getOperator(Operator.Type type) {
+ return AppsMap.getApps(Operator.class)
+ .stream()
+ .filter(operator -> operator.getType() == type)
+ .findFirst();
+ }
+
private static Set getPublicOperators() {
return AppsMap.getApps(Operator.class).stream()
.filter(s -> s.getType() != Operator.Type.PRIVATE)
diff --git a/src/test/java/suite/operator/V2ApiOperatorLocalOnlyTest.java b/src/test/java/suite/operator/V2ApiOperatorLocalOnlyTest.java
new file mode 100644
index 0000000..980cbf7
--- /dev/null
+++ b/src/test/java/suite/operator/V2ApiOperatorLocalOnlyTest.java
@@ -0,0 +1,74 @@
+package suite.operator;
+
+import app.component.App;
+import app.component.Operator;
+import com.uid2.client.*;
+import common.Const;
+import common.EnvUtil;
+import org.junit.jupiter.api.condition.EnabledIf;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import java.security.SecureRandom;
+import java.util.Base64;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assumptions.assumeThat;
+import static org.junit.jupiter.api.Assertions.assertAll;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+@EnabledIf("common.EnabledCondition#isLocal")
+public class V2ApiOperatorLocalOnlyTest {
+ @ParameterizedTest(name = "{index} ==> Sender {0} encrypts with {1}, recipient {2} decrypts with {3}, expected result is {4}")
+ @MethodSource({
+ "suite.operator.TestData#sharingArgs",
+ })
+ public void testSharing(TestData.Client sender, Operator senderOperator, TestData.Client recipient, Operator recipientOperator, DecryptionStatus expectedDecryptionStatus) throws Exception {
+ assumeThat(senderOperator).isNotNull();
+ assumeThat(recipientOperator).isNotNull();
+
+ final var rawUidBytes = new byte[33];
+ new SecureRandom().nextBytes(rawUidBytes);
+ rawUidBytes[0] = 0;
+
+ final var rawUid = Base64.getEncoder().encodeToString(rawUidBytes);
+
+ final var senderClient = new UID2Client(
+ senderOperator.getBaseUrl(),
+ sender.apiKey(),
+ sender.apiSecret(),
+ App.IDENTITY_SCOPE
+ );
+
+ final var recipientClient = new UID2Client(
+ recipientOperator.getBaseUrl(),
+ recipient.apiKey(),
+ recipient.apiSecret(),
+ App.IDENTITY_SCOPE
+ );
+
+ senderClient.refresh();
+ final var encrypted = senderClient.encrypt(rawUid);
+ assertTrue(encrypted.isSuccess());
+
+ recipientClient.refresh();
+ final var decrypted = recipientClient.decrypt(encrypted.getEncryptedData());
+ final var expectedRawUid = expectedDecryptionStatus == DecryptionStatus.SUCCESS ? rawUid : null;
+
+ assertAll(
+ () -> assertThat(decrypted.getStatus()).isEqualTo(expectedDecryptionStatus),
+ () -> assertThat(decrypted.getUid()).isEqualTo(expectedRawUid)
+ );
+ }
+
+ @ParameterizedTest(name = "/v2/token/generate - LOCAL MOCK OPTOUT - {0} - {2}")
+ @MethodSource({
+ "suite.operator.TestData#tokenEmailArgsLocalMockOptout"
+ })
+ public void testV2TokenGenerateLocalMockOptout(String label, Operator operator, String operatorName, String type, String identity) {
+ TokenGenerateResponse tokenGenerateResponse = operator.v2TokenGenerate(type, identity, false);
+ IdentityTokens currentIdentity = tokenGenerateResponse.getIdentity();
+
+ assertThat(currentIdentity).isNull();
+ }
+}
diff --git a/src/test/java/suite/operator/V2ApiOperatorPublicOnlyTest.java b/src/test/java/suite/operator/V2ApiOperatorPublicOnlyTest.java
index 6921e55..95042ae 100644
--- a/src/test/java/suite/operator/V2ApiOperatorPublicOnlyTest.java
+++ b/src/test/java/suite/operator/V2ApiOperatorPublicOnlyTest.java
@@ -7,6 +7,8 @@
import com.uid2.client.DecryptionResponse;
import com.uid2.client.IdentityTokens;
import com.uid2.client.TokenRefreshResponse;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.condition.EnabledIf;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
@@ -199,6 +201,7 @@ public void testV2IdentityMapBadPolicy(String label, Operator operator, String o
assertThat(response.at("/status").asText()).isEqualTo("success");
}
+ @EnabledIf("common.EnabledCondition#isLocal")
@ParameterizedTest(name = "/v2/token/client-generate - {0} - {2}")
@MethodSource({
"suite.operator.TestData#clientSideTokenGenerateArgs",
@@ -213,6 +216,7 @@ public void testV2ClientSideTokenGenerate(String label, Operator operator, Strin
assertThat(response.get("status").asText()).isEqualTo("success");
}
+ @EnabledIf("common.EnabledCondition#isLocal")
@ParameterizedTest(name = "/v2/token/client-generate - INVALID ORIGIN - {0} - {2}")
@MethodSource({
"suite.operator.TestData#clientSideTokenGenerateArgs",
diff --git a/src/test/java/suite/operator/V2ApiOperatorTest.java b/src/test/java/suite/operator/V2ApiOperatorTest.java
index f877db1..e87b190 100644
--- a/src/test/java/suite/operator/V2ApiOperatorTest.java
+++ b/src/test/java/suite/operator/V2ApiOperatorTest.java
@@ -1,19 +1,15 @@
package suite.operator;
+import common.Const;
import common.EnvUtil;
import common.Mapper;
import app.component.Operator;
import com.fasterxml.jackson.databind.JsonNode;
import com.uid2.client.*;
-import org.junit.jupiter.api.condition.EnabledIf;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
-import java.security.SecureRandom;
-import java.util.Base64;
-
import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.core.api.Assumptions.assumeThat;
import static org.junit.jupiter.api.Assertions.*;
@SuppressWarnings("unused")
@@ -29,49 +25,7 @@ public class V2ApiOperatorTest {
// The advertiser token will be different on every call due to randomness used in encryption,
// so we can't assert on it
- private static final String SITE_ID = EnvUtil.getEnv("UID2_E2E_SITE_ID");
-
- @ParameterizedTest(name = "{index} ==> Sender {0} encrypts with {1}, recipient {2} decrypts with {3}, expected result is {4}")
- @MethodSource({
- "suite.operator.TestData#sharingArgs",
- })
- public void testSharing(TestData.Client sender, Operator senderOperator, TestData.Client recipient, Operator recipientOperator, DecryptionStatus expectedDecryptionStatus) throws Exception {
- assumeThat(senderOperator).isNotNull();
- assumeThat(recipientOperator).isNotNull();
-
- final var rawUidBytes = new byte[33];
- new SecureRandom().nextBytes(rawUidBytes);
- rawUidBytes[0] = 0;
-
- final var rawUid = Base64.getEncoder().encodeToString(rawUidBytes);
-
- final var senderClient = new UID2Client(
- senderOperator.getBaseUrl(),
- sender.apiKey(),
- sender.apiSecret(),
- Operator.IDENTITY_SCOPE
- );
-
- final var recipientClient = new UID2Client(
- recipientOperator.getBaseUrl(),
- recipient.apiKey(),
- recipient.apiSecret(),
- Operator.IDENTITY_SCOPE
- );
-
- senderClient.refresh();
- final var encrypted = senderClient.encrypt(rawUid);
- assertTrue(encrypted.isSuccess());
-
- recipientClient.refresh();
- final var decrypted = recipientClient.decrypt(encrypted.getEncryptedData());
- final var expectedRawUid = expectedDecryptionStatus == DecryptionStatus.SUCCESS ? rawUid : null;
-
- assertAll(
- () -> assertThat(decrypted.getStatus()).isEqualTo(expectedDecryptionStatus),
- () -> assertThat(decrypted.getUid()).isEqualTo(expectedRawUid)
- );
- }
+ private static final String CLIENT_SITE_ID = EnvUtil.getEnv(Const.Config.Operator.CLIENT_SITE_ID);
@ParameterizedTest(name = "/v2/token/generate - {0} - {2}")
@MethodSource({
@@ -122,18 +76,6 @@ public void testV2SpecialRefreshOptout(String label, Operator operator, String o
assertTrue(refreshed.isOptout());
}
- @EnabledIf("common.EnabledCondition#isLocal")
- @ParameterizedTest(name = "/v2/token/generate - LOCAL MOCK OPTOUT - {0} - {2}")
- @MethodSource({
- "suite.operator.TestData#tokenEmailArgsLocalMockOptout"
- })
- public void testV2TokenGenerateLocalMockOptout(String label, Operator operator, String operatorName, String type, String identity) {
- TokenGenerateResponse tokenGenerateResponse = operator.v2TokenGenerate(type, identity, false);
- IdentityTokens currentIdentity = tokenGenerateResponse.getIdentity();
-
- assertThat(currentIdentity).isNull();
- }
-
@ParameterizedTest(name = "/v2/token/validate - {0} - {2}")
@MethodSource({
"suite.operator.TestData#tokenValidateEmailArgs",
@@ -191,6 +133,6 @@ public void testV2IdentityBuckets(String label, Operator operator, String operat
public void testV2KeySharing(Operator operator, String operatorName) throws Exception {
JsonNode response = operator.v2KeySharing();
- assertEquals(SITE_ID, response.at("/body/caller_site_id").asText());
+ assertEquals(CLIENT_SITE_ID, response.at("/body/caller_site_id").asText());
}
}
diff --git a/src/test/java/suite/optout/TestData.java b/src/test/java/suite/optout/TestData.java
index f595b15..4d78bb8 100644
--- a/src/test/java/suite/optout/TestData.java
+++ b/src/test/java/suite/optout/TestData.java
@@ -1,7 +1,7 @@
package suite.optout;
import app.AppsMap;
-import common.EnvUtil;
+import app.component.App;
import app.component.Operator;
import org.junit.jupiter.params.provider.Arguments;
@@ -14,7 +14,6 @@
public final class TestData {
public static final String ADVERTISING_ID = "advertising_id";
public static final String OPTED_OUT_SINCE = "opted_out_since";
- private static final boolean PHONE_SUPPORT = Boolean.parseBoolean(EnvUtil.getEnv("UID2_E2E_PHONE_SUPPORT"));
private TestData() {
}
@@ -55,7 +54,7 @@ public static Set tokenPhoneArgs() {
);
Set args = new HashSet<>();
- if (PHONE_SUPPORT) {
+ if (App.PHONE_SUPPORT) {
for (Operator operator : operators) {
for (List input : inputs) {
args.add(Arguments.of(input.get(0), operator, operator.getName(), input.get(1), input.get(2)));
@@ -70,7 +69,7 @@ public static Set optoutTokenPhoneArgs() {
Set> inputs = generatePhoneSet(1);
Set args = new HashSet<>();
- if (PHONE_SUPPORT) {
+ if (App.PHONE_SUPPORT) {
for (Operator operator : operators) {
for (List input : inputs) {
args.add(Arguments.of(input.get(0), operator, operator.getName(), input.get(1), input.get(2)));