Skip to content

Commit 4e45a60

Browse files
Merge pull request #200 from IABTechLab/bmz-UID2-4612-operator-config-endpoint
bmz-UID2-4612 add endpoint to serve operator config
2 parents fd57e38 + bb29d9c commit 4e45a60

12 files changed

+125
-13
lines changed

conf/operator-config.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"identity_token_expires_after_seconds": 3600,
3+
"refresh_token_expires_after_seconds": 86400,
4+
"refresh_identity_token_after_seconds": 900,
5+
"sharing_token_expiry_seconds": 2592000
6+
}

src/main/java/com/uid2/core/Const.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,6 @@ public class Config extends com.uid2.shared.Const.Config {
1717
public static final String KmsSecretAccessKeyProp = "kms_aws_secret_access_key";
1818
public static final String KmsEndpointProp = "kms_aws_endpoint";
1919
}
20+
21+
public static final String OPERATOR_CONFIG_PATH = "conf/operator-config.json";
2022
}

src/main/java/com/uid2/core/Main.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import io.vertx.core.DeploymentOptions;
3737
import io.vertx.core.Vertx;
3838
import io.vertx.core.VertxOptions;
39+
import io.vertx.core.file.FileSystem;
3940
import io.vertx.core.http.HttpServerOptions;
4041
import io.vertx.core.http.impl.HttpUtils;
4142
import io.vertx.core.json.JsonObject;
@@ -161,7 +162,8 @@ public static void main(String[] args) {
161162
);
162163

163164
JwtService jwtService = new JwtService(config);
164-
coreVerticle = new CoreVerticle(cloudStorage, operatorKeyProvider, attestationService, attestationTokenService, enclaveIdProvider, operatorJWTTokenProvider, jwtService, cloudEncryptionKeyProvider);
165+
FileSystem fileSystem = vertx.fileSystem();
166+
coreVerticle = new CoreVerticle(cloudStorage, operatorKeyProvider, attestationService, attestationTokenService, enclaveIdProvider, operatorJWTTokenProvider, jwtService, cloudEncryptionKeyProvider, fileSystem);
165167
} catch (Exception e) {
166168
System.out.println("failed to initialize core verticle: " + e.getMessage());
167169
System.exit(-1);

src/main/java/com/uid2/core/vertx/CoreVerticle.java

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import com.uid2.shared.vertx.VertxUtils;
2424
import io.vertx.core.AbstractVerticle;
2525
import io.vertx.core.Promise;
26+
import io.vertx.core.file.FileSystem;
2627
import io.vertx.core.http.HttpHeaders;
2728
import io.vertx.core.http.HttpMethod;
2829
import io.vertx.core.http.HttpServerResponse;
@@ -81,14 +82,17 @@ public class CoreVerticle extends AbstractVerticle {
8182
private final OperatorJWTTokenProvider operatorJWTTokenProvider;
8283
private final RotatingCloudEncryptionKeyProvider cloudEncryptionKeyProvider;
8384

85+
private final FileSystem fileSystem;
86+
8487
public CoreVerticle(ICloudStorage cloudStorage,
8588
IAuthorizableProvider authProvider,
8689
AttestationService attestationService,
8790
IAttestationTokenService attestationTokenService,
8891
IEnclaveIdentifierProvider enclaveIdentifierProvider,
8992
OperatorJWTTokenProvider operatorJWTTokenProvider,
9093
JwtService jwtService,
91-
RotatingCloudEncryptionKeyProvider cloudEncryptionKeyProvider) throws Exception {
94+
RotatingCloudEncryptionKeyProvider cloudEncryptionKeyProvider,
95+
FileSystem fileSystem) throws Exception {
9296
this.operatorJWTTokenProvider = operatorJWTTokenProvider;
9397
this.healthComponent.setHealthStatus(false, "not started");
9498

@@ -100,6 +104,8 @@ public CoreVerticle(ICloudStorage cloudStorage,
100104
this.enclaveIdentifierProvider.addListener(this.attestationService);
101105
this.cloudEncryptionKeyProvider = cloudEncryptionKeyProvider;
102106

107+
this.fileSystem = fileSystem;
108+
103109
final String jwtAudience = ConfigStore.Global.get(Const.Config.CorePublicUrlProp);
104110
final String jwtIssuer = ConfigStore.Global.get(Const.Config.CorePublicUrlProp);
105111
Boolean enforceJwt = ConfigStore.Global.getBoolean(Const.Config.EnforceJwtProp);
@@ -131,8 +137,9 @@ public CoreVerticle(ICloudStorage cloudStorage,
131137
IAttestationTokenService attestationTokenService,
132138
IEnclaveIdentifierProvider enclaveIdentifierProvider,
133139
OperatorJWTTokenProvider jwtTokenProvider,
134-
JwtService jwtService) throws Exception {
135-
this(cloudStorage, authorizableProvider, attestationService, attestationTokenService, enclaveIdentifierProvider, jwtTokenProvider, jwtService, null);
140+
JwtService jwtService,
141+
FileSystem fileSystem) throws Exception {
142+
this(cloudStorage, authorizableProvider, attestationService, attestationTokenService, enclaveIdentifierProvider, jwtTokenProvider, jwtService, null, fileSystem);
136143
}
137144

138145
@Override
@@ -192,6 +199,7 @@ private Router createRoutesSetup() {
192199
router.get(Endpoints.OPERATORS_REFRESH.toString()).handler(auth.handle(attestationMiddleware.handle(this::handleOperatorRefresh), Role.OPTOUT_SERVICE));
193200
router.get(Endpoints.PARTNERS_REFRESH.toString()).handler(auth.handle(attestationMiddleware.handle(this::handlePartnerRefresh), Role.OPTOUT_SERVICE));
194201
router.get(Endpoints.OPS_HEALTHCHECK.toString()).handler(this::handleHealthCheck);
202+
router.get(Endpoints.OPERATOR_CONFIG.toString()).handler(auth.handle(this::handleGetConfig, Role.OPERATOR));
195203

196204
if (Optional.ofNullable(ConfigStore.Global.getBoolean("enable_test_endpoints")).orElse(false)) {
197205
router.route(Endpoints.ATTEST_GET_TOKEN.toString()).handler(auth.handle(this::handleTestGetAttestationToken, Role.OPERATOR));
@@ -200,6 +208,30 @@ private Router createRoutesSetup() {
200208
return router;
201209
}
202210

211+
private void handleGetConfig(RoutingContext rc) {
212+
fileSystem.readFile(com.uid2.core.Const.OPERATOR_CONFIG_PATH, ar -> {
213+
if (ar.succeeded()) {
214+
try {
215+
String fileContent = ar.result().toString();
216+
JsonObject configJson = new JsonObject(fileContent);
217+
rc.response()
218+
.putHeader(HttpHeaders.CONTENT_TYPE, "application/json")
219+
.end(configJson.encodePrettily());
220+
} catch (Exception e) {
221+
rc.response()
222+
.setStatusCode(500)
223+
.end("Failed to parse configuration: " + e.getMessage());
224+
throw new RuntimeException(e);
225+
}
226+
} else {
227+
rc.response()
228+
.setStatusCode(500)
229+
.end("Failed to retrieve configuration: " + ar.cause().getMessage());
230+
}
231+
});
232+
}
233+
234+
203235
private void handleHealthCheck(RoutingContext rc) {
204236
if (HealthManager.instance.isHealthy()) {
205237
rc.response().end("OK");

src/main/java/com/uid2/core/vertx/Endpoints.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ public enum Endpoints {
2020
SERVICES_REFRESH("/services/refresh"),
2121
SERVICE_LINKS_REFRESH("/service_links/refresh"),
2222
OPERATORS_REFRESH("/operators/refresh"),
23-
PARTNERS_REFRESH("/partners/refresh");
23+
PARTNERS_REFRESH("/partners/refresh"),
24+
OPERATOR_CONFIG("/operator/config");
2425

2526
private final String path;
2627

src/test/java/com/uid2/core/vertx/TestClientSideKeypairMetadataPath.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import io.vertx.core.Handler;
1818
import io.vertx.core.Vertx;
1919
import io.vertx.core.buffer.Buffer;
20+
import io.vertx.core.file.FileSystem;
2021
import io.vertx.core.json.Json;
2122
import io.vertx.core.json.JsonObject;
2223
import io.vertx.ext.web.client.HttpResponse;
@@ -53,6 +54,7 @@ public class TestClientSideKeypairMetadataPath {
5354
private IEnclaveIdentifierProvider enclaveIdentifierProvider;
5455

5556
private AttestationService attestationService;
57+
private FileSystem fileSystem;
5658

5759
@Mock
5860
private OperatorJWTTokenProvider operatorJWTTokenProvider;
@@ -70,9 +72,10 @@ void deployVerticle(Vertx vertx, VertxTestContext testContext) throws Throwable
7072
ConfigStore.Global.load(config);
7173

7274
attestationService = new AttestationService();
75+
fileSystem = vertx.fileSystem();
7376
SecretStore.Global.load(((JsonObject) Json.decodeValue(openFile("/com.uid2.core/testGlobalMetadata/test-secrets.json"))));
7477
MockitoAnnotations.initMocks(this);
75-
CoreVerticle verticle = new CoreVerticle(cloudStorage, authProvider, attestationService, attestationTokenService, enclaveIdentifierProvider, operatorJWTTokenProvider, jwtService);
78+
CoreVerticle verticle = new CoreVerticle(cloudStorage, authProvider, attestationService, attestationTokenService, enclaveIdentifierProvider, operatorJWTTokenProvider, jwtService, fileSystem);
7679
vertx.deployVerticle(verticle, testContext.succeeding(id -> testContext.completeNow()));
7780
}
7881

src/test/java/com/uid2/core/vertx/TestCoreVerticle.java

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
import com.uid2.shared.store.reader.RotatingCloudEncryptionKeyProvider;
1818
import io.vertx.core.*;
1919
import io.vertx.core.buffer.Buffer;
20+
import io.vertx.core.file.FileSystem;
21+
import io.vertx.core.http.HttpHeaders;
2022
import io.vertx.core.json.JsonArray;
2123
import io.vertx.core.json.JsonObject;
2224
import io.vertx.ext.web.client.HttpResponse;
@@ -40,6 +42,8 @@
4042
import javax.crypto.Cipher;
4143
import java.io.ByteArrayInputStream;
4244
import java.net.URL;
45+
import java.nio.file.Files;
46+
import java.nio.file.Paths;
4347
import java.security.KeyPair;
4448
import java.security.KeyPairGenerator;
4549
import java.security.SecureRandom;
@@ -70,12 +74,14 @@ public class TestCoreVerticle {
7074
private JwtService jwtService;
7175
@Mock
7276
private RotatingCloudEncryptionKeyProvider cloudEncryptionKeyProvider;
77+
@Mock
78+
private FileSystem fileSystem;
7379

7480
private AttestationService attestationService;
81+
private String operatorConfig;
7582

7683
private static final String attestationProtocol = "test-attestation-protocol";
7784
private static final String attestationProtocolPublic = "trusted";
78-
7985
@BeforeEach
8086
void deployVerticle(TestInfo info, Vertx vertx, VertxTestContext testContext) throws Throwable {
8187
JsonObject config = new JsonObject();
@@ -116,7 +122,20 @@ void deployVerticle(TestInfo info, Vertx vertx, VertxTestContext testContext) th
116122
}
117123
});
118124

119-
CoreVerticle verticle = new CoreVerticle(cloudStorage, authProvider, attestationService, attestationTokenService, enclaveIdentifierProvider, operatorJWTTokenProvider, jwtService, cloudEncryptionKeyProvider);
125+
operatorConfig = Files.readString(Paths.get(com.uid2.core.Const.OPERATOR_CONFIG_PATH)).trim();
126+
127+
when(fileSystem.readFile(anyString(), any())).thenAnswer(invocation -> {
128+
String path = invocation.getArgument(0);
129+
Handler<AsyncResult<Buffer>> handler = invocation.getArgument(1);
130+
if (Objects.equals(path, com.uid2.core.Const.OPERATOR_CONFIG_PATH)) {
131+
handler.handle(Future.succeededFuture(Buffer.buffer(operatorConfig)));
132+
} else {
133+
handler.handle(Future.failedFuture(new RuntimeException("Failed to read file: " + path)));
134+
}
135+
return null;
136+
});
137+
138+
CoreVerticle verticle = new CoreVerticle(cloudStorage, authProvider, attestationService, attestationTokenService, enclaveIdentifierProvider, operatorJWTTokenProvider, jwtService, cloudEncryptionKeyProvider, fileSystem);
120139
vertx.deployVerticle(verticle, testContext.succeeding(id -> testContext.completeNow()));
121140

122141
}
@@ -874,4 +893,34 @@ void keysRefreshSuccessNoHeaderVersion(Vertx vertx, VertxTestContext testContext
874893
}
875894
});
876895
}
896+
897+
@Test
898+
void getConfigSuccess(Vertx vertx, VertxTestContext testContext) {
899+
JsonObject expectedConfig = new JsonObject(operatorConfig);
900+
901+
fakeAuth(Role.OPERATOR);
902+
903+
// Make HTTP Get request to operator config endpoint
904+
this.get(vertx, Endpoints.OPERATOR_CONFIG.toString(), testContext.succeeding(response -> testContext.verify(() -> {
905+
assertEquals(200, response.statusCode());
906+
assertEquals("application/json", response.getHeader(HttpHeaders.CONTENT_TYPE));
907+
JsonObject actualConfig = new JsonObject(response.bodyAsString());
908+
assertEquals(expectedConfig, actualConfig);
909+
testContext.completeNow();
910+
})
911+
));
912+
}
913+
914+
@Test
915+
void getConfigInvalidJson(Vertx vertx, VertxTestContext testContext) {
916+
operatorConfig = "invalid config";
917+
918+
fakeAuth(Role.OPERATOR);
919+
920+
this.get(vertx, Endpoints.OPERATOR_CONFIG.toString(), testContext.succeeding(response -> testContext.verify(() -> {
921+
assertEquals(500, response.statusCode());
922+
testContext.completeNow();
923+
})
924+
));
925+
}
877926
}

src/test/java/com/uid2/core/vertx/TestServiceLinkMetadataPath.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import io.vertx.core.Handler;
1818
import io.vertx.core.Vertx;
1919
import io.vertx.core.buffer.Buffer;
20+
import io.vertx.core.file.FileSystem;
2021
import io.vertx.core.json.Json;
2122
import io.vertx.core.json.JsonObject;
2223
import io.vertx.ext.web.client.HttpResponse;
@@ -52,6 +53,7 @@ public class TestServiceLinkMetadataPath {
5253
private IEnclaveIdentifierProvider enclaveIdentifierProvider;
5354

5455
private AttestationService attestationService;
56+
private FileSystem fileSystem;
5557

5658
@Mock
5759
private OperatorJWTTokenProvider operatorJWTTokenProvider;
@@ -69,9 +71,10 @@ void deployVerticle(Vertx vertx, VertxTestContext testContext) throws Throwable
6971
ConfigStore.Global.load(config);
7072

7173
attestationService = new AttestationService();
74+
fileSystem = vertx.fileSystem();
7275
SecretStore.Global.load(((JsonObject) Json.decodeValue(openFile("/com.uid2.core/testGlobalMetadata/test-secrets.json"))));
7376
MockitoAnnotations.initMocks(this);
74-
CoreVerticle verticle = new CoreVerticle(cloudStorage, authProvider, attestationService, attestationTokenService, enclaveIdentifierProvider, operatorJWTTokenProvider, jwtService);
77+
CoreVerticle verticle = new CoreVerticle(cloudStorage, authProvider, attestationService, attestationTokenService, enclaveIdentifierProvider, operatorJWTTokenProvider, jwtService, fileSystem);
7578
vertx.deployVerticle(verticle, testContext.succeeding(id -> testContext.completeNow()));
7679
}
7780

src/test/java/com/uid2/core/vertx/TestServiceMetadataPath.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import io.vertx.core.Handler;
1818
import io.vertx.core.Vertx;
1919
import io.vertx.core.buffer.Buffer;
20+
import io.vertx.core.file.FileSystem;
2021
import io.vertx.core.json.Json;
2122
import io.vertx.core.json.JsonObject;
2223
import io.vertx.ext.web.client.HttpResponse;
@@ -52,6 +53,7 @@ public class TestServiceMetadataPath {
5253
private IEnclaveIdentifierProvider enclaveIdentifierProvider;
5354

5455
private AttestationService attestationService;
56+
private FileSystem fileSystem;
5557

5658
@Mock
5759
private OperatorJWTTokenProvider operatorJWTTokenProvider;
@@ -69,9 +71,10 @@ void deployVerticle(Vertx vertx, VertxTestContext testContext) throws Throwable
6971
ConfigStore.Global.load(config);
7072

7173
attestationService = new AttestationService();
74+
fileSystem = vertx.fileSystem();
7275
SecretStore.Global.load(((JsonObject) Json.decodeValue(openFile("/com.uid2.core/testGlobalMetadata/test-secrets.json"))));
7376
MockitoAnnotations.initMocks(this);
74-
CoreVerticle verticle = new CoreVerticle(cloudStorage, authProvider, attestationService, attestationTokenService, enclaveIdentifierProvider, operatorJWTTokenProvider, jwtService);
77+
CoreVerticle verticle = new CoreVerticle(cloudStorage, authProvider, attestationService, attestationTokenService, enclaveIdentifierProvider, operatorJWTTokenProvider, jwtService, fileSystem);
7578
vertx.deployVerticle(verticle, testContext.succeeding(id -> testContext.completeNow()));
7679
}
7780

src/test/java/com/uid2/core/vertx/TestSiteSpecificMetadataPath.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import io.vertx.core.Handler;
1616
import io.vertx.core.Vertx;
1717
import io.vertx.core.buffer.Buffer;
18+
import io.vertx.core.file.FileSystem;
1819
import io.vertx.core.json.Json;
1920
import io.vertx.core.json.JsonObject;
2021
import io.vertx.ext.web.client.HttpResponse;
@@ -59,6 +60,7 @@ public class TestSiteSpecificMetadataPath {
5960
private JwtService jwtService;
6061

6162
private AttestationService attestationService;
63+
private FileSystem fileSystem;
6264

6365
// we need trusted to skip the attestation procedure or otherwise the core encpoint call made in this file will
6466
// fail at the attestation handler
@@ -67,10 +69,11 @@ public class TestSiteSpecificMetadataPath {
6769
@BeforeEach
6870
void deployVerticle(Vertx vertx, VertxTestContext testContext) throws Throwable {
6971
attestationService = new AttestationService();
72+
fileSystem = vertx.fileSystem();
7073
SecretStore.Global.load(((JsonObject) Json.decodeValue(openFile("/com.uid2.core/testSiteSpecificMetadata/test-secrets.json"))));
7174
ConfigStore.Global.load(((JsonObject) Json.decodeValue(openFile("/com.uid2.core/testSiteSpecificMetadata/test-configs-provide-private-site-data.json"))));
7275
MockitoAnnotations.initMocks(this);
73-
CoreVerticle verticle = new CoreVerticle(cloudStorage, authProvider, attestationService, attestationTokenService, enclaveIdentifierProvider, operatorJWTTokenProvider, jwtService);
76+
CoreVerticle verticle = new CoreVerticle(cloudStorage, authProvider, attestationService, attestationTokenService, enclaveIdentifierProvider, operatorJWTTokenProvider, jwtService, fileSystem);
7477
vertx.deployVerticle(verticle, testContext.succeeding(id -> testContext.completeNow()));
7578
}
7679

0 commit comments

Comments
 (0)