Skip to content

Commit

Permalink
fix: Validate url domain for aws metadata urls (#1079)
Browse files Browse the repository at this point in the history
* fix: Validate url domain for aws metadata urls

* fix external account tests

* static method and split tests

* rename param:
  • Loading branch information
sai-sunder-s authored Nov 9, 2022
1 parent eafb051 commit 31fe461
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 12 deletions.
25 changes: 25 additions & 0 deletions oauth2_http/java/com/google/auth/oauth2/AwsCredentials.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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;

Expand All @@ -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 =
Expand All @@ -78,8 +79,8 @@ public class AwsCredentialsTest {
new HashMap<String, Object>() {
{
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");
}
};
Expand All @@ -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<String, Object> 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 =
Expand Down Expand Up @@ -734,6 +761,20 @@ private static AwsCredentialSource buildAwsCredentialSource(
return new AwsCredentialSource(credentialSourceMap);
}

private static Map<String, Object> buildAwsIpv6CredentialSourceMap() {
String regionUrl = "http://[fd00:ec2::254]/region";
String url = "http://[fd00:ec2::254]";
String imdsv2SessionTokenUrl = "http://[fd00:ec2::254]/imdsv2";
Map<String, Object> 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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1117,8 +1117,8 @@ private GenericJson buildJsonAwsCredential() {

Map<String, String> 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);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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";

Expand Down

0 comments on commit 31fe461

Please sign in to comment.