aboutsummaryrefslogtreecommitdiffstats
path: root/vespa-athenz
diff options
context:
space:
mode:
Diffstat (limited to 'vespa-athenz')
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/api/AthenzAccessToken.java1
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/DefaultZtsClient.java31
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/ZtsClient.java17
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/bindings/AccessTokenResponseEntity.java49
-rw-r--r--vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/client/AthenzIdentityProviderImpl.java27
5 files changed, 125 insertions, 0 deletions
diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/api/AthenzAccessToken.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/api/AthenzAccessToken.java
index ec8c1f3f9f3..49b10a37329 100644
--- a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/api/AthenzAccessToken.java
+++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/api/AthenzAccessToken.java
@@ -32,6 +32,7 @@ public class AthenzAccessToken {
}
public String value() { return value; }
+ public String valueWithBearerPrefix() { return BEARER_TOKEN_PREFIX + value; }
@Override public String toString() { return "AthenzAccessToken{value='" + value + "'}"; }
diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/DefaultZtsClient.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/DefaultZtsClient.java
index eec578ddc26..c05213c8008 100644
--- a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/DefaultZtsClient.java
+++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/DefaultZtsClient.java
@@ -2,14 +2,17 @@
package com.yahoo.vespa.athenz.client.zts;
import com.yahoo.security.Pkcs10Csr;
+import com.yahoo.vespa.athenz.api.AthenzAccessToken;
import com.yahoo.vespa.athenz.api.AthenzDomain;
import com.yahoo.vespa.athenz.api.AthenzIdentity;
+import com.yahoo.vespa.athenz.api.AthenzResourceName;
import com.yahoo.vespa.athenz.api.AthenzRole;
import com.yahoo.vespa.athenz.api.AwsRole;
import com.yahoo.vespa.athenz.api.AwsTemporaryCredentials;
import com.yahoo.vespa.athenz.api.NToken;
import com.yahoo.vespa.athenz.api.ZToken;
import com.yahoo.vespa.athenz.client.common.ClientBase;
+import com.yahoo.vespa.athenz.client.zts.bindings.AccessTokenResponseEntity;
import com.yahoo.vespa.athenz.client.zts.bindings.AwsTemporaryCredentialsResponseEntity;
import com.yahoo.vespa.athenz.client.zts.bindings.IdentityRefreshRequestEntity;
import com.yahoo.vespa.athenz.client.zts.bindings.IdentityResponseEntity;
@@ -36,6 +39,7 @@ import java.time.Duration;
import java.util.List;
import java.util.Optional;
import java.util.function.Supplier;
+import java.util.stream.Collectors;
import static java.util.stream.Collectors.toList;
@@ -147,6 +151,33 @@ public class DefaultZtsClient extends ClientBase implements ZtsClient {
}
@Override
+ public AthenzAccessToken getAccessToken(AthenzDomain domain) {
+ return this.getAccessTokenImpl(List.of(new AthenzResourceName(domain, "domain")));
+ }
+
+ @Override
+ public AthenzAccessToken getAccessToken(List<AthenzRole> athenzRole) {
+ List<AthenzResourceName> athenzResourceNames = athenzRole.stream()
+ .map(AthenzRole::toResourceName)
+ .collect(toList());
+ return this.getAccessTokenImpl(athenzResourceNames);
+ }
+
+ private AthenzAccessToken getAccessTokenImpl(List<AthenzResourceName> resources) {
+ URI uri = ztsUrl.resolve("oauth2/token");
+ RequestBuilder requestBuilder = RequestBuilder.post(uri)
+ .addHeader("Content-Type", "application/x-www-form-urlencoded")
+ .addParameter("grant_type", "client_credentials")
+ .addParameter("scope", resources.stream().map(AthenzResourceName::toResourceNameString).collect(Collectors.joining(" ")));
+
+ HttpUriRequest request = requestBuilder.build();
+ return execute(request, response -> {
+ AccessTokenResponseEntity accessTokenResponseEntity = readEntity(response, AccessTokenResponseEntity.class);
+ return accessTokenResponseEntity.accessToken();
+ });
+ }
+
+ @Override
public X509Certificate getRoleCertificate(AthenzRole role, Pkcs10Csr csr, Duration expiry) {
RoleCertificateRequestEntity requestEntity = new RoleCertificateRequestEntity(csr, expiry);
URI uri = ztsUrl.resolve(String.format("domain/%s/role/%s/token", role.domain().getName(), role.roleName()));
diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/ZtsClient.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/ZtsClient.java
index c09ad8f48a0..baeb4271905 100644
--- a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/ZtsClient.java
+++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/ZtsClient.java
@@ -2,6 +2,7 @@
package com.yahoo.vespa.athenz.client.zts;
import com.yahoo.security.Pkcs10Csr;
+import com.yahoo.vespa.athenz.api.AthenzAccessToken;
import com.yahoo.vespa.athenz.api.AthenzDomain;
import com.yahoo.vespa.athenz.api.AthenzIdentity;
import com.yahoo.vespa.athenz.api.AthenzRole;
@@ -78,6 +79,22 @@ public interface ZtsClient extends AutoCloseable {
ZToken getRoleToken(AthenzRole athenzRole);
/**
+ * Fetch an access token for the target domain
+ *
+ * @param domain Target domain
+ * @return An Athenz access token
+ */
+ AthenzAccessToken getAccessToken(AthenzDomain domain);
+
+ /**
+ * Fetch an access token for the target roles
+ *
+ * @param athenzRole List of athenz roles to get access token for
+ * @return An Athenz access token
+ */
+ AthenzAccessToken getAccessToken(List<AthenzRole> athenzRole);
+
+ /**
* Fetch role certificate for the target domain and role
*
* @param role Target role
diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/bindings/AccessTokenResponseEntity.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/bindings/AccessTokenResponseEntity.java
new file mode 100644
index 00000000000..edd423b52bd
--- /dev/null
+++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/client/zts/bindings/AccessTokenResponseEntity.java
@@ -0,0 +1,49 @@
+// Copyright 2020 Oath Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.vespa.athenz.client.zts.bindings;
+
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.yahoo.vespa.athenz.api.AthenzAccessToken;
+import com.yahoo.vespa.athenz.api.AthenzResourceName;
+import com.yahoo.vespa.athenz.api.AthenzRole;
+
+import java.time.Instant;
+import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+/**
+ * @author mortent
+ */
+@JsonIgnoreProperties(ignoreUnknown = true)
+public class AccessTokenResponseEntity {
+ private final AthenzAccessToken accessToken;
+ private final Instant expiryTime;
+ private final List<AthenzRole> roles;
+
+ public AccessTokenResponseEntity(
+ @JsonProperty("access_token") String accessToken,
+ @JsonProperty("expires_in") int expiresIn,
+ @JsonProperty("scope") String roles) {
+
+ this.accessToken = new AthenzAccessToken(accessToken);
+ // We do not know from when, so best we can do is assume now ...
+ this.expiryTime = Instant.now().plusSeconds(expiresIn);
+ this.roles = Stream.of(roles.split(" "))
+ .map(AthenzResourceName::fromString)
+ .map(AthenzRole::fromResourceName)
+ .collect(Collectors.toList());
+ }
+
+ public AthenzAccessToken accessToken() {
+ return accessToken;
+ }
+
+ public Instant expiryTime() {
+ return expiryTime;
+ }
+
+ public List<AthenzRole> roles() {
+ return roles;
+ }
+}
diff --git a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/client/AthenzIdentityProviderImpl.java b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/client/AthenzIdentityProviderImpl.java
index bea9af458b4..5d6f0e3ce16 100644
--- a/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/client/AthenzIdentityProviderImpl.java
+++ b/vespa-athenz/src/main/java/com/yahoo/vespa/athenz/identityprovider/client/AthenzIdentityProviderImpl.java
@@ -16,6 +16,7 @@ import com.yahoo.security.KeyStoreType;
import com.yahoo.security.Pkcs10Csr;
import com.yahoo.security.SslContextBuilder;
import com.yahoo.security.tls.MutableX509KeyManager;
+import com.yahoo.vespa.athenz.api.AthenzAccessToken;
import com.yahoo.vespa.athenz.api.AthenzDomain;
import com.yahoo.vespa.athenz.api.AthenzRole;
import com.yahoo.vespa.athenz.api.AthenzService;
@@ -84,6 +85,8 @@ public final class AthenzIdentityProviderImpl extends AbstractComponent implemen
private final LoadingCache<AthenzRole, SSLContext> roleSslContextCache;
private final LoadingCache<AthenzRole, ZToken> roleSpecificRoleTokenCache;
private final LoadingCache<AthenzDomain, ZToken> domainSpecificRoleTokenCache;
+ private final LoadingCache<AthenzDomain, AthenzAccessToken> domainSpecificAccessTokenCache;
+ private final LoadingCache<List<AthenzRole>, AthenzAccessToken> roleSpecificAccessTokenCache;
private final CsrGenerator csrGenerator;
@Inject
@@ -116,6 +119,8 @@ public final class AthenzIdentityProviderImpl extends AbstractComponent implemen
roleSslContextCache = createCache(ROLE_SSL_CONTEXT_EXPIRY, this::createRoleSslContext);
roleSpecificRoleTokenCache = createCache(ROLE_TOKEN_EXPIRY, this::createRoleToken);
domainSpecificRoleTokenCache = createCache(ROLE_TOKEN_EXPIRY, this::createRoleToken);
+ domainSpecificAccessTokenCache = createCache(ROLE_TOKEN_EXPIRY, this::createAccessToken);
+ roleSpecificAccessTokenCache = createCache(ROLE_TOKEN_EXPIRY, this::createAccessToken);
this.csrGenerator = new CsrGenerator(config.athenzDnsSuffix(), config.configserverIdentityName());
this.identitySslContext = createIdentitySslContext(identityKeyManager, trustStore);
registerInstance();
@@ -199,6 +204,16 @@ public final class AthenzIdentityProviderImpl extends AbstractComponent implemen
}
@Override
+ public String getAccessToken(String domain) {
+ return null;
+ }
+
+ @Override
+ public String getAccessToken(String domain, List<String> roles) {
+ return null;
+ }
+
+ @Override
public PrivateKey getPrivateKey() {
return credentials.getKeyPair().getPrivate();
}
@@ -240,6 +255,18 @@ public final class AthenzIdentityProviderImpl extends AbstractComponent implemen
}
}
+ private AthenzAccessToken createAccessToken(AthenzDomain domain) {
+ try (ZtsClient client = createZtsClient()) {
+ return client.getAccessToken(domain);
+ }
+ }
+
+ private AthenzAccessToken createAccessToken(List<AthenzRole> roles) {
+ try (ZtsClient client = createZtsClient()) {
+ return client.getAccessToken(roles);
+ }
+ }
+
private DefaultZtsClient createZtsClient() {
return new DefaultZtsClient(ztsEndpoint, getIdentitySslContext());
}