aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilder.java15
-rw-r--r--jdisc-security-filters/src/main/java/com/yahoo/jdisc/http/filter/security/cloud/CloudTokenDataPlaneHandler.java31
-rw-r--r--jdisc-security-filters/src/test/java/com/yahoo/jdisc/http/filter/security/cloud/CloudTokenDataPlaneHandlerTest.java52
3 files changed, 97 insertions, 1 deletions
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilder.java b/config-model/src/main/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilder.java
index 643c2943e38..f8dfe5c82a1 100644
--- a/config-model/src/main/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilder.java
+++ b/config-model/src/main/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilder.java
@@ -39,6 +39,8 @@ import com.yahoo.container.jdisc.DataplaneProxyService;
import com.yahoo.container.logging.AccessLog;
import com.yahoo.container.logging.FileConnectionLog;
import com.yahoo.io.IOUtils;
+import com.yahoo.jdisc.http.filter.security.cloud.config.CloudTokenDataPlaneFilterConfig;
+import com.yahoo.jdisc.http.filter.security.cloud.config.CloudTokenDataPlaneFilterConfig.Builder;
import com.yahoo.jdisc.http.server.jetty.DataplaneProxyCredentials;
import com.yahoo.jdisc.http.server.jetty.VoidRequestLog;
import com.yahoo.osgi.provider.model.ComponentModel;
@@ -658,13 +660,24 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> {
// Setup token filter chain
var tokenChain = new HttpFilterChain("cloud-token-data-plane-secure", HttpFilterChain.Type.SYSTEM);
- tokenChain.addInnerComponent(new CloudTokenDataPlaneFilter(cluster, state));
+ var tokenFilter = new CloudTokenDataPlaneFilter(cluster, state);
+ tokenChain.addInnerComponent(tokenFilter);
cluster.getHttp().getFilterChains().add(tokenChain);
// Set as default filter for token port
cluster.getHttp().getHttpServer().orElseThrow().getConnectorFactories().stream()
.filter(c -> c.getListenPort() == tokenPort).findAny().orElseThrow()
.setDefaultRequestFilterChain(tokenChain.getComponentId());
+
+ // Set up handler that tells what fingerprints are known to the container
+ class CloudTokenDataPlaneHandler extends Handler implements CloudTokenDataPlaneFilterConfig.Producer {
+ CloudTokenDataPlaneHandler() {
+ super(new ComponentModel("com.yahoo.jdisc.http.filter.security.cloud.CloudTokenDataPlaneHandler", null, "jdisc-security-filters", null));
+ addServerBindings(SystemBindingPattern.fromHttpPortAndPath(Defaults.getDefaults().vespaWebServicePort(), "cloud-token-data-plane-fingerprints"));
+ }
+ @Override public void getConfig(Builder builder) { tokenFilter.getConfig(builder); }
+ }
+ cluster.addComponent(new CloudTokenDataPlaneHandler());
}
// Returns the client certificates of the clients defined for an application cluster
diff --git a/jdisc-security-filters/src/main/java/com/yahoo/jdisc/http/filter/security/cloud/CloudTokenDataPlaneHandler.java b/jdisc-security-filters/src/main/java/com/yahoo/jdisc/http/filter/security/cloud/CloudTokenDataPlaneHandler.java
new file mode 100644
index 00000000000..2270f514fb7
--- /dev/null
+++ b/jdisc-security-filters/src/main/java/com/yahoo/jdisc/http/filter/security/cloud/CloudTokenDataPlaneHandler.java
@@ -0,0 +1,31 @@
+package com.yahoo.jdisc.http.filter.security.cloud;
+
+import com.yahoo.container.jdisc.HttpRequest;
+import com.yahoo.container.jdisc.HttpResponse;
+import com.yahoo.container.jdisc.ThreadedHttpRequestHandler;
+import com.yahoo.jdisc.http.filter.security.cloud.config.CloudTokenDataPlaneFilterConfig;
+import com.yahoo.restapi.SlimeJsonResponse;
+
+import javax.inject.Inject;
+import java.util.List;
+import java.util.concurrent.Executor;
+
+public class CloudTokenDataPlaneHandler extends ThreadedHttpRequestHandler {
+
+ private final List<String> fingerprints;
+
+ @Inject
+ public CloudTokenDataPlaneHandler(CloudTokenDataPlaneFilterConfig config, Executor executor) {
+ super(executor);
+ fingerprints = config.clients().stream()
+ .flatMap(client -> client.tokens().stream())
+ .flatMap(token -> token.fingerprints().stream())
+ .distinct().sorted().toList();
+ }
+
+ @Override
+ public HttpResponse handle(HttpRequest request) {
+ return new SlimeJsonResponse() {{ fingerprints.forEach(slime.setObject().setArray("fingerprints")::addString); }};
+ }
+
+}
diff --git a/jdisc-security-filters/src/test/java/com/yahoo/jdisc/http/filter/security/cloud/CloudTokenDataPlaneHandlerTest.java b/jdisc-security-filters/src/test/java/com/yahoo/jdisc/http/filter/security/cloud/CloudTokenDataPlaneHandlerTest.java
new file mode 100644
index 00000000000..b84d35841da
--- /dev/null
+++ b/jdisc-security-filters/src/test/java/com/yahoo/jdisc/http/filter/security/cloud/CloudTokenDataPlaneHandlerTest.java
@@ -0,0 +1,52 @@
+package com.yahoo.jdisc.http.filter.security.cloud;
+
+import com.yahoo.container.jdisc.HttpResponse;
+import com.yahoo.jdisc.http.filter.security.cloud.config.CloudTokenDataPlaneFilterConfig.Builder;
+import com.yahoo.jdisc.http.filter.security.cloud.config.CloudTokenDataPlaneFilterConfig.Clients;
+import com.yahoo.jdisc.http.filter.security.cloud.config.CloudTokenDataPlaneFilterConfig.Clients.Tokens;
+import org.junit.jupiter.api.Test;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.List;
+
+import static com.yahoo.container.jdisc.HttpRequest.createTestRequest;
+import static com.yahoo.jdisc.http.HttpRequest.Method.GET;
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class CloudTokenDataPlaneHandlerTest {
+
+ @Test
+ void testFingerprints() throws IOException {
+ CloudTokenDataPlaneHandler handler = new CloudTokenDataPlaneHandler(
+ new Builder().tokenContext("context")
+ .clients(new Clients.Builder().id("client1")
+ .permissions("read")
+ .tokens(new Tokens.Builder().id("id1")
+ .fingerprints(List.of("pinky", "ring", "middle", "index", "thumb"))
+ .checkAccessHashes(List.of("a", "b", "c", "d", "e"))
+ .expirations(List.of("<none>", "<none>", "<none>", "<none>", "<none>")))
+ .tokens(new Tokens.Builder().id("id2")
+ .fingerprints("toasty")
+ .checkAccessHashes("hash")
+ .expirations("<none>")))
+ .clients(new Clients.Builder().id("client2")
+ .permissions("write")
+ .tokens(new Tokens.Builder().id("id2")
+ .fingerprints("toasty")
+ .checkAccessHashes("hash")
+ .expirations("<none>")))
+ .build(),
+ Runnable::run
+ );
+
+ HttpResponse response = handler.handle(createTestRequest("", GET));
+ assertEquals(200,
+ response.getStatus());
+ assertEquals("""
+ {"fingerprints":["index","middle","pinky","ring","thumb","toasty"]}""",
+ new ByteArrayOutputStream() {{ response.render(this); }}.toString(UTF_8));
+ }
+
+}