diff options
author | Bjørn Christian Seime <bjorncs@oath.com> | 2018-05-04 15:43:23 +0200 |
---|---|---|
committer | Bjørn Christian Seime <bjorncs@oath.com> | 2018-05-04 15:43:23 +0200 |
commit | 6ceb8c6a1695e715dc004c2ad055d123dcdf1522 (patch) | |
tree | 0e7bf1cb11a4c3b7b7294c6fc199ed70147ec9d2 /vespa-athenz | |
parent | 95e2b9d9a1cd0f81e1d1ed067af273d43d9161ec (diff) |
Add identity document client + domain types for signed identity document
Diffstat (limited to 'vespa-athenz')
5 files changed, 276 insertions, 0 deletions
diff --git a/vespa-athenz/pom.xml b/vespa-athenz/pom.xml index 835c9bb178c..731553bc749 100644 --- a/vespa-athenz/pom.xml +++ b/vespa-athenz/pom.xml @@ -110,6 +110,18 @@ </exclusion> </exclusions> </dependency> + <dependency> + <groupId>org.apache.httpcomponents</groupId> + <artifactId>httpcore</artifactId> + <version>4.4.1</version> + <scope>compile</scope> + </dependency> + <dependency> + <groupId>org.apache.httpcomponents</groupId> + <artifactId>httpclient</artifactId> + <version>4.5</version> + <scope>compile</scope> + </dependency> </dependencies> diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/api/IdentityDocument.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/api/IdentityDocument.java new file mode 100644 index 00000000000..8da2bd0a343 --- /dev/null +++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/api/IdentityDocument.java @@ -0,0 +1,50 @@ +// 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.time.Instant; +import java.util.Set; + +/** + * The identity document that contains the instance specific information + * + * @author bjorncs + */ +public class IdentityDocument { + private final VespaUniqueInstanceId providerUniqueId; + private final String configServerHostname; + private final String instanceHostname; + private final Instant createdAt; + private final Set<String> ipAddresses; + + public IdentityDocument(VespaUniqueInstanceId providerUniqueId, + String configServerHostname, + String instanceHostname, + Instant createdAt, + Set<String> ipAddresses) { + this.providerUniqueId = providerUniqueId; + this.configServerHostname = configServerHostname; + this.instanceHostname = instanceHostname; + this.createdAt = createdAt; + this.ipAddresses = ipAddresses; + } + + public VespaUniqueInstanceId providerUniqueId() { + return providerUniqueId; + } + + public String configServerHostname() { + return configServerHostname; + } + + public String instanceHostname() { + return instanceHostname; + } + + public Instant createdAt() { + return createdAt; + } + + public Set<String> ipAddresses() { + return ipAddresses; + } +} diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/api/IdentityDocumentClient.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/api/IdentityDocumentClient.java new file mode 100644 index 00000000000..9d903ff0c89 --- /dev/null +++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/api/IdentityDocumentClient.java @@ -0,0 +1,12 @@ +// 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; + +/** + * A client that communicates that fetches an identity document. + * + * @author bjorncs + */ +public interface IdentityDocumentClient { + SignedIdentityDocument getNodeIdentityDocument(String host); + SignedIdentityDocument getTenantIdentityDocument(String host); +} 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 new file mode 100644 index 00000000000..f9562c05c5d --- /dev/null +++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/api/SignedIdentityDocument.java @@ -0,0 +1,72 @@ +// 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 com.yahoo.vespa.athenz.api.AthenzService; + +import java.net.URI; + +/** + * A signed identity document which contains a {@link IdentityDocument} + * + * @author bjorncs + */ +public class SignedIdentityDocument { + private final IdentityDocument identityDocument; + private final String signature; + private final int signingKeyVersion; + private final VespaUniqueInstanceId providerUniqueId; + private final String dnsSuffix; + private final AthenzService providerService; + private final URI ztsEndpoint; + private final int documentVersion; + + public SignedIdentityDocument(IdentityDocument identityDocument, + String signature, + int signingKeyVersion, + VespaUniqueInstanceId providerUniqueId, + String dnsSuffix, + AthenzService providerService, + URI ztsEndpoint, + int documentVersion) { + this.identityDocument = identityDocument; + this.signature = signature; + this.signingKeyVersion = signingKeyVersion; + this.providerUniqueId = providerUniqueId; + this.dnsSuffix = dnsSuffix; + this.providerService = providerService; + this.ztsEndpoint = ztsEndpoint; + this.documentVersion = documentVersion; + } + + public IdentityDocument identityDocument() { + return identityDocument; + } + + public String signature() { + return signature; + } + + public int signingKeyVersion() { + return signingKeyVersion; + } + + public VespaUniqueInstanceId providerUniqueId() { + return providerUniqueId; + } + + public String dnsSuffix() { + return dnsSuffix; + } + + public AthenzService providerService() { + return providerService; + } + + public URI ztsEndpoint() { + return ztsEndpoint; + } + + public int documentVersion() { + return documentVersion; + } +} diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/client/DefaultIdentityDocumentClient.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/client/DefaultIdentityDocumentClient.java new file mode 100644 index 00000000000..7de42bed1ce --- /dev/null +++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/client/DefaultIdentityDocumentClient.java @@ -0,0 +1,130 @@ +// 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.client; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.yahoo.vespa.athenz.api.AthenzService; +import com.yahoo.vespa.athenz.identity.ServiceIdentityProvider; +import com.yahoo.vespa.athenz.identityprovider.api.IdentityDocument; +import com.yahoo.vespa.athenz.identityprovider.api.IdentityDocumentClient; +import com.yahoo.vespa.athenz.identityprovider.api.SignedIdentityDocument; +import com.yahoo.vespa.athenz.identityprovider.api.VespaUniqueInstanceId; +import com.yahoo.vespa.athenz.utils.AthenzIdentities; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpUriRequest; +import org.apache.http.client.methods.RequestBuilder; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.DefaultHttpRequestRetryHandler; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.util.EntityUtils; +import org.eclipse.jetty.http.HttpStatus; + +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.SSLContext; +import java.io.IOException; +import java.io.UncheckedIOException; +import java.net.URI; +import java.util.function.Supplier; + +/** + * Default implementation of {@link IdentityDocumentClient} + * + * @author bjorncs + */ +public class DefaultIdentityDocumentClient implements IdentityDocumentClient { + + private static final String IDENTITY_DOCUMENT_API = "/athenz/v1/provider/identity-document/"; + private static final ObjectMapper objectMapper = new ObjectMapper(); + + private final Supplier<SSLContext> sslContextSupplier; + private final HostnameVerifier hostnameVerifier; + private final URI configserverUri; + + public DefaultIdentityDocumentClient(URI configserverUri, + SSLContext sslContext, + HostnameVerifier hostnameVerifier) { + this.configserverUri = configserverUri; + this.sslContextSupplier = () -> sslContext; + this.hostnameVerifier = hostnameVerifier; + } + + public DefaultIdentityDocumentClient(URI configserverUri, + ServiceIdentityProvider identityProvider, + HostnameVerifier hostnameVerifier) { + this.configserverUri = configserverUri; + this.sslContextSupplier = identityProvider::getIdentitySslContext; + this.hostnameVerifier = hostnameVerifier; + } + + @Override + public SignedIdentityDocument getNodeIdentityDocument(String host) { + return getIdentityDocument(host, "node"); + } + + @Override + public SignedIdentityDocument getTenantIdentityDocument(String host) { + return getIdentityDocument(host, "tenant"); + } + + private SignedIdentityDocument getIdentityDocument(String host, String type) { + + try (CloseableHttpClient client = createHttpClient(sslContextSupplier.get(), hostnameVerifier)) { + URI uri = configserverUri + .resolve(IDENTITY_DOCUMENT_API) + .resolve(type + '/') + .resolve(host); + HttpUriRequest request = RequestBuilder.get() + .setUri(uri) + .addHeader("Connection", "close") + .addHeader("Accept", "application/json") + .build(); + try (CloseableHttpResponse response = client.execute(request)) { + String responseContent = EntityUtils.toString(response.getEntity()); + if (HttpStatus.isSuccess(response.getStatusLine().getStatusCode())) { + com.yahoo.vespa.athenz.identityprovider.api.bindings.SignedIdentityDocument entity = + objectMapper.readValue( + responseContent, + com.yahoo.vespa.athenz.identityprovider.api.bindings.SignedIdentityDocument.class); + return new SignedIdentityDocument( + toEntityDocument(entity.identityDocument), + entity.signature, + entity.signingKeyVersion, + VespaUniqueInstanceId.fromDottedString(entity.providerUniqueId), + entity.dnsSuffix, + (AthenzService) AthenzIdentities.from(entity.providerService), + entity.ztsEndpoint, + entity.documentVersion); + } else { + throw new RuntimeException( + String.format( + "Failed to retrieve identity document for host %s: %d - %s", + host, + response.getStatusLine().getStatusCode(), + responseContent)); + } + } + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + private static IdentityDocument toEntityDocument( + com.yahoo.vespa.athenz.identityprovider.api.bindings.IdentityDocument identityDocument) { + return new IdentityDocument( + identityDocument.providerUniqueId.toVespaUniqueInstanceId(), + identityDocument.configServerHostname, + identityDocument.instanceHostname, + identityDocument.createdAt, + identityDocument.ipAddresses); + } + + private static CloseableHttpClient createHttpClient(SSLContext sslContext, + HostnameVerifier hostnameVerifier) { + return HttpClientBuilder.create() + .setRetryHandler(new DefaultHttpRequestRetryHandler(3, /*requestSentRetryEnabled*/true)) + .setSSLContext(sslContext) + .setSSLHostnameVerifier(hostnameVerifier) + .setUserAgent("default-identity-document-client") + .build(); + } + +} |