changeset 1641:7dc6a2862f7b

Remove RMI from Thermostat Agent 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. This patch removes RMI communication between the agent and agent proxy, and converts the agent proxy into a non-interactive process. Given the process ID, the agent proxy will attach to the VM, retrieve the JMX service URL, and detach from the VM. The agent proxy then prints the JMX service URL to stdout, which is consumed by the agent. This simpler approach fulfills the current requirements for the agent proxy and does so without any insecure RMI communication. Reviewed-by: vanaltj Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2014-December/012320.html CVE-2014-8120 PR2154
author Elliott Baron <ebaron@redhat.com>
date Tue, 16 Dec 2014 16:00:40 -0500
parents 9198df881601
children 0d3f0fb73304
files agent/core/pom.xml agent/core/src/main/java/com/redhat/thermostat/agent/RMIRegistry.java agent/core/src/main/java/com/redhat/thermostat/agent/internal/Activator.java agent/core/src/main/java/com/redhat/thermostat/agent/internal/RMIRegistryImpl.java agent/core/src/main/java/com/redhat/thermostat/utils/management/internal/AgentProxyClient.java agent/core/src/main/java/com/redhat/thermostat/utils/management/internal/MXBeanConnectionPoolImpl.java agent/core/src/main/java/com/redhat/thermostat/utils/management/internal/MXBeanConnector.java agent/core/src/main/java/com/redhat/thermostat/utils/management/internal/ProcessUserInfoBuilder.java agent/core/src/test/java/com/redhat/thermostat/agent/internal/ActivatorTest.java agent/core/src/test/java/com/redhat/thermostat/agent/internal/RMIRegistryImplTest.java agent/core/src/test/java/com/redhat/thermostat/utils/management/internal/AgentProxyClientTest.java agent/core/src/test/java/com/redhat/thermostat/utils/management/internal/MXBeanConnectionPoolImplTest.java agent/core/src/test/java/com/redhat/thermostat/utils/management/internal/MXBeanConnectorTest.java agent/proxy/pom.xml agent/proxy/server/Makefile agent/proxy/server/pom.xml agent/proxy/server/src/main/java/com/redhat/thermostat/agent/proxy/server/AgentProxy.java agent/proxy/server/src/main/java/com/redhat/thermostat/agent/proxy/server/AgentProxyControlImpl.java agent/proxy/server/src/main/java/com/redhat/thermostat/agent/proxy/server/AgentProxyControlWrapper.java agent/proxy/server/src/main/java/com/redhat/thermostat/agent/proxy/server/AgentProxyLoginContext.java agent/proxy/server/src/main/java/com/redhat/thermostat/agent/proxy/server/AgentProxyLoginImpl.java agent/proxy/server/src/main/java/com/redhat/thermostat/agent/proxy/server/AgentProxyLoginModule.java agent/proxy/server/src/main/java/com/redhat/thermostat/agent/proxy/server/AgentProxyNativeUtils.java agent/proxy/server/src/main/java/com/redhat/thermostat/agent/proxy/server/AgentProxyPrincipal.java agent/proxy/server/src/main/java/com/redhat/thermostat/agent/proxy/server/ProcDataSource.java agent/proxy/server/src/main/java/com/redhat/thermostat/agent/proxy/server/ProcessUserInfoBuilder.java agent/proxy/server/src/main/java/com/redhat/thermostat/agent/proxy/server/RegistryUtils.java agent/proxy/server/src/main/java/com/redhat/thermostat/agent/proxy/server/ShutdownListener.java agent/proxy/server/src/main/java/com/redhat/thermostat/agent/proxy/server/UnixCredentials.java agent/proxy/server/src/main/native/AgentProxy.c agent/proxy/server/src/test/java/com/redhat/thermostat/agent/proxy/server/AgentProxyControlImplTest.java agent/proxy/server/src/test/java/com/redhat/thermostat/agent/proxy/server/AgentProxyControlWrapperTest.java agent/proxy/server/src/test/java/com/redhat/thermostat/agent/proxy/server/AgentProxyLoginContextTest.java agent/proxy/server/src/test/java/com/redhat/thermostat/agent/proxy/server/AgentProxyLoginImplTest.java agent/proxy/server/src/test/java/com/redhat/thermostat/agent/proxy/server/AgentProxyLoginModuleTest.java agent/proxy/server/src/test/java/com/redhat/thermostat/agent/proxy/server/AgentProxyTest.java agent/proxy/server/src/test/java/com/redhat/thermostat/agent/proxy/server/ProcessUserInfoBuilderTest.java distribution/assembly/core-assembly.xml distribution/config/agent_proxy_jaas.conf distribution/config/commands/agent.properties distribution/config/commands/service.properties distribution/pom.xml distribution/scripts/thermostat distribution/scripts/thermostat-agent-proxy
diffstat 44 files changed, 489 insertions(+), 2685 deletions(-) [+]
line wrap: on
line diff
--- a/agent/core/pom.xml	Tue Dec 16 15:34:39 2014 -0500
+++ b/agent/core/pom.xml	Tue Dec 16 16:00:40 2014 -0500
@@ -74,11 +74,6 @@
     </dependency>
     <dependency>
       <groupId>com.redhat.thermostat</groupId>
-      <artifactId>thermostat-agent-proxy-common</artifactId>
-      <version>${project.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>com.redhat.thermostat</groupId>
       <artifactId>thermostat-launcher</artifactId>
       <version>${project.version}</version>
     </dependency>
--- a/agent/core/src/main/java/com/redhat/thermostat/agent/RMIRegistry.java	Tue Dec 16 15:34:39 2014 -0500
+++ b/agent/core/src/main/java/com/redhat/thermostat/agent/RMIRegistry.java	Tue Dec 16 16:00:40 2014 -0500
@@ -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.
+ * 
+ * <p>
+ * <b> RMI is no longer used by the Thermostat agent. Invoking any of this
+ * service's methods will result in a {@link RemoteException}. </b>
  */
 @Service
+@Deprecated
 public interface RMIRegistry {
 
     /**
--- a/agent/core/src/main/java/com/redhat/thermostat/agent/internal/Activator.java	Tue Dec 16 15:34:39 2014 -0500
+++ b/agent/core/src/main/java/com/redhat/thermostat/agent/internal/Activator.java	Tue Dec 16 16:00:40 2014 -0500
@@ -62,14 +62,15 @@
         context.registerService(RMIRegistry.class, registry, null);
         ServiceReference<CommonPaths> 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.
--- a/agent/core/src/main/java/com/redhat/thermostat/agent/internal/RMIRegistryImpl.java	Tue Dec 16 15:34:39 2014 -0500
+++ b/agent/core/src/main/java/com/redhat/thermostat/agent/internal/RMIRegistryImpl.java	Tue Dec 16 16:00:40 2014 -0500
@@ -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);
-        }
-    }
-
 }
 
--- a/agent/core/src/main/java/com/redhat/thermostat/utils/management/internal/AgentProxyClient.java	Tue Dec 16 15:34:39 2014 -0500
+++ b/agent/core/src/main/java/com/redhat/thermostat/utils/management/internal/AgentProxyClient.java	Tue Dec 16 16:00:40 2014 -0500
@@ -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();
         }
     }
     
--- a/agent/core/src/main/java/com/redhat/thermostat/utils/management/internal/MXBeanConnectionPoolImpl.java	Tue Dec 16 15:34:39 2014 -0500
+++ b/agent/core/src/main/java/com/redhat/thermostat/utils/management/internal/MXBeanConnectionPoolImpl.java	Tue Dec 16 16:00:40 2014 -0500
@@ -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<Integer, Pair<Integer, MXBeanConnectionImpl>> 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<Integer, MXBeanConnectionImpl> 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<Integer, MXBeanConnectionImpl>(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<Integer, MXBeanConnectionImpl>(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;
         }
     }
--- a/agent/core/src/main/java/com/redhat/thermostat/utils/management/internal/MXBeanConnector.java	Tue Dec 16 15:34:39 2014 -0500
+++ b/agent/core/src/main/java/com/redhat/thermostat/utils/management/internal/MXBeanConnector.java	Tue Dec 16 16:00:40 2014 -0500
@@ -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);
--- /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 16:00:40 2014 -0500
@@ -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
+ * <http://www.gnu.org/licenses/>.
+ *
+ * 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:  <RealUid>   <EffectiveUid>   <SavedUid>   <FSUid>
+     */
+    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;
+    }
+
+
+}
+
--- a/agent/core/src/test/java/com/redhat/thermostat/agent/internal/ActivatorTest.java	Tue Dec 16 15:34:39 2014 -0500
+++ b/agent/core/src/test/java/com/redhat/thermostat/agent/internal/ActivatorTest.java	Tue Dec 16 16:00:40 2014 -0500
@@ -89,8 +89,6 @@
         activator.setPool(pool);
 
         activator.stop(context);
-
-        verify(pool).shutdown();
     }
 }
 
--- a/agent/core/src/test/java/com/redhat/thermostat/agent/internal/RMIRegistryImplTest.java	Tue Dec 16 15:34:39 2014 -0500
+++ b/agent/core/src/test/java/com/redhat/thermostat/agent/internal/RMIRegistryImplTest.java	Tue Dec 16 16:00:40 2014 -0500
@@ -36,124 +36,37 @@
 
 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<Integer> portCaptor = ArgumentCaptor.forClass(Integer.class);
-        ArgumentCaptor<RMIClientSocketFactory> csfCaptor = ArgumentCaptor.forClass(RMIClientSocketFactory.class);
-        ArgumentCaptor<RMIServerSocketFactory> 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);
     }
 }
--- a/agent/core/src/test/java/com/redhat/thermostat/utils/management/internal/AgentProxyClientTest.java	Tue Dec 16 15:34:39 2014 -0500
+++ b/agent/core/src/test/java/com/redhat/thermostat/utils/management/internal/AgentProxyClientTest.java	Tue Dec 16 16:00:40 2014 -0500
@@ -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<String[]> 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<Boolean>() {
-            @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<Boolean>() {
-            @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<LogRecord> 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<LogRecord> logMessages;
+        public TestLogHandler(List<LogRecord> 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();
-    }
-    
+
 }
 
--- a/agent/core/src/test/java/com/redhat/thermostat/utils/management/internal/MXBeanConnectionPoolImplTest.java	Tue Dec 16 15:34:39 2014 -0500
+++ b/agent/core/src/test/java/com/redhat/thermostat/utils/management/internal/MXBeanConnectionPoolImplTest.java	Tue Dec 16 16:00:40 2014 -0500
@@ -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();
-    }
 }
 
--- a/agent/core/src/test/java/com/redhat/thermostat/utils/management/internal/MXBeanConnectorTest.java	Tue Dec 16 15:34:39 2014 -0500
+++ b/agent/core/src/test/java/com/redhat/thermostat/utils/management/internal/MXBeanConnectorTest.java	Tue Dec 16 16:00:40 2014 -0500
@@ -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());
     }
 
--- a/agent/proxy/pom.xml	Tue Dec 16 15:34:39 2014 -0500
+++ b/agent/proxy/pom.xml	Tue Dec 16 16:00:40 2014 -0500
@@ -51,7 +51,6 @@
   <name>Thermostat Agent Proxy</name>
 
   <modules>
-    <module>common</module>
     <module>server</module>
   </modules>
 
--- a/agent/proxy/server/Makefile	Tue Dec 16 15:34:39 2014 -0500
+++ /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
--- a/agent/proxy/server/pom.xml	Tue Dec 16 15:34:39 2014 -0500
+++ b/agent/proxy/server/pom.xml	Tue Dec 16 16:00:40 2014 -0500
@@ -49,33 +49,6 @@
   <name>Thermostat Agent Proxy Server</name>
 
   <build>
-    <plugins>
-      <plugin>
-        <groupId>org.codehaus.mojo</groupId>
-        <artifactId>exec-maven-plugin</artifactId>
-        <version>1.2.1</version>
-        <executions>  
-          <execution>
-            <phase>compile</phase>
-            <goals>
-              <goal>exec</goal>
-            </goals>
-          </execution>  
-        </executions>
-        <configuration>
-          <executable>make</executable>
-          <arguments>
-            <argument>all</argument>
-          </arguments>
-          <systemProperties>
-            <systemProperty>
-              <key>JAVA_HOME</key>
-              <value>${java.home}</value>
-            </systemProperty>
-          </systemProperties>
-        </configuration>
-      </plugin>
-    </plugins>
     <pluginManagement>
       <plugins>
         <!--This plugin's configuration is used to store Eclipse m2e settings only. It has no influence on the Maven build itself.-->
@@ -110,11 +83,6 @@
   <dependencies>
     <dependency>
       <groupId>com.redhat.thermostat</groupId>
-      <artifactId>thermostat-agent-proxy-common</artifactId>
-      <version>${project.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>com.redhat.thermostat</groupId>
       <artifactId>thermostat-common-core</artifactId>
       <version>${project.version}</version>
     </dependency>
--- a/agent/proxy/server/src/main/java/com/redhat/thermostat/agent/proxy/server/AgentProxy.java	Tue Dec 16 15:34:39 2014 -0500
+++ b/agent/proxy/server/src/main/java/com/redhat/thermostat/agent/proxy/server/AgentProxy.java	Tue Dec 16 16:00:40 2014 -0500
@@ -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() + " <pidOfTargetJvm>");
     }
     
-    /*
-     * 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;
-    }
 }
 
--- a/agent/proxy/server/src/main/java/com/redhat/thermostat/agent/proxy/server/AgentProxyControlImpl.java	Tue Dec 16 15:34:39 2014 -0500
+++ b/agent/proxy/server/src/main/java/com/redhat/thermostat/agent/proxy/server/AgentProxyControlImpl.java	Tue Dec 16 16:00:40 2014 -0500
@@ -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<AgentProxyPrincipal> principals = user.getPrincipals(AgentProxyPrincipal.class);
-        if (principals.isEmpty()) {
-            throw new SecurityException("Access Denied");
+    void detach() throws IOException {
+        if (attached) {
+            vm.detach();
+            attached = false;
         }
     }
     
--- a/agent/proxy/server/src/main/java/com/redhat/thermostat/agent/proxy/server/AgentProxyControlWrapper.java	Tue Dec 16 15:34:39 2014 -0500
+++ /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
- * <http://www.gnu.org/licenses/>.
- *
- * 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();
-        }
-    }
-
-}
-
--- a/agent/proxy/server/src/main/java/com/redhat/thermostat/agent/proxy/server/AgentProxyLoginContext.java	Tue Dec 16 15:34:39 2014 -0500
+++ /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
- * <http://www.gnu.org/licenses/>.
- *
- * 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);
-        }
-    }
-
-}
-
--- a/agent/proxy/server/src/main/java/com/redhat/thermostat/agent/proxy/server/AgentProxyLoginImpl.java	Tue Dec 16 15:34:39 2014 -0500
+++ /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
- * <http://www.gnu.org/licenses/>.
- *
- * 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);
-        }
-    }
-    
-}
-
--- a/agent/proxy/server/src/main/java/com/redhat/thermostat/agent/proxy/server/AgentProxyLoginModule.java	Tue Dec 16 15:34:39 2014 -0500
+++ /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
- * <http://www.gnu.org/licenses/>.
- *
- * 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<String, ?> sharedState, Map<String, ?> 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<com.sun.security.auth.UnixNumericUserPrincipal> 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<com.sun.security.auth.UnixNumericGroupPrincipal> 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<com.sun.security.auth.UnixPrincipal> 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;
-    }
-    
-}
-
--- a/agent/proxy/server/src/main/java/com/redhat/thermostat/agent/proxy/server/AgentProxyNativeUtils.java	Tue Dec 16 15:34:39 2014 -0500
+++ /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
- * <http://www.gnu.org/licenses/>.
- *
- * 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;
-
-}
-
--- a/agent/proxy/server/src/main/java/com/redhat/thermostat/agent/proxy/server/AgentProxyPrincipal.java	Tue Dec 16 15:34:39 2014 -0500
+++ /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
- * <http://www.gnu.org/licenses/>.
- *
- * 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;
-    }
-
-}
-
--- a/agent/proxy/server/src/main/java/com/redhat/thermostat/agent/proxy/server/ProcDataSource.java	Tue Dec 16 15:34:39 2014 -0500
+++ /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
- * <http://www.gnu.org/licenses/>.
- *
- * 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));
-    }
-
-}
-
--- a/agent/proxy/server/src/main/java/com/redhat/thermostat/agent/proxy/server/ProcessUserInfoBuilder.java	Tue Dec 16 15:34:39 2014 -0500
+++ /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
- * <http://www.gnu.org/licenses/>.
- *
- * 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:  <RealUid>   <EffectiveUid>   <SavedUid>   <FSUid>
-     * Gid:  <RealGid>   <EffectiveGid>   <SavedGid>   <FSGid>
-     */
-    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;
-    }
-    
-}
-
--- a/agent/proxy/server/src/main/java/com/redhat/thermostat/agent/proxy/server/RegistryUtils.java	Tue Dec 16 15:34:39 2014 -0500
+++ /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
- * <http://www.gnu.org/licenses/>.
- *
- * 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.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
--- a/agent/proxy/server/src/main/java/com/redhat/thermostat/agent/proxy/server/ShutdownListener.java	Tue Dec 16 15:34:39 2014 -0500
+++ /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
- * <http://www.gnu.org/licenses/>.
- *
- * 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;
-
-}
-
--- a/agent/proxy/server/src/main/java/com/redhat/thermostat/agent/proxy/server/UnixCredentials.java	Tue Dec 16 15:34:39 2014 -0500
+++ /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
- * <http://www.gnu.org/licenses/>.
- *
- * 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;
-    }
-    
-}
-
--- a/agent/proxy/server/src/main/native/AgentProxy.c	Tue Dec 16 15:34:39 2014 -0500
+++ /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
- * <http://www.gnu.org/licenses/>.
- *
- * 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 <unistd.h>
-#include <string.h>
-#include <errno.h>
-
-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);
-}
-
--- a/agent/proxy/server/src/test/java/com/redhat/thermostat/agent/proxy/server/AgentProxyControlImplTest.java	Tue Dec 16 15:34:39 2014 -0500
+++ b/agent/proxy/server/src/test/java/com/redhat/thermostat/agent/proxy/server/AgentProxyControlImplTest.java	Tue Dec 16 16:00:40 2014 -0500
@@ -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"));
-    }
-
 }
 
--- a/agent/proxy/server/src/test/java/com/redhat/thermostat/agent/proxy/server/AgentProxyControlWrapperTest.java	Tue Dec 16 15:34:39 2014 -0500
+++ /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
- * <http://www.gnu.org/licenses/>.
- *
- * 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);
-    }
-    
-}
-
--- a/agent/proxy/server/src/test/java/com/redhat/thermostat/agent/proxy/server/AgentProxyLoginContextTest.java	Tue Dec 16 15:34:39 2014 -0500
+++ /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
- * <http://www.gnu.org/licenses/>.
- *
- * 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<CallbackHandler> 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();
-    }
-    
-}
-
--- a/agent/proxy/server/src/test/java/com/redhat/thermostat/agent/proxy/server/AgentProxyLoginImplTest.java	Tue Dec 16 15:34:39 2014 -0500
+++ /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
- * <http://www.gnu.org/licenses/>.
- *
- * 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<AgentProxyControl> 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));
-    }
-
-}
-
--- a/agent/proxy/server/src/test/java/com/redhat/thermostat/agent/proxy/server/AgentProxyLoginModuleTest.java	Tue Dec 16 15:34:39 2014 -0500
+++ /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
- * <http://www.gnu.org/licenses/>.
- *
- * 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<Void>() {
-            @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<String, Object>(), new HashMap<String, Object>());
-    }
-    
-    @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<AgentProxyPrincipal> 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());
-    }
-
-}
-
--- a/agent/proxy/server/src/test/java/com/redhat/thermostat/agent/proxy/server/AgentProxyTest.java	Tue Dec 16 15:34:39 2014 -0500
+++ b/agent/proxy/server/src/test/java/com/redhat/thermostat/agent/proxy/server/AgentProxyTest.java	Tue Dec 16 16:00:40 2014 -0500
@@ -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<Exception> 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);
     }
 
 }
--- a/agent/proxy/server/src/test/java/com/redhat/thermostat/agent/proxy/server/ProcessUserInfoBuilderTest.java	Tue Dec 16 15:34:39 2014 -0500
+++ /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
- * <http://www.gnu.org/licenses/>.
- *
- * 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);
-    }
-    
-}
-
--- a/distribution/assembly/core-assembly.xml	Tue Dec 16 15:34:39 2014 -0500
+++ b/distribution/assembly/core-assembly.xml	Tue Dec 16 16:00:40 2014 -0500
@@ -59,7 +59,6 @@
         <include>com.redhat.thermostat:thermostat-agent-core</include>
         <include>com.redhat.thermostat:thermostat-agent-cli</include>
         <include>com.redhat.thermostat:thermostat-agent-command</include>
-        <include>com.redhat.thermostat:thermostat-agent-proxy-common</include>
         <include>com.redhat.thermostat:thermostat-agent-proxy-server</include>
         <include>com.redhat.thermostat:thermostat-common-core</include>
         <include>com.redhat.thermostat:thermostat-common-command</include>
--- a/distribution/config/agent_proxy_jaas.conf	Tue Dec 16 15:34:39 2014 -0500
+++ /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;
-};
--- a/distribution/config/commands/agent.properties	Tue Dec 16 15:34:39 2014 -0500
+++ b/distribution/config/commands/agent.properties	Tue Dec 16 16:00:40 2014 -0500
@@ -8,7 +8,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.backend.system=${project.version}, \
--- a/distribution/config/commands/service.properties	Tue Dec 16 15:34:39 2014 -0500
+++ b/distribution/config/commands/service.properties	Tue Dec 16 16:00:40 2014 -0500
@@ -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
--- a/distribution/pom.xml	Tue Dec 16 15:34:39 2014 -0500
+++ b/distribution/pom.xml	Tue Dec 16 16:00:40 2014 -0500
@@ -174,7 +174,6 @@
                     <include>thermostat-roles.properties</include>
                     <include>thermostat_jaas.conf</include>
                     <include>devsetup.input</include>
-                    <include>agent_proxy_jaas.conf</include>
                     <include>db.properties</include>
                     <include>logging.properties</include>
                     <include>osgi-export.properties</include>
@@ -238,8 +237,6 @@
                       todir="${project.build.directory}/image/libs/native" />
                 <copy file="${main.basedir}/agent/core/target/libUserNameUtilWrapper.so"
                       todir="${project.build.directory}/image/libs/native" />
-                <copy file="${main.basedir}/agent/proxy/server/target/libAgentProxy.so"
-                      todir="${project.build.directory}/image/libs/native" />
                 <copy file="${main.basedir}/laf-utils/target/libGTKThemeUtils.so"
                       todir="${project.build.directory}/image/libs/native" />
               </target>
--- a/distribution/scripts/thermostat	Tue Dec 16 15:34:39 2014 -0500
+++ b/distribution/scripts/thermostat	Tue Dec 16 16:00:40 2014 -0500
@@ -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"
--- a/distribution/scripts/thermostat-agent-proxy	Tue Dec 16 15:34:39 2014 -0500
+++ b/distribution/scripts/thermostat-agent-proxy	Tue Dec 16 16:00:40 2014 -0500
@@ -40,6 +40,10 @@
 JAVA_DIR="@java.dir@"
 JAVA="@java.home@/bin/java"
 
+if [ "$#" -lt 2 ]; then
+  echo "usage: $0 <pidOfTargetJvm> <userNameOfJvmOwner>" >&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