Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 10 additions & 10 deletions src/main/java/com/uid2/admin/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@
import io.vertx.core.Vertx;
import io.vertx.core.VertxOptions;
import io.vertx.core.http.HttpServerOptions;
import io.vertx.core.http.impl.HttpUtils;
import io.vertx.core.json.JsonObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -201,16 +200,16 @@ public void run() {

CloudPath cloudEncryptionKeyMetadataPath = new CloudPath(config.getString(Const.Config.CloudEncryptionKeysMetadataPathProp));
GlobalScope cloudEncryptionKeyGlobalScope = new GlobalScope(cloudEncryptionKeyMetadataPath);
RotatingCloudEncryptionKeyProvider RotatingCloudEncryptionKeyProvider = new RotatingCloudEncryptionKeyProvider(cloudStorage, cloudEncryptionKeyGlobalScope);
CloudEncryptionKeyStoreWriter cloudEncryptionKeyStoreWriter = new CloudEncryptionKeyStoreWriter(RotatingCloudEncryptionKeyProvider, fileManager, jsonWriter, versionGenerator, clock, cloudEncryptionKeyGlobalScope);
RotatingCloudEncryptionKeyProvider rotatingCloudEncryptionKeyProvider = new RotatingCloudEncryptionKeyProvider(cloudStorage, cloudEncryptionKeyGlobalScope);
CloudEncryptionKeyStoreWriter cloudEncryptionKeyStoreWriter = new CloudEncryptionKeyStoreWriter(rotatingCloudEncryptionKeyProvider, fileManager, jsonWriter, versionGenerator, clock, cloudEncryptionKeyGlobalScope);
IKeyGenerator keyGenerator = new SecureKeyGenerator();
CloudEncryptionKeyManager cloudEncryptionKeyManager = new CloudEncryptionKeyManager(RotatingCloudEncryptionKeyProvider, cloudEncryptionKeyStoreWriter,keyGenerator);
CloudEncryptionKeyManager cloudEncryptionKeyManager = new CloudEncryptionKeyManager(rotatingCloudEncryptionKeyProvider, cloudEncryptionKeyStoreWriter,keyGenerator);
try {
RotatingCloudEncryptionKeyProvider.loadContent();
rotatingCloudEncryptionKeyProvider.loadContent();
} catch (CloudStorageException e) {
if (e.getMessage().contains("The specified key does not exist")) {
cloudEncryptionKeyStoreWriter.upload(new HashMap<>(), null);
RotatingCloudEncryptionKeyProvider.loadContent();
rotatingCloudEncryptionKeyProvider.loadContent();
} else {
throw e;
}
Expand Down Expand Up @@ -261,9 +260,10 @@ public void run() {
new SaltService(auth, writeLock, saltStoreWriter, saltProvider, saltRotation),
new SiteService(auth, writeLock, siteStoreWriter, siteProvider, clientKeyProvider),
new PartnerConfigService(auth, writeLock, partnerStoreWriter, partnerConfigProvider),
new PrivateSiteDataRefreshService(auth, jobDispatcher, writeLock, config, RotatingCloudEncryptionKeyProvider),
new PrivateSiteDataRefreshService(auth, jobDispatcher, writeLock, config, rotatingCloudEncryptionKeyProvider),
new JobDispatcherService(auth, jobDispatcher),
new SearchService(auth, clientKeyProvider, operatorKeyProvider)
new SearchService(auth, clientKeyProvider, operatorKeyProvider),
new CloudEncryptionKeyService(auth, rotatingCloudEncryptionKeyProvider)
};


Expand Down Expand Up @@ -293,7 +293,7 @@ public void run() {
config.getLong("cloud_encryption_key_activates_in_seconds"),
config.getInteger("cloud_encryption_key_count_per_site")
);
RotatingCloudEncryptionKeyProvider.loadContent();
rotatingCloudEncryptionKeyProvider.loadContent();
}

/*
Expand Down Expand Up @@ -342,7 +342,7 @@ public void run() {
CompletableFuture<Boolean> privateSiteDataSyncJobFuture = jobDispatcher.executeNextJob();
privateSiteDataSyncJobFuture.get();

EncryptedFilesSyncJob encryptedFilesSyncJob = new EncryptedFilesSyncJob(config, writeLock,RotatingCloudEncryptionKeyProvider);
EncryptedFilesSyncJob encryptedFilesSyncJob = new EncryptedFilesSyncJob(config, writeLock,rotatingCloudEncryptionKeyProvider);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Space before rotatingCloudEncryptionKeyProvider

jobDispatcher.enqueue(encryptedFilesSyncJob);
CompletableFuture<Boolean> encryptedFilesSyncJobFuture = jobDispatcher.executeNextJob();
encryptedFilesSyncJobFuture.get();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.uid2.admin.model;

import com.fasterxml.jackson.annotation.JsonProperty;

import java.util.List;

public record CloudEncryptionKeyListResponse(
@JsonProperty List<CloudEncryptionKeySummary> cloudEncryptionKeys
) {}

15 changes: 15 additions & 0 deletions src/main/java/com/uid2/admin/model/CloudEncryptionKeySummary.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.uid2.admin.model;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.uid2.shared.model.CloudEncryptionKey;

public record CloudEncryptionKeySummary(
@JsonProperty int id,
@JsonProperty int siteId,
@JsonProperty long activates,
@JsonProperty long created
) {
public static CloudEncryptionKeySummary fromFullKey(CloudEncryptionKey key) {
return new CloudEncryptionKeySummary(key.getId(), key.getSiteId(), key.getActivates(), key.getCreated());
}
}
2 changes: 2 additions & 0 deletions src/main/java/com/uid2/admin/vertx/Endpoints.java
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@ public enum Endpoints {
API_SITE_APP_NAMES("/api/site/app_names"),
API_SITE_UPDATE("/api/site/update"),

CLOUD_ENCRYPTION_KEY_LIST("/api/cloud-encryption-key/list"),

LOGIN("/login"),
LOGOUT("/logout"),
OPS_HEALTHCHECK("/ops/healthcheck"),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package com.uid2.admin.vertx.service;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.uid2.admin.auth.AdminAuthMiddleware;
import com.uid2.admin.model.CloudEncryptionKeyListResponse;
import com.uid2.admin.model.CloudEncryptionKeySummary;
import com.uid2.admin.vertx.Endpoints;
import com.uid2.shared.auth.Role;
import com.uid2.shared.store.reader.RotatingCloudEncryptionKeyProvider;
import com.uid2.shared.util.Mapper;
import io.vertx.core.http.HttpHeaders;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.RoutingContext;

import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class CloudEncryptionKeyService implements IService {
private final AdminAuthMiddleware auth;
private final RotatingCloudEncryptionKeyProvider keyProvider;
private static final ObjectMapper OBJECT_MAPPER = Mapper.getInstance();

public CloudEncryptionKeyService(AdminAuthMiddleware auth, RotatingCloudEncryptionKeyProvider keyProvider) {
this.auth = auth;
this.keyProvider = keyProvider;
}

@Override
public void setupRoutes(Router router) {
router.get(Endpoints.CLOUD_ENCRYPTION_KEY_LIST.toString()).handler(
auth.handle(this::handleList, Role.MAINTAINER)
);
}

private void handleList(RoutingContext rc) {
try {
var keySummaries = keyProvider.getAll()
.values()
.stream()
.map(CloudEncryptionKeySummary::fromFullKey)
.toList();
CloudEncryptionKeyListResponse response = new CloudEncryptionKeyListResponse(keySummaries);
respondWithJson(rc, response);
} catch (Exception e) {
rc.fail(500, e);
}
}

private static void respondWithJson(RoutingContext rc, CloudEncryptionKeyListResponse response) throws JsonProcessingException {
rc.response()
.putHeader(HttpHeaders.CONTENT_TYPE, "application/json")
.end(OBJECT_MAPPER.writeValueAsString(response));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package com.uid2.admin.vertx;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.uid2.admin.model.CloudEncryptionKeyListResponse;
import com.uid2.admin.model.CloudEncryptionKeySummary;
import com.uid2.admin.vertx.service.CloudEncryptionKeyService;
import com.uid2.admin.vertx.service.IService;
import com.uid2.admin.vertx.test.ServiceTestBase;
import com.uid2.shared.auth.Role;
import com.uid2.shared.model.CloudEncryptionKey;
import com.uid2.shared.util.Mapper;
import io.vertx.core.Vertx;
import io.vertx.junit5.VertxTestContext;
import org.junit.jupiter.api.Test;

import java.util.List;

import static org.junit.jupiter.api.Assertions.*;

public class CloudEncryptionKeyServiceTest extends ServiceTestBase {
private static final ObjectMapper OBJECT_MAPPER = Mapper.getInstance();

@Override
protected IService createService() {
return new CloudEncryptionKeyService(auth, cloudEncryptionKeyProvider);
}

@Test
public void testList_noKeys(Vertx vertx, VertxTestContext testContext) {
fakeAuth(Role.MAINTAINER);
var expected = new CloudEncryptionKeyListResponse(List.of());

get(vertx, testContext, Endpoints.CLOUD_ENCRYPTION_KEY_LIST, response -> {
assertEquals(200, response.statusCode());

CloudEncryptionKeyListResponse actual = OBJECT_MAPPER.readValue(response.bodyAsString(), new TypeReference<>() {});
assertEquals(expected, actual);

testContext.completeNow();
});
}

@Test
public void testList_noAccess(Vertx vertx, VertxTestContext testContext) {
get(vertx, testContext, Endpoints.CLOUD_ENCRYPTION_KEY_LIST, response -> {
assertEquals(401, response.statusCode());
testContext.completeNow();
});
}

@Test
public void testList_withKeys(Vertx vertx, VertxTestContext testContext) {
fakeAuth(Role.MAINTAINER);

CloudEncryptionKey key1 = new CloudEncryptionKey(1, 2, 100, 100, "secret 1");
CloudEncryptionKey key2 = new CloudEncryptionKey(2, 2, 200, 100, "secret 2");

setCloudEncryptionKeys(key1, key2);

var expected = new CloudEncryptionKeyListResponse(List.of(
new CloudEncryptionKeySummary(1, 2, 100, 100),
new CloudEncryptionKeySummary(2, 2, 200, 100)
));

get(vertx, testContext, Endpoints.CLOUD_ENCRYPTION_KEY_LIST, response -> {
assertEquals(200, response.statusCode());

CloudEncryptionKeyListResponse actual = OBJECT_MAPPER.readValue(response.bodyAsString(), new TypeReference<>() {});
assertEquals(expected, actual);

testContext.completeNow();
});
}
}
Loading