8

I have this simple JMX client

    public void testTomcatBasicAuthentication() throws Exception
    {
        System.out.println("Test Server Basic Authentication");
        try
        {
            String truststore = "C:\\client.jks";
            String trustStorePassword = "password";

            JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://xxx.xxx.xxx.xxx:9999/jmxrmi");

            HashMap environment = new HashMap();
            String[] credentials = new String[]
            {
                "user", "passwd"
            };
            environment.put(JMXConnector.CREDENTIALS, credentials);
//            environment.put("javax.net.ssl.trustStore", truststore);
//            environment.put("javax.net.ssl.trustStorePassword", trustStorePassword);
//            environment.put("javax.net.ssl.keyStore", truststore);
//            environment.put("javax.net.ssl.keyStorePassword", trustStorePassword);

            KeyManager[] kms = getKeyManagers(truststore, trustStorePassword);
            TrustManager[] tms = getTrustManagers(truststore, trustStorePassword);

            System.setProperty("javax.net.ssl.trustStore", truststore);
            System.setProperty("javax.net.ssl.trustStorePassword", trustStorePassword);
            System.setProperty("javax.net.ssl.keyStore", truststore);
            System.setProperty("javax.net.ssl.keyStorePassword", trustStorePassword);

            JMXConnector jmxc = JMXConnectorFactory.connect(url, environment);
            MBeanServerConnection server = jmxc.getMBeanServerConnection();

            Set<ObjectName> s2 = server.queryNames(new ObjectName("Catalina:type=Server,*"), null);
            for (ObjectName obj : s2)
            {
                ObjectName objname = new ObjectName(obj.getCanonicalName());
                System.out.println("serverInfo " + server.getAttribute(objname, "serverInfo"));
                System.out.println("address " + server.getAttribute(objname, "address"));
                System.out.println("stateName " + server.getAttribute(objname, "stateName"));
            }
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }

How I can replace System.setProperty(....) with Java code? I don't want to use System.setProperty.

Edit. I found this example

Can we use this code?

KeyManager[] kms = getKeyManagers(truststore, trustStorePassword);
            TrustManager[] tms = getTrustManagers(truststore, trustStorePassword);
            SslContext.setCurrentSslContext(new SslContext(kms, tms, null));

private static TrustManager[] getTrustManagers(String location, String password)
        throws IOException, GeneralSecurityException
    {
        // First, get the default TrustManagerFactory.
        String alg = TrustManagerFactory.getDefaultAlgorithm();
        TrustManagerFactory tmFact = TrustManagerFactory.getInstance(alg);

        FileInputStream fis = new FileInputStream(location);
        KeyStore ks = KeyStore.getInstance("jks");
        ks.load(fis, password.toCharArray());
        fis.close();

        tmFact.init(ks);

        // And now get the TrustManagers
        TrustManager[] tms = tmFact.getTrustManagers();
        return tms;
    }

    private static KeyManager[] getKeyManagers(String location, String password)
        throws IOException, GeneralSecurityException
    {
        // First, get the default KeyManagerFactory.
        String alg = KeyManagerFactory.getDefaultAlgorithm();
        KeyManagerFactory kmFact = KeyManagerFactory.getInstance(alg);

        FileInputStream fis = new FileInputStream(location);
        KeyStore ks = KeyStore.getInstance("jks");
        ks.load(fis, password.toCharArray());
        fis.close();

        // Now we initialise the KeyManagerFactory with this KeyStore
        kmFact.init(ks, password.toCharArray());

        // And now get the KeyManagers
        KeyManager[] kms = kmFact.getKeyManagers();
        return kms;
    }

    private static KeyStore keyStoreFromCertificateString(String alias, String certificateString)
        throws NoSuchAlgorithmException, CertificateException, IOException, KeyStoreException
    {
        KeyStore ks = KeyStore.getInstance("jks");
        ks.load(null); // Create empty key store
        CertificateFactory cf = CertificateFactory.getInstance("X.509");
        Certificate cert = cf.generateCertificate(new ByteArrayInputStream(certificateString.getBytes()));
        ks.setEntry(alias, new KeyStore.TrustedCertificateEntry(cert), null);
        return ks;
    }

Can you give some idea how we can integrate this code or there should be some other solution?

vzamanillo
  • 9,905
  • 1
  • 36
  • 56
Peter Penzov
  • 1,126
  • 134
  • 430
  • 808
  • 5
    What do you mean replace? What would you replace it with? `System.setProperty` *is* Java code – Vince Dec 26 '15 at 18:30
  • 1
    I guess OP means to pass these key/values to JMX factory without setting them systemwide. – Gaël J Dec 26 '15 at 18:32
  • @Gaël yes, you're correct – Peter Penzov Dec 26 '15 at 18:34
  • But "systemwide" just means "inside this jvm-instance" - which is usually fine unless you are in som kind of multi-tenant setup like in an app-server (JBoss etc.) – anders.norgaard Dec 26 '15 at 19:34
  • @anders.norgaard in my case I can't use system variables. – Peter Penzov Dec 26 '15 at 19:39
  • While the **System.setProperty** may seem unjavalike it does serve a purpose. This is a common mechanism used by many developers when using certificates over a secure connection. As you are now seeing it takes a lot to replace this simple approach. And unless you are intending to have more than one keystore it would seem like a waste of effort to replace a simple solution with a more complex one. – Mike Murphy Jan 08 '16 at 16:39
  • For me it's very important to implement this because I will have Java application which connect to different JMX servers with different SSL certificates. – Peter Penzov Jan 08 '16 at 20:15

3 Answers3

6

It seems like it should be relatively easy, but it's not.

You need to pass actual socket factory classes in the environment, see this example. However, the implementations used in that example use the jvm default socket factories. Instead, you need to setup your own SSL*SocketFactory instances with the appropriate key store and trust store. Then you need to implement your own RMI*SocketFactory instances using your configured socket factory(s). You can use the jdk impls as guides, SslRMIClientSocketFactory and SslRMIServerSocketFactory.

jtahlborn
  • 52,909
  • 5
  • 76
  • 118
  • I managed to copy the content of SslRMIClientSocketFactory and SslRMIServerSocketFactory. What I need to add in order to implement custom RMI*SocketFactory? – Peter Penzov Dec 26 '15 at 20:59
  • P.S by the way is there any other alternative solution? This approach will be very hard to implement? – Peter Penzov Dec 26 '15 at 21:10
  • @PeterPenzov - you use the TrustManager and KeyManager to init an SSLContext. you use the [SSLContext](https://docs.oracle.com/javase/6/docs/api/javax/net/ssl/SSLContext.html) to create the socket factories. there are lots of examples of doing this online. alter your implementations of the rmi socket factories to use your ssl socket factories instead of the jvm default instances. – jtahlborn Dec 27 '15 at 00:18
2

I fear your question is not very well formulated. I write you want to replace System.setProperty but for me it looks like, actually you want to use custom trust/key stores.

This has been answered already: Using a custom truststore in java as well as the default one

The example that you have found is only half of the solution. You have to use the respective managers when creating the connections. Something like this:

sslContext.init(null, trustManagers, null);
connection.setSSLSocketFactory(sslContext.getSocketFactory());

Source: https://planet.jboss.org/post/creating_https_connection_without_javax_net_ssl_truststore_property

But if you don't control the actual connection creation you probably have to use the global properties. (Or whatever config mechanism your application server has)

Community
  • 1
  • 1
Martin Rauscher
  • 1,700
  • 1
  • 14
  • 20
0

A simple and easy workaround to make this work is to use a separate copy of system properties for each thread as explained very well in here (interestingly, the main question self concerns the same problem as yours). After that, setting keyStore and trustStore on system properties will be thread-local.

Make sure you use different threads for your two different ssl connections.

Community
  • 1
  • 1
NiMa Thr
  • 458
  • 3
  • 12