From c96cb4a870c1fdf0490070dcab863990400a602e Mon Sep 17 00:00:00 2001 From: Riya Mehta Date: Fri, 23 Feb 2024 18:15:15 +0000 Subject: [PATCH 01/44] utils. --- .../com/google/auth/oauth2/MtlsConfig.java | 55 ++++++++++ .../java/com/google/auth/oauth2/S2A.java | 101 +++++++++++++++++ .../oauth2/MockMetadataServerTransport.java | 62 +++++++++++ .../google/auth/oauth2/MtlsConfigTest.java | 47 ++++++++ .../com/google/auth/oauth2/S2ATest.java | 102 ++++++++++++++++++ oauth2_http/pom.xml | 5 + 6 files changed, 372 insertions(+) create mode 100644 oauth2_http/java/com/google/auth/oauth2/MtlsConfig.java create mode 100644 oauth2_http/java/com/google/auth/oauth2/S2A.java create mode 100644 oauth2_http/javatests/com/google/auth/oauth2/MtlsConfigTest.java create mode 100644 oauth2_http/javatests/com/google/auth/oauth2/S2ATest.java diff --git a/oauth2_http/java/com/google/auth/oauth2/MtlsConfig.java b/oauth2_http/java/com/google/auth/oauth2/MtlsConfig.java new file mode 100644 index 000000000..18ad6b34d --- /dev/null +++ b/oauth2_http/java/com/google/auth/oauth2/MtlsConfig.java @@ -0,0 +1,55 @@ +package com.google.auth.oauth2; + +import org.joda.time.MutableDateTime; +import javax.annotation.concurrent.NotThreadSafe; + +/** + * Holds an mTLS configuration (consists of address of S2A) retrieved from the Metadata Server. + * + * Instances of {@link MtlsConfig} are not thread safe. Calls to {@code reset}, {@code getS2AAddress}, {@code isValid} + * and {@code getExpiry} should be made from a synchronized block. + */ +@NotThreadSafe +public final class MtlsConfig{ + private String s2aAddress; + private MutableDateTime expiry; + + private static final int MTLS_AUTOCONFIG_EXPIRATION_HOURS = 1; + + public static MtlsConfig createNullMtlsConfig() { + return new MtlsConfig("", null); + } + + public static MtlsConfig createMtlsConfig(String addr) { + MutableDateTime expiry = MutableDateTime.now(); + expiry.addHours(MTLS_AUTOCONFIG_EXPIRATION_HOURS); + return new MtlsConfig(addr, expiry); + } + + public void reset(String addr) { + this.s2aAddress = addr; + this.expiry = MutableDateTime.now(); + this.expiry.addHours(MTLS_AUTOCONFIG_EXPIRATION_HOURS); + } + + public String getS2AAddress() { + return s2aAddress; + } + + public boolean isValid() { + if (expiry == null) { return false; } + if (MutableDateTime.now().isAfter(this.expiry)) { + return false; + } + return true; + } + + public MutableDateTime getExpiry() { + return expiry; + } + + private MtlsConfig(String addr, MutableDateTime expiry) { + this.s2aAddress = addr; + this.expiry = expiry; + } +} diff --git a/oauth2_http/java/com/google/auth/oauth2/S2A.java b/oauth2_http/java/com/google/auth/oauth2/S2A.java new file mode 100644 index 000000000..7bdc3727c --- /dev/null +++ b/oauth2_http/java/com/google/auth/oauth2/S2A.java @@ -0,0 +1,101 @@ +package com.google.auth.oauth2; + +import com.google.api.client.http.HttpRequest; +import com.google.api.client.http.HttpResponse; +import com.google.api.client.http.HttpResponseException; +import com.google.api.client.http.HttpStatusCodes; +import com.google.api.client.http.HttpResponseException; +import com.google.api.client.http.GenericUrl; +import com.google.api.client.util.GenericData; +import com.google.api.client.json.JsonObjectParser; +import com.google.auth.http.HttpTransportFactory; +import com.google.common.collect.Iterables; +import java.io.InputStream; +import java.io.IOException; +import java.util.ServiceLoader; +import java.util.logging.Logger; +import java.util.logging.Level; +import javax.annotation.concurrent.ThreadSafe; + +/** + * Utilities to fetch the S2A (Secure Session Agent) address from the mTLS configuration. + * + * Periodically refresh the mTLS configuration by getting a new one from the MDS mTLS autoconfig endpoint. + */ +@ThreadSafe +public final class S2A { + public static final String DEFAULT_METADATA_SERVER_URL = "http://metadata.google.internal"; + public static final String MTLS_CONFIG_ENDPOINT = "/instance/platform-security/auto-mtls-configuration"; + + private static final String METADATA_FLAVOR = "Metadata-Flavor"; + private static final String GOOGLE = "Google"; + private static final String PARSE_ERROR_S2A = "Error parsing Mtls Auto Config response."; + + private MtlsConfig config; + + private transient HttpTransportFactory transportFactory; + + public S2A() { + config = MtlsConfig.createNullMtlsConfig(); + } + + public void setHttpTransportFactory(HttpTransportFactory tf) { + this.transportFactory = tf; + } + + /** + * Returns the S2A Address from the mTLS config. Refreshes the config if it is expired. + */ + public synchronized String getS2AAddress() { + if (!config.isValid()) { + String addr = getMdsMtlsConfigData(); + config.reset(addr); + } + return config.getS2AAddress(); + } + + /** + * Queries the MDS mTLS Autoconfiguration endpoint and returns the S2A address. Returns an empty address on error. + */ + private String getMdsMtlsConfigData() { + String s2aAddress = ""; + try { + if (transportFactory == null) { + transportFactory = Iterables.getFirst(ServiceLoader.load(HttpTransportFactory.class), OAuth2Utils.HTTP_TRANSPORT_FACTORY); + } + String url = getMdsMtlsEndpoint(DefaultCredentialsProvider.DEFAULT); + GenericUrl genericUrl = new GenericUrl(url); + HttpRequest request = transportFactory.create().createRequestFactory().buildGetRequest(genericUrl); + JsonObjectParser parser = new JsonObjectParser(OAuth2Utils.JSON_FACTORY); + request.setParser(parser); + request.getHeaders().set(METADATA_FLAVOR, GOOGLE); + request.setThrowExceptionOnExecuteError(false); + HttpResponse response = request.execute(); + + if (!response.isSuccessStatusCode()) { + return ""; + } + + InputStream content = response.getContent(); + if (content == null) { + return ""; + } + GenericData responseData = response.parseAs(GenericData.class); + s2aAddress = OAuth2Utils.validateString(responseData, "s2a", PARSE_ERROR_S2A); + } catch(IOException e) { + return ""; + } + return s2aAddress; + } + + /** + * @return MDS mTLS autoconfig endpoint. + */ + private String getMdsMtlsEndpoint(DefaultCredentialsProvider provider) { + String metadataServerAddress = provider.getEnv(DefaultCredentialsProvider.GCE_METADATA_HOST_ENV_VAR); + if (metadataServerAddress != null) { + return "http://" + metadataServerAddress + MTLS_CONFIG_ENDPOINT; + } + return DEFAULT_METADATA_SERVER_URL + MTLS_CONFIG_ENDPOINT; + } +} diff --git a/oauth2_http/javatests/com/google/auth/oauth2/MockMetadataServerTransport.java b/oauth2_http/javatests/com/google/auth/oauth2/MockMetadataServerTransport.java index 66878d4c6..1c78670ff 100644 --- a/oauth2_http/javatests/com/google/auth/oauth2/MockMetadataServerTransport.java +++ b/oauth2_http/javatests/com/google/auth/oauth2/MockMetadataServerTransport.java @@ -60,6 +60,10 @@ public class MockMetadataServerTransport extends MockHttpTransport { private byte[] signature; + private String s2aAddress; + + private boolean emptyContent; + public MockMetadataServerTransport() {} public void setAccessToken(String accessToken) { @@ -82,6 +86,26 @@ public void setIdToken(String idToken) { this.idToken = idToken; } + public void setS2AAddress(String address) { + this.s2aAddress = address; + } + + public void setEmptyContent(boolean emptyContent) { + this.emptyContent = emptyContent; + } + + public String getAddr() { + return s2aAddress; + } + + public Integer getCode() { + return requestStatusCode; + } + + public boolean getEmpty() { + return emptyContent; + } + @Override public LowLevelHttpRequest buildRequest(String method, String url) throws IOException { if (url.equals(ComputeEngineCredentials.getTokenServerEncodedUrl())) { @@ -92,6 +116,8 @@ public LowLevelHttpRequest buildRequest(String method, String url) throws IOExce return getMockRequestForSign(url); } else if (isIdentityDocumentUrl(url)) { return getMockRequestForIdentityDocument(url); + } else if (isMtlsConfigRequestUrl(url)) { + return getMockRequestForMtlsConfig(url); } return new MockLowLevelHttpRequest(url) { @Override @@ -233,6 +259,38 @@ public LowLevelHttpResponse execute() throws IOException { }; } + private MockLowLevelHttpRequest getMockRequestForMtlsConfig(String url) { + return new MockLowLevelHttpRequest(url) { + @Override + public LowLevelHttpResponse execute() throws IOException { + + String metadataRequestHeader = getFirstHeaderValue("Metadata-Flavor"); + if (!"Google".equals(metadataRequestHeader)) { + throw new IOException("Metadata request header not found"); + } + + // Create the JSON response + GenericJson content = new GenericJson(); + content.setFactory(OAuth2Utils.JSON_FACTORY); + content.put("s2a", s2aAddress); + String contentText = content.toPrettyString(); + + MockLowLevelHttpResponse response = new MockLowLevelHttpResponse(); + + if(requestStatusCode != null) { + response.setStatusCode(requestStatusCode); + } + if(emptyContent == true) { + return response.setZeroContent(); + } + response.setContentType(Json.MEDIA_TYPE) + .setContent(contentText); + return response; + } + }; + + } + protected boolean isGetServiceAccountsUrl(String url) { return url.equals(ComputeEngineCredentials.getServiceAccountsUrl()); } @@ -246,4 +304,8 @@ protected boolean isSignRequestUrl(String url) { protected boolean isIdentityDocumentUrl(String url) { return url.startsWith(String.format(ComputeEngineCredentials.getIdentityDocumentUrl())); } + + protected boolean isMtlsConfigRequestUrl(String url) { + return s2aAddress != null && url.equals(String.format(S2A.DEFAULT_METADATA_SERVER_URL + S2A.MTLS_CONFIG_ENDPOINT)); + } } diff --git a/oauth2_http/javatests/com/google/auth/oauth2/MtlsConfigTest.java b/oauth2_http/javatests/com/google/auth/oauth2/MtlsConfigTest.java new file mode 100644 index 000000000..b2cf003a6 --- /dev/null +++ b/oauth2_http/javatests/com/google/auth/oauth2/MtlsConfigTest.java @@ -0,0 +1,47 @@ +package com.google.auth.oauth2; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.joda.time.MutableDateTime; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + + +/** Test cases for {@link MtlsConfig}.*/ + +@RunWith(JUnit4.class) +public class MtlsConfigTest { + private static final String S2A_ADDRESS_A = "addr_a"; + private static final String S2A_ADDRESS_B = "addr_b"; + + @Test + public void NullMtlsConfig_invalid() { + MtlsConfig config = MtlsConfig.createNullMtlsConfig(); + assertEquals("", config.getS2AAddress()); + assertFalse(config.isValid()); + } + + @Test + public void NonNullMtlsConfig_valid() { + MtlsConfig config = MtlsConfig.createMtlsConfig(S2A_ADDRESS_A); + assertEquals(S2A_ADDRESS_A, config.getS2AAddress()); + assertTrue(config.isValid()); + } + + @Test + public void resetAddress_newExpiryGreater() throws Exception { + MtlsConfig config = MtlsConfig.createMtlsConfig(S2A_ADDRESS_A); + MutableDateTime e1 = config.getExpiry(); + assertEquals(S2A_ADDRESS_A, config.getS2AAddress()); + Thread.sleep(2000); + config.reset(S2A_ADDRESS_B); + assertEquals(S2A_ADDRESS_B, config.getS2AAddress()); + MutableDateTime e2 = config.getExpiry(); + int value = e2.compareTo(e1); + assertTrue(value > 0); + } + +} diff --git a/oauth2_http/javatests/com/google/auth/oauth2/S2ATest.java b/oauth2_http/javatests/com/google/auth/oauth2/S2ATest.java new file mode 100644 index 000000000..e7583e596 --- /dev/null +++ b/oauth2_http/javatests/com/google/auth/oauth2/S2ATest.java @@ -0,0 +1,102 @@ +package com.google.auth.oauth2; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import com.google.api.client.http.HttpStatusCodes; +import com.google.api.client.testing.http.MockHttpTransport; +import com.google.auth.http.HttpTransportFactory; +import com.google.auth.oauth2.ComputeEngineCredentialsTest.MockMetadataServerTransportFactory; +import java.util.concurrent.ExecutorService; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** Test cases for {@link S2A}.*/ +@RunWith(JUnit4.class) +public class S2ATest { + + private static final String S2A_ADDRESS_A = "addr_a"; + private static final String S2A_ADDRESS_B = "addr_b"; + + @Test + public void getS2AAddress_validAddress() { + MockMetadataServerTransportFactory transportFactory = new MockMetadataServerTransportFactory(); + transportFactory.transport.setS2AAddress(S2A_ADDRESS_A); + transportFactory.transport.setRequestStatusCode(HttpStatusCodes.STATUS_CODE_OK); + + S2A s2aUtils = new S2A(); + s2aUtils.setHttpTransportFactory(transportFactory); + String s2aAddress = s2aUtils.getS2AAddress(); + assertEquals(S2A_ADDRESS_A, s2aAddress); + } + + @Test + public void getS2AAddress_queryEndpointResponseErrorCode_emptyAddress() { + MockMetadataServerTransportFactory transportFactory = new MockMetadataServerTransportFactory(); + transportFactory.transport.setS2AAddress(S2A_ADDRESS_A); + transportFactory.transport.setRequestStatusCode(HttpStatusCodes.STATUS_CODE_SERVICE_UNAVAILABLE); + + S2A s2aUtils = new S2A(); + s2aUtils.setHttpTransportFactory(transportFactory); + String s2aAddress = s2aUtils.getS2AAddress(); + assertTrue(s2aAddress.isEmpty()); + } + + @Test + public void getS2AAddress_queryEndpointResponseEmpty_emptyAddress() { + MockMetadataServerTransportFactory transportFactory = new MockMetadataServerTransportFactory(); + transportFactory.transport.setS2AAddress(S2A_ADDRESS_A); + transportFactory.transport.setRequestStatusCode(HttpStatusCodes.STATUS_CODE_OK); + transportFactory.transport.setEmptyContent(true); + + S2A s2aUtils = new S2A(); + s2aUtils.setHttpTransportFactory(transportFactory); + String s2aAddress = s2aUtils.getS2AAddress(); + assertTrue(s2aAddress.isEmpty()); + } + + @Test + public void getS2AAdress_multipleThreads_validAddress() throws Exception{ + MockMetadataServerTransportFactory transportFactoryA = new MockMetadataServerTransportFactory(); + transportFactoryA.transport.setS2AAddress(S2A_ADDRESS_A); + transportFactoryA.transport.setRequestStatusCode(HttpStatusCodes.STATUS_CODE_OK); + + MockMetadataServerTransportFactory transportFactoryB = new MockMetadataServerTransportFactory(); + transportFactoryB.transport.setS2AAddress(S2A_ADDRESS_B); + transportFactoryB.transport.setRequestStatusCode(HttpStatusCodes.STATUS_CODE_OK); + + S2A s2aUtils = new S2A(); + + DoGetS2AAddress doGetS2AAddressA = new DoGetS2AAddress(transportFactoryA, S2A_ADDRESS_A, s2aUtils); + DoGetS2AAddress doGetS2AAddressB = new DoGetS2AAddress(transportFactoryB, S2A_ADDRESS_A, s2aUtils); + + doGetS2AAddressA.start(); + Thread.sleep(2000); + doGetS2AAddressB.start(); + + doGetS2AAddressA.join(); + doGetS2AAddressB.join(); + } + + private class DoGetS2AAddress extends Thread { + HttpTransportFactory transportFactory; + String exp_addr; + S2A s2aUtils; + public DoGetS2AAddress(HttpTransportFactory transportFactory, String addr, S2A s2aUtils) { + super(); + this.transportFactory = transportFactory; + this.exp_addr = addr; + this.s2aUtils = s2aUtils; + } + + @Override + public void run() { + s2aUtils.setHttpTransportFactory(transportFactory); + String s2aAddress = s2aUtils.getS2AAddress(); + assertEquals(exp_addr, s2aAddress); + } + } +} + + diff --git a/oauth2_http/pom.xml b/oauth2_http/pom.xml index 36da3d3b8..4beed7c00 100644 --- a/oauth2_http/pom.xml +++ b/oauth2_http/pom.xml @@ -226,6 +226,11 @@ hamcrest-core 1.3 test + + + joda-time + joda-time + 2.12.7 org.mockito From f90be0b751f7085b399c21ba873039ab2be37e83 Mon Sep 17 00:00:00 2001 From: Riya Mehta Date: Thu, 29 Feb 2024 14:40:15 -0800 Subject: [PATCH 02/44] formatted. --- .../com/google/auth/oauth2/MtlsConfig.java | 94 +++++----- .../java/com/google/auth/oauth2/S2A.java | 146 ++++++++------- .../oauth2/MockMetadataServerTransport.java | 53 +++--- .../google/auth/oauth2/MtlsConfigTest.java | 63 +++---- .../com/google/auth/oauth2/S2ATest.java | 172 +++++++++--------- 5 files changed, 262 insertions(+), 266 deletions(-) diff --git a/oauth2_http/java/com/google/auth/oauth2/MtlsConfig.java b/oauth2_http/java/com/google/auth/oauth2/MtlsConfig.java index 18ad6b34d..527745027 100644 --- a/oauth2_http/java/com/google/auth/oauth2/MtlsConfig.java +++ b/oauth2_http/java/com/google/auth/oauth2/MtlsConfig.java @@ -1,55 +1,57 @@ package com.google.auth.oauth2; -import org.joda.time.MutableDateTime; import javax.annotation.concurrent.NotThreadSafe; +import org.joda.time.MutableDateTime; /** * Holds an mTLS configuration (consists of address of S2A) retrieved from the Metadata Server. * - * Instances of {@link MtlsConfig} are not thread safe. Calls to {@code reset}, {@code getS2AAddress}, {@code isValid} - * and {@code getExpiry} should be made from a synchronized block. - */ + *

Instances of {@link MtlsConfig} are not thread safe. Calls to {@code reset}, {@code + * getS2AAddress}, {@code isValid} and {@code getExpiry} should be made from a synchronized block. + */ @NotThreadSafe -public final class MtlsConfig{ - private String s2aAddress; - private MutableDateTime expiry; - - private static final int MTLS_AUTOCONFIG_EXPIRATION_HOURS = 1; - - public static MtlsConfig createNullMtlsConfig() { - return new MtlsConfig("", null); - } - - public static MtlsConfig createMtlsConfig(String addr) { - MutableDateTime expiry = MutableDateTime.now(); - expiry.addHours(MTLS_AUTOCONFIG_EXPIRATION_HOURS); - return new MtlsConfig(addr, expiry); - } - - public void reset(String addr) { - this.s2aAddress = addr; - this.expiry = MutableDateTime.now(); - this.expiry.addHours(MTLS_AUTOCONFIG_EXPIRATION_HOURS); - } - - public String getS2AAddress() { - return s2aAddress; - } - - public boolean isValid() { - if (expiry == null) { return false; } - if (MutableDateTime.now().isAfter(this.expiry)) { - return false; - } - return true; - } - - public MutableDateTime getExpiry() { - return expiry; - } - - private MtlsConfig(String addr, MutableDateTime expiry) { - this.s2aAddress = addr; - this.expiry = expiry; - } +public final class MtlsConfig { + private String s2aAddress; + private MutableDateTime expiry; + + private static final int MTLS_AUTOCONFIG_EXPIRATION_HOURS = 1; + + public static MtlsConfig createNullMtlsConfig() { + return new MtlsConfig("", null); + } + + public static MtlsConfig createMtlsConfig(String addr) { + MutableDateTime expiry = MutableDateTime.now(); + expiry.addHours(MTLS_AUTOCONFIG_EXPIRATION_HOURS); + return new MtlsConfig(addr, expiry); + } + + public void reset(String addr) { + this.s2aAddress = addr; + this.expiry = MutableDateTime.now(); + this.expiry.addHours(MTLS_AUTOCONFIG_EXPIRATION_HOURS); + } + + public String getS2AAddress() { + return s2aAddress; + } + + public boolean isValid() { + if (expiry == null) { + return false; + } + if (MutableDateTime.now().isAfter(this.expiry)) { + return false; + } + return true; + } + + public MutableDateTime getExpiry() { + return expiry; + } + + private MtlsConfig(String addr, MutableDateTime expiry) { + this.s2aAddress = addr; + this.expiry = expiry; + } } diff --git a/oauth2_http/java/com/google/auth/oauth2/S2A.java b/oauth2_http/java/com/google/auth/oauth2/S2A.java index 7bdc3727c..5b57bad94 100644 --- a/oauth2_http/java/com/google/auth/oauth2/S2A.java +++ b/oauth2_http/java/com/google/auth/oauth2/S2A.java @@ -1,101 +1,99 @@ package com.google.auth.oauth2; +import com.google.api.client.http.GenericUrl; import com.google.api.client.http.HttpRequest; import com.google.api.client.http.HttpResponse; -import com.google.api.client.http.HttpResponseException; -import com.google.api.client.http.HttpStatusCodes; -import com.google.api.client.http.HttpResponseException; -import com.google.api.client.http.GenericUrl; -import com.google.api.client.util.GenericData; import com.google.api.client.json.JsonObjectParser; +import com.google.api.client.util.GenericData; import com.google.auth.http.HttpTransportFactory; import com.google.common.collect.Iterables; -import java.io.InputStream; import java.io.IOException; +import java.io.InputStream; import java.util.ServiceLoader; -import java.util.logging.Logger; -import java.util.logging.Level; import javax.annotation.concurrent.ThreadSafe; /** * Utilities to fetch the S2A (Secure Session Agent) address from the mTLS configuration. * - * Periodically refresh the mTLS configuration by getting a new one from the MDS mTLS autoconfig endpoint. + *

Periodically refresh the mTLS configuration by getting a new one from the MDS mTLS autoconfig + * endpoint. */ @ThreadSafe public final class S2A { - public static final String DEFAULT_METADATA_SERVER_URL = "http://metadata.google.internal"; - public static final String MTLS_CONFIG_ENDPOINT = "/instance/platform-security/auto-mtls-configuration"; + public static final String DEFAULT_METADATA_SERVER_URL = "http://metadata.google.internal"; + public static final String MTLS_CONFIG_ENDPOINT = + "/instance/platform-security/auto-mtls-configuration"; + + private static final String METADATA_FLAVOR = "Metadata-Flavor"; + private static final String GOOGLE = "Google"; + private static final String PARSE_ERROR_S2A = "Error parsing Mtls Auto Config response."; - private static final String METADATA_FLAVOR = "Metadata-Flavor"; - private static final String GOOGLE = "Google"; - private static final String PARSE_ERROR_S2A = "Error parsing Mtls Auto Config response."; + private MtlsConfig config; - private MtlsConfig config; + private transient HttpTransportFactory transportFactory; - private transient HttpTransportFactory transportFactory; + public S2A() { + config = MtlsConfig.createNullMtlsConfig(); + } - public S2A() { - config = MtlsConfig.createNullMtlsConfig(); - } + public void setHttpTransportFactory(HttpTransportFactory tf) { + this.transportFactory = tf; + } - public void setHttpTransportFactory(HttpTransportFactory tf) { - this.transportFactory = tf; - } + /** Returns the S2A Address from the mTLS config. Refreshes the config if it is expired. */ + public synchronized String getS2AAddress() { + if (!config.isValid()) { + String addr = getMdsMtlsConfigData(); + config.reset(addr); + } + return config.getS2AAddress(); + } - /** - * Returns the S2A Address from the mTLS config. Refreshes the config if it is expired. - */ - public synchronized String getS2AAddress() { - if (!config.isValid()) { - String addr = getMdsMtlsConfigData(); - config.reset(addr); - } - return config.getS2AAddress(); - } + /** + * Queries the MDS mTLS Autoconfiguration endpoint and returns the S2A address. Returns an empty + * address on error. + */ + private String getMdsMtlsConfigData() { + String s2aAddress = ""; + try { + if (transportFactory == null) { + transportFactory = + Iterables.getFirst( + ServiceLoader.load(HttpTransportFactory.class), OAuth2Utils.HTTP_TRANSPORT_FACTORY); + } + String url = getMdsMtlsEndpoint(DefaultCredentialsProvider.DEFAULT); + GenericUrl genericUrl = new GenericUrl(url); + HttpRequest request = + transportFactory.create().createRequestFactory().buildGetRequest(genericUrl); + JsonObjectParser parser = new JsonObjectParser(OAuth2Utils.JSON_FACTORY); + request.setParser(parser); + request.getHeaders().set(METADATA_FLAVOR, GOOGLE); + request.setThrowExceptionOnExecuteError(false); + HttpResponse response = request.execute(); - /** - * Queries the MDS mTLS Autoconfiguration endpoint and returns the S2A address. Returns an empty address on error. - */ - private String getMdsMtlsConfigData() { - String s2aAddress = ""; - try { - if (transportFactory == null) { - transportFactory = Iterables.getFirst(ServiceLoader.load(HttpTransportFactory.class), OAuth2Utils.HTTP_TRANSPORT_FACTORY); - } - String url = getMdsMtlsEndpoint(DefaultCredentialsProvider.DEFAULT); - GenericUrl genericUrl = new GenericUrl(url); - HttpRequest request = transportFactory.create().createRequestFactory().buildGetRequest(genericUrl); - JsonObjectParser parser = new JsonObjectParser(OAuth2Utils.JSON_FACTORY); - request.setParser(parser); - request.getHeaders().set(METADATA_FLAVOR, GOOGLE); - request.setThrowExceptionOnExecuteError(false); - HttpResponse response = request.execute(); + if (!response.isSuccessStatusCode()) { + return ""; + } - if (!response.isSuccessStatusCode()) { - return ""; - } - - InputStream content = response.getContent(); - if (content == null) { - return ""; - } - GenericData responseData = response.parseAs(GenericData.class); - s2aAddress = OAuth2Utils.validateString(responseData, "s2a", PARSE_ERROR_S2A); - } catch(IOException e) { - return ""; - } - return s2aAddress; - } + InputStream content = response.getContent(); + if (content == null) { + return ""; + } + GenericData responseData = response.parseAs(GenericData.class); + s2aAddress = OAuth2Utils.validateString(responseData, "s2a", PARSE_ERROR_S2A); + } catch (IOException e) { + return ""; + } + return s2aAddress; + } - /** - * @return MDS mTLS autoconfig endpoint. - */ - private String getMdsMtlsEndpoint(DefaultCredentialsProvider provider) { - String metadataServerAddress = provider.getEnv(DefaultCredentialsProvider.GCE_METADATA_HOST_ENV_VAR); - if (metadataServerAddress != null) { - return "http://" + metadataServerAddress + MTLS_CONFIG_ENDPOINT; - } - return DEFAULT_METADATA_SERVER_URL + MTLS_CONFIG_ENDPOINT; - } + /** @return MDS mTLS autoconfig endpoint. */ + private String getMdsMtlsEndpoint(DefaultCredentialsProvider provider) { + String metadataServerAddress = + provider.getEnv(DefaultCredentialsProvider.GCE_METADATA_HOST_ENV_VAR); + if (metadataServerAddress != null) { + return "http://" + metadataServerAddress + MTLS_CONFIG_ENDPOINT; + } + return DEFAULT_METADATA_SERVER_URL + MTLS_CONFIG_ENDPOINT; + } } diff --git a/oauth2_http/javatests/com/google/auth/oauth2/MockMetadataServerTransport.java b/oauth2_http/javatests/com/google/auth/oauth2/MockMetadataServerTransport.java index 1c78670ff..242990223 100644 --- a/oauth2_http/javatests/com/google/auth/oauth2/MockMetadataServerTransport.java +++ b/oauth2_http/javatests/com/google/auth/oauth2/MockMetadataServerTransport.java @@ -61,7 +61,7 @@ public class MockMetadataServerTransport extends MockHttpTransport { private byte[] signature; private String s2aAddress; - + private boolean emptyContent; public MockMetadataServerTransport() {} @@ -87,23 +87,23 @@ public void setIdToken(String idToken) { } public void setS2AAddress(String address) { - this.s2aAddress = address; + this.s2aAddress = address; } - + public void setEmptyContent(boolean emptyContent) { - this.emptyContent = emptyContent; + this.emptyContent = emptyContent; } public String getAddr() { - return s2aAddress; + return s2aAddress; } public Integer getCode() { - return requestStatusCode; + return requestStatusCode; } public boolean getEmpty() { - return emptyContent; + return emptyContent; } @Override @@ -264,31 +264,29 @@ private MockLowLevelHttpRequest getMockRequestForMtlsConfig(String url) { @Override public LowLevelHttpResponse execute() throws IOException { - String metadataRequestHeader = getFirstHeaderValue("Metadata-Flavor"); - if (!"Google".equals(metadataRequestHeader)) { - throw new IOException("Metadata request header not found"); - } - + String metadataRequestHeader = getFirstHeaderValue("Metadata-Flavor"); + if (!"Google".equals(metadataRequestHeader)) { + throw new IOException("Metadata request header not found"); + } + // Create the JSON response GenericJson content = new GenericJson(); content.setFactory(OAuth2Utils.JSON_FACTORY); content.put("s2a", s2aAddress); - String contentText = content.toPrettyString(); - - MockLowLevelHttpResponse response = new MockLowLevelHttpResponse(); - - if(requestStatusCode != null) { - response.setStatusCode(requestStatusCode); - } - if(emptyContent == true) { - return response.setZeroContent(); - } - response.setContentType(Json.MEDIA_TYPE) - .setContent(contentText); - return response; + String contentText = content.toPrettyString(); + + MockLowLevelHttpResponse response = new MockLowLevelHttpResponse(); + + if (requestStatusCode != null) { + response.setStatusCode(requestStatusCode); + } + if (emptyContent == true) { + return response.setZeroContent(); + } + response.setContentType(Json.MEDIA_TYPE).setContent(contentText); + return response; } }; - } protected boolean isGetServiceAccountsUrl(String url) { @@ -306,6 +304,7 @@ protected boolean isIdentityDocumentUrl(String url) { } protected boolean isMtlsConfigRequestUrl(String url) { - return s2aAddress != null && url.equals(String.format(S2A.DEFAULT_METADATA_SERVER_URL + S2A.MTLS_CONFIG_ENDPOINT)); + return s2aAddress != null + && url.equals(String.format(S2A.DEFAULT_METADATA_SERVER_URL + S2A.MTLS_CONFIG_ENDPOINT)); } } diff --git a/oauth2_http/javatests/com/google/auth/oauth2/MtlsConfigTest.java b/oauth2_http/javatests/com/google/auth/oauth2/MtlsConfigTest.java index b2cf003a6..648a661c4 100644 --- a/oauth2_http/javatests/com/google/auth/oauth2/MtlsConfigTest.java +++ b/oauth2_http/javatests/com/google/auth/oauth2/MtlsConfigTest.java @@ -9,39 +9,36 @@ import org.junit.runner.RunWith; import org.junit.runners.JUnit4; - -/** Test cases for {@link MtlsConfig}.*/ - +/** Test cases for {@link MtlsConfig}. */ @RunWith(JUnit4.class) public class MtlsConfigTest { - private static final String S2A_ADDRESS_A = "addr_a"; - private static final String S2A_ADDRESS_B = "addr_b"; - - @Test - public void NullMtlsConfig_invalid() { - MtlsConfig config = MtlsConfig.createNullMtlsConfig(); - assertEquals("", config.getS2AAddress()); - assertFalse(config.isValid()); - } - - @Test - public void NonNullMtlsConfig_valid() { - MtlsConfig config = MtlsConfig.createMtlsConfig(S2A_ADDRESS_A); - assertEquals(S2A_ADDRESS_A, config.getS2AAddress()); - assertTrue(config.isValid()); - } - - @Test - public void resetAddress_newExpiryGreater() throws Exception { - MtlsConfig config = MtlsConfig.createMtlsConfig(S2A_ADDRESS_A); - MutableDateTime e1 = config.getExpiry(); - assertEquals(S2A_ADDRESS_A, config.getS2AAddress()); - Thread.sleep(2000); - config.reset(S2A_ADDRESS_B); - assertEquals(S2A_ADDRESS_B, config.getS2AAddress()); - MutableDateTime e2 = config.getExpiry(); - int value = e2.compareTo(e1); - assertTrue(value > 0); - } - + private static final String S2A_ADDRESS_A = "addr_a"; + private static final String S2A_ADDRESS_B = "addr_b"; + + @Test + public void NullMtlsConfig_invalid() { + MtlsConfig config = MtlsConfig.createNullMtlsConfig(); + assertEquals("", config.getS2AAddress()); + assertFalse(config.isValid()); + } + + @Test + public void NonNullMtlsConfig_valid() { + MtlsConfig config = MtlsConfig.createMtlsConfig(S2A_ADDRESS_A); + assertEquals(S2A_ADDRESS_A, config.getS2AAddress()); + assertTrue(config.isValid()); + } + + @Test + public void resetAddress_newExpiryGreater() throws Exception { + MtlsConfig config = MtlsConfig.createMtlsConfig(S2A_ADDRESS_A); + MutableDateTime e1 = config.getExpiry(); + assertEquals(S2A_ADDRESS_A, config.getS2AAddress()); + Thread.sleep(2000); + config.reset(S2A_ADDRESS_B); + assertEquals(S2A_ADDRESS_B, config.getS2AAddress()); + MutableDateTime e2 = config.getExpiry(); + int value = e2.compareTo(e1); + assertTrue(value > 0); + } } diff --git a/oauth2_http/javatests/com/google/auth/oauth2/S2ATest.java b/oauth2_http/javatests/com/google/auth/oauth2/S2ATest.java index e7583e596..46535d8c3 100644 --- a/oauth2_http/javatests/com/google/auth/oauth2/S2ATest.java +++ b/oauth2_http/javatests/com/google/auth/oauth2/S2ATest.java @@ -4,99 +4,99 @@ import static org.junit.Assert.assertTrue; import com.google.api.client.http.HttpStatusCodes; -import com.google.api.client.testing.http.MockHttpTransport; import com.google.auth.http.HttpTransportFactory; import com.google.auth.oauth2.ComputeEngineCredentialsTest.MockMetadataServerTransportFactory; -import java.util.concurrent.ExecutorService; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; -/** Test cases for {@link S2A}.*/ +/** Test cases for {@link S2A}. */ @RunWith(JUnit4.class) public class S2ATest { - private static final String S2A_ADDRESS_A = "addr_a"; - private static final String S2A_ADDRESS_B = "addr_b"; - - @Test - public void getS2AAddress_validAddress() { - MockMetadataServerTransportFactory transportFactory = new MockMetadataServerTransportFactory(); - transportFactory.transport.setS2AAddress(S2A_ADDRESS_A); - transportFactory.transport.setRequestStatusCode(HttpStatusCodes.STATUS_CODE_OK); - - S2A s2aUtils = new S2A(); - s2aUtils.setHttpTransportFactory(transportFactory); - String s2aAddress = s2aUtils.getS2AAddress(); - assertEquals(S2A_ADDRESS_A, s2aAddress); - } - - @Test - public void getS2AAddress_queryEndpointResponseErrorCode_emptyAddress() { - MockMetadataServerTransportFactory transportFactory = new MockMetadataServerTransportFactory(); - transportFactory.transport.setS2AAddress(S2A_ADDRESS_A); - transportFactory.transport.setRequestStatusCode(HttpStatusCodes.STATUS_CODE_SERVICE_UNAVAILABLE); - - S2A s2aUtils = new S2A(); - s2aUtils.setHttpTransportFactory(transportFactory); - String s2aAddress = s2aUtils.getS2AAddress(); - assertTrue(s2aAddress.isEmpty()); - } - - @Test - public void getS2AAddress_queryEndpointResponseEmpty_emptyAddress() { - MockMetadataServerTransportFactory transportFactory = new MockMetadataServerTransportFactory(); - transportFactory.transport.setS2AAddress(S2A_ADDRESS_A); - transportFactory.transport.setRequestStatusCode(HttpStatusCodes.STATUS_CODE_OK); - transportFactory.transport.setEmptyContent(true); - - S2A s2aUtils = new S2A(); - s2aUtils.setHttpTransportFactory(transportFactory); - String s2aAddress = s2aUtils.getS2AAddress(); - assertTrue(s2aAddress.isEmpty()); - } - - @Test - public void getS2AAdress_multipleThreads_validAddress() throws Exception{ - MockMetadataServerTransportFactory transportFactoryA = new MockMetadataServerTransportFactory(); - transportFactoryA.transport.setS2AAddress(S2A_ADDRESS_A); - transportFactoryA.transport.setRequestStatusCode(HttpStatusCodes.STATUS_CODE_OK); - - MockMetadataServerTransportFactory transportFactoryB = new MockMetadataServerTransportFactory(); - transportFactoryB.transport.setS2AAddress(S2A_ADDRESS_B); - transportFactoryB.transport.setRequestStatusCode(HttpStatusCodes.STATUS_CODE_OK); - - S2A s2aUtils = new S2A(); - - DoGetS2AAddress doGetS2AAddressA = new DoGetS2AAddress(transportFactoryA, S2A_ADDRESS_A, s2aUtils); - DoGetS2AAddress doGetS2AAddressB = new DoGetS2AAddress(transportFactoryB, S2A_ADDRESS_A, s2aUtils); - - doGetS2AAddressA.start(); - Thread.sleep(2000); - doGetS2AAddressB.start(); - - doGetS2AAddressA.join(); - doGetS2AAddressB.join(); - } - - private class DoGetS2AAddress extends Thread { - HttpTransportFactory transportFactory; - String exp_addr; - S2A s2aUtils; - public DoGetS2AAddress(HttpTransportFactory transportFactory, String addr, S2A s2aUtils) { - super(); - this.transportFactory = transportFactory; - this.exp_addr = addr; - this.s2aUtils = s2aUtils; - } - - @Override - public void run() { - s2aUtils.setHttpTransportFactory(transportFactory); - String s2aAddress = s2aUtils.getS2AAddress(); - assertEquals(exp_addr, s2aAddress); - } - } + private static final String S2A_ADDRESS_A = "addr_a"; + private static final String S2A_ADDRESS_B = "addr_b"; + + @Test + public void getS2AAddress_validAddress() { + MockMetadataServerTransportFactory transportFactory = new MockMetadataServerTransportFactory(); + transportFactory.transport.setS2AAddress(S2A_ADDRESS_A); + transportFactory.transport.setRequestStatusCode(HttpStatusCodes.STATUS_CODE_OK); + + S2A s2aUtils = new S2A(); + s2aUtils.setHttpTransportFactory(transportFactory); + String s2aAddress = s2aUtils.getS2AAddress(); + assertEquals(S2A_ADDRESS_A, s2aAddress); + } + + @Test + public void getS2AAddress_queryEndpointResponseErrorCode_emptyAddress() { + MockMetadataServerTransportFactory transportFactory = new MockMetadataServerTransportFactory(); + transportFactory.transport.setS2AAddress(S2A_ADDRESS_A); + transportFactory.transport.setRequestStatusCode( + HttpStatusCodes.STATUS_CODE_SERVICE_UNAVAILABLE); + + S2A s2aUtils = new S2A(); + s2aUtils.setHttpTransportFactory(transportFactory); + String s2aAddress = s2aUtils.getS2AAddress(); + assertTrue(s2aAddress.isEmpty()); + } + + @Test + public void getS2AAddress_queryEndpointResponseEmpty_emptyAddress() { + MockMetadataServerTransportFactory transportFactory = new MockMetadataServerTransportFactory(); + transportFactory.transport.setS2AAddress(S2A_ADDRESS_A); + transportFactory.transport.setRequestStatusCode(HttpStatusCodes.STATUS_CODE_OK); + transportFactory.transport.setEmptyContent(true); + + S2A s2aUtils = new S2A(); + s2aUtils.setHttpTransportFactory(transportFactory); + String s2aAddress = s2aUtils.getS2AAddress(); + assertTrue(s2aAddress.isEmpty()); + } + + @Test + public void getS2AAdress_multipleThreads_validAddress() throws Exception { + MockMetadataServerTransportFactory transportFactoryA = new MockMetadataServerTransportFactory(); + transportFactoryA.transport.setS2AAddress(S2A_ADDRESS_A); + transportFactoryA.transport.setRequestStatusCode(HttpStatusCodes.STATUS_CODE_OK); + + MockMetadataServerTransportFactory transportFactoryB = new MockMetadataServerTransportFactory(); + transportFactoryB.transport.setS2AAddress(S2A_ADDRESS_B); + transportFactoryB.transport.setRequestStatusCode(HttpStatusCodes.STATUS_CODE_OK); + + S2A s2aUtils = new S2A(); + + DoGetS2AAddress doGetS2AAddressA = + new DoGetS2AAddress(transportFactoryA, S2A_ADDRESS_A, s2aUtils); + DoGetS2AAddress doGetS2AAddressB = + new DoGetS2AAddress(transportFactoryB, S2A_ADDRESS_A, s2aUtils); + + doGetS2AAddressA.start(); + Thread.sleep(2000); + doGetS2AAddressB.start(); + + doGetS2AAddressA.join(); + doGetS2AAddressB.join(); + } + + private class DoGetS2AAddress extends Thread { + HttpTransportFactory transportFactory; + String exp_addr; + S2A s2aUtils; + + public DoGetS2AAddress(HttpTransportFactory transportFactory, String addr, S2A s2aUtils) { + super(); + this.transportFactory = transportFactory; + this.exp_addr = addr; + this.s2aUtils = s2aUtils; + } + + @Override + public void run() { + s2aUtils.setHttpTransportFactory(transportFactory); + String s2aAddress = s2aUtils.getS2AAddress(); + assertEquals(exp_addr, s2aAddress); + } + } } - - From 0c64a0a8fd70810969c795a4dcfe4be914947412 Mon Sep 17 00:00:00 2001 From: Riya Mehta Date: Tue, 12 Mar 2024 10:02:20 -0700 Subject: [PATCH 03/44] static mtls config. --- .../com/google/auth/oauth2/MtlsConfig.java | 47 ++----------------- .../java/com/google/auth/oauth2/S2A.java | 37 +++++++-------- .../oauth2/MockMetadataServerTransport.java | 16 +------ .../google/auth/oauth2/MtlsConfigTest.java | 27 +---------- .../com/google/auth/oauth2/S2ATest.java | 47 ------------------- oauth2_http/pom.xml | 5 -- 6 files changed, 25 insertions(+), 154 deletions(-) diff --git a/oauth2_http/java/com/google/auth/oauth2/MtlsConfig.java b/oauth2_http/java/com/google/auth/oauth2/MtlsConfig.java index 527745027..de4ab23ff 100644 --- a/oauth2_http/java/com/google/auth/oauth2/MtlsConfig.java +++ b/oauth2_http/java/com/google/auth/oauth2/MtlsConfig.java @@ -1,57 +1,18 @@ package com.google.auth.oauth2; -import javax.annotation.concurrent.NotThreadSafe; -import org.joda.time.MutableDateTime; - -/** - * Holds an mTLS configuration (consists of address of S2A) retrieved from the Metadata Server. - * - *

Instances of {@link MtlsConfig} are not thread safe. Calls to {@code reset}, {@code - * getS2AAddress}, {@code isValid} and {@code getExpiry} should be made from a synchronized block. - */ -@NotThreadSafe +/** Holds an mTLS configuration (consists of address of S2A) retrieved from the Metadata Server. */ public final class MtlsConfig { - private String s2aAddress; - private MutableDateTime expiry; - - private static final int MTLS_AUTOCONFIG_EXPIRATION_HOURS = 1; - - public static MtlsConfig createNullMtlsConfig() { - return new MtlsConfig("", null); - } + private final String s2aAddress; public static MtlsConfig createMtlsConfig(String addr) { - MutableDateTime expiry = MutableDateTime.now(); - expiry.addHours(MTLS_AUTOCONFIG_EXPIRATION_HOURS); - return new MtlsConfig(addr, expiry); - } - - public void reset(String addr) { - this.s2aAddress = addr; - this.expiry = MutableDateTime.now(); - this.expiry.addHours(MTLS_AUTOCONFIG_EXPIRATION_HOURS); + return new MtlsConfig(addr); } public String getS2AAddress() { return s2aAddress; } - public boolean isValid() { - if (expiry == null) { - return false; - } - if (MutableDateTime.now().isAfter(this.expiry)) { - return false; - } - return true; - } - - public MutableDateTime getExpiry() { - return expiry; - } - - private MtlsConfig(String addr, MutableDateTime expiry) { + private MtlsConfig(String addr) { this.s2aAddress = addr; - this.expiry = expiry; } } diff --git a/oauth2_http/java/com/google/auth/oauth2/S2A.java b/oauth2_http/java/com/google/auth/oauth2/S2A.java index 5b57bad94..598f46fb2 100644 --- a/oauth2_http/java/com/google/auth/oauth2/S2A.java +++ b/oauth2_http/java/com/google/auth/oauth2/S2A.java @@ -15,8 +15,7 @@ /** * Utilities to fetch the S2A (Secure Session Agent) address from the mTLS configuration. * - *

Periodically refresh the mTLS configuration by getting a new one from the MDS mTLS autoconfig - * endpoint. + *

mTLS configuration is queried from the MDS MTLS Autoconfiguration endpoint. */ @ThreadSafe public final class S2A { @@ -24,34 +23,39 @@ public final class S2A { public static final String MTLS_CONFIG_ENDPOINT = "/instance/platform-security/auto-mtls-configuration"; - private static final String METADATA_FLAVOR = "Metadata-Flavor"; - private static final String GOOGLE = "Google"; + public static final String METADATA_FLAVOR = "Metadata-Flavor"; + public static final String GOOGLE = "Google"; private static final String PARSE_ERROR_S2A = "Error parsing Mtls Auto Config response."; private MtlsConfig config; private transient HttpTransportFactory transportFactory; - public S2A() { - config = MtlsConfig.createNullMtlsConfig(); - } + public S2A() {} public void setHttpTransportFactory(HttpTransportFactory tf) { this.transportFactory = tf; } - /** Returns the S2A Address from the mTLS config. Refreshes the config if it is expired. */ + /** + * Returns the S2A Address from the mTLS config. + * + * @return the S2A address. + */ public synchronized String getS2AAddress() { - if (!config.isValid()) { + if (config == null) { String addr = getMdsMtlsConfigData(); - config.reset(addr); + config = MtlsConfig.createMtlsConfig(addr); } return config.getS2AAddress(); } /** - * Queries the MDS mTLS Autoconfiguration endpoint and returns the S2A address. Returns an empty - * address on error. + * Queries the MDS mTLS Autoconfiguration endpoint and returns the S2A address. + * + *

Returns an empty address on error. + * + * @return the S2A address. */ private String getMdsMtlsConfigData() { String s2aAddress = ""; @@ -61,7 +65,7 @@ private String getMdsMtlsConfigData() { Iterables.getFirst( ServiceLoader.load(HttpTransportFactory.class), OAuth2Utils.HTTP_TRANSPORT_FACTORY); } - String url = getMdsMtlsEndpoint(DefaultCredentialsProvider.DEFAULT); + String url = getMdsMtlsEndpoint(); GenericUrl genericUrl = new GenericUrl(url); HttpRequest request = transportFactory.create().createRequestFactory().buildGetRequest(genericUrl); @@ -88,12 +92,7 @@ private String getMdsMtlsConfigData() { } /** @return MDS mTLS autoconfig endpoint. */ - private String getMdsMtlsEndpoint(DefaultCredentialsProvider provider) { - String metadataServerAddress = - provider.getEnv(DefaultCredentialsProvider.GCE_METADATA_HOST_ENV_VAR); - if (metadataServerAddress != null) { - return "http://" + metadataServerAddress + MTLS_CONFIG_ENDPOINT; - } + private String getMdsMtlsEndpoint() { return DEFAULT_METADATA_SERVER_URL + MTLS_CONFIG_ENDPOINT; } } diff --git a/oauth2_http/javatests/com/google/auth/oauth2/MockMetadataServerTransport.java b/oauth2_http/javatests/com/google/auth/oauth2/MockMetadataServerTransport.java index 242990223..2554ff5a4 100644 --- a/oauth2_http/javatests/com/google/auth/oauth2/MockMetadataServerTransport.java +++ b/oauth2_http/javatests/com/google/auth/oauth2/MockMetadataServerTransport.java @@ -94,18 +94,6 @@ public void setEmptyContent(boolean emptyContent) { this.emptyContent = emptyContent; } - public String getAddr() { - return s2aAddress; - } - - public Integer getCode() { - return requestStatusCode; - } - - public boolean getEmpty() { - return emptyContent; - } - @Override public LowLevelHttpRequest buildRequest(String method, String url) throws IOException { if (url.equals(ComputeEngineCredentials.getTokenServerEncodedUrl())) { @@ -264,8 +252,8 @@ private MockLowLevelHttpRequest getMockRequestForMtlsConfig(String url) { @Override public LowLevelHttpResponse execute() throws IOException { - String metadataRequestHeader = getFirstHeaderValue("Metadata-Flavor"); - if (!"Google".equals(metadataRequestHeader)) { + String metadataRequestHeader = getFirstHeaderValue(S2A.METADATA_FLAVOR); + if (!S2A.GOOGLE.equals(metadataRequestHeader)) { throw new IOException("Metadata request header not found"); } diff --git a/oauth2_http/javatests/com/google/auth/oauth2/MtlsConfigTest.java b/oauth2_http/javatests/com/google/auth/oauth2/MtlsConfigTest.java index 648a661c4..201756d05 100644 --- a/oauth2_http/javatests/com/google/auth/oauth2/MtlsConfigTest.java +++ b/oauth2_http/javatests/com/google/auth/oauth2/MtlsConfigTest.java @@ -1,10 +1,7 @@ package com.google.auth.oauth2; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import org.joda.time.MutableDateTime; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -13,32 +10,10 @@ @RunWith(JUnit4.class) public class MtlsConfigTest { private static final String S2A_ADDRESS_A = "addr_a"; - private static final String S2A_ADDRESS_B = "addr_b"; @Test - public void NullMtlsConfig_invalid() { - MtlsConfig config = MtlsConfig.createNullMtlsConfig(); - assertEquals("", config.getS2AAddress()); - assertFalse(config.isValid()); - } - - @Test - public void NonNullMtlsConfig_valid() { - MtlsConfig config = MtlsConfig.createMtlsConfig(S2A_ADDRESS_A); - assertEquals(S2A_ADDRESS_A, config.getS2AAddress()); - assertTrue(config.isValid()); - } - - @Test - public void resetAddress_newExpiryGreater() throws Exception { + public void createMtlsConfig_success() { MtlsConfig config = MtlsConfig.createMtlsConfig(S2A_ADDRESS_A); - MutableDateTime e1 = config.getExpiry(); assertEquals(S2A_ADDRESS_A, config.getS2AAddress()); - Thread.sleep(2000); - config.reset(S2A_ADDRESS_B); - assertEquals(S2A_ADDRESS_B, config.getS2AAddress()); - MutableDateTime e2 = config.getExpiry(); - int value = e2.compareTo(e1); - assertTrue(value > 0); } } diff --git a/oauth2_http/javatests/com/google/auth/oauth2/S2ATest.java b/oauth2_http/javatests/com/google/auth/oauth2/S2ATest.java index 46535d8c3..163043c98 100644 --- a/oauth2_http/javatests/com/google/auth/oauth2/S2ATest.java +++ b/oauth2_http/javatests/com/google/auth/oauth2/S2ATest.java @@ -4,7 +4,6 @@ import static org.junit.Assert.assertTrue; import com.google.api.client.http.HttpStatusCodes; -import com.google.auth.http.HttpTransportFactory; import com.google.auth.oauth2.ComputeEngineCredentialsTest.MockMetadataServerTransportFactory; import org.junit.Test; import org.junit.runner.RunWith; @@ -15,7 +14,6 @@ public class S2ATest { private static final String S2A_ADDRESS_A = "addr_a"; - private static final String S2A_ADDRESS_B = "addr_b"; @Test public void getS2AAddress_validAddress() { @@ -54,49 +52,4 @@ public void getS2AAddress_queryEndpointResponseEmpty_emptyAddress() { String s2aAddress = s2aUtils.getS2AAddress(); assertTrue(s2aAddress.isEmpty()); } - - @Test - public void getS2AAdress_multipleThreads_validAddress() throws Exception { - MockMetadataServerTransportFactory transportFactoryA = new MockMetadataServerTransportFactory(); - transportFactoryA.transport.setS2AAddress(S2A_ADDRESS_A); - transportFactoryA.transport.setRequestStatusCode(HttpStatusCodes.STATUS_CODE_OK); - - MockMetadataServerTransportFactory transportFactoryB = new MockMetadataServerTransportFactory(); - transportFactoryB.transport.setS2AAddress(S2A_ADDRESS_B); - transportFactoryB.transport.setRequestStatusCode(HttpStatusCodes.STATUS_CODE_OK); - - S2A s2aUtils = new S2A(); - - DoGetS2AAddress doGetS2AAddressA = - new DoGetS2AAddress(transportFactoryA, S2A_ADDRESS_A, s2aUtils); - DoGetS2AAddress doGetS2AAddressB = - new DoGetS2AAddress(transportFactoryB, S2A_ADDRESS_A, s2aUtils); - - doGetS2AAddressA.start(); - Thread.sleep(2000); - doGetS2AAddressB.start(); - - doGetS2AAddressA.join(); - doGetS2AAddressB.join(); - } - - private class DoGetS2AAddress extends Thread { - HttpTransportFactory transportFactory; - String exp_addr; - S2A s2aUtils; - - public DoGetS2AAddress(HttpTransportFactory transportFactory, String addr, S2A s2aUtils) { - super(); - this.transportFactory = transportFactory; - this.exp_addr = addr; - this.s2aUtils = s2aUtils; - } - - @Override - public void run() { - s2aUtils.setHttpTransportFactory(transportFactory); - String s2aAddress = s2aUtils.getS2AAddress(); - assertEquals(exp_addr, s2aAddress); - } - } } diff --git a/oauth2_http/pom.xml b/oauth2_http/pom.xml index 4beed7c00..36da3d3b8 100644 --- a/oauth2_http/pom.xml +++ b/oauth2_http/pom.xml @@ -226,11 +226,6 @@ hamcrest-core 1.3 test - - - joda-time - joda-time - 2.12.7 org.mockito From 993663daff0e2f09dc6a1d1c9f1eb5d09f017fcc Mon Sep 17 00:00:00 2001 From: Riya Mehta Date: Wed, 13 Mar 2024 12:41:58 -0700 Subject: [PATCH 04/44] update autoconfig endpoint URL. --- oauth2_http/java/com/google/auth/oauth2/S2A.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/oauth2_http/java/com/google/auth/oauth2/S2A.java b/oauth2_http/java/com/google/auth/oauth2/S2A.java index 598f46fb2..930c030ee 100644 --- a/oauth2_http/java/com/google/auth/oauth2/S2A.java +++ b/oauth2_http/java/com/google/auth/oauth2/S2A.java @@ -19,9 +19,9 @@ */ @ThreadSafe public final class S2A { - public static final String DEFAULT_METADATA_SERVER_URL = "http://metadata.google.internal"; + public static final String DEFAULT_METADATA_SERVER_URL = "http://169.254.169.254"; public static final String MTLS_CONFIG_ENDPOINT = - "/instance/platform-security/auto-mtls-configuration"; + "/computeMetadata/v1/instance/platform-security/auto-mtls-configuration"; public static final String METADATA_FLAVOR = "Metadata-Flavor"; public static final String GOOGLE = "Google"; From 0f96e8690e83f62cce58df29a410e9f44bd1493e Mon Sep 17 00:00:00 2001 From: Riya Mehta Date: Wed, 13 Mar 2024 14:28:24 -0700 Subject: [PATCH 05/44] plaintext and mtls S2A address. --- .../com/google/auth/oauth2/MtlsConfig.java | 54 ++++++++++++++++--- .../java/com/google/auth/oauth2/S2A.java | 47 +++++++++------- .../oauth2/MockMetadataServerTransport.java | 18 +++++-- .../google/auth/oauth2/MtlsConfigTest.java | 20 +++++-- .../com/google/auth/oauth2/S2ATest.java | 30 +++++++---- 5 files changed, 125 insertions(+), 44 deletions(-) diff --git a/oauth2_http/java/com/google/auth/oauth2/MtlsConfig.java b/oauth2_http/java/com/google/auth/oauth2/MtlsConfig.java index de4ab23ff..61ee45cd8 100644 --- a/oauth2_http/java/com/google/auth/oauth2/MtlsConfig.java +++ b/oauth2_http/java/com/google/auth/oauth2/MtlsConfig.java @@ -1,18 +1,58 @@ package com.google.auth.oauth2; +import com.google.errorprone.annotations.CanIgnoreReturnValue; + /** Holds an mTLS configuration (consists of address of S2A) retrieved from the Metadata Server. */ public final class MtlsConfig { - private final String s2aAddress; + // plaintextS2AAddress is the plaintext address to reach the S2A. + private final String plaintextS2AAddress; + + // mtlsS2AAddress is the mTLS address to reach the S2A. + private final String mtlsS2AAddress; + + public static Builder createBuilder() { + return new Builder(); + } + + public String getPlaintextS2AAddress() { + return plaintextS2AAddress; + } - public static MtlsConfig createMtlsConfig(String addr) { - return new MtlsConfig(addr); + public String getMtlsS2AAddress() { + return mtlsS2AAddress; } - public String getS2AAddress() { - return s2aAddress; + public static final class Builder { + // plaintextS2AAddress is the plaintext address to reach the S2A. + private String plaintextS2AAddress; + + // mtlsS2AAddress is the mTLS address to reach the S2A. + private String mtlsS2AAddress; + + Builder() { + plaintextS2AAddress = ""; + mtlsS2AAddress = ""; + } + + @CanIgnoreReturnValue + public Builder setPlaintextS2AAddress(String plaintextS2AAddress) { + this.plaintextS2AAddress = plaintextS2AAddress; + return this; + } + + @CanIgnoreReturnValue + public Builder setMtlsS2AAddress(String mtlsS2AAddress) { + this.mtlsS2AAddress = mtlsS2AAddress; + return this; + } + + public MtlsConfig build() { + return new MtlsConfig(plaintextS2AAddress, mtlsS2AAddress); + } } - private MtlsConfig(String addr) { - this.s2aAddress = addr; + private MtlsConfig(String plaintextS2AAddress, String mtlsS2AAddress) { + this.plaintextS2AAddress = plaintextS2AAddress; + this.mtlsS2AAddress = mtlsS2AAddress; } } diff --git a/oauth2_http/java/com/google/auth/oauth2/S2A.java b/oauth2_http/java/com/google/auth/oauth2/S2A.java index 930c030ee..ff8450b60 100644 --- a/oauth2_http/java/com/google/auth/oauth2/S2A.java +++ b/oauth2_http/java/com/google/auth/oauth2/S2A.java @@ -37,28 +37,32 @@ public void setHttpTransportFactory(HttpTransportFactory tf) { this.transportFactory = tf; } - /** - * Returns the S2A Address from the mTLS config. - * - * @return the S2A address. - */ - public synchronized String getS2AAddress() { + /** @return the mTLS S2A Address from the mTLS config. */ + public synchronized String getMtlsS2AAddress() { + if (config == null) { + config = getMdsMtlsConfig(); + } + return config.getMtlsS2AAddress(); + } + + /** @return the plaintext S2A Address from the mTLS config. */ + public synchronized String getPlaintextS2AAddress() { if (config == null) { - String addr = getMdsMtlsConfigData(); - config = MtlsConfig.createMtlsConfig(addr); + config = getMdsMtlsConfig(); } - return config.getS2AAddress(); + return config.getPlaintextS2AAddress(); } /** - * Queries the MDS mTLS Autoconfiguration endpoint and returns the S2A address. + * Queries the MDS mTLS Autoconfiguration endpoint and returns the {@link MtlsConfig}. * - *

Returns an empty address on error. + *

Returns {@link MtlsConfig} with empty addresses on error. * - * @return the S2A address. + * @return the {@link MtlsConfig}. */ - private String getMdsMtlsConfigData() { - String s2aAddress = ""; + private MtlsConfig getMdsMtlsConfig() { + String plaintextS2AAddress = ""; + String mtlsS2AAddress = ""; try { if (transportFactory == null) { transportFactory = @@ -76,19 +80,24 @@ private String getMdsMtlsConfigData() { HttpResponse response = request.execute(); if (!response.isSuccessStatusCode()) { - return ""; + return MtlsConfig.createBuilder().build(); } InputStream content = response.getContent(); if (content == null) { - return ""; + return MtlsConfig.createBuilder().build(); } GenericData responseData = response.parseAs(GenericData.class); - s2aAddress = OAuth2Utils.validateString(responseData, "s2a", PARSE_ERROR_S2A); + plaintextS2AAddress = + OAuth2Utils.validateString(responseData, "plaintext_address", PARSE_ERROR_S2A); + mtlsS2AAddress = OAuth2Utils.validateString(responseData, "mtls_address", PARSE_ERROR_S2A); } catch (IOException e) { - return ""; + return MtlsConfig.createBuilder().build(); } - return s2aAddress; + return MtlsConfig.createBuilder() + .setPlaintextS2AAddress(plaintextS2AAddress) + .setMtlsS2AAddress(mtlsS2AAddress) + .build(); } /** @return MDS mTLS autoconfig endpoint. */ diff --git a/oauth2_http/javatests/com/google/auth/oauth2/MockMetadataServerTransport.java b/oauth2_http/javatests/com/google/auth/oauth2/MockMetadataServerTransport.java index 2554ff5a4..8e1a0b455 100644 --- a/oauth2_http/javatests/com/google/auth/oauth2/MockMetadataServerTransport.java +++ b/oauth2_http/javatests/com/google/auth/oauth2/MockMetadataServerTransport.java @@ -60,7 +60,9 @@ public class MockMetadataServerTransport extends MockHttpTransport { private byte[] signature; - private String s2aAddress; + private String plaintextS2AAddress; + + private String mtlsS2AAddress; private boolean emptyContent; @@ -86,8 +88,12 @@ public void setIdToken(String idToken) { this.idToken = idToken; } - public void setS2AAddress(String address) { - this.s2aAddress = address; + public void setPlaintextS2AAddress(String address) { + this.plaintextS2AAddress = address; + } + + public void setMtlsS2AAddress(String address) { + this.mtlsS2AAddress = address; } public void setEmptyContent(boolean emptyContent) { @@ -260,7 +266,8 @@ public LowLevelHttpResponse execute() throws IOException { // Create the JSON response GenericJson content = new GenericJson(); content.setFactory(OAuth2Utils.JSON_FACTORY); - content.put("s2a", s2aAddress); + content.put("plaintext_address", plaintextS2AAddress); + content.put("mtls_address", mtlsS2AAddress); String contentText = content.toPrettyString(); MockLowLevelHttpResponse response = new MockLowLevelHttpResponse(); @@ -292,7 +299,8 @@ protected boolean isIdentityDocumentUrl(String url) { } protected boolean isMtlsConfigRequestUrl(String url) { - return s2aAddress != null + return plaintextS2AAddress != null + && mtlsS2AAddress != null && url.equals(String.format(S2A.DEFAULT_METADATA_SERVER_URL + S2A.MTLS_CONFIG_ENDPOINT)); } } diff --git a/oauth2_http/javatests/com/google/auth/oauth2/MtlsConfigTest.java b/oauth2_http/javatests/com/google/auth/oauth2/MtlsConfigTest.java index 201756d05..64f1185d5 100644 --- a/oauth2_http/javatests/com/google/auth/oauth2/MtlsConfigTest.java +++ b/oauth2_http/javatests/com/google/auth/oauth2/MtlsConfigTest.java @@ -1,6 +1,7 @@ package com.google.auth.oauth2; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import org.junit.Test; import org.junit.runner.RunWith; @@ -9,11 +10,24 @@ /** Test cases for {@link MtlsConfig}. */ @RunWith(JUnit4.class) public class MtlsConfigTest { - private static final String S2A_ADDRESS_A = "addr_a"; + private static final String S2A_PLAINTEXT_ADDRESS = "plaintext"; + private static final String S2A_MTLS_ADDRESS = "mtls"; @Test public void createMtlsConfig_success() { - MtlsConfig config = MtlsConfig.createMtlsConfig(S2A_ADDRESS_A); - assertEquals(S2A_ADDRESS_A, config.getS2AAddress()); + MtlsConfig config = + MtlsConfig.createBuilder() + .setPlaintextS2AAddress(S2A_PLAINTEXT_ADDRESS) + .setMtlsS2AAddress(S2A_MTLS_ADDRESS) + .build(); + assertEquals(S2A_PLAINTEXT_ADDRESS, config.getPlaintextS2AAddress()); + assertEquals(S2A_MTLS_ADDRESS, config.getMtlsS2AAddress()); + } + + @Test + public void createEmptyMtlsConfig_success() { + MtlsConfig config = MtlsConfig.createBuilder().build(); + assertTrue(config.getPlaintextS2AAddress().isEmpty()); + assertTrue(config.getMtlsS2AAddress().isEmpty()); } } diff --git a/oauth2_http/javatests/com/google/auth/oauth2/S2ATest.java b/oauth2_http/javatests/com/google/auth/oauth2/S2ATest.java index 163043c98..590662e43 100644 --- a/oauth2_http/javatests/com/google/auth/oauth2/S2ATest.java +++ b/oauth2_http/javatests/com/google/auth/oauth2/S2ATest.java @@ -13,43 +13,53 @@ @RunWith(JUnit4.class) public class S2ATest { - private static final String S2A_ADDRESS_A = "addr_a"; + private static final String S2A_PLAINTEXT_ADDRESS = "plaintext"; + private static final String S2A_MTLS_ADDRESS = "mtls"; @Test public void getS2AAddress_validAddress() { MockMetadataServerTransportFactory transportFactory = new MockMetadataServerTransportFactory(); - transportFactory.transport.setS2AAddress(S2A_ADDRESS_A); + transportFactory.transport.setPlaintextS2AAddress(S2A_PLAINTEXT_ADDRESS); + transportFactory.transport.setMtlsS2AAddress(S2A_MTLS_ADDRESS); transportFactory.transport.setRequestStatusCode(HttpStatusCodes.STATUS_CODE_OK); S2A s2aUtils = new S2A(); s2aUtils.setHttpTransportFactory(transportFactory); - String s2aAddress = s2aUtils.getS2AAddress(); - assertEquals(S2A_ADDRESS_A, s2aAddress); + String plaintextS2AAddress = s2aUtils.getPlaintextS2AAddress(); + String mtlsS2AAddress = s2aUtils.getMtlsS2AAddress(); + assertEquals(S2A_PLAINTEXT_ADDRESS, plaintextS2AAddress); + assertEquals(S2A_MTLS_ADDRESS, mtlsS2AAddress); } @Test public void getS2AAddress_queryEndpointResponseErrorCode_emptyAddress() { MockMetadataServerTransportFactory transportFactory = new MockMetadataServerTransportFactory(); - transportFactory.transport.setS2AAddress(S2A_ADDRESS_A); + transportFactory.transport.setPlaintextS2AAddress(S2A_PLAINTEXT_ADDRESS); + transportFactory.transport.setMtlsS2AAddress(S2A_MTLS_ADDRESS); transportFactory.transport.setRequestStatusCode( HttpStatusCodes.STATUS_CODE_SERVICE_UNAVAILABLE); S2A s2aUtils = new S2A(); s2aUtils.setHttpTransportFactory(transportFactory); - String s2aAddress = s2aUtils.getS2AAddress(); - assertTrue(s2aAddress.isEmpty()); + String plaintextS2AAddress = s2aUtils.getPlaintextS2AAddress(); + String mtlsS2AAddress = s2aUtils.getMtlsS2AAddress(); + assertTrue(plaintextS2AAddress.isEmpty()); + assertTrue(mtlsS2AAddress.isEmpty()); } @Test public void getS2AAddress_queryEndpointResponseEmpty_emptyAddress() { MockMetadataServerTransportFactory transportFactory = new MockMetadataServerTransportFactory(); - transportFactory.transport.setS2AAddress(S2A_ADDRESS_A); + transportFactory.transport.setPlaintextS2AAddress(S2A_PLAINTEXT_ADDRESS); + transportFactory.transport.setMtlsS2AAddress(S2A_MTLS_ADDRESS); transportFactory.transport.setRequestStatusCode(HttpStatusCodes.STATUS_CODE_OK); transportFactory.transport.setEmptyContent(true); S2A s2aUtils = new S2A(); s2aUtils.setHttpTransportFactory(transportFactory); - String s2aAddress = s2aUtils.getS2AAddress(); - assertTrue(s2aAddress.isEmpty()); + String plaintextS2AAddress = s2aUtils.getPlaintextS2AAddress(); + String mtlsS2AAddress = s2aUtils.getMtlsS2AAddress(); + assertTrue(plaintextS2AAddress.isEmpty()); + assertTrue(mtlsS2AAddress.isEmpty()); } } From 3d68cef4ab01c2990fd1a7395cedef24fc0f284f Mon Sep 17 00:00:00 2001 From: Riya Mehta Date: Fri, 23 Feb 2024 18:15:15 +0000 Subject: [PATCH 06/44] utils. --- .../com/google/auth/oauth2/MtlsConfig.java | 55 ++++++++++ .../java/com/google/auth/oauth2/S2A.java | 101 +++++++++++++++++ .../oauth2/MockMetadataServerTransport.java | 62 +++++++++++ .../google/auth/oauth2/MtlsConfigTest.java | 47 ++++++++ .../com/google/auth/oauth2/S2ATest.java | 102 ++++++++++++++++++ oauth2_http/pom.xml | 5 + 6 files changed, 372 insertions(+) create mode 100644 oauth2_http/java/com/google/auth/oauth2/MtlsConfig.java create mode 100644 oauth2_http/java/com/google/auth/oauth2/S2A.java create mode 100644 oauth2_http/javatests/com/google/auth/oauth2/MtlsConfigTest.java create mode 100644 oauth2_http/javatests/com/google/auth/oauth2/S2ATest.java diff --git a/oauth2_http/java/com/google/auth/oauth2/MtlsConfig.java b/oauth2_http/java/com/google/auth/oauth2/MtlsConfig.java new file mode 100644 index 000000000..18ad6b34d --- /dev/null +++ b/oauth2_http/java/com/google/auth/oauth2/MtlsConfig.java @@ -0,0 +1,55 @@ +package com.google.auth.oauth2; + +import org.joda.time.MutableDateTime; +import javax.annotation.concurrent.NotThreadSafe; + +/** + * Holds an mTLS configuration (consists of address of S2A) retrieved from the Metadata Server. + * + * Instances of {@link MtlsConfig} are not thread safe. Calls to {@code reset}, {@code getS2AAddress}, {@code isValid} + * and {@code getExpiry} should be made from a synchronized block. + */ +@NotThreadSafe +public final class MtlsConfig{ + private String s2aAddress; + private MutableDateTime expiry; + + private static final int MTLS_AUTOCONFIG_EXPIRATION_HOURS = 1; + + public static MtlsConfig createNullMtlsConfig() { + return new MtlsConfig("", null); + } + + public static MtlsConfig createMtlsConfig(String addr) { + MutableDateTime expiry = MutableDateTime.now(); + expiry.addHours(MTLS_AUTOCONFIG_EXPIRATION_HOURS); + return new MtlsConfig(addr, expiry); + } + + public void reset(String addr) { + this.s2aAddress = addr; + this.expiry = MutableDateTime.now(); + this.expiry.addHours(MTLS_AUTOCONFIG_EXPIRATION_HOURS); + } + + public String getS2AAddress() { + return s2aAddress; + } + + public boolean isValid() { + if (expiry == null) { return false; } + if (MutableDateTime.now().isAfter(this.expiry)) { + return false; + } + return true; + } + + public MutableDateTime getExpiry() { + return expiry; + } + + private MtlsConfig(String addr, MutableDateTime expiry) { + this.s2aAddress = addr; + this.expiry = expiry; + } +} diff --git a/oauth2_http/java/com/google/auth/oauth2/S2A.java b/oauth2_http/java/com/google/auth/oauth2/S2A.java new file mode 100644 index 000000000..7bdc3727c --- /dev/null +++ b/oauth2_http/java/com/google/auth/oauth2/S2A.java @@ -0,0 +1,101 @@ +package com.google.auth.oauth2; + +import com.google.api.client.http.HttpRequest; +import com.google.api.client.http.HttpResponse; +import com.google.api.client.http.HttpResponseException; +import com.google.api.client.http.HttpStatusCodes; +import com.google.api.client.http.HttpResponseException; +import com.google.api.client.http.GenericUrl; +import com.google.api.client.util.GenericData; +import com.google.api.client.json.JsonObjectParser; +import com.google.auth.http.HttpTransportFactory; +import com.google.common.collect.Iterables; +import java.io.InputStream; +import java.io.IOException; +import java.util.ServiceLoader; +import java.util.logging.Logger; +import java.util.logging.Level; +import javax.annotation.concurrent.ThreadSafe; + +/** + * Utilities to fetch the S2A (Secure Session Agent) address from the mTLS configuration. + * + * Periodically refresh the mTLS configuration by getting a new one from the MDS mTLS autoconfig endpoint. + */ +@ThreadSafe +public final class S2A { + public static final String DEFAULT_METADATA_SERVER_URL = "http://metadata.google.internal"; + public static final String MTLS_CONFIG_ENDPOINT = "/instance/platform-security/auto-mtls-configuration"; + + private static final String METADATA_FLAVOR = "Metadata-Flavor"; + private static final String GOOGLE = "Google"; + private static final String PARSE_ERROR_S2A = "Error parsing Mtls Auto Config response."; + + private MtlsConfig config; + + private transient HttpTransportFactory transportFactory; + + public S2A() { + config = MtlsConfig.createNullMtlsConfig(); + } + + public void setHttpTransportFactory(HttpTransportFactory tf) { + this.transportFactory = tf; + } + + /** + * Returns the S2A Address from the mTLS config. Refreshes the config if it is expired. + */ + public synchronized String getS2AAddress() { + if (!config.isValid()) { + String addr = getMdsMtlsConfigData(); + config.reset(addr); + } + return config.getS2AAddress(); + } + + /** + * Queries the MDS mTLS Autoconfiguration endpoint and returns the S2A address. Returns an empty address on error. + */ + private String getMdsMtlsConfigData() { + String s2aAddress = ""; + try { + if (transportFactory == null) { + transportFactory = Iterables.getFirst(ServiceLoader.load(HttpTransportFactory.class), OAuth2Utils.HTTP_TRANSPORT_FACTORY); + } + String url = getMdsMtlsEndpoint(DefaultCredentialsProvider.DEFAULT); + GenericUrl genericUrl = new GenericUrl(url); + HttpRequest request = transportFactory.create().createRequestFactory().buildGetRequest(genericUrl); + JsonObjectParser parser = new JsonObjectParser(OAuth2Utils.JSON_FACTORY); + request.setParser(parser); + request.getHeaders().set(METADATA_FLAVOR, GOOGLE); + request.setThrowExceptionOnExecuteError(false); + HttpResponse response = request.execute(); + + if (!response.isSuccessStatusCode()) { + return ""; + } + + InputStream content = response.getContent(); + if (content == null) { + return ""; + } + GenericData responseData = response.parseAs(GenericData.class); + s2aAddress = OAuth2Utils.validateString(responseData, "s2a", PARSE_ERROR_S2A); + } catch(IOException e) { + return ""; + } + return s2aAddress; + } + + /** + * @return MDS mTLS autoconfig endpoint. + */ + private String getMdsMtlsEndpoint(DefaultCredentialsProvider provider) { + String metadataServerAddress = provider.getEnv(DefaultCredentialsProvider.GCE_METADATA_HOST_ENV_VAR); + if (metadataServerAddress != null) { + return "http://" + metadataServerAddress + MTLS_CONFIG_ENDPOINT; + } + return DEFAULT_METADATA_SERVER_URL + MTLS_CONFIG_ENDPOINT; + } +} diff --git a/oauth2_http/javatests/com/google/auth/oauth2/MockMetadataServerTransport.java b/oauth2_http/javatests/com/google/auth/oauth2/MockMetadataServerTransport.java index 66878d4c6..1c78670ff 100644 --- a/oauth2_http/javatests/com/google/auth/oauth2/MockMetadataServerTransport.java +++ b/oauth2_http/javatests/com/google/auth/oauth2/MockMetadataServerTransport.java @@ -60,6 +60,10 @@ public class MockMetadataServerTransport extends MockHttpTransport { private byte[] signature; + private String s2aAddress; + + private boolean emptyContent; + public MockMetadataServerTransport() {} public void setAccessToken(String accessToken) { @@ -82,6 +86,26 @@ public void setIdToken(String idToken) { this.idToken = idToken; } + public void setS2AAddress(String address) { + this.s2aAddress = address; + } + + public void setEmptyContent(boolean emptyContent) { + this.emptyContent = emptyContent; + } + + public String getAddr() { + return s2aAddress; + } + + public Integer getCode() { + return requestStatusCode; + } + + public boolean getEmpty() { + return emptyContent; + } + @Override public LowLevelHttpRequest buildRequest(String method, String url) throws IOException { if (url.equals(ComputeEngineCredentials.getTokenServerEncodedUrl())) { @@ -92,6 +116,8 @@ public LowLevelHttpRequest buildRequest(String method, String url) throws IOExce return getMockRequestForSign(url); } else if (isIdentityDocumentUrl(url)) { return getMockRequestForIdentityDocument(url); + } else if (isMtlsConfigRequestUrl(url)) { + return getMockRequestForMtlsConfig(url); } return new MockLowLevelHttpRequest(url) { @Override @@ -233,6 +259,38 @@ public LowLevelHttpResponse execute() throws IOException { }; } + private MockLowLevelHttpRequest getMockRequestForMtlsConfig(String url) { + return new MockLowLevelHttpRequest(url) { + @Override + public LowLevelHttpResponse execute() throws IOException { + + String metadataRequestHeader = getFirstHeaderValue("Metadata-Flavor"); + if (!"Google".equals(metadataRequestHeader)) { + throw new IOException("Metadata request header not found"); + } + + // Create the JSON response + GenericJson content = new GenericJson(); + content.setFactory(OAuth2Utils.JSON_FACTORY); + content.put("s2a", s2aAddress); + String contentText = content.toPrettyString(); + + MockLowLevelHttpResponse response = new MockLowLevelHttpResponse(); + + if(requestStatusCode != null) { + response.setStatusCode(requestStatusCode); + } + if(emptyContent == true) { + return response.setZeroContent(); + } + response.setContentType(Json.MEDIA_TYPE) + .setContent(contentText); + return response; + } + }; + + } + protected boolean isGetServiceAccountsUrl(String url) { return url.equals(ComputeEngineCredentials.getServiceAccountsUrl()); } @@ -246,4 +304,8 @@ protected boolean isSignRequestUrl(String url) { protected boolean isIdentityDocumentUrl(String url) { return url.startsWith(String.format(ComputeEngineCredentials.getIdentityDocumentUrl())); } + + protected boolean isMtlsConfigRequestUrl(String url) { + return s2aAddress != null && url.equals(String.format(S2A.DEFAULT_METADATA_SERVER_URL + S2A.MTLS_CONFIG_ENDPOINT)); + } } diff --git a/oauth2_http/javatests/com/google/auth/oauth2/MtlsConfigTest.java b/oauth2_http/javatests/com/google/auth/oauth2/MtlsConfigTest.java new file mode 100644 index 000000000..b2cf003a6 --- /dev/null +++ b/oauth2_http/javatests/com/google/auth/oauth2/MtlsConfigTest.java @@ -0,0 +1,47 @@ +package com.google.auth.oauth2; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.joda.time.MutableDateTime; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + + +/** Test cases for {@link MtlsConfig}.*/ + +@RunWith(JUnit4.class) +public class MtlsConfigTest { + private static final String S2A_ADDRESS_A = "addr_a"; + private static final String S2A_ADDRESS_B = "addr_b"; + + @Test + public void NullMtlsConfig_invalid() { + MtlsConfig config = MtlsConfig.createNullMtlsConfig(); + assertEquals("", config.getS2AAddress()); + assertFalse(config.isValid()); + } + + @Test + public void NonNullMtlsConfig_valid() { + MtlsConfig config = MtlsConfig.createMtlsConfig(S2A_ADDRESS_A); + assertEquals(S2A_ADDRESS_A, config.getS2AAddress()); + assertTrue(config.isValid()); + } + + @Test + public void resetAddress_newExpiryGreater() throws Exception { + MtlsConfig config = MtlsConfig.createMtlsConfig(S2A_ADDRESS_A); + MutableDateTime e1 = config.getExpiry(); + assertEquals(S2A_ADDRESS_A, config.getS2AAddress()); + Thread.sleep(2000); + config.reset(S2A_ADDRESS_B); + assertEquals(S2A_ADDRESS_B, config.getS2AAddress()); + MutableDateTime e2 = config.getExpiry(); + int value = e2.compareTo(e1); + assertTrue(value > 0); + } + +} diff --git a/oauth2_http/javatests/com/google/auth/oauth2/S2ATest.java b/oauth2_http/javatests/com/google/auth/oauth2/S2ATest.java new file mode 100644 index 000000000..e7583e596 --- /dev/null +++ b/oauth2_http/javatests/com/google/auth/oauth2/S2ATest.java @@ -0,0 +1,102 @@ +package com.google.auth.oauth2; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import com.google.api.client.http.HttpStatusCodes; +import com.google.api.client.testing.http.MockHttpTransport; +import com.google.auth.http.HttpTransportFactory; +import com.google.auth.oauth2.ComputeEngineCredentialsTest.MockMetadataServerTransportFactory; +import java.util.concurrent.ExecutorService; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** Test cases for {@link S2A}.*/ +@RunWith(JUnit4.class) +public class S2ATest { + + private static final String S2A_ADDRESS_A = "addr_a"; + private static final String S2A_ADDRESS_B = "addr_b"; + + @Test + public void getS2AAddress_validAddress() { + MockMetadataServerTransportFactory transportFactory = new MockMetadataServerTransportFactory(); + transportFactory.transport.setS2AAddress(S2A_ADDRESS_A); + transportFactory.transport.setRequestStatusCode(HttpStatusCodes.STATUS_CODE_OK); + + S2A s2aUtils = new S2A(); + s2aUtils.setHttpTransportFactory(transportFactory); + String s2aAddress = s2aUtils.getS2AAddress(); + assertEquals(S2A_ADDRESS_A, s2aAddress); + } + + @Test + public void getS2AAddress_queryEndpointResponseErrorCode_emptyAddress() { + MockMetadataServerTransportFactory transportFactory = new MockMetadataServerTransportFactory(); + transportFactory.transport.setS2AAddress(S2A_ADDRESS_A); + transportFactory.transport.setRequestStatusCode(HttpStatusCodes.STATUS_CODE_SERVICE_UNAVAILABLE); + + S2A s2aUtils = new S2A(); + s2aUtils.setHttpTransportFactory(transportFactory); + String s2aAddress = s2aUtils.getS2AAddress(); + assertTrue(s2aAddress.isEmpty()); + } + + @Test + public void getS2AAddress_queryEndpointResponseEmpty_emptyAddress() { + MockMetadataServerTransportFactory transportFactory = new MockMetadataServerTransportFactory(); + transportFactory.transport.setS2AAddress(S2A_ADDRESS_A); + transportFactory.transport.setRequestStatusCode(HttpStatusCodes.STATUS_CODE_OK); + transportFactory.transport.setEmptyContent(true); + + S2A s2aUtils = new S2A(); + s2aUtils.setHttpTransportFactory(transportFactory); + String s2aAddress = s2aUtils.getS2AAddress(); + assertTrue(s2aAddress.isEmpty()); + } + + @Test + public void getS2AAdress_multipleThreads_validAddress() throws Exception{ + MockMetadataServerTransportFactory transportFactoryA = new MockMetadataServerTransportFactory(); + transportFactoryA.transport.setS2AAddress(S2A_ADDRESS_A); + transportFactoryA.transport.setRequestStatusCode(HttpStatusCodes.STATUS_CODE_OK); + + MockMetadataServerTransportFactory transportFactoryB = new MockMetadataServerTransportFactory(); + transportFactoryB.transport.setS2AAddress(S2A_ADDRESS_B); + transportFactoryB.transport.setRequestStatusCode(HttpStatusCodes.STATUS_CODE_OK); + + S2A s2aUtils = new S2A(); + + DoGetS2AAddress doGetS2AAddressA = new DoGetS2AAddress(transportFactoryA, S2A_ADDRESS_A, s2aUtils); + DoGetS2AAddress doGetS2AAddressB = new DoGetS2AAddress(transportFactoryB, S2A_ADDRESS_A, s2aUtils); + + doGetS2AAddressA.start(); + Thread.sleep(2000); + doGetS2AAddressB.start(); + + doGetS2AAddressA.join(); + doGetS2AAddressB.join(); + } + + private class DoGetS2AAddress extends Thread { + HttpTransportFactory transportFactory; + String exp_addr; + S2A s2aUtils; + public DoGetS2AAddress(HttpTransportFactory transportFactory, String addr, S2A s2aUtils) { + super(); + this.transportFactory = transportFactory; + this.exp_addr = addr; + this.s2aUtils = s2aUtils; + } + + @Override + public void run() { + s2aUtils.setHttpTransportFactory(transportFactory); + String s2aAddress = s2aUtils.getS2AAddress(); + assertEquals(exp_addr, s2aAddress); + } + } +} + + diff --git a/oauth2_http/pom.xml b/oauth2_http/pom.xml index c14201002..e5756eda6 100644 --- a/oauth2_http/pom.xml +++ b/oauth2_http/pom.xml @@ -253,6 +253,11 @@ hamcrest-core 1.3 test + + + joda-time + joda-time + 2.12.7 org.mockito From 6d75a4e2ae23058a194dccef32f40a6f64923200 Mon Sep 17 00:00:00 2001 From: Riya Mehta Date: Thu, 29 Feb 2024 14:40:15 -0800 Subject: [PATCH 07/44] formatted. --- .../com/google/auth/oauth2/MtlsConfig.java | 94 +++++----- .../java/com/google/auth/oauth2/S2A.java | 146 ++++++++------- .../oauth2/MockMetadataServerTransport.java | 53 +++--- .../google/auth/oauth2/MtlsConfigTest.java | 63 +++---- .../com/google/auth/oauth2/S2ATest.java | 172 +++++++++--------- 5 files changed, 262 insertions(+), 266 deletions(-) diff --git a/oauth2_http/java/com/google/auth/oauth2/MtlsConfig.java b/oauth2_http/java/com/google/auth/oauth2/MtlsConfig.java index 18ad6b34d..527745027 100644 --- a/oauth2_http/java/com/google/auth/oauth2/MtlsConfig.java +++ b/oauth2_http/java/com/google/auth/oauth2/MtlsConfig.java @@ -1,55 +1,57 @@ package com.google.auth.oauth2; -import org.joda.time.MutableDateTime; import javax.annotation.concurrent.NotThreadSafe; +import org.joda.time.MutableDateTime; /** * Holds an mTLS configuration (consists of address of S2A) retrieved from the Metadata Server. * - * Instances of {@link MtlsConfig} are not thread safe. Calls to {@code reset}, {@code getS2AAddress}, {@code isValid} - * and {@code getExpiry} should be made from a synchronized block. - */ + *

Instances of {@link MtlsConfig} are not thread safe. Calls to {@code reset}, {@code + * getS2AAddress}, {@code isValid} and {@code getExpiry} should be made from a synchronized block. + */ @NotThreadSafe -public final class MtlsConfig{ - private String s2aAddress; - private MutableDateTime expiry; - - private static final int MTLS_AUTOCONFIG_EXPIRATION_HOURS = 1; - - public static MtlsConfig createNullMtlsConfig() { - return new MtlsConfig("", null); - } - - public static MtlsConfig createMtlsConfig(String addr) { - MutableDateTime expiry = MutableDateTime.now(); - expiry.addHours(MTLS_AUTOCONFIG_EXPIRATION_HOURS); - return new MtlsConfig(addr, expiry); - } - - public void reset(String addr) { - this.s2aAddress = addr; - this.expiry = MutableDateTime.now(); - this.expiry.addHours(MTLS_AUTOCONFIG_EXPIRATION_HOURS); - } - - public String getS2AAddress() { - return s2aAddress; - } - - public boolean isValid() { - if (expiry == null) { return false; } - if (MutableDateTime.now().isAfter(this.expiry)) { - return false; - } - return true; - } - - public MutableDateTime getExpiry() { - return expiry; - } - - private MtlsConfig(String addr, MutableDateTime expiry) { - this.s2aAddress = addr; - this.expiry = expiry; - } +public final class MtlsConfig { + private String s2aAddress; + private MutableDateTime expiry; + + private static final int MTLS_AUTOCONFIG_EXPIRATION_HOURS = 1; + + public static MtlsConfig createNullMtlsConfig() { + return new MtlsConfig("", null); + } + + public static MtlsConfig createMtlsConfig(String addr) { + MutableDateTime expiry = MutableDateTime.now(); + expiry.addHours(MTLS_AUTOCONFIG_EXPIRATION_HOURS); + return new MtlsConfig(addr, expiry); + } + + public void reset(String addr) { + this.s2aAddress = addr; + this.expiry = MutableDateTime.now(); + this.expiry.addHours(MTLS_AUTOCONFIG_EXPIRATION_HOURS); + } + + public String getS2AAddress() { + return s2aAddress; + } + + public boolean isValid() { + if (expiry == null) { + return false; + } + if (MutableDateTime.now().isAfter(this.expiry)) { + return false; + } + return true; + } + + public MutableDateTime getExpiry() { + return expiry; + } + + private MtlsConfig(String addr, MutableDateTime expiry) { + this.s2aAddress = addr; + this.expiry = expiry; + } } diff --git a/oauth2_http/java/com/google/auth/oauth2/S2A.java b/oauth2_http/java/com/google/auth/oauth2/S2A.java index 7bdc3727c..5b57bad94 100644 --- a/oauth2_http/java/com/google/auth/oauth2/S2A.java +++ b/oauth2_http/java/com/google/auth/oauth2/S2A.java @@ -1,101 +1,99 @@ package com.google.auth.oauth2; +import com.google.api.client.http.GenericUrl; import com.google.api.client.http.HttpRequest; import com.google.api.client.http.HttpResponse; -import com.google.api.client.http.HttpResponseException; -import com.google.api.client.http.HttpStatusCodes; -import com.google.api.client.http.HttpResponseException; -import com.google.api.client.http.GenericUrl; -import com.google.api.client.util.GenericData; import com.google.api.client.json.JsonObjectParser; +import com.google.api.client.util.GenericData; import com.google.auth.http.HttpTransportFactory; import com.google.common.collect.Iterables; -import java.io.InputStream; import java.io.IOException; +import java.io.InputStream; import java.util.ServiceLoader; -import java.util.logging.Logger; -import java.util.logging.Level; import javax.annotation.concurrent.ThreadSafe; /** * Utilities to fetch the S2A (Secure Session Agent) address from the mTLS configuration. * - * Periodically refresh the mTLS configuration by getting a new one from the MDS mTLS autoconfig endpoint. + *

Periodically refresh the mTLS configuration by getting a new one from the MDS mTLS autoconfig + * endpoint. */ @ThreadSafe public final class S2A { - public static final String DEFAULT_METADATA_SERVER_URL = "http://metadata.google.internal"; - public static final String MTLS_CONFIG_ENDPOINT = "/instance/platform-security/auto-mtls-configuration"; + public static final String DEFAULT_METADATA_SERVER_URL = "http://metadata.google.internal"; + public static final String MTLS_CONFIG_ENDPOINT = + "/instance/platform-security/auto-mtls-configuration"; + + private static final String METADATA_FLAVOR = "Metadata-Flavor"; + private static final String GOOGLE = "Google"; + private static final String PARSE_ERROR_S2A = "Error parsing Mtls Auto Config response."; - private static final String METADATA_FLAVOR = "Metadata-Flavor"; - private static final String GOOGLE = "Google"; - private static final String PARSE_ERROR_S2A = "Error parsing Mtls Auto Config response."; + private MtlsConfig config; - private MtlsConfig config; + private transient HttpTransportFactory transportFactory; - private transient HttpTransportFactory transportFactory; + public S2A() { + config = MtlsConfig.createNullMtlsConfig(); + } - public S2A() { - config = MtlsConfig.createNullMtlsConfig(); - } + public void setHttpTransportFactory(HttpTransportFactory tf) { + this.transportFactory = tf; + } - public void setHttpTransportFactory(HttpTransportFactory tf) { - this.transportFactory = tf; - } + /** Returns the S2A Address from the mTLS config. Refreshes the config if it is expired. */ + public synchronized String getS2AAddress() { + if (!config.isValid()) { + String addr = getMdsMtlsConfigData(); + config.reset(addr); + } + return config.getS2AAddress(); + } - /** - * Returns the S2A Address from the mTLS config. Refreshes the config if it is expired. - */ - public synchronized String getS2AAddress() { - if (!config.isValid()) { - String addr = getMdsMtlsConfigData(); - config.reset(addr); - } - return config.getS2AAddress(); - } + /** + * Queries the MDS mTLS Autoconfiguration endpoint and returns the S2A address. Returns an empty + * address on error. + */ + private String getMdsMtlsConfigData() { + String s2aAddress = ""; + try { + if (transportFactory == null) { + transportFactory = + Iterables.getFirst( + ServiceLoader.load(HttpTransportFactory.class), OAuth2Utils.HTTP_TRANSPORT_FACTORY); + } + String url = getMdsMtlsEndpoint(DefaultCredentialsProvider.DEFAULT); + GenericUrl genericUrl = new GenericUrl(url); + HttpRequest request = + transportFactory.create().createRequestFactory().buildGetRequest(genericUrl); + JsonObjectParser parser = new JsonObjectParser(OAuth2Utils.JSON_FACTORY); + request.setParser(parser); + request.getHeaders().set(METADATA_FLAVOR, GOOGLE); + request.setThrowExceptionOnExecuteError(false); + HttpResponse response = request.execute(); - /** - * Queries the MDS mTLS Autoconfiguration endpoint and returns the S2A address. Returns an empty address on error. - */ - private String getMdsMtlsConfigData() { - String s2aAddress = ""; - try { - if (transportFactory == null) { - transportFactory = Iterables.getFirst(ServiceLoader.load(HttpTransportFactory.class), OAuth2Utils.HTTP_TRANSPORT_FACTORY); - } - String url = getMdsMtlsEndpoint(DefaultCredentialsProvider.DEFAULT); - GenericUrl genericUrl = new GenericUrl(url); - HttpRequest request = transportFactory.create().createRequestFactory().buildGetRequest(genericUrl); - JsonObjectParser parser = new JsonObjectParser(OAuth2Utils.JSON_FACTORY); - request.setParser(parser); - request.getHeaders().set(METADATA_FLAVOR, GOOGLE); - request.setThrowExceptionOnExecuteError(false); - HttpResponse response = request.execute(); + if (!response.isSuccessStatusCode()) { + return ""; + } - if (!response.isSuccessStatusCode()) { - return ""; - } - - InputStream content = response.getContent(); - if (content == null) { - return ""; - } - GenericData responseData = response.parseAs(GenericData.class); - s2aAddress = OAuth2Utils.validateString(responseData, "s2a", PARSE_ERROR_S2A); - } catch(IOException e) { - return ""; - } - return s2aAddress; - } + InputStream content = response.getContent(); + if (content == null) { + return ""; + } + GenericData responseData = response.parseAs(GenericData.class); + s2aAddress = OAuth2Utils.validateString(responseData, "s2a", PARSE_ERROR_S2A); + } catch (IOException e) { + return ""; + } + return s2aAddress; + } - /** - * @return MDS mTLS autoconfig endpoint. - */ - private String getMdsMtlsEndpoint(DefaultCredentialsProvider provider) { - String metadataServerAddress = provider.getEnv(DefaultCredentialsProvider.GCE_METADATA_HOST_ENV_VAR); - if (metadataServerAddress != null) { - return "http://" + metadataServerAddress + MTLS_CONFIG_ENDPOINT; - } - return DEFAULT_METADATA_SERVER_URL + MTLS_CONFIG_ENDPOINT; - } + /** @return MDS mTLS autoconfig endpoint. */ + private String getMdsMtlsEndpoint(DefaultCredentialsProvider provider) { + String metadataServerAddress = + provider.getEnv(DefaultCredentialsProvider.GCE_METADATA_HOST_ENV_VAR); + if (metadataServerAddress != null) { + return "http://" + metadataServerAddress + MTLS_CONFIG_ENDPOINT; + } + return DEFAULT_METADATA_SERVER_URL + MTLS_CONFIG_ENDPOINT; + } } diff --git a/oauth2_http/javatests/com/google/auth/oauth2/MockMetadataServerTransport.java b/oauth2_http/javatests/com/google/auth/oauth2/MockMetadataServerTransport.java index 1c78670ff..242990223 100644 --- a/oauth2_http/javatests/com/google/auth/oauth2/MockMetadataServerTransport.java +++ b/oauth2_http/javatests/com/google/auth/oauth2/MockMetadataServerTransport.java @@ -61,7 +61,7 @@ public class MockMetadataServerTransport extends MockHttpTransport { private byte[] signature; private String s2aAddress; - + private boolean emptyContent; public MockMetadataServerTransport() {} @@ -87,23 +87,23 @@ public void setIdToken(String idToken) { } public void setS2AAddress(String address) { - this.s2aAddress = address; + this.s2aAddress = address; } - + public void setEmptyContent(boolean emptyContent) { - this.emptyContent = emptyContent; + this.emptyContent = emptyContent; } public String getAddr() { - return s2aAddress; + return s2aAddress; } public Integer getCode() { - return requestStatusCode; + return requestStatusCode; } public boolean getEmpty() { - return emptyContent; + return emptyContent; } @Override @@ -264,31 +264,29 @@ private MockLowLevelHttpRequest getMockRequestForMtlsConfig(String url) { @Override public LowLevelHttpResponse execute() throws IOException { - String metadataRequestHeader = getFirstHeaderValue("Metadata-Flavor"); - if (!"Google".equals(metadataRequestHeader)) { - throw new IOException("Metadata request header not found"); - } - + String metadataRequestHeader = getFirstHeaderValue("Metadata-Flavor"); + if (!"Google".equals(metadataRequestHeader)) { + throw new IOException("Metadata request header not found"); + } + // Create the JSON response GenericJson content = new GenericJson(); content.setFactory(OAuth2Utils.JSON_FACTORY); content.put("s2a", s2aAddress); - String contentText = content.toPrettyString(); - - MockLowLevelHttpResponse response = new MockLowLevelHttpResponse(); - - if(requestStatusCode != null) { - response.setStatusCode(requestStatusCode); - } - if(emptyContent == true) { - return response.setZeroContent(); - } - response.setContentType(Json.MEDIA_TYPE) - .setContent(contentText); - return response; + String contentText = content.toPrettyString(); + + MockLowLevelHttpResponse response = new MockLowLevelHttpResponse(); + + if (requestStatusCode != null) { + response.setStatusCode(requestStatusCode); + } + if (emptyContent == true) { + return response.setZeroContent(); + } + response.setContentType(Json.MEDIA_TYPE).setContent(contentText); + return response; } }; - } protected boolean isGetServiceAccountsUrl(String url) { @@ -306,6 +304,7 @@ protected boolean isIdentityDocumentUrl(String url) { } protected boolean isMtlsConfigRequestUrl(String url) { - return s2aAddress != null && url.equals(String.format(S2A.DEFAULT_METADATA_SERVER_URL + S2A.MTLS_CONFIG_ENDPOINT)); + return s2aAddress != null + && url.equals(String.format(S2A.DEFAULT_METADATA_SERVER_URL + S2A.MTLS_CONFIG_ENDPOINT)); } } diff --git a/oauth2_http/javatests/com/google/auth/oauth2/MtlsConfigTest.java b/oauth2_http/javatests/com/google/auth/oauth2/MtlsConfigTest.java index b2cf003a6..648a661c4 100644 --- a/oauth2_http/javatests/com/google/auth/oauth2/MtlsConfigTest.java +++ b/oauth2_http/javatests/com/google/auth/oauth2/MtlsConfigTest.java @@ -9,39 +9,36 @@ import org.junit.runner.RunWith; import org.junit.runners.JUnit4; - -/** Test cases for {@link MtlsConfig}.*/ - +/** Test cases for {@link MtlsConfig}. */ @RunWith(JUnit4.class) public class MtlsConfigTest { - private static final String S2A_ADDRESS_A = "addr_a"; - private static final String S2A_ADDRESS_B = "addr_b"; - - @Test - public void NullMtlsConfig_invalid() { - MtlsConfig config = MtlsConfig.createNullMtlsConfig(); - assertEquals("", config.getS2AAddress()); - assertFalse(config.isValid()); - } - - @Test - public void NonNullMtlsConfig_valid() { - MtlsConfig config = MtlsConfig.createMtlsConfig(S2A_ADDRESS_A); - assertEquals(S2A_ADDRESS_A, config.getS2AAddress()); - assertTrue(config.isValid()); - } - - @Test - public void resetAddress_newExpiryGreater() throws Exception { - MtlsConfig config = MtlsConfig.createMtlsConfig(S2A_ADDRESS_A); - MutableDateTime e1 = config.getExpiry(); - assertEquals(S2A_ADDRESS_A, config.getS2AAddress()); - Thread.sleep(2000); - config.reset(S2A_ADDRESS_B); - assertEquals(S2A_ADDRESS_B, config.getS2AAddress()); - MutableDateTime e2 = config.getExpiry(); - int value = e2.compareTo(e1); - assertTrue(value > 0); - } - + private static final String S2A_ADDRESS_A = "addr_a"; + private static final String S2A_ADDRESS_B = "addr_b"; + + @Test + public void NullMtlsConfig_invalid() { + MtlsConfig config = MtlsConfig.createNullMtlsConfig(); + assertEquals("", config.getS2AAddress()); + assertFalse(config.isValid()); + } + + @Test + public void NonNullMtlsConfig_valid() { + MtlsConfig config = MtlsConfig.createMtlsConfig(S2A_ADDRESS_A); + assertEquals(S2A_ADDRESS_A, config.getS2AAddress()); + assertTrue(config.isValid()); + } + + @Test + public void resetAddress_newExpiryGreater() throws Exception { + MtlsConfig config = MtlsConfig.createMtlsConfig(S2A_ADDRESS_A); + MutableDateTime e1 = config.getExpiry(); + assertEquals(S2A_ADDRESS_A, config.getS2AAddress()); + Thread.sleep(2000); + config.reset(S2A_ADDRESS_B); + assertEquals(S2A_ADDRESS_B, config.getS2AAddress()); + MutableDateTime e2 = config.getExpiry(); + int value = e2.compareTo(e1); + assertTrue(value > 0); + } } diff --git a/oauth2_http/javatests/com/google/auth/oauth2/S2ATest.java b/oauth2_http/javatests/com/google/auth/oauth2/S2ATest.java index e7583e596..46535d8c3 100644 --- a/oauth2_http/javatests/com/google/auth/oauth2/S2ATest.java +++ b/oauth2_http/javatests/com/google/auth/oauth2/S2ATest.java @@ -4,99 +4,99 @@ import static org.junit.Assert.assertTrue; import com.google.api.client.http.HttpStatusCodes; -import com.google.api.client.testing.http.MockHttpTransport; import com.google.auth.http.HttpTransportFactory; import com.google.auth.oauth2.ComputeEngineCredentialsTest.MockMetadataServerTransportFactory; -import java.util.concurrent.ExecutorService; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; -/** Test cases for {@link S2A}.*/ +/** Test cases for {@link S2A}. */ @RunWith(JUnit4.class) public class S2ATest { - private static final String S2A_ADDRESS_A = "addr_a"; - private static final String S2A_ADDRESS_B = "addr_b"; - - @Test - public void getS2AAddress_validAddress() { - MockMetadataServerTransportFactory transportFactory = new MockMetadataServerTransportFactory(); - transportFactory.transport.setS2AAddress(S2A_ADDRESS_A); - transportFactory.transport.setRequestStatusCode(HttpStatusCodes.STATUS_CODE_OK); - - S2A s2aUtils = new S2A(); - s2aUtils.setHttpTransportFactory(transportFactory); - String s2aAddress = s2aUtils.getS2AAddress(); - assertEquals(S2A_ADDRESS_A, s2aAddress); - } - - @Test - public void getS2AAddress_queryEndpointResponseErrorCode_emptyAddress() { - MockMetadataServerTransportFactory transportFactory = new MockMetadataServerTransportFactory(); - transportFactory.transport.setS2AAddress(S2A_ADDRESS_A); - transportFactory.transport.setRequestStatusCode(HttpStatusCodes.STATUS_CODE_SERVICE_UNAVAILABLE); - - S2A s2aUtils = new S2A(); - s2aUtils.setHttpTransportFactory(transportFactory); - String s2aAddress = s2aUtils.getS2AAddress(); - assertTrue(s2aAddress.isEmpty()); - } - - @Test - public void getS2AAddress_queryEndpointResponseEmpty_emptyAddress() { - MockMetadataServerTransportFactory transportFactory = new MockMetadataServerTransportFactory(); - transportFactory.transport.setS2AAddress(S2A_ADDRESS_A); - transportFactory.transport.setRequestStatusCode(HttpStatusCodes.STATUS_CODE_OK); - transportFactory.transport.setEmptyContent(true); - - S2A s2aUtils = new S2A(); - s2aUtils.setHttpTransportFactory(transportFactory); - String s2aAddress = s2aUtils.getS2AAddress(); - assertTrue(s2aAddress.isEmpty()); - } - - @Test - public void getS2AAdress_multipleThreads_validAddress() throws Exception{ - MockMetadataServerTransportFactory transportFactoryA = new MockMetadataServerTransportFactory(); - transportFactoryA.transport.setS2AAddress(S2A_ADDRESS_A); - transportFactoryA.transport.setRequestStatusCode(HttpStatusCodes.STATUS_CODE_OK); - - MockMetadataServerTransportFactory transportFactoryB = new MockMetadataServerTransportFactory(); - transportFactoryB.transport.setS2AAddress(S2A_ADDRESS_B); - transportFactoryB.transport.setRequestStatusCode(HttpStatusCodes.STATUS_CODE_OK); - - S2A s2aUtils = new S2A(); - - DoGetS2AAddress doGetS2AAddressA = new DoGetS2AAddress(transportFactoryA, S2A_ADDRESS_A, s2aUtils); - DoGetS2AAddress doGetS2AAddressB = new DoGetS2AAddress(transportFactoryB, S2A_ADDRESS_A, s2aUtils); - - doGetS2AAddressA.start(); - Thread.sleep(2000); - doGetS2AAddressB.start(); - - doGetS2AAddressA.join(); - doGetS2AAddressB.join(); - } - - private class DoGetS2AAddress extends Thread { - HttpTransportFactory transportFactory; - String exp_addr; - S2A s2aUtils; - public DoGetS2AAddress(HttpTransportFactory transportFactory, String addr, S2A s2aUtils) { - super(); - this.transportFactory = transportFactory; - this.exp_addr = addr; - this.s2aUtils = s2aUtils; - } - - @Override - public void run() { - s2aUtils.setHttpTransportFactory(transportFactory); - String s2aAddress = s2aUtils.getS2AAddress(); - assertEquals(exp_addr, s2aAddress); - } - } + private static final String S2A_ADDRESS_A = "addr_a"; + private static final String S2A_ADDRESS_B = "addr_b"; + + @Test + public void getS2AAddress_validAddress() { + MockMetadataServerTransportFactory transportFactory = new MockMetadataServerTransportFactory(); + transportFactory.transport.setS2AAddress(S2A_ADDRESS_A); + transportFactory.transport.setRequestStatusCode(HttpStatusCodes.STATUS_CODE_OK); + + S2A s2aUtils = new S2A(); + s2aUtils.setHttpTransportFactory(transportFactory); + String s2aAddress = s2aUtils.getS2AAddress(); + assertEquals(S2A_ADDRESS_A, s2aAddress); + } + + @Test + public void getS2AAddress_queryEndpointResponseErrorCode_emptyAddress() { + MockMetadataServerTransportFactory transportFactory = new MockMetadataServerTransportFactory(); + transportFactory.transport.setS2AAddress(S2A_ADDRESS_A); + transportFactory.transport.setRequestStatusCode( + HttpStatusCodes.STATUS_CODE_SERVICE_UNAVAILABLE); + + S2A s2aUtils = new S2A(); + s2aUtils.setHttpTransportFactory(transportFactory); + String s2aAddress = s2aUtils.getS2AAddress(); + assertTrue(s2aAddress.isEmpty()); + } + + @Test + public void getS2AAddress_queryEndpointResponseEmpty_emptyAddress() { + MockMetadataServerTransportFactory transportFactory = new MockMetadataServerTransportFactory(); + transportFactory.transport.setS2AAddress(S2A_ADDRESS_A); + transportFactory.transport.setRequestStatusCode(HttpStatusCodes.STATUS_CODE_OK); + transportFactory.transport.setEmptyContent(true); + + S2A s2aUtils = new S2A(); + s2aUtils.setHttpTransportFactory(transportFactory); + String s2aAddress = s2aUtils.getS2AAddress(); + assertTrue(s2aAddress.isEmpty()); + } + + @Test + public void getS2AAdress_multipleThreads_validAddress() throws Exception { + MockMetadataServerTransportFactory transportFactoryA = new MockMetadataServerTransportFactory(); + transportFactoryA.transport.setS2AAddress(S2A_ADDRESS_A); + transportFactoryA.transport.setRequestStatusCode(HttpStatusCodes.STATUS_CODE_OK); + + MockMetadataServerTransportFactory transportFactoryB = new MockMetadataServerTransportFactory(); + transportFactoryB.transport.setS2AAddress(S2A_ADDRESS_B); + transportFactoryB.transport.setRequestStatusCode(HttpStatusCodes.STATUS_CODE_OK); + + S2A s2aUtils = new S2A(); + + DoGetS2AAddress doGetS2AAddressA = + new DoGetS2AAddress(transportFactoryA, S2A_ADDRESS_A, s2aUtils); + DoGetS2AAddress doGetS2AAddressB = + new DoGetS2AAddress(transportFactoryB, S2A_ADDRESS_A, s2aUtils); + + doGetS2AAddressA.start(); + Thread.sleep(2000); + doGetS2AAddressB.start(); + + doGetS2AAddressA.join(); + doGetS2AAddressB.join(); + } + + private class DoGetS2AAddress extends Thread { + HttpTransportFactory transportFactory; + String exp_addr; + S2A s2aUtils; + + public DoGetS2AAddress(HttpTransportFactory transportFactory, String addr, S2A s2aUtils) { + super(); + this.transportFactory = transportFactory; + this.exp_addr = addr; + this.s2aUtils = s2aUtils; + } + + @Override + public void run() { + s2aUtils.setHttpTransportFactory(transportFactory); + String s2aAddress = s2aUtils.getS2AAddress(); + assertEquals(exp_addr, s2aAddress); + } + } } - - From d932e0c9e20f05acc015ab370342cf256ec3d8f4 Mon Sep 17 00:00:00 2001 From: Riya Mehta Date: Tue, 12 Mar 2024 10:02:20 -0700 Subject: [PATCH 08/44] static mtls config. --- .../com/google/auth/oauth2/MtlsConfig.java | 47 ++----------------- .../java/com/google/auth/oauth2/S2A.java | 37 +++++++-------- .../oauth2/MockMetadataServerTransport.java | 16 +------ .../google/auth/oauth2/MtlsConfigTest.java | 27 +---------- .../com/google/auth/oauth2/S2ATest.java | 47 ------------------- oauth2_http/pom.xml | 5 -- 6 files changed, 25 insertions(+), 154 deletions(-) diff --git a/oauth2_http/java/com/google/auth/oauth2/MtlsConfig.java b/oauth2_http/java/com/google/auth/oauth2/MtlsConfig.java index 527745027..de4ab23ff 100644 --- a/oauth2_http/java/com/google/auth/oauth2/MtlsConfig.java +++ b/oauth2_http/java/com/google/auth/oauth2/MtlsConfig.java @@ -1,57 +1,18 @@ package com.google.auth.oauth2; -import javax.annotation.concurrent.NotThreadSafe; -import org.joda.time.MutableDateTime; - -/** - * Holds an mTLS configuration (consists of address of S2A) retrieved from the Metadata Server. - * - *

Instances of {@link MtlsConfig} are not thread safe. Calls to {@code reset}, {@code - * getS2AAddress}, {@code isValid} and {@code getExpiry} should be made from a synchronized block. - */ -@NotThreadSafe +/** Holds an mTLS configuration (consists of address of S2A) retrieved from the Metadata Server. */ public final class MtlsConfig { - private String s2aAddress; - private MutableDateTime expiry; - - private static final int MTLS_AUTOCONFIG_EXPIRATION_HOURS = 1; - - public static MtlsConfig createNullMtlsConfig() { - return new MtlsConfig("", null); - } + private final String s2aAddress; public static MtlsConfig createMtlsConfig(String addr) { - MutableDateTime expiry = MutableDateTime.now(); - expiry.addHours(MTLS_AUTOCONFIG_EXPIRATION_HOURS); - return new MtlsConfig(addr, expiry); - } - - public void reset(String addr) { - this.s2aAddress = addr; - this.expiry = MutableDateTime.now(); - this.expiry.addHours(MTLS_AUTOCONFIG_EXPIRATION_HOURS); + return new MtlsConfig(addr); } public String getS2AAddress() { return s2aAddress; } - public boolean isValid() { - if (expiry == null) { - return false; - } - if (MutableDateTime.now().isAfter(this.expiry)) { - return false; - } - return true; - } - - public MutableDateTime getExpiry() { - return expiry; - } - - private MtlsConfig(String addr, MutableDateTime expiry) { + private MtlsConfig(String addr) { this.s2aAddress = addr; - this.expiry = expiry; } } diff --git a/oauth2_http/java/com/google/auth/oauth2/S2A.java b/oauth2_http/java/com/google/auth/oauth2/S2A.java index 5b57bad94..598f46fb2 100644 --- a/oauth2_http/java/com/google/auth/oauth2/S2A.java +++ b/oauth2_http/java/com/google/auth/oauth2/S2A.java @@ -15,8 +15,7 @@ /** * Utilities to fetch the S2A (Secure Session Agent) address from the mTLS configuration. * - *

Periodically refresh the mTLS configuration by getting a new one from the MDS mTLS autoconfig - * endpoint. + *

mTLS configuration is queried from the MDS MTLS Autoconfiguration endpoint. */ @ThreadSafe public final class S2A { @@ -24,34 +23,39 @@ public final class S2A { public static final String MTLS_CONFIG_ENDPOINT = "/instance/platform-security/auto-mtls-configuration"; - private static final String METADATA_FLAVOR = "Metadata-Flavor"; - private static final String GOOGLE = "Google"; + public static final String METADATA_FLAVOR = "Metadata-Flavor"; + public static final String GOOGLE = "Google"; private static final String PARSE_ERROR_S2A = "Error parsing Mtls Auto Config response."; private MtlsConfig config; private transient HttpTransportFactory transportFactory; - public S2A() { - config = MtlsConfig.createNullMtlsConfig(); - } + public S2A() {} public void setHttpTransportFactory(HttpTransportFactory tf) { this.transportFactory = tf; } - /** Returns the S2A Address from the mTLS config. Refreshes the config if it is expired. */ + /** + * Returns the S2A Address from the mTLS config. + * + * @return the S2A address. + */ public synchronized String getS2AAddress() { - if (!config.isValid()) { + if (config == null) { String addr = getMdsMtlsConfigData(); - config.reset(addr); + config = MtlsConfig.createMtlsConfig(addr); } return config.getS2AAddress(); } /** - * Queries the MDS mTLS Autoconfiguration endpoint and returns the S2A address. Returns an empty - * address on error. + * Queries the MDS mTLS Autoconfiguration endpoint and returns the S2A address. + * + *

Returns an empty address on error. + * + * @return the S2A address. */ private String getMdsMtlsConfigData() { String s2aAddress = ""; @@ -61,7 +65,7 @@ private String getMdsMtlsConfigData() { Iterables.getFirst( ServiceLoader.load(HttpTransportFactory.class), OAuth2Utils.HTTP_TRANSPORT_FACTORY); } - String url = getMdsMtlsEndpoint(DefaultCredentialsProvider.DEFAULT); + String url = getMdsMtlsEndpoint(); GenericUrl genericUrl = new GenericUrl(url); HttpRequest request = transportFactory.create().createRequestFactory().buildGetRequest(genericUrl); @@ -88,12 +92,7 @@ private String getMdsMtlsConfigData() { } /** @return MDS mTLS autoconfig endpoint. */ - private String getMdsMtlsEndpoint(DefaultCredentialsProvider provider) { - String metadataServerAddress = - provider.getEnv(DefaultCredentialsProvider.GCE_METADATA_HOST_ENV_VAR); - if (metadataServerAddress != null) { - return "http://" + metadataServerAddress + MTLS_CONFIG_ENDPOINT; - } + private String getMdsMtlsEndpoint() { return DEFAULT_METADATA_SERVER_URL + MTLS_CONFIG_ENDPOINT; } } diff --git a/oauth2_http/javatests/com/google/auth/oauth2/MockMetadataServerTransport.java b/oauth2_http/javatests/com/google/auth/oauth2/MockMetadataServerTransport.java index 242990223..2554ff5a4 100644 --- a/oauth2_http/javatests/com/google/auth/oauth2/MockMetadataServerTransport.java +++ b/oauth2_http/javatests/com/google/auth/oauth2/MockMetadataServerTransport.java @@ -94,18 +94,6 @@ public void setEmptyContent(boolean emptyContent) { this.emptyContent = emptyContent; } - public String getAddr() { - return s2aAddress; - } - - public Integer getCode() { - return requestStatusCode; - } - - public boolean getEmpty() { - return emptyContent; - } - @Override public LowLevelHttpRequest buildRequest(String method, String url) throws IOException { if (url.equals(ComputeEngineCredentials.getTokenServerEncodedUrl())) { @@ -264,8 +252,8 @@ private MockLowLevelHttpRequest getMockRequestForMtlsConfig(String url) { @Override public LowLevelHttpResponse execute() throws IOException { - String metadataRequestHeader = getFirstHeaderValue("Metadata-Flavor"); - if (!"Google".equals(metadataRequestHeader)) { + String metadataRequestHeader = getFirstHeaderValue(S2A.METADATA_FLAVOR); + if (!S2A.GOOGLE.equals(metadataRequestHeader)) { throw new IOException("Metadata request header not found"); } diff --git a/oauth2_http/javatests/com/google/auth/oauth2/MtlsConfigTest.java b/oauth2_http/javatests/com/google/auth/oauth2/MtlsConfigTest.java index 648a661c4..201756d05 100644 --- a/oauth2_http/javatests/com/google/auth/oauth2/MtlsConfigTest.java +++ b/oauth2_http/javatests/com/google/auth/oauth2/MtlsConfigTest.java @@ -1,10 +1,7 @@ package com.google.auth.oauth2; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import org.joda.time.MutableDateTime; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -13,32 +10,10 @@ @RunWith(JUnit4.class) public class MtlsConfigTest { private static final String S2A_ADDRESS_A = "addr_a"; - private static final String S2A_ADDRESS_B = "addr_b"; @Test - public void NullMtlsConfig_invalid() { - MtlsConfig config = MtlsConfig.createNullMtlsConfig(); - assertEquals("", config.getS2AAddress()); - assertFalse(config.isValid()); - } - - @Test - public void NonNullMtlsConfig_valid() { - MtlsConfig config = MtlsConfig.createMtlsConfig(S2A_ADDRESS_A); - assertEquals(S2A_ADDRESS_A, config.getS2AAddress()); - assertTrue(config.isValid()); - } - - @Test - public void resetAddress_newExpiryGreater() throws Exception { + public void createMtlsConfig_success() { MtlsConfig config = MtlsConfig.createMtlsConfig(S2A_ADDRESS_A); - MutableDateTime e1 = config.getExpiry(); assertEquals(S2A_ADDRESS_A, config.getS2AAddress()); - Thread.sleep(2000); - config.reset(S2A_ADDRESS_B); - assertEquals(S2A_ADDRESS_B, config.getS2AAddress()); - MutableDateTime e2 = config.getExpiry(); - int value = e2.compareTo(e1); - assertTrue(value > 0); } } diff --git a/oauth2_http/javatests/com/google/auth/oauth2/S2ATest.java b/oauth2_http/javatests/com/google/auth/oauth2/S2ATest.java index 46535d8c3..163043c98 100644 --- a/oauth2_http/javatests/com/google/auth/oauth2/S2ATest.java +++ b/oauth2_http/javatests/com/google/auth/oauth2/S2ATest.java @@ -4,7 +4,6 @@ import static org.junit.Assert.assertTrue; import com.google.api.client.http.HttpStatusCodes; -import com.google.auth.http.HttpTransportFactory; import com.google.auth.oauth2.ComputeEngineCredentialsTest.MockMetadataServerTransportFactory; import org.junit.Test; import org.junit.runner.RunWith; @@ -15,7 +14,6 @@ public class S2ATest { private static final String S2A_ADDRESS_A = "addr_a"; - private static final String S2A_ADDRESS_B = "addr_b"; @Test public void getS2AAddress_validAddress() { @@ -54,49 +52,4 @@ public void getS2AAddress_queryEndpointResponseEmpty_emptyAddress() { String s2aAddress = s2aUtils.getS2AAddress(); assertTrue(s2aAddress.isEmpty()); } - - @Test - public void getS2AAdress_multipleThreads_validAddress() throws Exception { - MockMetadataServerTransportFactory transportFactoryA = new MockMetadataServerTransportFactory(); - transportFactoryA.transport.setS2AAddress(S2A_ADDRESS_A); - transportFactoryA.transport.setRequestStatusCode(HttpStatusCodes.STATUS_CODE_OK); - - MockMetadataServerTransportFactory transportFactoryB = new MockMetadataServerTransportFactory(); - transportFactoryB.transport.setS2AAddress(S2A_ADDRESS_B); - transportFactoryB.transport.setRequestStatusCode(HttpStatusCodes.STATUS_CODE_OK); - - S2A s2aUtils = new S2A(); - - DoGetS2AAddress doGetS2AAddressA = - new DoGetS2AAddress(transportFactoryA, S2A_ADDRESS_A, s2aUtils); - DoGetS2AAddress doGetS2AAddressB = - new DoGetS2AAddress(transportFactoryB, S2A_ADDRESS_A, s2aUtils); - - doGetS2AAddressA.start(); - Thread.sleep(2000); - doGetS2AAddressB.start(); - - doGetS2AAddressA.join(); - doGetS2AAddressB.join(); - } - - private class DoGetS2AAddress extends Thread { - HttpTransportFactory transportFactory; - String exp_addr; - S2A s2aUtils; - - public DoGetS2AAddress(HttpTransportFactory transportFactory, String addr, S2A s2aUtils) { - super(); - this.transportFactory = transportFactory; - this.exp_addr = addr; - this.s2aUtils = s2aUtils; - } - - @Override - public void run() { - s2aUtils.setHttpTransportFactory(transportFactory); - String s2aAddress = s2aUtils.getS2AAddress(); - assertEquals(exp_addr, s2aAddress); - } - } } diff --git a/oauth2_http/pom.xml b/oauth2_http/pom.xml index e5756eda6..c14201002 100644 --- a/oauth2_http/pom.xml +++ b/oauth2_http/pom.xml @@ -253,11 +253,6 @@ hamcrest-core 1.3 test - - - joda-time - joda-time - 2.12.7 org.mockito From 6aa071b9e3984ba6aabe528fd51cbe6e2a4763e1 Mon Sep 17 00:00:00 2001 From: Riya Mehta Date: Wed, 13 Mar 2024 12:41:58 -0700 Subject: [PATCH 09/44] update autoconfig endpoint URL. --- oauth2_http/java/com/google/auth/oauth2/S2A.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/oauth2_http/java/com/google/auth/oauth2/S2A.java b/oauth2_http/java/com/google/auth/oauth2/S2A.java index 598f46fb2..930c030ee 100644 --- a/oauth2_http/java/com/google/auth/oauth2/S2A.java +++ b/oauth2_http/java/com/google/auth/oauth2/S2A.java @@ -19,9 +19,9 @@ */ @ThreadSafe public final class S2A { - public static final String DEFAULT_METADATA_SERVER_URL = "http://metadata.google.internal"; + public static final String DEFAULT_METADATA_SERVER_URL = "http://169.254.169.254"; public static final String MTLS_CONFIG_ENDPOINT = - "/instance/platform-security/auto-mtls-configuration"; + "/computeMetadata/v1/instance/platform-security/auto-mtls-configuration"; public static final String METADATA_FLAVOR = "Metadata-Flavor"; public static final String GOOGLE = "Google"; From ddac7aab52e4e651c2d1050e7d76afd17a6f847a Mon Sep 17 00:00:00 2001 From: Riya Mehta Date: Wed, 13 Mar 2024 14:28:24 -0700 Subject: [PATCH 10/44] plaintext and mtls S2A address. --- .../com/google/auth/oauth2/MtlsConfig.java | 54 ++++++++++++++++--- .../java/com/google/auth/oauth2/S2A.java | 47 +++++++++------- .../oauth2/MockMetadataServerTransport.java | 18 +++++-- .../google/auth/oauth2/MtlsConfigTest.java | 20 +++++-- .../com/google/auth/oauth2/S2ATest.java | 30 +++++++---- 5 files changed, 125 insertions(+), 44 deletions(-) diff --git a/oauth2_http/java/com/google/auth/oauth2/MtlsConfig.java b/oauth2_http/java/com/google/auth/oauth2/MtlsConfig.java index de4ab23ff..61ee45cd8 100644 --- a/oauth2_http/java/com/google/auth/oauth2/MtlsConfig.java +++ b/oauth2_http/java/com/google/auth/oauth2/MtlsConfig.java @@ -1,18 +1,58 @@ package com.google.auth.oauth2; +import com.google.errorprone.annotations.CanIgnoreReturnValue; + /** Holds an mTLS configuration (consists of address of S2A) retrieved from the Metadata Server. */ public final class MtlsConfig { - private final String s2aAddress; + // plaintextS2AAddress is the plaintext address to reach the S2A. + private final String plaintextS2AAddress; + + // mtlsS2AAddress is the mTLS address to reach the S2A. + private final String mtlsS2AAddress; + + public static Builder createBuilder() { + return new Builder(); + } + + public String getPlaintextS2AAddress() { + return plaintextS2AAddress; + } - public static MtlsConfig createMtlsConfig(String addr) { - return new MtlsConfig(addr); + public String getMtlsS2AAddress() { + return mtlsS2AAddress; } - public String getS2AAddress() { - return s2aAddress; + public static final class Builder { + // plaintextS2AAddress is the plaintext address to reach the S2A. + private String plaintextS2AAddress; + + // mtlsS2AAddress is the mTLS address to reach the S2A. + private String mtlsS2AAddress; + + Builder() { + plaintextS2AAddress = ""; + mtlsS2AAddress = ""; + } + + @CanIgnoreReturnValue + public Builder setPlaintextS2AAddress(String plaintextS2AAddress) { + this.plaintextS2AAddress = plaintextS2AAddress; + return this; + } + + @CanIgnoreReturnValue + public Builder setMtlsS2AAddress(String mtlsS2AAddress) { + this.mtlsS2AAddress = mtlsS2AAddress; + return this; + } + + public MtlsConfig build() { + return new MtlsConfig(plaintextS2AAddress, mtlsS2AAddress); + } } - private MtlsConfig(String addr) { - this.s2aAddress = addr; + private MtlsConfig(String plaintextS2AAddress, String mtlsS2AAddress) { + this.plaintextS2AAddress = plaintextS2AAddress; + this.mtlsS2AAddress = mtlsS2AAddress; } } diff --git a/oauth2_http/java/com/google/auth/oauth2/S2A.java b/oauth2_http/java/com/google/auth/oauth2/S2A.java index 930c030ee..ff8450b60 100644 --- a/oauth2_http/java/com/google/auth/oauth2/S2A.java +++ b/oauth2_http/java/com/google/auth/oauth2/S2A.java @@ -37,28 +37,32 @@ public void setHttpTransportFactory(HttpTransportFactory tf) { this.transportFactory = tf; } - /** - * Returns the S2A Address from the mTLS config. - * - * @return the S2A address. - */ - public synchronized String getS2AAddress() { + /** @return the mTLS S2A Address from the mTLS config. */ + public synchronized String getMtlsS2AAddress() { + if (config == null) { + config = getMdsMtlsConfig(); + } + return config.getMtlsS2AAddress(); + } + + /** @return the plaintext S2A Address from the mTLS config. */ + public synchronized String getPlaintextS2AAddress() { if (config == null) { - String addr = getMdsMtlsConfigData(); - config = MtlsConfig.createMtlsConfig(addr); + config = getMdsMtlsConfig(); } - return config.getS2AAddress(); + return config.getPlaintextS2AAddress(); } /** - * Queries the MDS mTLS Autoconfiguration endpoint and returns the S2A address. + * Queries the MDS mTLS Autoconfiguration endpoint and returns the {@link MtlsConfig}. * - *

Returns an empty address on error. + *

Returns {@link MtlsConfig} with empty addresses on error. * - * @return the S2A address. + * @return the {@link MtlsConfig}. */ - private String getMdsMtlsConfigData() { - String s2aAddress = ""; + private MtlsConfig getMdsMtlsConfig() { + String plaintextS2AAddress = ""; + String mtlsS2AAddress = ""; try { if (transportFactory == null) { transportFactory = @@ -76,19 +80,24 @@ private String getMdsMtlsConfigData() { HttpResponse response = request.execute(); if (!response.isSuccessStatusCode()) { - return ""; + return MtlsConfig.createBuilder().build(); } InputStream content = response.getContent(); if (content == null) { - return ""; + return MtlsConfig.createBuilder().build(); } GenericData responseData = response.parseAs(GenericData.class); - s2aAddress = OAuth2Utils.validateString(responseData, "s2a", PARSE_ERROR_S2A); + plaintextS2AAddress = + OAuth2Utils.validateString(responseData, "plaintext_address", PARSE_ERROR_S2A); + mtlsS2AAddress = OAuth2Utils.validateString(responseData, "mtls_address", PARSE_ERROR_S2A); } catch (IOException e) { - return ""; + return MtlsConfig.createBuilder().build(); } - return s2aAddress; + return MtlsConfig.createBuilder() + .setPlaintextS2AAddress(plaintextS2AAddress) + .setMtlsS2AAddress(mtlsS2AAddress) + .build(); } /** @return MDS mTLS autoconfig endpoint. */ diff --git a/oauth2_http/javatests/com/google/auth/oauth2/MockMetadataServerTransport.java b/oauth2_http/javatests/com/google/auth/oauth2/MockMetadataServerTransport.java index 2554ff5a4..8e1a0b455 100644 --- a/oauth2_http/javatests/com/google/auth/oauth2/MockMetadataServerTransport.java +++ b/oauth2_http/javatests/com/google/auth/oauth2/MockMetadataServerTransport.java @@ -60,7 +60,9 @@ public class MockMetadataServerTransport extends MockHttpTransport { private byte[] signature; - private String s2aAddress; + private String plaintextS2AAddress; + + private String mtlsS2AAddress; private boolean emptyContent; @@ -86,8 +88,12 @@ public void setIdToken(String idToken) { this.idToken = idToken; } - public void setS2AAddress(String address) { - this.s2aAddress = address; + public void setPlaintextS2AAddress(String address) { + this.plaintextS2AAddress = address; + } + + public void setMtlsS2AAddress(String address) { + this.mtlsS2AAddress = address; } public void setEmptyContent(boolean emptyContent) { @@ -260,7 +266,8 @@ public LowLevelHttpResponse execute() throws IOException { // Create the JSON response GenericJson content = new GenericJson(); content.setFactory(OAuth2Utils.JSON_FACTORY); - content.put("s2a", s2aAddress); + content.put("plaintext_address", plaintextS2AAddress); + content.put("mtls_address", mtlsS2AAddress); String contentText = content.toPrettyString(); MockLowLevelHttpResponse response = new MockLowLevelHttpResponse(); @@ -292,7 +299,8 @@ protected boolean isIdentityDocumentUrl(String url) { } protected boolean isMtlsConfigRequestUrl(String url) { - return s2aAddress != null + return plaintextS2AAddress != null + && mtlsS2AAddress != null && url.equals(String.format(S2A.DEFAULT_METADATA_SERVER_URL + S2A.MTLS_CONFIG_ENDPOINT)); } } diff --git a/oauth2_http/javatests/com/google/auth/oauth2/MtlsConfigTest.java b/oauth2_http/javatests/com/google/auth/oauth2/MtlsConfigTest.java index 201756d05..64f1185d5 100644 --- a/oauth2_http/javatests/com/google/auth/oauth2/MtlsConfigTest.java +++ b/oauth2_http/javatests/com/google/auth/oauth2/MtlsConfigTest.java @@ -1,6 +1,7 @@ package com.google.auth.oauth2; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import org.junit.Test; import org.junit.runner.RunWith; @@ -9,11 +10,24 @@ /** Test cases for {@link MtlsConfig}. */ @RunWith(JUnit4.class) public class MtlsConfigTest { - private static final String S2A_ADDRESS_A = "addr_a"; + private static final String S2A_PLAINTEXT_ADDRESS = "plaintext"; + private static final String S2A_MTLS_ADDRESS = "mtls"; @Test public void createMtlsConfig_success() { - MtlsConfig config = MtlsConfig.createMtlsConfig(S2A_ADDRESS_A); - assertEquals(S2A_ADDRESS_A, config.getS2AAddress()); + MtlsConfig config = + MtlsConfig.createBuilder() + .setPlaintextS2AAddress(S2A_PLAINTEXT_ADDRESS) + .setMtlsS2AAddress(S2A_MTLS_ADDRESS) + .build(); + assertEquals(S2A_PLAINTEXT_ADDRESS, config.getPlaintextS2AAddress()); + assertEquals(S2A_MTLS_ADDRESS, config.getMtlsS2AAddress()); + } + + @Test + public void createEmptyMtlsConfig_success() { + MtlsConfig config = MtlsConfig.createBuilder().build(); + assertTrue(config.getPlaintextS2AAddress().isEmpty()); + assertTrue(config.getMtlsS2AAddress().isEmpty()); } } diff --git a/oauth2_http/javatests/com/google/auth/oauth2/S2ATest.java b/oauth2_http/javatests/com/google/auth/oauth2/S2ATest.java index 163043c98..590662e43 100644 --- a/oauth2_http/javatests/com/google/auth/oauth2/S2ATest.java +++ b/oauth2_http/javatests/com/google/auth/oauth2/S2ATest.java @@ -13,43 +13,53 @@ @RunWith(JUnit4.class) public class S2ATest { - private static final String S2A_ADDRESS_A = "addr_a"; + private static final String S2A_PLAINTEXT_ADDRESS = "plaintext"; + private static final String S2A_MTLS_ADDRESS = "mtls"; @Test public void getS2AAddress_validAddress() { MockMetadataServerTransportFactory transportFactory = new MockMetadataServerTransportFactory(); - transportFactory.transport.setS2AAddress(S2A_ADDRESS_A); + transportFactory.transport.setPlaintextS2AAddress(S2A_PLAINTEXT_ADDRESS); + transportFactory.transport.setMtlsS2AAddress(S2A_MTLS_ADDRESS); transportFactory.transport.setRequestStatusCode(HttpStatusCodes.STATUS_CODE_OK); S2A s2aUtils = new S2A(); s2aUtils.setHttpTransportFactory(transportFactory); - String s2aAddress = s2aUtils.getS2AAddress(); - assertEquals(S2A_ADDRESS_A, s2aAddress); + String plaintextS2AAddress = s2aUtils.getPlaintextS2AAddress(); + String mtlsS2AAddress = s2aUtils.getMtlsS2AAddress(); + assertEquals(S2A_PLAINTEXT_ADDRESS, plaintextS2AAddress); + assertEquals(S2A_MTLS_ADDRESS, mtlsS2AAddress); } @Test public void getS2AAddress_queryEndpointResponseErrorCode_emptyAddress() { MockMetadataServerTransportFactory transportFactory = new MockMetadataServerTransportFactory(); - transportFactory.transport.setS2AAddress(S2A_ADDRESS_A); + transportFactory.transport.setPlaintextS2AAddress(S2A_PLAINTEXT_ADDRESS); + transportFactory.transport.setMtlsS2AAddress(S2A_MTLS_ADDRESS); transportFactory.transport.setRequestStatusCode( HttpStatusCodes.STATUS_CODE_SERVICE_UNAVAILABLE); S2A s2aUtils = new S2A(); s2aUtils.setHttpTransportFactory(transportFactory); - String s2aAddress = s2aUtils.getS2AAddress(); - assertTrue(s2aAddress.isEmpty()); + String plaintextS2AAddress = s2aUtils.getPlaintextS2AAddress(); + String mtlsS2AAddress = s2aUtils.getMtlsS2AAddress(); + assertTrue(plaintextS2AAddress.isEmpty()); + assertTrue(mtlsS2AAddress.isEmpty()); } @Test public void getS2AAddress_queryEndpointResponseEmpty_emptyAddress() { MockMetadataServerTransportFactory transportFactory = new MockMetadataServerTransportFactory(); - transportFactory.transport.setS2AAddress(S2A_ADDRESS_A); + transportFactory.transport.setPlaintextS2AAddress(S2A_PLAINTEXT_ADDRESS); + transportFactory.transport.setMtlsS2AAddress(S2A_MTLS_ADDRESS); transportFactory.transport.setRequestStatusCode(HttpStatusCodes.STATUS_CODE_OK); transportFactory.transport.setEmptyContent(true); S2A s2aUtils = new S2A(); s2aUtils.setHttpTransportFactory(transportFactory); - String s2aAddress = s2aUtils.getS2AAddress(); - assertTrue(s2aAddress.isEmpty()); + String plaintextS2AAddress = s2aUtils.getPlaintextS2AAddress(); + String mtlsS2AAddress = s2aUtils.getMtlsS2AAddress(); + assertTrue(plaintextS2AAddress.isEmpty()); + assertTrue(mtlsS2AAddress.isEmpty()); } } From 67f9462a096831e1aaa75584d66b7b29eb342516 Mon Sep 17 00:00:00 2001 From: Riya Mehta Date: Fri, 17 May 2024 09:59:26 -0700 Subject: [PATCH 11/44] Use logic in ComputeEngineCredentials to get MDS URL. --- oauth2_http/java/com/google/auth/oauth2/S2A.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/oauth2_http/java/com/google/auth/oauth2/S2A.java b/oauth2_http/java/com/google/auth/oauth2/S2A.java index ff8450b60..44e272212 100644 --- a/oauth2_http/java/com/google/auth/oauth2/S2A.java +++ b/oauth2_http/java/com/google/auth/oauth2/S2A.java @@ -19,7 +19,6 @@ */ @ThreadSafe public final class S2A { - public static final String DEFAULT_METADATA_SERVER_URL = "http://169.254.169.254"; public static final String MTLS_CONFIG_ENDPOINT = "/computeMetadata/v1/instance/platform-security/auto-mtls-configuration"; @@ -102,6 +101,6 @@ private MtlsConfig getMdsMtlsConfig() { /** @return MDS mTLS autoconfig endpoint. */ private String getMdsMtlsEndpoint() { - return DEFAULT_METADATA_SERVER_URL + MTLS_CONFIG_ENDPOINT; + return ComputeEngineCredentials.getMetadataServerUrl() + MTLS_CONFIG_ENDPOINT; } } From 36d4cd18fcc6a846cad3e02f76edec77faeeae95 Mon Sep 17 00:00:00 2001 From: Riya Mehta Date: Fri, 17 May 2024 10:47:34 -0700 Subject: [PATCH 12/44] retry MDS request. --- .../java/com/google/auth/oauth2/S2A.java | 68 ++++++++++--------- .../oauth2/MockMetadataServerTransport.java | 2 +- 2 files changed, 38 insertions(+), 32 deletions(-) diff --git a/oauth2_http/java/com/google/auth/oauth2/S2A.java b/oauth2_http/java/com/google/auth/oauth2/S2A.java index 44e272212..223c1a46c 100644 --- a/oauth2_http/java/com/google/auth/oauth2/S2A.java +++ b/oauth2_http/java/com/google/auth/oauth2/S2A.java @@ -24,6 +24,7 @@ public final class S2A { public static final String METADATA_FLAVOR = "Metadata-Flavor"; public static final String GOOGLE = "Google"; + private static final int MAX_MDS_PING_TRIES = 3; private static final String PARSE_ERROR_S2A = "Error parsing Mtls Auto Config response."; private MtlsConfig config; @@ -62,41 +63,46 @@ public synchronized String getPlaintextS2AAddress() { private MtlsConfig getMdsMtlsConfig() { String plaintextS2AAddress = ""; String mtlsS2AAddress = ""; - try { - if (transportFactory == null) { - transportFactory = - Iterables.getFirst( - ServiceLoader.load(HttpTransportFactory.class), OAuth2Utils.HTTP_TRANSPORT_FACTORY); - } - String url = getMdsMtlsEndpoint(); - GenericUrl genericUrl = new GenericUrl(url); - HttpRequest request = - transportFactory.create().createRequestFactory().buildGetRequest(genericUrl); - JsonObjectParser parser = new JsonObjectParser(OAuth2Utils.JSON_FACTORY); - request.setParser(parser); - request.getHeaders().set(METADATA_FLAVOR, GOOGLE); - request.setThrowExceptionOnExecuteError(false); - HttpResponse response = request.execute(); - if (!response.isSuccessStatusCode()) { - return MtlsConfig.createBuilder().build(); - } + String url = getMdsMtlsEndpoint(); + GenericUrl genericUrl = new GenericUrl(url); + + for (int i = 0; i < MAX_MDS_PING_TRIES; i++) { + try { + if (transportFactory == null) { + transportFactory = + Iterables.getFirst( + ServiceLoader.load(HttpTransportFactory.class), OAuth2Utils.HTTP_TRANSPORT_FACTORY); + } + HttpRequest request = + transportFactory.create().createRequestFactory().buildGetRequest(genericUrl); + JsonObjectParser parser = new JsonObjectParser(OAuth2Utils.JSON_FACTORY); + request.setParser(parser); + request.getHeaders().set(METADATA_FLAVOR, GOOGLE); + request.setThrowExceptionOnExecuteError(false); + HttpResponse response = request.execute(); + + if (!response.isSuccessStatusCode()) { + continue; + } - InputStream content = response.getContent(); - if (content == null) { - return MtlsConfig.createBuilder().build(); + InputStream content = response.getContent(); + if (content == null) { + continue; + } + GenericData responseData = response.parseAs(GenericData.class); + plaintextS2AAddress = + OAuth2Utils.validateString(responseData, "plaintext_address", PARSE_ERROR_S2A); + mtlsS2AAddress = OAuth2Utils.validateString(responseData, "mtls_address", PARSE_ERROR_S2A); + } catch (IOException e) { + continue; } - GenericData responseData = response.parseAs(GenericData.class); - plaintextS2AAddress = - OAuth2Utils.validateString(responseData, "plaintext_address", PARSE_ERROR_S2A); - mtlsS2AAddress = OAuth2Utils.validateString(responseData, "mtls_address", PARSE_ERROR_S2A); - } catch (IOException e) { - return MtlsConfig.createBuilder().build(); + return MtlsConfig.createBuilder() + .setPlaintextS2AAddress(plaintextS2AAddress) + .setMtlsS2AAddress(mtlsS2AAddress) + .build(); } - return MtlsConfig.createBuilder() - .setPlaintextS2AAddress(plaintextS2AAddress) - .setMtlsS2AAddress(mtlsS2AAddress) - .build(); + return MtlsConfig.createBuilder().build(); } /** @return MDS mTLS autoconfig endpoint. */ diff --git a/oauth2_http/javatests/com/google/auth/oauth2/MockMetadataServerTransport.java b/oauth2_http/javatests/com/google/auth/oauth2/MockMetadataServerTransport.java index 8e1a0b455..5a9063639 100644 --- a/oauth2_http/javatests/com/google/auth/oauth2/MockMetadataServerTransport.java +++ b/oauth2_http/javatests/com/google/auth/oauth2/MockMetadataServerTransport.java @@ -301,6 +301,6 @@ protected boolean isIdentityDocumentUrl(String url) { protected boolean isMtlsConfigRequestUrl(String url) { return plaintextS2AAddress != null && mtlsS2AAddress != null - && url.equals(String.format(S2A.DEFAULT_METADATA_SERVER_URL + S2A.MTLS_CONFIG_ENDPOINT)); + && url.equals(String.format(ComputeEngineCredentials.getMetadataServerUrl() + S2A.MTLS_CONFIG_ENDPOINT)); } } From 359fd432480bfd92440ee680e1459bfe0e782fb9 Mon Sep 17 00:00:00 2001 From: Riya Mehta Date: Thu, 26 Sep 2024 14:26:45 -0700 Subject: [PATCH 13/44] rebranch MtlsConfig as S2AConfig. --- .../com/google/auth/oauth2/MtlsConfig.java | 58 ------------------- .../java/com/google/auth/oauth2/S2A.java | 26 ++++----- .../com/google/auth/oauth2/S2AConfig.java | 58 +++++++++++++++++++ .../google/auth/oauth2/MtlsConfigTest.java | 33 ----------- .../com/google/auth/oauth2/S2AConfigTest.java | 33 +++++++++++ 5 files changed, 104 insertions(+), 104 deletions(-) delete mode 100644 oauth2_http/java/com/google/auth/oauth2/MtlsConfig.java create mode 100644 oauth2_http/java/com/google/auth/oauth2/S2AConfig.java delete mode 100644 oauth2_http/javatests/com/google/auth/oauth2/MtlsConfigTest.java create mode 100644 oauth2_http/javatests/com/google/auth/oauth2/S2AConfigTest.java diff --git a/oauth2_http/java/com/google/auth/oauth2/MtlsConfig.java b/oauth2_http/java/com/google/auth/oauth2/MtlsConfig.java deleted file mode 100644 index 61ee45cd8..000000000 --- a/oauth2_http/java/com/google/auth/oauth2/MtlsConfig.java +++ /dev/null @@ -1,58 +0,0 @@ -package com.google.auth.oauth2; - -import com.google.errorprone.annotations.CanIgnoreReturnValue; - -/** Holds an mTLS configuration (consists of address of S2A) retrieved from the Metadata Server. */ -public final class MtlsConfig { - // plaintextS2AAddress is the plaintext address to reach the S2A. - private final String plaintextS2AAddress; - - // mtlsS2AAddress is the mTLS address to reach the S2A. - private final String mtlsS2AAddress; - - public static Builder createBuilder() { - return new Builder(); - } - - public String getPlaintextS2AAddress() { - return plaintextS2AAddress; - } - - public String getMtlsS2AAddress() { - return mtlsS2AAddress; - } - - public static final class Builder { - // plaintextS2AAddress is the plaintext address to reach the S2A. - private String plaintextS2AAddress; - - // mtlsS2AAddress is the mTLS address to reach the S2A. - private String mtlsS2AAddress; - - Builder() { - plaintextS2AAddress = ""; - mtlsS2AAddress = ""; - } - - @CanIgnoreReturnValue - public Builder setPlaintextS2AAddress(String plaintextS2AAddress) { - this.plaintextS2AAddress = plaintextS2AAddress; - return this; - } - - @CanIgnoreReturnValue - public Builder setMtlsS2AAddress(String mtlsS2AAddress) { - this.mtlsS2AAddress = mtlsS2AAddress; - return this; - } - - public MtlsConfig build() { - return new MtlsConfig(plaintextS2AAddress, mtlsS2AAddress); - } - } - - private MtlsConfig(String plaintextS2AAddress, String mtlsS2AAddress) { - this.plaintextS2AAddress = plaintextS2AAddress; - this.mtlsS2AAddress = mtlsS2AAddress; - } -} diff --git a/oauth2_http/java/com/google/auth/oauth2/S2A.java b/oauth2_http/java/com/google/auth/oauth2/S2A.java index 223c1a46c..eb9ee30d0 100644 --- a/oauth2_http/java/com/google/auth/oauth2/S2A.java +++ b/oauth2_http/java/com/google/auth/oauth2/S2A.java @@ -27,7 +27,7 @@ public final class S2A { private static final int MAX_MDS_PING_TRIES = 3; private static final String PARSE_ERROR_S2A = "Error parsing Mtls Auto Config response."; - private MtlsConfig config; + private S2AConfig config; private transient HttpTransportFactory transportFactory; @@ -40,27 +40,27 @@ public void setHttpTransportFactory(HttpTransportFactory tf) { /** @return the mTLS S2A Address from the mTLS config. */ public synchronized String getMtlsS2AAddress() { if (config == null) { - config = getMdsMtlsConfig(); + config = getS2AConfig(); } - return config.getMtlsS2AAddress(); + return config.getMtlsAddress(); } /** @return the plaintext S2A Address from the mTLS config. */ public synchronized String getPlaintextS2AAddress() { if (config == null) { - config = getMdsMtlsConfig(); + config = getS2AConfig(); } - return config.getPlaintextS2AAddress(); + return config.getPlaintextAddress(); } /** - * Queries the MDS mTLS Autoconfiguration endpoint and returns the {@link MtlsConfig}. + * Queries the MDS mTLS Autoconfiguration endpoint and returns the {@link S2AConfig}. * - *

Returns {@link MtlsConfig} with empty addresses on error. + *

Returns {@link S2AConfig} with empty addresses on error. * - * @return the {@link MtlsConfig}. + * @return the {@link S2AConfig}. */ - private MtlsConfig getMdsMtlsConfig() { + private S2AConfig getS2AConfig() { String plaintextS2AAddress = ""; String mtlsS2AAddress = ""; @@ -97,12 +97,12 @@ private MtlsConfig getMdsMtlsConfig() { } catch (IOException e) { continue; } - return MtlsConfig.createBuilder() - .setPlaintextS2AAddress(plaintextS2AAddress) - .setMtlsS2AAddress(mtlsS2AAddress) + return S2AConfig.createBuilder() + .setPlaintextAddress(plaintextS2AAddress) + .setMtlsAddress(mtlsS2AAddress) .build(); } - return MtlsConfig.createBuilder().build(); + return S2AConfig.createBuilder().build(); } /** @return MDS mTLS autoconfig endpoint. */ diff --git a/oauth2_http/java/com/google/auth/oauth2/S2AConfig.java b/oauth2_http/java/com/google/auth/oauth2/S2AConfig.java new file mode 100644 index 000000000..889157d13 --- /dev/null +++ b/oauth2_http/java/com/google/auth/oauth2/S2AConfig.java @@ -0,0 +1,58 @@ +package com.google.auth.oauth2; + +import com.google.errorprone.annotations.CanIgnoreReturnValue; + +/** Holds an mTLS configuration (consists of address of S2A) retrieved from the Metadata Server. */ +public final class S2AConfig { + // plaintextAddress is the plaintext address to reach the S2A. + private final String plaintextAddress; + + // mtlsAddress is the mTLS address to reach the S2A. + private final String mtlsAddress; + + public static Builder createBuilder() { + return new Builder(); + } + + public String getPlaintextAddress() { + return plaintextAddress; + } + + public String getMtlsAddress() { + return mtlsAddress; + } + + public static final class Builder { + // plaintextAddress is the plaintext address to reach the S2A. + private String plaintextAddress; + + // mtlsAddress is the mTLS address to reach the S2A. + private String mtlsAddress; + + Builder() { + plaintextAddress = ""; + mtlsAddress = ""; + } + + @CanIgnoreReturnValue + public Builder setPlaintextAddress(String plaintextAddress) { + this.plaintextAddress = plaintextAddress; + return this; + } + + @CanIgnoreReturnValue + public Builder setMtlsAddress(String mtlsAddress) { + this.mtlsAddress = mtlsAddress; + return this; + } + + public S2AConfig build() { + return new S2AConfig(plaintextAddress, mtlsAddress); + } + } + + private S2AConfig(String plaintextAddress, String mtlsAddress) { + this.plaintextAddress = plaintextAddress; + this.mtlsAddress = mtlsAddress; + } +} diff --git a/oauth2_http/javatests/com/google/auth/oauth2/MtlsConfigTest.java b/oauth2_http/javatests/com/google/auth/oauth2/MtlsConfigTest.java deleted file mode 100644 index 64f1185d5..000000000 --- a/oauth2_http/javatests/com/google/auth/oauth2/MtlsConfigTest.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.google.auth.oauth2; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -/** Test cases for {@link MtlsConfig}. */ -@RunWith(JUnit4.class) -public class MtlsConfigTest { - private static final String S2A_PLAINTEXT_ADDRESS = "plaintext"; - private static final String S2A_MTLS_ADDRESS = "mtls"; - - @Test - public void createMtlsConfig_success() { - MtlsConfig config = - MtlsConfig.createBuilder() - .setPlaintextS2AAddress(S2A_PLAINTEXT_ADDRESS) - .setMtlsS2AAddress(S2A_MTLS_ADDRESS) - .build(); - assertEquals(S2A_PLAINTEXT_ADDRESS, config.getPlaintextS2AAddress()); - assertEquals(S2A_MTLS_ADDRESS, config.getMtlsS2AAddress()); - } - - @Test - public void createEmptyMtlsConfig_success() { - MtlsConfig config = MtlsConfig.createBuilder().build(); - assertTrue(config.getPlaintextS2AAddress().isEmpty()); - assertTrue(config.getMtlsS2AAddress().isEmpty()); - } -} diff --git a/oauth2_http/javatests/com/google/auth/oauth2/S2AConfigTest.java b/oauth2_http/javatests/com/google/auth/oauth2/S2AConfigTest.java new file mode 100644 index 000000000..ab3baff48 --- /dev/null +++ b/oauth2_http/javatests/com/google/auth/oauth2/S2AConfigTest.java @@ -0,0 +1,33 @@ +package com.google.auth.oauth2; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** Test cases for {@link S2AConfig}. */ +@RunWith(JUnit4.class) +public class S2AConfigTest { + private static final String S2A_PLAINTEXT_ADDRESS = "plaintext"; + private static final String S2A_MTLS_ADDRESS = "mtls"; + + @Test + public void createS2AConfig_success() { + S2AConfig config = + S2AConfig.createBuilder() + .setPlaintextAddress(S2A_PLAINTEXT_ADDRESS) + .setMtlsAddress(S2A_MTLS_ADDRESS) + .build(); + assertEquals(S2A_PLAINTEXT_ADDRESS, config.getPlaintextAddress()); + assertEquals(S2A_MTLS_ADDRESS, config.getMtlsAddress()); + } + + @Test + public void createEmptyS2AConfig_success() { + S2AConfig config = S2AConfig.createBuilder().build(); + assertTrue(config.getPlaintextAddress().isEmpty()); + assertTrue(config.getMtlsAddress().isEmpty()); + } +} From bce602e84717d76c284e55e3cd6c8c69c99007e9 Mon Sep 17 00:00:00 2001 From: Riya Mehta Date: Thu, 26 Sep 2024 14:31:42 -0700 Subject: [PATCH 14/44] change naming to S2AConfig elsewhere. --- oauth2_http/java/com/google/auth/oauth2/S2A.java | 10 +++++----- .../auth/oauth2/MockMetadataServerTransport.java | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/oauth2_http/java/com/google/auth/oauth2/S2A.java b/oauth2_http/java/com/google/auth/oauth2/S2A.java index eb9ee30d0..ad1361171 100644 --- a/oauth2_http/java/com/google/auth/oauth2/S2A.java +++ b/oauth2_http/java/com/google/auth/oauth2/S2A.java @@ -19,7 +19,7 @@ */ @ThreadSafe public final class S2A { - public static final String MTLS_CONFIG_ENDPOINT = + public static final String S2A_CONFIG_ENDPOINT_POSTFIX = "/computeMetadata/v1/instance/platform-security/auto-mtls-configuration"; public static final String METADATA_FLAVOR = "Metadata-Flavor"; @@ -40,7 +40,7 @@ public void setHttpTransportFactory(HttpTransportFactory tf) { /** @return the mTLS S2A Address from the mTLS config. */ public synchronized String getMtlsS2AAddress() { if (config == null) { - config = getS2AConfig(); + config = getS2AConfigFromMDS(); } return config.getMtlsAddress(); } @@ -48,7 +48,7 @@ public synchronized String getMtlsS2AAddress() { /** @return the plaintext S2A Address from the mTLS config. */ public synchronized String getPlaintextS2AAddress() { if (config == null) { - config = getS2AConfig(); + config = getS2AConfigFromMDS(); } return config.getPlaintextAddress(); } @@ -60,7 +60,7 @@ public synchronized String getPlaintextS2AAddress() { * * @return the {@link S2AConfig}. */ - private S2AConfig getS2AConfig() { + private S2AConfig getS2AConfigFromMDS() { String plaintextS2AAddress = ""; String mtlsS2AAddress = ""; @@ -107,6 +107,6 @@ private S2AConfig getS2AConfig() { /** @return MDS mTLS autoconfig endpoint. */ private String getMdsMtlsEndpoint() { - return ComputeEngineCredentials.getMetadataServerUrl() + MTLS_CONFIG_ENDPOINT; + return ComputeEngineCredentials.getMetadataServerUrl() + S2A_CONFIG_ENDPOINT_POSTFIX; } } diff --git a/oauth2_http/javatests/com/google/auth/oauth2/MockMetadataServerTransport.java b/oauth2_http/javatests/com/google/auth/oauth2/MockMetadataServerTransport.java index 3db1c418f..098344a6f 100644 --- a/oauth2_http/javatests/com/google/auth/oauth2/MockMetadataServerTransport.java +++ b/oauth2_http/javatests/com/google/auth/oauth2/MockMetadataServerTransport.java @@ -328,6 +328,6 @@ protected boolean isIdentityDocumentUrl(String url) { protected boolean isMtlsConfigRequestUrl(String url) { return plaintextS2AAddress != null && mtlsS2AAddress != null - && url.equals(String.format(ComputeEngineCredentials.getMetadataServerUrl() + S2A.MTLS_CONFIG_ENDPOINT)); + && url.equals(String.format(ComputeEngineCredentials.getMetadataServerUrl() + S2A.S2A_CONFIG_ENDPOINT_POSTFIX)); } } From 32caef5066f64f69ede2f8e4f3592fc53286c8d8 Mon Sep 17 00:00:00 2001 From: Riya Mehta Date: Thu, 26 Sep 2024 14:44:28 -0700 Subject: [PATCH 15/44] set config in constructor. --- oauth2_http/java/com/google/auth/oauth2/S2A.java | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/oauth2_http/java/com/google/auth/oauth2/S2A.java b/oauth2_http/java/com/google/auth/oauth2/S2A.java index ad1361171..0f22fe650 100644 --- a/oauth2_http/java/com/google/auth/oauth2/S2A.java +++ b/oauth2_http/java/com/google/auth/oauth2/S2A.java @@ -35,21 +35,16 @@ public S2A() {} public void setHttpTransportFactory(HttpTransportFactory tf) { this.transportFactory = tf; + this.config = getS2AConfigFromMDS(); } /** @return the mTLS S2A Address from the mTLS config. */ - public synchronized String getMtlsS2AAddress() { - if (config == null) { - config = getS2AConfigFromMDS(); - } + public String getMtlsS2AAddress() { return config.getMtlsAddress(); } /** @return the plaintext S2A Address from the mTLS config. */ - public synchronized String getPlaintextS2AAddress() { - if (config == null) { - config = getS2AConfigFromMDS(); - } + public String getPlaintextS2AAddress() { return config.getPlaintextAddress(); } From b82790ac44f2d45d2232cd362656dc112fe6390b Mon Sep 17 00:00:00 2001 From: Riya Mehta Date: Thu, 26 Sep 2024 14:46:46 -0700 Subject: [PATCH 16/44] make error message more specific. --- oauth2_http/java/com/google/auth/oauth2/S2A.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oauth2_http/java/com/google/auth/oauth2/S2A.java b/oauth2_http/java/com/google/auth/oauth2/S2A.java index 0f22fe650..c40d7b6ed 100644 --- a/oauth2_http/java/com/google/auth/oauth2/S2A.java +++ b/oauth2_http/java/com/google/auth/oauth2/S2A.java @@ -25,7 +25,7 @@ public final class S2A { public static final String METADATA_FLAVOR = "Metadata-Flavor"; public static final String GOOGLE = "Google"; private static final int MAX_MDS_PING_TRIES = 3; - private static final String PARSE_ERROR_S2A = "Error parsing Mtls Auto Config response."; + private static final String PARSE_ERROR_S2A = "Error parsing S2A Config from MDS JSON response."; private S2AConfig config; From 05aa9cc3d33b57e2d06541f51011c6b850286719 Mon Sep 17 00:00:00 2001 From: Riya Mehta Date: Thu, 26 Sep 2024 14:54:00 -0700 Subject: [PATCH 17/44] move creation of transportFactory and parser out of loop. --- oauth2_http/java/com/google/auth/oauth2/S2A.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/oauth2_http/java/com/google/auth/oauth2/S2A.java b/oauth2_http/java/com/google/auth/oauth2/S2A.java index c40d7b6ed..642e6acac 100644 --- a/oauth2_http/java/com/google/auth/oauth2/S2A.java +++ b/oauth2_http/java/com/google/auth/oauth2/S2A.java @@ -61,17 +61,17 @@ private S2AConfig getS2AConfigFromMDS() { String url = getMdsMtlsEndpoint(); GenericUrl genericUrl = new GenericUrl(url); - + JsonObjectParser parser = new JsonObjectParser(OAuth2Utils.JSON_FACTORY); + if (transportFactory == null) { + transportFactory = + Iterables.getFirst( + ServiceLoader.load(HttpTransportFactory.class), OAuth2Utils.HTTP_TRANSPORT_FACTORY); + } + for (int i = 0; i < MAX_MDS_PING_TRIES; i++) { try { - if (transportFactory == null) { - transportFactory = - Iterables.getFirst( - ServiceLoader.load(HttpTransportFactory.class), OAuth2Utils.HTTP_TRANSPORT_FACTORY); - } HttpRequest request = transportFactory.create().createRequestFactory().buildGetRequest(genericUrl); - JsonObjectParser parser = new JsonObjectParser(OAuth2Utils.JSON_FACTORY); request.setParser(parser); request.getHeaders().set(METADATA_FLAVOR, GOOGLE); request.setThrowExceptionOnExecuteError(false); From 1466f0dc69818ac6a02ee993b8b049fe8e39dacb Mon Sep 17 00:00:00 2001 From: Riya Mehta Date: Wed, 2 Oct 2024 12:52:02 -0700 Subject: [PATCH 18/44] construct request once. --- .../java/com/google/auth/oauth2/S2A.java | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/oauth2_http/java/com/google/auth/oauth2/S2A.java b/oauth2_http/java/com/google/auth/oauth2/S2A.java index 642e6acac..e075fb6a4 100644 --- a/oauth2_http/java/com/google/auth/oauth2/S2A.java +++ b/oauth2_http/java/com/google/auth/oauth2/S2A.java @@ -66,21 +66,25 @@ private S2AConfig getS2AConfigFromMDS() { transportFactory = Iterables.getFirst( ServiceLoader.load(HttpTransportFactory.class), OAuth2Utils.HTTP_TRANSPORT_FACTORY); - } + } + + HttpRequest request; + try { + request = + transportFactory.create().createRequestFactory().buildGetRequest(genericUrl); + request.setParser(parser); + request.getHeaders().set(METADATA_FLAVOR, GOOGLE); + request.setThrowExceptionOnExecuteError(false); + } catch (IOException e) { + return S2AConfig.createBuilder().build(); + } for (int i = 0; i < MAX_MDS_PING_TRIES; i++) { try { - HttpRequest request = - transportFactory.create().createRequestFactory().buildGetRequest(genericUrl); - request.setParser(parser); - request.getHeaders().set(METADATA_FLAVOR, GOOGLE); - request.setThrowExceptionOnExecuteError(false); HttpResponse response = request.execute(); - if (!response.isSuccessStatusCode()) { continue; } - InputStream content = response.getContent(); if (content == null) { continue; From be1cfd2b664096999d402ff81aa98b0afd63e474 Mon Sep 17 00:00:00 2001 From: Riya Mehta Date: Wed, 2 Oct 2024 12:54:05 -0700 Subject: [PATCH 19/44] move declare to loop. --- oauth2_http/java/com/google/auth/oauth2/S2A.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/oauth2_http/java/com/google/auth/oauth2/S2A.java b/oauth2_http/java/com/google/auth/oauth2/S2A.java index e075fb6a4..1c5d0f128 100644 --- a/oauth2_http/java/com/google/auth/oauth2/S2A.java +++ b/oauth2_http/java/com/google/auth/oauth2/S2A.java @@ -56,9 +56,6 @@ public String getPlaintextS2AAddress() { * @return the {@link S2AConfig}. */ private S2AConfig getS2AConfigFromMDS() { - String plaintextS2AAddress = ""; - String mtlsS2AAddress = ""; - String url = getMdsMtlsEndpoint(); GenericUrl genericUrl = new GenericUrl(url); JsonObjectParser parser = new JsonObjectParser(OAuth2Utils.JSON_FACTORY); @@ -80,6 +77,8 @@ private S2AConfig getS2AConfigFromMDS() { } for (int i = 0; i < MAX_MDS_PING_TRIES; i++) { + String plaintextS2AAddress = ""; + String mtlsS2AAddress = ""; try { HttpResponse response = request.execute(); if (!response.isSuccessStatusCode()) { From 544d9d1a05d5355b066e0fb1fc25b823e537b226 Mon Sep 17 00:00:00 2001 From: Riya Mehta Date: Wed, 23 Oct 2024 16:21:15 -0700 Subject: [PATCH 20/44] remove unnecessary empty constructor. --- oauth2_http/java/com/google/auth/oauth2/S2A.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/oauth2_http/java/com/google/auth/oauth2/S2A.java b/oauth2_http/java/com/google/auth/oauth2/S2A.java index 764185b36..5c0f0b360 100644 --- a/oauth2_http/java/com/google/auth/oauth2/S2A.java +++ b/oauth2_http/java/com/google/auth/oauth2/S2A.java @@ -61,8 +61,6 @@ public final class S2A { private transient HttpTransportFactory transportFactory; - public S2A() {} - public void setHttpTransportFactory(HttpTransportFactory tf) { this.transportFactory = tf; this.config = getS2AConfigFromMDS(); From c3ede1d32b1b4c3cd4c336f9c88a0eba399634e5 Mon Sep 17 00:00:00 2001 From: Riya Mehta Date: Wed, 23 Oct 2024 16:25:13 -0700 Subject: [PATCH 21/44] Use default retry value. --- oauth2_http/java/com/google/auth/oauth2/S2A.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/oauth2_http/java/com/google/auth/oauth2/S2A.java b/oauth2_http/java/com/google/auth/oauth2/S2A.java index 5c0f0b360..3f2a4c09f 100644 --- a/oauth2_http/java/com/google/auth/oauth2/S2A.java +++ b/oauth2_http/java/com/google/auth/oauth2/S2A.java @@ -54,7 +54,6 @@ public final class S2A { public static final String METADATA_FLAVOR = "Metadata-Flavor"; public static final String GOOGLE = "Google"; - private static final int MAX_MDS_PING_TRIES = 3; private static final String PARSE_ERROR_S2A = "Error parsing S2A Config from MDS JSON response."; private S2AConfig config; @@ -104,7 +103,7 @@ private S2AConfig getS2AConfigFromMDS() { return S2AConfig.createBuilder().build(); } - for (int i = 0; i < MAX_MDS_PING_TRIES; i++) { + for (int i = 0; i < OAuth2Utils.DEFAULT_NUMBER_OF_RETRIES; i++) { String plaintextS2AAddress = ""; String mtlsS2AAddress = ""; try { From 8238d50e14e86a529ce0c421079d74b84725a57a Mon Sep 17 00:00:00 2001 From: Riya Mehta Date: Wed, 23 Oct 2024 16:54:17 -0700 Subject: [PATCH 22/44] set config in constructor. --- oauth2_http/java/com/google/auth/oauth2/S2A.java | 5 +++-- .../javatests/com/google/auth/oauth2/S2ATest.java | 10 ++++------ 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/oauth2_http/java/com/google/auth/oauth2/S2A.java b/oauth2_http/java/com/google/auth/oauth2/S2A.java index 3f2a4c09f..2ec4c0186 100644 --- a/oauth2_http/java/com/google/auth/oauth2/S2A.java +++ b/oauth2_http/java/com/google/auth/oauth2/S2A.java @@ -39,6 +39,7 @@ import com.google.common.collect.Iterables; import java.io.IOException; import java.io.InputStream; +import java.util.Optional; import java.util.ServiceLoader; import javax.annotation.concurrent.ThreadSafe; @@ -60,8 +61,8 @@ public final class S2A { private transient HttpTransportFactory transportFactory; - public void setHttpTransportFactory(HttpTransportFactory tf) { - this.transportFactory = tf; + public S2A(Optional transportFactory) { + this.transportFactory = transportFactory.get(); this.config = getS2AConfigFromMDS(); } diff --git a/oauth2_http/javatests/com/google/auth/oauth2/S2ATest.java b/oauth2_http/javatests/com/google/auth/oauth2/S2ATest.java index eb14c9e41..bd8d15af3 100644 --- a/oauth2_http/javatests/com/google/auth/oauth2/S2ATest.java +++ b/oauth2_http/javatests/com/google/auth/oauth2/S2ATest.java @@ -35,6 +35,7 @@ import com.google.api.client.http.HttpStatusCodes; import com.google.auth.oauth2.ComputeEngineCredentialsTest.MockMetadataServerTransportFactory; +import java.util.Optional; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -53,8 +54,7 @@ public void getS2AAddress_validAddress() { transportFactory.transport.setMtlsS2AAddress(S2A_MTLS_ADDRESS); transportFactory.transport.setRequestStatusCode(HttpStatusCodes.STATUS_CODE_OK); - S2A s2aUtils = new S2A(); - s2aUtils.setHttpTransportFactory(transportFactory); + S2A s2aUtils = new S2A(Optional.of(transportFactory)); String plaintextS2AAddress = s2aUtils.getPlaintextS2AAddress(); String mtlsS2AAddress = s2aUtils.getMtlsS2AAddress(); assertEquals(S2A_PLAINTEXT_ADDRESS, plaintextS2AAddress); @@ -69,8 +69,7 @@ public void getS2AAddress_queryEndpointResponseErrorCode_emptyAddress() { transportFactory.transport.setRequestStatusCode( HttpStatusCodes.STATUS_CODE_SERVICE_UNAVAILABLE); - S2A s2aUtils = new S2A(); - s2aUtils.setHttpTransportFactory(transportFactory); + S2A s2aUtils = new S2A(Optional.of(transportFactory)); String plaintextS2AAddress = s2aUtils.getPlaintextS2AAddress(); String mtlsS2AAddress = s2aUtils.getMtlsS2AAddress(); assertTrue(plaintextS2AAddress.isEmpty()); @@ -85,8 +84,7 @@ public void getS2AAddress_queryEndpointResponseEmpty_emptyAddress() { transportFactory.transport.setRequestStatusCode(HttpStatusCodes.STATUS_CODE_OK); transportFactory.transport.setEmptyContent(true); - S2A s2aUtils = new S2A(); - s2aUtils.setHttpTransportFactory(transportFactory); + S2A s2aUtils = new S2A(Optional.of(transportFactory)); String plaintextS2AAddress = s2aUtils.getPlaintextS2AAddress(); String mtlsS2AAddress = s2aUtils.getMtlsS2AAddress(); assertTrue(plaintextS2AAddress.isEmpty()); From 36ab0a99f69a6ad94758b0bde9ab9ea3d1123d57 Mon Sep 17 00:00:00 2001 From: Riya Mehta Date: Wed, 23 Oct 2024 16:57:48 -0700 Subject: [PATCH 23/44] make MDS MTLS autoconfig endpoint a static constant. --- oauth2_http/java/com/google/auth/oauth2/S2A.java | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/oauth2_http/java/com/google/auth/oauth2/S2A.java b/oauth2_http/java/com/google/auth/oauth2/S2A.java index 2ec4c0186..18b97790f 100644 --- a/oauth2_http/java/com/google/auth/oauth2/S2A.java +++ b/oauth2_http/java/com/google/auth/oauth2/S2A.java @@ -56,6 +56,7 @@ public final class S2A { public static final String METADATA_FLAVOR = "Metadata-Flavor"; public static final String GOOGLE = "Google"; private static final String PARSE_ERROR_S2A = "Error parsing S2A Config from MDS JSON response."; + private static final String MDS_MTLS_ENDPOINT = ComputeEngineCredentials.getMetadataServerUrl() + S2A_CONFIG_ENDPOINT_POSTFIX; private S2AConfig config; @@ -84,8 +85,7 @@ public String getPlaintextS2AAddress() { * @return the {@link S2AConfig}. */ private S2AConfig getS2AConfigFromMDS() { - String url = getMdsMtlsEndpoint(); - GenericUrl genericUrl = new GenericUrl(url); + GenericUrl genericUrl = new GenericUrl(MDS_MTLS_ENDPOINT); JsonObjectParser parser = new JsonObjectParser(OAuth2Utils.JSON_FACTORY); if (transportFactory == null) { transportFactory = @@ -130,9 +130,4 @@ private S2AConfig getS2AConfigFromMDS() { } return S2AConfig.createBuilder().build(); } - - /** @return MDS mTLS autoconfig endpoint. */ - private String getMdsMtlsEndpoint() { - return ComputeEngineCredentials.getMetadataServerUrl() + S2A_CONFIG_ENDPOINT_POSTFIX; - } } From 36a0ac7cad28656f791a057bdcac70bb6cfd1e27 Mon Sep 17 00:00:00 2001 From: Riya Mehta Date: Wed, 23 Oct 2024 16:59:23 -0700 Subject: [PATCH 24/44] make S2AConfig private. --- oauth2_http/java/com/google/auth/oauth2/S2AConfig.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oauth2_http/java/com/google/auth/oauth2/S2AConfig.java b/oauth2_http/java/com/google/auth/oauth2/S2AConfig.java index ab67c8cf8..86b05a665 100644 --- a/oauth2_http/java/com/google/auth/oauth2/S2AConfig.java +++ b/oauth2_http/java/com/google/auth/oauth2/S2AConfig.java @@ -33,7 +33,7 @@ import com.google.errorprone.annotations.CanIgnoreReturnValue; /** Holds an mTLS configuration (consists of address of S2A) retrieved from the Metadata Server. */ -public final class S2AConfig { +final class S2AConfig { // plaintextAddress is the plaintext address to reach the S2A. private final String plaintextAddress; From ae545c82e217353bf086a856674ac7ae54e59e35 Mon Sep 17 00:00:00 2001 From: Riya Mehta Date: Thu, 24 Oct 2024 09:09:52 -0700 Subject: [PATCH 25/44] make constants package private. --- oauth2_http/java/com/google/auth/oauth2/S2A.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/oauth2_http/java/com/google/auth/oauth2/S2A.java b/oauth2_http/java/com/google/auth/oauth2/S2A.java index 18b97790f..c0628b888 100644 --- a/oauth2_http/java/com/google/auth/oauth2/S2A.java +++ b/oauth2_http/java/com/google/auth/oauth2/S2A.java @@ -50,11 +50,11 @@ */ @ThreadSafe public final class S2A { - public static final String S2A_CONFIG_ENDPOINT_POSTFIX = + static final String S2A_CONFIG_ENDPOINT_POSTFIX = "/computeMetadata/v1/instance/platform-security/auto-mtls-configuration"; - public static final String METADATA_FLAVOR = "Metadata-Flavor"; - public static final String GOOGLE = "Google"; + static final String METADATA_FLAVOR = "Metadata-Flavor"; + static final String GOOGLE = "Google"; private static final String PARSE_ERROR_S2A = "Error parsing S2A Config from MDS JSON response."; private static final String MDS_MTLS_ENDPOINT = ComputeEngineCredentials.getMetadataServerUrl() + S2A_CONFIG_ENDPOINT_POSTFIX; From 47b3f2e4205fc69ab40759214a259aca7215c9db Mon Sep 17 00:00:00 2001 From: Riya Mehta Date: Thu, 24 Oct 2024 09:22:54 -0700 Subject: [PATCH 26/44] Use Builder pattern. --- .../java/com/google/auth/oauth2/S2A.java | 29 +++++++++++++++++-- .../com/google/auth/oauth2/S2ATest.java | 6 ++-- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/oauth2_http/java/com/google/auth/oauth2/S2A.java b/oauth2_http/java/com/google/auth/oauth2/S2A.java index c0628b888..693bc3dd0 100644 --- a/oauth2_http/java/com/google/auth/oauth2/S2A.java +++ b/oauth2_http/java/com/google/auth/oauth2/S2A.java @@ -37,6 +37,7 @@ import com.google.api.client.util.GenericData; import com.google.auth.http.HttpTransportFactory; import com.google.common.collect.Iterables; +import com.google.errorprone.annotations.CanIgnoreReturnValue; import java.io.IOException; import java.io.InputStream; import java.util.Optional; @@ -62,8 +63,8 @@ public final class S2A { private transient HttpTransportFactory transportFactory; - public S2A(Optional transportFactory) { - this.transportFactory = transportFactory.get(); + S2A(S2A.Builder builder) { + this.transportFactory = builder.getHttpTransportFactory(); this.config = getS2AConfigFromMDS(); } @@ -77,6 +78,30 @@ public String getPlaintextS2AAddress() { return config.getPlaintextAddress(); } + public static Builder newBuilder() { + return new Builder(); + } + + public static class Builder { + private HttpTransportFactory transportFactory; + + protected Builder() {} + + @CanIgnoreReturnValue + public Builder setHttpTransportFactory(HttpTransportFactory transportFactory) { + this.transportFactory = transportFactory; + return this; + } + + public HttpTransportFactory getHttpTransportFactory() { + return this.transportFactory; + } + + public S2A build() { + return new S2A(this); + } + } + /** * Queries the MDS mTLS Autoconfiguration endpoint and returns the {@link S2AConfig}. * diff --git a/oauth2_http/javatests/com/google/auth/oauth2/S2ATest.java b/oauth2_http/javatests/com/google/auth/oauth2/S2ATest.java index bd8d15af3..b26b82849 100644 --- a/oauth2_http/javatests/com/google/auth/oauth2/S2ATest.java +++ b/oauth2_http/javatests/com/google/auth/oauth2/S2ATest.java @@ -54,7 +54,7 @@ public void getS2AAddress_validAddress() { transportFactory.transport.setMtlsS2AAddress(S2A_MTLS_ADDRESS); transportFactory.transport.setRequestStatusCode(HttpStatusCodes.STATUS_CODE_OK); - S2A s2aUtils = new S2A(Optional.of(transportFactory)); + S2A s2aUtils = S2A.newBuilder().setHttpTransportFactory(transportFactory).build(); String plaintextS2AAddress = s2aUtils.getPlaintextS2AAddress(); String mtlsS2AAddress = s2aUtils.getMtlsS2AAddress(); assertEquals(S2A_PLAINTEXT_ADDRESS, plaintextS2AAddress); @@ -69,7 +69,7 @@ public void getS2AAddress_queryEndpointResponseErrorCode_emptyAddress() { transportFactory.transport.setRequestStatusCode( HttpStatusCodes.STATUS_CODE_SERVICE_UNAVAILABLE); - S2A s2aUtils = new S2A(Optional.of(transportFactory)); + S2A s2aUtils = S2A.newBuilder().setHttpTransportFactory(transportFactory).build(); String plaintextS2AAddress = s2aUtils.getPlaintextS2AAddress(); String mtlsS2AAddress = s2aUtils.getMtlsS2AAddress(); assertTrue(plaintextS2AAddress.isEmpty()); @@ -84,7 +84,7 @@ public void getS2AAddress_queryEndpointResponseEmpty_emptyAddress() { transportFactory.transport.setRequestStatusCode(HttpStatusCodes.STATUS_CODE_OK); transportFactory.transport.setEmptyContent(true); - S2A s2aUtils = new S2A(Optional.of(transportFactory)); + S2A s2aUtils = S2A.newBuilder().setHttpTransportFactory(transportFactory).build(); String plaintextS2AAddress = s2aUtils.getPlaintextS2AAddress(); String mtlsS2AAddress = s2aUtils.getMtlsS2AAddress(); assertTrue(plaintextS2AAddress.isEmpty()); From fb577a1b6f3ba7b34f6fa0318309deb7efb76db8 Mon Sep 17 00:00:00 2001 From: Riya Mehta Date: Thu, 24 Oct 2024 10:09:51 -0700 Subject: [PATCH 27/44] Improve javadoc. --- oauth2_http/java/com/google/auth/oauth2/S2A.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/oauth2_http/java/com/google/auth/oauth2/S2A.java b/oauth2_http/java/com/google/auth/oauth2/S2A.java index 693bc3dd0..00bafec8d 100644 --- a/oauth2_http/java/com/google/auth/oauth2/S2A.java +++ b/oauth2_http/java/com/google/auth/oauth2/S2A.java @@ -105,7 +105,15 @@ public S2A build() { /** * Queries the MDS mTLS Autoconfiguration endpoint and returns the {@link S2AConfig}. * - *

Returns {@link S2AConfig} with empty addresses on error. + *

Returns {@link S2AConfig}. If S2A is not running, or if any error occurs when + * making the request to MDS, {@link S2AConfig} will be populated with empty addresses. + * + * Users are expected to try to fetch the mTLS-S2A address first (via + * {@link getMtlsS2AAddress}). If it is empty or they have some problem loading the + * mTLS-MDS credentials, they should then fallback to fetching the plaintext-S2A address + * (via {@link getPlaintextS2AAddress}). If the plaintext-S2A address is empty it means + * that an error occurred when talking to the MDS or that S2A is not running in the + * environment; in either case this indicates S2A shouldn't be used. * * @return the {@link S2AConfig}. */ From 1f333b4c5f5a7d6828204c244217f187945c11a2 Mon Sep 17 00:00:00 2001 From: Riya Mehta Date: Thu, 24 Oct 2024 10:12:15 -0700 Subject: [PATCH 28/44] Do not retry if autoconfig endpoint doesn't exist. --- oauth2_http/java/com/google/auth/oauth2/S2A.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/oauth2_http/java/com/google/auth/oauth2/S2A.java b/oauth2_http/java/com/google/auth/oauth2/S2A.java index 00bafec8d..4ebf94e12 100644 --- a/oauth2_http/java/com/google/auth/oauth2/S2A.java +++ b/oauth2_http/java/com/google/auth/oauth2/S2A.java @@ -143,6 +143,11 @@ private S2AConfig getS2AConfigFromMDS() { try { HttpResponse response = request.execute(); if (!response.isSuccessStatusCode()) { + int statusCode = response.getStatusCode(); + if (statusCode >= 400 && statusCode < 500) { + // Do not retry if endpoint does not exist. + return S2AConfig.createBuilder().build(); + } continue; } InputStream content = response.getContent(); From 0bbd3207a5cfe3f64e84eba510a50dc1fe755685 Mon Sep 17 00:00:00 2001 From: Riya Mehta Date: Thu, 24 Oct 2024 10:31:52 -0700 Subject: [PATCH 29/44] add comment around catching IOException. --- oauth2_http/java/com/google/auth/oauth2/S2A.java | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/oauth2_http/java/com/google/auth/oauth2/S2A.java b/oauth2_http/java/com/google/auth/oauth2/S2A.java index 4ebf94e12..0b445e8e7 100644 --- a/oauth2_http/java/com/google/auth/oauth2/S2A.java +++ b/oauth2_http/java/com/google/auth/oauth2/S2A.java @@ -106,14 +106,15 @@ public S2A build() { * Queries the MDS mTLS Autoconfiguration endpoint and returns the {@link S2AConfig}. * *

Returns {@link S2AConfig}. If S2A is not running, or if any error occurs when - * making the request to MDS, {@link S2AConfig} will be populated with empty addresses. + * making the request to MDS / processing the response, {@link S2AConfig} will be + * populated with empty addresses. * * Users are expected to try to fetch the mTLS-S2A address first (via * {@link getMtlsS2AAddress}). If it is empty or they have some problem loading the * mTLS-MDS credentials, they should then fallback to fetching the plaintext-S2A address * (via {@link getPlaintextS2AAddress}). If the plaintext-S2A address is empty it means - * that an error occurred when talking to the MDS or that S2A is not running in the - * environment; in either case this indicates S2A shouldn't be used. + * that an error occurred when talking to the MDS / processing the response or that S2A + * is not running in the environment; in either case this indicates S2A shouldn't be used. * * @return the {@link S2AConfig}. */ @@ -159,6 +160,13 @@ private S2AConfig getS2AConfigFromMDS() { OAuth2Utils.validateString(responseData, "plaintext_address", PARSE_ERROR_S2A); mtlsS2AAddress = OAuth2Utils.validateString(responseData, "mtls_address", PARSE_ERROR_S2A); } catch (IOException e) { + /* + Indicates an error when executing the {@link HttpRequest} or parsing the response from MDS. + In either case retry the request. If max retries have been exhausted, empty addresses + will be populated in S2AConfig. The user/caller of this library passes the address to the + S2A client, which will fail to create S2AChannelCredentials (due to empty address) after + which the user/caller should fallback to creating a channel without S2A. + */ continue; } return S2AConfig.createBuilder() From 0e6f5cef7a289b2a875a4788a4eca2d17545c944 Mon Sep 17 00:00:00 2001 From: Riya Mehta Date: Thu, 24 Oct 2024 16:15:23 -0700 Subject: [PATCH 30/44] Try and parse each address returned from MDS. --- .../java/com/google/auth/oauth2/S2A.java | 16 +++++--- .../oauth2/MockMetadataServerTransport.java | 20 ++++++++-- .../com/google/auth/oauth2/S2ATest.java | 39 +++++++++++++++++++ 3 files changed, 67 insertions(+), 8 deletions(-) diff --git a/oauth2_http/java/com/google/auth/oauth2/S2A.java b/oauth2_http/java/com/google/auth/oauth2/S2A.java index 0b445e8e7..e3fc27b74 100644 --- a/oauth2_http/java/com/google/auth/oauth2/S2A.java +++ b/oauth2_http/java/com/google/auth/oauth2/S2A.java @@ -51,6 +51,8 @@ */ @ThreadSafe public final class S2A { + static final String S2A_PLAINTEXT_ADDRESS_JSON_KEY = "plaintext_address"; + static final String S2A_MTLS_ADDRESS_JSON_KEY = "mtls_address"; static final String S2A_CONFIG_ENDPOINT_POSTFIX = "/computeMetadata/v1/instance/platform-security/auto-mtls-configuration"; @@ -156,13 +158,17 @@ private S2AConfig getS2AConfigFromMDS() { continue; } GenericData responseData = response.parseAs(GenericData.class); - plaintextS2AAddress = - OAuth2Utils.validateString(responseData, "plaintext_address", PARSE_ERROR_S2A); - mtlsS2AAddress = OAuth2Utils.validateString(responseData, "mtls_address", PARSE_ERROR_S2A); + try { + plaintextS2AAddress = + OAuth2Utils.validateString(responseData, S2A_PLAINTEXT_ADDRESS_JSON_KEY, PARSE_ERROR_S2A); + } catch (IOException ignore) {} + try { + mtlsS2AAddress = OAuth2Utils.validateString(responseData, S2A_MTLS_ADDRESS_JSON_KEY, PARSE_ERROR_S2A); + } catch (IOException ignore) {} } catch (IOException e) { /* - Indicates an error when executing the {@link HttpRequest} or parsing the response from MDS. - In either case retry the request. If max retries have been exhausted, empty addresses + Indicates an error when executing the {@link HttpRequest}. + The request is retried, if max retries have been exhausted, empty addresses will be populated in S2AConfig. The user/caller of this library passes the address to the S2A client, which will fail to create S2AChannelCredentials (due to empty address) after which the user/caller should fallback to creating a channel without S2A. diff --git a/oauth2_http/javatests/com/google/auth/oauth2/MockMetadataServerTransport.java b/oauth2_http/javatests/com/google/auth/oauth2/MockMetadataServerTransport.java index dd466e36c..a061b7a61 100644 --- a/oauth2_http/javatests/com/google/auth/oauth2/MockMetadataServerTransport.java +++ b/oauth2_http/javatests/com/google/auth/oauth2/MockMetadataServerTransport.java @@ -62,8 +62,12 @@ public class MockMetadataServerTransport extends MockHttpTransport { private byte[] signature; + private String plaintextS2AAddressJsonKey; + private String plaintextS2AAddress; + private String mtlsS2AAddressJsonKey; + private String mtlsS2AAddress; private boolean emptyContent; @@ -108,10 +112,18 @@ public void setIdToken(String idToken) { this.idToken = idToken; } + public void setPlaintextS2AAddressJsonKey(String key) { + this.plaintextS2AAddressJsonKey = key; + } + public void setPlaintextS2AAddress(String address) { this.plaintextS2AAddress = address; } + public void setMtlsS2AAddressJsonKey(String key) { + this.mtlsS2AAddressJsonKey = key; + } + public void setMtlsS2AAddress(String address) { this.mtlsS2AAddress = address; } @@ -304,8 +316,8 @@ public LowLevelHttpResponse execute() throws IOException { // Create the JSON response GenericJson content = new GenericJson(); content.setFactory(OAuth2Utils.JSON_FACTORY); - content.put("plaintext_address", plaintextS2AAddress); - content.put("mtls_address", mtlsS2AAddress); + content.put(plaintextS2AAddressJsonKey, plaintextS2AAddress); + content.put(mtlsS2AAddressJsonKey, mtlsS2AAddress); String contentText = content.toPrettyString(); MockLowLevelHttpResponse response = new MockLowLevelHttpResponse(); @@ -337,8 +349,10 @@ protected boolean isIdentityDocumentUrl(String url) { } protected boolean isMtlsConfigRequestUrl(String url) { - return plaintextS2AAddress != null + return plaintextS2AAddressJsonKey != null + && plaintextS2AAddress != null && mtlsS2AAddress != null + && mtlsS2AAddressJsonKey != null && url.equals(String.format(ComputeEngineCredentials.getMetadataServerUrl() + S2A.S2A_CONFIG_ENDPOINT_POSTFIX)); } } diff --git a/oauth2_http/javatests/com/google/auth/oauth2/S2ATest.java b/oauth2_http/javatests/com/google/auth/oauth2/S2ATest.java index b26b82849..00dae8499 100644 --- a/oauth2_http/javatests/com/google/auth/oauth2/S2ATest.java +++ b/oauth2_http/javatests/com/google/auth/oauth2/S2ATest.java @@ -44,13 +44,16 @@ @RunWith(JUnit4.class) public class S2ATest { + private static final String INVALID_JSON_KEY = "invalid_key"; private static final String S2A_PLAINTEXT_ADDRESS = "plaintext"; private static final String S2A_MTLS_ADDRESS = "mtls"; @Test public void getS2AAddress_validAddress() { MockMetadataServerTransportFactory transportFactory = new MockMetadataServerTransportFactory(); + transportFactory.transport.setPlaintextS2AAddressJsonKey(S2A.S2A_PLAINTEXT_ADDRESS_JSON_KEY); transportFactory.transport.setPlaintextS2AAddress(S2A_PLAINTEXT_ADDRESS); + transportFactory.transport.setMtlsS2AAddressJsonKey(S2A.S2A_MTLS_ADDRESS_JSON_KEY); transportFactory.transport.setMtlsS2AAddress(S2A_MTLS_ADDRESS); transportFactory.transport.setRequestStatusCode(HttpStatusCodes.STATUS_CODE_OK); @@ -64,7 +67,9 @@ public void getS2AAddress_validAddress() { @Test public void getS2AAddress_queryEndpointResponseErrorCode_emptyAddress() { MockMetadataServerTransportFactory transportFactory = new MockMetadataServerTransportFactory(); + transportFactory.transport.setPlaintextS2AAddressJsonKey(S2A.S2A_PLAINTEXT_ADDRESS_JSON_KEY); transportFactory.transport.setPlaintextS2AAddress(S2A_PLAINTEXT_ADDRESS); + transportFactory.transport.setMtlsS2AAddressJsonKey(S2A.S2A_MTLS_ADDRESS_JSON_KEY); transportFactory.transport.setMtlsS2AAddress(S2A_MTLS_ADDRESS); transportFactory.transport.setRequestStatusCode( HttpStatusCodes.STATUS_CODE_SERVICE_UNAVAILABLE); @@ -79,7 +84,9 @@ public void getS2AAddress_queryEndpointResponseErrorCode_emptyAddress() { @Test public void getS2AAddress_queryEndpointResponseEmpty_emptyAddress() { MockMetadataServerTransportFactory transportFactory = new MockMetadataServerTransportFactory(); + transportFactory.transport.setPlaintextS2AAddressJsonKey(S2A.S2A_PLAINTEXT_ADDRESS_JSON_KEY); transportFactory.transport.setPlaintextS2AAddress(S2A_PLAINTEXT_ADDRESS); + transportFactory.transport.setMtlsS2AAddressJsonKey(S2A.S2A_MTLS_ADDRESS_JSON_KEY); transportFactory.transport.setMtlsS2AAddress(S2A_MTLS_ADDRESS); transportFactory.transport.setRequestStatusCode(HttpStatusCodes.STATUS_CODE_OK); transportFactory.transport.setEmptyContent(true); @@ -90,4 +97,36 @@ public void getS2AAddress_queryEndpointResponseEmpty_emptyAddress() { assertTrue(plaintextS2AAddress.isEmpty()); assertTrue(mtlsS2AAddress.isEmpty()); } + + @Test + public void getS2AAddress_queryEndpointResponseInvalidPlaintextJsonKey_plaintextEmptyAddress() { + MockMetadataServerTransportFactory transportFactory = new MockMetadataServerTransportFactory(); + transportFactory.transport.setPlaintextS2AAddressJsonKey(INVALID_JSON_KEY); + transportFactory.transport.setPlaintextS2AAddress(S2A_PLAINTEXT_ADDRESS); + transportFactory.transport.setMtlsS2AAddressJsonKey(S2A.S2A_MTLS_ADDRESS_JSON_KEY); + transportFactory.transport.setMtlsS2AAddress(S2A_MTLS_ADDRESS); + transportFactory.transport.setRequestStatusCode(HttpStatusCodes.STATUS_CODE_OK); + + S2A s2aUtils = S2A.newBuilder().setHttpTransportFactory(transportFactory).build(); + String plaintextS2AAddress = s2aUtils.getPlaintextS2AAddress(); + String mtlsS2AAddress = s2aUtils.getMtlsS2AAddress(); + assertTrue(plaintextS2AAddress.isEmpty()); + assertEquals(S2A_MTLS_ADDRESS, mtlsS2AAddress); + } + + @Test + public void getS2AAddress_queryEndpointResponseInvalidMtlsJsonKey_mtlsEmptyAddress() { + MockMetadataServerTransportFactory transportFactory = new MockMetadataServerTransportFactory(); + transportFactory.transport.setPlaintextS2AAddressJsonKey(S2A.S2A_PLAINTEXT_ADDRESS_JSON_KEY); + transportFactory.transport.setPlaintextS2AAddress(S2A_PLAINTEXT_ADDRESS); + transportFactory.transport.setMtlsS2AAddressJsonKey(INVALID_JSON_KEY); + transportFactory.transport.setMtlsS2AAddress(S2A_MTLS_ADDRESS); + transportFactory.transport.setRequestStatusCode(HttpStatusCodes.STATUS_CODE_OK); + + S2A s2aUtils = S2A.newBuilder().setHttpTransportFactory(transportFactory).build(); + String plaintextS2AAddress = s2aUtils.getPlaintextS2AAddress(); + String mtlsS2AAddress = s2aUtils.getMtlsS2AAddress(); + assertEquals(S2A_PLAINTEXT_ADDRESS, plaintextS2AAddress); + assertTrue(mtlsS2AAddress.isEmpty()); + } } From e786886b996e5530dc5959b1d4a42b0023b27aa3 Mon Sep 17 00:00:00 2001 From: Riya Mehta Date: Thu, 24 Oct 2024 16:18:18 -0700 Subject: [PATCH 31/44] update license dates on added files. --- oauth2_http/java/com/google/auth/oauth2/S2A.java | 2 +- oauth2_http/java/com/google/auth/oauth2/S2AConfig.java | 2 +- oauth2_http/javatests/com/google/auth/oauth2/S2AConfigTest.java | 2 +- oauth2_http/javatests/com/google/auth/oauth2/S2ATest.java | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/oauth2_http/java/com/google/auth/oauth2/S2A.java b/oauth2_http/java/com/google/auth/oauth2/S2A.java index e3fc27b74..7f0b0707d 100644 --- a/oauth2_http/java/com/google/auth/oauth2/S2A.java +++ b/oauth2_http/java/com/google/auth/oauth2/S2A.java @@ -1,5 +1,5 @@ /* - * Copyright 2016, Google Inc. All rights reserved. + * Copyright 2024, Google Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are diff --git a/oauth2_http/java/com/google/auth/oauth2/S2AConfig.java b/oauth2_http/java/com/google/auth/oauth2/S2AConfig.java index 86b05a665..7b6e81d6b 100644 --- a/oauth2_http/java/com/google/auth/oauth2/S2AConfig.java +++ b/oauth2_http/java/com/google/auth/oauth2/S2AConfig.java @@ -1,5 +1,5 @@ /* - * Copyright 2016, Google Inc. All rights reserved. + * Copyright 2024, Google Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are diff --git a/oauth2_http/javatests/com/google/auth/oauth2/S2AConfigTest.java b/oauth2_http/javatests/com/google/auth/oauth2/S2AConfigTest.java index 9b3472825..cd8cca899 100644 --- a/oauth2_http/javatests/com/google/auth/oauth2/S2AConfigTest.java +++ b/oauth2_http/javatests/com/google/auth/oauth2/S2AConfigTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2016, Google Inc. All rights reserved. + * Copyright 2024, Google Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are diff --git a/oauth2_http/javatests/com/google/auth/oauth2/S2ATest.java b/oauth2_http/javatests/com/google/auth/oauth2/S2ATest.java index 00dae8499..5ef3af3fa 100644 --- a/oauth2_http/javatests/com/google/auth/oauth2/S2ATest.java +++ b/oauth2_http/javatests/com/google/auth/oauth2/S2ATest.java @@ -1,5 +1,5 @@ /* - * Copyright 2016, Google Inc. All rights reserved. + * Copyright 2024, Google Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are From 12b248d8245162d63a1fe4863921b4cb595afa48 Mon Sep 17 00:00:00 2001 From: Riya Mehta Date: Thu, 24 Oct 2024 17:34:19 -0700 Subject: [PATCH 32/44] Use Google Java Http client built in retry. --- .../java/com/google/auth/oauth2/S2A.java | 87 ++++++++++--------- .../oauth2/MockMetadataServerTransport.java | 6 +- 2 files changed, 52 insertions(+), 41 deletions(-) diff --git a/oauth2_http/java/com/google/auth/oauth2/S2A.java b/oauth2_http/java/com/google/auth/oauth2/S2A.java index 7f0b0707d..eead5b4e7 100644 --- a/oauth2_http/java/com/google/auth/oauth2/S2A.java +++ b/oauth2_http/java/com/google/auth/oauth2/S2A.java @@ -31,17 +31,23 @@ package com.google.auth.oauth2; import com.google.api.client.http.GenericUrl; +import com.google.api.client.http.HttpBackOffIOExceptionHandler; +import com.google.api.client.http.HttpBackOffUnsuccessfulResponseHandler; import com.google.api.client.http.HttpRequest; import com.google.api.client.http.HttpResponse; import com.google.api.client.json.JsonObjectParser; +import com.google.api.client.util.ExponentialBackOff; import com.google.api.client.util.GenericData; import com.google.auth.http.HttpTransportFactory; import com.google.common.collect.Iterables; import com.google.errorprone.annotations.CanIgnoreReturnValue; import java.io.IOException; import java.io.InputStream; +import java.util.Arrays; +import java.util.HashSet; import java.util.Optional; import java.util.ServiceLoader; +import java.util.Set; import javax.annotation.concurrent.ThreadSafe; /** @@ -58,6 +64,7 @@ public final class S2A { static final String METADATA_FLAVOR = "Metadata-Flavor"; static final String GOOGLE = "Google"; + private static final Set RETRYABLE_STATUS_CODES = new HashSet<>(Arrays.asList(500, 502, 503)); private static final String PARSE_ERROR_S2A = "Error parsing S2A Config from MDS JSON response."; private static final String MDS_MTLS_ENDPOINT = ComputeEngineCredentials.getMetadataServerUrl() + S2A_CONFIG_ENDPOINT_POSTFIX; @@ -136,50 +143,52 @@ private S2AConfig getS2AConfigFromMDS() { request.setParser(parser); request.getHeaders().set(METADATA_FLAVOR, GOOGLE); request.setThrowExceptionOnExecuteError(false); + request.setNumberOfRetries(OAuth2Utils.DEFAULT_NUMBER_OF_RETRIES); + + ExponentialBackOff backoff = + new ExponentialBackOff.Builder() + .setInitialIntervalMillis(OAuth2Utils.INITIAL_RETRY_INTERVAL_MILLIS) + .setRandomizationFactor(OAuth2Utils.RETRY_RANDOMIZATION_FACTOR) + .setMultiplier(OAuth2Utils.RETRY_MULTIPLIER) + .build(); + + // Retry on 5xx status codes. + request.setUnsuccessfulResponseHandler( + new HttpBackOffUnsuccessfulResponseHandler(backoff) + .setBackOffRequired( + response -> + RETRYABLE_STATUS_CODES.contains(response.getStatusCode()))); + request.setIOExceptionHandler(new HttpBackOffIOExceptionHandler(backoff)); } catch (IOException e) { return S2AConfig.createBuilder().build(); } - for (int i = 0; i < OAuth2Utils.DEFAULT_NUMBER_OF_RETRIES; i++) { - String plaintextS2AAddress = ""; - String mtlsS2AAddress = ""; - try { - HttpResponse response = request.execute(); - if (!response.isSuccessStatusCode()) { - int statusCode = response.getStatusCode(); - if (statusCode >= 400 && statusCode < 500) { - // Do not retry if endpoint does not exist. - return S2AConfig.createBuilder().build(); - } - continue; - } - InputStream content = response.getContent(); - if (content == null) { - continue; - } - GenericData responseData = response.parseAs(GenericData.class); - try { - plaintextS2AAddress = - OAuth2Utils.validateString(responseData, S2A_PLAINTEXT_ADDRESS_JSON_KEY, PARSE_ERROR_S2A); - } catch (IOException ignore) {} - try { - mtlsS2AAddress = OAuth2Utils.validateString(responseData, S2A_MTLS_ADDRESS_JSON_KEY, PARSE_ERROR_S2A); - } catch (IOException ignore) {} - } catch (IOException e) { - /* - Indicates an error when executing the {@link HttpRequest}. - The request is retried, if max retries have been exhausted, empty addresses - will be populated in S2AConfig. The user/caller of this library passes the address to the - S2A client, which will fail to create S2AChannelCredentials (due to empty address) after - which the user/caller should fallback to creating a channel without S2A. - */ - continue; + String plaintextS2AAddress = ""; + String mtlsS2AAddress = ""; + try { + HttpResponse response = request.execute(); + InputStream content = response.getContent(); + if (content == null) { + return S2AConfig.createBuilder().build(); } - return S2AConfig.createBuilder() - .setPlaintextAddress(plaintextS2AAddress) - .setMtlsAddress(mtlsS2AAddress) - .build(); + GenericData responseData = response.parseAs(GenericData.class); + try { + plaintextS2AAddress = + OAuth2Utils.validateString(responseData, S2A_PLAINTEXT_ADDRESS_JSON_KEY, PARSE_ERROR_S2A); + } catch (IOException ignore) {} + try { + mtlsS2AAddress = OAuth2Utils.validateString(responseData, S2A_MTLS_ADDRESS_JSON_KEY, PARSE_ERROR_S2A); + } catch (IOException ignore) {} + } catch (IOException ignore) { + /* + * Return empty addresses in {@link S2AConfig} once all retries have been exhausted. + */ } - return S2AConfig.createBuilder().build(); + + return S2AConfig.createBuilder() + .setPlaintextAddress(plaintextS2AAddress) + .setMtlsAddress(mtlsS2AAddress) + .build(); + } } diff --git a/oauth2_http/javatests/com/google/auth/oauth2/MockMetadataServerTransport.java b/oauth2_http/javatests/com/google/auth/oauth2/MockMetadataServerTransport.java index a061b7a61..c810bee68 100644 --- a/oauth2_http/javatests/com/google/auth/oauth2/MockMetadataServerTransport.java +++ b/oauth2_http/javatests/com/google/auth/oauth2/MockMetadataServerTransport.java @@ -316,8 +316,10 @@ public LowLevelHttpResponse execute() throws IOException { // Create the JSON response GenericJson content = new GenericJson(); content.setFactory(OAuth2Utils.JSON_FACTORY); - content.put(plaintextS2AAddressJsonKey, plaintextS2AAddress); - content.put(mtlsS2AAddressJsonKey, mtlsS2AAddress); + if (requestStatusCode < 400) { + content.put(plaintextS2AAddressJsonKey, plaintextS2AAddress); + content.put(mtlsS2AAddressJsonKey, mtlsS2AAddress); + } String contentText = content.toPrettyString(); MockLowLevelHttpResponse response = new MockLowLevelHttpResponse(); From 4d056380457e33f17fb758aec2b51a57849e751d Mon Sep 17 00:00:00 2001 From: Riya Mehta Date: Thu, 24 Oct 2024 17:41:44 -0700 Subject: [PATCH 33/44] Explain why no format check. --- oauth2_http/java/com/google/auth/oauth2/S2AConfig.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/oauth2_http/java/com/google/auth/oauth2/S2AConfig.java b/oauth2_http/java/com/google/auth/oauth2/S2AConfig.java index 7b6e81d6b..97e8c883e 100644 --- a/oauth2_http/java/com/google/auth/oauth2/S2AConfig.java +++ b/oauth2_http/java/com/google/auth/oauth2/S2AConfig.java @@ -66,12 +66,20 @@ public static final class Builder { @CanIgnoreReturnValue public Builder setPlaintextAddress(String plaintextAddress) { + /* + * No validation / format check is necessary here. It is up to the client which consumes this address + * to return error if there is a problem connecting to S2A at that address. + */ this.plaintextAddress = plaintextAddress; return this; } @CanIgnoreReturnValue public Builder setMtlsAddress(String mtlsAddress) { + /* + * No validation / format check is necessary here. It is up to the client which consumes this address + * to return error if there is a problem connecting to S2A at that address. + */ this.mtlsAddress = mtlsAddress; return this; } From 7447f0bc5e1adca191978f2c813860e03f130a26 Mon Sep 17 00:00:00 2001 From: Riya Mehta Date: Fri, 25 Oct 2024 09:20:14 -0700 Subject: [PATCH 34/44] run linter. --- .../java/com/google/auth/oauth2/S2A.java | 64 ++++++++++--------- .../com/google/auth/oauth2/S2AConfig.java | 8 +-- .../oauth2/MockMetadataServerTransport.java | 4 +- .../com/google/auth/oauth2/S2ATest.java | 1 - 4 files changed, 40 insertions(+), 37 deletions(-) diff --git a/oauth2_http/java/com/google/auth/oauth2/S2A.java b/oauth2_http/java/com/google/auth/oauth2/S2A.java index eead5b4e7..067eb4647 100644 --- a/oauth2_http/java/com/google/auth/oauth2/S2A.java +++ b/oauth2_http/java/com/google/auth/oauth2/S2A.java @@ -45,7 +45,6 @@ import java.io.InputStream; import java.util.Arrays; import java.util.HashSet; -import java.util.Optional; import java.util.ServiceLoader; import java.util.Set; import javax.annotation.concurrent.ThreadSafe; @@ -64,9 +63,11 @@ public final class S2A { static final String METADATA_FLAVOR = "Metadata-Flavor"; static final String GOOGLE = "Google"; - private static final Set RETRYABLE_STATUS_CODES = new HashSet<>(Arrays.asList(500, 502, 503)); + private static final Set RETRYABLE_STATUS_CODES = + new HashSet<>(Arrays.asList(500, 502, 503)); private static final String PARSE_ERROR_S2A = "Error parsing S2A Config from MDS JSON response."; - private static final String MDS_MTLS_ENDPOINT = ComputeEngineCredentials.getMetadataServerUrl() + S2A_CONFIG_ENDPOINT_POSTFIX; + private static final String MDS_MTLS_ENDPOINT = + ComputeEngineCredentials.getMetadataServerUrl() + S2A_CONFIG_ENDPOINT_POSTFIX; private S2AConfig config; @@ -114,22 +115,22 @@ public S2A build() { /** * Queries the MDS mTLS Autoconfiguration endpoint and returns the {@link S2AConfig}. * - *

Returns {@link S2AConfig}. If S2A is not running, or if any error occurs when - * making the request to MDS / processing the response, {@link S2AConfig} will be - * populated with empty addresses. - * - * Users are expected to try to fetch the mTLS-S2A address first (via - * {@link getMtlsS2AAddress}). If it is empty or they have some problem loading the - * mTLS-MDS credentials, they should then fallback to fetching the plaintext-S2A address - * (via {@link getPlaintextS2AAddress}). If the plaintext-S2A address is empty it means - * that an error occurred when talking to the MDS / processing the response or that S2A - * is not running in the environment; in either case this indicates S2A shouldn't be used. + *

Returns {@link S2AConfig}. If S2A is not running, or if any error occurs when making the + * request to MDS / processing the response, {@link S2AConfig} will be populated with empty + * addresses. + * + *

Users are expected to try to fetch the mTLS-S2A address first (via {@link + * getMtlsS2AAddress}). If it is empty or they have some problem loading the mTLS-MDS credentials, + * they should then fallback to fetching the plaintext-S2A address (via {@link + * getPlaintextS2AAddress}). If the plaintext-S2A address is empty it means that an error occurred + * when talking to the MDS / processing the response or that S2A is not running in the + * environment; in either case this indicates S2A shouldn't be used. * * @return the {@link S2AConfig}. */ private S2AConfig getS2AConfigFromMDS() { GenericUrl genericUrl = new GenericUrl(MDS_MTLS_ENDPOINT); - JsonObjectParser parser = new JsonObjectParser(OAuth2Utils.JSON_FACTORY); + JsonObjectParser parser = new JsonObjectParser(OAuth2Utils.JSON_FACTORY); if (transportFactory == null) { transportFactory = Iterables.getFirst( @@ -138,26 +139,24 @@ private S2AConfig getS2AConfigFromMDS() { HttpRequest request; try { - request = - transportFactory.create().createRequestFactory().buildGetRequest(genericUrl); + request = transportFactory.create().createRequestFactory().buildGetRequest(genericUrl); request.setParser(parser); request.getHeaders().set(METADATA_FLAVOR, GOOGLE); request.setThrowExceptionOnExecuteError(false); request.setNumberOfRetries(OAuth2Utils.DEFAULT_NUMBER_OF_RETRIES); ExponentialBackOff backoff = - new ExponentialBackOff.Builder() - .setInitialIntervalMillis(OAuth2Utils.INITIAL_RETRY_INTERVAL_MILLIS) - .setRandomizationFactor(OAuth2Utils.RETRY_RANDOMIZATION_FACTOR) - .setMultiplier(OAuth2Utils.RETRY_MULTIPLIER) - .build(); + new ExponentialBackOff.Builder() + .setInitialIntervalMillis(OAuth2Utils.INITIAL_RETRY_INTERVAL_MILLIS) + .setRandomizationFactor(OAuth2Utils.RETRY_RANDOMIZATION_FACTOR) + .setMultiplier(OAuth2Utils.RETRY_MULTIPLIER) + .build(); // Retry on 5xx status codes. request.setUnsuccessfulResponseHandler( - new HttpBackOffUnsuccessfulResponseHandler(backoff) - .setBackOffRequired( - response -> - RETRYABLE_STATUS_CODES.contains(response.getStatusCode()))); + new HttpBackOffUnsuccessfulResponseHandler(backoff) + .setBackOffRequired( + response -> RETRYABLE_STATUS_CODES.contains(response.getStatusCode()))); request.setIOExceptionHandler(new HttpBackOffIOExceptionHandler(backoff)); } catch (IOException e) { return S2AConfig.createBuilder().build(); @@ -174,11 +173,15 @@ private S2AConfig getS2AConfigFromMDS() { GenericData responseData = response.parseAs(GenericData.class); try { plaintextS2AAddress = - OAuth2Utils.validateString(responseData, S2A_PLAINTEXT_ADDRESS_JSON_KEY, PARSE_ERROR_S2A); - } catch (IOException ignore) {} - try { - mtlsS2AAddress = OAuth2Utils.validateString(responseData, S2A_MTLS_ADDRESS_JSON_KEY, PARSE_ERROR_S2A); - } catch (IOException ignore) {} + OAuth2Utils.validateString( + responseData, S2A_PLAINTEXT_ADDRESS_JSON_KEY, PARSE_ERROR_S2A); + } catch (IOException ignore) { + } + try { + mtlsS2AAddress = + OAuth2Utils.validateString(responseData, S2A_MTLS_ADDRESS_JSON_KEY, PARSE_ERROR_S2A); + } catch (IOException ignore) { + } } catch (IOException ignore) { /* * Return empty addresses in {@link S2AConfig} once all retries have been exhausted. @@ -189,6 +192,5 @@ private S2AConfig getS2AConfigFromMDS() { .setPlaintextAddress(plaintextS2AAddress) .setMtlsAddress(mtlsS2AAddress) .build(); - } } diff --git a/oauth2_http/java/com/google/auth/oauth2/S2AConfig.java b/oauth2_http/java/com/google/auth/oauth2/S2AConfig.java index 97e8c883e..6b9adb543 100644 --- a/oauth2_http/java/com/google/auth/oauth2/S2AConfig.java +++ b/oauth2_http/java/com/google/auth/oauth2/S2AConfig.java @@ -66,20 +66,20 @@ public static final class Builder { @CanIgnoreReturnValue public Builder setPlaintextAddress(String plaintextAddress) { - /* + /* * No validation / format check is necessary here. It is up to the client which consumes this address * to return error if there is a problem connecting to S2A at that address. - */ + */ this.plaintextAddress = plaintextAddress; return this; } @CanIgnoreReturnValue public Builder setMtlsAddress(String mtlsAddress) { - /* + /* * No validation / format check is necessary here. It is up to the client which consumes this address * to return error if there is a problem connecting to S2A at that address. - */ + */ this.mtlsAddress = mtlsAddress; return this; } diff --git a/oauth2_http/javatests/com/google/auth/oauth2/MockMetadataServerTransport.java b/oauth2_http/javatests/com/google/auth/oauth2/MockMetadataServerTransport.java index c810bee68..f8eaf8b84 100644 --- a/oauth2_http/javatests/com/google/auth/oauth2/MockMetadataServerTransport.java +++ b/oauth2_http/javatests/com/google/auth/oauth2/MockMetadataServerTransport.java @@ -355,6 +355,8 @@ protected boolean isMtlsConfigRequestUrl(String url) { && plaintextS2AAddress != null && mtlsS2AAddress != null && mtlsS2AAddressJsonKey != null - && url.equals(String.format(ComputeEngineCredentials.getMetadataServerUrl() + S2A.S2A_CONFIG_ENDPOINT_POSTFIX)); + && url.equals( + String.format( + ComputeEngineCredentials.getMetadataServerUrl() + S2A.S2A_CONFIG_ENDPOINT_POSTFIX)); } } diff --git a/oauth2_http/javatests/com/google/auth/oauth2/S2ATest.java b/oauth2_http/javatests/com/google/auth/oauth2/S2ATest.java index 5ef3af3fa..b8850ebe7 100644 --- a/oauth2_http/javatests/com/google/auth/oauth2/S2ATest.java +++ b/oauth2_http/javatests/com/google/auth/oauth2/S2ATest.java @@ -35,7 +35,6 @@ import com.google.api.client.http.HttpStatusCodes; import com.google.auth.oauth2.ComputeEngineCredentialsTest.MockMetadataServerTransportFactory; -import java.util.Optional; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; From ed681f58e377caef73ec3fc7d6696704d4bbb62f Mon Sep 17 00:00:00 2001 From: Riya Mehta Date: Fri, 25 Oct 2024 10:18:13 -0700 Subject: [PATCH 35/44] move it all into 1 try block. --- oauth2_http/java/com/google/auth/oauth2/S2A.java | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/oauth2_http/java/com/google/auth/oauth2/S2A.java b/oauth2_http/java/com/google/auth/oauth2/S2A.java index 067eb4647..6f432f14f 100644 --- a/oauth2_http/java/com/google/auth/oauth2/S2A.java +++ b/oauth2_http/java/com/google/auth/oauth2/S2A.java @@ -137,9 +137,10 @@ private S2AConfig getS2AConfigFromMDS() { ServiceLoader.load(HttpTransportFactory.class), OAuth2Utils.HTTP_TRANSPORT_FACTORY); } - HttpRequest request; + String plaintextS2AAddress = ""; + String mtlsS2AAddress = ""; try { - request = transportFactory.create().createRequestFactory().buildGetRequest(genericUrl); + HttpRequest request = transportFactory.create().createRequestFactory().buildGetRequest(genericUrl); request.setParser(parser); request.getHeaders().set(METADATA_FLAVOR, GOOGLE); request.setThrowExceptionOnExecuteError(false); @@ -158,13 +159,7 @@ private S2AConfig getS2AConfigFromMDS() { .setBackOffRequired( response -> RETRYABLE_STATUS_CODES.contains(response.getStatusCode()))); request.setIOExceptionHandler(new HttpBackOffIOExceptionHandler(backoff)); - } catch (IOException e) { - return S2AConfig.createBuilder().build(); - } - String plaintextS2AAddress = ""; - String mtlsS2AAddress = ""; - try { HttpResponse response = request.execute(); InputStream content = response.getContent(); if (content == null) { @@ -186,6 +181,7 @@ private S2AConfig getS2AConfigFromMDS() { /* * Return empty addresses in {@link S2AConfig} once all retries have been exhausted. */ + return S2AConfig.createBuilder().build(); } return S2AConfig.createBuilder() From 20825f70a2e6e21a03a4480267f62f706f7ea35f Mon Sep 17 00:00:00 2001 From: Riya Mehta Date: Fri, 25 Oct 2024 10:25:08 -0700 Subject: [PATCH 36/44] MockMetadataServerTransport populate content on 200. --- .../com/google/auth/oauth2/MockMetadataServerTransport.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/oauth2_http/javatests/com/google/auth/oauth2/MockMetadataServerTransport.java b/oauth2_http/javatests/com/google/auth/oauth2/MockMetadataServerTransport.java index f8eaf8b84..9777f262b 100644 --- a/oauth2_http/javatests/com/google/auth/oauth2/MockMetadataServerTransport.java +++ b/oauth2_http/javatests/com/google/auth/oauth2/MockMetadataServerTransport.java @@ -316,7 +316,7 @@ public LowLevelHttpResponse execute() throws IOException { // Create the JSON response GenericJson content = new GenericJson(); content.setFactory(OAuth2Utils.JSON_FACTORY); - if (requestStatusCode < 400) { + if (requestStatusCode == 200) { content.put(plaintextS2AAddressJsonKey, plaintextS2AAddress); content.put(mtlsS2AAddressJsonKey, mtlsS2AAddress); } From 594df7b06c0f18f407f03dc2f307f204e7b00a00 Mon Sep 17 00:00:00 2001 From: Riya Mehta Date: Fri, 25 Oct 2024 10:53:59 -0700 Subject: [PATCH 37/44] MockMetadataServerTransport uses s2aContentMap. --- .../oauth2/MockMetadataServerTransport.java | 36 +++++------------ .../com/google/auth/oauth2/S2ATest.java | 40 +++++++++---------- 2 files changed, 29 insertions(+), 47 deletions(-) diff --git a/oauth2_http/javatests/com/google/auth/oauth2/MockMetadataServerTransport.java b/oauth2_http/javatests/com/google/auth/oauth2/MockMetadataServerTransport.java index 9777f262b..5ec24378d 100644 --- a/oauth2_http/javatests/com/google/auth/oauth2/MockMetadataServerTransport.java +++ b/oauth2_http/javatests/com/google/auth/oauth2/MockMetadataServerTransport.java @@ -62,13 +62,7 @@ public class MockMetadataServerTransport extends MockHttpTransport { private byte[] signature; - private String plaintextS2AAddressJsonKey; - - private String plaintextS2AAddress; - - private String mtlsS2AAddressJsonKey; - - private String mtlsS2AAddress; + private Map s2aContentMap = new HashMap<>(); private boolean emptyContent; private MockLowLevelHttpRequest request; @@ -112,20 +106,8 @@ public void setIdToken(String idToken) { this.idToken = idToken; } - public void setPlaintextS2AAddressJsonKey(String key) { - this.plaintextS2AAddressJsonKey = key; - } - - public void setPlaintextS2AAddress(String address) { - this.plaintextS2AAddress = address; - } - - public void setMtlsS2AAddressJsonKey(String key) { - this.mtlsS2AAddressJsonKey = key; - } - - public void setMtlsS2AAddress(String address) { - this.mtlsS2AAddress = address; + public void setS2AContentMap(String key, String value) { + s2aContentMap.put(key, value); } public void setEmptyContent(boolean emptyContent) { @@ -317,8 +299,8 @@ public LowLevelHttpResponse execute() throws IOException { GenericJson content = new GenericJson(); content.setFactory(OAuth2Utils.JSON_FACTORY); if (requestStatusCode == 200) { - content.put(plaintextS2AAddressJsonKey, plaintextS2AAddress); - content.put(mtlsS2AAddressJsonKey, mtlsS2AAddress); + content.put(s2aContentMap.get("plaintextS2AAddressJsonKey"), s2aContentMap.get("plaintextS2AAddress")); + content.put(s2aContentMap.get("mtlsS2AAddressJsonKey"), s2aContentMap.get("mtlsS2AAddress")); } String contentText = content.toPrettyString(); @@ -351,10 +333,10 @@ protected boolean isIdentityDocumentUrl(String url) { } protected boolean isMtlsConfigRequestUrl(String url) { - return plaintextS2AAddressJsonKey != null - && plaintextS2AAddress != null - && mtlsS2AAddress != null - && mtlsS2AAddressJsonKey != null + return s2aContentMap.containsKey("plaintextS2AAddressJsonKey") + && s2aContentMap.containsKey("plaintextS2AAddress") + && s2aContentMap.containsKey("mtlsS2AAddressJsonKey") + && s2aContentMap.containsKey("mtlsS2AAddress") && url.equals( String.format( ComputeEngineCredentials.getMetadataServerUrl() + S2A.S2A_CONFIG_ENDPOINT_POSTFIX)); diff --git a/oauth2_http/javatests/com/google/auth/oauth2/S2ATest.java b/oauth2_http/javatests/com/google/auth/oauth2/S2ATest.java index b8850ebe7..a7d159e26 100644 --- a/oauth2_http/javatests/com/google/auth/oauth2/S2ATest.java +++ b/oauth2_http/javatests/com/google/auth/oauth2/S2ATest.java @@ -50,10 +50,10 @@ public class S2ATest { @Test public void getS2AAddress_validAddress() { MockMetadataServerTransportFactory transportFactory = new MockMetadataServerTransportFactory(); - transportFactory.transport.setPlaintextS2AAddressJsonKey(S2A.S2A_PLAINTEXT_ADDRESS_JSON_KEY); - transportFactory.transport.setPlaintextS2AAddress(S2A_PLAINTEXT_ADDRESS); - transportFactory.transport.setMtlsS2AAddressJsonKey(S2A.S2A_MTLS_ADDRESS_JSON_KEY); - transportFactory.transport.setMtlsS2AAddress(S2A_MTLS_ADDRESS); + transportFactory.transport.setS2AContentMap("plaintextS2AAddressJsonKey", S2A.S2A_PLAINTEXT_ADDRESS_JSON_KEY); + transportFactory.transport.setS2AContentMap("plaintextS2AAddress", S2A_PLAINTEXT_ADDRESS); + transportFactory.transport.setS2AContentMap("mtlsS2AAddressJsonKey", S2A.S2A_MTLS_ADDRESS_JSON_KEY); + transportFactory.transport.setS2AContentMap("mtlsS2AAddress", S2A_MTLS_ADDRESS); transportFactory.transport.setRequestStatusCode(HttpStatusCodes.STATUS_CODE_OK); S2A s2aUtils = S2A.newBuilder().setHttpTransportFactory(transportFactory).build(); @@ -66,10 +66,10 @@ public void getS2AAddress_validAddress() { @Test public void getS2AAddress_queryEndpointResponseErrorCode_emptyAddress() { MockMetadataServerTransportFactory transportFactory = new MockMetadataServerTransportFactory(); - transportFactory.transport.setPlaintextS2AAddressJsonKey(S2A.S2A_PLAINTEXT_ADDRESS_JSON_KEY); - transportFactory.transport.setPlaintextS2AAddress(S2A_PLAINTEXT_ADDRESS); - transportFactory.transport.setMtlsS2AAddressJsonKey(S2A.S2A_MTLS_ADDRESS_JSON_KEY); - transportFactory.transport.setMtlsS2AAddress(S2A_MTLS_ADDRESS); + transportFactory.transport.setS2AContentMap("plaintextS2AAddressJsonKey", S2A.S2A_PLAINTEXT_ADDRESS_JSON_KEY); + transportFactory.transport.setS2AContentMap("plaintextS2AAddress", S2A_PLAINTEXT_ADDRESS); + transportFactory.transport.setS2AContentMap("mtlsS2AAddressJsonKey", S2A.S2A_MTLS_ADDRESS_JSON_KEY); + transportFactory.transport.setS2AContentMap("mtlsS2AAddress", S2A_MTLS_ADDRESS); transportFactory.transport.setRequestStatusCode( HttpStatusCodes.STATUS_CODE_SERVICE_UNAVAILABLE); @@ -83,10 +83,10 @@ public void getS2AAddress_queryEndpointResponseErrorCode_emptyAddress() { @Test public void getS2AAddress_queryEndpointResponseEmpty_emptyAddress() { MockMetadataServerTransportFactory transportFactory = new MockMetadataServerTransportFactory(); - transportFactory.transport.setPlaintextS2AAddressJsonKey(S2A.S2A_PLAINTEXT_ADDRESS_JSON_KEY); - transportFactory.transport.setPlaintextS2AAddress(S2A_PLAINTEXT_ADDRESS); - transportFactory.transport.setMtlsS2AAddressJsonKey(S2A.S2A_MTLS_ADDRESS_JSON_KEY); - transportFactory.transport.setMtlsS2AAddress(S2A_MTLS_ADDRESS); + transportFactory.transport.setS2AContentMap("plaintextS2AAddressJsonKey", S2A.S2A_PLAINTEXT_ADDRESS_JSON_KEY); + transportFactory.transport.setS2AContentMap("plaintextS2AAddress", S2A_PLAINTEXT_ADDRESS); + transportFactory.transport.setS2AContentMap("mtlsS2AAddressJsonKey", S2A.S2A_MTLS_ADDRESS_JSON_KEY); + transportFactory.transport.setS2AContentMap("mtlsS2AAddress", S2A_MTLS_ADDRESS); transportFactory.transport.setRequestStatusCode(HttpStatusCodes.STATUS_CODE_OK); transportFactory.transport.setEmptyContent(true); @@ -100,10 +100,10 @@ public void getS2AAddress_queryEndpointResponseEmpty_emptyAddress() { @Test public void getS2AAddress_queryEndpointResponseInvalidPlaintextJsonKey_plaintextEmptyAddress() { MockMetadataServerTransportFactory transportFactory = new MockMetadataServerTransportFactory(); - transportFactory.transport.setPlaintextS2AAddressJsonKey(INVALID_JSON_KEY); - transportFactory.transport.setPlaintextS2AAddress(S2A_PLAINTEXT_ADDRESS); - transportFactory.transport.setMtlsS2AAddressJsonKey(S2A.S2A_MTLS_ADDRESS_JSON_KEY); - transportFactory.transport.setMtlsS2AAddress(S2A_MTLS_ADDRESS); + transportFactory.transport.setS2AContentMap("plaintextS2AAddressJsonKey", INVALID_JSON_KEY); + transportFactory.transport.setS2AContentMap("plaintextS2AAddress", S2A_PLAINTEXT_ADDRESS); + transportFactory.transport.setS2AContentMap("mtlsS2AAddressJsonKey", S2A.S2A_MTLS_ADDRESS_JSON_KEY); + transportFactory.transport.setS2AContentMap("mtlsS2AAddress", S2A_MTLS_ADDRESS); transportFactory.transport.setRequestStatusCode(HttpStatusCodes.STATUS_CODE_OK); S2A s2aUtils = S2A.newBuilder().setHttpTransportFactory(transportFactory).build(); @@ -116,10 +116,10 @@ public void getS2AAddress_queryEndpointResponseInvalidPlaintextJsonKey_plaintext @Test public void getS2AAddress_queryEndpointResponseInvalidMtlsJsonKey_mtlsEmptyAddress() { MockMetadataServerTransportFactory transportFactory = new MockMetadataServerTransportFactory(); - transportFactory.transport.setPlaintextS2AAddressJsonKey(S2A.S2A_PLAINTEXT_ADDRESS_JSON_KEY); - transportFactory.transport.setPlaintextS2AAddress(S2A_PLAINTEXT_ADDRESS); - transportFactory.transport.setMtlsS2AAddressJsonKey(INVALID_JSON_KEY); - transportFactory.transport.setMtlsS2AAddress(S2A_MTLS_ADDRESS); + transportFactory.transport.setS2AContentMap("plaintextS2AAddressJsonKey", S2A.S2A_PLAINTEXT_ADDRESS_JSON_KEY); + transportFactory.transport.setS2AContentMap("plaintextS2AAddress", S2A_PLAINTEXT_ADDRESS); + transportFactory.transport.setS2AContentMap("mtlsS2AAddressJsonKey", INVALID_JSON_KEY); + transportFactory.transport.setS2AContentMap("mtlsS2AAddress", S2A_MTLS_ADDRESS); transportFactory.transport.setRequestStatusCode(HttpStatusCodes.STATUS_CODE_OK); S2A s2aUtils = S2A.newBuilder().setHttpTransportFactory(transportFactory).build(); From 16fd964472cde6cde3cee7df8a22afab54eb9455 Mon Sep 17 00:00:00 2001 From: Riya Mehta Date: Fri, 25 Oct 2024 10:54:44 -0700 Subject: [PATCH 38/44] Run mvn fmt:format. --- .../java/com/google/auth/oauth2/S2A.java | 3 ++- .../oauth2/MockMetadataServerTransport.java | 7 ++++-- .../com/google/auth/oauth2/S2ATest.java | 24 ++++++++++++------- 3 files changed, 23 insertions(+), 11 deletions(-) diff --git a/oauth2_http/java/com/google/auth/oauth2/S2A.java b/oauth2_http/java/com/google/auth/oauth2/S2A.java index 6f432f14f..acd769fad 100644 --- a/oauth2_http/java/com/google/auth/oauth2/S2A.java +++ b/oauth2_http/java/com/google/auth/oauth2/S2A.java @@ -140,7 +140,8 @@ private S2AConfig getS2AConfigFromMDS() { String plaintextS2AAddress = ""; String mtlsS2AAddress = ""; try { - HttpRequest request = transportFactory.create().createRequestFactory().buildGetRequest(genericUrl); + HttpRequest request = + transportFactory.create().createRequestFactory().buildGetRequest(genericUrl); request.setParser(parser); request.getHeaders().set(METADATA_FLAVOR, GOOGLE); request.setThrowExceptionOnExecuteError(false); diff --git a/oauth2_http/javatests/com/google/auth/oauth2/MockMetadataServerTransport.java b/oauth2_http/javatests/com/google/auth/oauth2/MockMetadataServerTransport.java index 5ec24378d..2317140cd 100644 --- a/oauth2_http/javatests/com/google/auth/oauth2/MockMetadataServerTransport.java +++ b/oauth2_http/javatests/com/google/auth/oauth2/MockMetadataServerTransport.java @@ -299,8 +299,11 @@ public LowLevelHttpResponse execute() throws IOException { GenericJson content = new GenericJson(); content.setFactory(OAuth2Utils.JSON_FACTORY); if (requestStatusCode == 200) { - content.put(s2aContentMap.get("plaintextS2AAddressJsonKey"), s2aContentMap.get("plaintextS2AAddress")); - content.put(s2aContentMap.get("mtlsS2AAddressJsonKey"), s2aContentMap.get("mtlsS2AAddress")); + content.put( + s2aContentMap.get("plaintextS2AAddressJsonKey"), + s2aContentMap.get("plaintextS2AAddress")); + content.put( + s2aContentMap.get("mtlsS2AAddressJsonKey"), s2aContentMap.get("mtlsS2AAddress")); } String contentText = content.toPrettyString(); diff --git a/oauth2_http/javatests/com/google/auth/oauth2/S2ATest.java b/oauth2_http/javatests/com/google/auth/oauth2/S2ATest.java index a7d159e26..d90d6a707 100644 --- a/oauth2_http/javatests/com/google/auth/oauth2/S2ATest.java +++ b/oauth2_http/javatests/com/google/auth/oauth2/S2ATest.java @@ -50,9 +50,11 @@ public class S2ATest { @Test public void getS2AAddress_validAddress() { MockMetadataServerTransportFactory transportFactory = new MockMetadataServerTransportFactory(); - transportFactory.transport.setS2AContentMap("plaintextS2AAddressJsonKey", S2A.S2A_PLAINTEXT_ADDRESS_JSON_KEY); + transportFactory.transport.setS2AContentMap( + "plaintextS2AAddressJsonKey", S2A.S2A_PLAINTEXT_ADDRESS_JSON_KEY); transportFactory.transport.setS2AContentMap("plaintextS2AAddress", S2A_PLAINTEXT_ADDRESS); - transportFactory.transport.setS2AContentMap("mtlsS2AAddressJsonKey", S2A.S2A_MTLS_ADDRESS_JSON_KEY); + transportFactory.transport.setS2AContentMap( + "mtlsS2AAddressJsonKey", S2A.S2A_MTLS_ADDRESS_JSON_KEY); transportFactory.transport.setS2AContentMap("mtlsS2AAddress", S2A_MTLS_ADDRESS); transportFactory.transport.setRequestStatusCode(HttpStatusCodes.STATUS_CODE_OK); @@ -66,9 +68,11 @@ public void getS2AAddress_validAddress() { @Test public void getS2AAddress_queryEndpointResponseErrorCode_emptyAddress() { MockMetadataServerTransportFactory transportFactory = new MockMetadataServerTransportFactory(); - transportFactory.transport.setS2AContentMap("plaintextS2AAddressJsonKey", S2A.S2A_PLAINTEXT_ADDRESS_JSON_KEY); + transportFactory.transport.setS2AContentMap( + "plaintextS2AAddressJsonKey", S2A.S2A_PLAINTEXT_ADDRESS_JSON_KEY); transportFactory.transport.setS2AContentMap("plaintextS2AAddress", S2A_PLAINTEXT_ADDRESS); - transportFactory.transport.setS2AContentMap("mtlsS2AAddressJsonKey", S2A.S2A_MTLS_ADDRESS_JSON_KEY); + transportFactory.transport.setS2AContentMap( + "mtlsS2AAddressJsonKey", S2A.S2A_MTLS_ADDRESS_JSON_KEY); transportFactory.transport.setS2AContentMap("mtlsS2AAddress", S2A_MTLS_ADDRESS); transportFactory.transport.setRequestStatusCode( HttpStatusCodes.STATUS_CODE_SERVICE_UNAVAILABLE); @@ -83,9 +87,11 @@ public void getS2AAddress_queryEndpointResponseErrorCode_emptyAddress() { @Test public void getS2AAddress_queryEndpointResponseEmpty_emptyAddress() { MockMetadataServerTransportFactory transportFactory = new MockMetadataServerTransportFactory(); - transportFactory.transport.setS2AContentMap("plaintextS2AAddressJsonKey", S2A.S2A_PLAINTEXT_ADDRESS_JSON_KEY); + transportFactory.transport.setS2AContentMap( + "plaintextS2AAddressJsonKey", S2A.S2A_PLAINTEXT_ADDRESS_JSON_KEY); transportFactory.transport.setS2AContentMap("plaintextS2AAddress", S2A_PLAINTEXT_ADDRESS); - transportFactory.transport.setS2AContentMap("mtlsS2AAddressJsonKey", S2A.S2A_MTLS_ADDRESS_JSON_KEY); + transportFactory.transport.setS2AContentMap( + "mtlsS2AAddressJsonKey", S2A.S2A_MTLS_ADDRESS_JSON_KEY); transportFactory.transport.setS2AContentMap("mtlsS2AAddress", S2A_MTLS_ADDRESS); transportFactory.transport.setRequestStatusCode(HttpStatusCodes.STATUS_CODE_OK); transportFactory.transport.setEmptyContent(true); @@ -102,7 +108,8 @@ public void getS2AAddress_queryEndpointResponseInvalidPlaintextJsonKey_plaintext MockMetadataServerTransportFactory transportFactory = new MockMetadataServerTransportFactory(); transportFactory.transport.setS2AContentMap("plaintextS2AAddressJsonKey", INVALID_JSON_KEY); transportFactory.transport.setS2AContentMap("plaintextS2AAddress", S2A_PLAINTEXT_ADDRESS); - transportFactory.transport.setS2AContentMap("mtlsS2AAddressJsonKey", S2A.S2A_MTLS_ADDRESS_JSON_KEY); + transportFactory.transport.setS2AContentMap( + "mtlsS2AAddressJsonKey", S2A.S2A_MTLS_ADDRESS_JSON_KEY); transportFactory.transport.setS2AContentMap("mtlsS2AAddress", S2A_MTLS_ADDRESS); transportFactory.transport.setRequestStatusCode(HttpStatusCodes.STATUS_CODE_OK); @@ -116,7 +123,8 @@ public void getS2AAddress_queryEndpointResponseInvalidPlaintextJsonKey_plaintext @Test public void getS2AAddress_queryEndpointResponseInvalidMtlsJsonKey_mtlsEmptyAddress() { MockMetadataServerTransportFactory transportFactory = new MockMetadataServerTransportFactory(); - transportFactory.transport.setS2AContentMap("plaintextS2AAddressJsonKey", S2A.S2A_PLAINTEXT_ADDRESS_JSON_KEY); + transportFactory.transport.setS2AContentMap( + "plaintextS2AAddressJsonKey", S2A.S2A_PLAINTEXT_ADDRESS_JSON_KEY); transportFactory.transport.setS2AContentMap("plaintextS2AAddress", S2A_PLAINTEXT_ADDRESS); transportFactory.transport.setS2AContentMap("mtlsS2AAddressJsonKey", INVALID_JSON_KEY); transportFactory.transport.setS2AContentMap("mtlsS2AAddress", S2A_MTLS_ADDRESS); From 1e6c05872c3512c7fd237936da40405d20854708 Mon Sep 17 00:00:00 2001 From: Riya Mehta Date: Fri, 25 Oct 2024 14:38:53 -0700 Subject: [PATCH 39/44] Use ImmutableMap. --- .../oauth2/MockMetadataServerTransport.java | 23 ++++----- .../com/google/auth/oauth2/S2ATest.java | 49 ++++++++++--------- 2 files changed, 35 insertions(+), 37 deletions(-) diff --git a/oauth2_http/javatests/com/google/auth/oauth2/MockMetadataServerTransport.java b/oauth2_http/javatests/com/google/auth/oauth2/MockMetadataServerTransport.java index 2317140cd..5a854480c 100644 --- a/oauth2_http/javatests/com/google/auth/oauth2/MockMetadataServerTransport.java +++ b/oauth2_http/javatests/com/google/auth/oauth2/MockMetadataServerTransport.java @@ -39,6 +39,7 @@ import com.google.api.client.testing.http.MockLowLevelHttpRequest; import com.google.api.client.testing.http.MockLowLevelHttpResponse; import com.google.common.base.Splitter; +import com.google.common.collect.ImmutableMap; import com.google.common.io.BaseEncoding; import java.io.IOException; import java.io.UnsupportedEncodingException; @@ -106,8 +107,8 @@ public void setIdToken(String idToken) { this.idToken = idToken; } - public void setS2AContentMap(String key, String value) { - s2aContentMap.put(key, value); + public void setS2AContentMap(ImmutableMap map) { + this.s2aContentMap = map; } public void setEmptyContent(boolean emptyContent) { @@ -299,11 +300,9 @@ public LowLevelHttpResponse execute() throws IOException { GenericJson content = new GenericJson(); content.setFactory(OAuth2Utils.JSON_FACTORY); if (requestStatusCode == 200) { - content.put( - s2aContentMap.get("plaintextS2AAddressJsonKey"), - s2aContentMap.get("plaintextS2AAddress")); - content.put( - s2aContentMap.get("mtlsS2AAddressJsonKey"), s2aContentMap.get("mtlsS2AAddress")); + for (Map.Entry entrySet : s2aContentMap.entrySet()) { + content.put(entrySet.getKey(), entrySet.getValue()); + } } String contentText = content.toPrettyString(); @@ -336,12 +335,8 @@ protected boolean isIdentityDocumentUrl(String url) { } protected boolean isMtlsConfigRequestUrl(String url) { - return s2aContentMap.containsKey("plaintextS2AAddressJsonKey") - && s2aContentMap.containsKey("plaintextS2AAddress") - && s2aContentMap.containsKey("mtlsS2AAddressJsonKey") - && s2aContentMap.containsKey("mtlsS2AAddress") - && url.equals( - String.format( - ComputeEngineCredentials.getMetadataServerUrl() + S2A.S2A_CONFIG_ENDPOINT_POSTFIX)); + return url.equals( + String.format( + ComputeEngineCredentials.getMetadataServerUrl() + S2A.S2A_CONFIG_ENDPOINT_POSTFIX)); } } diff --git a/oauth2_http/javatests/com/google/auth/oauth2/S2ATest.java b/oauth2_http/javatests/com/google/auth/oauth2/S2ATest.java index d90d6a707..f532a2727 100644 --- a/oauth2_http/javatests/com/google/auth/oauth2/S2ATest.java +++ b/oauth2_http/javatests/com/google/auth/oauth2/S2ATest.java @@ -35,6 +35,7 @@ import com.google.api.client.http.HttpStatusCodes; import com.google.auth.oauth2.ComputeEngineCredentialsTest.MockMetadataServerTransportFactory; +import com.google.common.collect.ImmutableMap; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -51,11 +52,11 @@ public class S2ATest { public void getS2AAddress_validAddress() { MockMetadataServerTransportFactory transportFactory = new MockMetadataServerTransportFactory(); transportFactory.transport.setS2AContentMap( - "plaintextS2AAddressJsonKey", S2A.S2A_PLAINTEXT_ADDRESS_JSON_KEY); - transportFactory.transport.setS2AContentMap("plaintextS2AAddress", S2A_PLAINTEXT_ADDRESS); - transportFactory.transport.setS2AContentMap( - "mtlsS2AAddressJsonKey", S2A.S2A_MTLS_ADDRESS_JSON_KEY); - transportFactory.transport.setS2AContentMap("mtlsS2AAddress", S2A_MTLS_ADDRESS); + ImmutableMap.of( + S2A.S2A_PLAINTEXT_ADDRESS_JSON_KEY, + S2A_PLAINTEXT_ADDRESS, + S2A.S2A_MTLS_ADDRESS_JSON_KEY, + S2A_MTLS_ADDRESS)); transportFactory.transport.setRequestStatusCode(HttpStatusCodes.STATUS_CODE_OK); S2A s2aUtils = S2A.newBuilder().setHttpTransportFactory(transportFactory).build(); @@ -69,11 +70,11 @@ public void getS2AAddress_validAddress() { public void getS2AAddress_queryEndpointResponseErrorCode_emptyAddress() { MockMetadataServerTransportFactory transportFactory = new MockMetadataServerTransportFactory(); transportFactory.transport.setS2AContentMap( - "plaintextS2AAddressJsonKey", S2A.S2A_PLAINTEXT_ADDRESS_JSON_KEY); - transportFactory.transport.setS2AContentMap("plaintextS2AAddress", S2A_PLAINTEXT_ADDRESS); - transportFactory.transport.setS2AContentMap( - "mtlsS2AAddressJsonKey", S2A.S2A_MTLS_ADDRESS_JSON_KEY); - transportFactory.transport.setS2AContentMap("mtlsS2AAddress", S2A_MTLS_ADDRESS); + ImmutableMap.of( + S2A.S2A_PLAINTEXT_ADDRESS_JSON_KEY, + S2A_PLAINTEXT_ADDRESS, + S2A.S2A_MTLS_ADDRESS_JSON_KEY, + S2A_MTLS_ADDRESS)); transportFactory.transport.setRequestStatusCode( HttpStatusCodes.STATUS_CODE_SERVICE_UNAVAILABLE); @@ -88,11 +89,11 @@ public void getS2AAddress_queryEndpointResponseErrorCode_emptyAddress() { public void getS2AAddress_queryEndpointResponseEmpty_emptyAddress() { MockMetadataServerTransportFactory transportFactory = new MockMetadataServerTransportFactory(); transportFactory.transport.setS2AContentMap( - "plaintextS2AAddressJsonKey", S2A.S2A_PLAINTEXT_ADDRESS_JSON_KEY); - transportFactory.transport.setS2AContentMap("plaintextS2AAddress", S2A_PLAINTEXT_ADDRESS); - transportFactory.transport.setS2AContentMap( - "mtlsS2AAddressJsonKey", S2A.S2A_MTLS_ADDRESS_JSON_KEY); - transportFactory.transport.setS2AContentMap("mtlsS2AAddress", S2A_MTLS_ADDRESS); + ImmutableMap.of( + S2A.S2A_PLAINTEXT_ADDRESS_JSON_KEY, + S2A_PLAINTEXT_ADDRESS, + S2A.S2A_MTLS_ADDRESS_JSON_KEY, + S2A_MTLS_ADDRESS)); transportFactory.transport.setRequestStatusCode(HttpStatusCodes.STATUS_CODE_OK); transportFactory.transport.setEmptyContent(true); @@ -106,11 +107,12 @@ public void getS2AAddress_queryEndpointResponseEmpty_emptyAddress() { @Test public void getS2AAddress_queryEndpointResponseInvalidPlaintextJsonKey_plaintextEmptyAddress() { MockMetadataServerTransportFactory transportFactory = new MockMetadataServerTransportFactory(); - transportFactory.transport.setS2AContentMap("plaintextS2AAddressJsonKey", INVALID_JSON_KEY); - transportFactory.transport.setS2AContentMap("plaintextS2AAddress", S2A_PLAINTEXT_ADDRESS); transportFactory.transport.setS2AContentMap( - "mtlsS2AAddressJsonKey", S2A.S2A_MTLS_ADDRESS_JSON_KEY); - transportFactory.transport.setS2AContentMap("mtlsS2AAddress", S2A_MTLS_ADDRESS); + ImmutableMap.of( + INVALID_JSON_KEY, + S2A_PLAINTEXT_ADDRESS, + S2A.S2A_MTLS_ADDRESS_JSON_KEY, + S2A_MTLS_ADDRESS)); transportFactory.transport.setRequestStatusCode(HttpStatusCodes.STATUS_CODE_OK); S2A s2aUtils = S2A.newBuilder().setHttpTransportFactory(transportFactory).build(); @@ -124,10 +126,11 @@ public void getS2AAddress_queryEndpointResponseInvalidPlaintextJsonKey_plaintext public void getS2AAddress_queryEndpointResponseInvalidMtlsJsonKey_mtlsEmptyAddress() { MockMetadataServerTransportFactory transportFactory = new MockMetadataServerTransportFactory(); transportFactory.transport.setS2AContentMap( - "plaintextS2AAddressJsonKey", S2A.S2A_PLAINTEXT_ADDRESS_JSON_KEY); - transportFactory.transport.setS2AContentMap("plaintextS2AAddress", S2A_PLAINTEXT_ADDRESS); - transportFactory.transport.setS2AContentMap("mtlsS2AAddressJsonKey", INVALID_JSON_KEY); - transportFactory.transport.setS2AContentMap("mtlsS2AAddress", S2A_MTLS_ADDRESS); + ImmutableMap.of( + S2A.S2A_PLAINTEXT_ADDRESS_JSON_KEY, + S2A_PLAINTEXT_ADDRESS, + INVALID_JSON_KEY, + S2A_MTLS_ADDRESS)); transportFactory.transport.setRequestStatusCode(HttpStatusCodes.STATUS_CODE_OK); S2A s2aUtils = S2A.newBuilder().setHttpTransportFactory(transportFactory).build(); From 934679c76ab3ad0243a07e656afe45c3b85a79dc Mon Sep 17 00:00:00 2001 From: Riya Mehta Date: Mon, 28 Oct 2024 09:59:43 -0700 Subject: [PATCH 40/44] update javadoc to reference AIP. --- oauth2_http/java/com/google/auth/oauth2/S2A.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/oauth2_http/java/com/google/auth/oauth2/S2A.java b/oauth2_http/java/com/google/auth/oauth2/S2A.java index acd769fad..9d4256a66 100644 --- a/oauth2_http/java/com/google/auth/oauth2/S2A.java +++ b/oauth2_http/java/com/google/auth/oauth2/S2A.java @@ -52,7 +52,8 @@ /** * Utilities to fetch the S2A (Secure Session Agent) address from the mTLS configuration. * - *

mTLS configuration is queried from the MDS MTLS Autoconfiguration endpoint. + *

mTLS configuration is queried from the MDS MTLS Autoconfiguration endpoint. See + * https://google.aip.dev/auth/4115 for details. */ @ThreadSafe public final class S2A { From 6644d50203d25affc95bca8d447bed04bfe0779f Mon Sep 17 00:00:00 2001 From: Riya Mehta Date: Mon, 28 Oct 2024 13:42:55 -0700 Subject: [PATCH 41/44] Don't nest try/catch + add some comments about why no throw errors. --- .../java/com/google/auth/oauth2/S2A.java | 86 +++++++++++-------- 1 file changed, 50 insertions(+), 36 deletions(-) diff --git a/oauth2_http/java/com/google/auth/oauth2/S2A.java b/oauth2_http/java/com/google/auth/oauth2/S2A.java index 9d4256a66..8e643f8dd 100644 --- a/oauth2_http/java/com/google/auth/oauth2/S2A.java +++ b/oauth2_http/java/com/google/auth/oauth2/S2A.java @@ -130,55 +130,50 @@ public S2A build() { * @return the {@link S2AConfig}. */ private S2AConfig getS2AConfigFromMDS() { - GenericUrl genericUrl = new GenericUrl(MDS_MTLS_ENDPOINT); - JsonObjectParser parser = new JsonObjectParser(OAuth2Utils.JSON_FACTORY); if (transportFactory == null) { transportFactory = Iterables.getFirst( ServiceLoader.load(HttpTransportFactory.class), OAuth2Utils.HTTP_TRANSPORT_FACTORY); } - String plaintextS2AAddress = ""; - String mtlsS2AAddress = ""; + HttpRequest request = null; + GenericUrl genericUrl = new GenericUrl(MDS_MTLS_ENDPOINT); try { - HttpRequest request = - transportFactory.create().createRequestFactory().buildGetRequest(genericUrl); - request.setParser(parser); - request.getHeaders().set(METADATA_FLAVOR, GOOGLE); - request.setThrowExceptionOnExecuteError(false); - request.setNumberOfRetries(OAuth2Utils.DEFAULT_NUMBER_OF_RETRIES); - - ExponentialBackOff backoff = - new ExponentialBackOff.Builder() - .setInitialIntervalMillis(OAuth2Utils.INITIAL_RETRY_INTERVAL_MILLIS) - .setRandomizationFactor(OAuth2Utils.RETRY_RANDOMIZATION_FACTOR) - .setMultiplier(OAuth2Utils.RETRY_MULTIPLIER) - .build(); - - // Retry on 5xx status codes. - request.setUnsuccessfulResponseHandler( - new HttpBackOffUnsuccessfulResponseHandler(backoff) - .setBackOffRequired( - response -> RETRYABLE_STATUS_CODES.contains(response.getStatusCode()))); - request.setIOExceptionHandler(new HttpBackOffIOExceptionHandler(backoff)); + request = transportFactory.create().createRequestFactory().buildGetRequest(genericUrl); + } catch (IOException ignore) { + /* + * Return empty addresses in {@link S2AConfig} if error building the GET request. + */ + return S2AConfig.createBuilder().build(); + } + request.setParser(new JsonObjectParser(OAuth2Utils.JSON_FACTORY)); + request.getHeaders().set(METADATA_FLAVOR, GOOGLE); + request.setThrowExceptionOnExecuteError(false); + request.setNumberOfRetries(OAuth2Utils.DEFAULT_NUMBER_OF_RETRIES); + + ExponentialBackOff backoff = + new ExponentialBackOff.Builder() + .setInitialIntervalMillis(OAuth2Utils.INITIAL_RETRY_INTERVAL_MILLIS) + .setRandomizationFactor(OAuth2Utils.RETRY_RANDOMIZATION_FACTOR) + .setMultiplier(OAuth2Utils.RETRY_MULTIPLIER) + .build(); + + // Retry on 5xx status codes. + request.setUnsuccessfulResponseHandler( + new HttpBackOffUnsuccessfulResponseHandler(backoff) + .setBackOffRequired( + response -> RETRYABLE_STATUS_CODES.contains(response.getStatusCode()))); + request.setIOExceptionHandler(new HttpBackOffIOExceptionHandler(backoff)); + + GenericData responseData = null; + try { HttpResponse response = request.execute(); InputStream content = response.getContent(); if (content == null) { return S2AConfig.createBuilder().build(); } - GenericData responseData = response.parseAs(GenericData.class); - try { - plaintextS2AAddress = - OAuth2Utils.validateString( - responseData, S2A_PLAINTEXT_ADDRESS_JSON_KEY, PARSE_ERROR_S2A); - } catch (IOException ignore) { - } - try { - mtlsS2AAddress = - OAuth2Utils.validateString(responseData, S2A_MTLS_ADDRESS_JSON_KEY, PARSE_ERROR_S2A); - } catch (IOException ignore) { - } + responseData = response.parseAs(GenericData.class); } catch (IOException ignore) { /* * Return empty addresses in {@link S2AConfig} once all retries have been exhausted. @@ -186,6 +181,25 @@ private S2AConfig getS2AConfigFromMDS() { return S2AConfig.createBuilder().build(); } + String plaintextS2AAddress = ""; + String mtlsS2AAddress = ""; + try { + plaintextS2AAddress = + OAuth2Utils.validateString(responseData, S2A_PLAINTEXT_ADDRESS_JSON_KEY, PARSE_ERROR_S2A); + } catch (IOException ignore) { + /* + * Do not throw error because of parsing error, just leave the address as empty in {@link S2AConfig}. + */ + } + try { + mtlsS2AAddress = + OAuth2Utils.validateString(responseData, S2A_MTLS_ADDRESS_JSON_KEY, PARSE_ERROR_S2A); + } catch (IOException ignore) { + /* + * Do not throw error because of parsing error, just leave the address as empty in {@link S2AConfig}. + */ + } + return S2AConfig.createBuilder() .setPlaintextAddress(plaintextS2AAddress) .setMtlsAddress(mtlsS2AAddress) From 8ca8d693514c60756bef34904e45d064d1208f5e Mon Sep 17 00:00:00 2001 From: Riya Mehta Date: Tue, 29 Oct 2024 09:23:21 -0700 Subject: [PATCH 42/44] update javadoc for each public method. --- oauth2_http/java/com/google/auth/oauth2/S2AConfig.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/oauth2_http/java/com/google/auth/oauth2/S2AConfig.java b/oauth2_http/java/com/google/auth/oauth2/S2AConfig.java index 6b9adb543..90765f096 100644 --- a/oauth2_http/java/com/google/auth/oauth2/S2AConfig.java +++ b/oauth2_http/java/com/google/auth/oauth2/S2AConfig.java @@ -44,10 +44,12 @@ public static Builder createBuilder() { return new Builder(); } + /** @return the plaintext S2A Address. */ public String getPlaintextAddress() { return plaintextAddress; } + /** @return the mTLS S2A Address. */ public String getMtlsAddress() { return mtlsAddress; } From 699bed73281f348e89794444725df5f83c37facf Mon Sep 17 00:00:00 2001 From: Riya Mehta Date: Tue, 29 Oct 2024 11:31:13 -0700 Subject: [PATCH 43/44] add experimental note. --- oauth2_http/java/com/google/auth/oauth2/S2A.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/oauth2_http/java/com/google/auth/oauth2/S2A.java b/oauth2_http/java/com/google/auth/oauth2/S2A.java index 8e643f8dd..6a3e924e5 100644 --- a/oauth2_http/java/com/google/auth/oauth2/S2A.java +++ b/oauth2_http/java/com/google/auth/oauth2/S2A.java @@ -54,6 +54,8 @@ * *

mTLS configuration is queried from the MDS MTLS Autoconfiguration endpoint. See * https://google.aip.dev/auth/4115 for details. + * + * This is an experimental utility. */ @ThreadSafe public final class S2A { From 8e5ccb0cd6878a706bfeb1b959e6a689f6071e41 Mon Sep 17 00:00:00 2001 From: Riya Mehta Date: Tue, 29 Oct 2024 11:31:47 -0700 Subject: [PATCH 44/44] format. --- oauth2_http/java/com/google/auth/oauth2/S2A.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/oauth2_http/java/com/google/auth/oauth2/S2A.java b/oauth2_http/java/com/google/auth/oauth2/S2A.java index 6a3e924e5..aecf4a3b2 100644 --- a/oauth2_http/java/com/google/auth/oauth2/S2A.java +++ b/oauth2_http/java/com/google/auth/oauth2/S2A.java @@ -54,8 +54,8 @@ * *

mTLS configuration is queried from the MDS MTLS Autoconfiguration endpoint. See * https://google.aip.dev/auth/4115 for details. - * - * This is an experimental utility. + * + *

This is an experimental utility. */ @ThreadSafe public final class S2A {