summaryrefslogtreecommitdiffstats
path: root/security-utils
diff options
context:
space:
mode:
authorBjørn Christian Seime <bjorncs@yahooinc.com>2022-07-13 10:48:24 +0200
committerBjørn Christian Seime <bjorncs@yahooinc.com>2022-07-13 10:49:05 +0200
commit1f693c55dcc6f7a4fbf9fae288085bd2dea2c63e (patch)
tree9256738699d0bf0f3b7d88b2de868146a74c1934 /security-utils
parentb9b314f5c55b3b09e12d5407415640a149844767 (diff)
Add Capability and CapabilitySet including JSON serialization
Diffstat (limited to 'security-utils')
-rw-r--r--security-utils/src/main/java/com/yahoo/security/tls/json/TransportSecurityOptionsEntity.java1
-rw-r--r--security-utils/src/main/java/com/yahoo/security/tls/json/TransportSecurityOptionsJsonSerializer.java17
-rw-r--r--security-utils/src/main/java/com/yahoo/security/tls/policy/Capability.java32
-rw-r--r--security-utils/src/main/java/com/yahoo/security/tls/policy/CapabilitySet.java90
-rw-r--r--security-utils/src/main/java/com/yahoo/security/tls/policy/PeerPolicy.java11
-rw-r--r--security-utils/src/test/java/com/yahoo/security/tls/json/TransportSecurityOptionsJsonSerializerTest.java7
-rw-r--r--security-utils/src/test/java/com/yahoo/security/tls/policy/CapabilitySetTest.java27
-rw-r--r--security-utils/src/test/resources/transport-security-options-with-authz-rules.json3
8 files changed, 182 insertions, 6 deletions
diff --git a/security-utils/src/main/java/com/yahoo/security/tls/json/TransportSecurityOptionsEntity.java b/security-utils/src/main/java/com/yahoo/security/tls/json/TransportSecurityOptionsEntity.java
index 02c6fe2ab99..b80a7e4f2fb 100644
--- a/security-utils/src/main/java/com/yahoo/security/tls/json/TransportSecurityOptionsEntity.java
+++ b/security-utils/src/main/java/com/yahoo/security/tls/json/TransportSecurityOptionsEntity.java
@@ -36,6 +36,7 @@ class TransportSecurityOptionsEntity {
@JsonProperty("required-credentials") List<RequiredCredential> requiredCredentials;
@JsonProperty("name") String name;
@JsonProperty("description") @JsonInclude(NON_NULL) String description;
+ @JsonProperty("capabilities") @JsonInclude(NON_EMPTY) List<String> capabilities;
}
@JsonIgnoreProperties(ignoreUnknown = true)
diff --git a/security-utils/src/main/java/com/yahoo/security/tls/json/TransportSecurityOptionsJsonSerializer.java b/security-utils/src/main/java/com/yahoo/security/tls/json/TransportSecurityOptionsJsonSerializer.java
index 5deebf48d1b..195e200febb 100644
--- a/security-utils/src/main/java/com/yahoo/security/tls/json/TransportSecurityOptionsJsonSerializer.java
+++ b/security-utils/src/main/java/com/yahoo/security/tls/json/TransportSecurityOptionsJsonSerializer.java
@@ -8,6 +8,7 @@ import com.yahoo.security.tls.json.TransportSecurityOptionsEntity.CredentialFiel
import com.yahoo.security.tls.json.TransportSecurityOptionsEntity.Files;
import com.yahoo.security.tls.json.TransportSecurityOptionsEntity.RequiredCredential;
import com.yahoo.security.tls.policy.AuthorizedPeers;
+import com.yahoo.security.tls.policy.CapabilitySet;
import com.yahoo.security.tls.policy.PeerPolicy;
import com.yahoo.security.tls.policy.RequiredPeerCredential;
@@ -19,6 +20,7 @@ import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
+import java.util.Optional;
import java.util.Set;
import static java.util.stream.Collectors.toList;
@@ -99,7 +101,16 @@ public class TransportSecurityOptionsJsonSerializer {
if (authorizedPeer.requiredCredentials == null) {
throw missingFieldException("required-credentials");
}
- return new PeerPolicy(authorizedPeer.name, authorizedPeer.description, toRequestPeerCredentials(authorizedPeer.requiredCredentials));
+ return new PeerPolicy(authorizedPeer.name, Optional.ofNullable(authorizedPeer.description),
+ toCapabilities(authorizedPeer.capabilities), toRequestPeerCredentials(authorizedPeer.requiredCredentials));
+ }
+
+ private static CapabilitySet toCapabilities(List<String> capabilities) {
+ if (capabilities == null) return CapabilitySet.all();
+ if (capabilities.isEmpty())
+ throw new IllegalArgumentException("\"capabilities\" array must either be not present " +
+ "(implies all capabilities) or contain at least one capability name");
+ return CapabilitySet.fromNames(capabilities);
}
private static List<RequiredPeerCredential> toRequestPeerCredentials(List<RequiredCredential> requiredCredentials) {
@@ -142,6 +153,10 @@ public class TransportSecurityOptionsJsonSerializer {
authorizedPeer.name = peerPolicy.policyName();
authorizedPeer.requiredCredentials = new ArrayList<>();
authorizedPeer.description = peerPolicy.description().orElse(null);
+ CapabilitySet caps = peerPolicy.capabilities();
+ if (!caps.hasAllCapabilities()) {
+ authorizedPeer.capabilities = List.copyOf(caps.toCapabilityNames());
+ }
for (RequiredPeerCredential requiredPeerCredential : peerPolicy.requiredCredentials()) {
RequiredCredential requiredCredential = new RequiredCredential();
requiredCredential.field = toField(requiredPeerCredential.field());
diff --git a/security-utils/src/main/java/com/yahoo/security/tls/policy/Capability.java b/security-utils/src/main/java/com/yahoo/security/tls/policy/Capability.java
new file mode 100644
index 00000000000..09d4de37831
--- /dev/null
+++ b/security-utils/src/main/java/com/yahoo/security/tls/policy/Capability.java
@@ -0,0 +1,32 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.security.tls.policy;
+
+import java.util.Arrays;
+
+/**
+ * @author bjorncs
+ */
+public enum Capability {
+ CONTENT__CLUSTER_CONTROLLER__INTERNAL_STATE_API("vespa.content.cluster_controller.internal_state_api"),
+ CONTENT__DOCUMENT_API("vespa.content.document_api"),
+ CONTENT__METRICS_API("vespa.content.metrics_api"),
+ CONTENT__SEARCH_API("vespa.content.search_api"),
+ CONTENT__STATUS_PAGES("vespa.content.status_pages"),
+ CONTENT__STORAGE_API("vespa.content.storage_api"),
+ SLOBROK__API("vespa.slobrok.api"),
+ ;
+
+ private final String name;
+
+ Capability(String name) { this.name = name; }
+
+ public String asString() { return name; }
+
+ public static Capability fromName(String name) {
+ return Arrays.stream(values())
+ .filter(c -> c.name.equals(name))
+ .findAny().orElseThrow(() ->
+ new IllegalArgumentException("Cannot find predefined capability set with name '" + name + "'"));
+ }
+
+}
diff --git a/security-utils/src/main/java/com/yahoo/security/tls/policy/CapabilitySet.java b/security-utils/src/main/java/com/yahoo/security/tls/policy/CapabilitySet.java
new file mode 100644
index 00000000000..44ff1eedfb0
--- /dev/null
+++ b/security-utils/src/main/java/com/yahoo/security/tls/policy/CapabilitySet.java
@@ -0,0 +1,90 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.security.tls.policy;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.SortedSet;
+import java.util.TreeSet;
+import java.util.stream.Collectors;
+
+/**
+ * @author bjorncs
+ */
+public class CapabilitySet {
+ public enum Predefined {
+ CONTENT_NODE("vespa.content_node",
+ Capability.CONTENT__STORAGE_API, Capability.CONTENT__DOCUMENT_API, Capability.SLOBROK__API),
+ CONTAINER_NODE("vespa.container_node",
+ Capability.CONTENT__DOCUMENT_API, Capability.CONTENT__SEARCH_API, Capability.SLOBROK__API),
+ TELEMETRY("vespa.telemetry",
+ Capability.CONTENT__STATUS_PAGES, Capability.CONTENT__METRICS_API),
+ CLUSTER_CONTROLLER_NODE("vespa.cluster_controller_node",
+ Capability.CONTENT__CLUSTER_CONTROLLER__INTERNAL_STATE_API, Capability.SLOBROK__API),
+ CONFIG_SERVER("vespa.config_server"),
+ ;
+
+ private final String name;
+ private final EnumSet<Capability> caps;
+
+ Predefined(String name, Capability... caps) {
+ this.name = name;
+ this.caps = caps.length == 0 ? EnumSet.noneOf(Capability.class) : EnumSet.copyOf(List.of(caps)); }
+
+ public static Optional<Predefined> fromName(String name) {
+ return Arrays.stream(values()).filter(p -> p.name.equals(name)).findAny();
+ }
+ }
+
+ private static final CapabilitySet ALL_CAPABILITIES = new CapabilitySet(EnumSet.allOf(Capability.class));
+ private static final CapabilitySet NO_CAPABILITIES = new CapabilitySet(EnumSet.noneOf(Capability.class));
+
+ private final EnumSet<Capability> caps;
+
+ private CapabilitySet(EnumSet<Capability> caps) { this.caps = caps; }
+
+ public static CapabilitySet fromNames(Collection<String> names) {
+ EnumSet<Capability> caps = EnumSet.noneOf(Capability.class);
+ for (String name : names) {
+ Predefined predefined = Predefined.fromName(name).orElse(null);
+ if (predefined != null) caps.addAll(predefined.caps);
+ else caps.add(Capability.fromName(name));
+ }
+ return new CapabilitySet(caps);
+ }
+
+ public static CapabilitySet from(EnumSet<Capability> caps) { return new CapabilitySet(EnumSet.copyOf(caps)); }
+ public static CapabilitySet from(Collection<Capability> caps) { return new CapabilitySet(EnumSet.copyOf(caps)); }
+ public static CapabilitySet from(Capability... caps) { return new CapabilitySet(EnumSet.copyOf(List.of(caps))); }
+ public static CapabilitySet all() { return ALL_CAPABILITIES; }
+ public static CapabilitySet none() { return NO_CAPABILITIES; }
+
+ public boolean hasAllCapabilities() { return this.caps.equals(ALL_CAPABILITIES.caps); }
+
+ public SortedSet<String> toCapabilityNames() {
+ return caps.stream().map(Capability::asString).collect(Collectors.toCollection(TreeSet::new));
+ }
+
+ @Override
+ public String toString() {
+ return "CapabilitySet{" +
+ "caps=" + caps +
+ '}';
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ CapabilitySet that = (CapabilitySet) o;
+ return Objects.equals(caps, that.caps);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(caps);
+ }
+}
diff --git a/security-utils/src/main/java/com/yahoo/security/tls/policy/PeerPolicy.java b/security-utils/src/main/java/com/yahoo/security/tls/policy/PeerPolicy.java
index 332c0d1a43f..cb39e5e9c3c 100644
--- a/security-utils/src/main/java/com/yahoo/security/tls/policy/PeerPolicy.java
+++ b/security-utils/src/main/java/com/yahoo/security/tls/policy/PeerPolicy.java
@@ -7,13 +7,18 @@ import java.util.Optional;
/**
* @author bjorncs
*/
-public record PeerPolicy(String policyName, Optional<String> description, List<RequiredPeerCredential> requiredCredentials) {
+public record PeerPolicy(String policyName, Optional<String> description, CapabilitySet capabilities,
+ List<RequiredPeerCredential> requiredCredentials) {
+
+ public PeerPolicy {
+ requiredCredentials = List.copyOf(requiredCredentials);
+ }
public PeerPolicy(String policyName, List<RequiredPeerCredential> requiredCredentials) {
- this(policyName, Optional.empty(), List.copyOf(requiredCredentials));
+ this(policyName, Optional.empty(), CapabilitySet.all(), requiredCredentials);
}
public PeerPolicy(String policyName, String description, List<RequiredPeerCredential> requiredCredentials) {
- this(policyName, Optional.ofNullable(description), List.copyOf(requiredCredentials));
+ this(policyName, Optional.ofNullable(description), CapabilitySet.all(), requiredCredentials);
}
}
diff --git a/security-utils/src/test/java/com/yahoo/security/tls/json/TransportSecurityOptionsJsonSerializerTest.java b/security-utils/src/test/java/com/yahoo/security/tls/json/TransportSecurityOptionsJsonSerializerTest.java
index 2cb262cecc0..852d6ae94c9 100644
--- a/security-utils/src/test/java/com/yahoo/security/tls/json/TransportSecurityOptionsJsonSerializerTest.java
+++ b/security-utils/src/test/java/com/yahoo/security/tls/json/TransportSecurityOptionsJsonSerializerTest.java
@@ -3,6 +3,8 @@ package com.yahoo.security.tls.json;
import com.yahoo.security.tls.TransportSecurityOptions;
import com.yahoo.security.tls.policy.AuthorizedPeers;
+import com.yahoo.security.tls.policy.Capability;
+import com.yahoo.security.tls.policy.CapabilitySet;
import com.yahoo.security.tls.policy.PeerPolicy;
import com.yahoo.security.tls.policy.RequiredPeerCredential;
import org.junit.Rule;
@@ -20,6 +22,7 @@ import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashSet;
+import java.util.Optional;
import static com.yahoo.security.tls.policy.RequiredPeerCredential.Field.CN;
import static com.yahoo.security.tls.policy.RequiredPeerCredential.Field.SAN_DNS;
@@ -49,7 +52,9 @@ public class TransportSecurityOptionsJsonSerializerTest {
RequiredPeerCredential.of(CN, "mycfgserver"),
RequiredPeerCredential.of(SAN_DNS, "*.suffix.com"),
RequiredPeerCredential.of(SAN_URI, "myscheme://resource/path/"))),
- new PeerPolicy("node", Collections.singletonList(RequiredPeerCredential.of(CN, "hostname")))))))
+ new PeerPolicy("node", Optional.empty(),
+ CapabilitySet.from(Capability.SLOBROK__API),
+ Collections.singletonList(RequiredPeerCredential.of(CN, "hostname")))))))
.build();
ByteArrayOutputStream out = new ByteArrayOutputStream();
diff --git a/security-utils/src/test/java/com/yahoo/security/tls/policy/CapabilitySetTest.java b/security-utils/src/test/java/com/yahoo/security/tls/policy/CapabilitySetTest.java
new file mode 100644
index 00000000000..3379c37e918
--- /dev/null
+++ b/security-utils/src/test/java/com/yahoo/security/tls/policy/CapabilitySetTest.java
@@ -0,0 +1,27 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.security.tls.policy;
+
+import org.junit.jupiter.api.Test;
+
+import java.util.Arrays;
+import java.util.SortedSet;
+import java.util.TreeSet;
+import java.util.stream.Collectors;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+/**
+ * @author bjorncs
+ */
+class CapabilitySetTest {
+
+ @Test
+ void contains_all_capabilities() {
+ SortedSet<String> expectedNames = Arrays.stream(Capability.values())
+ .map(Capability::asString)
+ .collect(Collectors.toCollection(TreeSet::new));
+ SortedSet<String> actualNames = CapabilitySet.all().toCapabilityNames();
+ assertEquals(expectedNames, actualNames);
+ }
+
+}
diff --git a/security-utils/src/test/resources/transport-security-options-with-authz-rules.json b/security-utils/src/test/resources/transport-security-options-with-authz-rules.json
index 06ed6e0943c..85c3a78311e 100644
--- a/security-utils/src/test/resources/transport-security-options-with-authz-rules.json
+++ b/security-utils/src/test/resources/transport-security-options-with-authz-rules.json
@@ -22,6 +22,7 @@
"field" : "CN",
"must-match" : "hostname"
} ],
- "name" : "node"
+ "name" : "node",
+ "capabilities" : [ "vespa.slobrok.api" ]
} ]
} \ No newline at end of file