diff --git a/geode-assembly/build.gradle b/geode-assembly/build.gradle index 0102ccea40c..c8b75fb5e99 100755 --- a/geode-assembly/build.gradle +++ b/geode-assembly/build.gradle @@ -579,6 +579,11 @@ tasks.named('distributedTest') { ] } +// Increase heap size for integrationTest to prevent OOM with Pulse SSL tests +tasks.named('integrationTest') { + maxHeapSize = '2g' +} + acceptanceTest.dependsOn(rootProject.getTasksByName("publishToMavenLocal", true)) installDist.dependsOn ':extensions:geode-modules-assembly:dist' diff --git a/geode-assembly/geode-assembly-test/src/main/java/org/apache/geode/test/junit/rules/GeodeHttpClientRule.java b/geode-assembly/geode-assembly-test/src/main/java/org/apache/geode/test/junit/rules/GeodeHttpClientRule.java index b6dec6eb47a..72824a55089 100644 --- a/geode-assembly/geode-assembly-test/src/main/java/org/apache/geode/test/junit/rules/GeodeHttpClientRule.java +++ b/geode-assembly/geode-assembly-test/src/main/java/org/apache/geode/test/junit/rules/GeodeHttpClientRule.java @@ -25,6 +25,7 @@ import org.apache.hc.client5.http.classic.HttpClient; import org.apache.hc.client5.http.classic.methods.HttpGet; import org.apache.hc.client5.http.classic.methods.HttpPost; +import org.apache.hc.client5.http.config.RequestConfig; import org.apache.hc.client5.http.cookie.BasicCookieStore; import org.apache.hc.client5.http.entity.UrlEncodedFormEntity; import org.apache.hc.client5.http.impl.DefaultRedirectStrategy; @@ -41,6 +42,7 @@ import org.apache.hc.core5.http.ProtocolException; import org.apache.hc.core5.http.message.BasicNameValuePair; import org.apache.hc.core5.net.URIBuilder; +import org.apache.hc.core5.util.TimeValue; import org.junit.rules.ExternalResource; import org.apache.geode.internal.net.SocketCreatorFactory; @@ -98,9 +100,56 @@ public ClassicHttpResponse loginToPulse(String username, String password) throws HttpClientContext freshLoginContext = HttpClientContext.create(); // Explicitly set an empty cookie store to ensure no cookies from previous requests freshLoginContext.setCookieStore(new BasicCookieStore()); - ClassicHttpResponse response = (ClassicHttpResponse) httpClientNoRedirect.execute(host, - buildHttpPost("/pulse/login", "username", username, "password", password), - freshLoginContext); + + long startTime = System.currentTimeMillis(); + System.err.println("[HTTP] ===== HTTP POST REQUEST START ====="); + System.err + .println("[HTTP] Timestamp: " + java.time.Instant.now() + " (epoch: " + startTime + ")"); + System.err.println("[HTTP] Target: " + host + "/pulse/login"); + System.err.println("[HTTP] Username: " + username); + System.err.println("[HTTP] About to call httpClientNoRedirect.execute()..."); + + ClassicHttpResponse response; + try { + System.err.println("[HTTP] Executing HTTP request NOW at " + java.time.Instant.now()); + response = (ClassicHttpResponse) httpClientNoRedirect.execute(host, + buildHttpPost("/pulse/login", "username", username, "password", password), + freshLoginContext); + long endTime = System.currentTimeMillis(); + System.err.println("[HTTP] ===== HTTP POST REQUEST COMPLETED ====="); + System.err.println("[HTTP] Duration: " + (endTime - startTime) + "ms"); + System.err.println("[HTTP] Response code: " + response.getCode()); + System.err.println("[HTTP] Response Location header: " + + (response.getFirstHeader("Location") != null + ? response.getFirstHeader("Location").getValue() : "null")); + System.err.println("[HTTP] Completed at: " + java.time.Instant.now()); + } catch (org.apache.hc.client5.http.impl.classic.RequestFailedException e) { + long endTime = System.currentTimeMillis(); + System.err.println("[HTTP] RequestFailedException after " + (endTime - startTime) + + "ms: " + e.getMessage() + " (request aborted/cancelled)"); + throw e; + } catch (org.apache.hc.core5.http.ConnectionRequestTimeoutException e) { + long endTime = System.currentTimeMillis(); + System.err.println("[HTTP] ConnectionRequestTimeoutException after " + (endTime - startTime) + + "ms: " + e.getMessage() + " (pool exhausted waiting for connection)"); + throw e; + } catch (java.net.SocketTimeoutException e) { + long endTime = System.currentTimeMillis(); + System.err.println("[HTTP] SocketTimeoutException after " + (endTime - startTime) + + "ms: " + e.getMessage() + " (connect or read timeout)"); + throw e; + } catch (org.apache.hc.core5.http.ConnectionClosedException e) { + long endTime = System.currentTimeMillis(); + System.err.println("[HTTP] ConnectionClosedException after " + (endTime - startTime) + + "ms: " + e.getMessage() + " (connection closed by server)"); + throw e; + } catch (Exception e) { + long endTime = System.currentTimeMillis(); + System.err + .println("[HTTP] " + e.getClass().getSimpleName() + " after " + (endTime - startTime) + + "ms: " + e.getMessage()); + throw e; + } // If login is successful (302 redirect to clusterDetail), update shared context with new // session if (response.getCode() == 302 && response.getFirstHeader("Location") != null @@ -160,6 +209,10 @@ private void connect() { return; } + System.err + .println("[HTTP-INIT] Starting HTTP client initialization at " + java.time.Instant.now()); + System.err.println("[HTTP-INIT] SSL enabled: " + useSSL); + // Jakarta EE migration: Create lenient redirect strategy for URIs with placeholders // Apache HttpComponents 5 is stricter about URI validation than version 4 // This allows Spring Security OAuth2 redirect URIs with property placeholders @@ -184,37 +237,91 @@ public boolean isRedirected( } }; - host = new HttpHost(useSSL ? "https" : "http", hostName, portSupplier.get()); + int port = portSupplier.get(); + host = new HttpHost(useSSL ? "https" : "http", hostName, port); + System.err.println( + "[HTTP-INIT] Target host: " + (useSSL ? "https" : "http") + "://" + hostName + ":" + port); + + // Configure timeouts to prevent tests from hanging indefinitely + // when Pulse JMX authentication backend is not ready. + // Using shorter timeouts (5s) allows await() retry logic to poll more frequently + // rather than waiting 30s per failed attempt. + RequestConfig requestConfig = RequestConfig.custom() + .setConnectionRequestTimeout(5000, java.util.concurrent.TimeUnit.MILLISECONDS) + .setConnectTimeout(5000, java.util.concurrent.TimeUnit.MILLISECONDS) + .setResponseTimeout(5000, java.util.concurrent.TimeUnit.MILLISECONDS) + .build(); + System.err.println( + "[HTTP-INIT] Request config: ConnectionRequestTimeout=5s, ConnectTimeout=5s, ResponseTimeout=5s"); + if (useSSL) { + System.err.println("[HTTP-INIT] Configuring SSL connection manager..."); HttpClientBuilder clientBuilder = HttpClients.custom(); SSLContext ctx = SocketCreatorFactory .getSocketCreatorForComponent(SecurableCommunicationChannel.WEB).getSslContext(); // HttpClient 5.x: SSL configuration via connection manager + // Increase pool size and enable eviction to prevent connection exhaustion during retries HttpClientConnectionManager connectionManager = PoolingHttpClientConnectionManagerBuilder.create() + .setMaxConnPerRoute(10) // Increase from default 2 to handle multiple retries + .setMaxConnTotal(20) // Increase from default 20 .setSSLSocketFactory(SSLConnectionSocketFactoryBuilder.create() .setSslContext(ctx) .setHostnameVerifier(NoopHostnameVerifier.INSTANCE) .build()) .build(); + System.err.println( + "[HTTP-INIT] SSL connection manager created: maxConnPerRoute=10, maxConnTotal=20"); clientBuilder.setConnectionManager(connectionManager); + // Enable connection eviction to release stale connections + System.err + .println("[HTTP-INIT] Enabling connection eviction: expired immediately, idle after 10s"); + clientBuilder.evictExpiredConnections(); + clientBuilder.evictIdleConnections(TimeValue.ofSeconds(10)); // Jakarta EE migration: Create client with lenient redirect strategy clientBuilder.setRedirectStrategy(lenientRedirectStrategy); + clientBuilder.setDefaultRequestConfig(requestConfig); + System.err.println("[HTTP-INIT] Building main HTTP client with SSL..."); httpClient = clientBuilder.build(); + System.err.println("[HTTP-INIT] Main HTTP client created successfully"); // Jakarta EE migration: Create client without redirect handling for login verification + System.err.println("[HTTP-INIT] Building no-redirect HTTP client..."); httpClientNoRedirect = HttpClients.custom() .setConnectionManager(connectionManager) + .setDefaultRequestConfig(requestConfig) .disableRedirectHandling() .build(); + System.err.println("[HTTP-INIT] No-redirect HTTP client created successfully"); + System.err.println( + "[HTTP-INIT] HTTP client initialization completed at " + java.time.Instant.now()); } else { + System.err.println("[HTTP-INIT] Configuring non-SSL connection manager..."); + // Configure connection pool for non-SSL client + HttpClientConnectionManager connectionManager = + PoolingHttpClientConnectionManagerBuilder.create() + .setMaxConnPerRoute(10) + .setMaxConnTotal(20) + .build(); + System.err.println( + "[HTTP-INIT] Non-SSL connection manager created: maxConnPerRoute=10, maxConnTotal=20"); // Jakarta EE migration: Create client with lenient redirect strategy + System.err.println("[HTTP-INIT] Building non-SSL HTTP clients..."); httpClient = HttpClients.custom() + .setConnectionManager(connectionManager) .setRedirectStrategy(lenientRedirectStrategy) + .setDefaultRequestConfig(requestConfig) + .evictExpiredConnections() + .evictIdleConnections(TimeValue.ofSeconds(10)) .build(); // Jakarta EE migration: Create client without redirect handling for login verification httpClientNoRedirect = HttpClients.custom() + .setConnectionManager(connectionManager) + .setDefaultRequestConfig(requestConfig) .disableRedirectHandling() .build(); + System.err.println("[HTTP-INIT] Non-SSL HTTP clients created successfully"); + System.err.println( + "[HTTP-INIT] HTTP client initialization completed at " + java.time.Instant.now()); } } diff --git a/geode-assembly/src/integrationTest/java/org/apache/geode/tools/pulse/PulseSecurityWithSSLTest.java b/geode-assembly/src/integrationTest/java/org/apache/geode/tools/pulse/PulseSecurityWithSSLTest.java index efcd704b744..5df573a9a06 100644 --- a/geode-assembly/src/integrationTest/java/org/apache/geode/tools/pulse/PulseSecurityWithSSLTest.java +++ b/geode-assembly/src/integrationTest/java/org/apache/geode/tools/pulse/PulseSecurityWithSSLTest.java @@ -36,6 +36,7 @@ import static org.apache.geode.distributed.ConfigurationProperties.SSL_PROTOCOLS; import static org.apache.geode.distributed.ConfigurationProperties.SSL_TRUSTSTORE; import static org.apache.geode.distributed.ConfigurationProperties.SSL_TRUSTSTORE_PASSWORD; +import static org.apache.geode.test.awaitility.GeodeAwaitility.await; import static org.apache.geode.test.util.ResourceUtils.createTempFileFromResource; import static org.assertj.core.api.Assertions.assertThat; @@ -46,11 +47,13 @@ import com.jayway.jsonpath.JsonPath; import org.apache.commons.io.IOUtils; import org.apache.hc.core5.http.ClassicHttpResponse; +import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.experimental.categories.Category; import org.apache.geode.examples.SimpleSecurityManager; +import org.apache.geode.management.ManagementService; import org.apache.geode.security.SecurableCommunicationChannels; import org.apache.geode.test.junit.categories.PulseTest; import org.apache.geode.test.junit.categories.SecurityTest; @@ -70,6 +73,17 @@ public class PulseSecurityWithSSLTest { @Rule public GeodeHttpClientRule client = new GeodeHttpClientRule(locator::getHttpPort).withSSL(); + @Before + public void logTestStart() { + String testName = Thread.currentThread().getStackTrace()[2].getMethodName(); + System.err.println("========================================"); + System.err.println("[TEST START] " + getClass().getSimpleName() + "." + testName); + System.err.println("[TEST] Java Version: " + System.getProperty("java.version")); + System.err.println("[TEST] OS: " + System.getProperty("os.name")); + System.err.println("[TEST] Timestamp: " + java.time.Instant.now()); + System.err.println("========================================"); + } + @Test public void loginWithIncorrectAndThenCorrectPassword() throws Exception { Properties securityProps = new Properties(); @@ -81,15 +95,117 @@ public void loginWithIncorrectAndThenCorrectPassword() throws Exception { securityProps.setProperty(SSL_PROTOCOLS, "TLSv1.2"); securityProps.setProperty(SSL_CIPHERS, "any"); + System.err.println("[DEBUG] Starting locator with SSL configuration..."); + System.err.println("[DEBUG] SSL_PROTOCOLS: TLSv1.2"); + System.err.println("[DEBUG] SSL_CIPHERS: any"); locator.withSecurityManager(SimpleSecurityManager.class).withProperties(securityProps) .startLocator(); + System.err.println("[DEBUG] Locator started successfully on port: " + locator.getHttpPort()); + System.err.println("[DEBUG] Locator JMX port: " + locator.getJmxPort()); + + // Wait for JMX/Management Service to be fully initialized before login attempts + // This prevents race conditions on slower CI machines where authentication may fail + // if the JMX backend is not ready yet + System.err.println("[DEBUG] Getting ManagementService instance..."); + ManagementService service = + ManagementService.getExistingManagementService(locator.getLocator().getCache()); + System.err.println("[DEBUG] ManagementService obtained: " + service); + System.err.println("[DEBUG] Waiting for MemberMXBean to be ready..."); + long mbeanWaitStart = System.currentTimeMillis(); + await() + .untilAsserted(() -> assertThat(service.getMemberMXBean()).isNotNull()); + long mbeanWaitEnd = System.currentTimeMillis(); + System.err.println("[DEBUG] MemberMXBean is ready after " + (mbeanWaitEnd - mbeanWaitStart) + + "ms: " + service.getMemberMXBean()); + System.err + .println("[DEBUG] MemberMXBean class: " + service.getMemberMXBean().getClass().getName()); + // Additionally wait for Pulse web application to be fully responsive + System.err.println("[DEBUG] Waiting for Pulse web app to respond..."); + long webAppWaitStart = System.currentTimeMillis(); + await() + .untilAsserted(() -> { + ClassicHttpResponse loginPageResponse = client.get("/pulse/login.html"); + try { + assertThat(loginPageResponse.getCode()).isEqualTo(200); + } finally { + // Ensure entity is consumed to return connection to pool + if (loginPageResponse.getEntity() != null) { + try { + loginPageResponse.getEntity().getContent().close(); + } catch (Exception ignore) { + } + } + } + }); + long webAppWaitEnd = System.currentTimeMillis(); + System.err.println( + "[DEBUG] Pulse web app is responsive after " + (webAppWaitEnd - webAppWaitStart) + "ms"); + + System.err.println("[DEBUG] ===== Testing wrong password login ====="); + System.err.println("[DEBUG] Attempting login with wrong password (data/wrongPassword)..."); + long wrongPasswordStart = System.currentTimeMillis(); ClassicHttpResponse response = client.loginToPulse("data", "wrongPassword"); + long wrongPasswordEnd = System.currentTimeMillis(); + System.err.println("[DEBUG] Wrong password response received in " + + (wrongPasswordEnd - wrongPasswordStart) + "ms"); + System.err.println("[DEBUG] Response code: " + response.getCode()); + System.err.println("[DEBUG] Location header: " + + (response.getFirstHeader("Location") != null + ? response.getFirstHeader("Location").getValue() : "null")); assertThat(response.getCode()).isEqualTo(302); assertThat(response.getFirstHeader("Location").getValue()) .contains("/pulse/login.html?error=BAD_CREDS"); - client.loginToPulseAndVerify("cluster", "cluster"); + // Wait for JMX authentication backend to be ready by polling login attempts + // The backend may timeout initially while JMX connections are being established + System.err.println("[DEBUG] ===== Starting JMX backend readiness check ====="); + System.err.println("[DEBUG] Waiting for JMX authentication backend to be ready..."); + System.err.println("[DEBUG] Max wait time: 5 minutes, poll interval: 50ms"); + long jmxBackendWaitStart = System.currentTimeMillis(); + final java.util.concurrent.atomic.AtomicInteger attemptCounter = + new java.util.concurrent.atomic.AtomicInteger(0); + await() + .untilAsserted(() -> { + int attempt = attemptCounter.incrementAndGet(); + long attemptStartTime = System.currentTimeMillis(); + long elapsedSinceJmxStart = attemptStartTime - jmxBackendWaitStart; + System.err.println("[DEBUG] ========================================"); + System.err.println("[DEBUG] === Attempt #" + attempt + " ==="); + System.err.println("[DEBUG] Timestamp: " + java.time.Instant.now()); + System.err + .println("[DEBUG] Elapsed since JMX check start: " + elapsedSinceJmxStart + "ms"); + System.err + .println("[DEBUG] Attempting login with correct credentials (cluster/cluster)..."); + try { + long startTime = System.currentTimeMillis(); + client.loginToPulseAndVerify("cluster", "cluster"); + long duration = System.currentTimeMillis() - startTime; + System.err.println("[DEBUG] Login successful after " + duration + "ms!"); + long totalElapsed = System.currentTimeMillis() - jmxBackendWaitStart; + System.err.println("[DEBUG] Total JMX backend readiness time: " + totalElapsed + + "ms, total attempts: " + attempt); + } catch (Exception e) { + long duration = System.currentTimeMillis() - attemptStartTime; + System.err.println("[DEBUG] Login failed after " + duration + "ms: " + + e.getClass().getSimpleName() + ": " + e.getMessage()); + // Print root cause if different + Throwable cause = e.getCause(); + if (cause != null && cause != e) { + System.err.println("[DEBUG] Caused by: " + cause.getClass().getSimpleName() + ": " + + cause.getMessage()); + // Print second-level cause if present + Throwable secondLevelCause = cause.getCause(); + if (secondLevelCause != null && secondLevelCause != cause) { + System.err.println( + "[DEBUG] Caused by: " + secondLevelCause.getClass().getSimpleName() + ": " + + secondLevelCause.getMessage()); + } + } + System.err.println("[DEBUG] Will retry (attempt #" + attempt + ")..."); + throw new AssertionError("Login failed, will retry", e); + } + }); // Ensure that the backend JMX connection is working too response = client.post("/pulse/pulseUpdate", "pulseData", @@ -122,8 +238,98 @@ public void loginWithDeprecatedSSLOptions() throws Exception { locator.withSecurityManager(SimpleSecurityManager.class).withProperties(securityProps) .startLocator(); + System.err + .println("[DEBUG] Locator started (deprecated SSL) on port: " + locator.getHttpPort()); + System.err.println("[DEBUG] Locator JMX port: " + locator.getJmxPort()); + + // Wait for JMX/Management Service to be fully initialized before login attempts + // This prevents race conditions on slower CI machines where authentication may fail + // if the JMX backend is not ready yet + System.err.println("[DEBUG] Getting ManagementService instance..."); + ManagementService service = + ManagementService.getExistingManagementService(locator.getLocator().getCache()); + System.err.println("[DEBUG] ManagementService obtained: " + service); + System.err.println("[DEBUG] Waiting for MemberMXBean to be ready..."); + long mbeanWaitStart = System.currentTimeMillis(); + await() + .untilAsserted(() -> assertThat(service.getMemberMXBean()).isNotNull()); + long mbeanWaitEnd = System.currentTimeMillis(); + System.err.println("[DEBUG] MemberMXBean is ready after " + (mbeanWaitEnd - mbeanWaitStart) + + "ms: " + service.getMemberMXBean()); + System.err + .println("[DEBUG] MemberMXBean class: " + service.getMemberMXBean().getClass().getName()); + + // Additionally wait for Pulse web application to be fully responsive + System.err.println("[DEBUG] Waiting for Pulse web app to respond..."); + long webAppWaitStart = System.currentTimeMillis(); + await() + .untilAsserted(() -> { + ClassicHttpResponse loginPageResponse = client.get("/pulse/login.html"); + try { + assertThat(loginPageResponse.getCode()).isEqualTo(200); + } finally { + // Ensure entity is consumed to return connection to pool + if (loginPageResponse.getEntity() != null) { + try { + loginPageResponse.getEntity().getContent().close(); + } catch (Exception ignore) { + } + } + } + }); + long webAppWaitEnd = System.currentTimeMillis(); + System.err.println( + "[DEBUG] Pulse web app is responsive after " + (webAppWaitEnd - webAppWaitStart) + "ms"); - client.loginToPulseAndVerify("cluster", "cluster"); + // Wait for JMX authentication backend to be ready by polling login attempts + // The backend may timeout initially while JMX connections are being established + System.err.println("[DEBUG] ===== Starting JMX backend readiness check ====="); + System.err.println("[DEBUG] Waiting for JMX authentication backend to be ready..."); + System.err.println("[DEBUG] Max wait time: 5 minutes, poll interval: 50ms"); + long jmxBackendWaitStart = System.currentTimeMillis(); + final java.util.concurrent.atomic.AtomicInteger attemptCounter2 = + new java.util.concurrent.atomic.AtomicInteger(0); + await() + .untilAsserted(() -> { + int attempt = attemptCounter2.incrementAndGet(); + long attemptStartTime = System.currentTimeMillis(); + long elapsedSinceJmxStart = attemptStartTime - jmxBackendWaitStart; + System.err.println("[DEBUG] ========================================"); + System.err.println("[DEBUG] === Attempt #" + attempt + " ==="); + System.err.println("[DEBUG] Timestamp: " + java.time.Instant.now()); + System.err + .println("[DEBUG] Elapsed since JMX check start: " + elapsedSinceJmxStart + "ms"); + System.err + .println("[DEBUG] Attempting login with correct credentials (cluster/cluster)..."); + try { + long startTime = System.currentTimeMillis(); + client.loginToPulseAndVerify("cluster", "cluster"); + long duration = System.currentTimeMillis() - startTime; + System.err.println("[DEBUG] Login successful after " + duration + "ms!"); + long totalElapsed = System.currentTimeMillis() - jmxBackendWaitStart; + System.err.println("[DEBUG] Total JMX backend readiness time: " + totalElapsed + + "ms, total attempts: " + attempt); + } catch (Exception e) { + long duration = System.currentTimeMillis() - attemptStartTime; + System.err.println("[DEBUG] Login failed after " + duration + "ms: " + + e.getClass().getSimpleName() + ": " + e.getMessage()); + // Print root cause if different + Throwable cause = e.getCause(); + if (cause != null && cause != e) { + System.err.println("[DEBUG] Caused by: " + cause.getClass().getSimpleName() + ": " + + cause.getMessage()); + // Print second-level cause if present + Throwable secondLevelCause = cause.getCause(); + if (secondLevelCause != null && secondLevelCause != cause) { + System.err.println( + "[DEBUG] Caused by: " + secondLevelCause.getClass().getSimpleName() + ": " + + secondLevelCause.getMessage()); + } + } + System.err.println("[DEBUG] Will retry (attempt #" + attempt + ")..."); + throw new AssertionError("Login failed, will retry", e); + } + }); // Ensure that the backend JMX connection is working too ClassicHttpResponse response = client.post("/pulse/pulseUpdate", "pulseData", diff --git a/geode-pulse/src/main/java/org/apache/geode/tools/pulse/internal/data/JMXDataUpdater.java b/geode-pulse/src/main/java/org/apache/geode/tools/pulse/internal/data/JMXDataUpdater.java index c73daab61ea..d923f502c07 100644 --- a/geode-pulse/src/main/java/org/apache/geode/tools/pulse/internal/data/JMXDataUpdater.java +++ b/geode-pulse/src/main/java/org/apache/geode/tools/pulse/internal/data/JMXDataUpdater.java @@ -173,6 +173,11 @@ private JmxManagerInfo getManagerInfoFromLocator(Repository repository) { */ @Override public JMXConnector connect(Object credentials) { + long connectStartTime = System.currentTimeMillis(); + System.err.println("[JMX-CONNECT] Starting JMX connection at " + java.time.Instant.now()); + System.err.println("[JMX-CONNECT] Thread: " + Thread.currentThread().getName()); + System.err.println("[JMX-CONNECT] Credentials type: " + + (credentials != null ? credentials.getClass().getName() : "null")); try { String jmxSerURL = ""; @@ -220,16 +225,38 @@ public JMXConnector connect(Object credentials) { env.put("com.sun.jndi.rmi.factory.socket", new SslRMIClientSocketFactory()); } logger.info("Connecting to jmxURL : {}", jmxSerURL); + System.err + .println("[JMX-CONNECT] Attempting JMXConnectorFactory.connect() to: " + jmxSerURL); + System.err.println("[JMX-CONNECT] With SSL: " + repository.isUseSSLManager()); + long jmxCallStart = System.currentTimeMillis(); conn = JMXConnectorFactory.connect(url, env); + long jmxCallEnd = System.currentTimeMillis(); + System.err.println("[JMX-CONNECT] JMXConnectorFactory.connect() successful in " + + (jmxCallEnd - jmxCallStart) + "ms"); mbs = conn.getMBeanServerConnection(); cluster.setConnectedFlag(true); + long totalDuration = System.currentTimeMillis() - connectStartTime; + System.err.println("[JMX-CONNECT] Total connection time: " + totalDuration + "ms"); } finally { System.setProperties(originalProperties); } } } catch (Exception e) { + long totalDuration = System.currentTimeMillis() - connectStartTime; cluster.setConnectedFlag(false); cluster.setConnectionErrorMsg(e.getMessage()); + System.err.println("[JMX-CONNECT] Connection FAILED after " + totalDuration + "ms"); + System.err.println("[JMX-CONNECT] Exception type: " + e.getClass().getName()); + System.err.println("[JMX-CONNECT] Exception message: " + e.getMessage()); + if (e.getCause() != null) { + System.err.println("[JMX-CONNECT] Caused by: " + e.getCause().getClass().getName() + ": " + + e.getCause().getMessage()); + if (e.getCause().getCause() != null) { + System.err + .println("[JMX-CONNECT] Caused by: " + e.getCause().getCause().getClass().getName() + + ": " + e.getCause().getCause().getMessage()); + } + } logger.fatal(e.getMessage(), e); if (conn != null) { try { diff --git a/geode-pulse/src/main/java/org/apache/geode/tools/pulse/internal/security/GemFireAuthenticationProvider.java b/geode-pulse/src/main/java/org/apache/geode/tools/pulse/internal/security/GemFireAuthenticationProvider.java index f790c822b40..1457e7632fe 100644 --- a/geode-pulse/src/main/java/org/apache/geode/tools/pulse/internal/security/GemFireAuthenticationProvider.java +++ b/geode-pulse/src/main/java/org/apache/geode/tools/pulse/internal/security/GemFireAuthenticationProvider.java @@ -30,6 +30,7 @@ import org.springframework.security.core.GrantedAuthority; import org.springframework.stereotype.Component; +import org.apache.geode.tools.pulse.internal.data.Cluster; import org.apache.geode.tools.pulse.internal.data.Repository; /** @@ -63,11 +64,24 @@ public Authentication authenticate(Authentication authentication) throws Authent String password = authentication.getCredentials().toString(); logger.debug("Connecting to GemFire with user=" + name); - JMXConnector jmxc = - repository.getClusterWithUserNameAndPassword(name, password).getJMXConnector(); + System.err.println( + "[PULSE-AUTH] Authentication request for user: " + name + " at " + java.time.Instant.now()); + long authStartTime = System.currentTimeMillis(); + Cluster cluster = repository.getClusterWithUserNameAndPassword(name, password); + long authEndTime = System.currentTimeMillis(); + System.err.println("[PULSE-AUTH] getClusterWithUserNameAndPassword returned in " + + (authEndTime - authStartTime) + "ms"); + System.err.println( + "[PULSE-AUTH] Cluster connected flag: " + (cluster != null && cluster.isConnectedFlag())); + System.err.println("[PULSE-AUTH] Cluster connection error: " + + (cluster != null ? cluster.getConnectionErrorMsg() : "null")); + JMXConnector jmxc = cluster != null ? cluster.getJMXConnector() : null; if (jmxc == null) { + System.err.println("[PULSE-AUTH] JMXConnector is NULL - authentication FAILED for " + name); throw new BadCredentialsException("Error connecting to GemFire JMX Server"); } + System.err + .println("[PULSE-AUTH] JMXConnector obtained - authentication SUCCESSFUL for " + name); Collection list = GemFireAuthentication.populateAuthorities(jmxc); GemFireAuthentication auth = new GemFireAuthentication(authentication.getPrincipal(),