Saturday, October 31, 2009

Java 5 EOSL

Java 5 has reached End Of Life. Most of the bigger organization in the service industry are still using Java 1.4 and are not willing to migrate as they anticipate migration issues and feel that its a risk and unjustifiable. Java 6 has been out for a long and its time to take advantage of the new features, especially the web services stack (JAX-WS). There are lot of performance improvements which might be one reason to migrate.

On a personal note migration is little to do with technical, but more often political.

http://java.sun.com/products/archive/eol.policy.html

Thursday, September 17, 2009

File Download issue with IE over HTTPS

I am currently working on a project where the user can download PDF, XLS and CSV files. These files are dynamically generated within the application and thrown out on the browser when the user clicks on a particular link. This was running like a charm till recently, we decided to move to HTTPS and it stopped working. We were getting a message saying

"The file could not be stored in cache."
"Internet Explorer was unable to open this site. The requested site is either unavailable or cannot be found. Please try again later."


After a little googling I found that it is a known issue with IE. Refer to the link below. http://support.microsoft.com/kb/815313 But installing a hotfix was out of question. So I went looking for a solution that could be handled through code and here is the solution that seems to work for us and the magic required to satisfy IE
response.setHeader("Pragma", "public");
response.setHeader("Cache-Control", "max-age=0");

Wednesday, August 12, 2009

Two way SSL on Tomcat & JBoss

Continued from the previous post where I had put in steps to setup one way SSL. In this post i shall provide steps to enable client certificate authorization. Hence here we will see a situation where the client verifies the server cert and server verifies the client cert for validity and trust before a successful SSL handshake. The initial steps shall be the same as mentioned in my previous post and with an assumption that your one way SSL is already working. Now to enable the client authorization, we need to modify the server.xml as below:
<Connector 
  port="8443" minSpareThreads="5" maxSpareThreads="75" enableLookups="true"
  disableUploadTimeout="true" acceptCount="100" maxThreads="200" scheme="https" 
  secure="true" SSLEnabled="true" keystoreFile="c:/certs/test_store" keystorePass="password" 
  clientAuth="true" truststoreFile="c:/certs/test_store" 
  truststorePass="password" sslProtocol="TLS"/>
Export a certificate from the client keystore (client_store in this example) and import it into the server's truststore (test_store in this example). In real world you probably would not import each client cert but a CA root cert and then sign each client cert with that one. The above mentioned way is only for testing purposes and get the feel of the process. Launch the server. No modifications are needed in the code on the client side. You can launch the client using:
c:\>java -Djavax.net.ssl.trustStore=c:/certs/client_store -Djavax.net.ssl.trustStorePassword=password -Djavax.net.ssl.keyStore=c:/certs/client_store -Djavax.net.ssl.keyStorePassword=password HelloWorld
Additional Tips: 1)In order to get detailed debug statements for the SSL handshake between the server and the client you can use the vm argument -Djavax.net.debug=ssl,handshake on either side. 2)If you want to be able to access the site using your browser then you will have to have the client certificate in the Internet Options > Content > Certificates > Personal section. For this you will have to be using a PKCS12 keystore instead of a standard JKS keystore. Hence instead use the following steps to generate the keystore on the client side:
keytool -genkey -v -alias clientKey -keyalg RSA -storetype PKCS12 -keystore client.p12
The keypass and storepass needs to be the same. Like in the steps for client using JKS, even here you can use a similar command to export the cert
keytool -export -alias clientKey -keystore client.p12 -storetype PKCS12 -rfc -file client.cer
Rest instructions like importing this cert into server's keystore continue to be same. One important point to note is that since the server's cert cannot be imported into PKCS12 keystore on client side, you have to import it into a JKS truststore and the commandline to launch the program needs to be modified as:
c:\>java -Djavax.net.debug=ssl,handshake -Djavax.net.ssl.keyStoreType=PKCS12
-Djavax.net.ssl.keyStore=c:/certs/client.p12 -Djavax.net.ssl.keyStorePassword=password
-Djavax.net.ssl.trustStore=c:/certs/cacerts -Djavax.net.ssl.trustStorePassword=password HelloWorld
In this case, the server's certificate has been imported into the cacerts truststore of type JKS. The PKCS12 keystore can be imported into the internet explorer at the above mentioned path. Now if you hit the URL using https, you shall be displayed a dialog box to select the cert you want to use for client authorization. Once you select it, the handshake process continues. Through out the example we have been making hits to a servlet (https://personal-PC:8443/SampleWebApp/HelloWorld). We can get the details of the client cert used to access this URL from an attribute in the request object.
X509Certificate certs[] = (X509Certificate[])request.getAttribute("javax.servlet.request.X509Certificate");
for (X509Certificate cert : certs) {
out.println(cert.getIssuerDN());
}

Tuesday, August 4, 2009

SSL on Tomcat, JBoss and command line client (continued)

I finished my previous post with the ending lines as So if you had used domain name in the cert CN, then use domain name or if it is machine name then use the machine name ; and if you don't do so you shall see error messages similiar to HTTPS hostname wrong: should be <personal-pc> where you had given your ip or localhost as the CN name while creating the keystore whereas referring the machine by its name (personal-pc in this case). If you go by the rules mentioned in previous post, it shall work i.e. using the same name in the URL to refer the machine you used as CN. What if you still want to be able to work with the different name (not the one similiar to the CN) or you want to use the IP in the URL when accessing the site? Well there is also a provision for this. You can write your own code to decide what needs to be done in such a situation by implementing the HostnameVerifier interface.
URL url = new URL("https://personal-PC:8443/SampleWebApp/HelloWorld");
URLConnection connection = url.openConnection();

if (connection instanceof HttpsURLConnection) {
    ((HttpsURLConnection) connection).setHostnameVerifier(new HostnameVerifier() {

        public boolean verify(String hostname, SSLSession session) {
           //TODO: Logic controlling the verfication.
           return true;
        }
    });
}

BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
//Rest of the IO code.
In the code above, I am just returning true for what ever comes in as host name, you shall write your logic here to handle the situation the way you like. With the above code in place, you will be able to use all valid names to refer your machine in the URL including computer name and localhost/127.0.0.1 (only for testing purposes).

Monday, August 3, 2009

SSL on Tomcat, JBoss and command line client

Talking about a secure website, the first thing that comes to mind is SSL. For almost all the sites today, we do encounter a section in the website where the address bar turns yellow with a lock indicating that the data being transfered is being encrypted. That section can be a login screen or a transaction screen etc. In this post i've tried to put some steps to achieve the goal of securing a HelloWorldServlet (not much useful but the technique for this or a complex one shall be same).
In order to start with the process of securing your site, we need a certificate. You shall be able to get a valid certificate from a Certification Authority like Thwate, Verisign and many more. Here I shall use a self-signed certificate but the process shall be quite similar for the ones from a Certification Authority (CA).
First of all we create a Keystore using the keytool available in a JRE installation. You can look for it in JDK\bin or JRE\bin directory.
keytool -genkey -alias rsatest -keyalg RSA -keystore test_store -validity 60
Keep in mind while creating the keystore that the answer to the first question i.e. What is your first and last name? should be either your domain address or machine name (It should be the name by which your machine shall be referred in URL when clients are making hits to it using an HttpsURLConnection). This is the CN (Common Name).
After answering a number of self explanatory questions and providing an appropriate password, you shall see a file names test_store in your present working directory folder.
In the next step, you can create a certificate that shall be required by the client application to communicate with this machine using SSL.
keytool -export -alias rsatest -file rsatest.cer -keystore test_store
After executing this command, you shall see a rsatest.cer file created.
In order to start tomcat in https mode in addition to its default http mode, we need to modify the server.xml in the TOMCAT_HOME\CONF folder.
Paste the snippet below in server.xml.
 <Connector port="8443" minSpareThreads="5" maxSpareThreads="75" enableLookups="true" 
  disableUploadTimeout="true" acceptCount="100" maxThreads="200" scheme="https" secure="true" 
  SSLEnabled="true" keystoreFile="c:/certs/test_store" keystorePass="password" clientAuth="false" sslProtocol="TLS"/>
Replace the location of keystoreFile and the keystorePass with appropriate values.
In case of JBoss the process is quite similar to that of Tomcat. We need to edit JBOSS_HOME\server\default\deploy\jboss-web.deployer\server.xml instead and paste the below give snippet.
 <Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
     maxThreads="150" scheme="https" secure="true"
     clientAuth="false" strategy="ms"
     address="${jboss.bind.address}"
     keystoreFile="C:/certs/test_store"
     keystorePass="password"
     sslProtocol="TLS"/>
Which ever server you choose to modify, after you are done with saving the server.xml file start the server. You should be able to make hits to the server url with https protocol on an appropriate port (8443 in our case). Expect to see some warning like There is a problem with this website's security certificate. on IE or localhost:8443 uses an invalid security certificate. on firefox for the reasons explained very well on that screen. This happens as ours is a self-signed certificate and not issued by a trusted certificate authority that the machine or the browsers certificate stores posses. These self signed shall be good enough for internal use or testing but for internet use you should get the certs from a trusted certificate authority.
Well, we are ready with our server running in https mode. For example purposes I had developed a very simple HelloWorldServlet. I am able to access via https://localhost:8443/WebAppDemo/HelloWorldServlet
Before we write the client code, we need to get the cert that we generated earlier. As we are on the same machine, you can re-use the trust store (for practice purposes) but in real environment (on a different machine), you shall create a new trust store and import the cert into it using the command given below:
keytool -import -alias rsatest -file rsatest.cer -keystore cacerts
The same command is used to import any ROOT certificates or the certs provided by a website that you want to connect using your java program.
With the above command we created a new keystore and imported the certificate into it. The client code is very simple i.e. a usual HttpUrlConnection code. A small snippet from my test class HelloWorld.java is given below:
  URL url = new URL("https://localhost:8443/WebAppDemo/HelloWorldServlet");
  URLConnection connection = url.openConnection();
Rest code is simple IO reading from stream hence skipping it.
The important part is are the VM arguments. If you have written a stand alone application, you shall run it using the following command:
c:\>java -Djavax.net.ssl.trustStore=c:/certs/cacerts -Djavax.net.ssl.trustStorePassword=password HelloWorld
One very important point is that in the URL the server machine should be refered by the name used in the CN while creating the keystore. So you need to use the domain name of the machine as the CN. It won't work otherwise. In my example using localhost is a bad practice but I feel you get the point and modify your codes according to the situation. The IP of the machine should not be used as a CN, so you have to use the domain name or the machine name as the CN for the cert. The same domain name or machine name (used in CN) should be used when accessing the URL or else you will encounter host name verification failure.

Monday, February 23, 2009

Executing the code while JVM shuts down

A number of times we have encountered a situation where we want a particular piece of code to be executed when our application is exiting. More necessarily we need such a mechanism when we have developed a server and want the code to be executed for any System.exit(0) call or a CTRL + C key combination on the console. A shutdown hook is the way out for this problem. Writing it is very simple. All the code we need to be executed should be written in a Thread and its object should be registered with the Runtime of the JVM. The code is as below.
Runtime.getRuntime().addShutdownHook(new Thread() {
    public void run() {
        System.out.println("Executing the code while closing down.");
    }
});
A detailed explanation of the above method is provided in the Javadocs for the Runtime class.

Sunday, January 25, 2009

Remote debugging application on pocket pc running on j9

I assume that eclipse was used for the development of the application. Once the application is ready, It shall be copied over to the device that has j9 run time environment. The application can be deployed as a jar file or classes. In order to run the application, either command line needs to be used or we can create a link file with the following content:
255#"\Program Files\j9\bin\j9.exe" -jcl:ppro11  -cp "Test.jar" "trial.Test"
Assuming that the application is packed into a jar file and the trail.Test is the main class. Save the above file with a .lnk extension e.g. Test.lnk. Click on the Test.lnk file and see that the application launches properly.
Now in order to remote debug, check for the existence of j9dbg23.dll in your j9 bin directory. Modify the Test.lnk file to:
255#"\Program Files\j9\bin\j9w.exe" -jcl:ppro11 -debug:transport=dt_socket,server=y,address=4142 -cp "Test.jar" "trial.Test"
Once it is done, open the same project in eclipse.
  1. Open the Debug Configurations window (Run > Debug Configuration).
  2. Create a new Remote Java Application configuration and enter the details as follows:
  • Project -> Select your project.
  • Connection Type -> Standard (Socket Attach)
  • Connection Properties -> ip of the remote machine (pocket pc) and the debug port (4142 in our example case). This port is mentioned in the above created ".lnk" file, hence should be the same in this "Remote Java Application" debug configuration.
  • Run the application on the pocket pc by clicking on the Test.lnk file.
  • Click on the Debug button on the newly created "Remote Java Application" debug configuration.
You are ready to debug your application buy putting break points in appropriate code locations. This scenario has been tested with j9 on a Windows CE 4.2 environment. Should be the same for Windows Mobile and Linux environment (you'll get an .so instead of a .dll in j9 distribution).
The debugger can similiarly be attached even using netbeans.