From c96cb4a870c1fdf0490070dcab863990400a602e Mon Sep 17 00:00:00 2001 From: Riya Mehta Date: Fri, 23 Feb 2024 18:15:15 +0000 Subject: [PATCH 01/12] 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/12] 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/12] 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/12] 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/12] 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/12] 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/12] 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/12] 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/12] 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/12] 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/12] 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/12] 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)); } }