diff --git a/google-auth-library-java/oauth2_http/java/com/google/auth/oauth2/RegionalAccessBoundary.java b/google-auth-library-java/oauth2_http/java/com/google/auth/oauth2/RegionalAccessBoundary.java index b2a3f42942d7..972a9e08bebd 100644 --- a/google-auth-library-java/oauth2_http/java/com/google/auth/oauth2/RegionalAccessBoundary.java +++ b/google-auth-library-java/oauth2_http/java/com/google/auth/oauth2/RegionalAccessBoundary.java @@ -40,10 +40,11 @@ import com.google.api.client.http.HttpResponse; import com.google.api.client.http.HttpUnsuccessfulResponseHandler; import com.google.api.client.json.GenericJson; -import com.google.api.client.json.JsonParser; +import com.google.api.client.json.JsonObjectParser; import com.google.api.client.util.Clock; import com.google.api.client.util.ExponentialBackOff; import com.google.api.client.util.Key; +import com.google.api.core.InternalApi; import com.google.auth.http.HttpTransportFactory; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.MoreObjects; @@ -53,7 +54,6 @@ import java.io.Serializable; import java.util.Collections; import java.util.List; -import javax.annotation.Nullable; /** * Represents the regional access boundary configuration for a credential. This class holds the @@ -67,10 +67,24 @@ final class RegionalAccessBoundary implements Serializable { static final String X_ALLOWED_LOCATIONS_HEADER_KEY = "x-allowed-locations"; private static final long serialVersionUID = -2428522338274020302L; - // Note: this is for internal testing use use only. - // TODO: Fix unit test mocks so this can be removed - // Refer -> https://github.com/googleapis/google-auth-library-java/issues/1898 - static final String ENABLE_EXPERIMENT_ENV_VAR = "GOOGLE_AUTH_TRUST_BOUNDARY_ENABLE_EXPERIMENT"; + private static final ThreadLocal DISABLE_RAB_FOR_TESTS = + ThreadLocal.withInitial(() -> false); + + @VisibleForTesting + static void disableForTests() { + DISABLE_RAB_FOR_TESTS.set(true); + } + + @VisibleForTesting + static void enableForTests() { + DISABLE_RAB_FOR_TESTS.set(false); + } + + @VisibleForTesting + static void resetForTests() { + DISABLE_RAB_FOR_TESTS.remove(); + } + static final long TTL_MILLIS = 6 * 60 * 60 * 1000L; // 6 hours static final long REFRESH_THRESHOLD_MILLIS = 1 * 60 * 60 * 1000L; // 1 hour @@ -79,8 +93,6 @@ final class RegionalAccessBoundary implements Serializable { private final long refreshTime; private transient Clock clock; - private static EnvironmentProvider environmentProvider = SystemEnvironmentProvider.getInstance(); - /** * Creates a new RegionalAccessBoundary instance. * @@ -172,28 +184,16 @@ public String toString() { } } - @VisibleForTesting - static void setEnvironmentProviderForTest(@Nullable EnvironmentProvider provider) { - environmentProvider = provider == null ? SystemEnvironmentProvider.getInstance() : provider; - } - /** - * Checks if the regional access boundary feature is enabled. The feature is enabled if the - * environment variable or system property "GOOGLE_AUTH_TRUST_BOUNDARY_ENABLE_EXPERIMENT" is set - * to "true" or "1" (case-insensitive). + * Checks if the regional access boundary feature is enabled. + * + *

This method is for internal use only and may be changed or removed in future releases. * * @return True if the regional access boundary feature is enabled, false otherwise. */ + @InternalApi static boolean isEnabled() { - String enabled = environmentProvider.getEnv(ENABLE_EXPERIMENT_ENV_VAR); - if (enabled == null) { - enabled = System.getProperty(ENABLE_EXPERIMENT_ENV_VAR); - } - if (enabled == null) { - return false; - } - String lowercased = enabled.toLowerCase(); - return "true".equals(lowercased) || "1".equals(enabled); + return !DISABLE_RAB_FOR_TESTS.get(); } /** @@ -249,15 +249,20 @@ static RegionalAccessBoundary refresh( HttpIOExceptionHandler ioExceptionHandler = new HttpBackOffIOExceptionHandler(backoff); request.setIOExceptionHandler(ioExceptionHandler); + request.setParser(new JsonObjectParser(OAuth2Utils.JSON_FACTORY)); + RegionalAccessBoundaryResponse json; + HttpResponse response = null; try { - HttpResponse response = request.execute(); - String responseString = response.parseAsString(); - JsonParser parser = OAuth2Utils.JSON_FACTORY.createJsonParser(responseString); - json = parser.parseAndClose(RegionalAccessBoundaryResponse.class); + response = request.execute(); + json = response.parseAs(RegionalAccessBoundaryResponse.class); } catch (IOException e) { throw new IOException( "RegionalAccessBoundary: Failure while getting regional access boundaries:", e); + } finally { + if (response != null) { + response.disconnect(); + } } String encodedLocations = json.getEncodedLocations(); // The encodedLocations is the value attached to the x-allowed-locations header, and diff --git a/google-auth-library-java/oauth2_http/java/com/google/auth/oauth2/RegionalAccessBoundaryManager.java b/google-auth-library-java/oauth2_http/java/com/google/auth/oauth2/RegionalAccessBoundaryManager.java index eeea75bc2c86..05962ba68deb 100644 --- a/google-auth-library-java/oauth2_http/java/com/google/auth/oauth2/RegionalAccessBoundaryManager.java +++ b/google-auth-library-java/oauth2_http/java/com/google/auth/oauth2/RegionalAccessBoundaryManager.java @@ -36,6 +36,9 @@ import com.google.auth.http.HttpTransportFactory; import com.google.common.annotations.VisibleForTesting; import com.google.common.util.concurrent.SettableFuture; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; import java.util.logging.Level; import javax.annotation.Nullable; @@ -78,6 +81,20 @@ final class RegionalAccessBoundaryManager { private final AtomicReference cooldownState = new AtomicReference<>(new CooldownState(0, INITIAL_COOLDOWN_MILLIS)); + // Unbounded thread creation is discouraged in library code to avoid resource + // exhaustion. A shared, bounded executor service ensures a hard limit (5) + // on concurrent refresh tasks, while threadCount provides unique names + // for easier debugging. + private static final AtomicInteger threadCount = new AtomicInteger(0); + private static final ExecutorService EXECUTOR = + Executors.newFixedThreadPool( + 5, + r -> { + Thread t = new Thread(r, "RAB-refresh-" + threadCount.getAndIncrement()); + t.setDaemon(true); + return t; + }); + private final transient Clock clock; private final int maxRetryElapsedTimeMillis; @@ -161,14 +178,7 @@ void triggerAsyncRefresh( }; try { - // We use new Thread() here instead of - // CompletableFuture.runAsync() (which uses ForkJoinPool.commonPool()). - // This avoids consuming CPU resources since - // The common pool has a small, fixed number of threads designed for - // CPU-bound tasks. - Thread refreshThread = new Thread(refreshTask, "RAB-refresh-thread"); - refreshThread.setDaemon(true); - refreshThread.start(); + EXECUTOR.submit(refreshTask); } catch (Exception | Error e) { // If scheduling fails (e.g., RejectedExecutionException, OutOfMemoryError for threads), // the task's finally block will never execute. We must release the lock here. diff --git a/google-auth-library-java/oauth2_http/javatests/com/google/auth/oauth2/AwsCredentialsTest.java b/google-auth-library-java/oauth2_http/javatests/com/google/auth/oauth2/AwsCredentialsTest.java index a0930b796d04..7f3fb826e799 100644 --- a/google-auth-library-java/oauth2_http/javatests/com/google/auth/oauth2/AwsCredentialsTest.java +++ b/google-auth-library-java/oauth2_http/javatests/com/google/auth/oauth2/AwsCredentialsTest.java @@ -65,11 +65,6 @@ class AwsCredentialsTest extends BaseSerializationTest { @org.junit.jupiter.api.BeforeEach void setUp() {} - @org.junit.jupiter.api.AfterEach - void tearDown() { - RegionalAccessBoundary.setEnvironmentProviderForTest(null); - } - private static final String STS_URL = "https://sts.googleapis.com/v1/token"; private static final String AWS_CREDENTIALS_URL = "https://169.254.169.254"; private static final String AWS_CREDENTIALS_URL_WITH_ROLE = "https://169.254.169.254/roleName"; @@ -1369,9 +1364,6 @@ public AwsSecurityCredentials getCredentials(ExternalAccountSupplierContext cont @Test public void testRefresh_regionalAccessBoundarySuccess() throws IOException, InterruptedException { - TestEnvironmentProvider environmentProvider = new TestEnvironmentProvider(); - RegionalAccessBoundary.setEnvironmentProviderForTest(environmentProvider); - environmentProvider.setEnv(RegionalAccessBoundary.ENABLE_EXPERIMENT_ENV_VAR, "1"); MockExternalAccountCredentialsTransportFactory transportFactory = new MockExternalAccountCredentialsTransportFactory(); diff --git a/google-auth-library-java/oauth2_http/javatests/com/google/auth/oauth2/ComputeEngineCredentialsTest.java b/google-auth-library-java/oauth2_http/javatests/com/google/auth/oauth2/ComputeEngineCredentialsTest.java index 8b20d0cc20f4..034fec1cc387 100644 --- a/google-auth-library-java/oauth2_http/javatests/com/google/auth/oauth2/ComputeEngineCredentialsTest.java +++ b/google-auth-library-java/oauth2_http/javatests/com/google/auth/oauth2/ComputeEngineCredentialsTest.java @@ -80,11 +80,6 @@ class ComputeEngineCredentialsTest extends BaseSerializationTest { @org.junit.jupiter.api.BeforeEach void setUp() {} - @org.junit.jupiter.api.AfterEach - void tearDown() { - RegionalAccessBoundary.setEnvironmentProviderForTest(null); - } - private static final URI CALL_URI = URI.create("http://googleapis.com/testapi/v1/foo"); private static final String TOKEN_URL = @@ -1188,9 +1183,6 @@ void getProjectId_explicitSet_noMDsCall() { @org.junit.jupiter.api.Test void refresh_regionalAccessBoundarySuccess() throws IOException, InterruptedException { - TestEnvironmentProvider environmentProvider = new TestEnvironmentProvider(); - RegionalAccessBoundary.setEnvironmentProviderForTest(environmentProvider); - environmentProvider.setEnv(RegionalAccessBoundary.ENABLE_EXPERIMENT_ENV_VAR, "1"); String defaultAccountEmail = "default@email.com"; MockMetadataServerTransportFactory transportFactory = new MockMetadataServerTransportFactory(); diff --git a/google-auth-library-java/oauth2_http/javatests/com/google/auth/oauth2/ExternalAccountAuthorizedUserCredentialsTest.java b/google-auth-library-java/oauth2_http/javatests/com/google/auth/oauth2/ExternalAccountAuthorizedUserCredentialsTest.java index fbf3f79dbe65..4d4d83afe13f 100644 --- a/google-auth-library-java/oauth2_http/javatests/com/google/auth/oauth2/ExternalAccountAuthorizedUserCredentialsTest.java +++ b/google-auth-library-java/oauth2_http/javatests/com/google/auth/oauth2/ExternalAccountAuthorizedUserCredentialsTest.java @@ -130,9 +130,7 @@ void setup() { } @org.junit.jupiter.api.AfterEach - void tearDown() { - RegionalAccessBoundary.setEnvironmentProviderForTest(null); - } + void tearDown() {} @Test void builder_allFields() throws IOException { @@ -1243,9 +1241,6 @@ void serialize() throws IOException, ClassNotFoundException { @org.junit.jupiter.api.Test void testRefresh_regionalAccessBoundarySuccess() throws IOException, InterruptedException { - TestEnvironmentProvider environmentProvider = new TestEnvironmentProvider(); - RegionalAccessBoundary.setEnvironmentProviderForTest(environmentProvider); - environmentProvider.setEnv(RegionalAccessBoundary.ENABLE_EXPERIMENT_ENV_VAR, "1"); ExternalAccountAuthorizedUserCredentials credentials = ExternalAccountAuthorizedUserCredentials.newBuilder() diff --git a/google-auth-library-java/oauth2_http/javatests/com/google/auth/oauth2/ExternalAccountCredentialsTest.java b/google-auth-library-java/oauth2_http/javatests/com/google/auth/oauth2/ExternalAccountCredentialsTest.java index 5b20f33db983..751bc7874eb5 100644 --- a/google-auth-library-java/oauth2_http/javatests/com/google/auth/oauth2/ExternalAccountCredentialsTest.java +++ b/google-auth-library-java/oauth2_http/javatests/com/google/auth/oauth2/ExternalAccountCredentialsTest.java @@ -92,11 +92,6 @@ void setup() { transportFactory = new MockExternalAccountCredentialsTransportFactory(); } - @org.junit.jupiter.api.AfterEach - void tearDown() { - RegionalAccessBoundary.setEnvironmentProviderForTest(null); - } - @Test void fromStream_identityPoolCredentials() throws IOException { GenericJson json = buildJsonIdentityPoolCredential(); @@ -1302,9 +1297,7 @@ public void getRegionalAccessBoundaryUrl_invalidAudience_throws() { @Test public void refresh_workload_regionalAccessBoundarySuccess() throws IOException, InterruptedException { - TestEnvironmentProvider environmentProvider = new TestEnvironmentProvider(); - RegionalAccessBoundary.setEnvironmentProviderForTest(environmentProvider); - environmentProvider.setEnv(RegionalAccessBoundary.ENABLE_EXPERIMENT_ENV_VAR, "1"); + String audience = "//iam.googleapis.com/projects/12345/locations/global/workloadIdentityPools/my-pool/providers/my-provider"; @@ -1339,9 +1332,7 @@ public String retrieveSubjectToken() throws IOException { @Test public void refresh_workforce_regionalAccessBoundarySuccess() throws IOException, InterruptedException { - TestEnvironmentProvider environmentProvider = new TestEnvironmentProvider(); - RegionalAccessBoundary.setEnvironmentProviderForTest(environmentProvider); - environmentProvider.setEnv(RegionalAccessBoundary.ENABLE_EXPERIMENT_ENV_VAR, "1"); + String audience = "//iam.googleapis.com/locations/global/workforcePools/my-pool/providers/my-provider"; @@ -1376,9 +1367,7 @@ public String retrieveSubjectToken() throws IOException { @Test public void refresh_impersonated_workload_regionalAccessBoundarySuccess() throws IOException, InterruptedException { - TestEnvironmentProvider environmentProvider = new TestEnvironmentProvider(); - RegionalAccessBoundary.setEnvironmentProviderForTest(environmentProvider); - environmentProvider.setEnv(RegionalAccessBoundary.ENABLE_EXPERIMENT_ENV_VAR, "1"); + String projectNumber = "12345"; String poolId = "my-pool"; String providerId = "my-provider"; @@ -1440,9 +1429,7 @@ public void refresh_impersonated_workload_regionalAccessBoundarySuccess() @Test public void refresh_impersonated_workforce_regionalAccessBoundarySuccess() throws IOException, InterruptedException { - TestEnvironmentProvider environmentProvider = new TestEnvironmentProvider(); - RegionalAccessBoundary.setEnvironmentProviderForTest(environmentProvider); - environmentProvider.setEnv(RegionalAccessBoundary.ENABLE_EXPERIMENT_ENV_VAR, "1"); + String poolId = "my-pool"; String providerId = "my-provider"; String audience = diff --git a/google-auth-library-java/oauth2_http/javatests/com/google/auth/oauth2/GoogleCredentialsTest.java b/google-auth-library-java/oauth2_http/javatests/com/google/auth/oauth2/GoogleCredentialsTest.java index dd64a07d4a1f..18e5c4585eef 100644 --- a/google-auth-library-java/oauth2_http/javatests/com/google/auth/oauth2/GoogleCredentialsTest.java +++ b/google-auth-library-java/oauth2_http/javatests/com/google/auth/oauth2/GoogleCredentialsTest.java @@ -109,9 +109,7 @@ class GoogleCredentialsTest extends BaseSerializationTest { void setUp() {} @org.junit.jupiter.api.AfterEach - void tearDown() { - RegionalAccessBoundary.setEnvironmentProviderForTest(null); - } + void tearDown() {} @Test void getApplicationDefault_nullTransport_throws() { @@ -858,9 +856,6 @@ void serialize() throws IOException, ClassNotFoundException { @Test public void serialize_removesStaleRabHeaders() throws Exception { - TestEnvironmentProvider environmentProvider = new TestEnvironmentProvider(); - RegionalAccessBoundary.setEnvironmentProviderForTest(environmentProvider); - environmentProvider.setEnv(RegionalAccessBoundary.ENABLE_EXPERIMENT_ENV_VAR, "1"); MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); RegionalAccessBoundary rab = @@ -1046,9 +1041,7 @@ void getCredentialInfo_impersonatedServiceAccount() throws IOException { @Test public void regionalAccessBoundary_shouldFetchAndReturnRegionalAccessBoundaryDataSuccessfully() throws IOException, InterruptedException { - TestEnvironmentProvider environmentProvider = new TestEnvironmentProvider(); - RegionalAccessBoundary.setEnvironmentProviderForTest(environmentProvider); - environmentProvider.setEnv(RegionalAccessBoundary.ENABLE_EXPERIMENT_ENV_VAR, "1"); + MockTokenServerTransport transport = new MockTokenServerTransport(); transport.addServiceAccount(SA_CLIENT_EMAIL, ACCESS_TOKEN); RegionalAccessBoundary regionalAccessBoundary = @@ -1083,9 +1076,6 @@ public void regionalAccessBoundary_shouldFetchAndReturnRegionalAccessBoundaryDat @Test public void regionalAccessBoundary_shouldRetryRegionalAccessBoundaryLookupOnFailure() throws IOException, InterruptedException { - TestEnvironmentProvider environmentProvider = new TestEnvironmentProvider(); - RegionalAccessBoundary.setEnvironmentProviderForTest(environmentProvider); - environmentProvider.setEnv(RegionalAccessBoundary.ENABLE_EXPERIMENT_ENV_VAR, "1"); // This transport will be used for the regional access boundary lookup. // We will configure it to fail on the first attempt. @@ -1137,9 +1127,7 @@ public com.google.api.client.http.LowLevelHttpRequest buildRequest( @Test public void regionalAccessBoundary_refreshShouldNotThrowWhenNoValidAccessTokenIsPassed() throws IOException { - TestEnvironmentProvider environmentProvider = new TestEnvironmentProvider(); - RegionalAccessBoundary.setEnvironmentProviderForTest(environmentProvider); - environmentProvider.setEnv(RegionalAccessBoundary.ENABLE_EXPERIMENT_ENV_VAR, "1"); + MockTokenServerTransport transport = new MockTokenServerTransport(); // Return an expired access token. transport.addServiceAccount(SA_CLIENT_EMAIL, "expired-token"); @@ -1162,9 +1150,7 @@ public void regionalAccessBoundary_refreshShouldNotThrowWhenNoValidAccessTokenIs @Test public void regionalAccessBoundary_cooldownDoublingAndRefresh() throws IOException, InterruptedException { - TestEnvironmentProvider environmentProvider = new TestEnvironmentProvider(); - RegionalAccessBoundary.setEnvironmentProviderForTest(environmentProvider); - environmentProvider.setEnv(RegionalAccessBoundary.ENABLE_EXPERIMENT_ENV_VAR, "1"); + MockTokenServerTransport transport = new MockTokenServerTransport(); transport.addServiceAccount(SA_CLIENT_EMAIL, ACCESS_TOKEN); // Always fail lookup for now. @@ -1224,9 +1210,7 @@ public void regionalAccessBoundary_cooldownDoublingAndRefresh() @Test public void regionalAccessBoundary_shouldFailOpenWhenRefreshCannotBeStarted() throws IOException { - TestEnvironmentProvider environmentProvider = new TestEnvironmentProvider(); - RegionalAccessBoundary.setEnvironmentProviderForTest(environmentProvider); - environmentProvider.setEnv(RegionalAccessBoundary.ENABLE_EXPERIMENT_ENV_VAR, "1"); + // Use a simple AccessToken-based credential that won't try to refresh. GoogleCredentials credentials = GoogleCredentials.create(new AccessToken("some-token", null)); @@ -1238,9 +1222,7 @@ public void regionalAccessBoundary_shouldFailOpenWhenRefreshCannotBeStarted() th @Test public void regionalAccessBoundary_deduplicationOfConcurrentRefreshes() throws IOException, InterruptedException { - TestEnvironmentProvider environmentProvider = new TestEnvironmentProvider(); - RegionalAccessBoundary.setEnvironmentProviderForTest(environmentProvider); - environmentProvider.setEnv(RegionalAccessBoundary.ENABLE_EXPERIMENT_ENV_VAR, "1"); + MockTokenServerTransport transport = new MockTokenServerTransport(); transport.setRegionalAccessBoundary( new RegionalAccessBoundary("valid", Collections.singletonList("us-central1"), null)); @@ -1269,9 +1251,7 @@ public void regionalAccessBoundary_deduplicationOfConcurrentRefreshes() @Test public void regionalAccessBoundary_shouldSkipRefreshForRegionalEndpoints() throws IOException { - TestEnvironmentProvider environmentProvider = new TestEnvironmentProvider(); - RegionalAccessBoundary.setEnvironmentProviderForTest(environmentProvider); - environmentProvider.setEnv(RegionalAccessBoundary.ENABLE_EXPERIMENT_ENV_VAR, "1"); + MockTokenServerTransport transport = new MockTokenServerTransport(); GoogleCredentials credentials = createTestCredentials(transport); diff --git a/google-auth-library-java/oauth2_http/javatests/com/google/auth/oauth2/IdentityPoolCredentialsTest.java b/google-auth-library-java/oauth2_http/javatests/com/google/auth/oauth2/IdentityPoolCredentialsTest.java index 399bf7246c9a..1f4b8167a2f8 100644 --- a/google-auth-library-java/oauth2_http/javatests/com/google/auth/oauth2/IdentityPoolCredentialsTest.java +++ b/google-auth-library-java/oauth2_http/javatests/com/google/auth/oauth2/IdentityPoolCredentialsTest.java @@ -81,9 +81,7 @@ class IdentityPoolCredentialsTest extends BaseSerializationTest { void setUp() {} @org.junit.jupiter.api.AfterEach - void tearDown() { - RegionalAccessBoundary.setEnvironmentProviderForTest(null); - } + void tearDown() {} @Test void createdScoped_clonedCredentialWithAddedScopes() { @@ -1312,9 +1310,6 @@ void setShouldThrowOnGetKeyStore(boolean shouldThrow) { @Test public void testRefresh_regionalAccessBoundarySuccess() throws IOException, InterruptedException { - TestEnvironmentProvider environmentProvider = new TestEnvironmentProvider(); - RegionalAccessBoundary.setEnvironmentProviderForTest(environmentProvider); - environmentProvider.setEnv(RegionalAccessBoundary.ENABLE_EXPERIMENT_ENV_VAR, "1"); MockExternalAccountCredentialsTransportFactory transportFactory = new MockExternalAccountCredentialsTransportFactory(); diff --git a/google-auth-library-java/oauth2_http/javatests/com/google/auth/oauth2/ImpersonatedCredentialsTest.java b/google-auth-library-java/oauth2_http/javatests/com/google/auth/oauth2/ImpersonatedCredentialsTest.java index fc3c2e9c783e..853e105cf24c 100644 --- a/google-auth-library-java/oauth2_http/javatests/com/google/auth/oauth2/ImpersonatedCredentialsTest.java +++ b/google-auth-library-java/oauth2_http/javatests/com/google/auth/oauth2/ImpersonatedCredentialsTest.java @@ -163,11 +163,6 @@ void setup() throws IOException { mockTransportFactory = new MockIAMCredentialsServiceTransportFactory(); } - @org.junit.After - public void tearDown() { - RegionalAccessBoundary.setEnvironmentProviderForTest(null); - } - static GoogleCredentials getSourceCredentials() throws IOException { MockTokenServerTransportFactory transportFactory = new MockTokenServerTransportFactory(); PrivateKey privateKey = OAuth2Utils.privateKeyFromPkcs8(SA_PRIVATE_KEY_PKCS8); @@ -1276,9 +1271,7 @@ void refreshAccessToken_afterSerialization_success() throws IOException, ClassNo @Test void refresh_regionalAccessBoundarySuccess() throws IOException, InterruptedException { - TestEnvironmentProvider environmentProvider = new TestEnvironmentProvider(); - RegionalAccessBoundary.setEnvironmentProviderForTest(environmentProvider); - environmentProvider.setEnv(RegionalAccessBoundary.ENABLE_EXPERIMENT_ENV_VAR, "1"); + // Mock regional access boundary response RegionalAccessBoundary regionalAccessBoundary = REGIONAL_ACCESS_BOUNDARY; diff --git a/google-auth-library-java/oauth2_http/javatests/com/google/auth/oauth2/PluggableAuthCredentialsTest.java b/google-auth-library-java/oauth2_http/javatests/com/google/auth/oauth2/PluggableAuthCredentialsTest.java index adc945dd72ea..8576ffe38e3a 100644 --- a/google-auth-library-java/oauth2_http/javatests/com/google/auth/oauth2/PluggableAuthCredentialsTest.java +++ b/google-auth-library-java/oauth2_http/javatests/com/google/auth/oauth2/PluggableAuthCredentialsTest.java @@ -59,9 +59,7 @@ class PluggableAuthCredentialsTest extends BaseSerializationTest { @org.junit.jupiter.api.AfterEach - void tearDown() { - RegionalAccessBoundary.setEnvironmentProviderForTest(null); - } + void tearDown() {} // The default timeout for waiting for the executable to finish (30 seconds). private static final int DEFAULT_EXECUTABLE_TIMEOUT_MS = 30 * 1000; @@ -610,9 +608,6 @@ void serialize() { @Test public void testRefresh_regionalAccessBoundarySuccess() throws IOException, InterruptedException { - TestEnvironmentProvider environmentProvider = new TestEnvironmentProvider(); - RegionalAccessBoundary.setEnvironmentProviderForTest(environmentProvider); - environmentProvider.setEnv(RegionalAccessBoundary.ENABLE_EXPERIMENT_ENV_VAR, "1"); MockExternalAccountCredentialsTransportFactory transportFactory = new MockExternalAccountCredentialsTransportFactory(); diff --git a/google-auth-library-java/oauth2_http/javatests/com/google/auth/oauth2/RegionalAccessBoundaryTest.java b/google-auth-library-java/oauth2_http/javatests/com/google/auth/oauth2/RegionalAccessBoundaryTest.java index 7c7ccd690ce2..8e68404b6e9e 100644 --- a/google-auth-library-java/oauth2_http/javatests/com/google/auth/oauth2/RegionalAccessBoundaryTest.java +++ b/google-auth-library-java/oauth2_http/javatests/com/google/auth/oauth2/RegionalAccessBoundaryTest.java @@ -31,9 +31,9 @@ package com.google.auth.oauth2; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; import com.google.api.client.testing.http.MockHttpTransport; import com.google.api.client.testing.http.MockLowLevelHttpResponse; @@ -41,17 +41,15 @@ import com.google.auth.http.HttpTransportFactory; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; +import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.util.Collections; import java.util.concurrent.atomic.AtomicLong; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -@RunWith(JUnit4.class) public class RegionalAccessBoundaryTest { private static final long TTL = RegionalAccessBoundary.TTL_MILLIS; @@ -59,12 +57,12 @@ public class RegionalAccessBoundaryTest { private TestClock testClock; - @Before + @BeforeEach public void setUp() { testClock = new TestClock(); } - @After + @AfterEach public void tearDown() {} @Test @@ -127,6 +125,27 @@ public void testSerialization() throws Exception { assertFalse(deserializedRab.isExpired()); } + @Test + public void testRefreshClosesResponse() throws Exception { + final String url = "https://example.com/rab"; + final AccessToken token = + new AccessToken("token", new java.util.Date(System.currentTimeMillis() + 3600000L)); + + TrackingMockLowLevelHttpResponse mockResponse = new TrackingMockLowLevelHttpResponse(); + mockResponse.setContentType("application/json"); + mockResponse.setContent("{\"encodedLocations\": \"encoded\", \"locations\": [\"loc\"]}"); + + MockHttpTransport transport = + new MockHttpTransport.Builder().setLowLevelHttpResponse(mockResponse).build(); + HttpTransportFactory transportFactory = () -> transport; + + RegionalAccessBoundary rab = + RegionalAccessBoundary.refresh(transportFactory, url, token, testClock, 1000); + + assertEquals("encoded", rab.getEncodedLocations()); + assertTrue(mockResponse.isDisconnected(), "Response should have been disconnected"); + } + @Test public void testManagerTriggersRefreshInGracePeriod() throws InterruptedException { final String url = @@ -200,8 +219,8 @@ public void testManagerTriggersRefreshInGracePeriod() throws InterruptedExceptio } assertTrue( - "Refresh should have completed and updated the cache within 5 seconds", - resultRab != null && newerEncoded.equals(resultRab.getEncodedLocations())); + resultRab != null && newerEncoded.equals(resultRab.getEncodedLocations()), + "Refresh should have completed and updated the cache within 5 seconds"); assertEquals(newerEncoded, resultRab.getEncodedLocations()); } @@ -217,4 +236,18 @@ public void set(long millis) { currentTime.set(millis); } } + + private static class TrackingMockLowLevelHttpResponse extends MockLowLevelHttpResponse { + private boolean disconnected = false; + + @Override + public void disconnect() throws IOException { + super.disconnect(); + disconnected = true; + } + + public boolean isDisconnected() { + return disconnected; + } + } } diff --git a/google-auth-library-java/oauth2_http/javatests/com/google/auth/oauth2/ServiceAccountCredentialsTest.java b/google-auth-library-java/oauth2_http/javatests/com/google/auth/oauth2/ServiceAccountCredentialsTest.java index 1ac38f957c6e..9f8df19a188b 100644 --- a/google-auth-library-java/oauth2_http/javatests/com/google/auth/oauth2/ServiceAccountCredentialsTest.java +++ b/google-auth-library-java/oauth2_http/javatests/com/google/auth/oauth2/ServiceAccountCredentialsTest.java @@ -160,9 +160,7 @@ static ServiceAccountCredentials.Builder createDefaultBuilder() throws IOExcepti void setUp() {} @org.junit.jupiter.api.AfterEach - void tearDown() { - RegionalAccessBoundary.setEnvironmentProviderForTest(null); - } + void tearDown() {} @Test void setLifetime() throws IOException { @@ -1773,9 +1771,7 @@ void createScopes_existingAccessTokenInvalidated() throws IOException { @Test public void refresh_regionalAccessBoundarySuccess() throws IOException, InterruptedException { - TestEnvironmentProvider environmentProvider = new TestEnvironmentProvider(); - RegionalAccessBoundary.setEnvironmentProviderForTest(environmentProvider); - environmentProvider.setEnv(RegionalAccessBoundary.ENABLE_EXPERIMENT_ENV_VAR, "1"); + // Mock regional access boundary response RegionalAccessBoundary regionalAccessBoundary = new RegionalAccessBoundary( @@ -1813,9 +1809,7 @@ public void refresh_regionalAccessBoundarySuccess() throws IOException, Interrup @Test public void refresh_regionalAccessBoundary_selfSignedJWT() throws IOException, InterruptedException { - TestEnvironmentProvider environmentProvider = new TestEnvironmentProvider(); - RegionalAccessBoundary.setEnvironmentProviderForTest(environmentProvider); - environmentProvider.setEnv(RegionalAccessBoundary.ENABLE_EXPERIMENT_ENV_VAR, "1"); + RegionalAccessBoundary regionalAccessBoundary = new RegionalAccessBoundary( TestUtils.REGIONAL_ACCESS_BOUNDARY_ENCODED_LOCATION,