aboutsummaryrefslogtreecommitdiffstats
path: root/config-model
diff options
context:
space:
mode:
authorMorten Tokle <mortent@vespa.ai>2024-04-17 22:53:16 +0200
committerMorten Tokle <mortent@vespa.ai>2024-04-17 22:54:57 +0200
commit2b264b1ac241ab7b27a0c3c37749daaad16c0c8e (patch)
tree0d4231cee30987fd0b17cf0e02ad482473394bf5 /config-model
parent83b0e810215725e86b0066c1bead886c5bc5ac9d (diff)
Check for duplicate clients
Diffstat (limited to 'config-model')
-rw-r--r--config-model/src/main/java/com/yahoo/vespa/model/container/xml/ContainerModelBuilder.java7
-rw-r--r--config-model/src/test/java/com/yahoo/vespa/model/container/xml/CloudTokenDataPlaneFilterTest.java30
2 files changed, 37 insertions, 0 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 360a02256a9..c6fca8d32c6 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
@@ -506,6 +506,13 @@ public class ContainerModelBuilder extends ConfigModelBuilder<ContainerModel> {
boolean atLeastOneClientWithCertificate = clients.stream().anyMatch(client -> !client.certificates().isEmpty());
if (!atLeastOneClientWithCertificate)
throw new IllegalArgumentException("At least one client must require a certificate");
+
+ List<String> duplicates = clients.stream().collect(Collectors.groupingBy(Client::id))
+ .entrySet().stream().filter(entry -> entry.getValue().size() > 1)
+ .map(Map.Entry::getKey).sorted().toList();
+ if (! duplicates.isEmpty()) {
+ throw new IllegalArgumentException("Duplicate client ids: " + duplicates);
+ }
}
List<X509Certificate> operatorAndTesterCertificates = deployState.getProperties().operatorCertificates();
diff --git a/config-model/src/test/java/com/yahoo/vespa/model/container/xml/CloudTokenDataPlaneFilterTest.java b/config-model/src/test/java/com/yahoo/vespa/model/container/xml/CloudTokenDataPlaneFilterTest.java
index 1c5eb16be80..fa09d3c1890 100644
--- a/config-model/src/test/java/com/yahoo/vespa/model/container/xml/CloudTokenDataPlaneFilterTest.java
+++ b/config-model/src/test/java/com/yahoo/vespa/model/container/xml/CloudTokenDataPlaneFilterTest.java
@@ -162,6 +162,36 @@ public class CloudTokenDataPlaneFilterTest extends ContainerModelBuilderTestBase
assertEquals("Invalid permission 'unknown-permission'. Valid values are 'read' and 'write'.", exception.getMessage());
}
+ @Test
+ void fails_on_duplicate_clients() throws IOException {
+ var certFile = securityFolder.resolve("foo.pem");
+ var servicesXml = """
+ <container version="1.0">
+ <clients>
+ <client id="mtls" permissions="read,write">
+ <certificate file="%1$s"/>
+ </client>
+ <client id="mtls" permissions="read,write">
+ <certificate file="%1$s"/>
+ </client>
+ <client id="token1" permissions="read">
+ <token id="my-token"/>
+ </client>
+ <client id="token2" permissions="read">
+ <token id="my-token"/>
+ </client>
+ <client id="token1" permissions="read">
+ <token id="my-token"/>
+ </client>
+ </clients>
+ </container>
+ """.formatted(applicationFolder.toPath().relativize(certFile).toString());
+ var clusterElem = DomBuilderTest.parse(servicesXml);
+ createCertificate(certFile);
+ var exception = assertThrows(IllegalArgumentException.class, () -> buildModel(Set.of(mtlsEndpoint), defaultTokens, clusterElem));
+ assertEquals("Duplicate client ids: [mtls, token1]", exception.getMessage());
+ }
+
private static CloudTokenDataPlaneFilterConfig.Clients.Tokens tokenConfig(
String id, Collection<String> fingerprints, Collection<String> accessCheckHashes, Collection<String> expirations) {
return new CloudTokenDataPlaneFilterConfig.Clients.Tokens.Builder()