« Use The Source, Duke! | Main | Lame Excuses »

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....

Comments (9)

Bob Dunbar:

This code is working great. Thank you.

Any tricks for getting the sessionID from the HTTP Header response? For Example, using Axis to get the 'Set-Cookie' value from the following HTTP response header:

HTTP/1.1 200 OK
Server: Microsoft-IIS/5.1
Date: Wed, 31 Dec 2003 03:24:54 GMT
X-Powered-By: ASP.NET
X-AspNet-Version: 1.1.4322
Set-Cookie: ASP.NET_SessionId=3kgjohv50iaskl3xnxgyifzc; path=/
Cache-Control: private, max-age=0
Content-Type: text/xml; charset=utf-8
Content-Length: 292

Thanks in advance,

Bob

The trick I used was to put the cookie in the applet/object tag as a paraemeter, including the title and everything. This works good when the needed cookie is not JSESSIONID, so the code looked something like...
<% String sessionName = request.getHeader("cookie");%>
<OBJECT classid="clsid:8AD9C840-044E-11D1-B3E9-00805F499D93"
codebase="local jre">
<!-- other params -->
<PARAM NAME="SESSION" VALUE="<%=sessionName%>"/>
</OBJECT>

I would then use the SESSION parameter to populate the axis cookie. Of course this is JSP code and not ASP code, so I am sure the details are different on IIS.

Gunter Blache:

Hello Permalink,

thanks for that posting, it was what I needed to get HTTP basic authentication running with Axis. For completeness, my code looks like:

import org.apache.axis.client.Stub;
...
ServiceLocator sl = new ServiceLocator();
Service c = sl.getService(new URL("http://...service/soap/1.0/"));
Stub s = (Stub)c;
s.setUsername("user");
s.setPassword("password");
String return = c.getString();

and works great. Thank you

Gunter

ddd_80:

Hello,
Thank you Danno for the previous post. I can set the cookie now.

I wanted to ask if it possible to create a Axis handler on the client side and set a cookie there. If yes which handler to create and how to set the cookie.

I want the client to pass a session Id on every call to the server. Can this be done in a Axis handler ?


Thank you
Deval

Danno Ferrin:

This is not a support forum. Try the apache axis users mailing lsit at axis-user@ws.apache.org.

ddd_80:

Hello,
I was trying to add a cookie to session using the code you provided. By I get a ClassCastException.

org.apache.axis.client.Service.Service service = new org.apache.axis.client.Service.Service();

Call call = (Call) service.createCall();
(javax.xml.rpc.Stub)service)._setProperty("javax.xml.rpc.session.maintain", Boolean.TRUE);

((javax.xml.rpc.Stub)service)._setProperty( HTTPConstants.HEADER_COOKIE,"cookieName=" + sid);

I get the following exception:
Exception in thread "main" java.lang.ClassCastException: org.apache.axis.client.Service

Thanks in advance.
Deval

Danno Ferrin:

You are not using the axis service locator to find the stub object. Use the ServiceLocator or the JNDI finders to get at the stub for your service.

Generally speaking, don't directly instantiate a org.apache.axis.client.Service object, specific instances of those are used to build and return specific stubs. The MyServiceLocator is the specific instance of org.apache.axis.client.Service you want to play with. Then using the ServiceLocator you get the Stub object, which implements the interfaces your soap service defines.

I you are doing a dynamic soap call, set the properties on the Call object you create from the generic service object.

There is some real confusing and unfortionalte choice to terminiology there, but them's the facts!

MG:

I went through the same pain as you did to figure this thing out and wish I had run into this article before, thanks for sharing though.

-MG

Atique Khan:

This is how I retrieved the Cookie from the response header:

Stub stub = (Stub) service;
Call call = stub._getCall();
MessageContext msgContext = call.getMessageContext();
Message message = msgContext.getResponseMessage();
MimeHeaders mhd = message.getMimeHeaders();
String[] cookies = mhd.getHeader(SET_COOKIE);

Integer index = null;
if(cookies != null) {
for(int j = 0; j String currentCookie = cookies[j];
if(index == null && currentCookie.contains( JSESSIONID)) {
index = j;
}
}
}

if(index != null) {
HttpServletRequest request;
HttpSession session;
String sessionId;
sessionId = cookies[index].substring( cookies[index].indexOf(JSESSIONID + "=") + 11, cookies[index].indexOf(";"));
}

Post a comment


About

This page contains a single entry from the blog posted on May 5, 2003 1:09 AM.

The previous post in this blog was Use The Source, Duke!.

The next post in this blog is Lame Excuses.

Many more can be found on the main index page or by looking through the archives.

Powered by
Movable Type 3.33