QuickCloud: copy authorization code from ConsoleProxyManagerImpl
Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/e2fdd720 Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/e2fdd720 Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/e2fdd720 Branch: refs/heads/quickcloud Commit: e2fdd720c0a75f0c7a9f1c6a491bebc41cb87ba9 Parents: 5391852 Author: Chiradeep Vittal <chirad...@apache.org> Authored: Tue Mar 26 10:05:06 2013 -0700 Committer: Chiradeep Vittal <chirad...@apache.org> Committed: Tue Mar 26 10:05:06 2013 -0700 ---------------------------------------------------------------------- .../consoleproxy/StaticConsoleProxyManager.java | 268 ++++++++++++++- 1 files changed, 257 insertions(+), 11 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cloudstack/blob/e2fdd720/server/src/com/cloud/consoleproxy/StaticConsoleProxyManager.java ---------------------------------------------------------------------- diff --git a/server/src/com/cloud/consoleproxy/StaticConsoleProxyManager.java b/server/src/com/cloud/consoleproxy/StaticConsoleProxyManager.java index 3ba98a9..04e6f24 100755 --- a/server/src/com/cloud/consoleproxy/StaticConsoleProxyManager.java +++ b/server/src/com/cloud/consoleproxy/StaticConsoleProxyManager.java @@ -16,29 +16,74 @@ // under the License. package com.cloud.consoleproxy; + +import java.util.Date; import java.util.List; import java.util.Map; +import java.util.Random; +import java.util.UUID; import javax.ejb.Local; import javax.inject.Inject; import javax.naming.ConfigurationException; -import org.springframework.stereotype.Component; +import org.apache.log4j.Logger; +import com.cloud.agent.api.AgentControlAnswer; +import com.cloud.agent.api.Answer; +import com.cloud.agent.api.ConsoleAccessAuthenticationAnswer; +import com.cloud.agent.api.ConsoleAccessAuthenticationCommand; +import com.cloud.agent.api.GetVncPortAnswer; +import com.cloud.agent.api.GetVncPortCommand; +import com.cloud.agent.api.StartupCommand; +import com.cloud.agent.api.StartupProxyCommand; +import com.cloud.agent.api.proxy.StartConsoleProxyAgentHttpHandlerCommand; +import com.cloud.configuration.Config; import com.cloud.configuration.dao.ConfigurationDao; +import com.cloud.exception.AgentUnavailableException; +import com.cloud.exception.OperationTimedoutException; import com.cloud.host.Host.Type; import com.cloud.host.HostVO; +import com.cloud.host.dao.HostDao; import com.cloud.info.ConsoleProxyInfo; +import com.cloud.keystore.KeystoreDao; +import com.cloud.keystore.KeystoreManager; import com.cloud.resource.ResourceManager; +import com.cloud.resource.ResourceStateAdapter; +import com.cloud.resource.ServerResource; +import com.cloud.resource.UnableDeleteHostException; +import com.cloud.servlet.ConsoleProxyServlet; +import com.cloud.utils.NumbersUtil; +import com.cloud.utils.Ternary; import com.cloud.vm.VMInstanceVO; +import com.cloud.vm.VirtualMachine; import com.cloud.vm.dao.ConsoleProxyDao; +import com.cloud.vm.dao.VMInstanceDao; @Local(value={ConsoleProxyManager.class}) -public class StaticConsoleProxyManager extends AgentBasedConsoleProxyManager implements ConsoleProxyManager { - String _ip = null; - @Inject ConsoleProxyDao _proxyDao; - @Inject ResourceManager _resourceMgr; - @Inject ConfigurationDao _configDao; +public class StaticConsoleProxyManager extends AgentBasedConsoleProxyManager implements ConsoleProxyManager, + ResourceStateAdapter { + private static final Logger s_logger = Logger.getLogger(StaticConsoleProxyManager.class); + + @Inject + ConsoleProxyDao _proxyDao; + @Inject + ResourceManager _resourceMgr; + @Inject + ConfigurationDao _configDao; + @Inject + private VMInstanceDao _instanceDao; + @Inject + KeystoreDao _ksDao; + @Inject + private KeystoreManager _ksMgr; + @Inject + private HostDao _hostDao; + private final Random _random = new Random(System.currentTimeMillis()); + private String _hashKey; + private String _ip = null; + + @Override protected HostVO findHost(VMInstanceVO vm) { @@ -50,20 +95,221 @@ public class StaticConsoleProxyManager extends AgentBasedConsoleProxyManager imp @Override public ConsoleProxyInfo assignProxy(long dataCenterId, long userVmId) { - return new ConsoleProxyInfo(false, _ip, _consoleProxyPort, _consoleProxyUrlPort, _consoleProxyUrlDomain); + return new ConsoleProxyInfo(_sslEnabled, _ip, _consoleProxyPort, _consoleProxyUrlPort, _consoleProxyUrlDomain); } @Override public boolean configure(String name, Map<String, Object> params) throws ConfigurationException { super.configure(name, params); - - Map<String, String> dbParams = _configDao.getConfiguration("ManagementServer", params); - - _ip = dbParams.get("public.ip"); + _ip = _configDao.getValue("consoleproxy.static.publicIp"); if (_ip == null) { _ip = "127.0.0.1"; } + + String value = (String) params.get("consoleproxy.sslEnabled"); + if (value != null && value.equalsIgnoreCase("true")) { + _sslEnabled = true; + } + int defaultPort = 8088; + if (_sslEnabled) + defaultPort = 8443; + _consoleProxyUrlPort = NumbersUtil.parseInt(_configDao.getValue("consoleproxy.static.port"), defaultPort); + + _resourceMgr.registerResourceStateAdapter(this.getClass().getSimpleName(), this); + return true; } + + @Override + public HostVO createHostVOForConnectedAgent(HostVO host, StartupCommand[] cmd) { + if (!(cmd[0] instanceof StartupProxyCommand)) { + return null; + } + + host.setType(com.cloud.host.Host.Type.ConsoleProxy); + return host; + } + + @Override + public HostVO createHostVOForDirectConnectAgent(HostVO host, StartupCommand[] startup, ServerResource resource, + Map<String, String> details, List<String> hostTags) { + return null; + } + + @Override + public DeleteHostAnswer deleteHost(HostVO host, boolean isForced, boolean isForceDeleteStorage) + throws UnableDeleteHostException { + return null; + } + + @Override + public void startAgentHttpHandlerInVM(StartupProxyCommand startupCmd) { + StartConsoleProxyAgentHttpHandlerCommand cmd = null; + if (_configDao.isPremium()) { + String storePassword = String.valueOf(_random.nextLong()); + byte[] ksBits = + _ksMgr.getKeystoreBits(ConsoleProxyManager.CERTIFICATE_NAME, ConsoleProxyManager.CERTIFICATE_NAME, + storePassword); + + assert (ksBits != null); + if (ksBits == null) { + s_logger.error("Could not find and construct a valid SSL certificate"); + } + cmd = new StartConsoleProxyAgentHttpHandlerCommand(ksBits, storePassword); + cmd.setEncryptorPassword(getHashKey()); + } else { + cmd = new StartConsoleProxyAgentHttpHandlerCommand(); + cmd.setEncryptorPassword(getHashKey()); + } + HostVO consoleProxyHost = findConsoleProxyHost(startupCmd.getGuid()); + + Answer answer; + try { + answer = _agentMgr.send(consoleProxyHost.getId(), cmd); + if (answer == null || !answer.getResult()) { + s_logger.error("Console proxy agent reported that it failed to execute http handling startup command"); + } else { + s_logger.info("Successfully sent out command to start HTTP handling in console proxy agent"); + } + } catch (AgentUnavailableException e) { + s_logger.error("Failed to send http start up command to console proxy due to ", e); + } catch (OperationTimedoutException e) { + s_logger.error("Failed to send http start up command to console proxy due to ", e); + } + + + } + + private HostVO findConsoleProxyHost(String guid) { + return _hostDao.findByGuid(guid); + } + + public String getHashKey() { + // although we may have race conditioning here, database transaction + // serialization should + // give us the same key + if (_hashKey == null) { + _hashKey = + _configDao.getValueAndInitIfNotExist(Config.HashKey.key(), Config.HashKey.getCategory(), UUID + .randomUUID().toString()); + } + return _hashKey; + } + + public AgentControlAnswer onConsoleAccessAuthentication(ConsoleAccessAuthenticationCommand cmd) { + Long vmId = null; + + String ticketInUrl = cmd.getTicket(); + if (ticketInUrl == null) { + s_logger.error("Access ticket could not be found, you could be running an old version of console proxy. vmId: " + + cmd.getVmId()); + return new ConsoleAccessAuthenticationAnswer(cmd, false); + } + + if (s_logger.isDebugEnabled()) { + s_logger.debug("Console authentication. Ticket in url for " + cmd.getHost() + ":" + cmd.getPort() + "-" + + cmd.getVmId() + " is " + ticketInUrl); + } + + if (!cmd.isReauthenticating()) { + String ticket = + ConsoleProxyServlet.genAccessTicket(cmd.getHost(), cmd.getPort(), cmd.getSid(), cmd.getVmId()); + if (s_logger.isDebugEnabled()) { + s_logger.debug("Console authentication. Ticket in 1 minute boundary for " + cmd.getHost() + ":" + + cmd.getPort() + "-" + cmd.getVmId() + " is " + ticket); + } + + if (!ticket.equals(ticketInUrl)) { + Date now = new Date(); + // considering of minute round-up + String minuteEarlyTicket = + ConsoleProxyServlet.genAccessTicket(cmd.getHost(), cmd.getPort(), cmd.getSid(), cmd.getVmId(), + new Date(now.getTime() - 60 * 1000)); + + if (s_logger.isDebugEnabled()) { + s_logger.debug("Console authentication. Ticket in 2-minute boundary for " + cmd.getHost() + ":" + + cmd.getPort() + "-" + cmd.getVmId() + " is " + minuteEarlyTicket); + } + + if (!minuteEarlyTicket.equals(ticketInUrl)) { + s_logger.error("Access ticket expired or has been modified. vmId: " + cmd.getVmId() + + "ticket in URL: " + ticketInUrl + ", tickets to check against: " + ticket + "," + + minuteEarlyTicket); + return new ConsoleAccessAuthenticationAnswer(cmd, false); + } + } + } + + if (cmd.getVmId() != null && cmd.getVmId().isEmpty()) { + if (s_logger.isDebugEnabled()) { + s_logger.debug("Invalid vm id sent from proxy(happens when proxy session has terminated)"); + } + return new ConsoleAccessAuthenticationAnswer(cmd, false); + } + + VirtualMachine vm = _instanceDao.findByUuid(cmd.getVmId()); + if (vm == null) { + vm = _instanceDao.findById(Long.parseLong(cmd.getVmId())); + } + if (vm == null) { + s_logger.error("Invalid vm id " + cmd.getVmId() + " sent from console access authentication"); + return new ConsoleAccessAuthenticationAnswer(cmd, false); + } + + if (vm.getHostId() == null) { + s_logger.warn("VM " + vmId + " lost host info, failed authentication request"); + return new ConsoleAccessAuthenticationAnswer(cmd, false); + } + + HostVO host = _hostDao.findById(vm.getHostId()); + if (host == null) { + s_logger.warn("VM " + vmId + "'s host does not exist, fail authentication request"); + return new ConsoleAccessAuthenticationAnswer(cmd, false); + } + + String sid = cmd.getSid(); + if (sid == null || !sid.equals(vm.getVncPassword())) { + s_logger.warn("sid " + sid + " in url does not match stored sid " + vm.getVncPassword()); + return new ConsoleAccessAuthenticationAnswer(cmd, false); + } + + if (cmd.isReauthenticating()) { + ConsoleAccessAuthenticationAnswer authenticationAnswer = new ConsoleAccessAuthenticationAnswer(cmd, true); + authenticationAnswer.setReauthenticating(true); + + s_logger.info("Re-authentication request, ask host " + vm.getHostId() + " for new console info"); + GetVncPortAnswer answer = + (GetVncPortAnswer) _agentMgr.easySend(vm.getHostId(), + new GetVncPortCommand(vm.getId(), vm.getInstanceName())); + + if (answer != null && answer.getResult()) { + Ternary<String, String, String> parsedHostInfo = ConsoleProxyServlet.parseHostInfo(answer.getAddress()); + + if (parsedHostInfo.second() != null && parsedHostInfo.third() != null) { + + s_logger.info("Re-authentication result. vm: " + vm.getId() + ", tunnel url: " + + parsedHostInfo.second() + ", tunnel session: " + parsedHostInfo.third()); + + authenticationAnswer.setTunnelUrl(parsedHostInfo.second()); + authenticationAnswer.setTunnelSession(parsedHostInfo.third()); + } else { + s_logger.info("Re-authentication result. vm: " + vm.getId() + ", host address: " + + parsedHostInfo.first() + ", port: " + answer.getPort()); + + authenticationAnswer.setHost(parsedHostInfo.first()); + authenticationAnswer.setPort(answer.getPort()); + } + } else { + s_logger.warn("Re-authentication request failed"); + + authenticationAnswer.setSuccess(false); + } + + return authenticationAnswer; + } + + return new ConsoleAccessAuthenticationAnswer(cmd, true); + } + }