diff options
author | Bjørn Christian Seime <bjorncs@oath.com> | 2018-05-31 15:20:49 +0200 |
---|---|---|
committer | Bjørn Christian Seime <bjorncs@oath.com> | 2018-06-07 11:02:29 +0200 |
commit | 7f046ca8efed0644a563d012ff3959457ff69d6b (patch) | |
tree | cff4750fdf350b3f385bd835634476a14fcb7cee /vespa-athenz/src | |
parent | 11e726b444abe0b4cd01d390ae1b7cee68ed6e98 (diff) |
Add identity type to unique instance id and signed identity document
Diffstat (limited to 'vespa-athenz/src')
8 files changed, 128 insertions, 25 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 9f065e7285d..12389712976 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 @@ -12,6 +12,8 @@ import com.yahoo.vespa.athenz.utils.AthenzIdentities; import java.util.Base64; +import static com.yahoo.vespa.athenz.identityprovider.api.VespaUniqueInstanceId.*; + /** * Utility class for mapping objects model types and their Jackson binding versions. * @@ -33,7 +35,7 @@ public class EntityBindingsMapper { public static VespaUniqueInstanceId toVespaUniqueInstanceId(VespaUniqueInstanceIdEntity entity) { return new VespaUniqueInstanceId( - entity.clusterIndex, entity.clusterId, entity.instance, entity.application, entity.tenant, entity.region, entity.environment); + entity.clusterIndex, entity.clusterId, entity.instance, entity.application, entity.tenant, entity.region, entity.environment, entity.type != null ? IdentityType.fromId(entity.type) : null); // TODO Remove support for legacy representation without type } public static IdentityDocument toIdentityDocument(IdentityDocumentEntity entity) { @@ -50,7 +52,7 @@ public class EntityBindingsMapper { toIdentityDocument(entity.identityDocument), entity.signature, entity.signingKeyVersion, - VespaUniqueInstanceId.fromDottedString(entity.providerUniqueId), + fromDottedString(entity.providerUniqueId), entity.dnsSuffix, (AthenzService) AthenzIdentities.from(entity.providerService), entity.ztsEndpoint, @@ -58,13 +60,14 @@ public class EntityBindingsMapper { entity.configServerHostname, entity.instanceHostname, entity.createdAt, - entity.ipAddresses); + entity.ipAddresses, + entity.identityType != null ? IdentityType.fromId(entity.identityType) : null); // TODO Remove support for legacy representation without type } public static VespaUniqueInstanceIdEntity toVespaUniqueInstanceIdEntity(VespaUniqueInstanceId model) { return new VespaUniqueInstanceIdEntity( model.tenant(), model.application(), model.environment(), model.region(), - model.instance(), model.clusterId(), model.clusterIndex()); + model.instance(), model.clusterId(), model.clusterIndex(), model.type() != null ? model.type().id() : null); // TODO Remove support for legacy representation without type } public static IdentityDocumentEntity toIdentityDocumentEntity(IdentityDocument model) { @@ -92,7 +95,8 @@ public class EntityBindingsMapper { model.configServerHostname(), model.instanceHostname(), model.createdAt(), - model.ipAddresses()); + model.ipAddresses(), + model.identityType() != null ? model.identityType().id() : null); // TODO Remove support for legacy representation without type } catch (JsonProcessingException e) { throw new RuntimeException(e); } diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/api/IdentityType.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/api/IdentityType.java new file mode 100644 index 00000000000..4ca2e34a618 --- /dev/null +++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/api/IdentityType.java @@ -0,0 +1,25 @@ +// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.vespa.athenz.identityprovider.api; + +import java.util.Arrays; + +/** + * Represents the types of identities that the configserver can provide. + * + * @author bjorncs + */ +public enum IdentityType {TENANT("tenant"), NODE("node"); + private final String id; + + IdentityType(String id) { this.id = id; } + + public String id() { return id; } + + public static IdentityType fromId(String id) { + return Arrays.stream(values()) + .filter(v -> v.id.equals(id)) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException("Invalid id: " + id)); + } +} + 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 6372c2202f0..60be42544c7 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 @@ -28,6 +28,7 @@ public class SignedIdentityDocument { private final String instanceHostname; private final Instant createdAt; private final Set<String> ipAddresses; + private final IdentityType identityType; public SignedIdentityDocument(IdentityDocument identityDocument, String signature, @@ -40,7 +41,8 @@ public class SignedIdentityDocument { String configServerHostname, String instanceHostname, Instant createdAt, - Set<String> ipAddresses) { + Set<String> ipAddresses, + IdentityType identityType) { this.identityDocument = identityDocument; this.signature = signature; this.signingKeyVersion = signingKeyVersion; @@ -53,6 +55,7 @@ public class SignedIdentityDocument { this.instanceHostname = instanceHostname; this.createdAt = createdAt; this.ipAddresses = ipAddresses; + this.identityType = identityType; } public IdentityDocument identityDocument() { @@ -102,4 +105,8 @@ public class SignedIdentityDocument { public Set<String> ipAddresses() { return ipAddresses; } + + public IdentityType identityType() { + return identityType; + } } diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/api/VespaUniqueInstanceId.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/api/VespaUniqueInstanceId.java index 5539ba53882..be94cc59691 100644 --- a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/api/VespaUniqueInstanceId.java +++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/api/VespaUniqueInstanceId.java @@ -4,6 +4,8 @@ package com.yahoo.vespa.athenz.identityprovider.api; import java.util.Objects; /** + * Represents the unique instance id as used in Vespa's integration with Athenz Copper Argos + * * @author bjorncs */ public class VespaUniqueInstanceId { @@ -15,6 +17,7 @@ public class VespaUniqueInstanceId { private final String tenant; private final String region; private final String environment; + private final IdentityType type; public VespaUniqueInstanceId(int clusterIndex, String clusterId, @@ -22,7 +25,8 @@ public class VespaUniqueInstanceId { String application, String tenant, String region, - String environment) { + String environment, + IdentityType type) { this.clusterIndex = clusterIndex; this.clusterId = clusterId; this.instance = instance; @@ -30,21 +34,43 @@ public class VespaUniqueInstanceId { this.tenant = tenant; this.region = region; this.environment = environment; + this.type = type; } + // TODO Remove support for legacy representation without type + @Deprecated + public VespaUniqueInstanceId(int clusterIndex, + String clusterId, + String instance, + String application, + String tenant, + String region, + String environment) { + this(clusterIndex, clusterId, instance, application, tenant, region, environment, null); + } + + + // TODO Remove support for legacy representation without type public static VespaUniqueInstanceId fromDottedString(String instanceId) { String[] tokens = instanceId.split("\\."); - if (tokens.length != 7) { + if (tokens.length != 7 && tokens.length != 8) { throw new IllegalArgumentException("Invalid instance id: " + instanceId); } return new VespaUniqueInstanceId( - Integer.parseInt(tokens[0]), tokens[1], tokens[2], tokens[3], tokens[4], tokens[5], tokens[6]); + Integer.parseInt(tokens[0]), tokens[1], tokens[2], tokens[3], tokens[4], tokens[5], tokens[6], tokens.length == 8 ? IdentityType.fromId(tokens[7]) : null); } + // TODO Remove support for legacy representation without type public String asDottedString() { - return String.format( - "%d.%s.%s.%s.%s.%s.%s", - clusterIndex, clusterId, instance, application, tenant, region, environment); + if (type != null) { + return String.format( + "%d.%s.%s.%s.%s.%s.%s.%s", + clusterIndex, clusterId, instance, application, tenant, region, environment, type.id()); + } else { + return String.format( + "%d.%s.%s.%s.%s.%s.%s", + clusterIndex, clusterId, instance, application, tenant, region, environment); + } } public int clusterIndex() { @@ -75,6 +101,8 @@ public class VespaUniqueInstanceId { return environment; } + public IdentityType type() { return type; } + @Override public String toString() { return "VespaUniqueInstanceId{" + @@ -85,6 +113,7 @@ public class VespaUniqueInstanceId { ", tenant='" + tenant + '\'' + ", region='" + region + '\'' + ", environment='" + environment + '\'' + + ", type=" + type + '}'; } @@ -99,11 +128,12 @@ public class VespaUniqueInstanceId { Objects.equals(application, that.application) && Objects.equals(tenant, that.tenant) && Objects.equals(region, that.region) && - Objects.equals(environment, that.environment); + Objects.equals(environment, that.environment) && + type == that.type; } @Override public int hashCode() { - return Objects.hash(clusterIndex, clusterId, instance, application, tenant, region, environment); + return Objects.hash(clusterIndex, clusterId, instance, application, tenant, region, environment, type); } } 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 5b8ea681b25..aa514b3caf3 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 @@ -37,6 +37,7 @@ public class SignedIdentityDocumentEntity { @JsonProperty("instance-hostname") public final String instanceHostname; @JsonProperty("created-at") public final Instant createdAt; @JsonProperty("ip-addresses") public final Set<String> ipAddresses; + @JsonProperty("identity-type") public final String identityType; @JsonCreator public SignedIdentityDocumentEntity(@JsonProperty("identity-document") String rawIdentityDocument, @@ -50,7 +51,8 @@ public class SignedIdentityDocumentEntity { @JsonProperty("configserver-hostname") String configServerHostname, @JsonProperty("instance-hostname") String instanceHostname, @JsonProperty("created-at") Instant createdAt, - @JsonProperty("ip-addresses") Set<String> ipAddresses) { + @JsonProperty("ip-addresses") Set<String> ipAddresses, + @JsonProperty("identity-type") String identityType) { this.rawIdentityDocument = rawIdentityDocument; this.identityDocument = parseIdentityDocument(rawIdentityDocument); this.signature = signature; @@ -64,6 +66,7 @@ public class SignedIdentityDocumentEntity { this.instanceHostname = instanceHostname; this.createdAt = createdAt; this.ipAddresses = ipAddresses; + this.identityType = identityType; } private static IdentityDocumentEntity parseIdentityDocument(String rawIdentityDocument) { @@ -96,6 +99,7 @@ public class SignedIdentityDocumentEntity { ", instanceHostname='" + instanceHostname + '\'' + ", createdAt=" + createdAt + ", ipAddresses=" + ipAddresses + + ", identityType=" + identityType + '}'; } @@ -116,14 +120,12 @@ public class SignedIdentityDocumentEntity { Objects.equals(configServerHostname, that.configServerHostname) && Objects.equals(instanceHostname, that.instanceHostname) && Objects.equals(createdAt, that.createdAt) && - Objects.equals(ipAddresses, that.ipAddresses); + Objects.equals(ipAddresses, that.ipAddresses) && + Objects.equals(identityType, identityType); } @Override public int hashCode() { - - return Objects.hash(rawIdentityDocument, identityDocument, signature, signingKeyVersion, providerUniqueId, - dnsSuffix, providerService, ztsEndpoint, documentVersion, configServerHostname, - instanceHostname, createdAt, ipAddresses); + return Objects.hash(rawIdentityDocument, identityDocument, signature, signingKeyVersion, providerUniqueId, dnsSuffix, providerService, ztsEndpoint, documentVersion, configServerHostname, instanceHostname, createdAt, ipAddresses, identityType); } } diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/api/bindings/VespaUniqueInstanceIdEntity.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/api/bindings/VespaUniqueInstanceIdEntity.java index 3c521e992ad..3fdbb49b28e 100644 --- a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/api/bindings/VespaUniqueInstanceIdEntity.java +++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/api/bindings/VespaUniqueInstanceIdEntity.java @@ -2,6 +2,7 @@ package com.yahoo.vespa.athenz.identityprovider.api.bindings; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; import java.util.Objects; @@ -26,14 +27,18 @@ public class VespaUniqueInstanceIdEntity { public final String clusterId; @JsonProperty("cluster-index") public final int clusterIndex; + @JsonProperty("type") + public final String type; + @JsonCreator public VespaUniqueInstanceIdEntity(@JsonProperty("tenant") String tenant, @JsonProperty("application") String application, @JsonProperty("environment") String environment, @JsonProperty("region") String region, @JsonProperty("instance") String instance, @JsonProperty("cluster-id") String clusterId, - @JsonProperty("cluster-index") int clusterIndex) { + @JsonProperty("cluster-index") int clusterIndex, + @JsonProperty("type") String type) { this.tenant = tenant; this.application = application; this.environment = environment; @@ -41,8 +46,21 @@ public class VespaUniqueInstanceIdEntity { this.instance = instance; this.clusterId = clusterId; this.clusterIndex = clusterIndex; + this.type = type; } + @Deprecated + public VespaUniqueInstanceIdEntity(String tenant, + String application, + String environment, + String region, + String instance, + String clusterId, + int clusterIndex) { + this(tenant, application, environment, region, instance, clusterId, clusterIndex, null); + } + + @Override public String toString() { return "VespaUniqueInstanceIdEntity{" + @@ -53,6 +71,7 @@ public class VespaUniqueInstanceIdEntity { ", instance='" + instance + '\'' + ", clusterId='" + clusterId + '\'' + ", clusterIndex=" + clusterIndex + + ", type='" + type + '\'' + '}'; } @@ -67,11 +86,12 @@ public class VespaUniqueInstanceIdEntity { Objects.equals(environment, that.environment) && Objects.equals(region, that.region) && Objects.equals(instance, that.instance) && - Objects.equals(clusterId, that.clusterId); + Objects.equals(clusterId, that.clusterId) && + Objects.equals(type, that.type); } @Override public int hashCode() { - return Objects.hash(tenant, application, environment, region, instance, clusterId, clusterIndex); + return Objects.hash(tenant, application, environment, region, instance, clusterId, clusterIndex, type); } } diff --git a/vespa-athenz/src/test/java/com/yahoo/vespa/athenz/identityprovider/api/VespaUniqueInstanceIdTest.java b/vespa-athenz/src/test/java/com/yahoo/vespa/athenz/identityprovider/api/VespaUniqueInstanceIdTest.java index 8c4e4c1262d..86b6c566987 100644 --- a/vespa-athenz/src/test/java/com/yahoo/vespa/athenz/identityprovider/api/VespaUniqueInstanceIdTest.java +++ b/vespa-athenz/src/test/java/com/yahoo/vespa/athenz/identityprovider/api/VespaUniqueInstanceIdTest.java @@ -2,6 +2,7 @@ package com.yahoo.vespa.athenz.identityprovider.api; import org.junit.Test; +import static com.yahoo.vespa.athenz.identityprovider.api.IdentityType.*; import static org.junit.Assert.*; /** @@ -12,6 +13,18 @@ public class VespaUniqueInstanceIdTest { @Test public void can_serialize_to_and_deserialize_from_string() { VespaUniqueInstanceId id = + new VespaUniqueInstanceId(1, "cluster-id", "instance", "application", "tenant", "region", "environment", TENANT); + String stringRepresentation = id.asDottedString(); + String expectedStringRepresentation = "1.cluster-id.instance.application.tenant.region.environment.tenant"; + assertEquals(expectedStringRepresentation, stringRepresentation); + VespaUniqueInstanceId deserializedId = VespaUniqueInstanceId.fromDottedString(stringRepresentation); + assertEquals(id, deserializedId); + } + + // TODO Remove support for legacy representation without type + @Test + public void supports_legacy_representation_without_type() { + VespaUniqueInstanceId id = new VespaUniqueInstanceId(1, "cluster-id", "instance", "application", "tenant", "region", "environment"); String stringRepresentation = id.asDottedString(); String expectedStringRepresentation = "1.cluster-id.instance.application.tenant.region.environment"; diff --git a/vespa-athenz/src/test/java/com/yahoo/vespa/athenz/identityprovider/client/AthenzIdentityProviderImplTest.java b/vespa-athenz/src/test/java/com/yahoo/vespa/athenz/identityprovider/client/AthenzIdentityProviderImplTest.java index a84435f2982..7ad465a7d80 100644 --- a/vespa-athenz/src/test/java/com/yahoo/vespa/athenz/identityprovider/client/AthenzIdentityProviderImplTest.java +++ b/vespa-athenz/src/test/java/com/yahoo/vespa/athenz/identityprovider/client/AthenzIdentityProviderImplTest.java @@ -11,6 +11,7 @@ import com.yahoo.test.ManualClock; import com.yahoo.vespa.athenz.api.AthenzService; import com.yahoo.vespa.athenz.identityprovider.api.EntityBindingsMapper; import com.yahoo.vespa.athenz.identityprovider.api.IdentityDocument; +import com.yahoo.vespa.athenz.identityprovider.api.IdentityType; import com.yahoo.vespa.athenz.identityprovider.api.SignedIdentityDocument; import com.yahoo.vespa.athenz.identityprovider.api.VespaUniqueInstanceId; import com.yahoo.vespa.athenz.tls.KeyStoreBuilder; @@ -132,7 +133,7 @@ public class AthenzIdentityProviderImplTest { } private static String getIdentityDocument() throws JsonProcessingException { - VespaUniqueInstanceId instanceId = new VespaUniqueInstanceId(0, "default", "default", "application", "tenant", "us-north-1", "dev"); + VespaUniqueInstanceId instanceId = new VespaUniqueInstanceId(0, "default", "default", "application", "tenant", "us-north-1", "dev", IdentityType.TENANT); SignedIdentityDocument signedIdentityDocument = new SignedIdentityDocument( new IdentityDocument(instanceId, "localhost", "x.y.com", Instant.EPOCH, Collections.emptySet()), "dummysignature", @@ -145,7 +146,8 @@ public class AthenzIdentityProviderImplTest { "localhost", "x.y.com", Instant.EPOCH, - Collections.emptySet()); + Collections.emptySet(), + IdentityType.TENANT); return new ObjectMapper().registerModule(new JavaTimeModule()) .writeValueAsString(EntityBindingsMapper.toSignedIdentityDocumentEntity(signedIdentityDocument)); |