diff options
author | Morten Tokle <mortent@vespa.ai> | 2024-04-17 22:53:16 +0200 |
---|---|---|
committer | Morten Tokle <mortent@vespa.ai> | 2024-04-17 22:54:57 +0200 |
commit | 2b264b1ac241ab7b27a0c3c37749daaad16c0c8e (patch) | |
tree | 0d4231cee30987fd0b17cf0e02ad482473394bf5 /config-model | |
parent | 83b0e810215725e86b0066c1bead886c5bc5ac9d (diff) |
Check for duplicate clients
Diffstat (limited to 'config-model')
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() |