summaryrefslogtreecommitdiffstats
path: root/vespa-athenz
diff options
context:
space:
mode:
authorBjørn Christian Seime <bjorncs@yahooinc.com>2023-02-07 13:28:47 +0100
committerBjørn Christian Seime <bjorncs@yahooinc.com>2023-02-07 13:31:04 +0100
commit2669ebaf70b96f709b7935d3a0a74953a622722d (patch)
tree414b3fb295646411ab90132c956a245ce779291b /vespa-athenz
parentb79686282bb938c9d8257f067606b1b344c6f8ac (diff)
Handle unknown attributes in identity document
Diffstat (limited to 'vespa-athenz')
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/api/EntityBindingsMapper.java19
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/api/SignedIdentityDocument.java20
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/api/bindings/SignedIdentityDocumentEntity.java52
-rw-r--r--vespa-athenz/src/test/java/com/yahoo/vespa/athenz/identityprovider/api/EntityBindingsMapperTest.java47
4 files changed, 118 insertions, 20 deletions
diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/api/EntityBindingsMapper.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/api/EntityBindingsMapper.java
index 110bd5e885e..9b7b666e353 100644
--- a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/api/EntityBindingsMapper.java
+++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/api/EntityBindingsMapper.java
@@ -25,7 +25,7 @@ import static com.yahoo.vespa.athenz.identityprovider.api.VespaUniqueInstanceId.
*/
public class EntityBindingsMapper {
- private static final ObjectMapper mapper = new ObjectMapper().registerModule(new JavaTimeModule());
+ static final ObjectMapper mapper = new ObjectMapper().registerModule(new JavaTimeModule());
private EntityBindingsMapper() {}
@@ -37,6 +37,14 @@ public class EntityBindingsMapper {
}
}
+ public static SignedIdentityDocument fromInputStream(InputStream in) throws IOException {
+ return EntityBindingsMapper.toSignedIdentityDocument(mapper.readValue(in, SignedIdentityDocumentEntity.class));
+ }
+
+ public static SignedIdentityDocument fromString(String json) throws IOException {
+ return EntityBindingsMapper.toSignedIdentityDocument(mapper.readValue(json, SignedIdentityDocumentEntity.class));
+ }
+
public static SignedIdentityDocument toSignedIdentityDocument(SignedIdentityDocumentEntity entity) {
return new SignedIdentityDocument(
entity.signature(),
@@ -49,7 +57,8 @@ public class EntityBindingsMapper {
entity.createdAt(),
entity.ipAddresses(),
IdentityType.fromId(entity.identityType()),
- Optional.ofNullable(entity.clusterType()).map(ClusterType::from).orElse(null));
+ Optional.ofNullable(entity.clusterType()).map(ClusterType::from).orElse(null),
+ entity.unknownAttributes());
}
public static SignedIdentityDocumentEntity toSignedIdentityDocumentEntity(SignedIdentityDocument model) {
@@ -64,13 +73,13 @@ public class EntityBindingsMapper {
model.createdAt(),
model.ipAddresses(),
model.identityType().id(),
- Optional.ofNullable(model.clusterType()).map(ClusterType::toConfigValue).orElse(null));
+ Optional.ofNullable(model.clusterType()).map(ClusterType::toConfigValue).orElse(null),
+ model.unknownAttributes());
}
public static SignedIdentityDocument readSignedIdentityDocumentFromFile(Path file) {
try (InputStream inputStream = Files.newInputStream(file)) {
- SignedIdentityDocumentEntity entity = mapper.readValue(inputStream, SignedIdentityDocumentEntity.class);
- return EntityBindingsMapper.toSignedIdentityDocument(entity);
+ return fromInputStream(inputStream);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/api/SignedIdentityDocument.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/api/SignedIdentityDocument.java
index e331fc1f6e8..a08f0d3391d 100644
--- a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/api/SignedIdentityDocument.java
+++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/api/SignedIdentityDocument.java
@@ -4,17 +4,33 @@ package com.yahoo.vespa.athenz.identityprovider.api;
import com.yahoo.vespa.athenz.api.AthenzService;
import java.time.Instant;
+import java.util.Map;
import java.util.Set;
/**
- * A signed identity document
+ * A signed identity document.
+ * The {@link #unknownAttributes()} member provides forward compatibility and ensures any new/unknown fields are kept intact when serialized to JSON.
*
* @author bjorncs
*/
public record SignedIdentityDocument(String signature, int signingKeyVersion, VespaUniqueInstanceId providerUniqueId,
AthenzService providerService, int documentVersion, String configServerHostname,
String instanceHostname, Instant createdAt, Set<String> ipAddresses,
- IdentityType identityType, ClusterType clusterType) {
+ IdentityType identityType, ClusterType clusterType, Map<String, Object> unknownAttributes) {
+
+ public SignedIdentityDocument {
+ ipAddresses = Set.copyOf(ipAddresses);
+ unknownAttributes = Map.copyOf(unknownAttributes);
+ }
+
+ public SignedIdentityDocument(String signature, int signingKeyVersion, VespaUniqueInstanceId providerUniqueId,
+ AthenzService providerService, int documentVersion, String configServerHostname,
+ String instanceHostname, Instant createdAt, Set<String> ipAddresses,
+ IdentityType identityType, ClusterType clusterType) {
+ this(signature, signingKeyVersion, providerUniqueId, providerService, documentVersion, configServerHostname,
+ instanceHostname, createdAt, ipAddresses, identityType, clusterType, Map.of());
+ }
+
public static final int DEFAULT_DOCUMENT_VERSION = 2;
}
diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/api/bindings/SignedIdentityDocumentEntity.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/api/bindings/SignedIdentityDocumentEntity.java
index 2fb709615da..c37dd2f9147 100644
--- a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/api/bindings/SignedIdentityDocumentEntity.java
+++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/api/bindings/SignedIdentityDocumentEntity.java
@@ -1,25 +1,51 @@
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.athenz.identityprovider.api.bindings;
-import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonAnyGetter;
+import com.fasterxml.jackson.annotation.JsonAnySetter;
+import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.time.Instant;
+import java.util.HashMap;
+import java.util.Map;
import java.util.Set;
/**
* @author bjorncs
*/
-@JsonIgnoreProperties(ignoreUnknown = true)
-public record SignedIdentityDocumentEntity(@JsonProperty("signature") String signature,
- @JsonProperty("signing-key-version") int signingKeyVersion,
- @JsonProperty("provider-unique-id") String providerUniqueId,
- @JsonProperty("provider-service") String providerService,
- @JsonProperty("document-version") int documentVersion,
- @JsonProperty("configserver-hostname") String configServerHostname,
- @JsonProperty("instance-hostname") String instanceHostname,
- @JsonProperty("created-at") Instant createdAt,
- @JsonProperty("ip-addresses") Set<String> ipAddresses,
- @JsonProperty("identity-type") String identityType,
- @JsonProperty("cluster-type") String clusterType) {
+public record SignedIdentityDocumentEntity(
+ String signature, int signingKeyVersion, String providerUniqueId, String providerService, int documentVersion,
+ String configServerHostname, String instanceHostname, Instant createdAt, Set<String> ipAddresses,
+ String identityType, String clusterType, Map<String, Object> unknownAttributes) {
+
+ @JsonCreator
+ public SignedIdentityDocumentEntity(@JsonProperty("signature") String signature,
+ @JsonProperty("signing-key-version") int signingKeyVersion,
+ @JsonProperty("provider-unique-id") String providerUniqueId,
+ @JsonProperty("provider-service") String providerService,
+ @JsonProperty("document-version") int documentVersion,
+ @JsonProperty("configserver-hostname") String configServerHostname,
+ @JsonProperty("instance-hostname") String instanceHostname,
+ @JsonProperty("created-at") Instant createdAt,
+ @JsonProperty("ip-addresses") Set<String> ipAddresses,
+ @JsonProperty("identity-type") String identityType,
+ @JsonProperty("cluster-type") String clusterType) {
+ this(signature, signingKeyVersion, providerUniqueId, providerService, documentVersion, configServerHostname,
+ instanceHostname, createdAt, ipAddresses, identityType, clusterType, new HashMap<>());
+ }
+
+ @JsonProperty("signature") @Override public String signature() { return signature; }
+ @JsonProperty("signing-key-version") @Override public int signingKeyVersion() { return signingKeyVersion; }
+ @JsonProperty("provider-unique-id") @Override public String providerUniqueId() { return providerUniqueId; }
+ @JsonProperty("provider-service") @Override public String providerService() { return providerService; }
+ @JsonProperty("document-version") @Override public int documentVersion() { return documentVersion; }
+ @JsonProperty("configserver-hostname") @Override public String configServerHostname() { return configServerHostname; }
+ @JsonProperty("instance-hostname") @Override public String instanceHostname() { return instanceHostname; }
+ @JsonProperty("created-at") @Override public Instant createdAt() { return createdAt; }
+ @JsonProperty("ip-addresses") @Override public Set<String> ipAddresses() { return ipAddresses; }
+ @JsonProperty("identity-type") @Override public String identityType() { return identityType; }
+ @JsonProperty("cluster-type") @Override public String clusterType() { return clusterType; }
+ @JsonAnyGetter @Override public Map<String, Object> unknownAttributes() { return unknownAttributes; }
+ @JsonAnySetter public void set(String name, Object value) { unknownAttributes.put(name, value); }
}
diff --git a/vespa-athenz/src/test/java/com/yahoo/vespa/athenz/identityprovider/api/EntityBindingsMapperTest.java b/vespa-athenz/src/test/java/com/yahoo/vespa/athenz/identityprovider/api/EntityBindingsMapperTest.java
new file mode 100644
index 00000000000..f8c119190a6
--- /dev/null
+++ b/vespa-athenz/src/test/java/com/yahoo/vespa/athenz/identityprovider/api/EntityBindingsMapperTest.java
@@ -0,0 +1,47 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+package com.yahoo.vespa.athenz.identityprovider.api;
+
+import org.junit.jupiter.api.Test;
+
+import java.io.IOException;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * @author bjorncs
+ */
+class EntityBindingsMapperTest {
+
+ @Test
+ public void persists_unknown_json_members() throws IOException {
+ var originalJson =
+ """
+ {
+ "signature": "sig",
+ "signing-key-version": 0,
+ "provider-unique-id": "0.cluster.instance.app.tenant.us-west-1.test.node",
+ "provider-service": "domain.service",
+ "document-version": 2,
+ "configserver-hostname": "cfg",
+ "instance-hostname": "host",
+ "created-at": 12345.0,
+ "ip-addresses": [],
+ "identity-type": "node",
+ "cluster-type": "admin",
+ "unknown-string": "string-value",
+ "unknown-object": { "member-in-unknown-object": 123 }
+ }
+ """;
+ var entity = EntityBindingsMapper.fromString(originalJson);
+ assertEquals(2, entity.unknownAttributes().size(), entity.unknownAttributes().toString());
+ var json = EntityBindingsMapper.toAttestationData(entity);
+
+ var expectedMemberInJson = "member-in-unknown-object";
+ assertTrue(json.contains(expectedMemberInJson),
+ () -> "Expected JSON to contain '%s', but got \n'%s'".formatted(expectedMemberInJson, json));
+ assertEquals(EntityBindingsMapper.mapper.readTree(originalJson), EntityBindingsMapper.mapper.readTree(json));
+ }
+
+} \ No newline at end of file