Copilot commented on code in PR #13058:
URL: https://github.com/apache/cloudstack/pull/13058#discussion_r3153177256


##########
services/console-proxy/server/src/main/java/com/cloud/consoleproxy/ConsoleProxy.java:
##########
@@ -233,20 +234,21 @@ public static ConsoleProxyAuthenticationResult 
authenticateConsoleAccess(Console
             Object result;
             try {
                 result =
-                        authMethod.invoke(ConsoleProxy.context, 
param.getClientHostAddress(), String.valueOf(param.getClientHostPort()), 
param.getClientTag(),
-                                param.getClientHostPassword(), 
param.getTicket(), reauthentication, param.getSessionUuid());
+                        authMethod.invoke(ConsoleProxy.context, 
param.getClientHostAddress(), String.valueOf(param.getClientHostPort()),
+                                param.getClientTag(), 
param.getClientHostPassword(), param.getTicket(), reauthentication,
+                                param.getSessionUuid(), param.getClientIp());
             } catch (IllegalAccessException e) {

Review Comment:
   authenticateConsoleAccess(...) now invokes authMethod with an extra 
param.getClientIp() argument. On 4.20, 
ConsoleProxyResource.authenticateConsoleAccess(...) only accepts 7 arguments, 
so this call will fail if/when authMethod is resolved. Keep the invocation 
arguments consistent with the reflected method signature (or implement a 
dual-signature invocation path).



##########
services/console-proxy/server/src/main/java/com/cloud/consoleproxy/ConsoleProxy.java:
##########
@@ -308,7 +311,7 @@ public static void startWithContext(Properties conf, Object 
context, byte[] ksBi
             final ClassLoader loader = 
Thread.currentThread().getContextClassLoader();
             Class<?> contextClazz = 
loader.loadClass("com.cloud.agent.resource.consoleproxy.ConsoleProxyResource");
             authMethod = 
contextClazz.getDeclaredMethod("authenticateConsoleAccess", String.class, 
String.class,
-                    String.class, String.class, String.class, Boolean.class, 
String.class);
+                    String.class, String.class, String.class, Boolean.class, 
String.class, String.class);

Review Comment:
   The reflective lookup of ConsoleProxyResource.authenticateConsoleAccess(...) 
now expects an extra String parameter, but in this branch ConsoleProxyResource 
defines authenticateConsoleAccess(host, port, vmId, sid, ticket, 
isReauthentication, sessionToken) with 7 params. This will trigger 
NoSuchMethodException at startup, leaving authMethod unset and causing 
authenticateConsoleAccess(...) to fall back to "offline mode" (success=true) 
which effectively bypasses management-server authentication. Align the 
getDeclaredMethod(...) signature (and corresponding invoke call) with the 
actual ConsoleProxyResource method in 4.20, or add a backwards-compatible 
lookup that tries both signatures.
   ```suggestion
                       String.class, String.class, String.class, Boolean.class, 
String.class);
   ```



##########
services/console-proxy/server/src/main/java/com/cloud/consoleproxy/ConsoleProxy.java:
##########
@@ -596,50 +611,55 @@ public void execute(Runnable r) {
     }
 
     public static ConsoleProxyNoVncClient 
getNoVncViewer(ConsoleProxyClientParam param, String ajaxSession,
-            Session session) throws AuthenticationException {
+                                                         Session session) 
throws AuthenticationException {
         boolean reportLoadChange = false;
         String clientKey = param.getClientMapKey();
-        synchronized (connectionMap) {
-            ConsoleProxyClient viewer = connectionMap.get(clientKey);
-            if (viewer == null || viewer.getClass() != 
ConsoleProxyNoVncClient.class) {
-                authenticationExternally(param);
-                viewer = new ConsoleProxyNoVncClient(session);
-                viewer.initClient(param);
+        LOGGER.debug("Getting NoVNC viewer for {}. Client tag: {}. session 
UUID: {}",
+        clientKey, param.getClientTag(), param.getSessionUuid());
+synchronized (connectionMap) {
+    ConsoleProxyClient viewer = connectionMap.get(clientKey);
+    if (viewer == null || viewer.getClass() != ConsoleProxyNoVncClient.class) {
+        authenticationExternally(param);
+        viewer = new ConsoleProxyNoVncClient(session);
+        viewer.initClient(param);
+
+        connectionMap.put(clientKey, viewer);
+        reportLoadChange = true;
+    } else {
+        if (param.getClientHostPassword() == null || 
param.getClientHostPassword().isEmpty()
+                || 
!param.getClientHostPassword().equals(viewer.getClientHostPassword())) {
+            throw new AuthenticationException("Cannot use the existing viewer 
" + viewer + ": bad sid");
+        }
 
-                connectionMap.put(clientKey, viewer);
-                reportLoadChange = true;
-            } else {
-                if (param.getClientHostPassword() == null || 
param.getClientHostPassword().isEmpty() ||
-                        
!param.getClientHostPassword().equals(viewer.getClientHostPassword()))
-                    throw new AuthenticationException("Cannot use the existing 
viewer " + viewer + ": bad sid");
+        try {
+            authenticationExternally(param);
+        } catch (Exception e) {
+            LOGGER.error("Authentication failed for param: " + param);

Review Comment:
   In getNoVncViewer(...), the AuthenticationException path logs 
"Authentication failed" without including the caught exception, which loses the 
stack trace/context needed to debug auth failures. Log the exception (and 
preferably include key identifiers like sessionUuid/clientKey) when catching 
the failure.
   ```suggestion
               LOGGER.error("Authentication failed for sessionUuid={}, 
clientKey={}, param={}",
                       param.getSessionUuid(), clientKey, param, e);
   ```



##########
services/console-proxy/server/src/main/java/com/cloud/consoleproxy/ConsoleProxyNoVNCHandler.java:
##########
@@ -93,15 +94,16 @@ public void onConnect(final Session session) throws 
IOException, InterruptedExce
         String websocketUrl = queryMap.get("websocketUrl");
         String sessionUuid = queryMap.get("sessionUuid");
         String clientIp = 
session.getRemoteAddress().getAddress().getHostAddress();
+        boolean sessionRequiresNewViewer = 
Boolean.parseBoolean(queryMap.get("sessionRequiresNewViewer"));

Review Comment:
   sessionRequiresNewViewer is parsed from the query string but never used. If 
this branch intentionally does not support that behavior (per the PR 
description), remove this local variable (and possibly the query param 
handling) to avoid confusion and dead code.
   ```suggestion
   
   ```



##########
services/console-proxy/server/src/main/java/com/cloud/consoleproxy/ConsoleProxyGCThread.java:
##########
@@ -32,9 +32,13 @@
  * management software
  */
 public class ConsoleProxyGCThread extends Thread {
-    protected Logger logger = LogManager.getLogger(ConsoleProxyGCThread.class);
+    private static final Logger logger = 
LogManager.getLogger(ConsoleProxyGCThread.class);
 
-    private final static int MAX_SESSION_IDLE_SECONDS = 180;
+    /**
+     * Maximum time (in seconds) a console session is allowed to be idle 
before it is closed.
+     * This value should be kept in sync with 
ConsoleProxy.VIEWER_LINGER_SECONDS.
+     */
+    private static final int MAX_SESSION_IDLE_SECONDS = 180;

Review Comment:
   MAX_SESSION_IDLE_SECONDS is still hard-coded to 180s, which does not match 
the documented/expected behavior of honoring the global 
consoleproxy.session.timeout (default 300000ms) and is also duplicating 
ConsoleProxy.VIEWER_LINGER_SECONDS. To honor the setting and avoid drift, 
derive the idle timeout from the configured consoleproxy.session.timeout and 
use a single shared value for both GC and viewer liveness checks.
   ```suggestion
        * Reuse the shared viewer linger timeout so GC honors the configured
        * consoleproxy.session.timeout and does not drift from viewer liveness 
checks.
        */
       private static final int MAX_SESSION_IDLE_SECONDS = 
ConsoleProxy.VIEWER_LINGER_SECONDS;
   ```



##########
services/console-proxy/server/src/main/java/com/cloud/consoleproxy/ConsoleProxyNoVNCHandler.java:
##########
@@ -183,12 +186,20 @@ public void onClose(Session session, int statusCode, 
String reason) throws IOExc
 
     @OnWebSocketFrame
     public void onFrame(Frame f) throws IOException {
+        if (viewer == null) {
+            logger.debug("Ignoring WebSocket frame because viewer is not 
initialized yet.");
+            return;
+        }

Review Comment:
   NoVNC session idle tracking relies on getClientLastFrontEndActivityTime(), 
but this handler does not update the viewer's front-end activity timestamp when 
frames arrive from the browser. As a result, GC/linger logic may not reflect 
actual browser activity and can prevent consoleproxy.session.timeout from being 
enforced. Update the viewer's front-end activity time on each received 
WebSocket frame (and ensure the timestamp isn't continuously refreshed by 
backend reads alone).
   ```suggestion
           }
           viewer.setClientLastFrontEndActivityTime(System.currentTimeMillis());
   ```



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to