# HG changeset patch # User Elliott Baron # Date 1418756098 25200 # Node ID adb678c592f534ecf072e1f91f9c7b63dd62139f # Parent 2c1c1a1613963adaab294f1e19bf456cceb1b161 Remove RMI-based agent-proxy mechanism. It was discovered that, in certain configurations, the Thermostat agent disclosed JMX management URLs of all local Java virtual machines to any local user. A local, unprivileged user could use this flaw to escalate their privileges on the system. (CVE-2014-8120) More information will be available at: http://cve.mitre.org/cgi-bin/cvename.gci?name=CVE=2014-8120 diff -r 2c1c1a161396 -r adb678c592f5 agent/core/pom.xml --- a/agent/core/pom.xml Thu Aug 21 15:21:57 2014 -0400 +++ b/agent/core/pom.xml Tue Dec 16 11:54:58 2014 -0700 @@ -75,11 +75,6 @@ com.redhat.thermostat - thermostat-agent-proxy-common - ${project.version} - - - com.redhat.thermostat thermostat-launcher ${project.version} diff -r 2c1c1a161396 -r adb678c592f5 agent/core/src/main/java/com/redhat/thermostat/agent/RMIRegistry.java --- a/agent/core/src/main/java/com/redhat/thermostat/agent/RMIRegistry.java Thu Aug 21 15:21:57 2014 -0400 +++ b/agent/core/src/main/java/com/redhat/thermostat/agent/RMIRegistry.java Tue Dec 16 11:54:58 2014 -0700 @@ -45,8 +45,13 @@ /** * Maintains an RMI registry used for inter-process communication between * the Thermostat agent and other helper processes on the same host. + * + *

+ * RMI is no longer used by the Thermostat agent. Invoking any of this + * service's methods will result in a {@link RemoteException}. */ @Service +@Deprecated public interface RMIRegistry { /** diff -r 2c1c1a161396 -r adb678c592f5 agent/core/src/main/java/com/redhat/thermostat/agent/internal/Activator.java --- a/agent/core/src/main/java/com/redhat/thermostat/agent/internal/Activator.java Thu Aug 21 15:21:57 2014 -0400 +++ b/agent/core/src/main/java/com/redhat/thermostat/agent/internal/Activator.java Tue Dec 16 11:54:58 2014 -0700 @@ -62,14 +62,15 @@ context.registerService(RMIRegistry.class, registry, null); ServiceReference pathsRef = context.getServiceReference(CommonPaths.class); CommonPaths paths = context.getService(pathsRef); - pool = new MXBeanConnectionPoolImpl(registry, paths.getSystemBinRoot()); + UserNameUtilImpl usernameUtil = new UserNameUtilImpl(); + context.registerService(UserNameUtil.class, usernameUtil, null); + pool = new MXBeanConnectionPoolImpl(paths.getSystemBinRoot(), usernameUtil); context.registerService(MXBeanConnectionPool.class, pool, null); StorageCredentials creds = new AgentStorageCredentials(paths.getUserAgentAuthConfigFile()); context.registerService(StorageCredentials.class, creds, null); AgentConfigsUtils.setConfigFiles(paths.getSystemAgentConfigurationFile(), paths.getUserAgentConfigurationFile()); paths = null; context.ungetService(pathsRef); - context.registerService(UserNameUtil.class, new UserNameUtilImpl(), null); VmBlacklistImpl blacklist = new VmBlacklistImpl(); blacklist.addVmFilter(new AgentProxyFilter()); context.registerService(VmBlacklist.class, blacklist, null); @@ -78,10 +79,7 @@ @Override public void stop(BundleContext context) throws Exception { // Services automatically unregistered by framework - if (pool != null) { - pool.shutdown(); - pool = null; - } + pool = null; } // Testing hook. diff -r 2c1c1a161396 -r adb678c592f5 agent/core/src/main/java/com/redhat/thermostat/agent/internal/RMIRegistryImpl.java --- a/agent/core/src/main/java/com/redhat/thermostat/agent/internal/RMIRegistryImpl.java Thu Aug 21 15:21:57 2014 -0400 +++ b/agent/core/src/main/java/com/redhat/thermostat/agent/internal/RMIRegistryImpl.java Tue Dec 16 11:54:58 2014 -0700 @@ -36,121 +36,32 @@ package com.redhat.thermostat.agent.internal; -import java.io.IOException; -import java.net.InetAddress; -import java.net.ServerSocket; -import java.rmi.NoSuchObjectException; import java.rmi.Remote; import java.rmi.RemoteException; -import java.rmi.registry.LocateRegistry; import java.rmi.registry.Registry; -import java.rmi.server.RMIClientSocketFactory; -import java.rmi.server.RMIServerSocketFactory; -import java.rmi.server.RMISocketFactory; -import java.rmi.server.UnicastRemoteObject; -import java.util.logging.Logger; import com.redhat.thermostat.agent.RMIRegistry; -import com.redhat.thermostat.common.utils.LoggingUtils; +@Deprecated public class RMIRegistryImpl implements RMIRegistry { - private static final Logger logger = LoggingUtils.getLogger(RMIRegistryImpl.class); - - private RegistryWrapper registryWrapper; - private ServerSocketCreator serverSockCreator; - private Registry registry; - - public RMIRegistryImpl() { - this(new RegistryWrapper(), new ServerSocketCreator()); - } - - RMIRegistryImpl(RegistryWrapper registryWrapper, ServerSocketCreator serverSockCreator) { - this.registryWrapper = registryWrapper; - this.serverSockCreator = serverSockCreator; - } - - public void start() throws RemoteException { - this.registry = registryWrapper.createRegistry(Registry.REGISTRY_PORT /* TODO customize */, - RMISocketFactory.getDefaultSocketFactory(), - new RMIServerSocketFactory() { - - @Override - public ServerSocket createServerSocket(int port) throws IOException { - // Allow only local connections - return serverSockCreator.createSocket(port, 0, InetAddress.getLoopbackAddress()); - } - }); - logger.fine("Starting RMI registry"); + RMIRegistryImpl() { } @Override public Registry getRegistry() throws RemoteException { - // We get a class loading problem when returning the local registry reference, - // this returns a remote stub reference instead - return registryWrapper.getRegistry(); - } - - public void stop() throws RemoteException { - if (registry != null) { - registryWrapper.destroyRegistry(registry); - registry = null; - logger.fine("Shutting down RMI registry"); - } + throw new RemoteException("RMI is no longer used"); } @Override public Remote export(Remote obj) throws RemoteException { - if (registry == null) { - throw new RemoteException("RMI registry is not running"); - } - return registryWrapper.export(obj, 0); + throw new RemoteException("RMI is no longer used"); } @Override public boolean unexport(Remote obj) throws RemoteException { - if (registry == null) { - throw new RemoteException("RMI registry is not running"); - } - return registryWrapper.unexport(obj, true); - } - - /* - * For testing purposes only. - */ - Registry getRegistryImpl() { - return registry; + throw new RemoteException("RMI is no longer used"); } - static class RegistryWrapper { - Registry createRegistry(int port, RMIClientSocketFactory csf, - RMIServerSocketFactory ssf) throws RemoteException { - return LocateRegistry.createRegistry(port, csf, ssf); - } - - Registry getRegistry() throws RemoteException { - return LocateRegistry.getRegistry(InetAddress.getLoopbackAddress().getHostName()); - } - - void destroyRegistry(Registry registry) throws NoSuchObjectException { - // Shuts down RMI registry - UnicastRemoteObject.unexportObject(registry, true); - } - - Remote export(Remote obj, int port) throws RemoteException { - return UnicastRemoteObject.exportObject(obj, 0); - } - - boolean unexport(Remote obj, boolean force) throws NoSuchObjectException { - return UnicastRemoteObject.unexportObject(obj, force); - } - } - - static class ServerSocketCreator { - ServerSocket createSocket(int port, int backlog, InetAddress bindAddr) throws IOException { - return new ServerSocket(port, backlog, bindAddr); - } - } - } diff -r 2c1c1a161396 -r adb678c592f5 agent/core/src/main/java/com/redhat/thermostat/utils/management/internal/AgentProxyClient.java --- a/agent/core/src/main/java/com/redhat/thermostat/utils/management/internal/AgentProxyClient.java Thu Aug 21 15:21:57 2014 -0400 +++ b/agent/core/src/main/java/com/redhat/thermostat/utils/management/internal/AgentProxyClient.java Tue Dec 16 11:54:58 2014 -0700 @@ -36,141 +36,107 @@ package com.redhat.thermostat.utils.management.internal; +import java.io.BufferedReader; import java.io.File; import java.io.IOException; -import java.rmi.NotBoundException; -import java.rmi.RemoteException; -import java.rmi.registry.Registry; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.logging.Level; import java.util.logging.Logger; -import com.redhat.thermostat.agent.RMIRegistry; -import com.redhat.thermostat.agent.proxy.common.AgentProxyControl; -import com.redhat.thermostat.agent.proxy.common.AgentProxyListener; -import com.redhat.thermostat.agent.proxy.common.AgentProxyLogin; import com.redhat.thermostat.common.tools.ApplicationException; -import com.redhat.thermostat.common.utils.LoggedExternalProcess; import com.redhat.thermostat.common.utils.LoggingUtils; -class AgentProxyClient implements AgentProxyListener { +class AgentProxyClient { - private static final long SERVER_TIMEOUT_MS = 5000L; private static final String SERVER_NAME = "thermostat-agent-proxy"; private static final Logger logger = LoggingUtils.getLogger(AgentProxyClient.class); - private final RMIRegistry registry; private final int pid; private final ProcessCreator procCreator; private final File binPath; - private final CountDownLatch started; + private final String username; - private AgentProxyControl proxy; - private Exception serverError; - - AgentProxyClient(RMIRegistry registry, int pid, File binPath) { - this(registry, pid, binPath, new CountDownLatch(1), - new ProcessCreator()); + AgentProxyClient(int pid, String user, File binPath) { + this(pid, user, binPath, new ProcessCreator()); } - AgentProxyClient(RMIRegistry registry, int pid, File binPath, - CountDownLatch started, ProcessCreator procCreator) { - this.registry = registry; + AgentProxyClient(int pid, String user, File binPath, ProcessCreator procCreator) { this.pid = pid; this.binPath = binPath; - this.started = started; this.procCreator = procCreator; + this.username = user; } - void createProxy() throws IOException, ApplicationException { - // Export our listener - AgentProxyListener stub = (AgentProxyListener) registry.export(this); - String listenerName = REMOTE_PREFIX + String.valueOf(pid); - Registry reg = registry.getRegistry(); - reg.rebind(listenerName, stub); - logger.fine("Registered proxy listener for " + pid); + String getJMXServiceURL() throws IOException, ApplicationException { + // Start the agent proxy + Process proxy = null; + Thread errReaderThread = null; + try { + proxy = startProcess(); + + final InputStream errStream = proxy.getErrorStream(); - // Start the agent proxy, and wait until it exports itself - try { - startProcess(); - } finally { - // Got started event or timed out, unregister our listener + // Log stderr in a separate thread + errReaderThread = new Thread(new Runnable() { + @Override + public void run() { + BufferedReader errReader = new BufferedReader(new InputStreamReader(errStream)); + String line; + try { + while ((line = errReader.readLine()) != null + && !Thread.currentThread().isInterrupted()) { + logger.info(line); + } + errReader.close(); + } catch (IOException e) { + logger.log(Level.WARNING, "Failed to read error stream", e); + } + } + }); + errReaderThread.start(); + + // Get JMX service URL from stdout + BufferedReader outReader = new BufferedReader(new InputStreamReader(proxy.getInputStream())); + String url = outReader.readLine(); + + // Wait for process to terminate try { - reg.unbind(listenerName); - registry.unexport(this); - } catch (NotBoundException e) { - throw new RemoteException("Error unregistering listener", e); + proxy.waitFor(); + } catch (InterruptedException e) { + errReaderThread.interrupt(); + Thread.currentThread().interrupt(); } - } + outReader.close(); + if (url == null) { + throw new IOException("Failed to determine JMX service URL from proxy process"); + } - // Check if server started successfully - if (serverError != null) { - throw new RemoteException("Server failed to start", serverError); - } - - // Lookup server - String serverName = AgentProxyLogin.REMOTE_PREFIX + String.valueOf(pid); - try { - // Need to authenticate in order to obtain proxy object - AgentProxyLogin proxyLogin = (AgentProxyLogin) reg.lookup(serverName); - proxy = proxyLogin.login(); - } catch (NotBoundException e) { - throw new RemoteException("Unable to find remote interface", e); + return url; + } finally { + if (proxy != null) { + proxy.destroy(); + } + if (errReaderThread != null) { + try { + errReaderThread.join(); + } catch (InterruptedException e) { + errReaderThread.interrupt(); + Thread.currentThread().interrupt(); + } + } } } - private void startProcess() throws IOException, ApplicationException { + private Process startProcess() throws IOException, ApplicationException { String serverPath = binPath + File.separator + SERVER_NAME; - procCreator.createAndRunProcess(new String[] { serverPath, String.valueOf(pid) }); - try { - boolean result = started.await(SERVER_TIMEOUT_MS, TimeUnit.MILLISECONDS); - if (!result) { - throw new RemoteException("Timeout while waiting for server"); - } - } catch (InterruptedException e) { - // Restore interrupted status - Thread.currentThread().interrupt(); - } - } - - void attach() throws RemoteException { - proxy.attach(); - } - - boolean isAttached() throws RemoteException { - return proxy.isAttached(); - } - - String getConnectorAddress() throws RemoteException { - return proxy.getConnectorAddress(); - } - - void detach() throws RemoteException { - proxy.detach(); - } - - @Override - public void serverStarted() throws RemoteException { - started.countDown(); - } - - @Override - public void serverFailedToStart(Exception error) throws RemoteException { - serverError = error; - started.countDown(); - } - - /* - * For testing purposes only. - */ - AgentProxyControl getProxy() { - return proxy; + return procCreator.createAndRunProcess(new String[] { serverPath, String.valueOf(pid), username }); } static class ProcessCreator { Process createAndRunProcess(String[] args) throws IOException, ApplicationException { - LoggedExternalProcess process = new LoggedExternalProcess(args); - return process.runAndReturnProcess(); + ProcessBuilder process = new ProcessBuilder(args); + return process.start(); } } diff -r 2c1c1a161396 -r adb678c592f5 agent/core/src/main/java/com/redhat/thermostat/utils/management/internal/MXBeanConnectionPoolImpl.java --- a/agent/core/src/main/java/com/redhat/thermostat/utils/management/internal/MXBeanConnectionPoolImpl.java Thu Aug 21 15:21:57 2014 -0400 +++ b/agent/core/src/main/java/com/redhat/thermostat/utils/management/internal/MXBeanConnectionPoolImpl.java Tue Dec 16 11:54:58 2014 -0700 @@ -38,46 +38,34 @@ import java.io.File; import java.io.IOException; -import java.rmi.RemoteException; import java.util.HashMap; import java.util.Map; -import java.util.logging.Level; -import java.util.logging.Logger; -import com.redhat.thermostat.agent.RMIRegistry; -import com.redhat.thermostat.agent.internal.RMIRegistryImpl; +import com.redhat.thermostat.agent.utils.ProcDataSource; import com.redhat.thermostat.agent.utils.management.MXBeanConnection; import com.redhat.thermostat.agent.utils.management.MXBeanConnectionPool; +import com.redhat.thermostat.agent.utils.username.UserNameUtil; import com.redhat.thermostat.common.Pair; import com.redhat.thermostat.common.tools.ApplicationException; -import com.redhat.thermostat.common.utils.LoggingUtils; +import com.redhat.thermostat.utils.management.internal.ProcessUserInfoBuilder.ProcessUserInfo; public class MXBeanConnectionPoolImpl implements MXBeanConnectionPool { - private static final Logger logger = LoggingUtils.getLogger(MXBeanConnectionPoolImpl.class); - // pid -> (usageCount, actualObject) private Map> pool = new HashMap<>(); private final ConnectorCreator creator; - private final RMIRegistryImpl registry; private final File binPath; + private final ProcessUserInfoBuilder userInfoBuilder; - public MXBeanConnectionPoolImpl(RMIRegistryImpl registry, File binPath) { - this(new ConnectorCreator(), registry, binPath); + public MXBeanConnectionPoolImpl(File binPath, UserNameUtil userNameUtil) { + this(new ConnectorCreator(), binPath, new ProcessUserInfoBuilder(new ProcDataSource(), userNameUtil)); } - MXBeanConnectionPoolImpl(ConnectorCreator connectorCreator, RMIRegistryImpl registry, File binPath) { + MXBeanConnectionPoolImpl(ConnectorCreator connectorCreator, File binPath, ProcessUserInfoBuilder userInfoBuilder) { this.creator = connectorCreator; - this.registry = registry; this.binPath = binPath; - - // Start RMI registry - try { - registry.start(); - } catch (RemoteException e) { - logger.log(Level.SEVERE, "Unable to start RMI registry", e); - } + this.userInfoBuilder = userInfoBuilder; } @Override @@ -85,16 +73,14 @@ Pair data = pool.get(pid); if (data == null) { MXBeanConnector connector = null; - try { - connector = creator.create(registry, pid, binPath); - connector.attach(); - MXBeanConnectionImpl connection = connector.connect(); - data = new Pair(1, connection); - } finally { - if (connector != null) { - connector.close(); - } + ProcessUserInfo info = userInfoBuilder.build(pid); + String username = info.getUsername(); + if (username == null) { + throw new IOException("Unable to determine owner of " + pid); } + connector = creator.create(pid, username, binPath); + MXBeanConnectionImpl connection = connector.connect(); + data = new Pair(1, connection); } else { data = new Pair<>(data.getFirst() + 1, data.getSecond()); } @@ -117,17 +103,9 @@ } } - public void shutdown() { - try { - registry.stop(); - } catch (RemoteException e) { - logger.log(Level.SEVERE, "Unable to stop RMI registry", e); - } - } - static class ConnectorCreator { - public MXBeanConnector create(RMIRegistry registry, int pid, File binPath) throws IOException, ApplicationException { - MXBeanConnector connector = new MXBeanConnector(registry, pid, binPath); + public MXBeanConnector create(int pid, String user, File binPath) throws IOException, ApplicationException { + MXBeanConnector connector = new MXBeanConnector(pid, user, binPath); return connector; } } diff -r 2c1c1a161396 -r adb678c592f5 agent/core/src/main/java/com/redhat/thermostat/utils/management/internal/MXBeanConnector.java --- a/agent/core/src/main/java/com/redhat/thermostat/utils/management/internal/MXBeanConnector.java Thu Aug 21 15:21:57 2014 -0400 +++ b/agent/core/src/main/java/com/redhat/thermostat/utils/management/internal/MXBeanConnector.java Tue Dec 16 11:54:58 2014 -0700 @@ -36,40 +36,32 @@ package com.redhat.thermostat.utils.management.internal; -import java.io.Closeable; import java.io.File; import java.io.IOException; -import java.rmi.RemoteException; import javax.management.MBeanServerConnection; import javax.management.remote.JMXConnector; import javax.management.remote.JMXConnectorFactory; import javax.management.remote.JMXServiceURL; -import com.redhat.thermostat.agent.RMIRegistry; import com.redhat.thermostat.common.tools.ApplicationException; -class MXBeanConnector implements Closeable { +class MXBeanConnector { - private final AgentProxyClient client; private final JMXConnectionCreator jmxCreator; + private final String serviceURL; - public MXBeanConnector(RMIRegistry registry, int pid, File binPath) throws IOException, ApplicationException { - this(new AgentProxyClient(registry, pid, binPath), new JMXConnectionCreator()); + public MXBeanConnector(int pid, String user, File binPath) throws IOException, ApplicationException { + this(new AgentProxyClient(pid, user, binPath), new JMXConnectionCreator()); } MXBeanConnector(AgentProxyClient client, JMXConnectionCreator jmxCreator) throws IOException, ApplicationException { - this.client = client; this.jmxCreator = jmxCreator; - client.createProxy(); - } - - public synchronized void attach() throws Exception { - client.attach(); + this.serviceURL = client.getJMXServiceURL(); } public synchronized MXBeanConnectionImpl connect() throws IOException { - JMXServiceURL url = new JMXServiceURL(client.getConnectorAddress()); + JMXServiceURL url = new JMXServiceURL(serviceURL); JMXConnector connection = jmxCreator.create(url); MBeanServerConnection mbsc = null; try { @@ -83,15 +75,6 @@ return new MXBeanConnectionImpl(connection, mbsc); } - public boolean isAttached() throws RemoteException { - return client.isAttached(); - } - - @Override - public synchronized void close() throws IOException { - client.detach(); - } - static class JMXConnectionCreator { JMXConnector create(JMXServiceURL url) throws IOException { return JMXConnectorFactory.connect(url); diff -r 2c1c1a161396 -r adb678c592f5 agent/core/src/main/java/com/redhat/thermostat/utils/management/internal/ProcessUserInfoBuilder.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/agent/core/src/main/java/com/redhat/thermostat/utils/management/internal/ProcessUserInfoBuilder.java Tue Dec 16 11:54:58 2014 -0700 @@ -0,0 +1,141 @@ +/* + * Copyright 2012-2014 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.utils.management.internal; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.Reader; +import java.util.logging.Level; +import java.util.logging.Logger; + +import com.redhat.thermostat.agent.utils.ProcDataSource; +import com.redhat.thermostat.agent.utils.username.UserNameLookupException; +import com.redhat.thermostat.agent.utils.username.UserNameUtil; +import com.redhat.thermostat.common.utils.LoggingUtils; + +/* + * FIXME: This class was copied from system-backend to avoid adding new API. + */ +class ProcessUserInfoBuilder { + + private static final ProcessUserInfo NON_EXISTENT_USER = new ProcessUserInfo(); + private static final String PROC_STATUS_UID = "Uid:"; + private static final Logger logger = LoggingUtils.getLogger(ProcessUserInfoBuilder.class); + private ProcDataSource source; + private UserNameUtil userNameUtil; + + ProcessUserInfoBuilder(ProcDataSource source, UserNameUtil userNameUtil) { + this.source = source; + this.userNameUtil = userNameUtil; + } + + static class ProcessUserInfo { + + private long uid; + private String username; + + ProcessUserInfo(long uid, String username) { + this.uid = uid; + this.username = username; + } + + ProcessUserInfo() { + this.uid = -1; + this.username = null; + } + + public long getUid() { + return uid; + } + + public String getUsername() { + return username; + } + } + + ProcessUserInfo build(int pid) { + ProcessUserInfo info = NON_EXISTENT_USER; + try { + Reader reader = source.getStatusReader(pid); + long uid = getUidFromProcfs(new BufferedReader(reader)); + String name = null; + try { + name = userNameUtil.getUserName(uid); + } catch (UserNameLookupException e) { + logger.log(Level.WARNING, "Unable to retrieve username for uid: " + uid, e); + } + info = new ProcessUserInfo(uid, name); + } catch (IOException e) { + logger.log(Level.WARNING, "Unable to read user info for " + pid, e); + } + + return info; + } + + /* + * Look for the following line: + * Uid: + */ + private long getUidFromProcfs(BufferedReader br) throws IOException { + long uid = -1; + String line; + while ((line = br.readLine()) != null) { + line = line.trim(); + if (line.startsWith(PROC_STATUS_UID)) { + String[] parts = line.split("\\s+"); + if (parts.length == 5) { + try { + // Use Real UID + uid = Long.parseLong(parts[1]); + } catch (NumberFormatException e) { + throw new IOException("Unexpected output from ps command", e); + } + } + else { + throw new IOException("Expected 5 parts from split /proc/${pid}/status output, got " + parts.length); + } + } + } + if (uid < 0) { + throw new IOException("Unable to determine UID from /proc/${pid}/status"); + } + return uid; + } + + +} + diff -r 2c1c1a161396 -r adb678c592f5 agent/core/src/test/java/com/redhat/thermostat/agent/internal/ActivatorTest.java --- a/agent/core/src/test/java/com/redhat/thermostat/agent/internal/ActivatorTest.java Thu Aug 21 15:21:57 2014 -0400 +++ b/agent/core/src/test/java/com/redhat/thermostat/agent/internal/ActivatorTest.java Tue Dec 16 11:54:58 2014 -0700 @@ -89,8 +89,6 @@ activator.setPool(pool); activator.stop(context); - - verify(pool).shutdown(); } } diff -r 2c1c1a161396 -r adb678c592f5 agent/core/src/test/java/com/redhat/thermostat/agent/internal/RMIRegistryImplTest.java --- a/agent/core/src/test/java/com/redhat/thermostat/agent/internal/RMIRegistryImplTest.java Thu Aug 21 15:21:57 2014 -0400 +++ b/agent/core/src/test/java/com/redhat/thermostat/agent/internal/RMIRegistryImplTest.java Tue Dec 16 11:54:58 2014 -0700 @@ -1,123 +1,36 @@ package com.redhat.thermostat.agent.internal; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyInt; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import java.io.IOException; -import java.net.InetAddress; import java.rmi.Remote; import java.rmi.RemoteException; -import java.rmi.registry.Registry; -import java.rmi.server.RMIClientSocketFactory; -import java.rmi.server.RMIServerSocketFactory; -import java.rmi.server.RMISocketFactory; import org.junit.Before; import org.junit.Test; -import org.mockito.ArgumentCaptor; - -import com.redhat.thermostat.agent.internal.RMIRegistryImpl.RegistryWrapper; -import com.redhat.thermostat.agent.internal.RMIRegistryImpl.ServerSocketCreator; public class RMIRegistryImplTest { - private RegistryWrapper wrapper; - private Registry reg; private RMIRegistryImpl registry; - private ServerSocketCreator sockCreator; @Before - public void setup() throws RemoteException { - wrapper = mock(RegistryWrapper.class); - reg = mock(Registry.class); - when(wrapper.createRegistry(anyInt(), any(RMIClientSocketFactory.class), - any(RMIServerSocketFactory.class))).thenReturn(reg); - sockCreator = mock(ServerSocketCreator.class); - - registry = new RMIRegistryImpl(wrapper, sockCreator); - } - - @Test - public void testRegistryStart() throws IOException { - registry.start(); - - ArgumentCaptor portCaptor = ArgumentCaptor.forClass(Integer.class); - ArgumentCaptor csfCaptor = ArgumentCaptor.forClass(RMIClientSocketFactory.class); - ArgumentCaptor ssfCaptor = ArgumentCaptor.forClass(RMIServerSocketFactory.class); - verify(wrapper).createRegistry(portCaptor.capture(), csfCaptor.capture(), ssfCaptor.capture()); - - // Ensure defaults used for port and client socket factory - int port = portCaptor.getValue(); - assertEquals(Registry.REGISTRY_PORT, port); - - RMIClientSocketFactory csf = csfCaptor.getValue(); - assertEquals(RMISocketFactory.getDefaultSocketFactory(), csf); - - // Ensure bound to loopback address - RMIServerSocketFactory ssf = ssfCaptor.getValue(); - ssf.createServerSocket(port); - verify(sockCreator).createSocket(port, 0, InetAddress.getLoopbackAddress()); - } - - @Test - public void testRegistryStop() throws IOException { - registry.start(); - - registry.stop(); - - verify(wrapper).destroyRegistry(reg); - assertNull(registry.getRegistryImpl()); - } - - @Test - public void testRegistryStopNotStarted() throws IOException { - registry.stop(); - - verify(wrapper, never()).destroyRegistry(reg); - } - - @Test - public void testGetRegistry() throws Exception { - Registry stub = mock(Registry.class); - when(wrapper.getRegistry()).thenReturn(stub); - assertEquals(stub, registry.getRegistry()); - } - - @Test - public void testExportObject() throws Exception { - Remote obj = mock(Remote.class); - Remote stub = mock(Remote.class); - when(wrapper.export(obj, 0)).thenReturn(stub); - - registry.start(); - assertEquals(stub, registry.export(obj)); + public void setup() throws Exception { + registry = new RMIRegistryImpl(); } @Test(expected=RemoteException.class) - public void testExportObjectNotStarted() throws Exception { + public void testGetRegistry() throws Exception { + registry.getRegistry(); + } + + @Test(expected=RemoteException.class) + public void testExportObject() throws Exception { Remote obj = mock(Remote.class); registry.export(obj); } - @Test + @Test(expected=RemoteException.class) public void testUnexportObject() throws Exception { Remote obj = mock(Remote.class); - when(wrapper.unexport(obj, true)).thenReturn(true); - - registry.start(); - assertEquals(true, registry.unexport(obj)); - verify(wrapper).unexport(obj, true); - } - - @Test(expected=RemoteException.class) - public void testUnexportObjectNotStarted() throws Exception { - Remote obj = mock(Remote.class); registry.unexport(obj); } } diff -r 2c1c1a161396 -r adb678c592f5 agent/core/src/test/java/com/redhat/thermostat/utils/management/internal/AgentProxyClientTest.java --- a/agent/core/src/test/java/com/redhat/thermostat/utils/management/internal/AgentProxyClientTest.java Thu Aug 21 15:21:57 2014 -0400 +++ b/agent/core/src/test/java/com/redhat/thermostat/utils/management/internal/AgentProxyClientTest.java Tue Dec 16 11:54:58 2014 -0700 @@ -37,186 +37,117 @@ package com.redhat.thermostat.utils.management.internal; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.Matchers.any; -import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; -import java.rmi.RemoteException; -import java.rmi.registry.Registry; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Handler; +import java.util.logging.LogRecord; import org.junit.Before; import org.junit.Test; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.stubbing.Answer; +import org.mockito.ArgumentCaptor; -import com.redhat.thermostat.agent.internal.RMIRegistryImpl; -import com.redhat.thermostat.agent.proxy.common.AgentProxyControl; -import com.redhat.thermostat.agent.proxy.common.AgentProxyListener; -import com.redhat.thermostat.agent.proxy.common.AgentProxyLogin; -import com.redhat.thermostat.common.tools.ApplicationException; +import com.redhat.thermostat.common.utils.LoggingUtils; import com.redhat.thermostat.utils.management.internal.AgentProxyClient.ProcessCreator; public class AgentProxyClientTest { private AgentProxyClient client; - private RMIRegistryImpl rmi; - private Registry registry; private ProcessCreator procCreator; - private CountDownLatch latch; - private AgentProxyListener listenerStub; - private AgentProxyLogin proxyLogin; - private AgentProxyControl proxyControl; + private String user; private File binPath; @Before public void setup() throws Exception { - rmi = mock(RMIRegistryImpl.class); - listenerStub = mock(AgentProxyListener.class); - when(rmi.export(any(AgentProxyListener.class))).thenReturn(listenerStub); - registry = mock(Registry.class); - when(rmi.getRegistry()).thenReturn(registry); - proxyLogin = mock(AgentProxyLogin.class); - when(registry.lookup(AgentProxyLogin.REMOTE_PREFIX + "0")).thenReturn(proxyLogin); - proxyControl = mock(AgentProxyControl.class); - when(proxyLogin.login()).thenReturn(proxyControl); - procCreator = mock(ProcessCreator.class); binPath = new File("/path/to/thermostat/bin"); - latch = mock(CountDownLatch.class); + user = "Hello"; + client = new AgentProxyClient(9000, user, binPath, procCreator); } @Test public void testCreateProxy() throws Exception { - createClient(); - - // Verify listener exported and bound - verify(rmi).export(client); - verify(registry).rebind(AgentProxyListener.REMOTE_PREFIX + "0", listenerStub); + Process proxy = mock(Process.class); + final String jmxUrl = "myJmxUrl"; + when(proxy.getInputStream()).thenReturn(new ByteArrayInputStream(jmxUrl.getBytes())); + when(proxy.getErrorStream()).thenReturn(new ByteArrayInputStream(new byte[0])); + when(procCreator.createAndRunProcess(any(String[].class))).thenReturn(proxy); - // Verify server created - String progName = "/path/to/thermostat/bin" + File.separator + "thermostat-agent-proxy"; - verify(procCreator).createAndRunProcess(new String[] { progName, "0" }); - verify(latch).countDown(); - - // Verify listener removed - verify(registry).unbind(AgentProxyListener.REMOTE_PREFIX + "0"); - verify(rmi).unexport(client); - - // Verify login - verify(registry).lookup(AgentProxyLogin.REMOTE_PREFIX + "0"); - verify(proxyLogin).login(); + // Check returned URL + String result = client.getJMXServiceURL(); + assertEquals(jmxUrl, result); - // Check returned proxy control - assertEquals(proxyControl, client.getProxy()); - } - - private void createClient() throws InterruptedException, IOException, - ApplicationException { - client = new AgentProxyClient(rmi, 0, binPath, latch, procCreator); + // Check process arguments + ArgumentCaptor argsCaptor = ArgumentCaptor.forClass(String[].class); + verify(procCreator).createAndRunProcess(argsCaptor.capture()); + String[] args = argsCaptor.getValue(); + assertEquals(3, args.length); + assertEquals("/path/to/thermostat/bin/thermostat-agent-proxy", args[0]); + assertEquals("9000", args[1]); + assertEquals("Hello", args[2]); - doAnswer(new Answer() { - @Override - public Boolean answer(InvocationOnMock invocation) throws Throwable { - // Trigger server started - client.serverStarted(); - return true; - } - }).when(latch).await(any(Long.class), any(TimeUnit.class)); - - client.createProxy(); + // Check cleanup + verify(proxy).waitFor(); } @Test - public void testCreateProxyFailed() throws Exception { - client = new AgentProxyClient(rmi, 0, binPath, latch, procCreator); + public void testErrorHandler() throws Exception { + Process proxy = mock(Process.class); + final String errors = "This is an error\nThis is also an error\nOh no!\n"; + when(proxy.getInputStream()).thenReturn(new ByteArrayInputStream(new byte[0])); + when(proxy.getErrorStream()).thenReturn(new ByteArrayInputStream(errors.getBytes())); + when(procCreator.createAndRunProcess(any(String[].class))).thenReturn(proxy); - final Exception error = mock(Exception.class); - doAnswer(new Answer() { - @Override - public Boolean answer(InvocationOnMock invocation) throws Throwable { - // Trigger server started - client.serverFailedToStart(error); - return true; - } - }).when(latch).await(any(Long.class), any(TimeUnit.class)); + List logMessages = new ArrayList<>(); + TestLogHandler logHandler = new TestLogHandler(logMessages); + LoggingUtils.getLogger(AgentProxyClient.class).addHandler(logHandler); try { - client.createProxy(); - fail("Expected RemoteException"); - } catch (RemoteException e) { - assertEquals(error, e.getCause()); - } - - // Verify listener exported and bound - verify(rmi).export(client); - verify(registry).rebind(AgentProxyListener.REMOTE_PREFIX + "0", listenerStub); - - // Verify server created - String progName = "/path/to/thermostat/bin" + File.separator + "thermostat-agent-proxy"; - verify(procCreator).createAndRunProcess(new String[] { progName, "0" }); - verify(latch).countDown(); - - // Verify listener removed - verify(registry).unbind(AgentProxyListener.REMOTE_PREFIX + "0"); - verify(rmi).unexport(client); - } - - @Test - public void testCreateProxyTimeout() throws Exception { - when(latch.await(any(Long.class), any(TimeUnit.class))).thenReturn(false); - client = new AgentProxyClient(rmi, 0, binPath, latch, procCreator); - - try { - client.createProxy(); - fail("Expected RemoteException"); - } catch (RemoteException e) { - // Verify listener exported and bound - verify(rmi).export(client); - verify(registry).rebind(AgentProxyListener.REMOTE_PREFIX + "0", listenerStub); - - // Verify server created - String progName = "/path/to/thermostat/bin" + File.separator + "thermostat-agent-proxy"; - verify(procCreator).createAndRunProcess(new String[] { progName, "0" }); - - // Verify listener removed - verify(registry).unbind(AgentProxyListener.REMOTE_PREFIX + "0"); - verify(rmi).unexport(client); + try { + client.getJMXServiceURL(); + fail("Expected exception"); + } catch (IOException e) { + // Expected + } + assertEquals(3, logMessages.size()); + assertEquals("This is an error", logMessages.get(0).getMessage()); + assertEquals("This is also an error", logMessages.get(1).getMessage()); + assertEquals("Oh no!", logMessages.get(2).getMessage()); + } finally { + LoggingUtils.getLogger(AgentProxyClient.class).removeHandler(logHandler); } } - @Test - public void testAttach() throws Exception { - createClient(); + private static class TestLogHandler extends Handler { - client.attach(); - verify(proxyControl).attach(); - } - - @Test - public void testIsAttached() throws Exception { - createClient(); - when(proxyControl.isAttached()).thenReturn(true); + private List logMessages; + public TestLogHandler(List logMessages) { + this.logMessages = logMessages; + } + + @Override + public void publish(LogRecord record) { + logMessages.add(record); + } - boolean result = client.isAttached(); - verify(proxyControl).isAttached(); - assertTrue(result); + @Override + public void flush() { + // Do nothing + } + + @Override + public void close() throws SecurityException { + // Do nothing + } } - - @Test - public void testDetach() throws Exception { - createClient(); - - client.detach(); - verify(proxyControl).detach(); - } - + } diff -r 2c1c1a161396 -r adb678c592f5 agent/core/src/test/java/com/redhat/thermostat/utils/management/internal/MXBeanConnectionPoolImplTest.java --- a/agent/core/src/test/java/com/redhat/thermostat/utils/management/internal/MXBeanConnectionPoolImplTest.java Thu Aug 21 15:21:57 2014 -0400 +++ b/agent/core/src/test/java/com/redhat/thermostat/utils/management/internal/MXBeanConnectionPoolImplTest.java Tue Dec 16 11:54:58 2014 -0700 @@ -50,9 +50,9 @@ import org.junit.Test; -import com.redhat.thermostat.agent.internal.RMIRegistryImpl; import com.redhat.thermostat.agent.utils.management.MXBeanConnection; import com.redhat.thermostat.utils.management.internal.MXBeanConnectionPoolImpl.ConnectorCreator; +import com.redhat.thermostat.utils.management.internal.ProcessUserInfoBuilder.ProcessUserInfo; public class MXBeanConnectionPoolImplTest { @@ -64,20 +64,20 @@ MXBeanConnector connector = mock(MXBeanConnector.class); ConnectorCreator creator = mock(ConnectorCreator.class); - when(creator.create(any(RMIRegistryImpl.class), anyInt(), any(File.class))).thenReturn(connector); + when(creator.create(anyInt(), any(String.class), any(File.class))).thenReturn(connector); when(connector.connect()).thenReturn(toReturn); - RMIRegistryImpl registry = mock(RMIRegistryImpl.class); - MXBeanConnectionPoolImpl pool = new MXBeanConnectionPoolImpl(creator, registry, binDir); + ProcessUserInfoBuilder builder = mock(ProcessUserInfoBuilder.class); + ProcessUserInfo info = new ProcessUserInfo(0, "Test"); + when(builder.build(0)).thenReturn(info); + MXBeanConnectionPoolImpl pool = new MXBeanConnectionPoolImpl(creator, binDir, builder); MXBeanConnection connection = pool.acquire(0); assertNotNull(connection); assertEquals(connection, toReturn); - verify(connector).attach(); verify(connector).connect(); - verify(connector).close(); } @Test @@ -86,17 +86,17 @@ MXBeanConnector connector = mock(MXBeanConnector.class); ConnectorCreator creator = mock(ConnectorCreator.class); - when(creator.create(any(RMIRegistryImpl.class), anyInt(), any(File.class))).thenReturn(connector); + when(creator.create(anyInt(), any(String.class), any(File.class))).thenReturn(connector); when(connector.connect()).thenReturn(toReturn); - RMIRegistryImpl registry = mock(RMIRegistryImpl.class); - MXBeanConnectionPoolImpl pool = new MXBeanConnectionPoolImpl(creator, registry, binDir); + ProcessUserInfoBuilder builder = mock(ProcessUserInfoBuilder.class); + ProcessUserInfo info = new ProcessUserInfo(0, "Test"); + when(builder.build(0)).thenReturn(info); + MXBeanConnectionPoolImpl pool = new MXBeanConnectionPoolImpl(creator, binDir, builder); MXBeanConnection connection1 = pool.acquire(0); - verify(connector).attach(); verify(connector).connect(); - verify(connector).close(); MXBeanConnection connection2 = pool.acquire(0); @@ -112,11 +112,13 @@ MXBeanConnector connector = mock(MXBeanConnector.class); ConnectorCreator creator = mock(ConnectorCreator.class); - when(creator.create(any(RMIRegistryImpl.class), anyInt(), any(File.class))).thenReturn(connector); + when(creator.create(anyInt(), any(String.class), any(File.class))).thenReturn(connector); when(connector.connect()).thenReturn(actualConnection); - RMIRegistryImpl registry = mock(RMIRegistryImpl.class); - MXBeanConnectionPoolImpl pool = new MXBeanConnectionPoolImpl(creator, registry, binDir); + ProcessUserInfoBuilder builder = mock(ProcessUserInfoBuilder.class); + ProcessUserInfo info = new ProcessUserInfo(0, "Test"); + when(builder.build(0)).thenReturn(info); + MXBeanConnectionPoolImpl pool = new MXBeanConnectionPoolImpl(creator, binDir, builder); MXBeanConnection connection = pool.acquire(0); @@ -133,11 +135,13 @@ MXBeanConnector connector = mock(MXBeanConnector.class); ConnectorCreator creator = mock(ConnectorCreator.class); - when(creator.create(any(RMIRegistryImpl.class), anyInt(), any(File.class))).thenReturn(connector); + when(creator.create(anyInt(), any(String.class), any(File.class))).thenReturn(connector); when(connector.connect()).thenReturn(actualConnection); - RMIRegistryImpl registry = mock(RMIRegistryImpl.class); - MXBeanConnectionPoolImpl pool = new MXBeanConnectionPoolImpl(creator, registry, binDir); + ProcessUserInfoBuilder builder = mock(ProcessUserInfoBuilder.class); + ProcessUserInfo info = new ProcessUserInfo(0, "Test"); + when(builder.build(0)).thenReturn(info); + MXBeanConnectionPoolImpl pool = new MXBeanConnectionPoolImpl(creator, binDir, builder); // connection1 == connection1 == actualConnection MXBeanConnection connection1 = pool.acquire(0); @@ -153,15 +157,5 @@ } - @Test - public void testShutdown() throws Exception { - RMIRegistryImpl registry = mock(RMIRegistryImpl.class); - ConnectorCreator creator = mock(ConnectorCreator.class); - MXBeanConnectionPoolImpl pool = new MXBeanConnectionPoolImpl(creator, registry, binDir); - verify(registry).start(); - - pool.shutdown(); - verify(registry).stop(); - } } diff -r 2c1c1a161396 -r adb678c592f5 agent/core/src/test/java/com/redhat/thermostat/utils/management/internal/MXBeanConnectorTest.java --- a/agent/core/src/test/java/com/redhat/thermostat/utils/management/internal/MXBeanConnectorTest.java Thu Aug 21 15:21:57 2014 -0400 +++ b/agent/core/src/test/java/com/redhat/thermostat/utils/management/internal/MXBeanConnectorTest.java Tue Dec 16 11:54:58 2014 -0700 @@ -37,7 +37,6 @@ package com.redhat.thermostat.utils.management.internal; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -53,6 +52,8 @@ public class MXBeanConnectorTest { + private static final String JMX_URL = "service:jmx:rmi://myHost:1099/blah"; + private MXBeanConnector connector; private JMXConnectionCreator jmxCreator; private AgentProxyClient client; @@ -61,47 +62,24 @@ public void setup() throws Exception { jmxCreator = mock(JMXConnectionCreator.class); client = mock(AgentProxyClient.class); + when(client.getJMXServiceURL()).thenReturn(JMX_URL); connector = new MXBeanConnector(client, jmxCreator); } @Test public void testInit() throws Exception { - // MXBeanConnector constructor calls createProxy - verify(client).createProxy(); - } - - @Test - public void testAttach() throws Exception { - connector.attach(); - verify(client).attach(); - } - - @Test - public void testIsAttached() throws Exception { - when(client.isAttached()).thenReturn(true); - boolean result = connector.isAttached(); - verify(client).isAttached(); - assertTrue(result); - } - - @Test - public void testClose() throws Exception { - connector.close(); - verify(client).detach(); + // MXBeanConnector constructor calls getJMXServiceURL + verify(client).getJMXServiceURL(); } @Test public void testConnect() throws Exception { - String jmxUrl = "service:jmx:rmi://myHost:1099/blah"; - when(client.getConnectorAddress()).thenReturn(jmxUrl); - JMXConnector jmxConnector = mock(JMXConnector.class); - when(jmxCreator.create(new JMXServiceURL(jmxUrl))).thenReturn(jmxConnector); + when(jmxCreator.create(new JMXServiceURL(JMX_URL))).thenReturn(jmxConnector); MBeanServerConnection connection = mock(MBeanServerConnection.class); when(jmxConnector.getMBeanServerConnection()).thenReturn(connection); MXBeanConnectionImpl result = connector.connect(); - verify(client).getConnectorAddress(); assertEquals(connection, result.get()); } diff -r 2c1c1a161396 -r adb678c592f5 agent/proxy/pom.xml --- a/agent/proxy/pom.xml Thu Aug 21 15:21:57 2014 -0400 +++ b/agent/proxy/pom.xml Tue Dec 16 11:54:58 2014 -0700 @@ -51,7 +51,6 @@ Thermostat Agent Proxy - common server diff -r 2c1c1a161396 -r adb678c592f5 agent/proxy/server/Makefile --- a/agent/proxy/server/Makefile Thu Aug 21 15:21:57 2014 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,41 +0,0 @@ -CC = gcc -JAVAH = javah -MYCFLAGS = -c -Wall -fPIC -MYLDFLAGS = -fPIC -shared -COPY = cp -a - -CLASSPATH = target/classes -TARGET_DIR = target - -INCLUDE = -I $(TARGET_DIR) -I $(JAVA_HOME)/include/ -I $(JAVA_HOME)/include/linux -SOURCES = src/main/native/AgentProxy.c -TARGET = $(TARGET_DIR)/AgentProxy.c -OBJECTS = $(TARGET:.c=.o) - -EXECUTABLE = libAgentProxy.so - -.PHONY: -JNI_LIST = com.redhat.thermostat.agent.proxy.server.AgentProxyNativeUtils - -$(JNI_LIST): - $(JAVAH) -force -classpath $(CLASSPATH) -d $(TARGET_DIR) $(JNI_LIST) - -all: $(JNI_LIST) init $(SOURCES) $(EXECUTABLE) - -.PHONY: -init: - $(COPY) $(SOURCES) $(TARGET) - -$(EXECUTABLE): $(OBJECTS) - $(CC) $(OBJECTS) -o $(TARGET_DIR)/$@ $(MYLDFLAGS) $(LDFLAGS) - -.c.o: - $(CC) $(MYCFLAGS) $(CFLAGS) $(INCLUDE) $< -o $@ - -clean-lib: - rm -f $(TARGET_DIR)/$(EXECUTABLE) - -clean-obj: - rm -f $(OBJECTS) $(TARGET) - -clean: clean-obj clean-lib diff -r 2c1c1a161396 -r adb678c592f5 agent/proxy/server/pom.xml --- a/agent/proxy/server/pom.xml Thu Aug 21 15:21:57 2014 -0400 +++ b/agent/proxy/server/pom.xml Tue Dec 16 11:54:58 2014 -0700 @@ -49,33 +49,6 @@ Thermostat Agent Proxy Server - - - org.codehaus.mojo - exec-maven-plugin - 1.2.1 - - - compile - - exec - - - - - make - - all - - - - JAVA_HOME - ${java.home} - - - - - @@ -110,11 +83,6 @@ com.redhat.thermostat - thermostat-agent-proxy-common - ${project.version} - - - com.redhat.thermostat thermostat-common-core ${project.version} diff -r 2c1c1a161396 -r adb678c592f5 agent/proxy/server/src/main/java/com/redhat/thermostat/agent/proxy/server/AgentProxy.java --- a/agent/proxy/server/src/main/java/com/redhat/thermostat/agent/proxy/server/AgentProxy.java Thu Aug 21 15:21:57 2014 -0400 +++ b/agent/proxy/server/src/main/java/com/redhat/thermostat/agent/proxy/server/AgentProxy.java Tue Dec 16 11:54:58 2014 -0700 @@ -37,50 +37,21 @@ package com.redhat.thermostat.agent.proxy.server; import java.io.IOException; -import java.rmi.NotBoundException; -import java.rmi.RemoteException; -import java.rmi.registry.Registry; -import java.util.Timer; -import java.util.TimerTask; +import java.io.PrintStream; import java.util.logging.Level; import java.util.logging.Logger; -import com.redhat.thermostat.agent.proxy.common.AgentProxyListener; -import com.redhat.thermostat.agent.proxy.common.AgentProxyLogin; import com.redhat.thermostat.common.utils.LoggingUtils; +import com.sun.tools.attach.AttachNotSupportedException; public class AgentProxy { private static final Logger logger = LoggingUtils.getLogger(AgentProxy.class); - private static final long TIMEOUT_MS = 300000L; // 5 minutes should be more than enough - private static final ShutdownListener shutdownListener = new ShutdownListener() { - @Override - public void shutdown() throws RemoteException { - shutdownProxy(); - } - }; - private static final TimerTask timeoutTask = new TimerTask() { - @Override - public void run() { - try { - shutdownProxy(); - logger.warning("Server timed out"); - } catch (RemoteException e) { - logger.log(Level.SEVERE, "Exception while shutting down " - + "timed out server" , e); - } - } - }; - - private static String name = null; + private static int pid = -1; - private static Registry registry = null; - private static boolean bound = false; - private static AgentProxyLogin agent = null; - private static RegistryUtils registryUtils = new RegistryUtils(); - private static AgentProxyNativeUtils nativeUtils = new AgentProxyNativeUtils(); - private static ProcessUserInfoBuilder builder = new ProcessUserInfoBuilder(new ProcDataSource()); - private static Timer timeoutTimer = new Timer(true); + private static AgentProxyControlImpl agent = null; + private static ControlCreator creator = new ControlCreator(); + private static PrintStream outStream = System.out; public static void main(String[] args) { if (args.length < 1) { @@ -94,87 +65,27 @@ usage(); } - // Schedule a timeout - timeoutTimer.schedule(timeoutTask, TIMEOUT_MS); + // Start proxy agent + agent = creator.create(pid); - // Load the native library - nativeUtils.loadLibrary(); - - // Look for registered status listener - AgentProxyListener listener; try { - String listenerName = AgentProxyListener.REMOTE_PREFIX + String.valueOf(pid); - registry = registryUtils.getRegistry(); - listener = (AgentProxyListener) registry.lookup(listenerName); - } catch (RemoteException e) { - throw new RuntimeException("Failed to locate registry", e); - } catch (NotBoundException e) { - throw new RuntimeException("No listener registered", e); - } - - // Start proxy agent - Exception ex = null; - try { - setupProxy(pid); - } catch (Exception e) { - logger.log(Level.SEVERE, "Failed to setup agent proxy for " + pid, e); - ex = e; + agent.attach(); + } catch (AttachNotSupportedException | IOException e) { + logger.log(Level.SEVERE, "Failed to attach to VM (pid: " + pid + ")", e); + return; } - // Notify listener of result - try { - if (ex == null) { - // Success - listener.serverStarted(); - } - else { - // Send exception to client - listener.serverFailedToStart(ex); - } - } catch (RemoteException e) { - throw new RuntimeException("Failed to notify listener", e); - } - } - - private static void setupProxy(int pid) throws Exception { try { - UnixCredentials creds; - try { - creds = builder.build(pid); - } catch (IOException e) { - throw new Exception("Failed to read credentials", e); - } - - try { - // Set UID/GID to owner of target VM - nativeUtils.setCredentials(creds.getUid(), creds.getGid()); - } catch (Exception e) { - throw new Exception("Failed to set credentials to " + creds.getUid() - + ":" + creds.getGid() , e); - } - - agent = new AgentProxyLoginImpl(creds, pid, shutdownListener); - name = AgentProxyLogin.REMOTE_PREFIX + String.valueOf(pid); - AgentProxyLogin stub = (AgentProxyLogin) registryUtils.exportObject(agent); - registry.rebind(name, stub); - bound = true; - logger.info(name + " bound to RMI registry"); - } catch (RemoteException e) { - throw new Exception("Failed to create remote object", e); + String connectorAddress = agent.getConnectorAddress(); + outStream.println(connectorAddress); + } catch (IOException e) { + logger.log(Level.SEVERE, "Failed to retrieve JMX connection URL", e); } - } - - private static void shutdownProxy() throws RemoteException { - // Unbind from RMI registry - if (bound) { - try { - registry.unbind(name); - registryUtils.unexportObject(agent); - logger.info(name + " unbound from RMI registry"); - bound = false; - } catch (NotBoundException e) { - throw new RemoteException("Object not bound", e); - } + + try { + agent.detach(); + } catch (IOException e) { + logger.log(Level.WARNING, "Failed to detach from VM (pid: " + pid + ")", e); } } @@ -182,53 +93,25 @@ throw new RuntimeException("usage: java " + AgentProxy.class.getName() + " "); } - /* - * For testing purposes only. - */ - static AgentProxyLogin getAgentProxyLogin() { - return agent; - } - - /* - * For testing purposes only. - */ - static ShutdownListener getShutdownListener() { - return shutdownListener; + static class ControlCreator { + AgentProxyControlImpl create(int pid) { + return new AgentProxyControlImpl(pid); + } } /* * For testing purposes only. */ - static boolean isBound() { - return bound; - } - - /* - * For testing purposes only. - */ - static void setRegistryUtils(RegistryUtils registryUtils) { - AgentProxy.registryUtils = registryUtils; + static void setControlCreator(ControlCreator creator) { + AgentProxy.creator = creator; } /* * For testing purposes only. */ - static void setNativeUtils(AgentProxyNativeUtils nativeUtils) { - AgentProxy.nativeUtils = nativeUtils; + static void setOutStream(PrintStream stream) { + AgentProxy.outStream = stream; } - /* - * For testing purposes only. - */ - static void setProcessUserInfoBuilder(ProcessUserInfoBuilder builder) { - AgentProxy.builder = builder; - } - - /* - * For testing purposes only. - */ - static void setTimeoutTimer(Timer timeoutTimer) { - AgentProxy.timeoutTimer = timeoutTimer; - } } diff -r 2c1c1a161396 -r adb678c592f5 agent/proxy/server/src/main/java/com/redhat/thermostat/agent/proxy/server/AgentProxyControlImpl.java --- a/agent/proxy/server/src/main/java/com/redhat/thermostat/agent/proxy/server/AgentProxyControlImpl.java Thu Aug 21 15:21:57 2014 -0400 +++ b/agent/proxy/server/src/main/java/com/redhat/thermostat/agent/proxy/server/AgentProxyControlImpl.java Tue Dec 16 11:54:58 2014 -0700 @@ -40,18 +40,14 @@ import java.io.IOException; import java.rmi.RemoteException; import java.util.Properties; -import java.util.Set; import java.util.logging.Logger; -import javax.security.auth.Subject; - +import com.redhat.thermostat.common.utils.LoggingUtils; import com.sun.tools.attach.AgentInitializationException; import com.sun.tools.attach.AgentLoadException; import com.sun.tools.attach.AttachNotSupportedException; import com.sun.tools.attach.VirtualMachine; -import com.redhat.thermostat.common.utils.LoggingUtils; - class AgentProxyControlImpl { private static final Logger logger = LoggingUtils.getLogger(AgentProxyControlImpl.class); @@ -74,65 +70,45 @@ this.vmUtils = vmUtils; } - void attach(Subject user) throws RemoteException, SecurityException { - authCheck(user); - try { - vm = vmUtils.attach(String.valueOf(pid)); - attached = true; - - Properties props = vm.getAgentProperties(); - connectorAddress = props.getProperty(CONNECTOR_ADDRESS_PROPERTY); - if (connectorAddress == null) { - String home = null; - String agent = null; - try { - props = vm.getSystemProperties(); - home = props.getProperty("java.home"); - agent = home + File.separator + "lib" + File.separator + "management-agent.jar"; - logger.fine("Loading '" + agent + "' into VM (pid: " + pid + ")"); - vm.loadAgent(agent); + void attach() throws AttachNotSupportedException, IOException { + vm = vmUtils.attach(String.valueOf(pid)); + attached = true; - props = vm.getAgentProperties(); - connectorAddress = props.getProperty(CONNECTOR_ADDRESS_PROPERTY); - } catch (IOException | AgentLoadException | AgentInitializationException e) { - throw new RemoteException("Failed to load agent ('" + agent + "', from home '" + home + "') into VM (pid: " + pid + ")", e); - } + Properties props = vm.getAgentProperties(); + connectorAddress = props.getProperty(CONNECTOR_ADDRESS_PROPERTY); + if (connectorAddress == null) { + String home = null; + String agent = null; + try { + props = vm.getSystemProperties(); + home = props.getProperty("java.home"); + agent = home + File.separator + "lib" + File.separator + "management-agent.jar"; + logger.fine("Loading '" + agent + "' into VM (pid: " + pid + ")"); + vm.loadAgent(agent); + + props = vm.getAgentProperties(); + connectorAddress = props.getProperty(CONNECTOR_ADDRESS_PROPERTY); + } catch (IOException | AgentLoadException | AgentInitializationException e) { + throw new RemoteException("Failed to load agent ('" + agent + "', from home '" + home + "') into VM (pid: " + pid + ")", e); } - } catch (AttachNotSupportedException | IOException e) { - throw new RemoteException("Failed to attach to VM (pid: " + pid + ")", e); } } - boolean isAttached(Subject user) throws RemoteException, SecurityException { - authCheck(user); + boolean isAttached() { return attached; } - String getConnectorAddress(Subject user) throws RemoteException, SecurityException { - authCheck(user); + String getConnectorAddress() throws IOException { if (!attached) { - throw new RemoteException("Agent not attached to target VM"); + throw new IOException("Agent not attached to target VM"); } return connectorAddress; } - void detach(Subject user) throws RemoteException, SecurityException { - authCheck(user); - try { - if (attached) { - vm.detach(); - attached = false; - } - } catch (IOException e) { - throw new RemoteException("Failed to detach from VM", e); - } - } - - private void authCheck(Subject user) throws SecurityException { - // If we've added our Principal, we've authenticated this user - Set principals = user.getPrincipals(AgentProxyPrincipal.class); - if (principals.isEmpty()) { - throw new SecurityException("Access Denied"); + void detach() throws IOException { + if (attached) { + vm.detach(); + attached = false; } } diff -r 2c1c1a161396 -r adb678c592f5 agent/proxy/server/src/main/java/com/redhat/thermostat/agent/proxy/server/AgentProxyControlWrapper.java --- a/agent/proxy/server/src/main/java/com/redhat/thermostat/agent/proxy/server/AgentProxyControlWrapper.java Thu Aug 21 15:21:57 2014 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,98 +0,0 @@ -/* - * Copyright 2012-2014 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * . - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.agent.proxy.server; - -import java.rmi.RemoteException; - -import javax.security.auth.Subject; -import javax.security.auth.login.LoginException; - -import com.redhat.thermostat.agent.proxy.common.AgentProxyControl; - -class AgentProxyControlWrapper implements AgentProxyControl { - - private final Subject user; - private final AgentProxyLoginContext context; - private final AgentProxyControlImpl impl; - private final ShutdownListener listener; - private final RegistryUtils registryUtils; - - AgentProxyControlWrapper(Subject user, AgentProxyLoginContext context, AgentProxyControlImpl impl, - ShutdownListener listener, RegistryUtils registryUtils) { - this.user = user; - this.context = context; - this.impl = impl; - this.listener = listener; - this.registryUtils = registryUtils; - } - - @Override - public void attach() throws RemoteException, SecurityException { - impl.attach(user); - } - - @Override - public boolean isAttached() throws RemoteException, SecurityException { - return impl.isAttached(user); - } - - @Override - public String getConnectorAddress() throws RemoteException, SecurityException { - return impl.getConnectorAddress(user); - } - - @Override - public void detach() throws RemoteException, SecurityException { - try { - impl.detach(user); - } finally { - try { - // Removes all Principals - context.logout(); - } catch (LoginException e) { - throw new RemoteException("Failed to log out", e); - } - // Unexport this object - registryUtils.unexportObject(this); - - // Shutdown RMI server - listener.shutdown(); - } - } - -} - diff -r 2c1c1a161396 -r adb678c592f5 agent/proxy/server/src/main/java/com/redhat/thermostat/agent/proxy/server/AgentProxyLoginContext.java --- a/agent/proxy/server/src/main/java/com/redhat/thermostat/agent/proxy/server/AgentProxyLoginContext.java Thu Aug 21 15:21:57 2014 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,102 +0,0 @@ -/* - * Copyright 2012-2014 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * . - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.agent.proxy.server; - -import java.io.IOException; - -import javax.security.auth.Subject; -import javax.security.auth.callback.Callback; -import javax.security.auth.callback.CallbackHandler; -import javax.security.auth.callback.UnsupportedCallbackException; -import javax.security.auth.login.LoginContext; -import javax.security.auth.login.LoginException; - -import com.redhat.thermostat.agent.proxy.server.AgentProxyLoginModule.AgentProxyCallback; - -/* - * Wraps both of our LoginModules. - */ -class AgentProxyLoginContext { - - private static final String UNIX_LOGIN_MODULE = "UnixLogin"; - private static final String AGENT_PROXY_LOGIN_MODULE = "AgentProxyLogin"; - - private final LoginContext unixContext; - private final LoginContext context; - - AgentProxyLoginContext(Subject user, UnixCredentials creds) throws LoginException { - this(user, creds, new ContextCreator()); - } - - AgentProxyLoginContext(Subject user, final UnixCredentials creds, ContextCreator creator) throws LoginException { - unixContext = creator.createContext(UNIX_LOGIN_MODULE, user); - context = creator.createContext(AGENT_PROXY_LOGIN_MODULE, user, new CallbackHandler() { - - @Override - public void handle(Callback[] callbacks) throws IOException, - UnsupportedCallbackException { - for (Callback callback : callbacks) { - if (callback instanceof AgentProxyCallback) { - ((AgentProxyCallback) callback).setTargetCredentials(creds); - } - } - } - }); - } - - void login() throws LoginException { - unixContext.login(); - context.login(); - } - - void logout() throws LoginException { - context.logout(); - unixContext.logout(); - } - - static class ContextCreator { - LoginContext createContext(String name, Subject subject) throws LoginException { - return new LoginContext(name, subject); - } - - LoginContext createContext(String name, Subject subject, CallbackHandler handler) throws LoginException { - return new LoginContext(name, subject, handler); - } - } - -} - diff -r 2c1c1a161396 -r adb678c592f5 agent/proxy/server/src/main/java/com/redhat/thermostat/agent/proxy/server/AgentProxyLoginImpl.java --- a/agent/proxy/server/src/main/java/com/redhat/thermostat/agent/proxy/server/AgentProxyLoginImpl.java Thu Aug 21 15:21:57 2014 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,91 +0,0 @@ -/* - * Copyright 2012-2014 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * . - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.agent.proxy.server; - -import java.rmi.RemoteException; - -import javax.security.auth.Subject; -import javax.security.auth.login.LoginException; - -import com.redhat.thermostat.agent.proxy.common.AgentProxyControl; -import com.redhat.thermostat.agent.proxy.common.AgentProxyLogin; - -class AgentProxyLoginImpl implements AgentProxyLogin { - - private final UnixCredentials creds; - private final AgentProxyControlImpl impl; - private final ShutdownListener listener; - private final LoginContextCreator contextCreator; - private final RegistryUtils registryUtils; - - AgentProxyLoginImpl(UnixCredentials creds, int pid, ShutdownListener listener) throws RemoteException { - this(creds, pid, listener, new LoginContextCreator(), new RegistryUtils()); - } - - AgentProxyLoginImpl(UnixCredentials creds, int pid, ShutdownListener listener, - LoginContextCreator contextCreator, RegistryUtils registryUtils) throws RemoteException { - this.creds = creds; - this.impl = new AgentProxyControlImpl(pid); - this.listener = listener; - this.contextCreator = contextCreator; - this.registryUtils = registryUtils; - } - - @Override - public AgentProxyControl login() throws RemoteException, SecurityException { - Subject user = new Subject(); - try { - AgentProxyLoginContext context = contextCreator.createContext(user, creds); - context.login(); - - AgentProxyControl control = new AgentProxyControlWrapper(user, context, impl, - listener, registryUtils); - AgentProxyControl stub = (AgentProxyControl) registryUtils.exportObject(control); - return stub; - } catch (LoginException e) { - throw new RemoteException("Failed to login", e); - } - } - - static class LoginContextCreator { - AgentProxyLoginContext createContext(Subject user, UnixCredentials creds) throws LoginException { - return new AgentProxyLoginContext(user, creds); - } - } - -} - diff -r 2c1c1a161396 -r adb678c592f5 agent/proxy/server/src/main/java/com/redhat/thermostat/agent/proxy/server/AgentProxyLoginModule.java --- a/agent/proxy/server/src/main/java/com/redhat/thermostat/agent/proxy/server/AgentProxyLoginModule.java Thu Aug 21 15:21:57 2014 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,240 +0,0 @@ -/* - * Copyright 2012-2014 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * . - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.agent.proxy.server; - -import java.io.IOException; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.CountDownLatch; - -import javax.security.auth.Subject; -import javax.security.auth.callback.Callback; -import javax.security.auth.callback.CallbackHandler; -import javax.security.auth.callback.UnsupportedCallbackException; -import javax.security.auth.login.LoginException; -import javax.security.auth.spi.LoginModule; - -public class AgentProxyLoginModule implements LoginModule { - - private Subject subject; - private CallbackHandler callbackHandler; - private AgentProxyPrincipal principal; - private boolean loggedIn; - private boolean committed; - private boolean debug; - - interface AgentProxyCallback extends Callback { - - void setTargetCredentials(UnixCredentials creds); - - } - - @Override - public void initialize(Subject subject, CallbackHandler callbackHandler, - Map sharedState, Map options) { - this.subject = subject; - this.callbackHandler = callbackHandler; - - // Check for debug option - debug = "true".equalsIgnoreCase((String) options.get("debug")); - } - - @Override - public boolean login() throws LoginException { - loggedIn = false; - - // Get credentials of target process from callback - UnixCredentials creds = getTargetCredentials(); - - // Verify subject's credentials match those of target process - checkCredentials(creds); - - // Add a custom principal to the subject to show we've authenticated - principal = createPrincipal(); - if (debug) { - System.out.println("\t\t[AgentProxyLoginModule]: " + - "created principal for user: " + principal.getName()); - } - - loggedIn = true; - return true; - } - - private UnixCredentials getTargetCredentials() throws LoginException { - final CountDownLatch latch = new CountDownLatch(1); - final UnixCredentials[] credsContainer = new UnixCredentials[1]; - - try { - callbackHandler.handle(new Callback[] { new AgentProxyCallback() { - - @Override - public void setTargetCredentials(UnixCredentials creds) { - credsContainer[0] = creds; - latch.countDown(); - } - - }}); - - latch.await(); - - return credsContainer[0]; - } catch (IOException e) { - throw new LoginException(e.getMessage()); - } catch (UnsupportedCallbackException e) { - throw new LoginException(e.getMessage()); - } catch (InterruptedException e) { - throw new LoginException("Interrupted"); - } - } - - @Override - public boolean commit() throws LoginException { - committed = false; - - if (loggedIn) { - subject.getPrincipals().add(principal); - if (debug) { - System.out.println("\t\t[AgentProxyLoginModule]: " + - "adding AgentProxyPrincipal to Subject"); - } - committed = true; - } - return committed; - } - - @Override - public boolean abort() throws LoginException { - if (debug) { - System.out.println("\t\t[AgentProxyLoginModule]: " + - "aborted authentication attempt"); - } - if (!loggedIn) { - return false; - } - else if (loggedIn && !committed) { - // Clean up state - loggedIn = false; - principal = null; - } - else { - // Clean up state & remove principal - logout(); - } - - return true; - } - - @Override - public boolean logout() throws LoginException { - // Remove principal - subject.getPrincipals().remove(principal); - if (debug) { - System.out.println("\t\t[AgentProxyLoginModule]: " + - "removed principal for user: " + principal.getName()); - } - - // Clean up state - loggedIn = false; - committed = false; - principal = null; - - return true; - } - - @SuppressWarnings("restriction") - private void checkCredentials(UnixCredentials creds) throws LoginException { - boolean uidOkay = false, gidOkay = false; - - // Check UID - Set userPrincipals = subject.getPrincipals(com.sun.security.auth.UnixNumericUserPrincipal.class); - if (!userPrincipals.isEmpty()) { - com.sun.security.auth.UnixNumericUserPrincipal userPrincipal = userPrincipals.iterator().next(); - if (debug) { - System.out.println("UnixLoginModule UID: " + userPrincipal.longValue() + ", PID: " + creds.getPid() + ", Owner: " + creds.getUid()); - } - if (userPrincipal.longValue() == creds.getUid() || userPrincipal.longValue() == 0) { - uidOkay = true; - } - } - - // Check GID - Set groupPrincipals = subject.getPrincipals(com.sun.security.auth.UnixNumericGroupPrincipal.class); - for (com.sun.security.auth.UnixNumericGroupPrincipal groupPrincipal : groupPrincipals) { - if (groupPrincipal.longValue() == creds.getGid() || groupPrincipal.longValue() == 0) { - gidOkay = true; - } - } - - if (!uidOkay || !gidOkay) { - throw new LoginException("Access Denied"); - } - } - - @SuppressWarnings("restriction") - private AgentProxyPrincipal createPrincipal() throws LoginException { - Set userPrincipals = subject.getPrincipals(com.sun.security.auth.UnixPrincipal.class); - if (userPrincipals.isEmpty()) { - throw new LoginException("Unable to obtain user ID"); - } - - com.sun.security.auth.UnixPrincipal userPrincipal = userPrincipals.iterator().next(); - return new AgentProxyPrincipal(userPrincipal.getName()); - } - - /* - * For testing purposes only. - */ - AgentProxyPrincipal getPrincipal() { - return principal; - } - - /* - * For testing purposes only. - */ - boolean isLoggedIn() { - return loggedIn; - } - - /* - * For testing purposes only. - */ - boolean isCommitted() { - return committed; - } - -} - diff -r 2c1c1a161396 -r adb678c592f5 agent/proxy/server/src/main/java/com/redhat/thermostat/agent/proxy/server/AgentProxyNativeUtils.java --- a/agent/proxy/server/src/main/java/com/redhat/thermostat/agent/proxy/server/AgentProxyNativeUtils.java Thu Aug 21 15:21:57 2014 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,54 +0,0 @@ -/* - * Copyright 2012-2014 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * . - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.agent.proxy.server; - -import com.redhat.thermostat.shared.config.NativeLibraryResolver; -import com.redhat.thermostat.shared.config.internal.CommonPathsImpl; - -class AgentProxyNativeUtils { - - void loadLibrary() { - // TODO if this used OSGi, then we wouldn't need this line - NativeLibraryResolver.setCommonPaths(new CommonPathsImpl()); - String libPath = NativeLibraryResolver.getAbsoluteLibraryPath("AgentProxy"); - System.load(libPath); - } - - native void setCredentials(long uid, long gid) throws Exception; - -} - diff -r 2c1c1a161396 -r adb678c592f5 agent/proxy/server/src/main/java/com/redhat/thermostat/agent/proxy/server/AgentProxyPrincipal.java --- a/agent/proxy/server/src/main/java/com/redhat/thermostat/agent/proxy/server/AgentProxyPrincipal.java Thu Aug 21 15:21:57 2014 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,55 +0,0 @@ -/* - * Copyright 2012-2014 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * . - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.agent.proxy.server; - -import java.security.Principal; - -class AgentProxyPrincipal implements Principal { - - private final String name; - - AgentProxyPrincipal(String name) { - this.name = name; - } - - @Override - public String getName() { - return name; - } - -} - diff -r 2c1c1a161396 -r adb678c592f5 agent/proxy/server/src/main/java/com/redhat/thermostat/agent/proxy/server/ProcDataSource.java --- a/agent/proxy/server/src/main/java/com/redhat/thermostat/agent/proxy/server/ProcDataSource.java Thu Aug 21 15:21:57 2014 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,62 +0,0 @@ -/* - * Copyright 2012-2014 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * . - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.agent.proxy.server; - -import java.io.FileReader; -import java.io.IOException; -import java.io.Reader; - -/** - * Wrapper for files under /proc. See proc(5) for details about this. - */ -class ProcDataSource { - - private static final String PID_STATUS_FILE = "/proc/${pid}/status"; - - /** - * Returns a reader for /proc/$PID/status - */ - Reader getStatusReader(int pid) throws IOException { - return new FileReader(getPidFile(PID_STATUS_FILE, pid)); - } - - private String getPidFile(String fileName, int pid) { - return fileName.replace("${pid}", Integer.toString(pid)); - } - -} - diff -r 2c1c1a161396 -r adb678c592f5 agent/proxy/server/src/main/java/com/redhat/thermostat/agent/proxy/server/ProcessUserInfoBuilder.java --- a/agent/proxy/server/src/main/java/com/redhat/thermostat/agent/proxy/server/ProcessUserInfoBuilder.java Thu Aug 21 15:21:57 2014 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,106 +0,0 @@ -/* - * Copyright 2012-2014 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * . - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.agent.proxy.server; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.Reader; - -class ProcessUserInfoBuilder { - - private static final String PROC_STATUS_UID = "Uid:"; - private static final String PROC_STATUS_GID = "Gid:"; - - private final ProcDataSource source; - - ProcessUserInfoBuilder(ProcDataSource source) { - this.source = source; - } - - UnixCredentials build(int pid) throws IOException { - Reader reader = source.getStatusReader(pid); - UnixCredentials creds = getUidGidFromProcfs(new BufferedReader(reader), pid); - return creds; - } - - /* - * Look for the following lines: - * Uid: - * Gid: - */ - private UnixCredentials getUidGidFromProcfs(BufferedReader br, int pid) throws IOException { - long uid = -1; - long gid = -1; - String line; - while ((line = br.readLine()) != null) { - line = line.trim(); - if (line.startsWith(PROC_STATUS_UID)) { - uid = parseUidGid(line); - } - else if (line.startsWith(PROC_STATUS_GID)) { - gid = parseUidGid(line); - } - } - if (uid < 0) { - throw new IOException("Unable to determine UID from /proc/${pid}/status"); - } - if (gid < 0) { - throw new IOException("Unable to determine GID from /proc/${pid}/status"); - } - - return new UnixCredentials(uid, gid, pid); - } - - private long parseUidGid(String line) throws IOException { - long result = -1; - String[] parts = line.split("\\s+"); - if (parts.length == 5) { - try { - // Use Effective UID/GID - result = Long.parseLong(parts[2]); - } catch (NumberFormatException e) { - throw new IOException("Unexpected output from ps command", e); - } - } - else { - throw new IOException("Expected 5 parts from split /proc/${pid}/status output, got " + parts.length); - } - return result; - } - -} - diff -r 2c1c1a161396 -r adb678c592f5 agent/proxy/server/src/main/java/com/redhat/thermostat/agent/proxy/server/RegistryUtils.java --- a/agent/proxy/server/src/main/java/com/redhat/thermostat/agent/proxy/server/RegistryUtils.java Thu Aug 21 15:21:57 2014 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,26 +0,0 @@ -package com.redhat.thermostat.agent.proxy.server; - -import java.net.InetAddress; -import java.rmi.NoSuchObjectException; -import java.rmi.Remote; -import java.rmi.RemoteException; -import java.rmi.registry.LocateRegistry; -import java.rmi.registry.Registry; -import java.rmi.server.UnicastRemoteObject; - -class RegistryUtils { - - Registry getRegistry() throws RemoteException { - return LocateRegistry.getRegistry(InetAddress.getLoopbackAddress().getHostName()); - } - - Remote exportObject(Remote obj) throws RemoteException { - // Single arg method exports stub instead of real object - return UnicastRemoteObject.exportObject(obj, 0); - } - - void unexportObject(Remote obj) throws NoSuchObjectException { - UnicastRemoteObject.unexportObject(obj, true); - } - -} \ No newline at end of file diff -r 2c1c1a161396 -r adb678c592f5 agent/proxy/server/src/main/java/com/redhat/thermostat/agent/proxy/server/ShutdownListener.java --- a/agent/proxy/server/src/main/java/com/redhat/thermostat/agent/proxy/server/ShutdownListener.java Thu Aug 21 15:21:57 2014 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,46 +0,0 @@ -/* - * Copyright 2012-2014 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * . - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.agent.proxy.server; - -import java.rmi.RemoteException; - -interface ShutdownListener { - - void shutdown() throws RemoteException; - -} - diff -r 2c1c1a161396 -r adb678c592f5 agent/proxy/server/src/main/java/com/redhat/thermostat/agent/proxy/server/UnixCredentials.java --- a/agent/proxy/server/src/main/java/com/redhat/thermostat/agent/proxy/server/UnixCredentials.java Thu Aug 21 15:21:57 2014 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,64 +0,0 @@ -/* - * Copyright 2012-2014 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * . - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.agent.proxy.server; - -class UnixCredentials { - - private final long uid; - private final long gid; - private final int pid; - - UnixCredentials(long uid, long gid, int pid) { - this.uid = uid; - this.gid = gid; - this.pid = pid; - } - - long getUid() { - return uid; - } - - long getGid() { - return gid; - } - - int getPid() { - return pid; - } - -} - diff -r 2c1c1a161396 -r adb678c592f5 agent/proxy/server/src/main/native/AgentProxy.c --- a/agent/proxy/server/src/main/native/AgentProxy.c Thu Aug 21 15:21:57 2014 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,76 +0,0 @@ -/* - * Copyright 2012-2014 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * . - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -#include "com_redhat_thermostat_agent_proxy_server_AgentProxyNativeUtils.h" - -#include -#include -#include - -static jint throw_Exception(JNIEnv *, const char *, const char *); - -JNIEXPORT void JNICALL -Java_com_redhat_thermostat_agent_proxy_server_AgentProxyNativeUtils_setCredentials( - JNIEnv *env, jclass splitAgentKlass, jlong uid, jlong gid) { - int rc; - char *err; - - // Need to setegid before seteuid, or otherwise we've dropped permissions - // needed to do so. - rc = setegid(gid); - if (rc < 0) { - err = strerror(errno); - throw_Exception(env, "java/lang/Exception", err); - } - - rc = seteuid(uid); - if (rc < 0) { - err = strerror(errno); - throw_Exception(env, "java/lang/Exception", err); - } -} - -static jint throw_Exception(JNIEnv *env, const char *class_name, - const char *message) { - jclass class; - - class = (*env)->FindClass(env, class_name); - if (class == NULL) { - return -1; - } - return (*env)->ThrowNew(env, class, message); -} - diff -r 2c1c1a161396 -r adb678c592f5 agent/proxy/server/src/test/java/com/redhat/thermostat/agent/proxy/server/AgentProxyControlImplTest.java --- a/agent/proxy/server/src/test/java/com/redhat/thermostat/agent/proxy/server/AgentProxyControlImplTest.java Thu Aug 21 15:21:57 2014 -0400 +++ b/agent/proxy/server/src/test/java/com/redhat/thermostat/agent/proxy/server/AgentProxyControlImplTest.java Tue Dec 16 11:54:58 2014 -0700 @@ -47,11 +47,9 @@ import static org.mockito.Mockito.when; import java.io.File; -import java.rmi.RemoteException; +import java.io.IOException; import java.util.Properties; -import javax.security.auth.Subject; - import org.junit.Before; import org.junit.Test; @@ -84,9 +82,7 @@ @Test public void testAttach() throws Exception { - Subject subject = new Subject(); - addPrincipal(subject); - control.attach(subject); + control.attach(); verify(vmUtils).attach("0"); verify(vm, times(2)).getAgentProperties(); @@ -94,80 +90,37 @@ verify(vm).loadAgent("/path/to/java/home" + File.separator + "lib" + File.separator + "management-agent.jar"); } - @Test(expected=SecurityException.class) - public void testAttachDenied() throws Exception { - Subject subject = new Subject(); - control.attach(subject); - } - @Test public void testIsAttached() throws Exception { - Subject subject = new Subject(); - addPrincipal(subject); - - assertFalse(control.isAttached(subject)); - control.attach(subject); - assertTrue(control.isAttached(subject)); - } - - @Test(expected=SecurityException.class) - public void testIsAttachedDenied() throws Exception { - Subject subject = new Subject(); - control.isAttached(subject); + assertFalse(control.isAttached()); + control.attach(); + assertTrue(control.isAttached()); } @Test public void testGetAddress() throws Exception { - Subject subject = new Subject(); - addPrincipal(subject); - - control.attach(subject); - String addr = control.getConnectorAddress(subject); + control.attach(); + String addr = control.getConnectorAddress(); assertEquals("myJmxUrl", addr); } - @Test(expected=SecurityException.class) - public void testGetAddressDenied() throws Exception { - Subject subject = new Subject(); - control.getConnectorAddress(subject); - } - - @Test(expected=RemoteException.class) + @Test(expected=IOException.class) public void testGetAddressNotAttached() throws Exception { - Subject subject = new Subject(); - addPrincipal(subject); - - control.getConnectorAddress(subject); + control.getConnectorAddress(); } @Test public void testDetach() throws Exception { - Subject subject = new Subject(); - addPrincipal(subject); - - control.attach(subject); - control.detach(subject); + control.attach(); + control.detach(); verify(vm).detach(); } @Test public void testDetachNotAttached() throws Exception { - Subject subject = new Subject(); - addPrincipal(subject); - - control.detach(subject); + control.detach(); verify(vm, never()).detach(); } - @Test(expected=SecurityException.class) - public void testDetachDenied() throws Exception { - Subject subject = new Subject(); - control.detach(subject); - } - - private void addPrincipal(Subject subject) { - subject.getPrincipals().add(new AgentProxyPrincipal("TEST")); - } - } diff -r 2c1c1a161396 -r adb678c592f5 agent/proxy/server/src/test/java/com/redhat/thermostat/agent/proxy/server/AgentProxyControlWrapperTest.java --- a/agent/proxy/server/src/test/java/com/redhat/thermostat/agent/proxy/server/AgentProxyControlWrapperTest.java Thu Aug 21 15:21:57 2014 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,95 +0,0 @@ -/* - * Copyright 2012-2014 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * . - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.agent.proxy.server; - -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; - -import javax.security.auth.Subject; - -import org.junit.Before; -import org.junit.Test; - -public class AgentProxyControlWrapperTest { - - private AgentProxyControlWrapper control; - private AgentProxyControlImpl impl; - private Subject user; - private AgentProxyLoginContext context; - private ShutdownListener listener; - private RegistryUtils registryUtils; - - @Before - public void setup() throws Exception { - user = new Subject(); - context = mock(AgentProxyLoginContext.class); - impl = mock(AgentProxyControlImpl.class); - listener = mock(ShutdownListener.class); - registryUtils = mock(RegistryUtils.class); - control = new AgentProxyControlWrapper(user, context, impl, listener, registryUtils); - } - - @Test - public void testAttach() throws Exception { - control.attach(); - verify(impl).attach(user); - } - - @Test - public void testIsAttached() throws Exception { - control.isAttached(); - verify(impl).isAttached(user); - } - - @Test - public void testGetAddress() throws Exception { - control.getConnectorAddress(); - verify(impl).getConnectorAddress(user); - } - - @Test - public void testDetach() throws Exception { - control.detach(); - - verify(impl).detach(user); - verify(context).logout(); - verify(listener).shutdown(); - verify(registryUtils).unexportObject(control); - } - -} - diff -r 2c1c1a161396 -r adb678c592f5 agent/proxy/server/src/test/java/com/redhat/thermostat/agent/proxy/server/AgentProxyLoginContextTest.java --- a/agent/proxy/server/src/test/java/com/redhat/thermostat/agent/proxy/server/AgentProxyLoginContextTest.java Thu Aug 21 15:21:57 2014 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,106 +0,0 @@ -/* - * Copyright 2012-2014 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * . - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.agent.proxy.server; - -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.eq; -import static org.mockito.Matchers.same; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import javax.security.auth.Subject; -import javax.security.auth.callback.Callback; -import javax.security.auth.callback.CallbackHandler; -import javax.security.auth.login.LoginContext; - -import org.junit.Before; -import org.junit.Test; -import org.mockito.ArgumentCaptor; - -import com.redhat.thermostat.agent.proxy.server.AgentProxyLoginContext.ContextCreator; -import com.redhat.thermostat.agent.proxy.server.AgentProxyLoginModule.AgentProxyCallback; - -public class AgentProxyLoginContextTest { - - private AgentProxyLoginContext context; - private ContextCreator creator; - private Subject user; - private UnixCredentials creds; - private LoginContext unixContext; - private LoginContext ourContext; - - @Before - public void setup() throws Exception { - user = new Subject(); - creds = new UnixCredentials(9000, 9001, 0); - creator = mock(ContextCreator.class); - unixContext = mock(LoginContext.class); - ourContext = mock(LoginContext.class); - when(creator.createContext("UnixLogin", user)).thenReturn(unixContext); - when(creator.createContext(eq("AgentProxyLogin"), same(user), any(CallbackHandler.class))).thenReturn(ourContext); - context = new AgentProxyLoginContext(user, creds, creator); - } - - @Test - public void testCreate() throws Exception { - verify(creator).createContext("UnixLogin", user); - ArgumentCaptor captor = ArgumentCaptor.forClass(CallbackHandler.class); - verify(creator).createContext(eq("AgentProxyLogin"), same(user), captor.capture()); - CallbackHandler handler = captor.getValue(); - - AgentProxyCallback callback = mock(AgentProxyCallback.class); - handler.handle(new Callback[] { callback }); - verify(callback).setTargetCredentials(creds); - } - - @Test - public void testLogin() throws Exception { - context.login(); - verify(unixContext).login(); - verify(ourContext).login(); - } - - @Test - public void testLogout() throws Exception { - context.logout(); - verify(ourContext).logout(); - verify(unixContext).logout(); - } - -} - diff -r 2c1c1a161396 -r adb678c592f5 agent/proxy/server/src/test/java/com/redhat/thermostat/agent/proxy/server/AgentProxyLoginImplTest.java --- a/agent/proxy/server/src/test/java/com/redhat/thermostat/agent/proxy/server/AgentProxyLoginImplTest.java Thu Aug 21 15:21:57 2014 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,118 +0,0 @@ -/* - * Copyright 2012-2014 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * . - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.agent.proxy.server; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.same; -import static org.mockito.Mockito.doThrow; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.rmi.RemoteException; -import java.rmi.registry.Registry; - -import javax.security.auth.Subject; -import javax.security.auth.login.LoginException; - -import org.junit.Before; -import org.junit.Test; -import org.mockito.ArgumentCaptor; - -import com.redhat.thermostat.agent.proxy.common.AgentProxyControl; -import com.redhat.thermostat.agent.proxy.server.AgentProxyLoginImpl.LoginContextCreator; - -public class AgentProxyLoginImplTest { - - private RegistryUtils registryUtils; - private Registry registry; - private UnixCredentials creds; - private LoginContextCreator contextCreator; - private AgentProxyLoginContext context; - - @Before - public void setup() throws Exception { - registry = mock(Registry.class); - registryUtils = mock(RegistryUtils.class); - when(registryUtils.getRegistry()).thenReturn(registry); - creds = new UnixCredentials(9000, 9001, 0); - contextCreator = mock(LoginContextCreator.class); - context = mock(AgentProxyLoginContext.class); - when(contextCreator.createContext(any(Subject.class), same(creds))).thenReturn(context); - } - - @Test - public void testLoginSuccess() throws Exception { - ShutdownListener listener = mock(ShutdownListener.class); - AgentProxyLoginImpl proxyLogin = new AgentProxyLoginImpl(creds, 0, listener, contextCreator, registryUtils); - AgentProxyControl stub = proxyLogin.login(); - - ArgumentCaptor captor = ArgumentCaptor.forClass(AgentProxyControl.class); - verify(registryUtils).exportObject(captor.capture()); - AgentProxyControl control = captor.getValue(); - - assertTrue(control instanceof AgentProxyControlWrapper); - assertFalse(stub instanceof AgentProxyControlWrapper); - } - - @Test - public void testLoginFailure() throws Exception { - ShutdownListener listener = mock(ShutdownListener.class); - - // Simulate login failure - LoginException ex = new LoginException("TEST"); - doThrow(ex).when(context).login(); - - AgentProxyLoginImpl proxyLogin = new AgentProxyLoginImpl(creds, 0, listener, contextCreator, registryUtils); - - try { - proxyLogin.login(); - fail("Expected exception from login"); - } catch (RemoteException e) { - assertEquals(ex, e.getCause()); - } - - verify(registryUtils, never()).exportObject(any(AgentProxyControl.class)); - } - -} - diff -r 2c1c1a161396 -r adb678c592f5 agent/proxy/server/src/test/java/com/redhat/thermostat/agent/proxy/server/AgentProxyLoginModuleTest.java --- a/agent/proxy/server/src/test/java/com/redhat/thermostat/agent/proxy/server/AgentProxyLoginModuleTest.java Thu Aug 21 15:21:57 2014 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,247 +0,0 @@ -/* - * Copyright 2012-2014 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * . - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.agent.proxy.server; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import static org.mockito.Mockito.*; - -import java.util.HashMap; -import java.util.Set; - -import javax.security.auth.Subject; -import javax.security.auth.callback.Callback; -import javax.security.auth.callback.CallbackHandler; -import javax.security.auth.login.LoginException; - -import org.junit.Before; -import org.junit.Test; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.stubbing.Answer; - -import com.redhat.thermostat.agent.proxy.server.AgentProxyLoginModule.AgentProxyCallback; - -public class AgentProxyLoginModuleTest { - - private AgentProxyLoginModule module; - private CallbackHandler handler; - private Subject subject; - - @Before - public void setup() throws Exception { - module = new AgentProxyLoginModule(); - subject = new Subject(); - handler = mock(CallbackHandler.class); - final UnixCredentials creds = new UnixCredentials(9000, 9001, 0); - doAnswer(new Answer() { - @Override - public Void answer(InvocationOnMock invocation) throws Throwable { - Callback[] callbacks = (Callback[]) invocation.getArguments()[0]; - for (Callback callback : callbacks) { - if (callback instanceof AgentProxyCallback) { - ((AgentProxyCallback) callback).setTargetCredentials(creds); - } - } - return null; - } - }).when(handler).handle(any(Callback[].class)); - module.initialize(subject, handler, new HashMap(), new HashMap()); - } - - @Test - public void testLoginSuccess() throws Exception { - addPrincipals(); - - assertTrue(module.login()); - - AgentProxyPrincipal principal = module.getPrincipal(); - assertNotNull(principal); - assertEquals("TEST", principal.getName()); - assertTrue(module.isLoggedIn()); - assertFalse(module.isCommitted()); - assertTrue(subject.getPrincipals(AgentProxyPrincipal.class).isEmpty()); - } - - @SuppressWarnings("restriction") - @Test - public void testLoginBadUid() throws Exception { - subject.getPrincipals().add(new com.sun.security.auth.UnixPrincipal("TEST")); - subject.getPrincipals().add(new com.sun.security.auth.UnixNumericUserPrincipal(8000)); - subject.getPrincipals().add(new com.sun.security.auth.UnixNumericGroupPrincipal(9001, true)); - - verifyFailedLogin(); - } - - @SuppressWarnings("restriction") - @Test - public void testLoginMissingUid() throws Exception { - subject.getPrincipals().add(new com.sun.security.auth.UnixPrincipal("TEST")); - subject.getPrincipals().add(new com.sun.security.auth.UnixNumericGroupPrincipal(9001, true)); - - verifyFailedLogin(); - } - - @SuppressWarnings("restriction") - @Test - public void testLoginBadGid() throws Exception { - subject.getPrincipals().add(new com.sun.security.auth.UnixPrincipal("TEST")); - subject.getPrincipals().add(new com.sun.security.auth.UnixNumericUserPrincipal(9000)); - subject.getPrincipals().add(new com.sun.security.auth.UnixNumericGroupPrincipal(8001, true)); - - verifyFailedLogin(); - } - - @SuppressWarnings("restriction") - @Test - public void testLoginMissingGid() throws Exception { - subject.getPrincipals().add(new com.sun.security.auth.UnixPrincipal("TEST")); - subject.getPrincipals().add(new com.sun.security.auth.UnixNumericUserPrincipal(9000)); - - verifyFailedLogin(); - } - - @SuppressWarnings("restriction") - @Test - public void testLoginMissingUsername() throws Exception { - subject.getPrincipals().add(new com.sun.security.auth.UnixNumericUserPrincipal(9000)); - subject.getPrincipals().add(new com.sun.security.auth.UnixNumericGroupPrincipal(9001, true)); - - verifyFailedLogin(); - } - - @Test - public void testCommitSuccess() throws Exception { - addPrincipals(); - - assertTrue(module.login()); - assertTrue(module.commit()); - - assertTrue(module.isLoggedIn()); - assertTrue(module.isCommitted()); - Set principals = subject.getPrincipals(AgentProxyPrincipal.class); - assertFalse(principals.isEmpty()); - assertEquals(module.getPrincipal(), principals.iterator().next()); - } - - @Test - public void testCommitNotLoggedIn() throws Exception { - addPrincipals(); - - assertFalse(module.commit()); - - assertFalse(module.isLoggedIn()); - assertFalse(module.isCommitted()); - assertTrue(subject.getPrincipals(AgentProxyPrincipal.class).isEmpty()); - } - - @Test - public void testAbortNotLoggedIn() throws Exception { - addPrincipals(); - - assertFalse(module.abort()); - - verifyStateReset(); - } - - @Test - public void testAbortNotCommitted() throws Exception { - addPrincipals(); - - assertTrue(module.login()); - assertTrue(module.abort()); - - verifyStateReset(); - } - - @Test - public void testAbortCommitted() throws Exception { - addPrincipals(); - - assertTrue(module.login()); - assertTrue(module.commit()); - assertTrue(module.abort()); - - verifyStateReset(); - } - - @Test - public void testLogout() throws Exception { - addPrincipals(); - - assertTrue(module.login()); - assertTrue(module.commit()); - assertTrue(module.logout()); - - verifyStateReset(); - } - - @SuppressWarnings("restriction") - private void addPrincipals() { - subject.getPrincipals().add(new com.sun.security.auth.UnixPrincipal("TEST")); - subject.getPrincipals().add(new com.sun.security.auth.UnixNumericUserPrincipal(9000)); - subject.getPrincipals().add(new com.sun.security.auth.UnixNumericGroupPrincipal(9001, true)); - } - - private void verifyFailedLogin() { - try { - module.login(); - fail("Expected LoginException"); - } catch (LoginException e) { - assertFalse(module.isLoggedIn()); - assertNull(module.getPrincipal()); - assertFalse(module.isCommitted()); - assertTrue(subject.getPrincipals(AgentProxyPrincipal.class).isEmpty()); - } - } - - @SuppressWarnings("restriction") - private void verifyStateReset() { - assertFalse(module.isLoggedIn()); - assertFalse(module.isCommitted()); - assertNull(module.getPrincipal()); - assertTrue(subject.getPrincipals(AgentProxyPrincipal.class).isEmpty()); - assertFalse(subject.getPrincipals(com.sun.security.auth.UnixPrincipal.class).isEmpty()); - assertFalse(subject.getPrincipals(com.sun.security.auth.UnixNumericUserPrincipal.class).isEmpty()); - assertFalse(subject.getPrincipals(com.sun.security.auth.UnixNumericGroupPrincipal.class).isEmpty()); - } - -} - diff -r 2c1c1a161396 -r adb678c592f5 agent/proxy/server/src/test/java/com/redhat/thermostat/agent/proxy/server/AgentProxyTest.java --- a/agent/proxy/server/src/test/java/com/redhat/thermostat/agent/proxy/server/AgentProxyTest.java Thu Aug 21 15:21:57 2014 -0400 +++ b/agent/proxy/server/src/test/java/com/redhat/thermostat/agent/proxy/server/AgentProxyTest.java Tue Dec 16 11:54:58 2014 -0700 @@ -36,106 +36,99 @@ package com.redhat.thermostat.agent.proxy.server; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.mockito.Matchers.any; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import java.rmi.RemoteException; -import java.rmi.registry.Registry; -import java.util.Timer; -import java.util.TimerTask; +import java.io.IOException; +import java.io.PrintStream; +import org.junit.After; import org.junit.Before; import org.junit.Test; -import org.mockito.ArgumentCaptor; -import com.redhat.thermostat.agent.proxy.common.AgentProxyListener; -import com.redhat.thermostat.agent.proxy.common.AgentProxyLogin; +import com.redhat.thermostat.agent.proxy.server.AgentProxy.ControlCreator; public class AgentProxyTest { - private AgentProxyNativeUtils nativeUtils; - private RegistryUtils registryUtils; - private Registry registry; - private AgentProxyLogin loginStub; - private AgentProxyListener listener; - private Timer timeoutTimer; + private static final String JMX_URL = "service:jmx:rmi://myHost:1099/blah"; + + private AgentProxyControlImpl control; + private PrintStream outStream; @Before public void setup() throws Exception { - registry = mock(Registry.class); - listener = mock(AgentProxyListener.class); - when(registry.lookup(AgentProxyListener.REMOTE_PREFIX + "0")).thenReturn(listener); - registryUtils = mock(RegistryUtils.class); - when(registryUtils.getRegistry()).thenReturn(registry); - loginStub = mock(AgentProxyLogin.class); - when(registryUtils.exportObject(any(AgentProxyLogin.class))).thenReturn(loginStub); - - nativeUtils = mock(AgentProxyNativeUtils.class); - ProcessUserInfoBuilder builder = mock(ProcessUserInfoBuilder.class); - when(builder.build(0)).thenReturn(new UnixCredentials(9000, 9001, 0)); - timeoutTimer = mock(Timer.class); - AgentProxy.setRegistryUtils(registryUtils); - AgentProxy.setNativeUtils(nativeUtils); - AgentProxy.setProcessUserInfoBuilder(builder); - AgentProxy.setTimeoutTimer(timeoutTimer); + ControlCreator creator = mock(ControlCreator.class); + control = mock(AgentProxyControlImpl.class); + when(control.getConnectorAddress()).thenReturn(JMX_URL); + outStream = mock(PrintStream.class); + when(creator.create(0)).thenReturn(control); + AgentProxy.setControlCreator(creator); + AgentProxy.setOutStream(outStream); + } + + @After + public void teardown() throws Exception { + AgentProxy.setControlCreator(new ControlCreator()); + AgentProxy.setOutStream(System.out); } @Test public void testMainSuccess() throws Exception { - assertFalse(AgentProxy.isBound()); + // Invoke main with PID of 0 + AgentProxy.main(new String[] { "0" }); + + verify(control).attach(); + verify(control).getConnectorAddress(); + verify(control).detach(); + verify(outStream).println(JMX_URL); + } + + @Test + public void testMainAttachFails() throws Exception { + // Simulate failure binding the login object + doThrow(new IOException()).when(control).attach(); // Invoke main with PID of 0 AgentProxy.main(new String[] { "0" }); - assertTrue(AgentProxy.isBound()); - - // Verify timeout set - verify(timeoutTimer).schedule(any(TimerTask.class), any(Long.class)); - - // Verify native library loaded and credentials properly set - verify(nativeUtils).loadLibrary(); - verify(nativeUtils).setCredentials(9000, 9001); - - // Verify login object exported - AgentProxyLogin proxyLogin = AgentProxy.getAgentProxyLogin(); - verify(registryUtils).exportObject(proxyLogin); - verify(registry).rebind(AgentProxyLogin.REMOTE_PREFIX + "0", loginStub); - - // Verify listener notified with positive response - verify(listener).serverStarted(); - - // Shutdown server - ShutdownListener shutdownListener = AgentProxy.getShutdownListener(); - shutdownListener.shutdown(); - - // Verify login object unexported - verify(registry).unbind(AgentProxyLogin.REMOTE_PREFIX + "0"); - verify(registryUtils).unexportObject(proxyLogin); - - assertFalse(AgentProxy.isBound()); + verify(control).attach(); + verify(control, never()).getConnectorAddress(); + verify(control, never()).detach(); + verify(outStream, never()).println(JMX_URL); } @Test - public void testMainFailure() throws Exception { + public void testMainGetAddressFails() throws Exception { // Simulate failure binding the login object - RemoteException ex = new RemoteException("TEST"); - doThrow(ex).when(registry).rebind(AgentProxyLogin.REMOTE_PREFIX + "0", loginStub); + doThrow(new IOException()).when(control).getConnectorAddress(); // Invoke main with PID of 0 AgentProxy.main(new String[] { "0" }); - // Verify listener notified with negative response - ArgumentCaptor errorCaptor = ArgumentCaptor.forClass(Exception.class); - verify(listener).serverFailedToStart(errorCaptor.capture()); - assertEquals(ex, errorCaptor.getValue().getCause()); + verify(control).attach(); + verify(control).getConnectorAddress(); - assertFalse(AgentProxy.isBound()); + // Should detach, but not print URL + verify(control).detach(); + verify(outStream, never()).println(JMX_URL); + } + + @Test + public void testMainDetachFails() throws Exception { + // Simulate failure binding the login object + doThrow(new IOException()).when(control).detach(); + + // Invoke main with PID of 0 + AgentProxy.main(new String[] { "0" }); + + // All should be called + verify(control).attach(); + verify(control).getConnectorAddress(); + verify(control).detach(); + verify(outStream).println(JMX_URL); } } diff -r 2c1c1a161396 -r adb678c592f5 agent/proxy/server/src/test/java/com/redhat/thermostat/agent/proxy/server/ProcessUserInfoBuilderTest.java --- a/agent/proxy/server/src/test/java/com/redhat/thermostat/agent/proxy/server/ProcessUserInfoBuilderTest.java Thu Aug 21 15:21:57 2014 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,85 +0,0 @@ -/* - * Copyright 2012-2014 Red Hat, Inc. - * - * This file is part of Thermostat. - * - * Thermostat is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published - * by the Free Software Foundation; either version 2, or (at your - * option) any later version. - * - * Thermostat is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Thermostat; see the file COPYING. If not see - * . - * - * Linking this code with other modules is making a combined work - * based on this code. Thus, the terms and conditions of the GNU - * General Public License cover the whole combination. - * - * As a special exception, the copyright holders of this code give - * you permission to link this code with independent modules to - * produce an executable, regardless of the license terms of these - * independent modules, and to copy and distribute the resulting - * executable under terms of your choice, provided that you also - * meet, for each linked independent module, the terms and conditions - * of the license of that module. An independent module is a module - * which is not derived from or based on this code. If you modify - * this code, you may extend this exception to your version of the - * library, but you are not obligated to do so. If you do not wish - * to do so, delete this exception statement from your version. - */ - -package com.redhat.thermostat.agent.proxy.server; - -import static org.junit.Assert.assertEquals; -import static org.mockito.Matchers.anyInt; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import java.io.IOException; -import java.io.StringReader; - -import org.junit.Test; - -import com.redhat.thermostat.common.tools.ApplicationException; - -public class ProcessUserInfoBuilderTest { - - @Test - public void testBuild() throws IOException { - StringReader reader = new StringReader("Uid: 2000 2000 2000 2000\nGid: 2001 2001 2001 2001"); - ProcDataSource source = mock(ProcDataSource.class); - when(source.getStatusReader(anyInt())).thenReturn(reader); - ProcessUserInfoBuilder builder = new ProcessUserInfoBuilder(source); - UnixCredentials creds = builder.build(1); - - assertEquals(2000, creds.getUid()); - assertEquals(2001, creds.getGid()); - assertEquals(1, creds.getPid()); - } - - @Test(expected=IOException.class) - public void testBuildErrorUid() throws IOException, ApplicationException { - StringReader reader = new StringReader("Gid: 2001 2001 2001 2001"); - ProcDataSource source = mock(ProcDataSource.class); - when(source.getStatusReader(anyInt())).thenReturn(reader); - ProcessUserInfoBuilder builder = new ProcessUserInfoBuilder(source); - builder.build(0); - } - - @Test(expected=IOException.class) - public void testBuildErrorGid() throws IOException, ApplicationException { - StringReader reader = new StringReader("Uid: 2000 2000 2000 2000"); - ProcDataSource source = mock(ProcDataSource.class); - when(source.getStatusReader(anyInt())).thenReturn(reader); - ProcessUserInfoBuilder builder = new ProcessUserInfoBuilder(source); - builder.build(0); - } - -} - diff -r 2c1c1a161396 -r adb678c592f5 distribution/assembly/core-assembly.xml --- a/distribution/assembly/core-assembly.xml Thu Aug 21 15:21:57 2014 -0400 +++ b/distribution/assembly/core-assembly.xml Tue Dec 16 11:54:58 2014 -0700 @@ -59,7 +59,6 @@ com.redhat.thermostat:thermostat-agent-core com.redhat.thermostat:thermostat-agent-cli com.redhat.thermostat:thermostat-agent-command - com.redhat.thermostat:thermostat-agent-proxy-common com.redhat.thermostat:thermostat-agent-proxy-server com.redhat.thermostat:thermostat-killvm-agent com.redhat.thermostat:thermostat-killvm-client-swing diff -r 2c1c1a161396 -r adb678c592f5 distribution/config/agent_proxy_jaas.conf --- a/distribution/config/agent_proxy_jaas.conf Thu Aug 21 15:21:57 2014 -0400 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,7 +0,0 @@ -UnixLogin { - com.sun.security.auth.module.UnixLoginModule required debug=false; -}; - -AgentProxyLogin { - com.redhat.thermostat.agent.proxy.server.AgentProxyLoginModule required debug=false; -}; diff -r 2c1c1a161396 -r adb678c592f5 distribution/config/commands/agent.properties --- a/distribution/config/commands/agent.properties Thu Aug 21 15:21:57 2014 -0400 +++ b/distribution/config/commands/agent.properties Tue Dec 16 11:54:58 2014 -0700 @@ -7,7 +7,6 @@ com.redhat.thermostat.process=${project.version}, \ com.redhat.thermostat.common.core=${project.version}, \ com.redhat.thermostat.agent.cli=${project.version}, \ - com.redhat.thermostat.agent.proxy.common=${project.version}, \ com.redhat.thermostat.common.command=${project.version}, \ com.redhat.thermostat.agent.command=${project.version}, \ com.redhat.thermostat.killvm.agent=${project.version}, \ diff -r 2c1c1a161396 -r adb678c592f5 distribution/config/commands/service.properties --- a/distribution/config/commands/service.properties Thu Aug 21 15:21:57 2014 -0400 +++ b/distribution/config/commands/service.properties Tue Dec 16 11:54:58 2014 -0700 @@ -10,7 +10,6 @@ com.redhat.thermostat.agent.command=${project.version}, \ com.redhat.thermostat.storage.cli=${project.version}, \ com.redhat.thermostat.agent.cli=${project.version}, \ - com.redhat.thermostat.agent.proxy.common=${project.version}, \ org.jboss.netty=${netty.version} description = starts and stops the thermostat storage and agent diff -r 2c1c1a161396 -r adb678c592f5 distribution/pom.xml --- a/distribution/pom.xml Thu Aug 21 15:21:57 2014 -0400 +++ b/distribution/pom.xml Tue Dec 16 11:54:58 2014 -0700 @@ -145,7 +145,6 @@ thermostat-users.properties thermostat-roles.properties thermostat_jaas.conf - agent_proxy_jaas.conf db.properties logging.properties osgi-export.properties @@ -209,8 +208,6 @@ todir="${project.build.directory}/image/libs/native" /> - diff -r 2c1c1a161396 -r adb678c592f5 distribution/scripts/thermostat --- a/distribution/scripts/thermostat Thu Aug 21 15:21:57 2014 -0400 +++ b/distribution/scripts/thermostat Tue Dec 16 11:54:58 2014 -0700 @@ -60,8 +60,6 @@ SERVICE_CLASSPATH="${SERVICE_CLASSPATH}:${THERMOSTAT_LIBS}/thermostat-launcher-@project.version@.jar" SERVICE_CLASSPATH="${SERVICE_CLASSPATH}:${THERMOSTAT_LIBS}/thermostat-main-@project.version@.jar" SERVICE_CLASSPATH="${SERVICE_CLASSPATH}:${THERMOSTAT_LIBS}/thermostat-shared-config-@project.version@.jar" -# This needs to be on the classpath for the RMI registry to find it -SERVICE_CLASSPATH="${SERVICE_CLASSPATH}:${THERMOSTAT_LIBS}/thermostat-agent-proxy-common-@project.version@.jar" # FIXME: Remove once jfreechart is a real OSGi bundle upstream SERVICE_CLASSPATH="${SERVICE_CLASSPATH}:${THERMOSTAT_LIBS}/jfreechart-@jfreechart.version@.jar" SERVICE_CLASSPATH="${SERVICE_CLASSPATH}:${THERMOSTAT_LIBS}/jcommon-@jcommon.version@.jar" diff -r 2c1c1a161396 -r adb678c592f5 distribution/scripts/thermostat-agent-proxy --- a/distribution/scripts/thermostat-agent-proxy Thu Aug 21 15:21:57 2014 -0400 +++ b/distribution/scripts/thermostat-agent-proxy Tue Dec 16 11:54:58 2014 -0700 @@ -40,6 +40,10 @@ JAVA_DIR="@java.dir@" JAVA="@java.home@/bin/java" +if [ "$#" -lt 2 ]; then + echo "usage: $0 " >&2 +fi + if [ x"$THERMOSTAT_INSTALL_DIR" = x ] ; then THERMOSTAT_INSTALL_DIR="@thermostat.home@" fi @@ -56,20 +60,20 @@ # JARs necessary for the server SERVICE_CLASSPATH="${THERMOSTAT_LIBS}/thermostat-common-core-@project.version@.jar" SERVICE_CLASSPATH="${SERVICE_CLASSPATH}:${THERMOSTAT_LIBS}/thermostat-shared-config-@project.version@.jar" -SERVICE_CLASSPATH="${SERVICE_CLASSPATH}:${THERMOSTAT_LIBS}/thermostat-agent-proxy-common-@project.version@.jar" SERVICE_CLASSPATH="${SERVICE_CLASSPATH}:${THERMOSTAT_LIBS}/thermostat-agent-proxy-server-@project.version@.jar" SERVICE_CLASSPATH="${TOOLS_JAR}:${SERVICE_CLASSPATH}" AGENT_PROXY_CLASS="com.redhat.thermostat.agent.proxy.server.AgentProxy" -JAAS_CONFIG="${THERMOSTAT_HOME}/etc/agent_proxy_jaas.conf" - # Set this to remote debug if [ x"$THERMOSTAT_DEBUG" != x ] ; then DEBUG_OPTS="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,address=1082" fi # Start server -${JAVA} -cp ${SERVICE_CLASSPATH} ${DEBUG_OPTS} "-Djava.security.auth.login.config=${JAAS_CONFIG}" \ -"-Djava.rmi.server.randomIDs=true" ${AGENT_PROXY_CLASS} "$1" - +# Drop permissions, if root +if [ "$(/bin/id -u)" -eq 0 ]; then + /bin/su "$2" -c "${JAVA} -cp ${SERVICE_CLASSPATH} ${DEBUG_OPTS} ${AGENT_PROXY_CLASS} $1" +else + ${JAVA} -cp ${SERVICE_CLASSPATH} ${DEBUG_OPTS} ${AGENT_PROXY_CLASS} $1 +fi