Why you should not use SOAP Headers

container

In the project I am working on right now we use apache XCF and Spring to provide a SOAP service to our customers. As part of the messages, there is a userid/password combo telling the application which user sent the request. I struggled with that today because I think that userid/password info should actually be in the SOAP Header, cleaning up my API, enable me to implement different authentication techniques in the future and generally be more “compliant” to the SOAP standard. Boy was I wrong.

First I needed to figure out how to get the userid/password info into the Header. Apache has some information on this which is supposed to be “very good” according to the web but I had quite a bit of trouble because it misses quite a bit of context.

At first, it took me ages to find out that I need to add this to my maven pom.xml file to actually “get” the security stuff onto my classpath:

<dependency>
 <groupId>org.apache.cxf</groupId>
 <artifactId>cxf-rt-ws-security</artifactId>
 <version>2.5.1</version>
</dependency>

I could find NO tutorial online telling me this, so I guess I saved you a good 20 minutes of searching right there.

Then, I needed to change the Spring configuration to include the mysterious “WSS4JInInterceptor” of which nobody understands what it does because it is an overdesigned elephant which implements obscure standards nobody seems to be using:

<jaxws:endpoint id="myCoolSOAPService" implementor="#myCoolService" address="/mycoolservice">
  <jaxws:inInterceptors>
    <ref bean="wss4jinterceptor"/>
  </jaxws:inInterceptors>
</jaxws:endpoint>

<bean id="wss4jinterceptor" class="org.apache.cxf.ws.security.wss4j.WSS4JInInterceptor">
  <constructor-arg>
    <map>
      <entry key="action" value="UsernameToken" />
      <entry key="passwordType" value="PasswordDigest" />
      <entry key="passwordCallbackRef">
        <ref bean="myPasswordCallback" />
      </entry>
    </map>
  </constructor-arg>
</bean>

As you can see, the WSS4JInterceptor is configured to accept Usernames and passwords (albeit in deeply, convoluted nested elements adding humongous amounts of XML bloat to your Header).

To be able to take the userid/password combo I dutifully started writing my password handler:

public class UseridPasswordCallback implements CallbackHandler {

     @Override
     public void handle(Callback[] arg0)
                 throws IOException, UnsupportedCallbackException {
          // Not implemented yet
     }
}

You can see that my handle(Callback) method is not implemented. And there is a good reason for that.

Just before implementing all the code, I checked the wiring of all this stuff. The application started up beautifully, and I pointed SOAPUI to the WSDL to generate some example requests. To my horror, SOAPUI did not generate example headers. For some reason, the whole CXF stack just “forgets” to put that info in the WSDL, or maybe the specs don’t leave room to have that information in the WSDL, I don’t know.

So I set out to see how to build that Soap Security header. It was nuts. Not only did I need to figure this out from crude and incomplete examples, reverse engineer xsd’s, and hand-craft it into the SOAPUI messages, I also had to deal with the awful error messages that gave me “Could not read XMReader” and the very helpful “ns1:InvalidSecurity”.

After an afternoon of absolute madness on something that should actually be infinitesimally simple, I gave up. I added the userid/password back into the functional calls (as part of my method signatures). And for a couple of very good reasons:

  1. The first an most important one: If I as a developer have this much trouble wading to the poorly documented, underutilized, astrophysics-level complexity just to add a freakin’ userid/password field to a SOAP message, how can I expect my users to ever accomplish this without rage-calling our helpline every 4 seconds?
  2. By making the fields part of the API, they become part of the WSDL, which immediately makes it clear what to add and where. SOAPUI even generates nice placeholders for it.
  3. I added an Aspect with an around advice intercepting the userid/password combo, use it to authenticate the user and immediately remove the password from memory. Simple, readable, effective and easily debuggable for any developer on the project.
  4. The pom.xml and the Spring configuration immediately become much simpler and gets rid of a few idiot acronyms in the process.

So there. Want to do SOAP Security as it was intended? Do yourself and your customers a favor: Don’t.

 

3 Responses to Why you should not use SOAP Headers

  1. Are you still using that piece of bloat they call SOAP? You know it’s been designed to work even through SMTP, right? JSON over HTTP is a much more modern way to do things, and much more efficient as it actually uses the underlaying HTTP protocol. Companies like eBay use this rather than SOAP, and with great effect.

  2. Roman says:

    Woah, about two years later I’m facing the same, confusing issue. My company got a SOAP service and now I am in charge of showing our customers how to implement it using Spring – maybe instead I should better develop another kind of API…
    Beeing quite new to Java, not to mention Spring, to me this turns out to be a really tricky, annoying undertaking.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s