diff --git a/agent/src/com/cloud/agent/resource/consoleproxy/ConsoleProxyResource.java b/agent/src/com/cloud/agent/resource/consoleproxy/ConsoleProxyResource.java index f350fc8c9ad..94a99400667 100644 --- a/agent/src/com/cloud/agent/resource/consoleproxy/ConsoleProxyResource.java +++ b/agent/src/com/cloud/agent/resource/consoleproxy/ConsoleProxyResource.java @@ -314,8 +314,8 @@ public class ConsoleProxyResource extends ServerResourceBase implements ServerRe _consoleProxyMain.start(); } - public boolean authenticateConsoleAccess(String vmId, String sid) { - ConsoleAccessAuthenticationCommand cmd = new ConsoleAccessAuthenticationCommand(vmId, sid); + public boolean authenticateConsoleAccess(String host, String port, String vmId, String sid, String ticket) { + ConsoleAccessAuthenticationCommand cmd = new ConsoleAccessAuthenticationCommand(host, port, vmId, sid, ticket); try { AgentControlAnswer answer = getAgentControl().sendRequest(cmd, 10000); diff --git a/console-proxy/src/com/cloud/consoleproxy/ConsoleProxy.java b/console-proxy/src/com/cloud/consoleproxy/ConsoleProxy.java index a1a1b35e915..81af054c487 100644 --- a/console-proxy/src/com/cloud/consoleproxy/ConsoleProxy.java +++ b/console-proxy/src/com/cloud/consoleproxy/ConsoleProxy.java @@ -180,14 +180,14 @@ public class ConsoleProxy { } } - public static boolean authenticateConsoleAccess(String vmId, String sid) { + public static boolean authenticateConsoleAccess(String host, String port, String vmId, String sid, String ticket) { if(standaloneStart) return true; if(authMethod != null) { Object result; try { - result = authMethod.invoke(ConsoleProxy.context, vmId, sid); + result = authMethod.invoke(ConsoleProxy.context, host, port, vmId, sid, ticket); } catch (IllegalAccessException e) { s_logger.error("Unable to invoke authenticateConsoleAccess due to IllegalAccessException" + " for vm: " + vmId, e); return false; @@ -252,7 +252,7 @@ public class ConsoleProxy { ConsoleProxy.context = context; try { Class> contextClazz = Class.forName("com.cloud.agent.resource.consoleproxy.ConsoleProxyResource"); - authMethod = contextClazz.getDeclaredMethod("authenticateConsoleAccess", String.class, String.class); + authMethod = contextClazz.getDeclaredMethod("authenticateConsoleAccess", String.class, String.class, String.class, String.class, String.class); reportMethod = contextClazz.getDeclaredMethod("reportLoadInfo", String.class); ensureRouteMethod = contextClazz.getDeclaredMethod("ensureRoute", String.class); } catch (SecurityException e) { @@ -419,8 +419,8 @@ public class ConsoleProxy { return viewer; } - static void initViewer(ConsoleProxyViewer viewer, String host, int port, String tag, String sid) throws AuthenticationException { - ConsoleProxyViewer.authenticationExternally(tag, sid); + static void initViewer(ConsoleProxyViewer viewer, String host, int port, String tag, String sid, String ticket) throws AuthenticationException { + ConsoleProxyViewer.authenticationExternally(host, String.valueOf(port), tag, sid, ticket); viewer.host = host; viewer.port = port; @@ -430,7 +430,7 @@ public class ConsoleProxy { viewer.init(); } - static ConsoleProxyViewer getVncViewer(String host, int port, String sid, String tag) throws Exception { + static ConsoleProxyViewer getVncViewer(String host, int port, String sid, String tag, String ticket) throws Exception { ConsoleProxyViewer viewer = null; boolean reportLoadChange = false; @@ -438,7 +438,7 @@ public class ConsoleProxy { viewer = connectionMap.get(host + ":" + port); if (viewer == null) { viewer = createViewer(); - initViewer(viewer, host, port, tag, sid); + initViewer(viewer, host, port, tag, sid, ticket); connectionMap.put(host + ":" + port, viewer); s_logger.info("Added viewer object " + viewer); @@ -446,12 +446,12 @@ public class ConsoleProxy { } else if (!viewer.rfbThread.isAlive()) { s_logger.info("The rfb thread died, reinitializing the viewer " + viewer); - initViewer(viewer, host, port, tag, sid); + initViewer(viewer, host, port, tag, sid, ticket); reportLoadChange = true; } else if (!sid.equals(viewer.passwordParam)) { s_logger.warn("Bad sid detected(VNC port may be reused). sid in session: " + viewer.passwordParam + ", sid in request: " + sid); - initViewer(viewer, host, port, tag, sid); + initViewer(viewer, host, port, tag, sid, ticket); reportLoadChange = true; @@ -484,7 +484,7 @@ public class ConsoleProxy { return viewer; } - static ConsoleProxyViewer getAjaxVncViewer(String host, int port, String sid, String tag) throws Exception { + static ConsoleProxyViewer getAjaxVncViewer(String host, int port, String sid, String tag, String ticket, String ajaxSession) throws Exception { boolean reportLoadChange = false; synchronized (connectionMap) { ConsoleProxyViewer viewer = connectionMap.get(host + ":" + port); @@ -494,25 +494,29 @@ public class ConsoleProxy { viewer = createViewer(); viewer.ajaxViewer = true; - initViewer(viewer, host, port, tag, sid); + initViewer(viewer, host, port, tag, sid, ticket); connectionMap.put(host + ":" + port, viewer); s_logger.info("Added viewer object " + viewer); reportLoadChange = true; } else if (!viewer.rfbThread.isAlive()) { s_logger.info("The rfb thread died, reinitializing the viewer " + viewer); - initViewer(viewer, host, port, tag, sid); + initViewer(viewer, host, port, tag, sid, ticket); reportLoadChange = true; } else if (!sid.equals(viewer.passwordParam)) { s_logger.warn("Bad sid detected(VNC port may be reused). sid in session: " + viewer.passwordParam + ", sid in request: " + sid); - initViewer(viewer, host, port, tag, sid); + initViewer(viewer, host, port, tag, sid, ticket); reportLoadChange = true; /* throw new AuthenticationException ("Cannot use the existing viewer " + viewer + ": bad sid"); */ + } else { + if(ajaxSession == null || ajaxSession.isEmpty()) + ConsoleProxyViewer.authenticationExternally(host, String.valueOf(port), tag, sid, ticket); } + if (viewer.status == ConsoleProxyViewer.STATUS_NORMAL_OPERATION) { // Do not update lastUsedTime if the viewer is in the process of starting up // or if it failed to authenticate. diff --git a/console-proxy/src/com/cloud/consoleproxy/ConsoleProxyAjaxHandler.java b/console-proxy/src/com/cloud/consoleproxy/ConsoleProxyAjaxHandler.java index 0324988c64b..22f8294fbec 100644 --- a/console-proxy/src/com/cloud/consoleproxy/ConsoleProxyAjaxHandler.java +++ b/console-proxy/src/com/cloud/consoleproxy/ConsoleProxyAjaxHandler.java @@ -72,7 +72,8 @@ public class ConsoleProxyAjaxHandler implements HttpHandler { String host = queryMap.get("host"); String portStr = queryMap.get("port"); String sid = queryMap.get("sid"); - String tag = queryMap.get("tag"); + String tag = queryMap.get("tag"); + String ticket = queryMap.get("ticket"); String ajaxSessionIdStr = queryMap.get("sess"); String eventStr = queryMap.get("event"); if(tag == null) @@ -113,7 +114,7 @@ public class ConsoleProxyAjaxHandler implements HttpHandler { ConsoleProxyViewer viewer = null; try { - viewer = ConsoleProxy.getAjaxVncViewer(host, port, sid, tag); + viewer = ConsoleProxy.getAjaxVncViewer(host, port, sid, tag, ticket, ajaxSessionIdStr); } catch(Exception e) { /* diff --git a/console-proxy/src/com/cloud/consoleproxy/ConsoleProxyAjaxImageHandler.java b/console-proxy/src/com/cloud/consoleproxy/ConsoleProxyAjaxImageHandler.java index 66cba4129b4..66632f93cea 100644 --- a/console-proxy/src/com/cloud/consoleproxy/ConsoleProxyAjaxImageHandler.java +++ b/console-proxy/src/com/cloud/consoleproxy/ConsoleProxyAjaxImageHandler.java @@ -62,7 +62,8 @@ public class ConsoleProxyAjaxImageHandler implements HttpHandler { String host = queryMap.get("host"); String portStr = queryMap.get("port"); String sid = queryMap.get("sid"); - String tag = queryMap.get("tag"); + String tag = queryMap.get("tag"); + String ticket = queryMap.get("ticket"); String keyStr = queryMap.get("key"); int key = 0; @@ -87,7 +88,7 @@ public class ConsoleProxyAjaxImageHandler implements HttpHandler { throw new IllegalArgumentException(e); } - ConsoleProxyViewer viewer = ConsoleProxy.getVncViewer(host, port, sid, tag); + ConsoleProxyViewer viewer = ConsoleProxy.getVncViewer(host, port, sid, tag, ticket); byte[] img = viewer.getAjaxImageCache().getImage(key); if(img != null) { Headers hds = t.getResponseHeaders(); diff --git a/console-proxy/src/com/cloud/consoleproxy/ConsoleProxyClientHandler.java b/console-proxy/src/com/cloud/consoleproxy/ConsoleProxyClientHandler.java index 4c9be4cd02d..23543a706c4 100644 --- a/console-proxy/src/com/cloud/consoleproxy/ConsoleProxyClientHandler.java +++ b/console-proxy/src/com/cloud/consoleproxy/ConsoleProxyClientHandler.java @@ -88,7 +88,7 @@ public class ConsoleProxyClientHandler extends Thread { String host = stk.nextToken(); int port = Integer.parseInt(stk.nextToken()); String sid = stk.nextToken(); - ConsoleProxyViewer viewer = ConsoleProxy.getVncViewer(host, port, sid, ""); + ConsoleProxyViewer viewer = ConsoleProxy.getVncViewer(host, port, sid, "", ""); ConsoleProxy.waitForViewerToStart(viewer); diff --git a/console-proxy/src/com/cloud/consoleproxy/ConsoleProxyThumbnailHandler.java b/console-proxy/src/com/cloud/consoleproxy/ConsoleProxyThumbnailHandler.java index 140ede10581..0773c263d9c 100644 --- a/console-proxy/src/com/cloud/consoleproxy/ConsoleProxyThumbnailHandler.java +++ b/console-proxy/src/com/cloud/consoleproxy/ConsoleProxyThumbnailHandler.java @@ -135,7 +135,8 @@ public class ConsoleProxyThumbnailHandler implements HttpHandler { String host = queryMap.get("host"); String portStr = queryMap.get("port"); String sid = queryMap.get("sid"); - String tag = queryMap.get("tag"); + String tag = queryMap.get("tag"); + String ticket = queryMap.get("ticket"); if(tag == null) tag = ""; @@ -150,7 +151,7 @@ public class ConsoleProxyThumbnailHandler implements HttpHandler { throw new IllegalArgumentException(e); } - ConsoleProxyViewer viewer = ConsoleProxy.getVncViewer(host, port, sid, tag); + ConsoleProxyViewer viewer = ConsoleProxy.getVncViewer(host, port, sid, tag, ticket); if (viewer.status != ConsoleProxyViewer.STATUS_NORMAL_OPERATION) { // use generated image instead of static diff --git a/console-proxy/src/com/cloud/consoleproxy/ConsoleProxyViewer.java b/console-proxy/src/com/cloud/consoleproxy/ConsoleProxyViewer.java index 754d8f6727e..98453acf134 100644 --- a/console-proxy/src/com/cloud/consoleproxy/ConsoleProxyViewer.java +++ b/console-proxy/src/com/cloud/consoleproxy/ConsoleProxyViewer.java @@ -315,7 +315,7 @@ public class ConsoleProxyViewer implements java.lang.Runnable, RfbViewer, RfbPro } } - static void authenticationExternally(String tag, String sid) throws AuthenticationException { + static void authenticationExternally(String host, String port, String tag, String sid, String ticket) throws AuthenticationException { /* if(ConsoleProxy.management_host != null) { try { @@ -352,7 +352,7 @@ public class ConsoleProxyViewer implements java.lang.Runnable, RfbViewer, RfbPro s_logger.warn("No external authentication source being setup."); } */ - if(!ConsoleProxy.authenticateConsoleAccess(tag, sid)) { + if(!ConsoleProxy.authenticateConsoleAccess(host, port, tag, sid, ticket)) { s_logger.warn("External authenticator failed authencation request for vm " + tag + " with sid " + sid); throw new AuthenticationException("External authenticator failed request for vm " + tag + " with sid " + sid); diff --git a/core/src/com/cloud/agent/api/ConsoleAccessAuthenticationCommand.java b/core/src/com/cloud/agent/api/ConsoleAccessAuthenticationCommand.java index f1c25c5bd2f..2db7dec8073 100644 --- a/core/src/com/cloud/agent/api/ConsoleAccessAuthenticationCommand.java +++ b/core/src/com/cloud/agent/api/ConsoleAccessAuthenticationCommand.java @@ -19,17 +19,31 @@ package com.cloud.agent.api; public class ConsoleAccessAuthenticationCommand extends AgentControlCommand { - + + private String _host; + private String _port; private String _vmId; - private String _sid; + private String _sid; + private String _ticket; public ConsoleAccessAuthenticationCommand() { } - public ConsoleAccessAuthenticationCommand(String vmId, String sid) { + public ConsoleAccessAuthenticationCommand(String host, String port, String vmId, String sid, String ticket) { + _host = host; + _port = port; _vmId = vmId; - _sid = sid; + _sid = sid; + _ticket = ticket; } + + public String getHost() { + return _host; + } + + public String getPort() { + return _port; + } public String getVmId() { return _vmId; @@ -37,5 +51,9 @@ public class ConsoleAccessAuthenticationCommand extends AgentControlCommand { public String getSid() { return _sid; + } + + public String getTicket() { + return _ticket; } } diff --git a/core/src/com/cloud/agent/api/storage/AbstractDownloadCommand.java b/core/src/com/cloud/agent/api/storage/AbstractDownloadCommand.java index e9a038f7cd6..135dc80a33d 100644 --- a/core/src/com/cloud/agent/api/storage/AbstractDownloadCommand.java +++ b/core/src/com/cloud/agent/api/storage/AbstractDownloadCommand.java @@ -30,6 +30,9 @@ public abstract class AbstractDownloadCommand extends StorageCommand { } protected AbstractDownloadCommand(String name, String url, ImageFormat format, long accountId) { + assert(url != null); + url = url.replace('\\', '/'); + this.url = url; this.format = format; this.accountId = accountId; @@ -62,6 +65,8 @@ public abstract class AbstractDownloadCommand extends StorageCommand { } public void setUrl(String url) { + assert(url != null); + url = url.replace('\\', '/'); this.url = url; } diff --git a/server/src/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java b/server/src/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java index 34eb107ecb1..9f3404fd687 100644 --- a/server/src/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java +++ b/server/src/com/cloud/consoleproxy/ConsoleProxyManagerImpl.java @@ -107,6 +107,7 @@ import com.cloud.offerings.NetworkOfferingVO; import com.cloud.offerings.dao.NetworkOfferingDao; import com.cloud.service.ServiceOfferingVO; import com.cloud.service.dao.ServiceOfferingDao; +import com.cloud.servlet.ConsoleProxyServlet; import com.cloud.storage.GuestOSVO; import com.cloud.storage.StorageManager; import com.cloud.storage.StoragePoolVO; @@ -1268,6 +1269,13 @@ public class ConsoleProxyManagerImpl implements ConsoleProxyManager, VirtualMach @Override public AgentControlAnswer onConsoleAccessAuthentication(ConsoleAccessAuthenticationCommand cmd) { long vmId = 0; + + String ticket = ConsoleProxyServlet.genAccessTicket(cmd.getHost(), cmd.getPort(), cmd.getSid(), cmd.getVmId()); + String ticketInUrl = cmd.getTicket(); + if(!ticket.startsWith(ticketInUrl)) { + s_logger.error("Access ticket expired or has been modified. vmId: " + cmd.getVmId()); + return new ConsoleAccessAuthenticationAnswer(cmd, false); + } if (cmd.getVmId() != null && cmd.getVmId().isEmpty()) { if (s_logger.isTraceEnabled()) diff --git a/server/src/com/cloud/servlet/ConsoleProxyServlet.java b/server/src/com/cloud/servlet/ConsoleProxyServlet.java index 2c364122854..b3b403f2eff 100644 --- a/server/src/com/cloud/servlet/ConsoleProxyServlet.java +++ b/server/src/com/cloud/servlet/ConsoleProxyServlet.java @@ -20,8 +20,10 @@ package com.cloud.servlet; import java.io.IOException; import java.net.URLEncoder; +import java.security.InvalidKeyException; import java.util.ArrayList; import java.util.Collections; +import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -214,73 +216,112 @@ public class ConsoleProxyServlet extends HttpServlet { String vmName = vm.getName(); if(vmName == null) vmName = vm.getInstanceName(); - - StringBuffer sb = new StringBuffer(); - sb.append("