Contents | Previous | Next | Java Management Extensions (JMX) Technology Tutorial |
This chapter gives examples of how to set up the JMX technology security features, as described in the following sections:
The simplest type of security you can use with the JMX technology is based upon encryption, user name and password authentication, and file access control.
You can find an example of an RMI connector with simple security in the directory work_dir/jmx_examples/Security/simple
.
/jmx_examples
/Security/simple
directory.Inside this directory you will find the following directories:
/server
, containing the fileServer.java
/config
, containing the security configuration files:/mbeans
, containing the following files:/client
, containing the following files:*.java
and *.properties
files in a text editorThese files will be analyzed in the following sections.
The Server.java
class is shown in CODE EXAMPLE 5-1.
public class Server { public static void main(String[] args) { try { MBeanServer mbs = MBeanServerFactory.createMBeanServer(); HashMap env = new HashMap(); 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); env.put("jmx.remote.x.password.file", "config" + File.separator + "password.properties"); env.put("jmx.remote.x.access.file", "config" + File.separator + "access.properties"); JMXServiceURL url = new JMXServiceURL( "service:jmx:rmi:///jndi/rmi://localhost:9999/server"); JMXConnectorServer cs = JMXConnectorServerFactory.newJMXConnectorServer(url, env, mbs); cs.start(); } catch (Exception e) { e.printStackTrace(); } } }
The Server
class shown in CODE EXAMPLE 5-1 creates an MBean server mbs
, and populates an environment map env
with a secure RMI client socket factory csf
, a secure RMI server socket factory ssf
, and the properties files password.properties
and access.properties
.
The properties file password.properties
contains a username and password and is accessed using the JMX Remote API interface JMXAuthenticator
. Using the property jmx.remote.x.
password.file
is the same as creating a password-based JMXAuthenticator
and passing it into the environment map through the jmx.remote.authenticator
property.
The properties file access.properties
contains a username and a level of access permission that can be either readwrite
or readonly
. This represents the level of access this user can have to MBean server operations. This file-based access control is implemented using the JMX technology interface MBeanServerForwarder
, which wraps the real MBean server inside an access controller MBean server. The access controller MBean server only forwards requests to the real MBean server after performing the appropriate checks.
Server
creates a JMX service URL, named url
, for an RMI connector that will operate over the default JRMP transport, and register an RMI connector stub in an RMI registry on port 9999
of the local host.
The MBean server mbs
, the environment map env and the service URL url
are all passed to JMXConnectorServer
to create a new, secure JMX connector server named cs
.
The SimpleStandardMBean
class defines the same straightforward MBean interface as was used in Chapter 3, "JMX Connectors".
The SimpleStandard
class defines the same straightforward MBean as was used in Chapter 3, "JMX Connectors".
The ClientListener
class defines the same straightforward notification listener as was used in Chapter 3, "JMX Connectors".
The Client.java
class is shown in CODE EXAMPLE 5-2.
public class Client { public static void main(String[] args) { try { HashMap env = new HashMap(); String[] credentials = new String[] { "username" , "password" }; env.put("jmx.remote.credentials", credentials); JMXServiceURL url = new JMXServiceURL( "service:jmx:rmi:///jndi/rmi://localhost:9999/server"); JMXConnector jmxc = JMXConnectorFactory.connect(url, env); MBeanServerConnection mbsc = jmxc.getMBeanServerConnection(); String domains[] = mbsc.getDomains(); for (int i = 0; i < domains.length; i++) { System.out.println("Domain[" + i + "] = " + domains[i]); } ObjectName mbeanName = new ObjectName("MBeans:type=SimpleStandard"); mbsc.createMBean("SimpleStandard", mbeanName, null, null); // Perform MBean operations [...] mbsc.removeNotificationListener(mbeanName, listener); mbsc.unregisterMBean(mbeanName); jmxc.close(); } catch (Exception e) { e.printStackTrace(); } } }
The Client
class shown in CODE EXAMPLE 5-2 populates an environment map env
with a set of credentials, namely the username
and password
expected by the Server
. These credentials are then given to an instance of JMXConnector
named jmxc
when the service URL of the connector stub and the environment map are passed to JMXConnectorFactory.connect()
. Through jmxc
, the Client
connects to the MBean server started by Server
, and performs MBean operations.
When the connection is established, the credentials supplied in the environment map env
are sent to the server. The server then calls the authenticate()
method of the JMXAuthenticator
interface, passing the client credentials as parameters. The authenticate()
method authenticates the client and returns a subject that contains the set of principals upon which the access control checks will be performed.
To run the RMI connector example with simple security, perform the following steps:
$ javac mbeans/SimpleStandard.java \ mbeans/SimpleStandardMBean.java \ server/Server.java \ client/Client.java \ client/ClientListener.java
Server
.
$
java -classpath server:mbeans \
-Djavax.net.ssl.keyStore=config/keystore \
-Djavax.net.ssl.keyStorePassword=password \
Server &
You will see confirmation of the creation of the MBean server and of the RMI connector.
Client
.
$
java -classpath client:server:mbeans \
-Djavax.net.ssl.trustStore=config/truststore \
-Djavax.net.ssl.trustStorePassword=trustword \
Client
You will see confirmation of the creation of the connector client, the various MBean operations followed by the closure of the connection.
As you can see, all the above appears to proceed in exactly the same manner as the basic RMI connector example shown in Chapter 3, "JMX Connectors". However, if you were to open password.properties
and change the password, you would see a java.lang.SecurityException
when you launched the Client
, and the connection would fail.
If your implementation requires the client end of the connection to perform different operations on behalf of multiple users or applications, using the security mechanisms demonstrated in Section 5.1 "Simple Security", each different user would require one secure connection for every operation it performs. If you expect your connector clients to interact with numerous users, you can reduce the load on your system by implementing subject delegation. Subject delegation establishes a single secure connection for a user, and this connection can be used to perform related operations on behalf of any number of users. The connection itself is made by an authenticated user. If the authenticated user has been granted a SubjectDelegationPermission
that allows it to act on behalf of another user, then operations can be performed over the connection on behalf of that user.
You can find an example of a secure RMI connector that implements subject delegation in the directory work_dir/jmx_examples/Security/subject_delegation
.
/jmx_examples
/Security/subject_delegation
directoryInside this directory you will find the following directories:
/server
, containing the file Server.java
:/config
, containing the security configuration files:/mbeans
, containing the following files:/client
, containing the following files:*.java
and *.properties
files in a text editorThese files will be analyzed in the following sections.
The Server.java
class is shown in CODE EXAMPLE 5-3:
public class Server { public static void main(String[] args) { try { MBeanServer mbs = MBeanServerFactory.createMBeanServer(); HashMap env = new HashMap(); env.put("jmx.remote.x.password.file", "config" + File.separator + "password.properties"); env.put("jmx.remote.x.access.file", "config" + File.separator + "access.properties"); JMXServiceURL url = new JMXServiceURL( "service:jmx:rmi:///jndi/rmi://localhost:9999/server"); JMXConnectorServer cs = JMXConnectorServerFactory.newJMXConnectorServer(url, env, mbs); cs.start(); } catch (Exception e) { e.printStackTrace(); } } }
CODE EXAMPLE 5-3 begins with the creation of an MBean server mbs
, and the population of an environment map env
with a password file and an access file, called password.properties
and access.properties
respectively:
The Server
then creates a connector server named cs
, and starts it in exactly the same way as in the previous RMI connector examples.
The java.policy
file grants to username
a SubjectDelegationPermission
so it can perform operations on behalf of the user delegate
, an instance of JMXPrincipal
created by the Client
class. The java.policy
file is required when launching the Server
class.
The SimpleStandardMBean
class defines the same straightforward MBean interface as was used in the previous examples.
The SimpleStandard
class defines the same straightforward MBean as was used in the previous examples.
The ClientListener
class defines the same straightforward notification listener as was used in the previous examples.
The Client.java
class is shown in CODE EXAMPLE 5-4:
public class Client { public static void main(String[] args) { try { HashMap env = new HashMap(); String[] credentials = new String[] { "username" , "password" }; env.put("jmx.remote.credentials", credentials); JMXServiceURL url = new JMXServiceURL( "service:jmx:rmi:///jndi/rmi://localhost:9999/server"); JMXConnector jmxc = JMXConnectorFactory.connect(url, env); Subject delegationSubject = new Subject(true, Collections.singleton(new JMXPrincipal("delegate")), Collections.EMPTY_SET, Collections.EMPTY_SET); MBeanServerConnection mbsc = jmxc.getMBeanServerConnection(delegationSubject); String domains[] = mbsc.getDomains(); ObjectName mbeanName = new ObjectName("MBeans:type=SimpleStandard"); mbsc.createMBean("SimpleStandard", mbeanName, null, null); // Perform MBean operations // [...] mbsc.removeNotificationListener(mbeanName, listener); mbsc.unregisterMBean(mbeanName); jmxc.close(); } catch (Exception e) { e.printStackTrace(); } } }
CODE EXAMPLE 5-4 begins with the creation of an environment map env
that is populated with a user name username
and a password password
. These strings match the user name and password stored in the password.properties
file that is held by the Server
to authenticate users accessing the connector server.
A JMX technology connector client jmxc
is created in the same way as in the previous RMI connector examples, with the user name and password passed into the environment map env
.
The Client
then creates an instance of Subject
, called delegationSubject
, with a Principal
that is an instance of JMXPrincipal
, named delegate
.
An MBean server connection, named mbsc
, is created by calling the getMBeanServerConnection()
method of JMXConnector
, with delegationSubject
passed in as a parameter. This MBean server connection therefore allows operations to be performed on the remote MBean server on behalf of the principals stored in the delegationSubject
, which in this example is the JMXPrincipal
named delegate
.
The example continues by creating and registering the SimpleStandard
MBean in the MBean server, and performing operations on it, in exactly the same way as in the previous examples.
To run the secure RMI connector example with subject delegation, perform the following steps:
$ javac mbeans/SimpleStandard.java \ mbeans/SimpleStandardMBean.java \ server/Server.java \ client/Client.java \ client/ClientListener.java
$
export CLASSPATH=server ; rmiregistry 9999 &
Server
.You will see confirmation of the creation of the MBean server, the initialization of the environment map, the creation of the RMI connector, and the registration of the connector in the MBean server.
Client
.
$
java -classpath client:server:mbeans Client
You will see confirmation of the creation of the connector client, the creation of the delegation subject, the connection to the MBean server and the various MBean operations followed by the closure of the connection.
You can implement a more fine-grained level of security in your connectors by managing user access through the Java Authentication and Authorization Service (JAAS) and Java platform Standard Edition (Java SE) Security Architecture. JAAS and Java SE security is based on the use of security managers and policy files to allocate different levels of access to different users. Consequently, you can decide more precisely which users are allowed to perform which operations.
The two examples in this section are very similar to those shown in Section 5.1 "Simple Security", with the difference being that the simple, file-based access control has been replaced by policy-based access control.
You can find an example of an RMI connector with fine-grained security in the directory work_dir/jmx_examples/Security/fine_grained
.
/jmx_examples
/Security/fine_grained.Inside this directory you will find the following directories:
/server
, containing the fileServer.java
/config
, containing the security configuration files:/mbeans
, containing the following files:/client
, containing the following files:*.java
and *.properties
files in a text editor.
The Server.java
class used in this example is very similar to the one used in the RMI connector example with simple security. The only difference is that there is no access.properties
file to map into the environment map in the fine-grained example. Otherwise, the two classes are identical.
The java.policy
file grants the following permissions:
server
code base, so that the connector server can create the connectors, and then perform the operations requested by remote user callsMBeanTrustPermission
to the mbeans
code base, allowing trusted MBeans to register in the MBean serverJMXPrincipal
named username.
The SimpleStandardMBean
class defines the same straightforward MBean interface as was used in the previous examples.
The SimpleStandard
class defines the same straightforward MBean as was used in the previous examples.
The ClientListener
class defines the same straightforward notification listener as as was used in the previous examples.
The Client.java
class is exactly the same as the one used in the RMI connector example with simple security.
To run the RMI connector example with fine-grained security, perform the following steps:
$ javac mbeans/SimpleStandard.java \ mbeans/SimpleStandardMBean.java \ server/Server.java \ client/Client.java \ client/ClientListener.java
$
export CLASSPATH=server ; rmiregistry 9999 &
Server
.
$
java -classpath server:mbeans \
-Djavax.net.ssl.keyStore=config/keystore \
-Djavax.net.ssl.keyStorePassword=password \
-Djava.security.manager \
-Djava.security.policy=config/java.policy \
Server &
You will see confirmation of the initialization of the environment map, the creation of the MBean server and of the RMI connector.
Client
.$ java -classpath client:server:mbeans \ -Djavax.net.ssl.trustStore=config/truststore \ -Djavax.net.ssl.trustStorePassword=trustword \ Client
You will see confirmation of the creation of the connector client, the connection to the RMI server and the various MBean operations followed by the closure of the connection.
Contents | Previous | Next |
Java Management Extensions (JMX) Technology Tutorial Java Management Extensions (JMX), Java Platform, Standard Edition 6 |
Copyright © 2006 Sun Microsystems, Inc. All rights reserved.