/*
* Copyright (C) The MX4J Contributors.
* All rights reserved.
*
* This software is distributed under the terms of the MX4J License version 1.0.
* See the terms of the MX4J License in the documentation provided with this software.
*/
package mx4j.examples.remote.rmi.ssl;
import java.io.IOException;
import java.io.InputStream;
import java.security.KeyStore;
import java.util.HashMap;
import java.util.Map;
import javax.management.MBeanServer;
import javax.management.MBeanServerFactory;
import javax.management.ObjectName;
import javax.management.remote.JMXConnectorServer;
import javax.management.remote.JMXConnectorServerFactory;
import javax.management.remote.JMXServiceURL;
import javax.management.remote.rmi.RMIConnectorServer;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import mx4j.tools.remote.rmi.SSLRMIClientSocketFactory;
import mx4j.tools.remote.rmi.SSLRMIServerSocketFactory;
/**
* This example shows how to setup a JSR 160 RMIConnectorServer over SSL. <br />
* An RMI server that has been setup to use SSL uses a private key to encrypt the
* communication with the client. The client must know the server's public key in order
* to be able to decrypt the communication; public keys are stored in X509 certificates.
* This X509 certificate is generated by the server and should be made available to
* clients (for example by distributing it). <br />
* The private and public key are normally stored in a server-side key store that can
* be created by using the JDK's keytool utility; here is a sample command that can
* be invoked to generate a keystore:
* <pre>
* keytool -genkey -v -keystore key.store -storepass storepwd -dname "CN=Anonymous Geek, OU=MX4J Development Team, O=The MX4J Project, L=New York City, S=NY, C=US"
* </pre>
* It creates a 'key.store' file that must be present in the classpath when running this example. <br />
* The next step is to export the X509 certificate for the clients, with the following command:
* <pre>
* keytool -export -v -storepass storepwd -keystore key.store -file myserver.cer
* </pre>
* It is also possible to generate a trust store containing the X509 certificate that
* can be used directly by the client with the following command:
* <pre>
* keytool -export -v -storepass storepwd -keystore key.store | keytool -import -v -storepass storepwd -keystore trust.store -noprompt
* </pre>
* Once you have exported the X509 certificate, follow the instructions on how to setup
* the client {@link Client here}.
*
* @version $Revision: 1.4 $
*/
public class Server
{
public static void main(String[] args) throws Exception
{
MBeanServer server = MBeanServerFactory.createMBeanServer();
// Register and start the rmiregistry MBean
ObjectName namingName = ObjectName.getInstance("naming:type=rmiregistry");
server.createMBean("mx4j.tools.naming.NamingService", namingName, null);
server.invoke(namingName, "start", null, null);
int namingPort = ((Integer)server.getAttribute(namingName, "Port")).intValue();
String jndiPath = "/ssljmxconnector";
JMXServiceURL url = new JMXServiceURL("service:jmx:rmi://localhost/jndi/rmi://localhost:" + namingPort + jndiPath);
// Create the rmi socket factories for SSL
Map environment = new HashMap();
SSLContext context = createSSLContext();
environment.put(RMIConnectorServer.RMI_CLIENT_SOCKET_FACTORY_ATTRIBUTE, new SSLRMIClientSocketFactory());
environment.put(RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE, new SSLRMIServerSocketFactory(context));
// Create and start the RMIConnectorServer
JMXConnectorServer connectorServer = JMXConnectorServerFactory.newJMXConnectorServer(url, environment, null);
ObjectName connectorServerName = ObjectName.getInstance("connectors:protocol=" + url.getProtocol());
server.registerMBean(connectorServer, connectorServerName);
connectorServer.start();
System.out.println("Server up and running");
}
/**
* Creates and returns an SSLContext by reading information from a keystore. <br>
* Change the hardcoded options to match your configuration and your environment.
*/
private static SSLContext createSSLContext() throws Exception
{
String keystoreName = "key.store";
String keystorePassword = "storepwd";
KeyStore keystore = KeyStore.getInstance("JKS");
InputStream keystoreStream = Server.class.getClassLoader().getResourceAsStream(keystoreName);
// Must check for nullity, otherwise a new empty keystore is created by KeyStore.load
if (keystoreStream == null) throw new IOException("Cannot find KeyStore " + keystoreName + " in classpath");
keystore.load(keystoreStream, keystorePassword.toCharArray());
KeyManagerFactory keyFactory = KeyManagerFactory.getInstance("SunX509");
keyFactory.init(keystore, keystorePassword.toCharArray());
SSLContext context = SSLContext.getInstance("TLS");
context.init(keyFactory.getKeyManagers(), null, null);
return context;
}
}