From 36235b0f4675adea1499ee859899647dbe59cf91 Mon Sep 17 00:00:00 2001 From: Cody Constine Date: Fri, 6 Dec 2024 15:54:45 -0700 Subject: [PATCH 01/19] Adding more work on salt encryption --- pom.xml | 2 +- .../EncryptionJob/ClientKeyEncryptionJob.java | 2 +- .../job/EncryptionJob/SaltEncryptionJob.java | 39 ++++++++++ .../job/jobsync/EncryptedFilesSyncJob.java | 2 - .../admin/store/factory/SaltStoreFactory.java | 66 ++++++++++++++++ .../store/writer/EncyptedSaltStoreWriter.java | 75 +++++++++++++++++++ .../admin/store/writer/SaltStoreWriter.java | 12 ++- .../com/uid2/admin/util/PrivateSiteUtil.java | 15 ++++ .../com/uid2/admin/util/PublicSiteUtil.java | 15 ++++ 9 files changed, 221 insertions(+), 7 deletions(-) create mode 100644 src/main/java/com/uid2/admin/job/EncryptionJob/SaltEncryptionJob.java create mode 100644 src/main/java/com/uid2/admin/store/factory/SaltStoreFactory.java create mode 100644 src/main/java/com/uid2/admin/store/writer/EncyptedSaltStoreWriter.java diff --git a/pom.xml b/pom.xml index 479eb475..d8e2d5f4 100644 --- a/pom.xml +++ b/pom.xml @@ -16,7 +16,7 @@ 1.12.2 5.11.2 - 8.0.6 + 8.0.10-alpha-172-SNAPSHOT 0.5.10 ${project.version} diff --git a/src/main/java/com/uid2/admin/job/EncryptionJob/ClientKeyEncryptionJob.java b/src/main/java/com/uid2/admin/job/EncryptionJob/ClientKeyEncryptionJob.java index 9febe5f7..8e81705c 100644 --- a/src/main/java/com/uid2/admin/job/EncryptionJob/ClientKeyEncryptionJob.java +++ b/src/main/java/com/uid2/admin/job/EncryptionJob/ClientKeyEncryptionJob.java @@ -33,7 +33,7 @@ public String getId() { public void execute() throws Exception { PrivateSiteDataMap desiredPrivateState = PrivateSiteUtil.getClientKeys(globalOperators, globalClientKeys); multiScopeStoreWriter.uploadPrivateWithEncryption(desiredPrivateState, null); - PrivateSiteDataMap desiredPublicState = PublicSiteUtil.getPublicClients(globalClientKeys,globalOperators); + PrivateSiteDataMap desiredPublicState = PublicSiteUtil.getPublicClients(globalClientKeys, globalOperators); multiScopeStoreWriter.uploadPublicWithEncryption(desiredPublicState, null); } } diff --git a/src/main/java/com/uid2/admin/job/EncryptionJob/SaltEncryptionJob.java b/src/main/java/com/uid2/admin/job/EncryptionJob/SaltEncryptionJob.java new file mode 100644 index 00000000..988b17da --- /dev/null +++ b/src/main/java/com/uid2/admin/job/EncryptionJob/SaltEncryptionJob.java @@ -0,0 +1,39 @@ +package com.uid2.admin.job.EncryptionJob; + +import com.uid2.admin.job.model.Job; +import com.uid2.admin.model.PrivateSiteDataMap; +import com.uid2.admin.store.MultiScopeStoreWriter; +import com.uid2.admin.util.PrivateSiteUtil; +import com.uid2.admin.util.PublicSiteUtil; +import com.uid2.shared.auth.OperatorKey; +import com.uid2.shared.model.SaltEntry; + +import java.util.Collection; + +public class SaltEncryptionJob extends Job { + private final Collection globalOperators; + private final Collection saltEntries; + private final MultiScopeStoreWriter> multiScopeStoreWriter; + + public SaltEncryptionJob(Collection globalOperators, + Collection saltEntries, + MultiScopeStoreWriter> multiScopeStoreWriter) { + this.globalOperators = globalOperators; + this.saltEntries = saltEntries; + this.multiScopeStoreWriter = multiScopeStoreWriter; + } + + + @Override + public String getId() { + return "cloud-encryption-sync-salts"; + } + + @Override + public void execute() throws Exception { + PrivateSiteDataMap desiredPrivateState = PrivateSiteUtil.getPrivateSaltEntries(saltEntries, globalOperators); + multiScopeStoreWriter.uploadPrivateWithEncryption(desiredPrivateState, null); + PrivateSiteDataMap desiredPublicState = PublicSiteUtil.getPublicSaltEntries(saltEntries, globalOperators); + multiScopeStoreWriter.uploadPublicWithEncryption(desiredPublicState, null); + } +} diff --git a/src/main/java/com/uid2/admin/job/jobsync/EncryptedFilesSyncJob.java b/src/main/java/com/uid2/admin/job/jobsync/EncryptedFilesSyncJob.java index 14077ac3..31c87b3e 100644 --- a/src/main/java/com/uid2/admin/job/jobsync/EncryptedFilesSyncJob.java +++ b/src/main/java/com/uid2/admin/job/jobsync/EncryptedFilesSyncJob.java @@ -2,7 +2,6 @@ import com.fasterxml.jackson.databind.ObjectWriter; import com.uid2.admin.job.EncryptionJob.*; -import com.uid2.admin.job.EncryptionJob.ClientKeyEncryptionJob; import com.uid2.admin.job.model.Job; import com.uid2.admin.store.*; import com.uid2.admin.store.factory.*; @@ -23,7 +22,6 @@ import com.uid2.shared.store.CloudPath; import com.uid2.admin.legacy.LegacyClientKey; import com.uid2.shared.store.reader.RotatingCloudEncryptionKeyProvider; -import com.uid2.shared.store.reader.RotatingCloudEncryptionKeyProvider; import com.uid2.shared.store.scope.GlobalScope; import io.vertx.core.json.JsonObject; diff --git a/src/main/java/com/uid2/admin/store/factory/SaltStoreFactory.java b/src/main/java/com/uid2/admin/store/factory/SaltStoreFactory.java new file mode 100644 index 00000000..21f31a1e --- /dev/null +++ b/src/main/java/com/uid2/admin/store/factory/SaltStoreFactory.java @@ -0,0 +1,66 @@ +package com.uid2.admin.store.factory; + +import com.uid2.admin.store.FileManager; +import com.uid2.admin.store.version.VersionGenerator; +import com.uid2.admin.store.writer.EncyptedSaltStoreWriter; +import com.uid2.admin.store.writer.StoreWriter; +import com.uid2.shared.cloud.TaggableCloudStorage; +import com.uid2.shared.store.CloudPath; +import com.uid2.shared.store.RotatingEncryptedSaltProvider; +import com.uid2.shared.store.RotatingSaltProvider; +import com.uid2.shared.store.reader.RotatingCloudEncryptionKeyProvider; +import com.uid2.shared.store.reader.StoreReader; +import com.uid2.shared.store.scope.EncryptedScope; +import io.vertx.core.json.JsonObject; + +import java.util.Collection; + +public class SaltStoreFactory implements EncryptedStoreFactory> { + JsonObject config; + CloudPath rootMetadatapath; + RotatingSaltProvider saltProvider; + FileManager fileManager; + TaggableCloudStorage taggableCloudStorage; + VersionGenerator versionGenerator; + RotatingCloudEncryptionKeyProvider cloudEncryptionKeyProvider; + + public SaltStoreFactory(JsonObject config, CloudPath rootMetadataPath, RotatingSaltProvider saltProvider, FileManager fileManager, + TaggableCloudStorage taggableCloudStorage, VersionGenerator versionGenerator, + RotatingCloudEncryptionKeyProvider cloudEncryptionKeyProvider) { + this.config = config; + this.rootMetadatapath = rootMetadataPath; + this.saltProvider = saltProvider; + this.fileManager = fileManager; + this.taggableCloudStorage = taggableCloudStorage; + this.versionGenerator = versionGenerator; + this.cloudEncryptionKeyProvider = cloudEncryptionKeyProvider; + } + + @Override + public StoreWriter> getEncryptedWriter(Integer siteId, boolean isPublic) { + return new EncyptedSaltStoreWriter(config, saltProvider, fileManager, taggableCloudStorage, versionGenerator, + new EncryptedScope(rootMetadatapath, siteId, isPublic), cloudEncryptionKeyProvider, siteId); + } + + @Override + public StoreReader> getEncryptedReader(Integer siteId, boolean isPublic) { + return new RotatingEncryptedSaltProvider(taggableCloudStorage, + new EncryptedScope(rootMetadatapath, siteId, isPublic).getMetadataPath().toString(), + cloudEncryptionKeyProvider); + } + + @Override + public RotatingCloudEncryptionKeyProvider getCloudEncryptionProvider() { + return cloudEncryptionKeyProvider; + } + + @Override + public StoreReader> getReader(Integer siteId) { + return null; + } + + @Override + public StoreWriter> getWriter(Integer siteId) { + return null; + } +} diff --git a/src/main/java/com/uid2/admin/store/writer/EncyptedSaltStoreWriter.java b/src/main/java/com/uid2/admin/store/writer/EncyptedSaltStoreWriter.java new file mode 100644 index 00000000..d29f8a29 --- /dev/null +++ b/src/main/java/com/uid2/admin/store/writer/EncyptedSaltStoreWriter.java @@ -0,0 +1,75 @@ +package com.uid2.admin.store.writer; + +import com.uid2.admin.store.FileManager; +import com.uid2.admin.store.version.VersionGenerator; +import com.uid2.shared.cloud.TaggableCloudStorage; +import com.uid2.shared.encryption.AesGcm; +import com.uid2.shared.model.CloudEncryptionKey; +import com.uid2.shared.store.CloudPath; +import com.uid2.shared.store.RotatingSaltProvider; +import com.uid2.shared.store.reader.RotatingCloudEncryptionKeyProvider; +import com.uid2.shared.store.scope.StoreScope; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import io.vertx.core.json.JsonObject; + +import java.nio.charset.StandardCharsets; +import java.util.Base64; + +public class EncyptedSaltStoreWriter extends SaltStoreWriter implements StoreWriter { + private StoreScope scope; + private RotatingCloudEncryptionKeyProvider cloudEncryptionKeyProvider; + private Integer siteId; + + private static final Logger LOGGER = LoggerFactory.getLogger(EncyptedSaltStoreWriter.class); + public EncyptedSaltStoreWriter(JsonObject config, RotatingSaltProvider provider, FileManager fileManager, + TaggableCloudStorage cloudStorage, VersionGenerator versionGenerator, StoreScope scope, + RotatingCloudEncryptionKeyProvider cloudEncryptionKeyProvider, Integer siteId) { + super(config, provider, fileManager, cloudStorage, versionGenerator); + this.scope = scope; + this.cloudEncryptionKeyProvider = cloudEncryptionKeyProvider; + this.siteId = siteId; + } + + @Override + protected java.lang.String getSaltSnapshotLocation(RotatingSaltProvider.SaltSnapshot snapshot) { + return scope.resolve(new CloudPath(saltSnapshotLocationPrefix + snapshot.getEffective().toEpochMilli())).toString(); + } + + @Override + protected void upload(String data, String location) throws Exception { + if (siteId == null) { + throw new IllegalStateException("Site ID is not set."); + } + + CloudEncryptionKey encryptionKey = null; + try { + encryptionKey = cloudEncryptionKeyProvider.getEncryptionKeyForSite(siteId); + } catch (IllegalStateException e) { + LOGGER.error("Error: No Cloud Encryption keys available for encryption for site ID: {}", siteId, e); + } + JsonObject encryptedJson = new JsonObject(); + if (encryptionKey != null) { + byte[] secret = Base64.getDecoder().decode(encryptionKey.getSecret()); + byte[] encryptedPayload = AesGcm.encrypt(data.getBytes(StandardCharsets.UTF_8), secret); + encryptedJson.put("key_id", encryptionKey.getId()) + .put("encryption_version", "1.0") + .put("encrypted_payload", Base64.getEncoder().encodeToString(encryptedPayload)); + } else { + throw new IllegalStateException("No Cloud Encryption keys available for encryption for site ID: " + siteId); + } + + + super.upload(encryptedJson.encodePrettily(), location); + } + + @Override + public void upload(Object data, JsonObject extraMeta) throws Exception { + super.upload((RotatingSaltProvider.SaltSnapshot) data); + } + + @Override + public void rewriteMeta() throws Exception { + + } +} diff --git a/src/main/java/com/uid2/admin/store/writer/SaltStoreWriter.java b/src/main/java/com/uid2/admin/store/writer/SaltStoreWriter.java index 76626539..6d350527 100644 --- a/src/main/java/com/uid2/admin/store/writer/SaltStoreWriter.java +++ b/src/main/java/com/uid2/admin/store/writer/SaltStoreWriter.java @@ -26,7 +26,7 @@ public class SaltStoreWriter { private static final Logger LOGGER = LoggerFactory.getLogger(SaltStoreWriter.class); private final RotatingSaltProvider provider; private final FileManager fileManager; - private final String saltSnapshotLocationPrefix; + protected final String saltSnapshotLocationPrefix; private final VersionGenerator versionGenerator; private final TaggableCloudStorage cloudStorage; @@ -111,7 +111,7 @@ public void archiveSaltLocations() throws Exception { }); } - private String getSaltSnapshotLocation(RotatingSaltProvider.SaltSnapshot snapshot) { + protected String getSaltSnapshotLocation(RotatingSaltProvider.SaltSnapshot snapshot) { return saltSnapshotLocationPrefix + snapshot.getEffective().toEpochMilli(); } @@ -130,7 +130,13 @@ private void uploadSaltsSnapshot(RotatingSaltProvider.SaltSnapshot snapshot, Str } } - cloudStorage.upload(newSaltsFile.toString(), location, this.currentTags); + //cloudStorage.upload(newSaltsFile.toString(), location, this.currentTags); + this.upload(newSaltsFile.toString(), location); + } + + protected void upload(String data, String location) throws Exception { + cloudStorage.upload(data, location, this.currentTags); + } private void setStatusTagToCurrent(String location) throws CloudStorageException { diff --git a/src/main/java/com/uid2/admin/util/PrivateSiteUtil.java b/src/main/java/com/uid2/admin/util/PrivateSiteUtil.java index f73541a9..dd81e397 100644 --- a/src/main/java/com/uid2/admin/util/PrivateSiteUtil.java +++ b/src/main/java/com/uid2/admin/util/PrivateSiteUtil.java @@ -6,6 +6,7 @@ import com.uid2.shared.auth.*; import com.uid2.shared.model.EncryptionKey; import com.uid2.shared.model.KeysetKey; +import com.uid2.shared.model.SaltEntry; import com.uid2.shared.model.Site; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -310,4 +311,18 @@ public static PrivateSiteDataMap getKeysetKeys(Collection getPrivateSaltEntries( + Collection globalSaltEntries, + Collection operators) { + final PrivateSiteDataMap result = getPrivateSites(operators); + + globalSaltEntries.forEach(saltEntry -> { + result.forEach((publicSiteId, publicSiteData) -> { + publicSiteData.add(saltEntry); + }); + }); + + return result; + } } diff --git a/src/main/java/com/uid2/admin/util/PublicSiteUtil.java b/src/main/java/com/uid2/admin/util/PublicSiteUtil.java index bc55bc14..7470c5c2 100644 --- a/src/main/java/com/uid2/admin/util/PublicSiteUtil.java +++ b/src/main/java/com/uid2/admin/util/PublicSiteUtil.java @@ -8,6 +8,7 @@ import com.uid2.shared.auth.OperatorType; import com.uid2.shared.model.EncryptionKey; import com.uid2.shared.model.KeysetKey; +import com.uid2.shared.model.SaltEntry; import com.uid2.shared.model.Site; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -128,4 +129,18 @@ public static PrivateSiteDataMap getPublicKeysetKeys( return result; } + + public static PrivateSiteDataMap getPublicSaltEntries( + Collection globalSaltEntries, + Collection operators) { + final PrivateSiteDataMap result = getPublicSitesMap(operators); + + globalSaltEntries.forEach(saltEntry -> { + result.forEach((publicSiteId, publicSiteData) -> { + publicSiteData.add(saltEntry); + }); + }); + + return result; + } } From fc62e0e48cb69ab1089e429a3471e689a96b9743 Mon Sep 17 00:00:00 2001 From: Cody Constine Date: Mon, 9 Dec 2024 14:33:09 -0700 Subject: [PATCH 02/19] Got the encryption job working on salts --- .../job/EncryptionJob/SaltEncryptionJob.java | 13 +++--- .../job/jobsync/EncryptedFilesSyncJob.java | 43 ++++++++++++++----- .../admin/store/factory/SaltStoreFactory.java | 15 +++---- .../store/writer/EncyptedSaltStoreWriter.java | 25 +++++++++-- .../admin/store/writer/SaltStoreWriter.java | 21 ++++++--- .../com/uid2/admin/util/PrivateSiteUtil.java | 7 +-- .../com/uid2/admin/util/PublicSiteUtil.java | 7 +-- 7 files changed, 93 insertions(+), 38 deletions(-) diff --git a/src/main/java/com/uid2/admin/job/EncryptionJob/SaltEncryptionJob.java b/src/main/java/com/uid2/admin/job/EncryptionJob/SaltEncryptionJob.java index 988b17da..6ab992f8 100644 --- a/src/main/java/com/uid2/admin/job/EncryptionJob/SaltEncryptionJob.java +++ b/src/main/java/com/uid2/admin/job/EncryptionJob/SaltEncryptionJob.java @@ -7,17 +7,18 @@ import com.uid2.admin.util.PublicSiteUtil; import com.uid2.shared.auth.OperatorKey; import com.uid2.shared.model.SaltEntry; +import com.uid2.shared.store.RotatingSaltProvider; import java.util.Collection; public class SaltEncryptionJob extends Job { private final Collection globalOperators; - private final Collection saltEntries; - private final MultiScopeStoreWriter> multiScopeStoreWriter; + private final Collection saltEntries; + private final MultiScopeStoreWriter> multiScopeStoreWriter; public SaltEncryptionJob(Collection globalOperators, - Collection saltEntries, - MultiScopeStoreWriter> multiScopeStoreWriter) { + Collection saltEntries, + MultiScopeStoreWriter> multiScopeStoreWriter) { this.globalOperators = globalOperators; this.saltEntries = saltEntries; this.multiScopeStoreWriter = multiScopeStoreWriter; @@ -31,9 +32,9 @@ public String getId() { @Override public void execute() throws Exception { - PrivateSiteDataMap desiredPrivateState = PrivateSiteUtil.getPrivateSaltEntries(saltEntries, globalOperators); + PrivateSiteDataMap desiredPrivateState = PrivateSiteUtil.getPrivateSaltEntries(saltEntries, globalOperators); multiScopeStoreWriter.uploadPrivateWithEncryption(desiredPrivateState, null); - PrivateSiteDataMap desiredPublicState = PublicSiteUtil.getPublicSaltEntries(saltEntries, globalOperators); + PrivateSiteDataMap desiredPublicState = PublicSiteUtil.getPublicSaltEntries(saltEntries, globalOperators); multiScopeStoreWriter.uploadPublicWithEncryption(desiredPublicState, null); } } diff --git a/src/main/java/com/uid2/admin/job/jobsync/EncryptedFilesSyncJob.java b/src/main/java/com/uid2/admin/job/jobsync/EncryptedFilesSyncJob.java index 31c87b3e..ce8c5da3 100644 --- a/src/main/java/com/uid2/admin/job/jobsync/EncryptedFilesSyncJob.java +++ b/src/main/java/com/uid2/admin/job/jobsync/EncryptedFilesSyncJob.java @@ -16,11 +16,14 @@ import com.uid2.shared.auth.RotatingOperatorKeyProvider; import com.uid2.shared.cloud.CloudUtils; import com.uid2.shared.cloud.ICloudStorage; +import com.uid2.shared.cloud.TaggableCloudStorage; import com.uid2.shared.model.EncryptionKey; import com.uid2.shared.model.KeysetKey; import com.uid2.shared.model.Site; import com.uid2.shared.store.CloudPath; import com.uid2.admin.legacy.LegacyClientKey; +import com.uid2.shared.store.RotatingEncryptedSaltProvider; +import com.uid2.shared.store.RotatingSaltProvider; import com.uid2.shared.store.reader.RotatingCloudEncryptionKeyProvider; import com.uid2.shared.store.scope.GlobalScope; import io.vertx.core.json.JsonObject; @@ -32,12 +35,12 @@ public class EncryptedFilesSyncJob extends Job { private final JsonObject config; private final WriteLock writeLock; - private final RotatingCloudEncryptionKeyProvider RotatingCloudEncryptionKeyProvider; + private final RotatingCloudEncryptionKeyProvider rotatingCloudEncryptionKeyProvider; public EncryptedFilesSyncJob(JsonObject config, WriteLock writeLock, RotatingCloudEncryptionKeyProvider RotatingCloudEncryptionKeyProvider) { this.config = config; this.writeLock = writeLock; - this.RotatingCloudEncryptionKeyProvider = RotatingCloudEncryptionKeyProvider; + this.rotatingCloudEncryptionKeyProvider = RotatingCloudEncryptionKeyProvider; } @Override @@ -47,20 +50,22 @@ public String getId() { @Override public void execute() throws Exception { - ICloudStorage cloudStorage = CloudUtils.createStorage(config.getString(Const.Config.CoreS3BucketProp), config); + TaggableCloudStorage cloudStorage = CloudUtils.createStorage(config.getString(Const.Config.CoreS3BucketProp), config); FileStorage fileStorage = new TmpFileStorage(); ObjectWriter jsonWriter = JsonUtil.createJsonWriter(); Clock clock = new InstantClock(); VersionGenerator versionGenerator = new EpochVersionGenerator(clock); FileManager fileManager = new FileManager(cloudStorage, fileStorage); + RotatingSaltProvider saltProvider = new RotatingSaltProvider(cloudStorage, config.getString(Const.Config.SaltsMetadataPathProp)); + SiteStoreFactory siteStoreFactory = new SiteStoreFactory( cloudStorage, new CloudPath(config.getString(Const.Config.SitesMetadataPathProp)), jsonWriter, versionGenerator, clock, - RotatingCloudEncryptionKeyProvider, + rotatingCloudEncryptionKeyProvider, fileManager); ClientKeyStoreFactory clientKeyStoreFactory = new ClientKeyStoreFactory( @@ -69,7 +74,7 @@ public void execute() throws Exception { jsonWriter, versionGenerator, clock, - RotatingCloudEncryptionKeyProvider, + rotatingCloudEncryptionKeyProvider, fileManager); EncryptionKeyStoreFactory encryptionKeyStoreFactory = new EncryptionKeyStoreFactory( @@ -77,7 +82,7 @@ public void execute() throws Exception { new CloudPath(config.getString(Const.Config.KeysMetadataPathProp)), versionGenerator, clock, - RotatingCloudEncryptionKeyProvider, + rotatingCloudEncryptionKeyProvider, fileManager); KeyAclStoreFactory keyAclStoreFactory = new KeyAclStoreFactory( @@ -86,7 +91,7 @@ public void execute() throws Exception { jsonWriter, versionGenerator, clock, - RotatingCloudEncryptionKeyProvider, + rotatingCloudEncryptionKeyProvider, fileManager); KeysetStoreFactory keysetStoreFactory = new KeysetStoreFactory( @@ -96,7 +101,7 @@ public void execute() throws Exception { versionGenerator, clock, fileManager, - RotatingCloudEncryptionKeyProvider, + rotatingCloudEncryptionKeyProvider, config.getBoolean(enableKeysetConfigProp)); KeysetKeyStoreFactory keysetKeyStoreFactory = new KeysetKeyStoreFactory( @@ -105,15 +110,24 @@ public void execute() throws Exception { versionGenerator, clock, fileManager, - RotatingCloudEncryptionKeyProvider, + rotatingCloudEncryptionKeyProvider, config.getBoolean(enableKeysetConfigProp)); + SaltStoreFactory saltStoreFactory = new SaltStoreFactory( + config, + new CloudPath(config.getString(Const.Config.SaltsMetadataPathProp)), + fileManager, + cloudStorage, + versionGenerator, + rotatingCloudEncryptionKeyProvider + ); + CloudPath operatorMetadataPath = new CloudPath(config.getString(Const.Config.OperatorsMetadataPathProp)); GlobalScope operatorScope = new GlobalScope(operatorMetadataPath); RotatingOperatorKeyProvider operatorKeyProvider = new RotatingOperatorKeyProvider(cloudStorage, cloudStorage, operatorScope); synchronized (writeLock) { - RotatingCloudEncryptionKeyProvider.loadContent(); + rotatingCloudEncryptionKeyProvider.loadContent(); operatorKeyProvider.loadContent(operatorKeyProvider.getMetadata()); siteStoreFactory.getGlobalReader().loadContent(siteStoreFactory.getGlobalReader().getMetadata()); clientKeyStoreFactory.getGlobalReader().loadContent(); @@ -123,7 +137,9 @@ public void execute() throws Exception { keysetStoreFactory.getGlobalReader().loadContent(); keysetKeyStoreFactory.getGlobalReader().loadContent(); } + saltProvider.loadContent(); } + Collection globalOperators = operatorKeyProvider.getAll(); Collection globalSites = siteStoreFactory.getGlobalReader().getAllSites(); Collection globalClients = clientKeyStoreFactory.getGlobalReader().getAll(); @@ -146,6 +162,10 @@ public void execute() throws Exception { fileManager, keyAclStoreFactory, MultiScopeStoreWriter::areMapsEqual); + MultiScopeStoreWriter> saltWriter = new MultiScopeStoreWriter<>( + fileManager, + saltStoreFactory, + MultiScopeStoreWriter::areCollectionsEqual); SiteEncryptionJob siteEncryptionSyncJob = new SiteEncryptionJob(siteWriter, globalSites, globalOperators); ClientKeyEncryptionJob clientEncryptionSyncJob = new ClientKeyEncryptionJob(clientWriter, globalClients, globalOperators); @@ -158,10 +178,13 @@ public void execute() throws Exception { encryptionKeyWriter ); KeyAclEncryptionJob keyAclEncryptionSyncJob = new KeyAclEncryptionJob(keyAclWriter, globalOperators, globalKeyAcls); + SaltEncryptionJob saltEncryptionJob = new SaltEncryptionJob(globalOperators, saltProvider.getSnapshots(), saltWriter); + siteEncryptionSyncJob.execute(); clientEncryptionSyncJob.execute(); encryptionKeyEncryptionSyncJob.execute(); keyAclEncryptionSyncJob.execute(); + saltEncryptionJob.execute(); if(config.getBoolean(enableKeysetConfigProp)) { Map globalKeysets = keysetStoreFactory.getGlobalReader().getSnapshot().getAllKeysets(); diff --git a/src/main/java/com/uid2/admin/store/factory/SaltStoreFactory.java b/src/main/java/com/uid2/admin/store/factory/SaltStoreFactory.java index 21f31a1e..b2acb5f0 100644 --- a/src/main/java/com/uid2/admin/store/factory/SaltStoreFactory.java +++ b/src/main/java/com/uid2/admin/store/factory/SaltStoreFactory.java @@ -4,6 +4,7 @@ import com.uid2.admin.store.version.VersionGenerator; import com.uid2.admin.store.writer.EncyptedSaltStoreWriter; import com.uid2.admin.store.writer.StoreWriter; +import com.uid2.shared.Const; import com.uid2.shared.cloud.TaggableCloudStorage; import com.uid2.shared.store.CloudPath; import com.uid2.shared.store.RotatingEncryptedSaltProvider; @@ -18,18 +19,16 @@ public class SaltStoreFactory implements EncryptedStoreFactory> { JsonObject config; CloudPath rootMetadatapath; - RotatingSaltProvider saltProvider; FileManager fileManager; TaggableCloudStorage taggableCloudStorage; VersionGenerator versionGenerator; RotatingCloudEncryptionKeyProvider cloudEncryptionKeyProvider; - public SaltStoreFactory(JsonObject config, CloudPath rootMetadataPath, RotatingSaltProvider saltProvider, FileManager fileManager, + public SaltStoreFactory(JsonObject config, CloudPath rootMetadataPath, FileManager fileManager, TaggableCloudStorage taggableCloudStorage, VersionGenerator versionGenerator, RotatingCloudEncryptionKeyProvider cloudEncryptionKeyProvider) { this.config = config; this.rootMetadatapath = rootMetadataPath; - this.saltProvider = saltProvider; this.fileManager = fileManager; this.taggableCloudStorage = taggableCloudStorage; this.versionGenerator = versionGenerator; @@ -38,15 +37,15 @@ public SaltStoreFactory(JsonObject config, CloudPath rootMetadataPath, RotatingS @Override public StoreWriter> getEncryptedWriter(Integer siteId, boolean isPublic) { - return new EncyptedSaltStoreWriter(config, saltProvider, fileManager, taggableCloudStorage, versionGenerator, - new EncryptedScope(rootMetadatapath, siteId, isPublic), cloudEncryptionKeyProvider, siteId); + EncryptedScope scope = new EncryptedScope(rootMetadatapath, siteId, isPublic); + RotatingEncryptedSaltProvider saltProvider = new RotatingEncryptedSaltProvider(taggableCloudStorage, + scope.resolve(new CloudPath(config.getString(Const.Config.SaltsMetadataPathProp))).toString(), cloudEncryptionKeyProvider ); + return new EncyptedSaltStoreWriter(config, saltProvider, fileManager, taggableCloudStorage, versionGenerator, scope, cloudEncryptionKeyProvider, siteId); } @Override public StoreReader> getEncryptedReader(Integer siteId, boolean isPublic) { - return new RotatingEncryptedSaltProvider(taggableCloudStorage, - new EncryptedScope(rootMetadatapath, siteId, isPublic).getMetadataPath().toString(), - cloudEncryptionKeyProvider); + return null; } @Override diff --git a/src/main/java/com/uid2/admin/store/writer/EncyptedSaltStoreWriter.java b/src/main/java/com/uid2/admin/store/writer/EncyptedSaltStoreWriter.java index d29f8a29..7bf85fc3 100644 --- a/src/main/java/com/uid2/admin/store/writer/EncyptedSaltStoreWriter.java +++ b/src/main/java/com/uid2/admin/store/writer/EncyptedSaltStoreWriter.java @@ -5,6 +5,7 @@ import com.uid2.shared.cloud.TaggableCloudStorage; import com.uid2.shared.encryption.AesGcm; import com.uid2.shared.model.CloudEncryptionKey; +import com.uid2.shared.model.SaltEntry; import com.uid2.shared.store.CloudPath; import com.uid2.shared.store.RotatingSaltProvider; import com.uid2.shared.store.reader.RotatingCloudEncryptionKeyProvider; @@ -13,8 +14,12 @@ import org.slf4j.LoggerFactory; import io.vertx.core.json.JsonObject; +import java.io.BufferedWriter; import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.Base64; +import java.util.Collection; public class EncyptedSaltStoreWriter extends SaltStoreWriter implements StoreWriter { private StoreScope scope; @@ -37,11 +42,19 @@ protected java.lang.String getSaltSnapshotLocation(RotatingSaltProvider.SaltSnap } @Override - protected void upload(String data, String location) throws Exception { + protected void uploadSaltsSnapshot(RotatingSaltProvider.SaltSnapshot snapshot, String location) throws Exception { if (siteId == null) { throw new IllegalStateException("Site ID is not set."); } + StringBuilder stringBuilder = new StringBuilder(); + + for (SaltEntry entry: snapshot.getAllRotatingSalts()) { + stringBuilder.append(entry.getId()).append(",").append(entry.getLastUpdated()).append(",").append(entry.getSalt()).append("\n"); + } + + String data = stringBuilder.toString(); + CloudEncryptionKey encryptionKey = null; try { encryptionKey = cloudEncryptionKeyProvider.getEncryptionKeyForSite(siteId); @@ -59,13 +72,19 @@ protected void upload(String data, String location) throws Exception { throw new IllegalStateException("No Cloud Encryption keys available for encryption for site ID: " + siteId); } + final Path newSaltsFile = Files.createTempFile("salts", ".txt"); + try (BufferedWriter w = Files.newBufferedWriter(newSaltsFile)) { + w.write(encryptedJson.encodePrettily()); + } - super.upload(encryptedJson.encodePrettily(), location); + this.upload(newSaltsFile.toString(), location); } @Override public void upload(Object data, JsonObject extraMeta) throws Exception { - super.upload((RotatingSaltProvider.SaltSnapshot) data); + for(RotatingSaltProvider.SaltSnapshot saltSnapshot: (Collection) data) { + super.upload(saltSnapshot); + } } @Override diff --git a/src/main/java/com/uid2/admin/store/writer/SaltStoreWriter.java b/src/main/java/com/uid2/admin/store/writer/SaltStoreWriter.java index 6d350527..2ea6899b 100644 --- a/src/main/java/com/uid2/admin/store/writer/SaltStoreWriter.java +++ b/src/main/java/com/uid2/admin/store/writer/SaltStoreWriter.java @@ -16,6 +16,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.time.Instant; +import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Map; @@ -46,7 +47,12 @@ public void upload(RotatingSaltProvider.SaltSnapshot data) throws Exception { final Instant now = Instant.now(); final long generated = now.getEpochSecond(); - final JsonObject metadata = provider.getMetadata(); + JsonObject metadata = null; + try { + metadata = provider.getMetadata(); + } catch (Exception e) { + metadata = new JsonObject(); + } // bump up metadata version metadata.put("version", versionGenerator.getVersion()); metadata.put("generated", generated); @@ -54,9 +60,14 @@ public void upload(RotatingSaltProvider.SaltSnapshot data) throws Exception { final JsonArray snapshotsMetadata = new JsonArray(); metadata.put("salts", snapshotsMetadata); - final List snapshots = Stream.concat(provider.getSnapshots().stream(), Stream.of(data)) - .sorted(Comparator.comparing(RotatingSaltProvider.SaltSnapshot::getEffective)) - .collect(Collectors.toList()); + List snapshots = null; + try { + snapshots = Stream.concat(provider.getSnapshots().stream(), Stream.of(data)) + .sorted(Comparator.comparing(RotatingSaltProvider.SaltSnapshot::getEffective)) + .collect(Collectors.toList()); + } catch (Exception e) { + snapshots = List.of(data); + } // of the currently effective snapshots keep only the most recent one RotatingSaltProvider.SaltSnapshot newestEffectiveSnapshot = snapshots.stream() .filter(snapshot -> snapshot.isEffective(now)) @@ -115,7 +126,7 @@ protected String getSaltSnapshotLocation(RotatingSaltProvider.SaltSnapshot snaps return saltSnapshotLocationPrefix + snapshot.getEffective().toEpochMilli(); } - private void uploadSaltsSnapshot(RotatingSaltProvider.SaltSnapshot snapshot, String location) throws Exception { + protected void uploadSaltsSnapshot(RotatingSaltProvider.SaltSnapshot snapshot, String location) throws Exception { // do not overwrite existing files if (!cloudStorage.list(location).isEmpty()) { // update the tags on the file to ensure it is still marked as current diff --git a/src/main/java/com/uid2/admin/util/PrivateSiteUtil.java b/src/main/java/com/uid2/admin/util/PrivateSiteUtil.java index dd81e397..f065ac79 100644 --- a/src/main/java/com/uid2/admin/util/PrivateSiteUtil.java +++ b/src/main/java/com/uid2/admin/util/PrivateSiteUtil.java @@ -8,6 +8,7 @@ import com.uid2.shared.model.KeysetKey; import com.uid2.shared.model.SaltEntry; import com.uid2.shared.model.Site; +import com.uid2.shared.store.RotatingSaltProvider; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -312,10 +313,10 @@ public static PrivateSiteDataMap getKeysetKeys(Collection getPrivateSaltEntries( - Collection globalSaltEntries, + public static PrivateSiteDataMap getPrivateSaltEntries( + Collection globalSaltEntries, Collection operators) { - final PrivateSiteDataMap result = getPrivateSites(operators); + final PrivateSiteDataMap result = getPrivateSites(operators); globalSaltEntries.forEach(saltEntry -> { result.forEach((publicSiteId, publicSiteData) -> { diff --git a/src/main/java/com/uid2/admin/util/PublicSiteUtil.java b/src/main/java/com/uid2/admin/util/PublicSiteUtil.java index 7470c5c2..5b657fc1 100644 --- a/src/main/java/com/uid2/admin/util/PublicSiteUtil.java +++ b/src/main/java/com/uid2/admin/util/PublicSiteUtil.java @@ -10,6 +10,7 @@ import com.uid2.shared.model.KeysetKey; import com.uid2.shared.model.SaltEntry; import com.uid2.shared.model.Site; +import com.uid2.shared.store.RotatingSaltProvider; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -130,10 +131,10 @@ public static PrivateSiteDataMap getPublicKeysetKeys( return result; } - public static PrivateSiteDataMap getPublicSaltEntries( - Collection globalSaltEntries, + public static PrivateSiteDataMap getPublicSaltEntries( + Collection globalSaltEntries, Collection operators) { - final PrivateSiteDataMap result = getPublicSitesMap(operators); + final PrivateSiteDataMap result = getPublicSitesMap(operators); globalSaltEntries.forEach(saltEntry -> { result.forEach((publicSiteId, publicSiteData) -> { From 249fdd052f4a3e8bbe984671af3313bb39fdd406 Mon Sep 17 00:00:00 2001 From: Cody Constine Date: Tue, 10 Dec 2024 16:17:40 -0700 Subject: [PATCH 03/19] Adding in client side keypair encryption --- pom.xml | 2 +- .../ClientSideKeypairEncryptionJob.java | 36 +++++++++ .../job/jobsync/EncryptedFilesSyncJob.java | 21 ++++- .../ClientSideKeypairStoreFactory.java | 79 +++++++++++++++++++ .../admin/store/factory/SaltStoreFactory.java | 4 +- .../writer/ClientSideKeypairStoreWriter.java | 3 +- .../admin/store/writer/SaltStoreWriter.java | 1 - .../com/uid2/admin/util/PublicSiteUtil.java | 19 ++++- .../store/MultiScopeStoreWriterTest.java | 6 ++ .../store/writer/SaltStoreWriterTest.java | 5 ++ 10 files changed, 166 insertions(+), 10 deletions(-) create mode 100644 src/main/java/com/uid2/admin/job/EncryptionJob/ClientSideKeypairEncryptionJob.java create mode 100644 src/main/java/com/uid2/admin/store/factory/ClientSideKeypairStoreFactory.java create mode 100644 src/test/java/com/uid2/admin/store/writer/SaltStoreWriterTest.java diff --git a/pom.xml b/pom.xml index d8e2d5f4..5d212dfd 100644 --- a/pom.xml +++ b/pom.xml @@ -16,7 +16,7 @@ 1.12.2 5.11.2 - 8.0.10-alpha-172-SNAPSHOT + 8.0.11-alpha-173-SNAPSHOT 0.5.10 ${project.version} diff --git a/src/main/java/com/uid2/admin/job/EncryptionJob/ClientSideKeypairEncryptionJob.java b/src/main/java/com/uid2/admin/job/EncryptionJob/ClientSideKeypairEncryptionJob.java new file mode 100644 index 00000000..98d43dd0 --- /dev/null +++ b/src/main/java/com/uid2/admin/job/EncryptionJob/ClientSideKeypairEncryptionJob.java @@ -0,0 +1,36 @@ +package com.uid2.admin.job.EncryptionJob; + +import com.uid2.admin.job.model.Job; +import com.uid2.admin.model.PrivateSiteDataMap; +import com.uid2.admin.store.MultiScopeStoreWriter; +import com.uid2.admin.util.PublicSiteUtil; +import com.uid2.shared.auth.OperatorKey; +import com.uid2.shared.model.ClientSideKeypair; + +import java.util.Collection; + +public class ClientSideKeypairEncryptionJob extends Job { + private final Collection globalOperators; + private final Collection globalClientSideKeypairs; + + private final MultiScopeStoreWriter> multiScopeStoreWriter; + + public ClientSideKeypairEncryptionJob(Collection globalOperators, Collection globalClientSideKeypairs, + MultiScopeStoreWriter> multiScopeStoreWriter) { + this.globalOperators = globalOperators; + this.globalClientSideKeypairs = globalClientSideKeypairs; + this.multiScopeStoreWriter = multiScopeStoreWriter; + } + + @Override + public String getId() { + return "cloud-encryption-sync-clientside-keypair"; + } + + @Override + public void execute() throws Exception { + // Only public operators support clientside keypair + PrivateSiteDataMap desiredPublicState = PublicSiteUtil.getPublicClientKeypairs(globalClientSideKeypairs, globalOperators); + multiScopeStoreWriter.uploadPublicWithEncryption(desiredPublicState, null); + } +} diff --git a/src/main/java/com/uid2/admin/job/jobsync/EncryptedFilesSyncJob.java b/src/main/java/com/uid2/admin/job/jobsync/EncryptedFilesSyncJob.java index ce8c5da3..186809d4 100644 --- a/src/main/java/com/uid2/admin/job/jobsync/EncryptedFilesSyncJob.java +++ b/src/main/java/com/uid2/admin/job/jobsync/EncryptedFilesSyncJob.java @@ -17,12 +17,13 @@ import com.uid2.shared.cloud.CloudUtils; import com.uid2.shared.cloud.ICloudStorage; import com.uid2.shared.cloud.TaggableCloudStorage; +import com.uid2.shared.model.ClientSideKeypair; import com.uid2.shared.model.EncryptionKey; import com.uid2.shared.model.KeysetKey; import com.uid2.shared.model.Site; import com.uid2.shared.store.CloudPath; import com.uid2.admin.legacy.LegacyClientKey; -import com.uid2.shared.store.RotatingEncryptedSaltProvider; +import com.uid2.shared.store.EncryptedRotatingSaltProvider; import com.uid2.shared.store.RotatingSaltProvider; import com.uid2.shared.store.reader.RotatingCloudEncryptionKeyProvider; import com.uid2.shared.store.scope.GlobalScope; @@ -122,6 +123,15 @@ public void execute() throws Exception { rotatingCloudEncryptionKeyProvider ); + ClientSideKeypairStoreFactory clientSideKeypairStoreFactory = new ClientSideKeypairStoreFactory( + cloudStorage, + new CloudPath(config.getString(Const.Config.ClientSideKeypairsMetadataPathProp)), + versionGenerator, + clock, + rotatingCloudEncryptionKeyProvider, + fileManager + ); + CloudPath operatorMetadataPath = new CloudPath(config.getString(Const.Config.OperatorsMetadataPathProp)); GlobalScope operatorScope = new GlobalScope(operatorMetadataPath); RotatingOperatorKeyProvider operatorKeyProvider = new RotatingOperatorKeyProvider(cloudStorage, cloudStorage, operatorScope); @@ -138,6 +148,7 @@ public void execute() throws Exception { keysetKeyStoreFactory.getGlobalReader().loadContent(); } saltProvider.loadContent(); + clientSideKeypairStoreFactory.getGlobalReader().loadContent(); } Collection globalOperators = operatorKeyProvider.getAll(); @@ -146,6 +157,8 @@ public void execute() throws Exception { Collection globalEncryptionKeys = encryptionKeyStoreFactory.getGlobalReader().getSnapshot().getActiveKeySet(); Integer globalMaxKeyId = encryptionKeyStoreFactory.getGlobalReader().getMetadata().getInteger("max_key_id"); Map globalKeyAcls = keyAclStoreFactory.getGlobalReader().getSnapshot().getAllAcls(); + Collection globalClientSideKeypair = clientSideKeypairStoreFactory.getGlobalReader().getAll(); + MultiScopeStoreWriter> siteWriter = new MultiScopeStoreWriter<>( fileManager, siteStoreFactory, @@ -166,6 +179,10 @@ public void execute() throws Exception { fileManager, saltStoreFactory, MultiScopeStoreWriter::areCollectionsEqual); + MultiScopeStoreWriter> clientSideKeypairWriter = new MultiScopeStoreWriter<>( + fileManager, + clientSideKeypairStoreFactory, + MultiScopeStoreWriter::areCollectionsEqual); SiteEncryptionJob siteEncryptionSyncJob = new SiteEncryptionJob(siteWriter, globalSites, globalOperators); ClientKeyEncryptionJob clientEncryptionSyncJob = new ClientKeyEncryptionJob(clientWriter, globalClients, globalOperators); @@ -179,12 +196,14 @@ public void execute() throws Exception { ); KeyAclEncryptionJob keyAclEncryptionSyncJob = new KeyAclEncryptionJob(keyAclWriter, globalOperators, globalKeyAcls); SaltEncryptionJob saltEncryptionJob = new SaltEncryptionJob(globalOperators, saltProvider.getSnapshots(), saltWriter); + ClientSideKeypairEncryptionJob clientSideKeypairEncryptionJob = new ClientSideKeypairEncryptionJob(globalOperators, globalClientSideKeypair, clientSideKeypairWriter); siteEncryptionSyncJob.execute(); clientEncryptionSyncJob.execute(); encryptionKeyEncryptionSyncJob.execute(); keyAclEncryptionSyncJob.execute(); saltEncryptionJob.execute(); + clientSideKeypairEncryptionJob.execute(); if(config.getBoolean(enableKeysetConfigProp)) { Map globalKeysets = keysetStoreFactory.getGlobalReader().getSnapshot().getAllKeysets(); diff --git a/src/main/java/com/uid2/admin/store/factory/ClientSideKeypairStoreFactory.java b/src/main/java/com/uid2/admin/store/factory/ClientSideKeypairStoreFactory.java new file mode 100644 index 00000000..a305d966 --- /dev/null +++ b/src/main/java/com/uid2/admin/store/factory/ClientSideKeypairStoreFactory.java @@ -0,0 +1,79 @@ +package com.uid2.admin.store.factory; + +import com.uid2.admin.store.writer.ClientSideKeypairStoreWriter; +import com.uid2.admin.store.writer.StoreWriter; +import com.uid2.shared.model.ClientSideKeypair; +import com.uid2.shared.store.reader.RotatingClientSideKeypairStore; +import com.uid2.shared.store.reader.RotatingCloudEncryptionKeyProvider; +import com.uid2.shared.store.reader.StoreReader; +import com.fasterxml.jackson.databind.ObjectWriter; +import com.uid2.admin.store.Clock; +import com.uid2.admin.store.FileManager; +import com.uid2.admin.store.version.VersionGenerator; +import com.uid2.shared.cloud.ICloudStorage; +import com.uid2.shared.store.CloudPath; +import com.uid2.shared.store.scope.EncryptedScope; +import com.uid2.shared.store.scope.GlobalScope; +import com.uid2.shared.store.scope.SiteScope; + +import java.util.Collection; + +public class ClientSideKeypairStoreFactory implements EncryptedStoreFactory> { + private final ICloudStorage fileStreamProvider; + private final CloudPath rootMetadataPath; + private final VersionGenerator versionGenerator; + private final Clock clock; + private final FileManager fileManager; + private final RotatingClientSideKeypairStore globalReader; + private final RotatingCloudEncryptionKeyProvider cloudEncryptionKeyProvider; + + public ClientSideKeypairStoreFactory( + ICloudStorage fileStreamProvider, + CloudPath rootMetadataPath, + VersionGenerator versionGenerator, + Clock clock, + RotatingCloudEncryptionKeyProvider cloudEncryptionKeyProvider, + FileManager fileManager) { + this.fileStreamProvider = fileStreamProvider; + this.rootMetadataPath = rootMetadataPath; + this.versionGenerator = versionGenerator; + this.clock = clock; + this.cloudEncryptionKeyProvider = cloudEncryptionKeyProvider; + this.fileManager = fileManager; + GlobalScope globalScope = new GlobalScope(rootMetadataPath); + globalReader = new RotatingClientSideKeypairStore(fileStreamProvider, globalScope); + } + + public RotatingClientSideKeypairStore getGlobalReader() { + return globalReader; + } + + @Override + public StoreWriter> getEncryptedWriter(Integer siteId, boolean isPublic) { + return new ClientSideKeypairStoreWriter(getEncryptedReader(siteId, isPublic), + fileManager, + versionGenerator, + clock, + new EncryptedScope(rootMetadataPath, siteId, isPublic)); + } + + @Override + public StoreReader> getEncryptedReader(Integer siteId, boolean isPublic) { + return new RotatingClientSideKeypairStore(fileStreamProvider, new EncryptedScope(rootMetadataPath, siteId, isPublic)); + } + + @Override + public RotatingCloudEncryptionKeyProvider getCloudEncryptionProvider() { + return cloudEncryptionKeyProvider; + } + + @Override + public StoreReader> getReader(Integer siteId) { + return new RotatingClientSideKeypairStore(fileStreamProvider, new SiteScope(rootMetadataPath, siteId)); + } + + @Override + public StoreWriter> getWriter(Integer siteId) { + return new ClientSideKeypairStoreWriter(getReader(siteId), fileManager, versionGenerator, clock, new SiteScope(rootMetadataPath, siteId)); + } +} diff --git a/src/main/java/com/uid2/admin/store/factory/SaltStoreFactory.java b/src/main/java/com/uid2/admin/store/factory/SaltStoreFactory.java index b2acb5f0..afce4442 100644 --- a/src/main/java/com/uid2/admin/store/factory/SaltStoreFactory.java +++ b/src/main/java/com/uid2/admin/store/factory/SaltStoreFactory.java @@ -7,7 +7,7 @@ import com.uid2.shared.Const; import com.uid2.shared.cloud.TaggableCloudStorage; import com.uid2.shared.store.CloudPath; -import com.uid2.shared.store.RotatingEncryptedSaltProvider; +import com.uid2.shared.store.EncryptedRotatingSaltProvider; import com.uid2.shared.store.RotatingSaltProvider; import com.uid2.shared.store.reader.RotatingCloudEncryptionKeyProvider; import com.uid2.shared.store.reader.StoreReader; @@ -38,7 +38,7 @@ public SaltStoreFactory(JsonObject config, CloudPath rootMetadataPath, FileManag @Override public StoreWriter> getEncryptedWriter(Integer siteId, boolean isPublic) { EncryptedScope scope = new EncryptedScope(rootMetadatapath, siteId, isPublic); - RotatingEncryptedSaltProvider saltProvider = new RotatingEncryptedSaltProvider(taggableCloudStorage, + EncryptedRotatingSaltProvider saltProvider = new EncryptedRotatingSaltProvider(taggableCloudStorage, scope.resolve(new CloudPath(config.getString(Const.Config.SaltsMetadataPathProp))).toString(), cloudEncryptionKeyProvider ); return new EncyptedSaltStoreWriter(config, saltProvider, fileManager, taggableCloudStorage, versionGenerator, scope, cloudEncryptionKeyProvider, siteId); } diff --git a/src/main/java/com/uid2/admin/store/writer/ClientSideKeypairStoreWriter.java b/src/main/java/com/uid2/admin/store/writer/ClientSideKeypairStoreWriter.java index fe48e533..24a96d06 100644 --- a/src/main/java/com/uid2/admin/store/writer/ClientSideKeypairStoreWriter.java +++ b/src/main/java/com/uid2/admin/store/writer/ClientSideKeypairStoreWriter.java @@ -6,6 +6,7 @@ import com.uid2.admin.store.version.VersionGenerator; import com.uid2.shared.model.ClientSideKeypair; import com.uid2.shared.store.reader.RotatingClientSideKeypairStore; +import com.uid2.shared.store.reader.StoreReader; import com.uid2.shared.store.scope.StoreScope; import io.vertx.core.json.JsonArray; import io.vertx.core.json.JsonObject; @@ -17,7 +18,7 @@ public class ClientSideKeypairStoreWriter implements StoreWriter> store, FileManager fileManager, VersionGenerator versionGenerator, Clock clock, StoreScope scope) { FileName dataFile = new FileName("client_side_keypairs", ".json"); String dataType = "client_side_keypairs"; writer = new ScopedStoreWriter(store, fileManager, versionGenerator, clock, scope, dataFile, dataType); diff --git a/src/main/java/com/uid2/admin/store/writer/SaltStoreWriter.java b/src/main/java/com/uid2/admin/store/writer/SaltStoreWriter.java index 2ea6899b..46a4b2a5 100644 --- a/src/main/java/com/uid2/admin/store/writer/SaltStoreWriter.java +++ b/src/main/java/com/uid2/admin/store/writer/SaltStoreWriter.java @@ -141,7 +141,6 @@ protected void uploadSaltsSnapshot(RotatingSaltProvider.SaltSnapshot snapshot, S } } - //cloudStorage.upload(newSaltsFile.toString(), location, this.currentTags); this.upload(newSaltsFile.toString(), location); } diff --git a/src/main/java/com/uid2/admin/util/PublicSiteUtil.java b/src/main/java/com/uid2/admin/util/PublicSiteUtil.java index 5b657fc1..f3ec8fd9 100644 --- a/src/main/java/com/uid2/admin/util/PublicSiteUtil.java +++ b/src/main/java/com/uid2/admin/util/PublicSiteUtil.java @@ -6,10 +6,7 @@ import com.uid2.shared.auth.Keyset; import com.uid2.shared.auth.OperatorKey; import com.uid2.shared.auth.OperatorType; -import com.uid2.shared.model.EncryptionKey; -import com.uid2.shared.model.KeysetKey; -import com.uid2.shared.model.SaltEntry; -import com.uid2.shared.model.Site; +import com.uid2.shared.model.*; import com.uid2.shared.store.RotatingSaltProvider; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -144,4 +141,18 @@ public static PrivateSiteDataMap getPublicSal return result; } + + public static PrivateSiteDataMap getPublicClientKeypairs( + Collection globalClientSideKeypair, + Collection operators) { + final PrivateSiteDataMap result = getPublicSitesMap(operators); + + globalClientSideKeypair.forEach(clientSideKeypair -> { + result.forEach((publicSiteId, publicSiteData) -> { + publicSiteData.add(clientSideKeypair); + }); + }); + + return result; + } } diff --git a/src/test/java/com/uid2/admin/store/MultiScopeStoreWriterTest.java b/src/test/java/com/uid2/admin/store/MultiScopeStoreWriterTest.java index 8f6adec9..4910c300 100644 --- a/src/test/java/com/uid2/admin/store/MultiScopeStoreWriterTest.java +++ b/src/test/java/com/uid2/admin/store/MultiScopeStoreWriterTest.java @@ -109,6 +109,10 @@ public void overwritesExistingDataWhenChanged() throws Exception { reader.loadContent(); Long oldVersion = reader.getMetadata().getLong("version"); + // This test relies on our version generator returning a new timestamp, but the code can execute so fast we don't get a new version + // This small sleep makes this test much more stable + Thread.sleep(100); + Site updatedSite = new Site(scopedSiteId, "site 1 updated", true); MultiScopeStoreWriter> multiStore = new MultiScopeStoreWriter<>(fileManager, siteStoreFactory, MultiScopeStoreWriter::areCollectionsEqual); @@ -204,6 +208,7 @@ public void uploadPrivateWithEncryption() throws Exception { Map allKeys = new HashMap<>(); allKeys.put(1, encryptionKey); when(cloudEncryptionKeyProvider.getAll()).thenReturn(allKeys); + when(cloudEncryptionKeyProvider.getKey(1)).thenReturn(encryptionKey); SiteStoreFactory siteStoreFactory = new SiteStoreFactory( cloudStorage, @@ -241,6 +246,7 @@ public void uploadPublicWithEncryption() throws Exception { Map allKeys = new HashMap<>(); allKeys.put(1, encryptionKey); when(cloudEncryptionKeyProvider.getAll()).thenReturn(allKeys); + when(cloudEncryptionKeyProvider.getKey(1)).thenReturn(encryptionKey); SiteStoreFactory siteStoreFactory = new SiteStoreFactory( cloudStorage, diff --git a/src/test/java/com/uid2/admin/store/writer/SaltStoreWriterTest.java b/src/test/java/com/uid2/admin/store/writer/SaltStoreWriterTest.java new file mode 100644 index 00000000..3355a313 --- /dev/null +++ b/src/test/java/com/uid2/admin/store/writer/SaltStoreWriterTest.java @@ -0,0 +1,5 @@ +package com.uid2.admin.store.writer; + +public class SaltStoreWriterTest { + +} From b3da3d905fb6379b9c26709a76d6fbe749c9ef5e Mon Sep 17 00:00:00 2001 From: Cody Constine Date: Tue, 10 Dec 2024 17:18:21 -0700 Subject: [PATCH 04/19] Adding encrypted salt writer test --- .../admin/store/writer/SaltStoreWriter.java | 16 ++- .../writer/EncryptedSaltStoreWriterTest.java | 124 ++++++++++++++++++ .../store/writer/SaltStoreWriterTest.java | 5 - 3 files changed, 135 insertions(+), 10 deletions(-) create mode 100644 src/test/java/com/uid2/admin/store/writer/EncryptedSaltStoreWriterTest.java delete mode 100644 src/test/java/com/uid2/admin/store/writer/SaltStoreWriterTest.java diff --git a/src/main/java/com/uid2/admin/store/writer/SaltStoreWriter.java b/src/main/java/com/uid2/admin/store/writer/SaltStoreWriter.java index 46a4b2a5..f5e953d4 100644 --- a/src/main/java/com/uid2/admin/store/writer/SaltStoreWriter.java +++ b/src/main/java/com/uid2/admin/store/writer/SaltStoreWriter.java @@ -50,8 +50,12 @@ public void upload(RotatingSaltProvider.SaltSnapshot data) throws Exception { JsonObject metadata = null; try { metadata = provider.getMetadata(); - } catch (Exception e) { - metadata = new JsonObject(); + } catch (CloudStorageException e) { + if (e.getMessage().contains("The specified key does not exist")) { + metadata = new JsonObject(); + } else { + throw e; + } } // bump up metadata version metadata.put("version", versionGenerator.getVersion()); @@ -60,12 +64,14 @@ public void upload(RotatingSaltProvider.SaltSnapshot data) throws Exception { final JsonArray snapshotsMetadata = new JsonArray(); metadata.put("salts", snapshotsMetadata); + List currentSnapshots = provider.getSnapshots(); List snapshots = null; - try { - snapshots = Stream.concat(provider.getSnapshots().stream(), Stream.of(data)) + + if (currentSnapshots != null) { + snapshots = Stream.concat(currentSnapshots.stream(), Stream.of(data)) .sorted(Comparator.comparing(RotatingSaltProvider.SaltSnapshot::getEffective)) .collect(Collectors.toList()); - } catch (Exception e) { + } else { snapshots = List.of(data); } // of the currently effective snapshots keep only the most recent one diff --git a/src/test/java/com/uid2/admin/store/writer/EncryptedSaltStoreWriterTest.java b/src/test/java/com/uid2/admin/store/writer/EncryptedSaltStoreWriterTest.java new file mode 100644 index 00000000..e351ad5e --- /dev/null +++ b/src/test/java/com/uid2/admin/store/writer/EncryptedSaltStoreWriterTest.java @@ -0,0 +1,124 @@ +package com.uid2.admin.store.writer; + +import com.uid2.admin.store.FileManager; +import com.uid2.admin.store.writer.EncyptedSaltStoreWriter; +import com.uid2.admin.store.version.VersionGenerator; +import com.uid2.shared.cloud.CloudStorageException; +import com.uid2.shared.cloud.TaggableCloudStorage; +import com.uid2.shared.model.CloudEncryptionKey; +import com.uid2.shared.model.SaltEntry; +import com.uid2.shared.store.CloudPath; +import com.uid2.shared.store.RotatingSaltProvider; +import com.uid2.shared.store.reader.RotatingCloudEncryptionKeyProvider; +import com.uid2.shared.store.scope.StoreScope; +import io.vertx.core.json.JsonObject; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Captor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.time.Instant; +import java.util.*; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.*; +import static com.uid2.shared.util.CloudEncryptionHelpers.decryptInputStream; + +public class EncryptedSaltStoreWriterTest { + private AutoCloseable mocks; + + @Mock + private FileManager fileManager; + + @Mock + TaggableCloudStorage taggableCloudStorage; + + @Mock + RotatingSaltProvider rotatingSaltProvider; + + @Mock + RotatingCloudEncryptionKeyProvider rotatingCloudEncryptionKeyProvider; + + @Mock + VersionGenerator versionGenerator; + + @Mock + StoreScope storeScope; + + CloudEncryptionKey encryptionKey; + + JsonObject config; + + private final Integer siteId = 1; + + @Captor + private ArgumentCaptor pathCaptor; + + @BeforeEach + public void setUp() throws Exception { + mocks = MockitoAnnotations.openMocks(this); + config = new JsonObject(); + config.put("salt_snapshot_location_prefix", "test"); + + when(versionGenerator.getVersion()).thenReturn(1L); + when(rotatingSaltProvider.getMetadataPath()).thenReturn("test/path/"); + when(storeScope.resolve(any())).thenReturn(new CloudPath("test/path/")); + + // Setup Cloud Encryption Keys + byte[] keyBytes = new byte[32]; + new Random().nextBytes(keyBytes); + String base64Key = Base64.getEncoder().encodeToString(keyBytes); + encryptionKey = new CloudEncryptionKey(1, 1, 0, 0, base64Key); + + Map mockKeyMap = new HashMap<>(); + mockKeyMap.put(encryptionKey.getId(), encryptionKey); + when(rotatingCloudEncryptionKeyProvider.getAll()).thenReturn(mockKeyMap); + when(rotatingCloudEncryptionKeyProvider.getKey(1)).thenReturn(mockKeyMap.get(1)); + when(rotatingCloudEncryptionKeyProvider.getEncryptionKeyForSite(siteId)).thenReturn(encryptionKey); + } + + private RotatingSaltProvider.SaltSnapshot makeSnapshot(Instant effective, Instant expires, int nsalts) { + SaltEntry[] entries = new SaltEntry[nsalts]; + for (int i = 0; i < entries.length; ++i) { + entries[i] = new SaltEntry(i, "hashed_id", effective.toEpochMilli(), "salt"); + } + return new RotatingSaltProvider.SaltSnapshot(effective, expires, entries, "test_first_level_salt"); + } + + private void verifyFile(String filelocation, RotatingSaltProvider.SaltSnapshot snapshot) throws IOException { + InputStream encoded = Files.newInputStream(Paths.get(filelocation)); + String contents = decryptInputStream(encoded, rotatingCloudEncryptionKeyProvider); + SaltEntry[] entries = snapshot.getAllRotatingSalts(); + Integer idx = 0; + for (String line : contents.split("\n")) { + String[] entrySplit = line.split(","); + assertEquals(entries[idx].getId(), Long.parseLong(entrySplit[0])); + assertEquals(entries[idx].getSalt(), entrySplit[2]); + idx++; + } + } + + @Test + public void testUploadNew() throws Exception { + RotatingSaltProvider.SaltSnapshot snapshot = makeSnapshot(Instant.now(), Instant.ofEpochMilli(Instant.now().toEpochMilli() + 10000), 100); + + when(rotatingSaltProvider.getMetadata()).thenThrow(new CloudStorageException("The specified key does not exist: AmazonS3Exception: test-core-bucket")); + when(rotatingSaltProvider.getSnapshots()).thenReturn(null); + + when(taggableCloudStorage.list(anyString())).thenReturn(new ArrayList<>()); + + EncyptedSaltStoreWriter encryptedSaltStoreWriter = new EncyptedSaltStoreWriter(config, rotatingSaltProvider, + fileManager, taggableCloudStorage, versionGenerator, storeScope, rotatingCloudEncryptionKeyProvider, siteId); + + encryptedSaltStoreWriter.upload(snapshot); + + verify(taggableCloudStorage).upload(pathCaptor.capture(), any(), any()); + verifyFile(pathCaptor.getValue(), snapshot); + } +} diff --git a/src/test/java/com/uid2/admin/store/writer/SaltStoreWriterTest.java b/src/test/java/com/uid2/admin/store/writer/SaltStoreWriterTest.java deleted file mode 100644 index 3355a313..00000000 --- a/src/test/java/com/uid2/admin/store/writer/SaltStoreWriterTest.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.uid2.admin.store.writer; - -public class SaltStoreWriterTest { - -} From 38838530836ffdb898a0c5916698398c041768ff Mon Sep 17 00:00:00 2001 From: Release Workflow Date: Wed, 11 Dec 2024 18:46:00 +0000 Subject: [PATCH 05/19] [CI Pipeline] Released Snapshot version: 5.16.1-alpha-96-SNAPSHOT --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 5d212dfd..f7227eaa 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.uid2 uid2-admin - 5.16.0 + 5.16.1-alpha-96-SNAPSHOT UTF-8 From f820cccab632e87d8a13e98b0fb52845d193178d Mon Sep 17 00:00:00 2001 From: Cody Constine Date: Wed, 11 Dec 2024 14:09:33 -0700 Subject: [PATCH 06/19] Making change to multiscope writer to not copy all salts for each site --- .../job/EncryptionJob/SaltEncryptionJob.java | 9 +++++---- .../admin/store/MultiScopeStoreWriter.java | 14 ++++++++++++++ .../admin/store/factory/SaltStoreFactory.java | 7 +++++++ .../com/uid2/admin/util/PrivateSiteUtil.java | 13 ++----------- .../com/uid2/admin/util/PublicSiteUtil.java | 18 +++--------------- .../writer/EncryptedSaltStoreWriterTest.java | 6 +++++- 6 files changed, 36 insertions(+), 31 deletions(-) diff --git a/src/main/java/com/uid2/admin/job/EncryptionJob/SaltEncryptionJob.java b/src/main/java/com/uid2/admin/job/EncryptionJob/SaltEncryptionJob.java index 6ab992f8..4ffb7b11 100644 --- a/src/main/java/com/uid2/admin/job/EncryptionJob/SaltEncryptionJob.java +++ b/src/main/java/com/uid2/admin/job/EncryptionJob/SaltEncryptionJob.java @@ -10,6 +10,7 @@ import com.uid2.shared.store.RotatingSaltProvider; import java.util.Collection; +import java.util.List; public class SaltEncryptionJob extends Job { private final Collection globalOperators; @@ -32,9 +33,9 @@ public String getId() { @Override public void execute() throws Exception { - PrivateSiteDataMap desiredPrivateState = PrivateSiteUtil.getPrivateSaltEntries(saltEntries, globalOperators); - multiScopeStoreWriter.uploadPrivateWithEncryption(desiredPrivateState, null); - PrivateSiteDataMap desiredPublicState = PublicSiteUtil.getPublicSaltEntries(saltEntries, globalOperators); - multiScopeStoreWriter.uploadPublicWithEncryption(desiredPublicState, null); + List desiredPrivateState = PrivateSiteUtil.getPrivateSaltSites(globalOperators); + multiScopeStoreWriter.uploadPrivateWithEncryption(desiredPrivateState, saltEntries, null); + List desiredPublicState = PublicSiteUtil.getPublicSaltSites(globalOperators); + multiScopeStoreWriter.uploadPublicWithEncryption(desiredPublicState, saltEntries, null); } } diff --git a/src/main/java/com/uid2/admin/store/MultiScopeStoreWriter.java b/src/main/java/com/uid2/admin/store/MultiScopeStoreWriter.java index 879b4e12..7c2205ca 100644 --- a/src/main/java/com/uid2/admin/store/MultiScopeStoreWriter.java +++ b/src/main/java/com/uid2/admin/store/MultiScopeStoreWriter.java @@ -69,6 +69,13 @@ public void uploadPrivateWithEncryption(Map desiredState, JsonObject } } + public void uploadPrivateWithEncryption(List siteIds, T desiredState, JsonObject extraMeta) throws Exception { + EncryptedStoreFactory encryptedFactory = (EncryptedStoreFactory) factory; + for (Integer siteId : siteIds) { + encryptedFactory.getEncryptedWriter(siteId,false).upload(desiredState, extraMeta); + } + } + public void uploadPublicWithEncryption(Map desiredPublicState, JsonObject extraMeta) throws Exception { EncryptedStoreFactory encryptedFactory = (EncryptedStoreFactory) factory; for (Map.Entry entry : desiredPublicState.entrySet()) { @@ -77,6 +84,13 @@ public void uploadPublicWithEncryption(Map desiredPublicState, JsonO } } + public void uploadPublicWithEncryption(List siteIds, T desiredState, JsonObject extraMeta) throws Exception { + EncryptedStoreFactory encryptedFactory = (EncryptedStoreFactory) factory; + for (Integer siteId : siteIds) { + encryptedFactory.getEncryptedWriter(siteId,true).upload(desiredState, extraMeta); + } + } + public static boolean areMapsEqual(Map a, Map b) { return a.size() == b.size() && a.entrySet().stream().allMatch(b.entrySet()::contains); } diff --git a/src/main/java/com/uid2/admin/store/factory/SaltStoreFactory.java b/src/main/java/com/uid2/admin/store/factory/SaltStoreFactory.java index afce4442..bd1fbcb9 100644 --- a/src/main/java/com/uid2/admin/store/factory/SaltStoreFactory.java +++ b/src/main/java/com/uid2/admin/store/factory/SaltStoreFactory.java @@ -13,10 +13,14 @@ import com.uid2.shared.store.reader.StoreReader; import com.uid2.shared.store.scope.EncryptedScope; import io.vertx.core.json.JsonObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.util.Collection; public class SaltStoreFactory implements EncryptedStoreFactory> { + private static final Logger LOGGER = LoggerFactory.getLogger(SaltStoreFactory.class); + JsonObject config; CloudPath rootMetadatapath; FileManager fileManager; @@ -45,6 +49,7 @@ public StoreWriter> getEncryptedWr @Override public StoreReader> getEncryptedReader(Integer siteId, boolean isPublic) { + LOGGER.warn("getEncryptedReader called on SaltStoreFactory. This method is not implemented."); return null; } @@ -55,11 +60,13 @@ public RotatingCloudEncryptionKeyProvider getCloudEncryptionProvider() { @Override public StoreReader> getReader(Integer siteId) { + LOGGER.warn("getReader called on SaltStoreFactory. This method is not implemented."); return null; } @Override public StoreWriter> getWriter(Integer siteId) { + LOGGER.warn("getWriter called on SaltStoreFactory. This method is not implemented."); return null; } } diff --git a/src/main/java/com/uid2/admin/util/PrivateSiteUtil.java b/src/main/java/com/uid2/admin/util/PrivateSiteUtil.java index f065ac79..525b9494 100644 --- a/src/main/java/com/uid2/admin/util/PrivateSiteUtil.java +++ b/src/main/java/com/uid2/admin/util/PrivateSiteUtil.java @@ -313,17 +313,8 @@ public static PrivateSiteDataMap getKeysetKeys(Collection getPrivateSaltEntries( - Collection globalSaltEntries, - Collection operators) { + public static List getPrivateSaltSites(Collection operators) { final PrivateSiteDataMap result = getPrivateSites(operators); - - globalSaltEntries.forEach(saltEntry -> { - result.forEach((publicSiteId, publicSiteData) -> { - publicSiteData.add(saltEntry); - }); - }); - - return result; + return result.keySet().stream().toList(); } } diff --git a/src/main/java/com/uid2/admin/util/PublicSiteUtil.java b/src/main/java/com/uid2/admin/util/PublicSiteUtil.java index f3ec8fd9..815454b4 100644 --- a/src/main/java/com/uid2/admin/util/PublicSiteUtil.java +++ b/src/main/java/com/uid2/admin/util/PublicSiteUtil.java @@ -11,10 +11,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; +import java.util.*; public class PublicSiteUtil { private static final Logger LOGGER = LoggerFactory.getLogger(PrivateSiteUtil.class); @@ -128,18 +125,9 @@ public static PrivateSiteDataMap getPublicKeysetKeys( return result; } - public static PrivateSiteDataMap getPublicSaltEntries( - Collection globalSaltEntries, - Collection operators) { + public static List getPublicSaltSites(Collection operators) { final PrivateSiteDataMap result = getPublicSitesMap(operators); - - globalSaltEntries.forEach(saltEntry -> { - result.forEach((publicSiteId, publicSiteData) -> { - publicSiteData.add(saltEntry); - }); - }); - - return result; + return result.keySet().stream().toList(); } public static PrivateSiteDataMap getPublicClientKeypairs( diff --git a/src/test/java/com/uid2/admin/store/writer/EncryptedSaltStoreWriterTest.java b/src/test/java/com/uid2/admin/store/writer/EncryptedSaltStoreWriterTest.java index e351ad5e..207dbf05 100644 --- a/src/test/java/com/uid2/admin/store/writer/EncryptedSaltStoreWriterTest.java +++ b/src/test/java/com/uid2/admin/store/writer/EncryptedSaltStoreWriterTest.java @@ -59,6 +59,8 @@ public class EncryptedSaltStoreWriterTest { @Captor private ArgumentCaptor pathCaptor; + @Captor + private ArgumentCaptor cloudPathCaptor; @BeforeEach public void setUp() throws Exception { @@ -118,7 +120,9 @@ public void testUploadNew() throws Exception { encryptedSaltStoreWriter.upload(snapshot); - verify(taggableCloudStorage).upload(pathCaptor.capture(), any(), any()); + verify(taggableCloudStorage).upload(pathCaptor.capture(), cloudPathCaptor.capture(), any()); + assertEquals(cloudPathCaptor.getValue(), "test/path"); + verifyFile(pathCaptor.getValue(), snapshot); } } From 1653bf06be1344c4cfaf75a2709fb84c725cfed5 Mon Sep 17 00:00:00 2001 From: Release Workflow Date: Wed, 11 Dec 2024 21:12:18 +0000 Subject: [PATCH 07/19] [CI Pipeline] Released Snapshot version: 5.16.2-alpha-97-SNAPSHOT --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index f7227eaa..fccd9037 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.uid2 uid2-admin - 5.16.1-alpha-96-SNAPSHOT + 5.16.2-alpha-97-SNAPSHOT UTF-8 From 18b99bfe6b885a9ae40004b12db804925e302f19 Mon Sep 17 00:00:00 2001 From: Cody Constine Date: Wed, 11 Dec 2024 15:10:45 -0700 Subject: [PATCH 08/19] Adding new shared and fixing bad file name --- pom.xml | 2 +- .../com/uid2/admin/store/factory/SaltStoreFactory.java | 4 ++-- ...tStoreWriter.java => EncryptedSaltStoreWriter.java} | 10 +++++----- .../store/writer/EncryptedSaltStoreWriterTest.java | 5 ++--- 4 files changed, 10 insertions(+), 11 deletions(-) rename src/main/java/com/uid2/admin/store/writer/{EncyptedSaltStoreWriter.java => EncryptedSaltStoreWriter.java} (88%) diff --git a/pom.xml b/pom.xml index fccd9037..dde73faa 100644 --- a/pom.xml +++ b/pom.xml @@ -16,7 +16,7 @@ 1.12.2 5.11.2 - 8.0.11-alpha-173-SNAPSHOT + 8.0.12-alpha-174-SNAPSHOT 0.5.10 ${project.version} diff --git a/src/main/java/com/uid2/admin/store/factory/SaltStoreFactory.java b/src/main/java/com/uid2/admin/store/factory/SaltStoreFactory.java index bd1fbcb9..a7369a12 100644 --- a/src/main/java/com/uid2/admin/store/factory/SaltStoreFactory.java +++ b/src/main/java/com/uid2/admin/store/factory/SaltStoreFactory.java @@ -2,7 +2,7 @@ import com.uid2.admin.store.FileManager; import com.uid2.admin.store.version.VersionGenerator; -import com.uid2.admin.store.writer.EncyptedSaltStoreWriter; +import com.uid2.admin.store.writer.EncryptedSaltStoreWriter; import com.uid2.admin.store.writer.StoreWriter; import com.uid2.shared.Const; import com.uid2.shared.cloud.TaggableCloudStorage; @@ -44,7 +44,7 @@ public StoreWriter> getEncryptedWr EncryptedScope scope = new EncryptedScope(rootMetadatapath, siteId, isPublic); EncryptedRotatingSaltProvider saltProvider = new EncryptedRotatingSaltProvider(taggableCloudStorage, scope.resolve(new CloudPath(config.getString(Const.Config.SaltsMetadataPathProp))).toString(), cloudEncryptionKeyProvider ); - return new EncyptedSaltStoreWriter(config, saltProvider, fileManager, taggableCloudStorage, versionGenerator, scope, cloudEncryptionKeyProvider, siteId); + return new EncryptedSaltStoreWriter(config, saltProvider, fileManager, taggableCloudStorage, versionGenerator, scope, cloudEncryptionKeyProvider, siteId); } @Override diff --git a/src/main/java/com/uid2/admin/store/writer/EncyptedSaltStoreWriter.java b/src/main/java/com/uid2/admin/store/writer/EncryptedSaltStoreWriter.java similarity index 88% rename from src/main/java/com/uid2/admin/store/writer/EncyptedSaltStoreWriter.java rename to src/main/java/com/uid2/admin/store/writer/EncryptedSaltStoreWriter.java index 7bf85fc3..ee79c526 100644 --- a/src/main/java/com/uid2/admin/store/writer/EncyptedSaltStoreWriter.java +++ b/src/main/java/com/uid2/admin/store/writer/EncryptedSaltStoreWriter.java @@ -21,15 +21,15 @@ import java.util.Base64; import java.util.Collection; -public class EncyptedSaltStoreWriter extends SaltStoreWriter implements StoreWriter { +public class EncryptedSaltStoreWriter extends SaltStoreWriter implements StoreWriter { private StoreScope scope; private RotatingCloudEncryptionKeyProvider cloudEncryptionKeyProvider; private Integer siteId; - private static final Logger LOGGER = LoggerFactory.getLogger(EncyptedSaltStoreWriter.class); - public EncyptedSaltStoreWriter(JsonObject config, RotatingSaltProvider provider, FileManager fileManager, - TaggableCloudStorage cloudStorage, VersionGenerator versionGenerator, StoreScope scope, - RotatingCloudEncryptionKeyProvider cloudEncryptionKeyProvider, Integer siteId) { + private static final Logger LOGGER = LoggerFactory.getLogger(EncryptedSaltStoreWriter.class); + public EncryptedSaltStoreWriter(JsonObject config, RotatingSaltProvider provider, FileManager fileManager, + TaggableCloudStorage cloudStorage, VersionGenerator versionGenerator, StoreScope scope, + RotatingCloudEncryptionKeyProvider cloudEncryptionKeyProvider, Integer siteId) { super(config, provider, fileManager, cloudStorage, versionGenerator); this.scope = scope; this.cloudEncryptionKeyProvider = cloudEncryptionKeyProvider; diff --git a/src/test/java/com/uid2/admin/store/writer/EncryptedSaltStoreWriterTest.java b/src/test/java/com/uid2/admin/store/writer/EncryptedSaltStoreWriterTest.java index 207dbf05..f7555106 100644 --- a/src/test/java/com/uid2/admin/store/writer/EncryptedSaltStoreWriterTest.java +++ b/src/test/java/com/uid2/admin/store/writer/EncryptedSaltStoreWriterTest.java @@ -1,7 +1,6 @@ package com.uid2.admin.store.writer; import com.uid2.admin.store.FileManager; -import com.uid2.admin.store.writer.EncyptedSaltStoreWriter; import com.uid2.admin.store.version.VersionGenerator; import com.uid2.shared.cloud.CloudStorageException; import com.uid2.shared.cloud.TaggableCloudStorage; @@ -108,14 +107,14 @@ private void verifyFile(String filelocation, RotatingSaltProvider.SaltSnapshot s @Test public void testUploadNew() throws Exception { - RotatingSaltProvider.SaltSnapshot snapshot = makeSnapshot(Instant.now(), Instant.ofEpochMilli(Instant.now().toEpochMilli() + 10000), 100); + RotatingSaltProvider.SaltSnapshot snapshot = makeSnapshot(Instant.now(), Instant.ofEpochMilli(Instant.now().toEpochMilli() + 10000), 1000000); when(rotatingSaltProvider.getMetadata()).thenThrow(new CloudStorageException("The specified key does not exist: AmazonS3Exception: test-core-bucket")); when(rotatingSaltProvider.getSnapshots()).thenReturn(null); when(taggableCloudStorage.list(anyString())).thenReturn(new ArrayList<>()); - EncyptedSaltStoreWriter encryptedSaltStoreWriter = new EncyptedSaltStoreWriter(config, rotatingSaltProvider, + EncryptedSaltStoreWriter encryptedSaltStoreWriter = new EncryptedSaltStoreWriter(config, rotatingSaltProvider, fileManager, taggableCloudStorage, versionGenerator, storeScope, rotatingCloudEncryptionKeyProvider, siteId); encryptedSaltStoreWriter.upload(snapshot); From ddd95946e85fef32469b6a54f596c96eb6a10799 Mon Sep 17 00:00:00 2001 From: Release Workflow Date: Wed, 11 Dec 2024 22:13:27 +0000 Subject: [PATCH 09/19] [CI Pipeline] Released Snapshot version: 5.16.3-alpha-98-SNAPSHOT --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index dde73faa..1a149cff 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.uid2 uid2-admin - 5.16.2-alpha-97-SNAPSHOT + 5.16.3-alpha-98-SNAPSHOT UTF-8 From d0d58fc601d99a8d8115d8d4d6909918b2c8f8a9 Mon Sep 17 00:00:00 2001 From: Cody Constine Date: Wed, 11 Dec 2024 16:08:31 -0700 Subject: [PATCH 10/19] Fixed client side keypair issue --- pom.xml | 2 +- .../store/factory/ClientSideKeypairStoreFactory.java | 5 +++-- .../admin/store/writer/ClientSideKeypairStoreWriter.java | 8 ++++++++ 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index dde73faa..5b033808 100644 --- a/pom.xml +++ b/pom.xml @@ -16,7 +16,7 @@ 1.12.2 5.11.2 - 8.0.12-alpha-174-SNAPSHOT + 8.0.13-alpha-175-SNAPSHOT 0.5.10 ${project.version} diff --git a/src/main/java/com/uid2/admin/store/factory/ClientSideKeypairStoreFactory.java b/src/main/java/com/uid2/admin/store/factory/ClientSideKeypairStoreFactory.java index a305d966..e3998741 100644 --- a/src/main/java/com/uid2/admin/store/factory/ClientSideKeypairStoreFactory.java +++ b/src/main/java/com/uid2/admin/store/factory/ClientSideKeypairStoreFactory.java @@ -54,12 +54,13 @@ public StoreWriter> getEncryptedWriter(Integer sit fileManager, versionGenerator, clock, - new EncryptedScope(rootMetadataPath, siteId, isPublic)); + new EncryptedScope(rootMetadataPath, siteId, isPublic), + cloudEncryptionKeyProvider); } @Override public StoreReader> getEncryptedReader(Integer siteId, boolean isPublic) { - return new RotatingClientSideKeypairStore(fileStreamProvider, new EncryptedScope(rootMetadataPath, siteId, isPublic)); + return new RotatingClientSideKeypairStore(fileStreamProvider, new EncryptedScope(rootMetadataPath, siteId, isPublic), cloudEncryptionKeyProvider); } @Override diff --git a/src/main/java/com/uid2/admin/store/writer/ClientSideKeypairStoreWriter.java b/src/main/java/com/uid2/admin/store/writer/ClientSideKeypairStoreWriter.java index 24a96d06..78c0a959 100644 --- a/src/main/java/com/uid2/admin/store/writer/ClientSideKeypairStoreWriter.java +++ b/src/main/java/com/uid2/admin/store/writer/ClientSideKeypairStoreWriter.java @@ -6,6 +6,7 @@ import com.uid2.admin.store.version.VersionGenerator; import com.uid2.shared.model.ClientSideKeypair; import com.uid2.shared.store.reader.RotatingClientSideKeypairStore; +import com.uid2.shared.store.reader.RotatingCloudEncryptionKeyProvider; import com.uid2.shared.store.reader.StoreReader; import com.uid2.shared.store.scope.StoreScope; import io.vertx.core.json.JsonArray; @@ -24,6 +25,13 @@ public ClientSideKeypairStoreWriter(StoreReader> s writer = new ScopedStoreWriter(store, fileManager, versionGenerator, clock, scope, dataFile, dataType); } + public ClientSideKeypairStoreWriter(StoreReader> store, FileManager fileManager, + VersionGenerator versionGenerator, Clock clock, StoreScope scope, RotatingCloudEncryptionKeyProvider cloudEncryptionKeyProvider) { + FileName dataFile = new FileName("client_side_keypairs", ".json"); + String dataType = "client_side_keypairs"; + writer = new EncryptedScopedStoreWriter(store, fileManager, versionGenerator, clock, scope, dataFile, dataType, cloudEncryptionKeyProvider, scope.getId()); + } + @Override public void upload(Collection data, JsonObject extraMeta) throws Exception { JsonArray jsonKeypairs = new JsonArray(); From 6a78f9afa95134eb79e2be0e7ef49a0707122aa8 Mon Sep 17 00:00:00 2001 From: Release Workflow Date: Wed, 11 Dec 2024 23:10:48 +0000 Subject: [PATCH 11/19] [CI Pipeline] Released Snapshot version: 5.16.4-alpha-99-SNAPSHOT --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 3ab58dd3..84b4ce42 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.uid2 uid2-admin - 5.16.3-alpha-98-SNAPSHOT + 5.16.4-alpha-99-SNAPSHOT UTF-8 From 2073903a14984c76d5fc7e0fecbdc481ffe599bf Mon Sep 17 00:00:00 2001 From: Cody Constine Date: Thu, 12 Dec 2024 10:05:32 -0700 Subject: [PATCH 12/19] Removed logic to refresh the encrypted salts writers --- .../uid2/admin/store/writer/EncryptedSaltStoreWriter.java | 5 +++++ .../java/com/uid2/admin/store/writer/SaltStoreWriter.java | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/src/main/java/com/uid2/admin/store/writer/EncryptedSaltStoreWriter.java b/src/main/java/com/uid2/admin/store/writer/EncryptedSaltStoreWriter.java index ee79c526..861fc81d 100644 --- a/src/main/java/com/uid2/admin/store/writer/EncryptedSaltStoreWriter.java +++ b/src/main/java/com/uid2/admin/store/writer/EncryptedSaltStoreWriter.java @@ -80,6 +80,11 @@ protected void uploadSaltsSnapshot(RotatingSaltProvider.SaltSnapshot snapshot, S this.upload(newSaltsFile.toString(), location); } + @Override + protected void refreshProvider() { + // we do not need to refresh the provider on encrypted writers + } + @Override public void upload(Object data, JsonObject extraMeta) throws Exception { for(RotatingSaltProvider.SaltSnapshot saltSnapshot: (Collection) data) { diff --git a/src/main/java/com/uid2/admin/store/writer/SaltStoreWriter.java b/src/main/java/com/uid2/admin/store/writer/SaltStoreWriter.java index f5e953d4..de383af5 100644 --- a/src/main/java/com/uid2/admin/store/writer/SaltStoreWriter.java +++ b/src/main/java/com/uid2/admin/store/writer/SaltStoreWriter.java @@ -106,6 +106,10 @@ public void upload(RotatingSaltProvider.SaltSnapshot data) throws Exception { fileManager.uploadMetadata(metadata, "salts", new CloudPath(provider.getMetadataPath())); // refresh manually + refreshProvider(); + } + + protected void refreshProvider() throws Exception { provider.loadContent(); } From fd653d99cdc954d08d1457acda217714cb7b9020 Mon Sep 17 00:00:00 2001 From: Release Workflow Date: Thu, 12 Dec 2024 17:07:42 +0000 Subject: [PATCH 13/19] [CI Pipeline] Released Snapshot version: 5.16.5-alpha-100-SNAPSHOT --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 84b4ce42..d650e7a6 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.uid2 uid2-admin - 5.16.4-alpha-99-SNAPSHOT + 5.16.5-alpha-100-SNAPSHOT UTF-8 From 345a708128c0b2937bc325b83082df5cd33fbb62 Mon Sep 17 00:00:00 2001 From: Cody Constine Date: Fri, 13 Dec 2024 11:50:52 -0700 Subject: [PATCH 14/19] Salts fixes to optimize --- pom.xml | 2 +- .../com/uid2/admin/store/factory/SaltStoreFactory.java | 3 +-- .../admin/store/writer/EncryptedSaltStoreWriter.java | 10 ++++++++-- .../com/uid2/admin/store/writer/SaltStoreWriter.java | 4 ++-- 4 files changed, 12 insertions(+), 7 deletions(-) diff --git a/pom.xml b/pom.xml index d650e7a6..9890fa33 100644 --- a/pom.xml +++ b/pom.xml @@ -16,7 +16,7 @@ 1.12.2 5.11.2 - 8.0.13-alpha-175-SNAPSHOT + 8.0.14-alpha-176-SNAPSHOT 0.5.10 ${project.version} diff --git a/src/main/java/com/uid2/admin/store/factory/SaltStoreFactory.java b/src/main/java/com/uid2/admin/store/factory/SaltStoreFactory.java index a7369a12..8261e942 100644 --- a/src/main/java/com/uid2/admin/store/factory/SaltStoreFactory.java +++ b/src/main/java/com/uid2/admin/store/factory/SaltStoreFactory.java @@ -42,8 +42,7 @@ public SaltStoreFactory(JsonObject config, CloudPath rootMetadataPath, FileManag @Override public StoreWriter> getEncryptedWriter(Integer siteId, boolean isPublic) { EncryptedScope scope = new EncryptedScope(rootMetadatapath, siteId, isPublic); - EncryptedRotatingSaltProvider saltProvider = new EncryptedRotatingSaltProvider(taggableCloudStorage, - scope.resolve(new CloudPath(config.getString(Const.Config.SaltsMetadataPathProp))).toString(), cloudEncryptionKeyProvider ); + EncryptedRotatingSaltProvider saltProvider = new EncryptedRotatingSaltProvider(taggableCloudStorage, cloudEncryptionKeyProvider, scope); return new EncryptedSaltStoreWriter(config, saltProvider, fileManager, taggableCloudStorage, versionGenerator, scope, cloudEncryptionKeyProvider, siteId); } diff --git a/src/main/java/com/uid2/admin/store/writer/EncryptedSaltStoreWriter.java b/src/main/java/com/uid2/admin/store/writer/EncryptedSaltStoreWriter.java index 861fc81d..775b29b8 100644 --- a/src/main/java/com/uid2/admin/store/writer/EncryptedSaltStoreWriter.java +++ b/src/main/java/com/uid2/admin/store/writer/EncryptedSaltStoreWriter.java @@ -38,7 +38,7 @@ public EncryptedSaltStoreWriter(JsonObject config, RotatingSaltProvider provider @Override protected java.lang.String getSaltSnapshotLocation(RotatingSaltProvider.SaltSnapshot snapshot) { - return scope.resolve(new CloudPath(saltSnapshotLocationPrefix + snapshot.getEffective().toEpochMilli())).toString(); + return scope.resolve(new CloudPath("salts.txt." + snapshot.getEffective().toEpochMilli())).toString(); } @Override @@ -47,6 +47,12 @@ protected void uploadSaltsSnapshot(RotatingSaltProvider.SaltSnapshot snapshot, S throw new IllegalStateException("Site ID is not set."); } + if (!cloudStorage.list(location).isEmpty()) { + // update the tags on the file to ensure it is still marked as current + this.setStatusTagToCurrent(location); + return; + } + StringBuilder stringBuilder = new StringBuilder(); for (SaltEntry entry: snapshot.getAllRotatingSalts()) { @@ -79,7 +85,7 @@ protected void uploadSaltsSnapshot(RotatingSaltProvider.SaltSnapshot snapshot, S this.upload(newSaltsFile.toString(), location); } - + @Override protected void refreshProvider() { // we do not need to refresh the provider on encrypted writers diff --git a/src/main/java/com/uid2/admin/store/writer/SaltStoreWriter.java b/src/main/java/com/uid2/admin/store/writer/SaltStoreWriter.java index de383af5..f8bfc2a5 100644 --- a/src/main/java/com/uid2/admin/store/writer/SaltStoreWriter.java +++ b/src/main/java/com/uid2/admin/store/writer/SaltStoreWriter.java @@ -30,7 +30,7 @@ public class SaltStoreWriter { protected final String saltSnapshotLocationPrefix; private final VersionGenerator versionGenerator; - private final TaggableCloudStorage cloudStorage; + protected final TaggableCloudStorage cloudStorage; private final Map currentTags = Map.of("status", "current"); private final Map obsoleteTags = Map.of("status", "obsolete"); @@ -159,7 +159,7 @@ protected void upload(String data, String location) throws Exception { } - private void setStatusTagToCurrent(String location) throws CloudStorageException { + protected void setStatusTagToCurrent(String location) throws CloudStorageException { this.cloudStorage.setTags(location, this.currentTags); } From d8236a610e5f8e0d3aecb4ead1d7cc41af65a8c3 Mon Sep 17 00:00:00 2001 From: Release Workflow Date: Fri, 13 Dec 2024 19:05:39 +0000 Subject: [PATCH 15/19] [CI Pipeline] Released Snapshot version: 5.16.6-alpha-101-SNAPSHOT --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 9890fa33..9215e131 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.uid2 uid2-admin - 5.16.5-alpha-100-SNAPSHOT + 5.16.6-alpha-101-SNAPSHOT UTF-8 From 197ac7da3df7f99cc183de7a93cf55b535b05502 Mon Sep 17 00:00:00 2001 From: Cody Constine Date: Fri, 13 Dec 2024 13:44:54 -0700 Subject: [PATCH 16/19] Upping the max heap size to match out memory --- Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/Dockerfile b/Dockerfile index d30085c1..aec568a9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -26,4 +26,5 @@ CMD java \ -Djava.security.egd=file:/dev/./urandom \ -Dvertx.logger-delegate-factory-class-name=io.vertx.core.logging.SLF4JLogDelegateFactory \ -Dlogback.configurationFile=${LOGBACK_CONF} \ + -Xmx4g \ -jar ${JAR_NAME}-${JAR_VERSION}.jar From 031bd22528efbf4d7bac57b51dffa2025241b5bc Mon Sep 17 00:00:00 2001 From: Release Workflow Date: Fri, 13 Dec 2024 20:47:18 +0000 Subject: [PATCH 17/19] [CI Pipeline] Released Snapshot version: 5.16.7-alpha-102-SNAPSHOT --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 9215e131..1ed66f20 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.uid2 uid2-admin - 5.16.6-alpha-101-SNAPSHOT + 5.16.7-alpha-102-SNAPSHOT UTF-8 From 8bdb95f43c7fb5bed8063f14c0c0373feca2ca0f Mon Sep 17 00:00:00 2001 From: Release Workflow Date: Fri, 13 Dec 2024 20:50:22 +0000 Subject: [PATCH 18/19] [CI Pipeline] Released Snapshot version: 5.16.8-alpha-103-SNAPSHOT --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 1ed66f20..16566826 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.uid2 uid2-admin - 5.16.7-alpha-102-SNAPSHOT + 5.16.8-alpha-103-SNAPSHOT UTF-8 From 6c1bbbe625ed7b4d5e99550aeea5644eed8bc5c3 Mon Sep 17 00:00:00 2001 From: Cody Constine Date: Tue, 17 Dec 2024 11:30:25 -0700 Subject: [PATCH 19/19] Adding new shared version --- pom.xml | 2 +- .../com/uid2/admin/store/writer/EncryptedScopedStoreWriter.java | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 16566826..85f51a9a 100644 --- a/pom.xml +++ b/pom.xml @@ -16,7 +16,7 @@ 1.12.2 5.11.2 - 8.0.14-alpha-176-SNAPSHOT + 8.0.25 0.5.10 ${project.version} diff --git a/src/main/java/com/uid2/admin/store/writer/EncryptedScopedStoreWriter.java b/src/main/java/com/uid2/admin/store/writer/EncryptedScopedStoreWriter.java index c2718c1e..57f82aec 100644 --- a/src/main/java/com/uid2/admin/store/writer/EncryptedScopedStoreWriter.java +++ b/src/main/java/com/uid2/admin/store/writer/EncryptedScopedStoreWriter.java @@ -31,6 +31,7 @@ public EncryptedScopedStoreWriter(IMetadataVersionedStore provider, this.siteId = siteId; } + @Override public void upload(String data, JsonObject extraMeta) throws Exception { if (siteId == null) { throw new IllegalStateException("Site ID is not set.");