Using HTTPS with REST in Java

Something to keep in mind is that this error isn't only due to self signed certs. The new Entrust CA certs fail with the same error, and the right thing to do is to update the server with the appropriate root certs, not to disable this important security feature.


When you say "is there an easier way to... trust this cert", that's exactly what you're doing by adding the cert to your Java trust store. And this is very, very easy to do, and there's nothing you need to do within your client app to get that trust store recognized or utilized.

On your client machine, find where your cacerts file is (that's your default Java trust store, and is, by default, located at <java-home>/lib/security/certs/cacerts.

Then, type the following:

keytool -import -alias <Name for the cert> -file <the .cer file> -keystore <path to cacerts>

That will import the cert into your trust store, and after this, your client app will be able to connect to your Grizzly HTTPS server without issue.

If you don't want to import the cert into your default trust store -- i.e., you just want it to be available to this one client app, but not to anything else you run on your JVM on that machine -- then you can create a new trust store just for your app. Instead of passing keytool the path to the existing, default cacerts file, pass keytool the path to your new trust store file:

keytool -import -alias <Name for the cert> -file <the .cer file> -keystore <path to new trust store>

You'll be asked to set and verify a new password for the trust store file. Then, when you start your client app, start it with the following parameters:

java -Djavax.net.ssl.trustStore=<path to new trust store> -Djavax.net.ssl.trustStorePassword=<trust store password>

Easy cheesy, really.


Check this out: http://code.google.com/p/resting/. I could use resting to consume HTTPS REST services.


Here's the painful route:

    SSLContext ctx = null;
    try {
        KeyStore trustStore;
        trustStore = KeyStore.getInstance("JKS");
        trustStore.load(new FileInputStream("C:\\truststore_client"),
                "asdfgh".toCharArray());
        TrustManagerFactory tmf = TrustManagerFactory
                .getInstance("SunX509");
        tmf.init(trustStore);
        ctx = SSLContext.getInstance("SSL");
        ctx.init(null, tmf.getTrustManagers(), null);
    } catch (NoSuchAlgorithmException e1) {
        e1.printStackTrace();
    } catch (KeyStoreException e) {
        e.printStackTrace();
    } catch (CertificateException e) {
        e.printStackTrace();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    } catch (KeyManagementException e) {
        e.printStackTrace();
    }
    ClientConfig config = new DefaultClientConfig();
    config.getProperties().put(HTTPSProperties.PROPERTY_HTTPS_PROPERTIES,
            new HTTPSProperties(null, ctx));

    WebResource service = Client.create(config).resource(
            "https://localhost:9999/");
    service.addFilter(new HTTPBasicAuthFilter(username, password));

    // Attempt to view the user's page.
    try {
        service.path("user/" + username).get(String.class);
    } catch (Exception e) {
        e.printStackTrace();
    }

Gotta love those six different caught exceptions :). There are certainly some refactoring to simplify the code a bit. But, I like delfuego's -D options on the VM. I wish there was a javax.net.ssl.trustStore static property that I could just set. Just two lines of code and done. Anyone know where that would be?

This may be too much to ask, but, ideally the keytool would not be used. Instead, the trustedStore would be created dynamically by the code and the cert is added at runtime.

There must be a better answer.

Tags:

Java

Rest

Ssl

X509