Wednesday, October 29, 2014

How to setup custom SSLSocketFactory's TrustManager per each URL connection

We can see from javadoc that javax.net.ssl.HttpsURLConnection provided a static method to override with setDefaultSSLSocketFory() method. This allow you to supply a custom javax.net.ssl.TrustManager that may verify your own  CA certs handshake and validation etc. But this will override the default for all "https" URLs per your JVM!

So how can we override just a single https URL? Looking at javax.net.ssl.HttpsURLConnection again we see instance method for setSSLSocketFactory(), but we can't instantiate HttpsURLConnection object directly! It took me some digging to realized that the java.net.URL is actually an factory class for its implementation! One can get an instance like this using new URL("https://localhost").openConnection()

To complete this article, I will provide a simple working example that demonstrate this.

package zemian;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

public class WGetText {
    public static void main(String[] args) throws Exception {
        String urlString = System.getProperty("url", "https://google.com");
        URL url = new URL(urlString);
        URLConnection urlConnection = url.openConnection();
        HttpsURLConnection httpsUrlConnection = (HttpsURLConnection) urlConnection;
        SSLSocketFactory sslSocketFactory = createTrustAllSslSocketFactory();
        httpsUrlConnection.setSSLSocketFactory(sslSocketFactory);
        try (InputStream inputStream = httpsUrlConnection.getInputStream()) {
            BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
            String line = null;
            while ((line = reader.readLine()) != null) {
                System.out.println(line);
            }
        }
    }

    private static SSLSocketFactory createTrustAllSslSocketFactory() throws Exception {
        TrustManager[] byPassTrustManagers = new TrustManager[] { new X509TrustManager() {
            public X509Certificate[] getAcceptedIssuers() {
                return new X509Certificate[0];
            }

            public void checkClientTrusted(X509Certificate[] chain, String authType) {
            }

            public void checkServerTrusted(X509Certificate[] chain, String authType) {
            }
        } };
        SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(null, byPassTrustManagers, new SecureRandom());
        return sslContext.getSocketFactory();
    }
}

Monday, October 27, 2014

How Servlet and JSP create sessions

In Servlet, you may get the Session object by "httpServletRequest.getSession(true)". The "true" flag will create the session if it doesn't already exist, else it gets the existing session.

Now if you want to check whether you have the session exists or not (without have to create one if doesn't exist), you need to pass in "false" and then check for "null".

Session session = httpServletRequest.getSession(false);
if (session == null) {
  // do something without creating session object.
}

Now comes the trick party. If you run above code and then dispatch the request to render a JSP page, you might quickly come to find out that the container will create a new Session object still! It turns out that by default JSP will create new Session object if you do not have one! To disable this, you need to set this explicitly on top of the JSP page:

 <% page session="false" %>

Only with this you will able to actually prevent creation of unnecessary Session object if you were to use JSP for output! Something to watch out for when debugging session based application.

Saturday, October 18, 2014

Poking around your REST application with a scriptable endpoint

I love the fact that JDK comes with a ScriptEngine. It's so flexible when you want to evaluate and troubleshoot your application that's already deployed in an server environment. Add this REST endpoint into a Java EE app, and it will give you instant access to internal states of the app.

package myrestapp;

import java.io.StringReader;
import java.util.logging.Logger;
import javax.script.Bindings;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.core.Context;

/**
 * Give instant access to your internal application with dynamic scripting.
 *
 * <p>Example script:
 * <pre>
 * "sc" + servletContext + ", req=" + request;
 * </pre>
 *
 * <p>Example2
 * <pre>
 * names = servletContext.getAttributeNames();
 * while(names.hasMoreElements()) {
 *   name = names.nextElement();
 *   println(name);
 * }
 * </pre>
 *
 * <p>Example on how to import Java packages and classes.
 * <pre>
 * importPackage(Packages.java.text);
 * df = new SimpleDateFormat("MM/dd/yyyy");
 * dt = df.parse("01/01/2014");
 * </pre>
 */
@Path("script")
public class ScriptResource {
    private static final Logger logger = Logger.getLogger(ScriptResource.class.getName());
   
    @Context
    private ServletContext servletContext;
       
    @POST
    public String script(@Context HttpServletRequest request, String scriptText) throws Exception {
        String engineName = "JavaScript";
        ScriptEngineManager manager = new ScriptEngineManager();
        ScriptEngine engine = manager.getEngineByName(engineName);
        logger.info("Running script text length=" + scriptText.length() + ", engine=" + engine);
        Object result = null;
        try (StringReader reader = new StringReader(scriptText)) {
            Bindings bindings = engine.createBindings();
            bindings.put("servletContext", servletContext);
            bindings.put("request", request);
            result = engine.eval(reader, bindings);
        }
        logger.info("Result " + result);
        return "RESULT=" + result;
    }
}


Notice that I gave couple JavaScript examples in the comment area already. You will have access to two binding variables that should give you full access to many internal components of your application. And here is a quick reference on scripting JDK 7.

Need an UI to test out this endpoint? How about give the "Advance Rest Client" Chrome Extension a try? (Thanks to my co-worker's Chris Griffith for showing me this cool extension. It's really handy tool to have!).

UPDATES (12/8/2014)
- If you are using FireFox, try the "RESTClient" add-ons.
- If you are using JDK7 Rhino JavaScript engine, here is a good ref for help: https://developer.mozilla.org/en-US/docs/Mozilla/Projects/Rhino/Scripting_Java
- If you're in a EE6 web application and doesn't have REST enabled yet, then simply add a class like this to your application. It should automatically configure an endpoint that you can access as "http://localhost/rest/script".

package myrestapp;

import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;

/**
 * This is the main entry into REST Application that bootstrap the provider.
 */
@ApplicationPath("rest")
public class RestApplication extends Application {
}