3

I need to create a Cookie with a specific name to be sent across in my web service calls to another network which has a routing logic based on it.

When i try to set to the HTTP header in my SOAP handler using

headers.put("Cookie", Collections.singletonList(cookiename + "='" + cookieValue + "'")); 

it works for the first time.

The response for this comes with a Set-Cookie for JSESSIONID.

My subsequent requests hold that JSESSIONID and it's value in the cookie and ignores setting my custom cookie.

Is there a way to make sure that my cookie gets set by default in all my requests?

Kaleid-o-scope
  • 159
  • 2
  • 7
  • Perhaps your cookie is stored in a database in webservice's endpoint and server only gives you a session id. By the way, did you try a custom HTTP header, like "X-MyCustomHeader: my value", instead of Cookie header? – R.Sicart Jul 14 '14 at 08:31

2 Answers2

5

We also needed to support JSESSIONID with SOAP service recently and this is what we came up with after reading StackOverflow and referring to an example of an SSO client on the IBM site.

We extended SOAPHandler:

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.List;

import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;

import com.sun.istack.internal.Nullable;

public class SoapMessageHandler implements SOAPHandler<SOAPMessageContext> {

    private String sessionCookie = "";

    @Override
    public void close(MessageContext arg0) { }

    @SuppressWarnings({ "rawtypes", "unchecked" })
    @Override
    public Set getHeaders() {
        return null;
    }

    @Override
    public boolean handleFault(SOAPMessageContext context) {
        return false;
    }

    @Override
    public boolean handleMessage(SOAPMessageContext soapMessageContext) {
        if ((Boolean) soapMessageContext.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY)) {
            // Add header to outbound request (set cookie in HTTP client header)
            // Set the Cookie
            Map<String, List<String>> headers = (Map<String, List<String>>)soapMessageContext.get(MessageContext.HTTP_REQUEST_HEADERS);
            if (headers == null) {
                headers = new HashMap<String, List<String>>();
                soapMessageContext.put(MessageContext.HTTP_REQUEST_HEADERS, headers);
            }
            List<String> cookie = headers.get("Cookie");
            if (cookie == null) {
                cookie = new ArrayList<String>();
                headers.put("Cookie", cookie);
            }
            cookie.add(sessionCookie);
        } else {
            // Read header from request (read cookie from server's HTTP headers)
            Map<String, List<String>> map = (Map<String, List<String>>) soapMessageContext.get(MessageContext.HTTP_RESPONSE_HEADERS);
            List<String> contentType = getHTTPHeader(map, "Set-Cookie");
            // Note, only grabs last cookie value!
            // If you need to present more than one cookie you could make
            // sessionCookie a List<String> and modify this class accordingly.
            if (contentType != null) {
                StringBuffer strBuf = new StringBuffer();
                for (String type : contentType) {
                    strBuf.append(type);
                }
                sessionCookie = strBuf.toString();
            }
        }
        return true;
    }

    private @Nullable List<String> getHTTPHeader(Map<String, List<String>> headers, String header) {
        for (Map.Entry<String, List<String>> entry : headers.entrySet()) {
            String name = entry.getKey();
            if (header != null && name !=null) {
                if (name.equalsIgnoreCase(header))
                    return entry.getValue();
            }
        }
        return null;
    }

}

This also requires HandlerResolver:

import java.util.ArrayList;
import java.util.List;
import javax.xml.ws.handler.Handler;
import javax.xml.ws.handler.HandlerResolver;
import javax.xml.ws.handler.PortInfo;

public class SoapHandlerResolver implements HandlerResolver {

@SuppressWarnings("unchecked")
public List<Handler> getHandlerChain(PortInfo portInfo) {
      List<Handler> handlerChain = new ArrayList<Handler>();
      handlerChain.add( new SoapMessageHandler() );
      return handlerChain;
   }
}

The extended HandlerResolver is then invoked when calling the SOAP service like so:

ExampleService exampleService = new ExampleService();
exampleService.setHandlerResolver( new SoapHandlerResolver() );
Example example = exampleService.getExampleServicePort();
example.myMethod();

This worked for us, with Java 6, with the limitation of only supporting one Cookie header (though could be trivially modified to support multiple Cookie headers).

NB: If, like us, you have to pass the same session cookie between multiple services (as if cookies on a SOAP service weren't bad enough) instead of this:

private String sessionCookie = "";

You could just do this:

static private String sessionCookie = "";

Which is super hacky, and may or may not work for you depending on how the service (and your code) works and how may sessions you can have on the remote service, so I'd suggest something more sophisticated than using a static in production.

Iain Collins
  • 6,774
  • 3
  • 43
  • 43
1

To be exact:

In the SOAPHandler class we need to pass the session id as JSESSIONID="actual ID". Below is whole code.

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.namespace.QName;
import javax.xml.soap.Name;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPFactory;
import javax.xml.soap.SOAPHeader;
import javax.xml.soap.SOAPHeaderElement;
import javax.xml.soap.SOAPMessage;
import javax.xml.ws.LogicalMessage;
import javax.xml.ws.ProtocolException;
import javax.xml.ws.handler.LogicalMessageContext;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPMessageContext;

public class SOAPHandler implements
javax.xml.ws.handler.soap.SOAPHandler<SOAPMessageContext> {

public Set<QName> getHeaders() {
return null;
}

public void close(MessageContext mc) {
}

public boolean handleFault(SOAPMessageContext mc) {
return true;
}

public boolean handleMessage(SOAPMessageContext mc) {
    System.out.println("Setting this before call");
if (Boolean.TRUE.equals(mc.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY))) {
   HandlerUtils.printMessageContext("Client SOAPHandler", mc);
   SOAPMessage sm = mc.getMessage();


    // Add header to outbound request (set cookie in HTTP client header)
   // Set the Cookie
   Map<String, List<String>> headers = (Map<String, List<String>>)mc.get(MessageContext.HTTP_REQUEST_HEADERS);
   if (headers == null) {
       headers = new HashMap<String, List<String>>();
       mc.put(MessageContext.HTTP_REQUEST_HEADERS, headers);
   }
   List<String> cookie = headers.get("Cookie");
   if (cookie == null) {
       cookie = new ArrayList<String>();
       headers.put("Cookie", cookie);
   }
   cookie.add("JSESSIONID=DBE5B99503B8F4B7EF76F4959D223B3B");
}

return true;
}
}

And then to test the service

public class ServiceTest {
  public static void main(String[] args) throws SFWebServiceFaultException {

    //Create object for service class, to get the port and call service method.
    PersonServiceImplService service = new PersonServiceImplService();
    PersonService port = service.getPersonServiceImplPort();
    SOAPHandler handler = new SOAPHandler();

    //Add the Handler to List
    List<Handler> handlerChain = new ArrayList<Handler>();
    handlerChain.add(handler);

    //Bind the handler to service 
    ((BindingProvider) port).getBinding().setHandlerChain(handlerChain);    

    //Call the service method
     System.out.println(port.greetPerson("Ganesh"));
  }
}
j2ko
  • 2,479
  • 1
  • 16
  • 29
Ethiraj
  • 11
  • 3
  • Reference url / good resource : https://web-gmazza.rhcloud.com/blog/entry/jaxws-handler-tutorial – Ethiraj Jul 19 '17 at 14:48