blob: 659f806d58ce7231756800d8fa4c22392fbced61 [file] [log] [blame]
/*
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
package org.apache.qpid.server.management;
import org.apache.log4j.Logger;
import org.apache.qpid.AMQException;
import org.apache.qpid.server.registry.ApplicationRegistry;
import org.apache.qpid.server.registry.IApplicationRegistry;
import org.apache.qpid.server.security.auth.database.Base64MD5PasswordFilePrincipalDatabase;
import org.apache.qpid.server.security.auth.database.PlainPasswordFilePrincipalDatabase;
import org.apache.qpid.server.security.auth.database.PrincipalDatabase;
import org.apache.qpid.server.security.auth.sasl.crammd5.CRAMMD5HashedInitialiser;
import org.apache.qpid.server.security.auth.sasl.plain.PlainInitialiser;
import javax.management.JMException;
import javax.management.MBeanServer;
import javax.management.MBeanServerFactory;
import javax.management.remote.JMXConnectorServer;
import javax.management.remote.JMXConnectorServerFactory;
import javax.management.remote.JMXServiceURL;
import javax.management.remote.MBeanServerForwarder;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
import java.util.HashMap;
import java.util.Map;
/**
* This class starts up an MBeanserver. If out of the box agent is being used then there are no security features
* implemented. To use the security features like user authentication, turn off the jmx options in the "QPID_OPTS" env
* variable and use JMXMP connector server. If JMXMP connector is not available, then the standard JMXConnector will be
* used, which again doesn't have user authentication.
*/
public class JMXManagedObjectRegistry implements ManagedObjectRegistry
{
private static final Logger _log = Logger.getLogger(JMXManagedObjectRegistry.class);
private final MBeanServer _mbeanServer;
private Registry _rmiRegistry;
private JMXServiceURL _jmxURL;
public static final String MANAGEMENT_PORT_CONFIG_PATH = "management.jmxport";
public static final int MANAGEMENT_PORT_DEFAULT = 8999;
public JMXManagedObjectRegistry() throws AMQException
{
_log.info("Initialising managed object registry using platform MBean server");
IApplicationRegistry appRegistry = ApplicationRegistry.getInstance();
// Retrieve the config parameters
boolean platformServer = appRegistry.getConfiguration().getBoolean("management.platform-mbeanserver", true);
_mbeanServer =
platformServer ? ManagementFactory.getPlatformMBeanServer()
: MBeanServerFactory.createMBeanServer(ManagedObject.DOMAIN);
}
public void start() throws IOException
{
// Check if the "QPID_OPTS" is set to use Out of the Box JMXAgent
if (areOutOfTheBoxJMXOptionsSet())
{
_log.info("JMX: Using the out of the box JMX Agent");
return;
}
IApplicationRegistry appRegistry = ApplicationRegistry.getInstance();
boolean security = appRegistry.getConfiguration().getBoolean("management.security-enabled", false);
int port = appRegistry.getConfiguration().getInt(MANAGEMENT_PORT_CONFIG_PATH, MANAGEMENT_PORT_DEFAULT);
if (security)
{
// For SASL using JMXMP
_jmxURL = new JMXServiceURL("jmxmp", null, port);
Map env = new HashMap();
Map<String, PrincipalDatabase> map = appRegistry.getDatabaseManager().getDatabases();
PrincipalDatabase db = null;
for (Map.Entry<String, PrincipalDatabase> entry : map.entrySet())
{
if (entry.getValue() instanceof Base64MD5PasswordFilePrincipalDatabase)
{
db = entry.getValue();
break;
}
else if (entry.getValue() instanceof PlainPasswordFilePrincipalDatabase)
{
db = entry.getValue();
}
}
if (db instanceof Base64MD5PasswordFilePrincipalDatabase)
{
env.put("jmx.remote.profiles", "SASL/CRAM-MD5");
CRAMMD5HashedInitialiser initialiser = new CRAMMD5HashedInitialiser();
initialiser.initialise(db);
env.put("jmx.remote.sasl.callback.handler", initialiser.getCallbackHandler());
}
else if (db instanceof PlainPasswordFilePrincipalDatabase)
{
PlainInitialiser initialiser = new PlainInitialiser();
initialiser.initialise(db);
env.put("jmx.remote.sasl.callback.handler", initialiser.getCallbackHandler());
env.put("jmx.remote.profiles", "SASL/PLAIN");
}
//workaround NPE generated from env map classloader issue when using Eclipse 3.4 to launch
env.put("jmx.remote.profile.provider.class.loader", this.getClass().getClassLoader());
// Enable the SSL security and server authentication
/*
SslRMIClientSocketFactory csf = new SslRMIClientSocketFactory();
SslRMIServerSocketFactory ssf = new SslRMIServerSocketFactory();
env.put(RMIConnectorServer.RMI_CLIENT_SOCKET_FACTORY_ATTRIBUTE, csf);
env.put(RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE, ssf);
*/
JMXConnectorServer cs = JMXConnectorServerFactory.newJMXConnectorServer(_jmxURL, env, _mbeanServer);
MBeanServerForwarder mbsf = MBeanInvocationHandlerImpl.newProxyInstance();
cs.setMBeanServerForwarder(mbsf);
cs.start();
_log.warn("JMX: Started JMXConnector server on port '" + port + "' with SASL");
}
else
{
startJMXConnectorServer(port);
_log.warn("JMX: Started JMXConnector server on port '" + port + "' with security disabled");
}
}
/**
* Starts up an RMIRegistry at configured port and attaches a JMXConnectorServer to it.
*
* @param port
*
* @throws IOException
*/
private void startJMXConnectorServer(int port) throws IOException
{
startRMIRegistry(port);
_jmxURL = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://localhost:" + port + "/jmxrmi");
JMXConnectorServer cs = JMXConnectorServerFactory.newJMXConnectorServer(_jmxURL, null, _mbeanServer);
cs.start();
}
public void registerObject(ManagedObject managedObject) throws JMException
{
_mbeanServer.registerMBean(managedObject, managedObject.getObjectName());
}
public void unregisterObject(ManagedObject managedObject) throws JMException
{
_mbeanServer.unregisterMBean(managedObject.getObjectName());
}
/**
* Checks is the "QPID_OPTS" env variable is set to use the out of the box JMXAgent.
*
* @return
*/
private boolean areOutOfTheBoxJMXOptionsSet()
{
if (System.getProperty("com.sun.management.jmxremote") != null)
{
return true;
}
if (System.getProperty("com.sun.management.jmxremote.port") != null)
{
return true;
}
return false;
}
/**
* Starts the rmi registry at given port
*
* @param port
*
* @throws RemoteException
*/
private void startRMIRegistry(int port) throws RemoteException
{
System.setProperty("java.rmi.server.randomIDs", "true");
_rmiRegistry = LocateRegistry.createRegistry(port);
}
// stops the RMIRegistry, if it was running and bound to a port
public void close() throws RemoteException
{
if (_rmiRegistry != null)
{
// Stopping the RMI registry
UnicastRemoteObject.unexportObject(_rmiRegistry, true);
}
}
}