Discussions

XML & Web services: How do i send an authentication header using Spring/JAXRPC?

  1. I have a webservice which im accessing from http://www.codebump.com/services/zipcodelookup.asmx?WSDL

    Its pretty simple and I was able to use Axis to generate the stub /data model classes and then strip out the connection specific stuff in favor of usings Springs JAXRPC endpoint support.

    All seems to be going well except that it needs to be authenticated -- that is, a header called
    "AuthenticationHeader" needs to be sent along with a password string.

    Or, put another way, how do i use/modify/coerce Springs support into allowing me to add

    <soap:Header>
        <t:AuthenticationHeader xmlns:t="http://skats.net/services/">
            <SessionID xsi:type="xsd:string">${SOMEHOW OR ANOTHER MY PASSWORD HAS TO BE HERE}</SessionID>
        </t:AuthenticationHeader>
    </soap:Header>

    to the request?

    Thanks again,
    Joshua

    The major/relevant code is:



    /////// -----------------------------------------------------------------------
    // CODE
    /////// -----------------------------------------------------------------------

    import net.skats.services.*;
    import org.apache.axis.encoding.ser.BeanDeserializerFactory;
    import org.apache.axis.encoding.ser.BeanSerializerFactory;
    import org.springframework.remoting.jaxrpc.JaxRpcPortProxyFactoryBean;

    import javax.xml.namespace.QName;
    import javax.xml.rpc.Service;
    import javax.xml.rpc.encoding.TypeMapping;
    import javax.xml.rpc.encoding.TypeMappingRegistry;
    import javax.xml.rpc.handler.HandlerInfo;
    import java.util.List;


    public class ZipcodePortProxyFactoryBean extends JaxRpcPortProxyFactoryBean {

        protected void postProcessJaxRpcService(Service service) {

            QName port = new QName(this.getNamespaceUri(), this.getPortName());
            List list = service.getHandlerRegistry().getHandlerChain(port);
            list.add(new HandlerInfo(CustomHandler.class, null, null)); // code for custom handler follows


            TypeMappingRegistry registry = service.getTypeMappingRegistry();
            TypeMapping mapping = registry.createTypeMapping();
            registerBeanMapping(mapping, GeoPlaceDistance.class, "GeoPlaceDistance");
            registerBeanMapping(mapping, ZipCodeCoordinates.class, "ZipCodeCoordinates");
            registerBeanMapping(mapping, UserPlaceDetail.class, "UserPlaceDetail");
            registerBeanMapping(mapping, ZipCodeDistances.class, "ZipCodeDistances");
            registerBeanMapping(mapping, FilterType.class, "FilterType");


            registry.register("http://schemas.xmlsoap.org/soap/encoding/", mapping);
        }

        protected void registerBeanMapping(TypeMapping mapping, Class type, String name) {
            QName qName = new QName("urn:ZipcodeService", name);
            mapping.register(type, qName,
                    new BeanSerializerFactory(type, qName),
                    new BeanDeserializerFactory(type, qName));
        }

    }


    // that code in turn references CustomHandler, which looks like:

    package net.skats.services.misc;

    import javax.xml.namespace.QName;
    import javax.xml.rpc.JAXRPCException;
    import javax.xml.rpc.handler.GenericHandler;
    import javax.xml.rpc.handler.MessageContext;
    import javax.xml.rpc.handler.soap.SOAPMessageContext;
    import javax.xml.soap.SOAPEnvelope;
    import javax.xml.soap.SOAPException;
    import javax.xml.soap.SOAPHeader;
    import javax.xml.soap.SOAPMessage;

    public class CustomHandler extends GenericHandler {


              // hardcoded for testing
             static private String PW = "my pw as obtained from the service hoster's website" ;


        public QName[] getHeaders() {
            //
            return null // return new QName[]{ new QName("AuthenticationHeader", PW) } ;

                  
        }

        public boolean handleRequest(MessageContext messageContext) {


            SOAPMessageContext smc = (SOAPMessageContext) messageContext;
            SOAPMessage msg = smc.getMessage();
            /*
    <soap:Header>
        <t:AuthenticationHeader xmlns:t="http://skats.net/services/">
            <SessionID xsi:type="xsd:string">${SOMEHOW OR ANOTHER MY PASSWORD HAS TO BE HERE}</SessionID>
        </t:AuthenticationHeader>
    </soap:Header>


            */
             

            try {
                SOAPEnvelope envelope = msg.getSOAPPart().getEnvelope();
                SOAPHeader header = envelope.getHeader();
                //header.setAttribute("AuthenticationHeader", );
                // header.setAttributeNS("http://skats.net/services/","SessionID" , PW );

            } catch (SOAPException e) {
                throw new JAXRPCException(e);
            }

            return true;

        }

    }
    The declaration is:


    /// the domain model /client-side generated code is excluded, but suffice it to say that it's not th eproblem



     /// the java use-case
     public void testZipcodeSearch() throws Throwable {
             IZipCodeService service = (IZipCodeService) _context.getBean("zipcodeService");
            ZipCodeCoordinates coords = service.GetZipCodeCoordinates("90211");
            log(coords.getLatRadians() + " : " + coords.getLonRadians());
        }




    //// the xml

        <bean id="zipcodeService" class="net.skats.services.misc.ZipcodePortProxyFactoryBean">

            <property name="serviceFactoryClass">
                <value>org.apache.axis.client.ServiceFactory</value>
            </property>

            <property name="wsdlDocumentUrl">
                <value>http://www.codebump.com/services/zipcodelookup.asmx?WSDL>
            </property>

            <property name="namespaceUri">
                <value>http://skats.net/services/>
            </property>

            <property name="serviceName">
                <value>ZipCodes</value>
            </property>

            <property name="portName">
                <value>ZipCodesSoap</value>
            </property>
            <property name="portInterface">
                <value>net.skats.services.ZipCodesSoap</value>
            </property>
           <property name="serviceInterface">
                <value>net.skats.services.IZipCodeService</value>
            </property>
      
        </bean>
  2. May be you can add a header using the addHeaderElement method of the SoapHeader interface.