Axis of Cookies
I swear, some times it feels like I spend more time reading third pary code to see what it's really doing than writing code of my own. Today's subject of abuse will be Apache Axis. Here's the use case: Using a java plug-in applet inside a web-app that uses form based authentication access a soap service behind that authentication. You don't have the password available (there are tricks to get the username, but you really have to think outside the box to intercept the password, and forget about C3 certification at that point!)
My first line of thought was that Cookies are magically added to URL requests in the plug in so it must work in axis. That is a cool and very real feature of the plug in, but it only works when using a java.net.URL, but Axis dosen't use it, it uses some custom HTTP sender with support for the Jakarta Commons HTTP Sender. Thank you for plauing try again.
What worked for a while was the URL re-writing method form the servlet spec, basically using http://shemnon.com/speling/;jsessionid=<sessionID>. That works fine on some servers, but not others. The hitch is that in the spec URL re-writing is only meant to be used when the client rejects the cookies. One app server accepts the session id in both the cookie or the url re-writing, but anohter one we need to support doesn't. And you know what sucks? It's the second app server that is probobly properly implementing that part of the servlet spec! We're not playing horseshoes here so I need to keep going.
So as little as I want to I have to dive into the JAXRPC spec. The truth is that Axis's WSDL2Java is so easy to use from a coding perspective you rarely need to use the standard APIs that it implements. It just looks like another RMI-style interface that maigcally works. Believe me, I like stuff that magically works, it allows me to go home after my 8 hours are in.
It turns out that the classes you get from the ServiceLocaters are also javax.xml.rpc.Stub classes. These provice access to some standard properites, like if I needed HTTP Basic authentication I'de be in luck, but alas no dice, I need to use the currently bound user. There is also another standard property that will maintain the http session but it maintains only new sessions! And it suckes when all you get is "302 Found" messages to the login form when you don't know the password. And apparently the session is only maintained on a per-service basis as well (per instance of the serivce to make things worse).
This is where open source and source available software comes in handy. After diving into the setMaintainSession(boolean) code deep inside of the transport handlers I came to the conclusion that the cookie was stored in a property set that inhereited ultimatly from the same properties that the service uses to read the standard JAXRPC properties. So all I need to do is set the cookie in the service session when I get it from the service...
import org.apache.axis.transport.http.HTTPConstants; /* ... */ MyServiceLocator locator = new MyServiceLocator(); MyService serivce = locator.getMyService(); ((javax.xml.rpc.Stub)service)._setProperty( "javax.xml.rpc.session.maintain"), Boolean.TRUE); ((javax.xml.rpc.Stub)service)._setProperty( HTTPConstants.HEADER_COOKIE, "JSESSIONID=" + sessionID);
and those last two statements only cost me one afternoon of lost time....