diff --git a/conf/default-config.json b/conf/default-config.json index 722f8626..0058cfae 100644 --- a/conf/default-config.json +++ b/conf/default-config.json @@ -1,4 +1,5 @@ { + "service_instances": 3, "pre_signed_url_expiry": 1800, "core_s3_bucket": null, "aws_region": null, diff --git a/conf/integ-config.json b/conf/integ-config.json index e05043cb..be7037e4 100644 --- a/conf/integ-config.json +++ b/conf/integ-config.json @@ -1,4 +1,5 @@ { + "service_instances": 3, "aws_region": "", "core_s3_bucket": "", "aws_access_key_id": "", diff --git a/conf/local-config.json b/conf/local-config.json index 9999c505..ba3440d9 100644 --- a/conf/local-config.json +++ b/conf/local-config.json @@ -1,4 +1,5 @@ { + "service_instances": 1, "aws_s3_endpoint": "http://localstack:5001", "enable_test_endpoints": true, "storage_mock": true, diff --git a/conf/local-e2e-config.json b/conf/local-e2e-config.json index fec4459f..de4163a9 100644 --- a/conf/local-e2e-config.json +++ b/conf/local-e2e-config.json @@ -1,4 +1,5 @@ { + "service_instances": 1, "enable_test_endpoints": true, "storage_mock": false, "aws_s3_endpoint": "http://localhost:5001", diff --git a/conf/local-e2e-docker-config.json b/conf/local-e2e-docker-config.json index cc9bb3ac..3a4b871d 100644 --- a/conf/local-e2e-docker-config.json +++ b/conf/local-e2e-docker-config.json @@ -1,4 +1,5 @@ { + "service_instances": 1, "enable_test_endpoints": true, "storage_mock": false, "aws_s3_endpoint": "http://localstack:5001", diff --git a/src/main/java/com/uid2/core/Const.java b/src/main/java/com/uid2/core/Const.java index 91ea7984..79d9997c 100644 --- a/src/main/java/com/uid2/core/Const.java +++ b/src/main/java/com/uid2/core/Const.java @@ -12,11 +12,12 @@ public static class RoutingContextData { public static final String ATTESTATION_FAILURE_DATA_PROP = "attestation-failure-data"; } - public class Config extends com.uid2.shared.Const.Config { + public static class Config extends com.uid2.shared.Const.Config { + public static final String ServiceInstancesProp = "service_instances"; public static final String KmsAccessKeyIdProp = "kms_aws_access_key_id"; public static final String KmsSecretAccessKeyProp = "kms_aws_secret_access_key"; public static final String KmsEndpointProp = "kms_aws_endpoint"; } public static final String OPERATOR_CONFIG_PATH = "conf/operator/operator-config.json"; -} \ No newline at end of file +} diff --git a/src/main/java/com/uid2/core/Main.java b/src/main/java/com/uid2/core/Main.java index 2af7fded..612e2478 100644 --- a/src/main/java/com/uid2/core/Main.java +++ b/src/main/java/com/uid2/core/Main.java @@ -16,7 +16,6 @@ import com.uid2.shared.auth.EnclaveIdentifierProvider; import com.uid2.shared.auth.RotatingOperatorKeyProvider; import com.uid2.shared.store.reader.RotatingCloudEncryptionKeyProvider; -import com.uid2.shared.model.CloudEncryptionKey; import com.uid2.shared.cloud.CloudUtils; import com.uid2.shared.cloud.EmbeddedResourceStorage; import com.uid2.shared.cloud.ICloudStorage; @@ -38,31 +37,32 @@ import io.vertx.core.VertxOptions; import io.vertx.core.file.FileSystem; import io.vertx.core.http.HttpServerOptions; -import io.vertx.core.http.impl.HttpUtils; import io.vertx.core.json.JsonObject; import io.vertx.micrometer.Label; import io.vertx.micrometer.MetricsDomain; import io.vertx.micrometer.MicrometerMetricsOptions; import io.vertx.micrometer.VertxPrometheusOptions; import io.vertx.micrometer.backends.BackendRegistries; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import javax.management.*; import java.lang.management.ManagementFactory; import java.util.*; public class Main { - - private static final int vertxServiceInstances = 1; + private static final Logger LOGGER = LoggerFactory.getLogger(CoreVerticle.class); + private static final int VERTX_WORKER_POOL_SIZE = 1000; // Cannot set this in config file because it's needed on Vertx init public static void main(String[] args) { final String vertxConfigPath = System.getProperty(Const.Config.VERTX_CONFIG_PATH_PROP); if (vertxConfigPath != null) { - System.out.format("Running CUSTOM CONFIG mode, config: %s\n", vertxConfigPath); + LOGGER.info("Running CUSTOM CONFIG mode, config: {}", vertxConfigPath); } else if (!Utils.isProductionEnvironment()) { - System.out.format("Running LOCAL DEBUG mode, config: %s\n", Const.Config.LOCAL_CONFIG_PATH); + LOGGER.info("Running LOCAL DEBUG mode, config: {}", Const.Config.LOCAL_CONFIG_PATH); System.setProperty(Const.Config.VERTX_CONFIG_PATH_PROP, Const.Config.LOCAL_CONFIG_PATH); } else { - System.out.format("Running PRODUCTION mode, config: %s\n", Const.Config.OVERRIDE_CONFIG_PATH); + LOGGER.info("Running PRODUCTION mode, config: {}", Const.Config.OVERRIDE_CONFIG_PATH); } // create AdminApi instance @@ -71,7 +71,7 @@ public static void main(String[] args) { MBeanServer server = ManagementFactory.getPlatformMBeanServer(); server.registerMBean(AdminApi.instance, objectName); } catch (InstanceAlreadyExistsException | MBeanRegistrationException | NotCompliantMBeanException | MalformedObjectNameException e) { - System.err.format("%s", e.getMessage()); + LOGGER.error(e.getMessage()); System.exit(-1); } @@ -81,17 +81,9 @@ public static void main(String[] args) { VertxOptions vertxOptions = getVertxOptions(metricOptions); Vertx vertx = Vertx.vertx(vertxOptions); - /* - CommandLine commandLine = parseArgs(args); - String configPath = commandLine.getOptionValue("config").toString(); - String secretsPath = commandLine.getOptionValue("secrets").toString(); - ConfigStore.Global.load(configPath); - SecretStore.Global.load(secretsPath); - */ - VertxUtils.createConfigRetriever(vertx).getConfig(ar -> { if (ar.failed()) { - System.out.println("failed to load config: " + ar.cause().toString()); + LOGGER.error("failed to load config: {}", ar.cause().toString()); System.exit(-1); } @@ -100,7 +92,7 @@ public static void main(String[] args) { SecretStore.Global.load(config); boolean useStorageMock = Optional.ofNullable(ConfigStore.Global.getBoolean("storage_mock")).orElse(false); - ICloudStorage cloudStorage = null; + ICloudStorage cloudStorage; if (useStorageMock) { cloudStorage = new EmbeddedResourceStorage(Main.class).withUrlPrefix(ConfigStore.Global.getOrDefault("storage_mock_url_prefix", "")); } else { @@ -110,24 +102,25 @@ public static void main(String[] args) { cloudStorage.setPreSignedUrlExpiry(expiryInSeconds); } - RotatingStoreVerticle enclaveRotatingVerticle = null; - RotatingStoreVerticle operatorRotatingVerticle = null; - RotatingStoreVerticle cloudEncryptionKeyRotatingVerticle = null; - CoreVerticle coreVerticle = null; try { + createVertxMetrics(); + CloudPath operatorMetadataPath = new CloudPath(config.getString(Const.Config.OperatorsMetadataPathProp)); GlobalScope operatorScope = new GlobalScope(operatorMetadataPath); RotatingOperatorKeyProvider operatorKeyProvider = new RotatingOperatorKeyProvider(cloudStorage, cloudStorage, operatorScope); - operatorRotatingVerticle = new RotatingStoreVerticle("operators", 60000, operatorKeyProvider); + RotatingStoreVerticle operatorRotatingVerticle = new RotatingStoreVerticle("operators", 60000, operatorKeyProvider); + vertx.deployVerticle(operatorRotatingVerticle); String enclaveMetadataPath = SecretStore.Global.get(EnclaveIdentifierProvider.ENCLAVES_METADATA_PATH); EnclaveIdentifierProvider enclaveIdProvider = new EnclaveIdentifierProvider(cloudStorage, enclaveMetadataPath); - enclaveRotatingVerticle = new RotatingStoreVerticle("enclaves", 60000, enclaveIdProvider); + RotatingStoreVerticle enclaveRotatingVerticle = new RotatingStoreVerticle("enclaves", 60000, enclaveIdProvider); + vertx.deployVerticle(enclaveRotatingVerticle); CloudPath cloudEncryptionKeyMetadataPath = new CloudPath(config.getString(Const.Config.CloudEncryptionKeysMetadataPathProp)); GlobalScope cloudEncryptionKeyScope = new GlobalScope(cloudEncryptionKeyMetadataPath); RotatingCloudEncryptionKeyProvider cloudEncryptionKeyProvider = new RotatingCloudEncryptionKeyProvider(cloudStorage, cloudEncryptionKeyScope); - cloudEncryptionKeyRotatingVerticle = new RotatingStoreVerticle("cloud_encryption_keys", 60000, cloudEncryptionKeyProvider); + RotatingStoreVerticle cloudEncryptionKeyRotatingVerticle = new RotatingStoreVerticle("cloud_encryption_keys", 60000, cloudEncryptionKeyProvider); + vertx.deployVerticle(cloudEncryptionKeyRotatingVerticle); String corePublicUrl = ConfigStore.Global.get(Const.Config.CorePublicUrlProp); AttestationService attestationService = new AttestationService() @@ -140,7 +133,7 @@ public static void main(String[] args) { Set enclaveParams = null; String params = config.getString(Const.Config.GcpEnclaveParamsProp); if (params != null) { - enclaveParams = Collections.unmodifiableSet(new HashSet<>(Arrays.asList(params.split(",")))); + enclaveParams = Set.of(params.split(",")); } // enable gcp-vmid attestation if requested @@ -155,7 +148,7 @@ public static void main(String[] args) { attestationService.with("gcp-oidc", new GcpOidcCoreAttestationService(corePublicUrl)); OperatorJWTTokenProvider operatorJWTTokenProvider = new OperatorJWTTokenProvider(config); - + IAttestationTokenService attestationTokenService = new AttestationTokenService( SecretStore.Global.get(Constants.AttestationEncryptionKeyName), SecretStore.Global.get(Constants.AttestationEncryptionSaltName), @@ -164,19 +157,20 @@ public static void main(String[] args) { JwtService jwtService = new JwtService(config); FileSystem fileSystem = vertx.fileSystem(); - coreVerticle = new CoreVerticle(cloudStorage, operatorKeyProvider, attestationService, attestationTokenService, enclaveIdProvider, operatorJWTTokenProvider, jwtService, cloudEncryptionKeyProvider, fileSystem); + + vertx.deployVerticle(() -> { + try { + return new CoreVerticle(cloudStorage, operatorKeyProvider, attestationService, attestationTokenService, enclaveIdProvider, operatorJWTTokenProvider, jwtService, cloudEncryptionKeyProvider, fileSystem); + } catch (Exception e) { + LOGGER.error("failed to deploy core verticle: {}", e.getMessage()); + System.exit(-1); + return null; + } + }, new DeploymentOptions().setInstances(ConfigStore.Global.getInteger(com.uid2.core.Const.Config.ServiceInstancesProp))); } catch (Exception e) { - System.out.println("failed to initialize core verticle: " + e.getMessage()); + LOGGER.error("failed to initialize core verticle: {}", e.getMessage()); System.exit(-1); } - - createVertxInstancesMetric(); - createVertxEventLoopsMetric(); - - vertx.deployVerticle(enclaveRotatingVerticle); - vertx.deployVerticle(operatorRotatingVerticle); - vertx.deployVerticle(cloudEncryptionKeyRotatingVerticle); - vertx.deployVerticle(coreVerticle, new DeploymentOptions().setInstances(vertxServiceInstances)); }); } @@ -184,9 +178,7 @@ private static void setupMetrics(MicrometerMetricsOptions metricOptions) { BackendRegistries.setupBackend(metricOptions, null); // As of now default backend registry should have been created - if (BackendRegistries.getDefaultNow() instanceof PrometheusMeterRegistry) { - PrometheusMeterRegistry prometheusRegistry = (PrometheusMeterRegistry) BackendRegistries.getDefaultNow(); - + if (BackendRegistries.getDefaultNow() instanceof PrometheusMeterRegistry prometheusRegistry) { // see also https://micrometer.io/docs/registry/prometheus prometheusRegistry.config() // providing common renaming for prometheus metric, e.g. "hello.world" to "hello_world" @@ -195,8 +187,8 @@ private static void setupMetrics(MicrometerMetricsOptions metricOptions) { actualPath -> HTTPPathMetricFilter.filterPath(actualPath, Endpoints.pathSet()))) // Don't record metrics for 404s. .meterFilter(MeterFilter.deny(id -> - id.getName().startsWith(MetricsDomain.HTTP_SERVER.getPrefix()) && - Objects.equals(id.getTag(Label.HTTP_CODE.toString()), "404"))) + id.getName().startsWith(MetricsDomain.HTTP_SERVER.getPrefix()) && + Objects.equals(id.getTag(Label.HTTP_CODE.toString()), "404"))) // adding common labels .commonTags("application", "uid2-core"); @@ -206,42 +198,26 @@ private static void setupMetrics(MicrometerMetricsOptions metricOptions) { // retrieve image version (will unify when uid2-common is used) String version = Optional.ofNullable(System.getenv("IMAGE_VERSION")).orElse("unknown"); - Gauge appStatus = Gauge - .builder("app.status", () -> 1) + Gauge.builder("app.status", () -> 1) .description("application version and status") .tags("version", version) .register(Metrics.globalRegistry); } - private static void createVertxInstancesMetric() { - Gauge.builder("uid2.vertx_service_instances", () -> vertxServiceInstances) + private static void createVertxMetrics() { + Gauge.builder("uid2.vertx_service_instances", () -> ConfigStore.Global.getInteger(com.uid2.core.Const.Config.ServiceInstancesProp)) .description("gauge for number of vertx service instances requested") .register(Metrics.globalRegistry); - } - private static void createVertxEventLoopsMetric() { + Gauge.builder("uid2.vertx_worker_pool_size", () -> VERTX_WORKER_POOL_SIZE) + .description("gauge for vertx worker pool size requested") + .register(Metrics.globalRegistry); + Gauge.builder("uid2.vertx_event_loop_threads", () -> VertxOptions.DEFAULT_EVENT_LOOP_POOL_SIZE) .description("gauge for number of vertx event loop threads") .register(Metrics.globalRegistry); } - - /* - private static CommandLine parseArgs(String[] args) { - final CLI cli = CLI.create("uid2-core") - .setSummary("run uid2 core service") - .addOption(new Option() - .setLongName("config") - .setDescription("path to configuration file") - .setRequired(true)) - .addOption(new Option() - .setLongName("secrets") - .setDescription("path to secrets file") - .setRequired(true)); - return cli.parse(Arrays.asList(args)); - } - */ - private static VertxOptions getVertxOptions(MicrometerMetricsOptions metricOptions) { final int threadBlockedCheckInterval = Utils.isProductionEnvironment() ? 60 * 1000 @@ -249,7 +225,8 @@ private static VertxOptions getVertxOptions(MicrometerMetricsOptions metricOptio return new VertxOptions() .setMetricsOptions(metricOptions) - .setBlockedThreadCheckInterval(threadBlockedCheckInterval); + .setBlockedThreadCheckInterval(threadBlockedCheckInterval) + .setWorkerPoolSize(VERTX_WORKER_POOL_SIZE); } private static MicrometerMetricsOptions getMetricOptions(VertxPrometheusOptions promOptions) { diff --git a/src/main/java/com/uid2/core/service/ClientMetadataProvider.java b/src/main/java/com/uid2/core/service/ClientMetadataProvider.java index 36935274..0f3af083 100644 --- a/src/main/java/com/uid2/core/service/ClientMetadataProvider.java +++ b/src/main/java/com/uid2/core/service/ClientMetadataProvider.java @@ -1,44 +1,18 @@ package com.uid2.core.service; -import com.uid2.core.model.SecretStore; import com.uid2.core.util.OperatorInfo; -import com.uid2.shared.auth.OperatorType; import com.uid2.shared.cloud.ICloudStorage; -import io.vertx.core.json.Json; -import io.vertx.core.json.JsonObject; - -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; - -import static com.uid2.core.util.MetadataHelper.getMetadataPathName; -import static com.uid2.core.util.MetadataHelper.readToEndAsString; - -public class ClientMetadataProvider implements IClientMetadataProvider { - - public static final String ClientsMetadataPathName = "clients_metadata_path"; - - private final ICloudStorage metadataStreamProvider; - private final ICloudStorage downloadUrlGenerator; - - @Override - public String getMetadata(OperatorInfo info) throws Exception { - String pathname = getMetadataPathName(info, SecretStore.Global.get(ClientsMetadataPathName)); - String original = readToEndAsString(metadataStreamProvider.download(pathname)); - JsonObject main = (JsonObject) Json.decodeValue(original); - JsonObject obj = main.getJsonObject("client_keys"); - String location = obj.getString("location"); - obj.put("location", downloadUrlGenerator.preSignUrl(location).toString()); - return main.encode(); - } +public class ClientMetadataProvider extends MetadataProvider { public ClientMetadataProvider(ICloudStorage cloudStorage) { - this.metadataStreamProvider = this.downloadUrlGenerator = cloudStorage; + super(cloudStorage); } public ClientMetadataProvider(ICloudStorage fileStreamProvider, ICloudStorage downloadUrlGenerator) { - this.metadataStreamProvider = fileStreamProvider; - this.downloadUrlGenerator = downloadUrlGenerator; + super(fileStreamProvider, downloadUrlGenerator); } + public String getMetadata(OperatorInfo info) throws Exception { + return getMetadata(info, "clients_metadata_path", "client_keys"); + } } diff --git a/src/main/java/com/uid2/core/service/ClientSideKeypairMetadataProvider.java b/src/main/java/com/uid2/core/service/ClientSideKeypairMetadataProvider.java index df0d2830..2ac2d237 100644 --- a/src/main/java/com/uid2/core/service/ClientSideKeypairMetadataProvider.java +++ b/src/main/java/com/uid2/core/service/ClientSideKeypairMetadataProvider.java @@ -1,38 +1,18 @@ package com.uid2.core.service; -import com.uid2.core.model.SecretStore; import com.uid2.core.util.OperatorInfo; import com.uid2.shared.cloud.ICloudStorage; -import com.uid2.shared.store.CloudPath; -import com.uid2.shared.store.scope.GlobalScope; -import io.vertx.core.json.Json; -import io.vertx.core.json.JsonObject; - -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; - -import static com.uid2.core.util.MetadataHelper.getMetadataPathName; -import static com.uid2.core.util.MetadataHelper.readToEndAsString; - -public class ClientSideKeypairMetadataProvider implements IClientSideKeypairMetadataProvider { - public static final String ClientSideKeypairMetadataPathName = "client_side_keypairs_metadata_path"; - - private final ICloudStorage metadataStreamProvider; - private final ICloudStorage downloadUrlGenerator; +public class ClientSideKeypairMetadataProvider extends MetadataProvider { public ClientSideKeypairMetadataProvider(ICloudStorage cloudStorage) { - this.metadataStreamProvider = this.downloadUrlGenerator = cloudStorage; + super(cloudStorage); + } + + public ClientSideKeypairMetadataProvider(ICloudStorage fileStreamProvider, ICloudStorage downloadUrlGenerator) { + super(fileStreamProvider, downloadUrlGenerator); } - @Override public String getMetadata(OperatorInfo info) throws Exception { - String pathname = getMetadataPathName(info, SecretStore.Global.get(ClientSideKeypairMetadataPathName)); - String original = readToEndAsString(metadataStreamProvider.download(pathname)); - JsonObject main = (JsonObject) Json.decodeValue(original); - JsonObject obj = main.getJsonObject("client_side_keypairs"); - String location = obj.getString("location"); - obj.put("location", downloadUrlGenerator.preSignUrl(location).toString()); - return main.encode(); + return getMetadata(info, "client_side_keypairs_metadata_path", "client_side_keypairs"); } } diff --git a/src/main/java/com/uid2/core/service/IClientMetadataProvider.java b/src/main/java/com/uid2/core/service/IClientMetadataProvider.java deleted file mode 100644 index affe57c6..00000000 --- a/src/main/java/com/uid2/core/service/IClientMetadataProvider.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.uid2.core.service; - -import com.uid2.core.util.OperatorInfo; -import com.uid2.shared.auth.OperatorType; - -public interface IClientMetadataProvider { - String getMetadata(OperatorInfo info) throws Exception; -} diff --git a/src/main/java/com/uid2/core/service/IClientSideKeypairMetadataProvider.java b/src/main/java/com/uid2/core/service/IClientSideKeypairMetadataProvider.java deleted file mode 100644 index 230516cc..00000000 --- a/src/main/java/com/uid2/core/service/IClientSideKeypairMetadataProvider.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.uid2.core.service; - - -import com.uid2.core.util.OperatorInfo; - -public interface IClientSideKeypairMetadataProvider { - String getMetadata(OperatorInfo info) throws Exception; -} diff --git a/src/main/java/com/uid2/core/service/IKeyAclMetadataProvider.java b/src/main/java/com/uid2/core/service/IKeyAclMetadataProvider.java deleted file mode 100644 index ac588574..00000000 --- a/src/main/java/com/uid2/core/service/IKeyAclMetadataProvider.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.uid2.core.service; - -import com.uid2.core.util.OperatorInfo; -import com.uid2.shared.auth.OperatorType; - -public interface IKeyAclMetadataProvider { - String getMetadata(OperatorInfo info) throws Exception; -} diff --git a/src/main/java/com/uid2/core/service/IKeyMetadataProvider.java b/src/main/java/com/uid2/core/service/IKeyMetadataProvider.java deleted file mode 100644 index 20e67214..00000000 --- a/src/main/java/com/uid2/core/service/IKeyMetadataProvider.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.uid2.core.service; - -import com.uid2.core.util.OperatorInfo; -import com.uid2.shared.auth.OperatorType; - -public interface IKeyMetadataProvider { - String getMetadata(OperatorInfo info) throws Exception; -} diff --git a/src/main/java/com/uid2/core/service/IKeysetKeyMetadataProvider.java b/src/main/java/com/uid2/core/service/IKeysetKeyMetadataProvider.java deleted file mode 100644 index 972019cd..00000000 --- a/src/main/java/com/uid2/core/service/IKeysetKeyMetadataProvider.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.uid2.core.service; - -import com.uid2.core.util.OperatorInfo; - -public interface IKeysetKeyMetadataProvider { - String getMetadata(OperatorInfo info) throws Exception; -} diff --git a/src/main/java/com/uid2/core/service/IKeysetMetadataProvider.java b/src/main/java/com/uid2/core/service/IKeysetMetadataProvider.java deleted file mode 100644 index a754c42c..00000000 --- a/src/main/java/com/uid2/core/service/IKeysetMetadataProvider.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.uid2.core.service; - -import com.uid2.core.util.OperatorInfo; - -public interface IKeysetMetadataProvider { - String getMetadata(OperatorInfo info) throws Exception; -} diff --git a/src/main/java/com/uid2/core/service/IOperatorMetadataProvider.java b/src/main/java/com/uid2/core/service/IOperatorMetadataProvider.java deleted file mode 100644 index 1e8ebd89..00000000 --- a/src/main/java/com/uid2/core/service/IOperatorMetadataProvider.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.uid2.core.service; - -public interface IOperatorMetadataProvider { - String getMetadata() throws Exception; -} diff --git a/src/main/java/com/uid2/core/service/IPartnerMetadataProvider.java b/src/main/java/com/uid2/core/service/IPartnerMetadataProvider.java deleted file mode 100644 index 46fd93ec..00000000 --- a/src/main/java/com/uid2/core/service/IPartnerMetadataProvider.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.uid2.core.service; - -public interface IPartnerMetadataProvider { - String getMetadata() throws Exception; -} diff --git a/src/main/java/com/uid2/core/service/ISaltMetadataProvider.java b/src/main/java/com/uid2/core/service/ISaltMetadataProvider.java deleted file mode 100644 index 1019d6ab..00000000 --- a/src/main/java/com/uid2/core/service/ISaltMetadataProvider.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.uid2.core.service; - -import com.uid2.core.util.OperatorInfo; - -public interface ISaltMetadataProvider { - String getMetadata(OperatorInfo info) throws Exception; -} diff --git a/src/main/java/com/uid2/core/service/IServiceLinkMetadataProvider.java b/src/main/java/com/uid2/core/service/IServiceLinkMetadataProvider.java deleted file mode 100644 index b260d943..00000000 --- a/src/main/java/com/uid2/core/service/IServiceLinkMetadataProvider.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.uid2.core.service; - -public interface IServiceLinkMetadataProvider { - String getMetadata() throws Exception; -} diff --git a/src/main/java/com/uid2/core/service/IServiceMetadataProvider.java b/src/main/java/com/uid2/core/service/IServiceMetadataProvider.java deleted file mode 100644 index dfd89bf0..00000000 --- a/src/main/java/com/uid2/core/service/IServiceMetadataProvider.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.uid2.core.service; - -public interface IServiceMetadataProvider { - String getMetadata() throws Exception; -} diff --git a/src/main/java/com/uid2/core/service/ISiteMetadataProvider.java b/src/main/java/com/uid2/core/service/ISiteMetadataProvider.java deleted file mode 100644 index 993f55fd..00000000 --- a/src/main/java/com/uid2/core/service/ISiteMetadataProvider.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.uid2.core.service; - -import com.uid2.core.util.OperatorInfo; - -public interface ISiteMetadataProvider { - String getMetadata(OperatorInfo info) throws Exception; -} diff --git a/src/main/java/com/uid2/core/service/KeyAclMetadataProvider.java b/src/main/java/com/uid2/core/service/KeyAclMetadataProvider.java index 8e81bbdf..ed3b0eab 100644 --- a/src/main/java/com/uid2/core/service/KeyAclMetadataProvider.java +++ b/src/main/java/com/uid2/core/service/KeyAclMetadataProvider.java @@ -1,33 +1,19 @@ package com.uid2.core.service; -import com.uid2.core.model.SecretStore; import com.uid2.core.util.OperatorInfo; import com.uid2.shared.Const; import com.uid2.shared.cloud.ICloudStorage; -import io.vertx.core.json.Json; -import io.vertx.core.json.JsonObject; - -import static com.uid2.core.util.MetadataHelper.getMetadataPathName; -import static com.uid2.core.util.MetadataHelper.readToEndAsString; - -public class KeyAclMetadataProvider implements IKeyAclMetadataProvider { - - private final ICloudStorage metadataStreamProvider; - private final ICloudStorage downloadUrlGenerator; +public class KeyAclMetadataProvider extends MetadataProvider { public KeyAclMetadataProvider(ICloudStorage cloudStorage) { - this.metadataStreamProvider = this.downloadUrlGenerator = cloudStorage; + super(cloudStorage); } - @Override - public String getMetadata(OperatorInfo info) throws Exception { - String pathname = getMetadataPathName(info.getOperatorType(), info.getSiteId(), SecretStore.Global.get(Const.Config.KeysAclMetadataPathProp)); - String original = readToEndAsString(metadataStreamProvider.download(pathname)); - JsonObject main = (JsonObject) Json.decodeValue(original); - JsonObject obj = main.getJsonObject("keys_acl"); - String location = obj.getString("location"); - obj.put("location", downloadUrlGenerator.preSignUrl(location).toString()); - return main.encode(); + public KeyAclMetadataProvider(ICloudStorage fileStreamProvider, ICloudStorage downloadUrlGenerator) { + super(fileStreamProvider, downloadUrlGenerator); } + public String getMetadata(OperatorInfo info) throws Exception { + return getMetadata(info, Const.Config.KeysAclMetadataPathProp, "keys_acl"); + } } diff --git a/src/main/java/com/uid2/core/service/KeyMetadataProvider.java b/src/main/java/com/uid2/core/service/KeyMetadataProvider.java index a68147ca..f8bfad40 100644 --- a/src/main/java/com/uid2/core/service/KeyMetadataProvider.java +++ b/src/main/java/com/uid2/core/service/KeyMetadataProvider.java @@ -1,34 +1,18 @@ package com.uid2.core.service; -import com.uid2.core.model.SecretStore; import com.uid2.core.util.OperatorInfo; import com.uid2.shared.cloud.ICloudStorage; -import io.vertx.core.json.Json; -import io.vertx.core.json.JsonObject; - - -import static com.uid2.core.util.MetadataHelper.getMetadataPathName; -import static com.uid2.core.util.MetadataHelper.readToEndAsString; - -public class KeyMetadataProvider implements IKeyMetadataProvider { - - public static final String KeysMetadataPathName = "keys_metadata_path"; - - private final ICloudStorage metadataStreamProvider; - private final ICloudStorage downloadUrlGenerator; +public class KeyMetadataProvider extends MetadataProvider { public KeyMetadataProvider(ICloudStorage cloudStorage) { - this.metadataStreamProvider = this.downloadUrlGenerator = cloudStorage; + super(cloudStorage); + } + + public KeyMetadataProvider(ICloudStorage fileStreamProvider, ICloudStorage downloadUrlGenerator) { + super(fileStreamProvider, downloadUrlGenerator); } - @Override public String getMetadata(OperatorInfo info) throws Exception { - String pathname = getMetadataPathName(info.getOperatorType(), info.getSiteId(), SecretStore.Global.get(KeysMetadataPathName)); - String original = readToEndAsString(metadataStreamProvider.download(pathname)); - JsonObject main = (JsonObject) Json.decodeValue(original); - JsonObject obj = main.getJsonObject("keys"); - String location = obj.getString("location"); - obj.put("location", downloadUrlGenerator.preSignUrl(location).toString()); - return main.encode(); + return getMetadata(info, "keys_metadata_path", "keys"); } } diff --git a/src/main/java/com/uid2/core/service/KeysetKeyMetadataProvider.java b/src/main/java/com/uid2/core/service/KeysetKeyMetadataProvider.java new file mode 100644 index 00000000..fb1a65b3 --- /dev/null +++ b/src/main/java/com/uid2/core/service/KeysetKeyMetadataProvider.java @@ -0,0 +1,19 @@ +package com.uid2.core.service; + +import com.uid2.core.util.OperatorInfo; +import com.uid2.shared.Const; +import com.uid2.shared.cloud.ICloudStorage; + +public class KeysetKeyMetadataProvider extends MetadataProvider { + public KeysetKeyMetadataProvider(ICloudStorage cloudStorage) { + super(cloudStorage); + } + + public KeysetKeyMetadataProvider(ICloudStorage fileStreamProvider, ICloudStorage downloadUrlGenerator) { + super(fileStreamProvider, downloadUrlGenerator); + } + + public String getMetadata(OperatorInfo info) throws Exception { + return getMetadata(info, Const.Config.KeysetKeysMetadataPathProp, "keyset_keys"); + } +} diff --git a/src/main/java/com/uid2/core/service/KeysetKeysMetadataProvider.java b/src/main/java/com/uid2/core/service/KeysetKeysMetadataProvider.java deleted file mode 100644 index f013ee2d..00000000 --- a/src/main/java/com/uid2/core/service/KeysetKeysMetadataProvider.java +++ /dev/null @@ -1,32 +0,0 @@ -package com.uid2.core.service; - -import com.uid2.core.util.OperatorInfo; -import com.uid2.shared.Const; -import com.uid2.shared.cloud.ICloudStorage; -import com.uid2.core.model.SecretStore; -import io.vertx.core.json.Json; -import io.vertx.core.json.JsonObject; - - -import static com.uid2.core.util.MetadataHelper.getMetadataPathName; -import static com.uid2.core.util.MetadataHelper.readToEndAsString; - -public class KeysetKeysMetadataProvider implements IKeysetKeyMetadataProvider { - private final ICloudStorage metadataStreamProvider; - private final ICloudStorage downloadUrlGenerator; - - public KeysetKeysMetadataProvider(ICloudStorage cloudStorage) { - this.metadataStreamProvider = this.downloadUrlGenerator = cloudStorage; - } - - @Override - public String getMetadata(OperatorInfo info) throws Exception { - String pathname = getMetadataPathName(info, SecretStore.Global.get(Const.Config.KeysetKeysMetadataPathProp)); - String original = readToEndAsString(metadataStreamProvider.download(pathname)); - JsonObject main = (JsonObject) Json.decodeValue(original); - JsonObject obj = main.getJsonObject("keyset_keys"); - String location = obj.getString("location"); - obj.put("location", downloadUrlGenerator.preSignUrl(location).toString()); - return main.encode(); - } -} diff --git a/src/main/java/com/uid2/core/service/KeysetMetadataProvider.java b/src/main/java/com/uid2/core/service/KeysetMetadataProvider.java index 208eea85..bc6c49d3 100644 --- a/src/main/java/com/uid2/core/service/KeysetMetadataProvider.java +++ b/src/main/java/com/uid2/core/service/KeysetMetadataProvider.java @@ -2,30 +2,18 @@ import com.uid2.core.util.OperatorInfo; import com.uid2.shared.cloud.ICloudStorage; -import com.uid2.core.model.SecretStore; import com.uid2.shared.Const; -import io.vertx.core.json.Json; -import io.vertx.core.json.JsonObject; - -import static com.uid2.core.util.MetadataHelper.getMetadataPathName; -import static com.uid2.core.util.MetadataHelper.readToEndAsString; - -public class KeysetMetadataProvider implements IKeysetMetadataProvider{ - private final ICloudStorage metadataStreamProvider; - private final ICloudStorage downloadUrlGenerator; +public class KeysetMetadataProvider extends MetadataProvider { public KeysetMetadataProvider(ICloudStorage cloudStorage) { - this.metadataStreamProvider = this.downloadUrlGenerator = cloudStorage; + super(cloudStorage); + } + + public KeysetMetadataProvider(ICloudStorage fileStreamProvider, ICloudStorage downloadUrlGenerator) { + super(fileStreamProvider, downloadUrlGenerator); } - @Override public String getMetadata(OperatorInfo info) throws Exception { - String pathname = getMetadataPathName(info, SecretStore.Global.get(Const.Config.KeysetsMetadataPathProp)); - String original = readToEndAsString(metadataStreamProvider.download(pathname)); - JsonObject main = (JsonObject) Json.decodeValue(original); - JsonObject obj = main.getJsonObject("keysets"); - String location = obj.getString("location"); - obj.put("location", downloadUrlGenerator.preSignUrl(location).toString()); - return main.encode(); + return getMetadata(info, Const.Config.KeysetsMetadataPathProp, "keysets"); } } diff --git a/src/main/java/com/uid2/core/service/MetadataProvider.java b/src/main/java/com/uid2/core/service/MetadataProvider.java new file mode 100644 index 00000000..728c459f --- /dev/null +++ b/src/main/java/com/uid2/core/service/MetadataProvider.java @@ -0,0 +1,66 @@ +package com.uid2.core.service; + +import com.uid2.core.model.SecretStore; +import com.uid2.core.util.OperatorInfo; +import com.uid2.shared.cloud.ICloudStorage; +import com.uid2.shared.store.CloudPath; +import com.uid2.shared.store.scope.GlobalScope; +import io.vertx.core.json.Json; +import io.vertx.core.json.JsonArray; +import io.vertx.core.json.JsonObject; +import lombok.Getter; + +import static com.uid2.core.util.MetadataHelper.*; + +@Getter +public abstract class MetadataProvider { + private final ICloudStorage metadataStreamProvider; + private final ICloudStorage downloadUrlGenerator; + + protected MetadataProvider(ICloudStorage cloudStorage) { + this.metadataStreamProvider = this.downloadUrlGenerator = cloudStorage; + } + + protected MetadataProvider(ICloudStorage fileStreamProvider, ICloudStorage downloadUrlGenerator) { + this.metadataStreamProvider = fileStreamProvider; + this.downloadUrlGenerator = downloadUrlGenerator; + } + + protected String getMetadata(String metadataPath, String keyName) throws Exception { + String json = readToEndAsString(metadataStreamProvider.download(SecretStore.Global.get(metadataPath))); + return getMetadataJson(json, keyName); + } + + protected String getMetadata(OperatorInfo info, String metadataPath, String keyName) throws Exception { + String pathName = getMetadataPathName(info, SecretStore.Global.get(metadataPath)); + String json = readToEndAsString(metadataStreamProvider.download(pathName)); + return getMetadataJson(json, keyName); + } + + protected String getArrayMetadata(OperatorInfo info, String metadataPath, String keyName) throws Exception { + String pathname = getMetadataPathNameOldPrivateNoSite(info, SecretStore.Global.get(metadataPath)); + String original = readToEndAsString(metadataStreamProvider.download(pathname)); + JsonObject main = (JsonObject) Json.decodeValue(original); + JsonArray arr = main.getJsonArray(keyName); + for(int i = 0; i < arr.size(); ++i) { + JsonObject obj = arr.getJsonObject(i); + String location = obj.getString("location"); + obj.put("location", getDownloadUrlGenerator().preSignUrl(location).toString()); + } + return main.encode(); + } + + protected String getGlobalScopeMetadata(String metadataPath, String keyName) throws Exception { + String pathName = new GlobalScope(new CloudPath(SecretStore.Global.get(metadataPath))).getMetadataPath().toString(); + String json = readToEndAsString(metadataStreamProvider.download(pathName)); + return getMetadataJson(json, keyName); + } + + private String getMetadataJson(String json, String keyName) throws Exception { + JsonObject main = (JsonObject) Json.decodeValue(json); + JsonObject obj = main.getJsonObject(keyName); + String location = obj.getString("location"); + obj.put("location", downloadUrlGenerator.preSignUrl(location).toString()); + return main.encode(); + } +} diff --git a/src/main/java/com/uid2/core/service/OperatorMetadataProvider.java b/src/main/java/com/uid2/core/service/OperatorMetadataProvider.java index e458d429..d150c7ef 100644 --- a/src/main/java/com/uid2/core/service/OperatorMetadataProvider.java +++ b/src/main/java/com/uid2/core/service/OperatorMetadataProvider.java @@ -1,39 +1,17 @@ package com.uid2.core.service; -import com.uid2.core.model.SecretStore; import com.uid2.shared.cloud.ICloudStorage; -import io.vertx.core.json.Json; -import io.vertx.core.json.JsonObject; - -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import static com.uid2.core.util.MetadataHelper.readToEndAsString; - -public class OperatorMetadataProvider implements IOperatorMetadataProvider { - - public static final String OperatorsMetadataPathName = "operators_metadata_path"; - - private final ICloudStorage metadataStreamProvider; - private final ICloudStorage downloadUrlGenerator; - - @Override - public String getMetadata() throws Exception { - String original = readToEndAsString(metadataStreamProvider.download(SecretStore.Global.get(OperatorsMetadataPathName))); - JsonObject main = (JsonObject) Json.decodeValue(original); - JsonObject obj = main.getJsonObject("operators"); - String location = obj.getString("location"); - obj.put("location", downloadUrlGenerator.preSignUrl(location).toString()); - return main.encode(); - } +public class OperatorMetadataProvider extends MetadataProvider { public OperatorMetadataProvider(ICloudStorage cloudStorage) { - this.metadataStreamProvider = this.downloadUrlGenerator = cloudStorage; + super(cloudStorage); } public OperatorMetadataProvider(ICloudStorage fileStreamProvider, ICloudStorage downloadUrlGenerator) { - this.metadataStreamProvider = fileStreamProvider; - this.downloadUrlGenerator = downloadUrlGenerator; + super(fileStreamProvider, downloadUrlGenerator); } + public String getMetadata() throws Exception { + return getMetadata("operators_metadata_path", "operators"); + } } diff --git a/src/main/java/com/uid2/core/service/PartnerMetadataProvider.java b/src/main/java/com/uid2/core/service/PartnerMetadataProvider.java index 24d6d2e8..38e73c43 100644 --- a/src/main/java/com/uid2/core/service/PartnerMetadataProvider.java +++ b/src/main/java/com/uid2/core/service/PartnerMetadataProvider.java @@ -1,38 +1,17 @@ package com.uid2.core.service; -import com.uid2.core.model.SecretStore; import com.uid2.shared.cloud.ICloudStorage; -import io.vertx.core.json.Json; -import io.vertx.core.json.JsonObject; - -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import static com.uid2.core.util.MetadataHelper.readToEndAsString; - -public class PartnerMetadataProvider implements IPartnerMetadataProvider { - - public static final String PartnersMetadataPathName = "partners_metadata_path"; - - private final ICloudStorage metadataStreamProvider; - private final ICloudStorage downloadUrlGenerator; - - @Override - public String getMetadata() throws Exception { - String original = readToEndAsString(metadataStreamProvider.download(SecretStore.Global.get(PartnersMetadataPathName))); - JsonObject main = (JsonObject) Json.decodeValue(original); - JsonObject obj = main.getJsonObject("partners"); - String location = obj.getString("location"); - obj.put("location", downloadUrlGenerator.preSignUrl(location).toString()); - return main.encode(); - } +public class PartnerMetadataProvider extends MetadataProvider { public PartnerMetadataProvider(ICloudStorage cloudStorage) { - this.metadataStreamProvider = this.downloadUrlGenerator = cloudStorage; + super(cloudStorage); } public PartnerMetadataProvider(ICloudStorage fileStreamProvider, ICloudStorage downloadUrlGenerator) { - this.metadataStreamProvider = fileStreamProvider; - this.downloadUrlGenerator = downloadUrlGenerator; + super(fileStreamProvider, downloadUrlGenerator); + } + + public String getMetadata() throws Exception { + return getMetadata("partners_metadata_path", "partners"); } } diff --git a/src/main/java/com/uid2/core/service/SaltMetadataProvider.java b/src/main/java/com/uid2/core/service/SaltMetadataProvider.java index f7500aca..0b42dc13 100644 --- a/src/main/java/com/uid2/core/service/SaltMetadataProvider.java +++ b/src/main/java/com/uid2/core/service/SaltMetadataProvider.java @@ -1,48 +1,18 @@ package com.uid2.core.service; -import com.uid2.core.model.SecretStore; import com.uid2.core.util.OperatorInfo; import com.uid2.shared.cloud.ICloudStorage; -import io.vertx.core.json.Json; -import io.vertx.core.json.JsonArray; -import io.vertx.core.json.JsonObject; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; - -import static com.uid2.core.util.MetadataHelper.*; - -public class SaltMetadataProvider implements ISaltMetadataProvider { - private static final Logger LOGGER = LoggerFactory.getLogger(SaltMetadataProvider.class); - - public static final String SaltsMetadataPathName = "salts_metadata_path"; - - private final ICloudStorage metadataStreamProvider; - private final ICloudStorage downloadUrlGenerator; +public class SaltMetadataProvider extends MetadataProvider { public SaltMetadataProvider(ICloudStorage cloudStorage) { - this.metadataStreamProvider = this.downloadUrlGenerator = cloudStorage; + super(cloudStorage); } public SaltMetadataProvider(ICloudStorage fileStreamProvider, ICloudStorage downloadUrlGenerator) { - this.metadataStreamProvider = fileStreamProvider; - this.downloadUrlGenerator = downloadUrlGenerator; + super(fileStreamProvider, downloadUrlGenerator); } - @Override public String getMetadata(OperatorInfo info) throws Exception { - String pathname = getMetadataPathNameOldPrivateNoSite(info, SecretStore.Global.get(SaltsMetadataPathName)); - String original = readToEndAsString(metadataStreamProvider.download(pathname)); - JsonObject main = (JsonObject) Json.decodeValue(original); - JsonArray salts = main.getJsonArray("salts"); - for(int i=0;i { OperatorInfo info = OperatorInfo.getOperatorInfo(rc); if (info.getOperatorType() != OperatorType.PUBLIC) { Error("error", 403, rc, "endpoint /sites/refresh is for public operators only"); - return; + return null; } - rc.response().putHeader(HttpHeaders.CONTENT_TYPE, "application/json") - .end(siteMetadataProvider.getMetadata(info)); - } catch (Exception e) { - logger.warn("exception in handleSiteRefresh: " + e.getMessage(), e); - Error("error", 500, rc, "error processing sites refresh"); - } + return siteMetadataProvider.getMetadata(info); + }, "handleSiteRefresh", "sites"); } private void handleSaltRefresh(RoutingContext rc) { - try { + handleRefresh(rc, () -> { OperatorInfo info = OperatorInfo.getOperatorInfo(rc); - rc.response().putHeader(HttpHeaders.CONTENT_TYPE, "application/json") - .end(saltMetadataProvider.getMetadata(info)); - } catch (Exception e) { - logger.warn("exception in handleSaltRefresh: " + e.getMessage(), e); - Error("error", 500, rc, "error processing salt refresh"); - } + return saltMetadataProvider.getMetadata(info); + }, "handleSaltRefresh", "salt"); } private void handleKeyRefresh(RoutingContext rc) { - try { + handleRefresh(rc, () -> { OperatorInfo info = OperatorInfo.getOperatorInfo(rc); - rc.response().putHeader(HttpHeaders.CONTENT_TYPE, "application/json") - .end(keyMetadataProvider.getMetadata(info)); - } catch (Exception e) { - logger.warn("exception in handleKeyRefresh: " + e.getMessage(), e); - Error("error", 500, rc, "error processing key refresh"); - } + return keyMetadataProvider.getMetadata(info); + }, "handleKeyRefresh", "key"); } private void handleKeyAclRefresh(RoutingContext rc) { - try { + handleRefresh(rc, () -> { OperatorInfo info = OperatorInfo.getOperatorInfo(rc); - rc.response().putHeader(HttpHeaders.CONTENT_TYPE, "application/json") - .end(keyAclMetadataProvider.getMetadata(info)); - } catch (Exception e) { - logger.warn("exception in handleKeyAclRefresh: " + e.getMessage(), e); - Error("error", 500, rc, "error processing key acl refresh"); - } + return keyAclMetadataProvider.getMetadata(info); + }, "handleKeyAclRefresh", "key acl"); } private void handleKeysetRefresh(RoutingContext rc) { - try { + handleRefresh(rc, () -> { OperatorInfo info = OperatorInfo.getOperatorInfo(rc); - rc.response().putHeader(HttpHeaders.CONTENT_TYPE, "application/json") - .end(keysetMetadataProvider.getMetadata(info)); - } catch (Exception e) { - logger.warn("exception in handleKeysetRefresh: " + e.getMessage(), e); - Error("error", 500, rc, "error processing key refresh"); - } + return keysetMetadataProvider.getMetadata(info); + }, "handleKeysetRefresh", "keyset"); } private void handleKeysetKeyRefresh(RoutingContext rc) { - try { + handleRefresh(rc, () -> { OperatorInfo info = OperatorInfo.getOperatorInfo(rc); - rc.response().putHeader(HttpHeaders.CONTENT_TYPE, "application/json") - .end(keysetKeyMetadataProvider.getMetadata(info)); - } catch (Exception e) { - logger.warn("exception in handleKeysetKeyRefresh: " + e.getMessage(), e); - Error("error", 500, rc, "error processing key refresh"); - } + return keysetKeyMetadataProvider.getMetadata(info); + }, "handleKeysetKeyRefresh", "keyset key"); } private void handleClientRefresh(RoutingContext rc) { - try { + handleRefresh(rc, () -> { OperatorInfo info = OperatorInfo.getOperatorInfo(rc); - rc.response().putHeader(HttpHeaders.CONTENT_TYPE, "application/json") - .end(clientMetadataProvider.getMetadata(info)); - } catch (Exception e) { - logger.warn("exception in handleClientRefresh: " + e.getMessage(), e); - Error("error", 500, rc, "error processing client refresh"); - } + return clientMetadataProvider.getMetadata(info); + }, "handleClientRefresh", "client"); } private void handleClientSideKeypairRefresh(RoutingContext rc) { - try { + handleRefresh(rc, () -> { OperatorInfo info = OperatorInfo.getOperatorInfo(rc); if (info.getOperatorType() != OperatorType.PUBLIC) { Error("error", 403, rc, "endpoint /client_side_keypairs/refresh is for public operators only"); - return; + return null; } - rc.response().putHeader(HttpHeaders.CONTENT_TYPE, "application/json") - .end(clientSideKeypairMetadataProvider.getMetadata(info)); - } catch (Exception e) { - logger.warn("exception in handleClientSideKeypairRefresh: " + e.getMessage(), e); - Error("error", 500, rc, "error processing client_side_keypairs refresh"); - } + return clientSideKeypairMetadataProvider.getMetadata(info); + }, "handleClientSideKeypairRefresh", "client_side_keypairs"); } private void handleServiceRefresh(RoutingContext rc) { - try { + handleRefresh(rc, () -> { OperatorInfo info = OperatorInfo.getOperatorInfo(rc); if (info.getOperatorType() != OperatorType.PUBLIC) { Error("error", 403, rc, "endpoint /services/refresh is for public operators only"); - return; + return null; } - rc.response().putHeader(HttpHeaders.CONTENT_TYPE, "application/json") - .end(serviceMetadataProvider.getMetadata()); - } catch (Exception e) { - logger.warn("exception in handleServiceRefresh: " + e.getMessage(), e); - Error("error", 500, rc, "error processing services refresh"); - } + return serviceMetadataProvider.getMetadata(); + }, "handleServiceRefresh", "services"); } private void handleServiceLinkRefresh(RoutingContext rc) { - try { + handleRefresh(rc, () -> { OperatorInfo info = OperatorInfo.getOperatorInfo(rc); if (info.getOperatorType() != OperatorType.PUBLIC) { Error("error", 403, rc, "endpoint /service_links/refresh is for public operators only"); - return; + return null; } - rc.response().putHeader(HttpHeaders.CONTENT_TYPE, "application/json") - .end(serviceLinkMetadataProvider.getMetadata()); - } catch (Exception e) { - logger.warn("exception in handleServiceLinkRefresh: " + e.getMessage(), e); - Error("error", 500, rc, "error processing service_links refresh"); - } + return serviceLinkMetadataProvider.getMetadata(); + }, "handleServiceLinkRefresh", "service_links"); } private void handleOperatorRefresh(RoutingContext rc) { - try { + handleRefresh(rc, () -> { OperatorInfo info = OperatorInfo.getOperatorInfo(rc); - rc.response().putHeader(HttpHeaders.CONTENT_TYPE, "application/json") - .end(operatorMetadataProvider.getMetadata()); - } catch (Exception e) { - logger.warn("exception in handleOperatorRefresh: " + e.getMessage(), e); - Error("error", 500, rc, "error processing operator refresh"); - } + return operatorMetadataProvider.getMetadata(); + }, "handleOperatorRefresh", "operator"); } private void handlePartnerRefresh(RoutingContext rc) { - try { + handleRefresh(rc, () -> { OperatorInfo info = OperatorInfo.getOperatorInfo(rc); - rc.response().putHeader(HttpHeaders.CONTENT_TYPE, "application/json") - .end(partnerMetadataProvider.getMetadata()); + return partnerMetadataProvider.getMetadata(); + }, "handlePartnerRefresh", "partner"); + } + + private void handleRefresh(RoutingContext rc, Callable metadataFn, String refreshFunctionName, String refreshKeyName) { + Future future; + try { + future = vertx.executeBlocking(metadataFn, false); } catch (Exception e) { - logger.warn("exception in handlePartnerRefresh: " + e.getMessage(), e); - Error("error", 500, rc, "error processing partner refresh"); + logger.warn("exception in {}: {}", refreshFunctionName, e.getMessage(), e); + Error("error", 500, rc, String.format("error processing %s refresh", refreshKeyName)); + return; } + + future.onComplete(res -> { + if (res.succeeded()) { + if (!rc.response().ended()) { + rc.response().putHeader(HttpHeaders.CONTENT_TYPE, "application/json") + .end(res.result()); + } + } else { + logger.warn("exception in {}: {}", refreshFunctionName, res.cause().getMessage(), res.cause()); + Error("error", 500, rc, String.format("error processing %s refresh", refreshKeyName)); + } + }); } private void handleEnclaveChange(RoutingContext rc, boolean isUnregister) { @@ -699,7 +676,7 @@ private void handleTestListEnclaves(RoutingContext rc) { //endregion test endpoints public static void Success(RoutingContext rc, Object body) { - final JsonObject json = new JsonObject(new HashMap() { + final JsonObject json = new JsonObject(new HashMap<>() { { put("status", "success"); put("body", body); @@ -710,7 +687,7 @@ public static void Success(RoutingContext rc, Object body) { } public static void Error(String errorStatus, int statusCode, RoutingContext rc, String message) { - final JsonObject json = new JsonObject(new HashMap() { + final JsonObject json = new JsonObject(new HashMap<>() { { put("status", errorStatus); } diff --git a/src/test/java/com/uid2/core/model/TestConfigStore.java b/src/test/java/com/uid2/core/model/ConfigStoreTest.java similarity index 83% rename from src/test/java/com/uid2/core/model/TestConfigStore.java rename to src/test/java/com/uid2/core/model/ConfigStoreTest.java index 67a99e69..2c2e9586 100644 --- a/src/test/java/com/uid2/core/model/TestConfigStore.java +++ b/src/test/java/com/uid2/core/model/ConfigStoreTest.java @@ -1,54 +1,54 @@ -package com.uid2.core.model; - -import com.uid2.core.vertx.TestSiteSpecificMetadataPathDisabled; -import io.vertx.core.json.Json; -import io.vertx.core.json.JsonObject; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import java.io.IOException; - -import static com.uid2.shared.Utils.readToEndAsString; -import static org.junit.jupiter.api.Assertions.*; - -public class TestConfigStore { - private ConfigStore store; - - @BeforeEach - void loadConfig() throws IOException { - store = new ConfigStore(); - store.load(((JsonObject) Json.decodeValue(openFile("/com.uid2.core/model/test-config.json")))); - } - - @Test - void loadIntegerSuccess() { - Integer token_lifespan = store.getInteger("att_token_lifetime_seconds"); - - assertEquals(120, token_lifespan); - } - - @Test - void loadMissingIntegerReturnsNull() { - Integer t = store.getInteger("missing_key"); - - assertNull(t); - } - - @Test - void loadIntegerDefaultForMissingKeySuccess() { - Integer token_lifespan = store.getIntegerOrDefault("missing_key", 45); - - assertEquals(45, token_lifespan); - } - - @Test - void loadIntegerDefaultForKnownKeySuccess() { - Integer token_lifespan = store.getIntegerOrDefault("att_token_lifetime_seconds", 120); - - assertEquals(120, token_lifespan); - } - - String openFile(String filePath) throws IOException { - return readToEndAsString(TestSiteSpecificMetadataPathDisabled.class.getResourceAsStream(filePath)); - } -} +package com.uid2.core.model; + +import com.uid2.core.vertx.SiteSpecificMetadataPathDisabledTest; +import io.vertx.core.json.Json; +import io.vertx.core.json.JsonObject; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.io.IOException; + +import static com.uid2.shared.Utils.readToEndAsString; +import static org.junit.jupiter.api.Assertions.*; + +public class ConfigStoreTest { + private ConfigStore store; + + @BeforeEach + void loadConfig() throws IOException { + store = new ConfigStore(); + store.load(((JsonObject) Json.decodeValue(openFile("/com.uid2.core/model/test-config.json")))); + } + + @Test + void loadIntegerSuccess() { + Integer token_lifespan = store.getInteger("att_token_lifetime_seconds"); + + assertEquals(120, token_lifespan); + } + + @Test + void loadMissingIntegerReturnsNull() { + Integer t = store.getInteger("missing_key"); + + assertNull(t); + } + + @Test + void loadIntegerDefaultForMissingKeySuccess() { + Integer token_lifespan = store.getIntegerOrDefault("missing_key", 45); + + assertEquals(45, token_lifespan); + } + + @Test + void loadIntegerDefaultForKnownKeySuccess() { + Integer token_lifespan = store.getIntegerOrDefault("att_token_lifetime_seconds", 120); + + assertEquals(120, token_lifespan); + } + + String openFile(String filePath) throws IOException { + return readToEndAsString(SiteSpecificMetadataPathDisabledTest.class.getResourceAsStream(filePath)); + } +} diff --git a/src/test/java/com/uid2/services/TestAttestation.java b/src/test/java/com/uid2/core/service/AttestationTokenServiceTest.java similarity index 99% rename from src/test/java/com/uid2/services/TestAttestation.java rename to src/test/java/com/uid2/core/service/AttestationTokenServiceTest.java index 4f960692..b6ca8bc5 100644 --- a/src/test/java/com/uid2/services/TestAttestation.java +++ b/src/test/java/com/uid2/core/service/AttestationTokenServiceTest.java @@ -1,11 +1,10 @@ -package com.uid2.services; +package com.uid2.core.service; import com.uid2.shared.secure.AttestationFailure; import com.uid2.shared.secure.AttestationResult; import com.uid2.shared.secure.ICertificateProvider; import com.uid2.shared.secure.NitroCoreAttestationService; import com.uid2.shared.secure.nitro.InMemoryAWSCertificateStore; -import com.uid2.core.service.AttestationService; import com.uid2.shared.attest.AttestationToken; import com.uid2.shared.attest.AttestationTokenService; import org.junit.jupiter.api.Test; @@ -17,7 +16,7 @@ import static org.junit.jupiter.api.Assertions.*; -public class TestAttestation { +public class AttestationTokenServiceTest { @Test public void testGenerateAttestationToken() diff --git a/src/test/java/com/uid2/core/service/JWTTokenProviderTests.java b/src/test/java/com/uid2/core/service/JWTTokenProviderTest.java similarity index 96% rename from src/test/java/com/uid2/core/service/JWTTokenProviderTests.java rename to src/test/java/com/uid2/core/service/JWTTokenProviderTest.java index e62b2fc8..0b84b373 100644 --- a/src/test/java/com/uid2/core/service/JWTTokenProviderTests.java +++ b/src/test/java/com/uid2/core/service/JWTTokenProviderTest.java @@ -1,196 +1,196 @@ -package com.uid2.core.service; - -import com.uid2.core.model.ConfigStore; -import io.vertx.core.json.Json; -import io.vertx.core.json.JsonObject; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockito.ArgumentCaptor; -import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; -import software.amazon.awssdk.core.SdkBytes; -import software.amazon.awssdk.http.SdkHttpResponse; -import software.amazon.awssdk.regions.Region; -import software.amazon.awssdk.services.kms.KmsClient; -import software.amazon.awssdk.services.kms.KmsClientBuilder; -import software.amazon.awssdk.services.kms.model.KmsException; -import software.amazon.awssdk.services.kms.model.SignRequest; -import software.amazon.awssdk.services.kms.model.SignResponse; -import software.amazon.awssdk.services.kms.model.SigningAlgorithmSpec; - -import java.io.IOException; -import java.time.Clock; -import java.time.Instant; -import java.util.Base64; -import java.util.HashMap; -import java.util.Optional; - -import static com.uid2.shared.Utils.readToEndAsString; -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -public class JWTTokenProviderTests { - private final JsonObject defaultHeaders = new JsonObject(); - - private KmsClient mockClient; - private ArgumentCaptor capturedSignRequest; - private JsonObject config; - - @BeforeEach - void setUp() throws IOException { - this.config = ((JsonObject) Json.decodeValue(openFile("/com.uid2.core/service/jwt-token-provider-test-config.json"))); - ConfigStore.Global.load(config); - defaultHeaders.put("typ", "JWT"); - defaultHeaders.put("alg", "RS256"); - } - - @Test - void getJwtReturnsValidToken() throws JWTTokenProvider.JwtSigningException { - - HashMap headers = new HashMap<>(); - headers.put("a", "b"); - headers.put("c", "d"); - - HashMap content = new HashMap<>(); - content.put("sub", "subject"); - content.put("iss", "issuer"); - - var builder = getBuilder(true, "TestSignature"); - JWTTokenProvider provider = new JWTTokenProvider(config, builder); - - Instant i = Clock.systemUTC().instant(); - - String result = provider.getJWT(i, i, headers, content); - - String expectedSig = "TestSignature"; - - assertNotNull(result); - defaultHeaders.put("a", "b"); - defaultHeaders.put("c", "d"); - - JsonObject contentJson = new JsonObject(); - contentJson.put("exp", i.getEpochSecond()); - contentJson.put("iat", i.getEpochSecond()); - contentJson.put("sub", "subject"); - contentJson.put("iss", "issuer"); - - assertJWT(defaultHeaders.encode(), contentJson.encode(), expectedSig, result); - assertEquals("1234", this.capturedSignRequest.getValue().keyId()); - assertEquals(SigningAlgorithmSpec.RSASSA_PKCS1_V1_5_SHA_256, this.capturedSignRequest.getValue().signingAlgorithm()); - } - - @Test - void getJwtEmptySignatureThrowsException() { - var builder = getBuilder(false, ""); - - JWTTokenProvider provider = new JWTTokenProvider(config, builder); - - JWTTokenProvider.JwtSigningException e = assertThrows( - JWTTokenProvider.JwtSigningException.class, - () -> provider.getJWT(Clock.systemUTC().instant().plusSeconds(600), Clock.systemUTC().instant(), new HashMap<>(), new HashMap<>())); - - assertEquals("Test status text", e.getMessage()); - } - - @Test - void getJwtEmptySignatureEmptyResponseText() { - var builder = getBuilder(false, "", Optional.empty()); - - JWTTokenProvider provider = new JWTTokenProvider(config, builder); - - JWTTokenProvider.JwtSigningException e = assertThrows( - JWTTokenProvider.JwtSigningException.class, - () -> provider.getJWT(Clock.systemUTC().instant().plusSeconds(600), Clock.systemUTC().instant(), new HashMap<>(), new HashMap<>())); - - assertEquals("No message returned from KMS Client", e.getMessage()); - } - - @Test - void getJwtEmptySignatureNullResponseText() { - var builder = getBuilder(false, "", null); - - JWTTokenProvider provider = new JWTTokenProvider(config, builder); - - JWTTokenProvider.JwtSigningException e = assertThrows( - JWTTokenProvider.JwtSigningException.class, - () -> provider.getJWT(Clock.systemUTC().instant().plusSeconds(600), Clock.systemUTC().instant(), new HashMap<>(), new HashMap<>())); - - assertEquals("No message returned from KMS Client", e.getMessage()); - } - - @Test - void getJwtSignatureThrowsKmsException() { - var builder = getBuilder(false, "", Optional.empty()); - - JWTTokenProvider provider = new JWTTokenProvider(config, builder); - var ex = KmsException.builder().message("Test Error").build(); - when(mockClient.sign(capturedSignRequest.capture())).thenThrow(ex); - - JWTTokenProvider.JwtSigningException e = assertThrows( - JWTTokenProvider.JwtSigningException.class, - () -> provider.getJWT(Clock.systemUTC().instant().plusSeconds(600), Clock.systemUTC().instant(), new HashMap<>(), new HashMap<>())); - - assertEquals("Error signing JWT Token.", e.getMessage()); - } - - @Test - void getJwtMissingKeyInConfig() throws IOException { - var data = (JsonObject) Json.decodeValue(openFile("/com.uid2.core/service/jwt-token-provider-test-config.json")); - data.put("aws_kms_jwt_signing_key_id", ""); - data.put("enforceJwt", true); - - ConfigStore.Global.load(data); - - var builder = getBuilder(false, "", Optional.empty()); - - JWTTokenProvider provider = new JWTTokenProvider(config, builder); - - JWTTokenProvider.JwtSigningException e = assertThrows( - JWTTokenProvider.JwtSigningException.class, - () -> provider.getJWT(Clock.systemUTC().instant().plusSeconds(600), Clock.systemUTC().instant(), new HashMap<>(), new HashMap<>())); - - assertEquals("Unable to retrieve the AWS KMS Key Id from config. Unable to sign JWT token", e.getMessage()); - } - - String openFile(String filePath) throws IOException { - return readToEndAsString(JWTTokenProviderTests.class.getResourceAsStream(filePath)); - } - - private KmsClientBuilder getBuilder(boolean isSuccessful, String signature) { - return getBuilder(isSuccessful, signature, Optional.of("Test status text")); - } - - private KmsClientBuilder getBuilder(boolean isSuccessful, String signature, Optional statusText) { - SdkHttpResponse sdkHttpResponse = mock(SdkHttpResponse.class); - when(sdkHttpResponse.isSuccessful()).thenReturn(isSuccessful); - when(sdkHttpResponse.statusText()).thenReturn(statusText); - - SignResponse response = mock(SignResponse.class); - when(response.sdkHttpResponse()).thenReturn(sdkHttpResponse); - when(response.signature()).thenReturn(SdkBytes.fromUtf8String(signature)); - - mockClient = mock(KmsClient.class); - capturedSignRequest = ArgumentCaptor.forClass(SignRequest.class); - when(mockClient.sign(capturedSignRequest.capture())).thenReturn(response); - - KmsClientBuilder builder = mock(KmsClientBuilder.class); - when(builder.region(any(Region.class))).thenReturn(builder); - when(builder.credentialsProvider(any(AwsCredentialsProvider.class))).thenReturn(builder); - when(builder.build()).thenReturn(mockClient); - - return builder; - } - - private void assertJWT(String expectedHeader, String expectedContent, String expectedSignature, String jwt) { - var decoder = Base64.getUrlDecoder(); - var parts = jwt.split("\\."); - String header = new String(decoder.decode(parts[0])); - assertEquals(expectedHeader, header); - - String content = new String(decoder.decode(parts[1])); - assertEquals(expectedContent, content); - - assertEquals(expectedSignature, new String(decoder.decode(parts[2]))); - } -} +package com.uid2.core.service; + +import com.uid2.core.model.ConfigStore; +import io.vertx.core.json.Json; +import io.vertx.core.json.JsonObject; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; +import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; +import software.amazon.awssdk.core.SdkBytes; +import software.amazon.awssdk.http.SdkHttpResponse; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.kms.KmsClient; +import software.amazon.awssdk.services.kms.KmsClientBuilder; +import software.amazon.awssdk.services.kms.model.KmsException; +import software.amazon.awssdk.services.kms.model.SignRequest; +import software.amazon.awssdk.services.kms.model.SignResponse; +import software.amazon.awssdk.services.kms.model.SigningAlgorithmSpec; + +import java.io.IOException; +import java.time.Clock; +import java.time.Instant; +import java.util.Base64; +import java.util.HashMap; +import java.util.Optional; + +import static com.uid2.shared.Utils.readToEndAsString; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class JWTTokenProviderTest { + private final JsonObject defaultHeaders = new JsonObject(); + + private KmsClient mockClient; + private ArgumentCaptor capturedSignRequest; + private JsonObject config; + + @BeforeEach + void setUp() throws IOException { + this.config = ((JsonObject) Json.decodeValue(openFile("/com.uid2.core/service/jwt-token-provider-test-config.json"))); + ConfigStore.Global.load(config); + defaultHeaders.put("typ", "JWT"); + defaultHeaders.put("alg", "RS256"); + } + + @Test + void getJwtReturnsValidToken() throws JWTTokenProvider.JwtSigningException { + + HashMap headers = new HashMap<>(); + headers.put("a", "b"); + headers.put("c", "d"); + + HashMap content = new HashMap<>(); + content.put("sub", "subject"); + content.put("iss", "issuer"); + + var builder = getBuilder(true, "TestSignature"); + JWTTokenProvider provider = new JWTTokenProvider(config, builder); + + Instant i = Clock.systemUTC().instant(); + + String result = provider.getJWT(i, i, headers, content); + + String expectedSig = "TestSignature"; + + assertNotNull(result); + defaultHeaders.put("a", "b"); + defaultHeaders.put("c", "d"); + + JsonObject contentJson = new JsonObject(); + contentJson.put("exp", i.getEpochSecond()); + contentJson.put("iat", i.getEpochSecond()); + contentJson.put("sub", "subject"); + contentJson.put("iss", "issuer"); + + assertJWT(defaultHeaders.encode(), contentJson.encode(), expectedSig, result); + assertEquals("1234", this.capturedSignRequest.getValue().keyId()); + assertEquals(SigningAlgorithmSpec.RSASSA_PKCS1_V1_5_SHA_256, this.capturedSignRequest.getValue().signingAlgorithm()); + } + + @Test + void getJwtEmptySignatureThrowsException() { + var builder = getBuilder(false, ""); + + JWTTokenProvider provider = new JWTTokenProvider(config, builder); + + JWTTokenProvider.JwtSigningException e = assertThrows( + JWTTokenProvider.JwtSigningException.class, + () -> provider.getJWT(Clock.systemUTC().instant().plusSeconds(600), Clock.systemUTC().instant(), new HashMap<>(), new HashMap<>())); + + assertEquals("Test status text", e.getMessage()); + } + + @Test + void getJwtEmptySignatureEmptyResponseText() { + var builder = getBuilder(false, "", Optional.empty()); + + JWTTokenProvider provider = new JWTTokenProvider(config, builder); + + JWTTokenProvider.JwtSigningException e = assertThrows( + JWTTokenProvider.JwtSigningException.class, + () -> provider.getJWT(Clock.systemUTC().instant().plusSeconds(600), Clock.systemUTC().instant(), new HashMap<>(), new HashMap<>())); + + assertEquals("No message returned from KMS Client", e.getMessage()); + } + + @Test + void getJwtEmptySignatureNullResponseText() { + var builder = getBuilder(false, "", null); + + JWTTokenProvider provider = new JWTTokenProvider(config, builder); + + JWTTokenProvider.JwtSigningException e = assertThrows( + JWTTokenProvider.JwtSigningException.class, + () -> provider.getJWT(Clock.systemUTC().instant().plusSeconds(600), Clock.systemUTC().instant(), new HashMap<>(), new HashMap<>())); + + assertEquals("No message returned from KMS Client", e.getMessage()); + } + + @Test + void getJwtSignatureThrowsKmsException() { + var builder = getBuilder(false, "", Optional.empty()); + + JWTTokenProvider provider = new JWTTokenProvider(config, builder); + var ex = KmsException.builder().message("Test Error").build(); + when(mockClient.sign(capturedSignRequest.capture())).thenThrow(ex); + + JWTTokenProvider.JwtSigningException e = assertThrows( + JWTTokenProvider.JwtSigningException.class, + () -> provider.getJWT(Clock.systemUTC().instant().plusSeconds(600), Clock.systemUTC().instant(), new HashMap<>(), new HashMap<>())); + + assertEquals("Error signing JWT Token.", e.getMessage()); + } + + @Test + void getJwtMissingKeyInConfig() throws IOException { + var data = (JsonObject) Json.decodeValue(openFile("/com.uid2.core/service/jwt-token-provider-test-config.json")); + data.put("aws_kms_jwt_signing_key_id", ""); + data.put("enforceJwt", true); + + ConfigStore.Global.load(data); + + var builder = getBuilder(false, "", Optional.empty()); + + JWTTokenProvider provider = new JWTTokenProvider(config, builder); + + JWTTokenProvider.JwtSigningException e = assertThrows( + JWTTokenProvider.JwtSigningException.class, + () -> provider.getJWT(Clock.systemUTC().instant().plusSeconds(600), Clock.systemUTC().instant(), new HashMap<>(), new HashMap<>())); + + assertEquals("Unable to retrieve the AWS KMS Key Id from config. Unable to sign JWT token", e.getMessage()); + } + + String openFile(String filePath) throws IOException { + return readToEndAsString(JWTTokenProviderTest.class.getResourceAsStream(filePath)); + } + + private KmsClientBuilder getBuilder(boolean isSuccessful, String signature) { + return getBuilder(isSuccessful, signature, Optional.of("Test status text")); + } + + private KmsClientBuilder getBuilder(boolean isSuccessful, String signature, Optional statusText) { + SdkHttpResponse sdkHttpResponse = mock(SdkHttpResponse.class); + when(sdkHttpResponse.isSuccessful()).thenReturn(isSuccessful); + when(sdkHttpResponse.statusText()).thenReturn(statusText); + + SignResponse response = mock(SignResponse.class); + when(response.sdkHttpResponse()).thenReturn(sdkHttpResponse); + when(response.signature()).thenReturn(SdkBytes.fromUtf8String(signature)); + + mockClient = mock(KmsClient.class); + capturedSignRequest = ArgumentCaptor.forClass(SignRequest.class); + when(mockClient.sign(capturedSignRequest.capture())).thenReturn(response); + + KmsClientBuilder builder = mock(KmsClientBuilder.class); + when(builder.region(any(Region.class))).thenReturn(builder); + when(builder.credentialsProvider(any(AwsCredentialsProvider.class))).thenReturn(builder); + when(builder.build()).thenReturn(mockClient); + + return builder; + } + + private void assertJWT(String expectedHeader, String expectedContent, String expectedSignature, String jwt) { + var decoder = Base64.getUrlDecoder(); + var parts = jwt.split("\\."); + String header = new String(decoder.decode(parts[0])); + assertEquals(expectedHeader, header); + + String content = new String(decoder.decode(parts[1])); + assertEquals(expectedContent, content); + + assertEquals(expectedSignature, new String(decoder.decode(parts[2]))); + } +} diff --git a/src/test/java/com/uid2/core/service/MetadataProviderTest.java b/src/test/java/com/uid2/core/service/MetadataProviderTest.java new file mode 100644 index 00000000..75f06d68 --- /dev/null +++ b/src/test/java/com/uid2/core/service/MetadataProviderTest.java @@ -0,0 +1,99 @@ +package com.uid2.core.service; + +import com.uid2.core.model.SecretStore; +import com.uid2.core.util.OperatorInfo; +import com.uid2.shared.auth.OperatorType; +import com.uid2.shared.cloud.ICloudStorage; +import io.vertx.core.json.JsonObject; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.io.ByteArrayInputStream; +import java.net.URL; +import java.nio.charset.StandardCharsets; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; + +public class MetadataProviderTest { + @Mock private ICloudStorage metadataStreamProvider; + @Mock private ICloudStorage downloadUrlGenerator; + private MockMetadataProvider metadataProvider; + + @BeforeAll + public static void setupAll() { + SecretStore.Global.load(new JsonObject("{\"mocks_metadata_path\":\"mocks/metadata.json\",\"arraymocks_metadata_path\":\"arraymocks/metadata.json\"}")); + } + + @AfterAll + public static void teardownAll() { + SecretStore.Global.load(new JsonObject()); + } + + @BeforeEach + public void setup() throws Exception { + MockitoAnnotations.openMocks(this); + when(metadataStreamProvider.download(eq("mocks/metadata.json"))).thenReturn(new ByteArrayInputStream("{\"mocks\":{\"location\":\"mocks3path/mocks.json\"}}".getBytes(StandardCharsets.UTF_8))); + when(downloadUrlGenerator.preSignUrl(eq("mocks3path/mocks.json"))).thenReturn(new URL("http://www.someawsurl.com/mocks3path/mocks.json")); + + when(metadataStreamProvider.download(eq("arraymocks/metadata.json"))).thenReturn(new ByteArrayInputStream("{\"arraymocks\":[{\"location\":\"mocks3path/arraymocks.json\"}]}".getBytes(StandardCharsets.UTF_8))); + when(downloadUrlGenerator.preSignUrl(eq("mocks3path/arraymocks.json"))).thenReturn(new URL("http://www.someawsurl.com/mocks3path/arraymocks.json")); + + metadataProvider = new MockMetadataProvider(metadataStreamProvider, downloadUrlGenerator); + } + + @Test + public void testGetMetadata() throws Exception { + String metadata = metadataProvider.getMetadata(); + assertEquals("{\"mocks\":{\"location\":\"http://www.someawsurl.com/mocks3path/mocks.json\"}}", metadata); + } + + @Test + public void testGetMetadataWithOperatorInfo() throws Exception { + String metadata = metadataProvider.getMetadata(new OperatorInfo(OperatorType.PUBLIC, 0, false)); + assertEquals("{\"mocks\":{\"location\":\"http://www.someawsurl.com/mocks3path/mocks.json\"}}", metadata); + } + + @Test + public void testGetArrayMetadata() throws Exception { + String metadata = metadataProvider.getArrayMetadata(new OperatorInfo(OperatorType.PUBLIC, 0, false)); + assertEquals("{\"arraymocks\":[{\"location\":\"http://www.someawsurl.com/mocks3path/arraymocks.json\"}]}", metadata); + } + + @Test + public void testGetGlobalScopeMetadata() throws Exception { + String metadata = metadataProvider.getGlobalMetadata(); + assertEquals("{\"mocks\":{\"location\":\"http://www.someawsurl.com/mocks3path/mocks.json\"}}", metadata); + } + + private static class MockMetadataProvider extends MetadataProvider { + public MockMetadataProvider(ICloudStorage cloudStorage) { + super(cloudStorage); + } + + public MockMetadataProvider(ICloudStorage fileStreamProvider, ICloudStorage downloadUrlGenerator) { + super(fileStreamProvider, downloadUrlGenerator); + } + + public String getMetadata() throws Exception { + return getMetadata("mocks_metadata_path", "mocks"); + } + + public String getMetadata(OperatorInfo info) throws Exception { + return getMetadata(info, "mocks_metadata_path", "mocks"); + } + + public String getArrayMetadata(OperatorInfo info) throws Exception { + return getArrayMetadata(info, "arraymocks_metadata_path", "arraymocks"); + } + + public String getGlobalMetadata() throws Exception { + return getGlobalScopeMetadata("mocks_metadata_path", "mocks"); + } + } +} diff --git a/src/test/java/com/uid2/core/util/TestMetadataHelper.java b/src/test/java/com/uid2/core/util/MetadataHelperTest.java similarity index 98% rename from src/test/java/com/uid2/core/util/TestMetadataHelper.java rename to src/test/java/com/uid2/core/util/MetadataHelperTest.java index 5d5f8071..3d3d3f08 100644 --- a/src/test/java/com/uid2/core/util/TestMetadataHelper.java +++ b/src/test/java/com/uid2/core/util/MetadataHelperTest.java @@ -12,7 +12,7 @@ import static org.mockito.Mockito.when; -public class TestMetadataHelper { +public class MetadataHelperTest { @Mock private OperatorInfo operatorInfo; diff --git a/src/test/java/com/uid2/core/util/TestOperatorInfo.java b/src/test/java/com/uid2/core/util/OperatorInfoTest.java similarity index 100% rename from src/test/java/com/uid2/core/util/TestOperatorInfo.java rename to src/test/java/com/uid2/core/util/OperatorInfoTest.java diff --git a/src/test/java/com/uid2/core/vertx/TestClientSideKeypairMetadataPath.java b/src/test/java/com/uid2/core/vertx/ClientSideKeypairMetadataPathTest.java similarity index 98% rename from src/test/java/com/uid2/core/vertx/TestClientSideKeypairMetadataPath.java rename to src/test/java/com/uid2/core/vertx/ClientSideKeypairMetadataPathTest.java index f2284ded..0e92a73e 100644 --- a/src/test/java/com/uid2/core/vertx/TestClientSideKeypairMetadataPath.java +++ b/src/test/java/com/uid2/core/vertx/ClientSideKeypairMetadataPathTest.java @@ -42,7 +42,7 @@ import static org.mockito.Mockito.when; @ExtendWith(VertxExtension.class) -public class TestClientSideKeypairMetadataPath { +public class ClientSideKeypairMetadataPathTest { @Mock private ICloudStorage cloudStorage; @@ -127,6 +127,6 @@ void privateOperatorGetsKeypairsError(Vertx vertx, VertxTestContext testContext) String openFile(String filePath) throws IOException { - return readToEndAsString(TestSiteSpecificMetadataPath.class.getResourceAsStream(filePath)); + return readToEndAsString(SiteSpecificMetadataPathTest.class.getResourceAsStream(filePath)); } } diff --git a/src/test/java/com/uid2/core/vertx/TestCoreVerticle.java b/src/test/java/com/uid2/core/vertx/CoreVerticleTest.java similarity index 99% rename from src/test/java/com/uid2/core/vertx/TestCoreVerticle.java rename to src/test/java/com/uid2/core/vertx/CoreVerticleTest.java index 1e5151e5..cc18a707 100644 --- a/src/test/java/com/uid2/core/vertx/TestCoreVerticle.java +++ b/src/test/java/com/uid2/core/vertx/CoreVerticleTest.java @@ -57,7 +57,7 @@ import static org.mockito.Mockito.*; @ExtendWith(VertxExtension.class) -public class TestCoreVerticle { +public class CoreVerticleTest { @Mock private ICloudStorage cloudStorage; @Mock diff --git a/src/test/java/com/uid2/core/vertx/TestServiceLinkMetadataPath.java b/src/test/java/com/uid2/core/vertx/ServiceLinkMetadataPathTest.java similarity index 98% rename from src/test/java/com/uid2/core/vertx/TestServiceLinkMetadataPath.java rename to src/test/java/com/uid2/core/vertx/ServiceLinkMetadataPathTest.java index 224dfcae..d604097d 100644 --- a/src/test/java/com/uid2/core/vertx/TestServiceLinkMetadataPath.java +++ b/src/test/java/com/uid2/core/vertx/ServiceLinkMetadataPathTest.java @@ -42,7 +42,7 @@ import static org.mockito.Mockito.when; @ExtendWith(VertxExtension.class) -public class TestServiceLinkMetadataPath { +public class ServiceLinkMetadataPathTest { @Mock private ICloudStorage cloudStorage; @Mock @@ -125,6 +125,6 @@ void privateOperatorGetsKeypairsError(Vertx vertx, VertxTestContext testContext) } String openFile(String filePath) throws IOException { - return readToEndAsString(TestSiteSpecificMetadataPath.class.getResourceAsStream(filePath)); + return readToEndAsString(SiteSpecificMetadataPathTest.class.getResourceAsStream(filePath)); } } diff --git a/src/test/java/com/uid2/core/vertx/TestServiceMetadataPath.java b/src/test/java/com/uid2/core/vertx/ServiceMetadataPathTest.java similarity index 98% rename from src/test/java/com/uid2/core/vertx/TestServiceMetadataPath.java rename to src/test/java/com/uid2/core/vertx/ServiceMetadataPathTest.java index 0fcf0dfc..70f42337 100644 --- a/src/test/java/com/uid2/core/vertx/TestServiceMetadataPath.java +++ b/src/test/java/com/uid2/core/vertx/ServiceMetadataPathTest.java @@ -42,7 +42,7 @@ import static org.mockito.Mockito.when; @ExtendWith(VertxExtension.class) -public class TestServiceMetadataPath { +public class ServiceMetadataPathTest { @Mock private ICloudStorage cloudStorage; @Mock @@ -125,6 +125,6 @@ void privateOperatorGetsKeypairsError(Vertx vertx, VertxTestContext testContext) } String openFile(String filePath) throws IOException { - return readToEndAsString(TestSiteSpecificMetadataPath.class.getResourceAsStream(filePath)); + return readToEndAsString(SiteSpecificMetadataPathTest.class.getResourceAsStream(filePath)); } } diff --git a/src/test/java/com/uid2/core/vertx/TestSiteSpecificMetadataPathDisabled.java b/src/test/java/com/uid2/core/vertx/SiteSpecificMetadataPathDisabledTest.java similarity index 98% rename from src/test/java/com/uid2/core/vertx/TestSiteSpecificMetadataPathDisabled.java rename to src/test/java/com/uid2/core/vertx/SiteSpecificMetadataPathDisabledTest.java index 626ae95f..cd34b0b9 100644 --- a/src/test/java/com/uid2/core/vertx/TestSiteSpecificMetadataPathDisabled.java +++ b/src/test/java/com/uid2/core/vertx/SiteSpecificMetadataPathDisabledTest.java @@ -43,7 +43,7 @@ * we still provide global scope metadata file instead of private operator caller's private site data */ @ExtendWith(VertxExtension.class) -public class TestSiteSpecificMetadataPathDisabled { +public class SiteSpecificMetadataPathDisabledTest { @Mock private ICloudStorage cloudStorage; @@ -169,7 +169,7 @@ void genericSiteSpecificTest(Vertx vertx, VertxTestContext testContext, Operator String openFile(String filePath) throws IOException { - return readToEndAsString(TestSiteSpecificMetadataPathDisabled.class.getResourceAsStream(filePath)); + return readToEndAsString(SiteSpecificMetadataPathDisabledTest.class.getResourceAsStream(filePath)); } } diff --git a/src/test/java/com/uid2/core/vertx/TestSiteSpecificMetadataPath.java b/src/test/java/com/uid2/core/vertx/SiteSpecificMetadataPathTest.java similarity index 98% rename from src/test/java/com/uid2/core/vertx/TestSiteSpecificMetadataPath.java rename to src/test/java/com/uid2/core/vertx/SiteSpecificMetadataPathTest.java index 0a2d2dad..3c14314c 100644 --- a/src/test/java/com/uid2/core/vertx/TestSiteSpecificMetadataPath.java +++ b/src/test/java/com/uid2/core/vertx/SiteSpecificMetadataPathTest.java @@ -42,7 +42,7 @@ * See TestSitesMetadataPath for testing public operator able to retrieve site metadata for CSTG use. */ @ExtendWith(VertxExtension.class) -public class TestSiteSpecificMetadataPath { +public class SiteSpecificMetadataPathTest { @Mock private ICloudStorage cloudStorage; @@ -167,7 +167,7 @@ void genericSiteSpecificTest(Vertx vertx, VertxTestContext testContext, Operator String openFile(String filePath) throws IOException { - return readToEndAsString(TestSiteSpecificMetadataPath.class.getResourceAsStream(filePath)); + return readToEndAsString(SiteSpecificMetadataPathTest.class.getResourceAsStream(filePath)); } } diff --git a/src/test/java/com/uid2/core/vertx/TestSitesMetadataPath.java b/src/test/java/com/uid2/core/vertx/SitesMetadataPathTest.java similarity index 98% rename from src/test/java/com/uid2/core/vertx/TestSitesMetadataPath.java rename to src/test/java/com/uid2/core/vertx/SitesMetadataPathTest.java index 338640d2..87606ff3 100644 --- a/src/test/java/com/uid2/core/vertx/TestSitesMetadataPath.java +++ b/src/test/java/com/uid2/core/vertx/SitesMetadataPathTest.java @@ -45,7 +45,7 @@ // this class is for test public operator able to retrieve site metadata for CSTG use. // For testing Core Service returning site specific metadata for private operator refer to TestSiteSpecificMetadataPath/TestSiteSpecificMetadataPathDisabled classes @ExtendWith(VertxExtension.class) -public class TestSitesMetadataPath { +public class SitesMetadataPathTest { @Mock private ICloudStorage cloudStorage; @Mock @@ -130,6 +130,6 @@ void privateOperatorGetsSitesError(Vertx vertx, VertxTestContext testContext) th String openFile(String filePath) throws IOException { - return readToEndAsString(TestSiteSpecificMetadataPath.class.getResourceAsStream(filePath)); + return readToEndAsString(SiteSpecificMetadataPathTest.class.getResourceAsStream(filePath)); } }