diff --git a/clients/java/zts/examples/tls-support/pom.xml b/clients/java/zts/examples/tls-support/pom.xml
index be80ea1669e..f8c06848921 100644
--- a/clients/java/zts/examples/tls-support/pom.xml
+++ b/clients/java/zts/examples/tls-support/pom.xml
@@ -27,7 +27,7 @@
UTF-8
UTF-8
- 1.7.33
+ 1.7.35
diff --git a/clients/java/zts/examples/tls-support/src/main/java/com/yahoo/athenz/example/zts/tls/client/ZTSAWSCredsClient.java b/clients/java/zts/examples/tls-support/src/main/java/com/yahoo/athenz/example/zts/tls/client/ZTSAWSCredsClient.java
index a5f909a3028..3a9872e78b0 100644
--- a/clients/java/zts/examples/tls-support/src/main/java/com/yahoo/athenz/example/zts/tls/client/ZTSAWSCredsClient.java
+++ b/clients/java/zts/examples/tls-support/src/main/java/com/yahoo/athenz/example/zts/tls/client/ZTSAWSCredsClient.java
@@ -29,6 +29,7 @@
import com.yahoo.athenz.zts.PublicKeyEntry;
import com.yahoo.athenz.zts.ZTSClient;
+import com.yahoo.athenz.zts.AWSCredentialsProviderImpl;
import com.yahoo.athenz.zts.ZTSClientException;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.AWSCredentialsProvider;
@@ -66,19 +67,24 @@ public static void main(String[] args) {
SSLContext sslContext = Utils.buildSSLContext(keyRefresher.getKeyManagerProxy(),
keyRefresher.getTrustManagerProxy());
- // we must not close this client as long as we're using the
- // AWS credentials provider since it needs this client to
- // refresh the certs when required
+ // obtain temporary credential provider for our domain and role
- ZTSClient ztsClient = new ZTSClient(ztsUrl, sslContext);
+ AWSCredentialsProviderImpl awsCredProvider = new AWSCredentialsProviderImpl(ztsUrl,
+ sslContext, domainName, roleName);
- // retrieve and display aws temporary creds
+ // retrieve and display aws temporary creds. Typically you just pass
+ // the AWSCredentialsProvider object to any AWS api that requires it.
+ // for example, when creating an AWS S3 client
+ // AmazonS3 s3client = AmazonS3ClientBuilder.standard()
+ // .withCredentials(awsCredProvider).withClientConfiguration(cltConf)
+ // .withRegion(getRegion()).build();
+
+ retrieveAWSTempCreds(awsCredProvider);
- retrieveAWSTempCreds(ztsClient, domainName, roleName);
-
- // we're done with our provider so we can close our client
+ // once we're done with our api and we no longer need our
+ // provider we need to make sure to close it
- ztsClient.close();
+ awsCredProvider.close();
} catch (Exception ex) {
System.out.println("Exception: " + ex.getMessage());
@@ -87,19 +93,28 @@ public static void main(String[] args) {
}
}
- private static boolean retrieveAWSTempCreds(ZTSClient ztsClient, final String domainName,
- final String roleName) {
+ private static boolean retrieveAWSTempCreds(AWSCredentialsProvider awsCredProvider) {
try {
- AWSCredentialsProvider awsCredProvider = ztsClient.getAWSCredentialProvider(domainName, roleName);
- AWSCredentials awsCreds = awsCredProvider.getCredentials();
- if (awsCreds == null) {
- System.out.println("Error: AWS Credentials are not available");
- return false;
+ // just for testing purposes we're going to run this code
+ // for 2 hours and keep asking for credentials every minute
+ // to make sure zts client is caching the creds and giving
+ // us new ones when they're about to expire
+
+ for (int i = 0; i < 120; i++) {
+ AWSCredentials awsCreds = awsCredProvider.getCredentials();
+ if (awsCreds == null) {
+ System.out.println("Error: AWS Credentials are not available");
+ return false;
+ }
+ System.out.println("AWS Temporary Credentials:\n");
+ System.out.println("\tAccess Key Id : " + awsCreds.getAWSAccessKeyId());
+ System.out.println("\tSecret Key : " + awsCreds.getAWSSecretKey());
+ try {
+ Thread.sleep(60000);
+ } catch (InterruptedException ex) {
+ }
}
- System.out.println("AWS Temporary Credentials:\n");
- System.out.println("\tAccess Key Id : " + awsCreds.getAWSAccessKeyId());
- System.out.println("\tSecret Key : " + awsCreds.getAWSSecretKey());
} catch (ZTSClientException ex) {
System.out.println("Unable to retrieve AWS credentials: " + ex.getMessage());
return false;
diff --git a/clients/java/zts/src/main/java/com/yahoo/athenz/zts/AWSCredentialsProviderImpl.java b/clients/java/zts/src/main/java/com/yahoo/athenz/zts/AWSCredentialsProviderImpl.java
index 2deab522a18..fb9fbccc2ce 100644
--- a/clients/java/zts/src/main/java/com/yahoo/athenz/zts/AWSCredentialsProviderImpl.java
+++ b/clients/java/zts/src/main/java/com/yahoo/athenz/zts/AWSCredentialsProviderImpl.java
@@ -1,50 +1,107 @@
+/**
+ * Copyright 2017 Yahoo Holdings Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package com.yahoo.athenz.zts;
+import java.io.Closeable;
+import java.io.IOException;
+import javax.net.ssl.SSLContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.AWSCredentialsProvider;
import com.amazonaws.auth.BasicSessionCredentials;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-public class AWSCredentialsProviderImpl implements AWSCredentialsProvider {
+public class AWSCredentialsProviderImpl implements AWSCredentialsProvider, Closeable {
+
private static final Logger LOG = LoggerFactory.getLogger(AWSCredentialsProviderImpl.class);
- private static String athensSvcDomain = "";
- private static String athensDomRole = "";
+
+ private String domainName;
+ private String roleName;
+ private ZTSClient ztsClient;
private volatile AWSCredentials credentials;
- private ZTSClient ztsClt;
-
+ private boolean closeZTSClient;
+
+ public AWSCredentialsProviderImpl(ZTSClient ztsClient, String domainName, String roleName) {
+ this.ztsClient = ztsClient;
+ this.domainName = domainName;
+ this.roleName = roleName;
+ this.closeZTSClient = false;
+ }
- public AWSCredentialsProviderImpl(ZTSClient ztsClt, String athensSvcDomain, String athensDomRole) {
- this.ztsClt = ztsClt;
- this.athensDomRole = athensDomRole;
- this.athensSvcDomain = athensSvcDomain;
+ /**
+ * Constructs a new AWSCredentialsProvider object with the given SSLContext object,
+ * ZTS Server Url, Athenz domain name and AWS Role Name to retrieve temporary
+ * credentials for. The constructor will automatically create and use the ZTS
+ * client object for retrieving credentials. This object must be closed so
+ * the ZTS client object is closed as well.
+ * @param ztsUrl ZTS Server's URL
+ * @param sslContext SSLContext that includes service's private key and x.509 certificate
+ * for authenticating requests
+ * @param domainName name of the domain
+ * @param roleName is the name of the role
+ */
+ public AWSCredentialsProviderImpl(String ztsUrl, SSLContext sslContext,
+ String domainName, String roleName) {
+ this.domainName = domainName;
+ this.roleName = roleName;
+ this.ztsClient = new ZTSClient(ztsUrl, sslContext);
+ this.closeZTSClient = true;
}
+ @Override
+ public void close() throws IOException {
+ if (closeZTSClient) {
+ ztsClient.close();
+ }
+ }
+
@Override
public AWSCredentials getCredentials() {
- this.refresh();
- return this.credentials;
+
+ // we are going to first refresh our credentials object.
+ // for initial request this will fetch the credentials
+ // while for others it will check if it exists in the cache
+ // and only fetch if it's about to expire
+
+ refresh();
+ return credentials;
}
@Override
public void refresh() {
try {
- AWSTemporaryCredentials creds = ztsClt.getAWSTemporaryCredentials(athensSvcDomain, athensDomRole);
+ AWSTemporaryCredentials creds = ztsClient.getAWSTemporaryCredentials(domainName, roleName);
if (LOG.isDebugEnabled()) {
- LOG.debug("AWSCredentialsProviderImpl:refresh: Credentials with id: \"" + creds.accessKeyId + "\" were fetched");
+ LOG.debug("Refresh: Credentials with id: {} and expiration {} were fetched",
+ creds.getAccessKeyId(), creds.getExpiration());
}
this.credentials = new BasicSessionCredentials(
creds.getAccessKeyId(),
creds.getSecretAccessKey(),
creds.getSessionToken());
- } catch (ZTSClientException exp) {
- this.credentials = null;
- LOG.error("AWSCredentialsProviderImpl:refresh: Failed to get the AWS temporary credentials from ZTS. Status: " + exp.getCode() + "Error" + exp.getData());
- } catch (Exception exp) {
- this.credentials = null;
- LOG.error("AWSCredentialsProviderImpl:refresh: Failed to refresh credentials . Error: " + exp.getMessage());
+
+ } catch (ZTSClientException ex) {
+ credentials = null;
+ LOG.error("Refresh: Failed to get the AWS temporary credentials from ZTS: {}",
+ ex.getMessage());
+ } catch (Exception ex) {
+ credentials = null;
+ LOG.error("Refresh: Failed to refresh credentials: {}", ex.getMessage());
}
}
}
diff --git a/clients/java/zts/src/main/java/com/yahoo/athenz/zts/ZTSClient.java b/clients/java/zts/src/main/java/com/yahoo/athenz/zts/ZTSClient.java
index 03e3853ff4c..30f9aae0138 100644
--- a/clients/java/zts/src/main/java/com/yahoo/athenz/zts/ZTSClient.java
+++ b/clients/java/zts/src/main/java/com/yahoo/athenz/zts/ZTSClient.java
@@ -78,6 +78,7 @@ public class ZTSClient implements Closeable {
private String service = null;
protected ZTSRDLGeneratedClient ztsClient;
protected ServiceIdentityProvider siaProvider = null;
+ private SSLContext sslContext = null;
// configurable fields
//
@@ -185,7 +186,7 @@ static boolean initConfigValues() {
* milliseconds.
*/
public ZTSClient() {
- initClient(null, null, null, null, null, null);
+ initClient(null, null, null, null, null);
enablePrefetch = false; // can't use this domain and service for prefetch
}
@@ -204,7 +205,7 @@ public ZTSClient() {
* @param ztsUrl ZTS Server's URL (optional)
*/
public ZTSClient(String ztsUrl) {
- initClient(ztsUrl, null, null, null, null, null);
+ initClient(ztsUrl, null, null, null, null);
enablePrefetch = false; // can't use this domain and service for prefetch
}
@@ -240,7 +241,7 @@ public ZTSClient(String ztsUrl, Principal identity) {
if (identity.getAuthority() == null) {
throw new IllegalArgumentException("Principal Authority cannot be null");
}
- initClient(ztsUrl, identity, null, null, null, null);
+ initClient(ztsUrl, identity, null, null, null);
enablePrefetch = false; // can't use this domain and service for prefetch
}
@@ -261,7 +262,8 @@ public ZTSClient(String ztsUrl, SSLContext sslContext) {
if (sslContext == null) {
throw new IllegalArgumentException("SSLContext object must be specified");
}
- initClient(ztsUrl, null, null, null, null, sslContext);
+ this.sslContext = sslContext;
+ initClient(ztsUrl, null, null, null, null);
}
/**
@@ -305,7 +307,7 @@ public ZTSClient(String ztsUrl, String domainName, String serviceName,
if (siaProvider == null) {
throw new IllegalArgumentException("Service Identity Provider must be specified");
}
- initClient(ztsUrl, null, domainName, serviceName, siaProvider, null);
+ initClient(ztsUrl, null, domainName, serviceName, siaProvider);
}
/**
@@ -456,7 +458,7 @@ static PrivateKeyStore loadServicePrivateKey() {
}
void initClient(String url, Principal identity, String domainName, String serviceName,
- ServiceIdentityProvider siaProvider, SSLContext sslContext) {
+ ServiceIdentityProvider siaProvider) {
if (url == null) {
ztsUrl = lookupZTSUrl();
@@ -1197,7 +1199,16 @@ boolean prefetchToken(String domainName, String roleName, Integer minExpiryTime,
}
String getRoleTokenCacheKey(String domainName, String roleName, String proxyForPrincipal) {
- return getRoleTokenCacheKey(domain, service, domainName, roleName, proxyForPrincipal);
+
+ // if we don't have a tenant domain specified but we have a ssl context
+ // then we're going to use the hash code for our sslcontext as the
+ // value for our tenant
+
+ String tenantDomain = domain;
+ if (domain == null && sslContext != null) {
+ tenantDomain = sslContext.toString();
+ }
+ return getRoleTokenCacheKey(tenantDomain, service, domainName, roleName, proxyForPrincipal);
}
static String getRoleTokenCacheKey(String tenantDomain, String tenantService, String domainName,