From 31fe461ac86e92fdff41bb17f0abc9b2a132676c Mon Sep 17 00:00:00 2001 From: sai-sunder-s <4540365+sai-sunder-s@users.noreply.github.com> Date: Wed, 9 Nov 2022 19:07:13 +0000 Subject: [PATCH] fix: Validate url domain for aws metadata urls (#1079) * fix: Validate url domain for aws metadata urls * fix external account tests * static method and split tests * rename param: --- .../google/auth/oauth2/AwsCredentials.java | 25 +++++++++ .../auth/oauth2/AwsCredentialsTest.java | 55 ++++++++++++++++--- .../ExternalAccountCredentialsTest.java | 4 +- ...ckExternalAccountCredentialsTransport.java | 6 +- 4 files changed, 78 insertions(+), 12 deletions(-) diff --git a/oauth2_http/java/com/google/auth/oauth2/AwsCredentials.java b/oauth2_http/java/com/google/auth/oauth2/AwsCredentials.java index 168af3054..34aaa5835 100644 --- a/oauth2_http/java/com/google/auth/oauth2/AwsCredentials.java +++ b/oauth2_http/java/com/google/auth/oauth2/AwsCredentials.java @@ -43,6 +43,8 @@ import com.google.common.annotations.VisibleForTesting; import java.io.IOException; import java.io.UnsupportedEncodingException; +import java.net.MalformedURLException; +import java.net.URL; import java.net.URLEncoder; import java.util.ArrayList; import java.util.Collection; @@ -125,6 +127,29 @@ static class AwsCredentialSource extends CredentialSource { } else { this.imdsv2SessionTokenUrl = null; } + + this.validateMetadataServerUrls(); + } + + private void validateMetadataServerUrls() { + validateMetadataServerUrlIfAny(this.regionUrl, "region_url"); + validateMetadataServerUrlIfAny(this.url, "url"); + validateMetadataServerUrlIfAny(this.imdsv2SessionTokenUrl, "imdsv2_session_token_url"); + } + + private static void validateMetadataServerUrlIfAny(String urlString, String nameInConfig) { + if (urlString != null) { + try { + URL url = new URL(urlString); + String host = url.getHost(); + if (!host.equals("169.254.169.254") && !host.equals("[fd00:ec2::254]")) { + throw new IllegalArgumentException( + String.format("Invalid host %s for %s.", host, nameInConfig)); + } + } catch (MalformedURLException malformedURLException) { + throw new IllegalArgumentException(malformedURLException); + } + } } } diff --git a/oauth2_http/javatests/com/google/auth/oauth2/AwsCredentialsTest.java b/oauth2_http/javatests/com/google/auth/oauth2/AwsCredentialsTest.java index 9b67a09bb..9c7cb3fa7 100644 --- a/oauth2_http/javatests/com/google/auth/oauth2/AwsCredentialsTest.java +++ b/oauth2_http/javatests/com/google/auth/oauth2/AwsCredentialsTest.java @@ -34,6 +34,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -53,6 +54,7 @@ import java.util.List; import java.util.Map; import org.junit.Test; +import org.junit.function.ThrowingRunnable; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -61,11 +63,10 @@ public class AwsCredentialsTest { private static final String STS_URL = "https://sts.googleapis.com"; - private static final String AWS_CREDENTIALS_URL = "https://www.aws-credentials.com"; - private static final String AWS_CREDENTIALS_URL_WITH_ROLE = - "https://www.aws-credentials.com/roleName"; - private static final String AWS_REGION_URL = "https://www.aws-region.com"; - private static final String AWS_IMDSV2_SESSION_TOKEN_URL = "https://www.aws-session-token.com"; + private static final String AWS_CREDENTIALS_URL = "https://169.254.169.254"; + private static final String AWS_CREDENTIALS_URL_WITH_ROLE = "https://169.254.169.254/roleName"; + private static final String AWS_REGION_URL = "https://169.254.169.254/region"; + private static final String AWS_IMDSV2_SESSION_TOKEN_URL = "https://169.254.169.254/imdsv2"; private static final String AWS_IMDSV2_SESSION_TOKEN = "sessiontoken"; private static final String GET_CALLER_IDENTITY_URL = @@ -78,8 +79,8 @@ public class AwsCredentialsTest { new HashMap() { { put("environment_id", "aws1"); - put("region_url", "regionUrl"); - put("url", "url"); + put("region_url", AWS_REGION_URL); + put("url", AWS_CREDENTIALS_URL); put("regional_cred_verification_url", "regionalCredVerificationUrl"); } }; @@ -101,6 +102,32 @@ public class AwsCredentialsTest { .setCredentialSource(AWS_CREDENTIAL_SOURCE) .build(); + @Test + public void test_awsCredentialSource_ipv6() { + // If no exception is thrown, it means the urls were valid. + new AwsCredentialSource(buildAwsIpv6CredentialSourceMap()); + } + + @Test + public void test_awsCredentialSource_invalid_urls() { + String keys[] = {"region_url", "url", "imdsv2_session_token_url"}; + for (String key : keys) { + Map credentialSourceWithInvalidUrl = buildAwsIpv6CredentialSourceMap(); + credentialSourceWithInvalidUrl.put(key, "https://badhost.com/fake"); + IllegalArgumentException e = + assertThrows( + IllegalArgumentException.class, + new ThrowingRunnable() { + @Override + public void run() throws Throwable { + new AwsCredentialSource(credentialSourceWithInvalidUrl); + } + }); + + assertEquals(String.format("Invalid host badhost.com for %s.", key), e.getMessage()); + } + } + @Test public void refreshAccessToken_withoutServiceAccountImpersonation() throws IOException { MockExternalAccountCredentialsTransportFactory transportFactory = @@ -734,6 +761,20 @@ private static AwsCredentialSource buildAwsCredentialSource( return new AwsCredentialSource(credentialSourceMap); } + private static Map buildAwsIpv6CredentialSourceMap() { + String regionUrl = "http://[fd00:ec2::254]/region"; + String url = "http://[fd00:ec2::254]"; + String imdsv2SessionTokenUrl = "http://[fd00:ec2::254]/imdsv2"; + Map credentialSourceMap = new HashMap<>(); + credentialSourceMap.put("environment_id", "aws1"); + credentialSourceMap.put("region_url", regionUrl); + credentialSourceMap.put("url", url); + credentialSourceMap.put("imdsv2_session_token_url", imdsv2SessionTokenUrl); + credentialSourceMap.put("regional_cred_verification_url", GET_CALLER_IDENTITY_URL); + + return credentialSourceMap; + } + static InputStream writeAwsCredentialsStream(String stsUrl, String regionUrl, String metadataUrl) throws IOException { GenericJson json = new GenericJson(); diff --git a/oauth2_http/javatests/com/google/auth/oauth2/ExternalAccountCredentialsTest.java b/oauth2_http/javatests/com/google/auth/oauth2/ExternalAccountCredentialsTest.java index 4fc59596c..d8f5b30e4 100644 --- a/oauth2_http/javatests/com/google/auth/oauth2/ExternalAccountCredentialsTest.java +++ b/oauth2_http/javatests/com/google/auth/oauth2/ExternalAccountCredentialsTest.java @@ -1117,8 +1117,8 @@ private GenericJson buildJsonAwsCredential() { Map map = new HashMap<>(); map.put("environment_id", "aws1"); - map.put("region_url", "regionUrl"); - map.put("url", "url"); + map.put("region_url", "https://169.254.169.254/region"); + map.put("url", "https://169.254.169.254/"); map.put("regional_cred_verification_url", "regionalCredVerificationUrl"); json.put("credential_source", map); diff --git a/oauth2_http/javatests/com/google/auth/oauth2/MockExternalAccountCredentialsTransport.java b/oauth2_http/javatests/com/google/auth/oauth2/MockExternalAccountCredentialsTransport.java index 96400dfe8..16c82c43b 100644 --- a/oauth2_http/javatests/com/google/auth/oauth2/MockExternalAccountCredentialsTransport.java +++ b/oauth2_http/javatests/com/google/auth/oauth2/MockExternalAccountCredentialsTransport.java @@ -65,9 +65,9 @@ public class MockExternalAccountCredentialsTransport extends MockHttpTransport { private static final String CLOUD_PLATFORM_SCOPE = "https://www.googleapis.com/auth/cloud-platform"; private static final String ISSUED_TOKEN_TYPE = "urn:ietf:params:oauth:token-type:access_token"; - private static final String AWS_CREDENTIALS_URL = "https://www.aws-credentials.com"; - private static final String AWS_REGION_URL = "https://www.aws-region.com"; - private static final String AWS_IMDSV2_SESSION_TOKEN_URL = "https://www.aws-session-token.com"; + private static final String AWS_CREDENTIALS_URL = "https://169.254.169.254"; + private static final String AWS_REGION_URL = "https://169.254.169.254/region"; + private static final String AWS_IMDSV2_SESSION_TOKEN_URL = "https://169.254.169.254/imdsv2"; private static final String METADATA_SERVER_URL = "https://www.metadata.google.com"; private static final String STS_URL = "https://sts.googleapis.com";