diff --git a/build.gradle b/build.gradle index 2f90b26..4f50863 100644 --- a/build.gradle +++ b/build.gradle @@ -24,8 +24,8 @@ apply plugin: 'com.jfrog.bintray' apply plugin: 'maven-publish' apply plugin: "com.github.johnrengelman.shadow" -sourceCompatibility = 1.7 -targetCompatibility = 1.7 +sourceCompatibility = 1.8 +targetCompatibility = 1.8 task copyProjectVersion() { def releaseVersion = version @@ -40,4 +40,4 @@ apply from: file('gradle/check.gradle') apply from: file('gradle/integration.gradle') apply from: file('gradle/bintray.gradle') -group = groupId \ No newline at end of file +group = groupId diff --git a/gradle.properties b/gradle.properties index 3ae4d09..d1138e3 100644 --- a/gradle.properties +++ b/gradle.properties @@ -13,6 +13,6 @@ # See the License for the specific language governing permissions and # limitations under the License. # -version=5.3.1 +version=6.0.0 groupId=com.nike artifactId=cerberus-client diff --git a/src/main/java/com/nike/cerberus/client/auth/CerberusCredentialsProvider.java b/src/main/java/com/nike/cerberus/client/auth/CerberusCredentialsProvider.java index 081b85b..aeaad65 100644 --- a/src/main/java/com/nike/cerberus/client/auth/CerberusCredentialsProvider.java +++ b/src/main/java/com/nike/cerberus/client/auth/CerberusCredentialsProvider.java @@ -16,7 +16,16 @@ package com.nike.cerberus.client.auth; - public interface CerberusCredentialsProvider { + CerberusCredentials getCredentials(); + + /** + * Overrideable method to tell a provider chain if a provider should be ran. + * @return true if the provider should run. + */ + default boolean shouldRun() { + return true; + } + } diff --git a/src/main/java/com/nike/cerberus/client/auth/CerberusCredentialsProviderChain.java b/src/main/java/com/nike/cerberus/client/auth/CerberusCredentialsProviderChain.java index d06ebc2..37b6039 100644 --- a/src/main/java/com/nike/cerberus/client/auth/CerberusCredentialsProviderChain.java +++ b/src/main/java/com/nike/cerberus/client/auth/CerberusCredentialsProviderChain.java @@ -77,6 +77,11 @@ public CerberusCredentials getCredentials() { List logMessages = new ArrayList<>(); for (final CerberusCredentialsProvider credentialsProvider : credentialsProviderList) { + + if (! credentialsProvider.shouldRun()) { + continue; + } + try { final CerberusCredentials credentials = credentialsProvider.getCredentials(); diff --git a/src/main/java/com/nike/cerberus/client/auth/aws/EcsTaskRoleCerberusCredentialsProvider.java b/src/main/java/com/nike/cerberus/client/auth/aws/EcsTaskRoleCerberusCredentialsProvider.java index 0079de2..c3217fc 100644 --- a/src/main/java/com/nike/cerberus/client/auth/aws/EcsTaskRoleCerberusCredentialsProvider.java +++ b/src/main/java/com/nike/cerberus/client/auth/aws/EcsTaskRoleCerberusCredentialsProvider.java @@ -27,6 +27,7 @@ import com.nike.cerberus.client.CerberusClientException; import com.nike.cerberus.client.UrlResolver; import com.nike.cerberus.client.auth.CerberusCredentialsProvider; +import com.nike.cerberus.client.util.EnvironmentUtils; import okhttp3.OkHttpClient; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; @@ -99,6 +100,10 @@ public EcsTaskRoleCerberusCredentialsProvider(UrlResolver urlResolver, String xC super(urlResolver, xCerberusClientOverride); } + public boolean shouldRun() { + return EnvironmentUtils.isRunningInEcs(); + } + /** * Looks up the IAM roles assigned to the task via the ECS task metadata * service. An attempt is made to authenticate and decrypt the Cerberus diff --git a/src/main/java/com/nike/cerberus/client/auth/aws/InstanceRoleCerberusCredentialsProvider.java b/src/main/java/com/nike/cerberus/client/auth/aws/InstanceRoleCerberusCredentialsProvider.java index 4238faf..953d1a1 100644 --- a/src/main/java/com/nike/cerberus/client/auth/aws/InstanceRoleCerberusCredentialsProvider.java +++ b/src/main/java/com/nike/cerberus/client/auth/aws/InstanceRoleCerberusCredentialsProvider.java @@ -24,6 +24,7 @@ import com.nike.cerberus.client.CerberusClientException; import com.nike.cerberus.client.UrlResolver; import com.nike.cerberus.client.auth.CerberusCredentialsProvider; +import com.nike.cerberus.client.util.EnvironmentUtils; import okhttp3.OkHttpClient; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; @@ -88,6 +89,10 @@ public InstanceRoleCerberusCredentialsProvider(UrlResolver urlResolver, String x super(urlResolver, xCerberusClientOverride); } + public boolean shouldRun() { + return EnvironmentUtils.isRunningInEc2(); + } + /** * Looks up the IAM roles assigned to the instance via the EC2 metadata * service. For each role assigned, an attempt is made to authenticate and diff --git a/src/main/java/com/nike/cerberus/client/util/EnvironmentUtils.java b/src/main/java/com/nike/cerberus/client/util/EnvironmentUtils.java new file mode 100644 index 0000000..30545f4 --- /dev/null +++ b/src/main/java/com/nike/cerberus/client/util/EnvironmentUtils.java @@ -0,0 +1,80 @@ +package com.nike.cerberus.client.util; + +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.HashMap; +import java.util.Map; + +import static java.util.concurrent.TimeUnit.MILLISECONDS; + +/** + * Simple Util for determining environment metadata + */ +public class EnvironmentUtils { + + private static final Map canGetSuccessfullyResults = new HashMap<>(); + + private static final Logger LOGGER = LoggerFactory.getLogger(EnvironmentUtils.class); + + /** + * This endpoint is available on EC2 instances + */ + private static final String INSTANCE_IDENTITY_DOCUMENT = "http://169.254.169.254/latest/dynamic/instance-identity/document"; + + /** + * This endpoint is available on ECS Containers + */ + private static final String ECS_METADATA_ENDPOINT = "http://localhost:51678/v1/metadata"; + + private EnvironmentUtils() { + } + + /** + * True if the current system is running in a pure EC2 environment, and not ECS. + */ + public static boolean isRunningInEc2() { + return hasInstanceIdentity() && ! isRunningInEcs(); + } + + /** + * True if the http://169.254.169.254/latest/dynamic/instance-identity/document endpoint + * is available and returns a 2xx status code. True means we are currently running on + * an Ec2 instance. This check should work both on Linux and Windows. + */ + private static boolean hasInstanceIdentity() { + return canGetSuccessfully(INSTANCE_IDENTITY_DOCUMENT); + } + + /** + * + * @return true if this is a container in ECS + */ + public static boolean isRunningInEcs() { + return canGetSuccessfully(ECS_METADATA_ENDPOINT); + } + + static boolean canGetSuccessfully(String url) { + return canGetSuccessfullyResults.computeIfAbsent(url, theUrl -> { + OkHttpClient httpClient = new OkHttpClient.Builder() + .connectTimeout(500, MILLISECONDS) + .readTimeout(500, MILLISECONDS) + .writeTimeout(500, MILLISECONDS) + .build(); + + Request request = new Request.Builder().get().url(theUrl).build(); + + try (Response response = httpClient.newCall(request).execute()) { + if (response.isSuccessful()) { + return true; + } + } catch (Exception e) { + LOGGER.debug("Error when trying to GET {}", theUrl, e); + } + return false; + }); + } +} diff --git a/src/test/java/com/nike/cerberus/client/auth/CerberusCredentialsProviderChainTest.java b/src/test/java/com/nike/cerberus/client/auth/CerberusCredentialsProviderChainTest.java index 23be2dd..5db356e 100644 --- a/src/test/java/com/nike/cerberus/client/auth/CerberusCredentialsProviderChainTest.java +++ b/src/test/java/com/nike/cerberus/client/auth/CerberusCredentialsProviderChainTest.java @@ -26,6 +26,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -47,6 +48,8 @@ public class CerberusCredentialsProviderChainTest { public void setup() { credentialsProviderOne = mock(CerberusCredentialsProvider.class); credentialsProviderTwo = mock(CerberusCredentialsProvider.class); + when(credentialsProviderOne.shouldRun()).thenReturn(true); + when(credentialsProviderTwo.shouldRun()).thenReturn(true); credentialsProviderChain = new CerberusCredentialsProviderChain(credentialsProviderOne, credentialsProviderTwo); } @@ -124,7 +127,7 @@ public void isReuseLastProvider_returns_if_reuse_last_provider_is_enabled() { } @Test - public void list_contstructor_set_provider_list() { + public void list_constructor_set_provider_list() { List list = new LinkedList<>(); list.add(credentialsProviderOne); list.add(credentialsProviderTwo); @@ -168,4 +171,16 @@ public String getToken() { return TOKEN; } } -} \ No newline at end of file + + @Test + public void test_that_if_a_provider_returns_false_for_should_run_it_is_not_ran() { + when(credentialsProviderOne.shouldRun()).thenReturn(false); + when(credentialsProviderTwo.getCredentials()).thenReturn(new TestCerberusCredentials()); + + CerberusCredentials credentials = credentialsProviderChain.getCredentials(); + + assertThat(credentials).isNotNull(); + + verify(credentialsProviderOne, never()).getCredentials(); + } +} diff --git a/src/test/java/com/nike/cerberus/client/util/EnvironmentUtilsTest.java b/src/test/java/com/nike/cerberus/client/util/EnvironmentUtilsTest.java new file mode 100644 index 0000000..40ab555 --- /dev/null +++ b/src/test/java/com/nike/cerberus/client/util/EnvironmentUtilsTest.java @@ -0,0 +1,23 @@ +package com.nike.cerberus.client.util; + +import org.junit.Test; + +import java.util.UUID; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class EnvironmentUtilsTest { + + @Test + public void test_that_canGetSuccessfully_can_get_google_index() { + assertTrue(EnvironmentUtils.canGetSuccessfully("http://www.google.com")); + assertTrue(EnvironmentUtils.canGetSuccessfully("http://www.google.com")); + } + + @Test + public void test_that_canGetSuccessfully_can_not_get_random_http_address() { + assertFalse(EnvironmentUtils.canGetSuccessfully("http://" + UUID.randomUUID().toString() + ".com/" + UUID.randomUUID().toString())); + } + +}