From 8a8ed0af8ee3d0a109f46bc7cf021e5a5b389774 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Fri, 13 Mar 2026 15:04:52 +0100 Subject: [PATCH] Fix OAuth2 test flakiness caused by Response and WebClient resource leaks Close Response objects in OAuth2TestUtils.getLocation() methods using try-finally blocks to prevent connection pool exhaustion under CI load. Close WebClient instances in AuthorizationGrantTest and PublicClientTest after use to release HTTP connections. Co-Authored-By: Claude Opus 4.6 --- .../oauth2/common/OAuth2TestUtils.java | 15 ++++++++-- .../oauth2/grants/AuthorizationGrantTest.java | 29 +++++++++++++++++-- .../oauth2/grants/PublicClientTest.java | 10 +++++++ 3 files changed, 49 insertions(+), 5 deletions(-) diff --git a/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/common/OAuth2TestUtils.java b/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/common/OAuth2TestUtils.java index ca99309632a..4f15cc0fafc 100644 --- a/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/common/OAuth2TestUtils.java +++ b/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/common/OAuth2TestUtils.java @@ -125,8 +125,12 @@ public static String getLocation(WebClient client, AuthorizationCodeParameters p client.path(parameters.getPath()); Response response = client.get(); - - OAuthAuthorizationData authzData = response.readEntity(OAuthAuthorizationData.class); + OAuthAuthorizationData authzData; + try { + authzData = response.readEntity(OAuthAuthorizationData.class); + } finally { + response.close(); + } return getLocation(client, authzData, parameters.getState()); } @@ -159,7 +163,12 @@ public static String getLocation(WebClient client, OAuthAuthorizationData authzD form.param("oauthDecision", "allow"); Response response = client.post(form); - String location = response.getHeaderString("Location"); + String location; + try { + location = response.getHeaderString("Location"); + } finally { + response.close(); + } if (state != null) { Assert.assertTrue(location.contains("state=" + state)); } diff --git a/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/grants/AuthorizationGrantTest.java b/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/grants/AuthorizationGrantTest.java index 89f96c6e223..70e28994bf7 100644 --- a/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/grants/AuthorizationGrantTest.java +++ b/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/grants/AuthorizationGrantTest.java @@ -126,6 +126,7 @@ public void testAuthorizationCodeGrant() throws Exception { // Get Authorization Code String code = OAuth2TestUtils.getAuthorizationCode(client); assertNotNull(code); + client.close(); // Now get the access token client = WebClient.create(address, "consumer-id", "this-is-a-secret", null); @@ -133,6 +134,7 @@ public void testAuthorizationCodeGrant() throws Exception { ClientAccessToken accessToken = OAuth2TestUtils.getAccessTokenWithAuthorizationCode(client, code); assertNotNull(accessToken.getTokenKey()); + client.close(); if (isAccessTokenInJWTFormat()) { validateAccessToken(accessToken.getTokenKey()); @@ -165,6 +167,7 @@ public void testAuthorizationCodeGrantPOST() throws Exception { String location = OAuth2TestUtils.getLocation(client, authzData, null); String code = OAuth2TestUtils.getSubstring(location, "code"); assertNotNull(code); + client.close(); // Now get the access token client = WebClient.create(address, "consumer-id", "this-is-a-secret", null); @@ -172,6 +175,7 @@ public void testAuthorizationCodeGrantPOST() throws Exception { ClientAccessToken accessToken = OAuth2TestUtils.getAccessTokenWithAuthorizationCode(client, code); assertNotNull(accessToken.getTokenKey()); + client.close(); if (isAccessTokenInJWTFormat()) { validateAccessToken(accessToken.getTokenKey()); @@ -190,6 +194,7 @@ public void testAuthorizationCodeGrantRefresh() throws Exception { // Get Authorization Code String code = OAuth2TestUtils.getAuthorizationCode(client); assertNotNull(code); + client.close(); // Now get the access token client = WebClient.create(address, OAuth2TestUtils.setupProviders(), @@ -214,6 +219,7 @@ public void testAuthorizationCodeGrantRefresh() throws Exception { accessToken = client.post(form, ClientAccessToken.class); assertNotNull(accessToken.getTokenKey()); assertNotNull(accessToken.getRefreshToken()); + client.close(); if (isAccessTokenInJWTFormat()) { validateAccessToken(accessToken.getTokenKey()); @@ -232,6 +238,7 @@ public void testAuthorizationCodeGrantRefreshWithScope() throws Exception { // Get Authorization Code String code = OAuth2TestUtils.getAuthorizationCode(client, "read_balance"); assertNotNull(code); + client.close(); // Now get the access token client = WebClient.create(address, OAuth2TestUtils.setupProviders(), @@ -258,6 +265,7 @@ public void testAuthorizationCodeGrantRefreshWithScope() throws Exception { assertNotNull(accessToken.getTokenKey()); assertNotNull(accessToken.getRefreshToken()); assertEquals("read_balance", accessToken.getApprovedScope()); + client.close(); if (isAccessTokenInJWTFormat()) { validateAccessToken(accessToken.getTokenKey()); @@ -277,6 +285,7 @@ public void testAuthorizationCodeGrantRefreshWithoutScope() throws Exception { // Get Authorization Code String code = OAuth2TestUtils.getAuthorizationCode(client, "read_balance"); assertNotNull(code); + client.close(); // Now get the access token client = WebClient.create(address, OAuth2TestUtils.setupProviders(), @@ -302,6 +311,7 @@ public void testAuthorizationCodeGrantRefreshWithoutScope() throws Exception { assertNotNull(accessToken.getTokenKey()); assertNotNull(accessToken.getRefreshToken()); // assertEquals("read_balance", accessToken.getApprovedScope()); + client.close(); if (isAccessTokenInJWTFormat()) { validateAccessToken(accessToken.getTokenKey()); @@ -320,6 +330,7 @@ public void testAuthorizationCodeGrantWithScope() throws Exception { // Get Authorization Code String code = OAuth2TestUtils.getAuthorizationCode(client, "read_balance"); assertNotNull(code); + client.close(); // Now get the access token client = WebClient.create(address, "consumer-id", "this-is-a-secret", null); @@ -327,6 +338,7 @@ public void testAuthorizationCodeGrantWithScope() throws Exception { ClientAccessToken accessToken = OAuth2TestUtils.getAccessTokenWithAuthorizationCode(client, code); assertNotNull(accessToken.getTokenKey()); + client.close(); } @org.junit.Test @@ -343,6 +355,7 @@ public void testAuthorizationCodeGrantWithState() throws Exception { String code = OAuth2TestUtils.getAuthorizationCode(client, "read_balance", "consumer-id", null, state); assertNotNull(code); + client.close(); // Now get the access token client = WebClient.create(address, "consumer-id", "this-is-a-secret", null); @@ -350,6 +363,7 @@ public void testAuthorizationCodeGrantWithState() throws Exception { ClientAccessToken accessToken = OAuth2TestUtils.getAccessTokenWithAuthorizationCode(client, code); assertNotNull(accessToken.getTokenKey()); + client.close(); } @org.junit.Test @@ -364,6 +378,7 @@ public void testAuthorizationCodeGrantWithAudience() throws Exception { // Get Authorization Code String code = OAuth2TestUtils.getAuthorizationCode(client, null, "consumer-id-aud"); assertNotNull(code); + client.close(); // Now get the access token client = WebClient.create(address, "consumer-id-aud", "this-is-a-secret", null); @@ -383,6 +398,7 @@ public void testAuthorizationCodeGrantWithAudience() throws Exception { OAuth2TestUtils.getAccessTokenWithAuthorizationCode(client, code, "consumer-id-aud", audience); assertNotNull(accessToken.getTokenKey()); + client.close(); } @org.junit.Test @@ -414,10 +430,15 @@ public void testImplicitGrant() throws Exception { form.param("oauthDecision", "allow"); Response response = client.post(form); - - String location = response.getHeaderString("Location"); + String location; + try { + location = response.getHeaderString("Location"); + } finally { + response.close(); + } String accessToken = OAuth2TestUtils.getSubstring(location, "access_token"); assertNotNull(accessToken); + client.close(); if (isAccessTokenInJWTFormat()) { validateAccessToken(accessToken); @@ -442,6 +463,7 @@ public void testPasswordsCredentialsGrant() throws Exception { ClientAccessToken accessToken = client.post(form, ClientAccessToken.class); assertNotNull(accessToken.getTokenKey()); assertNotNull(accessToken.getRefreshToken()); + client.close(); if (isAccessTokenInJWTFormat()) { validateAccessToken(accessToken.getTokenKey()); @@ -464,6 +486,7 @@ public void testClientCredentialsGrant() throws Exception { ClientAccessToken accessToken = client.post(form, ClientAccessToken.class); assertNotNull(accessToken.getTokenKey()); assertNotNull(accessToken.getRefreshToken()); + client.close(); if (isAccessTokenInJWTFormat()) { validateAccessToken(accessToken.getTokenKey()); @@ -491,6 +514,7 @@ public void testSAMLAuthorizationGrant() throws Exception { ClientAccessToken accessToken = client.post(form, ClientAccessToken.class); assertNotNull(accessToken.getTokenKey()); assertNotNull(accessToken.getRefreshToken()); + client.close(); if (isAccessTokenInJWTFormat()) { validateAccessToken(accessToken.getTokenKey()); @@ -519,6 +543,7 @@ public void testJWTAuthorizationGrant() throws Exception { ClientAccessToken accessToken = client.post(form, ClientAccessToken.class); assertNotNull(accessToken.getTokenKey()); assertNotNull(accessToken.getRefreshToken()); + client.close(); if (isAccessTokenInJWTFormat()) { validateAccessToken(accessToken.getTokenKey()); diff --git a/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/grants/PublicClientTest.java b/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/grants/PublicClientTest.java index b65ef72e259..68693acb74c 100644 --- a/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/grants/PublicClientTest.java +++ b/systests/rs-security/src/test/java/org/apache/cxf/systest/jaxrs/security/oauth2/grants/PublicClientTest.java @@ -111,6 +111,8 @@ public void testAuthorizationCodeGrantNoRedirectURI() throws Exception { fail("Failure expected on a missing (registered) redirectURI"); } catch (Exception ex) { // expected + } finally { + client.close(); } } @@ -166,12 +168,14 @@ private void testPKCE(CodeVerifierTransformer transformer) { String location = OAuth2TestUtils.getLocation(client, parameters); String code = OAuth2TestUtils.getSubstring(location, "code"); assertNotNull(code); + client.close(); // Now get the access token client = WebClient.create(tokenServiceAddress, busFile.toString()); ClientAccessToken accessToken = OAuth2TestUtils.getAccessTokenWithAuthorizationCode(client, code, "consumer-id", null, codeVerifier); assertNotNull(accessToken.getTokenKey()); + client.close(); } private void testPKCEMissingVerifier(CodeVerifierTransformer transformer) { @@ -196,6 +200,7 @@ private void testPKCEMissingVerifier(CodeVerifierTransformer transformer) { String location = OAuth2TestUtils.getLocation(client, parameters); String code = OAuth2TestUtils.getSubstring(location, "code"); assertNotNull(code); + client.close(); // Now get the access token client = WebClient.create(tokenServiceAddress, busFile.toString()); @@ -204,6 +209,8 @@ private void testPKCEMissingVerifier(CodeVerifierTransformer transformer) { fail("Failure expected on a missing verifier"); } catch (OAuthServiceException ex) { assertFalse(ex.getError().getError().isEmpty()); + } finally { + client.close(); } } @@ -229,6 +236,7 @@ private void testPKCEDifferentVerifier(CodeVerifierTransformer transformer) { String location = OAuth2TestUtils.getLocation(client, parameters); String code = OAuth2TestUtils.getSubstring(location, "code"); assertNotNull(code); + client.close(); // Now get the access token client = WebClient.create(tokenServiceAddress, busFile.toString()); @@ -239,6 +247,8 @@ private void testPKCEDifferentVerifier(CodeVerifierTransformer transformer) { fail("Failure expected on a different verifier"); } catch (OAuthServiceException ex) { assertFalse(ex.getError().getError().isEmpty()); + } finally { + client.close(); } }