Secure web service calls using WSS4J return “An error was discovered processing the <wsse:Security> header”

StackOverflow https://stackoverflow.com/questions/10125753

  •  31-05-2021
  •  | 
  •  

Question

I’m trying to add password digest WS-Security bits to web service calls from my client using WSS4J. I generated the client classes from the WSDL using Axis' WSDL4J and followed the instructions for adding WS-Security's "Password Digest" headers to the SOAP message using WSS4J, but return with the error message, "An error was discovered processing the header". Adding debug messages, it doesn’t look like my CallbackHandler is ever getting hit. Am I doing something very wrong? Or am I missing some setup piece that goes unexplained in the WSS4J documentation?

class CSProvider {
    public CS get(CSService csService, URL url, String username)
            throws ServiceException {
        CS csPort = csService.getCSPort(url);

        ((Stub) csPort)._setProperty(WSHandlerConstants.ACTION, WSHandlerConstants.USERNAME_TOKEN);
        ((Stub) csPort)._setProperty(WSHandlerConstants.USER, username);
        ((Stub) csPort)._setProperty(UsernameToken.PASSWORD_TYPE, WSConstants.PW_DIGEST);
        ((Stub) csPort)._setProperty(WSHandlerConstants.PW_CALLBACK_CLASS, "com.example.namespace.to.PasswordCallbackHandler");

        return csPort;   
    }
}

public class PasswordCallbackHandler implements CallbackHandler {

    @Override
    public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
        for (Callback callback : callbacks) {
            if (callback instanceof WSPasswordCallback) {
                ((WSPasswordCallback) callback).setPassword(PasswordStore.getPassword());
            } else {
                throw new UnsupportedCallbackException(callback);
            }
        }
    }
}
Was it helpful?

Solution

After much poking around, I discovered the problem. As I expected, the web service requests were going out without having been through PasswordCallbackHandler, so they were returned with the given error message from the remote server, which was expecting valid authentication credentials. What took me awhile to determine was that I needed to construct the service locator (csService, in this case) like so:

CSService csService = new CSServiceLocator(new FileProvider("client_deploy.wsdd"));

with a client_deploy.wsdd file something like the following:

<deployment xmlns="http://xml.apache.org/axis/wsdd/" xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
    <transport name="http" pivot="java:org.apache.axis.transport.http.HTTPSender"/>
    <globalConfiguration>
        <requestFlow>
            <handler name="csHandler" type="java:org.apache.ws.axis.security.WSDoAllSender"/>
        </requestFlow>
    </globalConfiguration>
</deployment>

Then setting the properties from CSProvider.get() worked just fine.

I had avoided a wsdd file because all the other examples I saw used it to set the username and password class -- two things I won't know until runtime. A word for the wise: when the documentation says you can use the _setProperty() methods instead of a wsdd file, it only means for the purposes of setting those properties, not replacing the file entirely.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top