|
From: Mattias J <mj...@ex...> - 2004-07-13 14:59:53
|
Hi again. As I have also mentioned on the general list I was unable to send messages using the HTTPS protocol with JDK 1.4 without making a non-JDK 1.3.1-compatible change to the hk.hku.cecid.phoenix.message.transport.Http class. I have now spent most of this day reading source code, forum posts and articles and testing, and believe I now have understood the problem and am able to provide a suggestion on how to solve this issue. I bet most of you understand these things much better than I do, but since the current code is erroneous I will try to explain some fundamentals as I understand them. Background What instance of java.net.URLConnection is used when opening a connection to any given java.net.URL will be decided by a java.net.URLStreamHandler. The URLStreamHandler used depends on the package names set up in the java.protocol.handler.pkgs system property. (Please see http://java.sun.com/j2se/1.4.2/docs/api/java/net/URL.html#URL(java.lang.String,%20java.lang.String,%20int,%20java.lang.String) for more information about this). For Java 1.3.1 (with the JSSE add-on) the URLStreamHandlers we want for HTTP and HTTPS is in the com.sun.net.ssl.internal.www.protocol package. The class used for HTTPS connections extends com.sun.net.ssl.HttpsURLConnection. For Java 1.4 the default handlers reside under the sun.net.www.protocol package. The HTTPS connection class extends the new (non JDK 1.3.1 compatible) javax.net.ssl.HttpsURLConnection. But there is also a backwards compatible handler under the com.sun.net.ssl.internal.www.protocol package (which in some manner wraps classes from javax.net.ssl, which I believe was what Ronald van Kuijk tried to explain to me). Problem Since the MSH is supposed to be Java 1.3.1 compatible, we cannot use the javax.net.ssl classes, since this would produce java.lang.NoClassDefFoundError (which according to my tests can be caught, but that is an ugly solution in comparison to what could be done, especially since it won't compile under 1.3.1 anyway). So, for key manager/trust manager (and proprietary hostnameVerifier) to be used, the connection must be an instance of com.sun.net.ssl.HttpsURLConnection (as of line 381 and forth in hk.hku.cecid.phoenix.message.transport.Http rev 1.12). As stated above, for the backwards compatible handler to be used in Java 1.4, the com.sun.net.ssl.internal.www.protocol package must be mentioned in the java.protocol.handler.pkgs system property. This might be the motivation for the following lines in hk.hku.cecid.phoenix.message.transport.Http (line numbers from rev 1.12): 368 URL url = new URL(toUrl); 369 if (url.getProtocol().equalsIgnoreCase 370 (Constants.TRANSPORT_TYPE_HTTPS)) { 371 String pkgs = System.getProperty(PROTOCOL_HANDLER_PKGS); // PROTOCOL_HANDLER_PKGS = "java.protocol.handler.pkgs" 372 if (pkgs == null || pkgs.indexOf(SSL_WWW_PROTOCOL) < 0 ) { // SSL_WWW_PROTOCOL = "com.sun.net.ssl.internal.www.protocol" 373 pkgs = (pkgs == null ? SSL_WWW_PROTOCOL : 374 SSL_WWW_PROTOCOL + "|" + pkgs); 375 System.setProperty(PROTOCOL_HANDLER_PKGS, pkgs); 376 } 377 } The problem here is that the system property is set AFTER the URL is constructed. The URLStreamHandler used for the URL is decided inside the URL constructor, so when the code above changes the system property, the new implementation from the sun.net.www.protocol package will already have been chosen, and the com.sun.net.ssl.HttpsURLConnection dependent code will not be run. Please note that it is NOT enough to move the setting of the system property before the URL creation on line 368. This is because the URLStreamHandler for a given protocol (in our case the HTTPS protocol) will be cached inside the java.net.URL class. So after the first HTTPS instance of java.net.URL has been created, they will all have the same connection implementation (or at least the same handler; this is unless the handler is explicitly provided to the constructor). For example, while trying to find a solution for this whole problem this I found myself getting the wrong implementation because there were MSHConfig records in the database having HTTPS toMshUrls being instantiated as soon as the MSH was started (on line 2865 of hk.hku.cecid.phoenix.message.handler.MessageServer). Solution Currently I have put the code to fix the system property in a static block in hk.hku.cecid.phoenix.message.transport.Http // Configure SSL connections to use pre JDK 1.4 protocol handlers static { String pkgs = System.getProperty(PROTOCOL_HANDLER_PKGS); if (pkgs == null || pkgs.indexOf(SSL_WWW_PROTOCOL) < 0 ) { pkgs = (pkgs == null ? SSL_WWW_PROTOCOL : SSL_WWW_PROTOCOL + "|" + pkgs); System.setProperty(PROTOCOL_HANDLER_PKGS, pkgs); } } I believe though there will be a more proper place to put this (I'm not sure what effect dynamic class loading has on static blocks, for example), such as at configuration time or in the MessageServiceHandler.init(), but I leave that up to you guys. Mattias Jiderhamn Expert Systems |