3

I'm currently struggling a little with the security layer of a web service I'm writing using WSS4J and CXF.

We obviously do not wish to store plaintext passwords in our backend, but would prefer to persist only salted hashes.

The service specifications, however, are preset by our client (who will be using the service to push a bunch of data our way), down to the use of UsernameTokens with plaintext password (All communication is SSL encrypted)

Now the problem I'm facing is that I cannot seem to find a way to hash the plaintext password from the request security header on our end, match it against our records along with the username and authorise or decline the request.

Every single guide, tutorial or example project I've found so far relies on a CallbackHandler configured as input interceptor, which requires retrieving the correct plaintext password, which is then matched against the supplied credentials directly. Not an option if we only store the hash. A couple of sources I came across that were trying to solve similar problems merely recommended to force the client to do the hashing. But as I stated above, this is not possible in our case. The service specifications are clear on the matter and it's out of our hands.

This particularly interesting sounding thread sadly didn't help me either: How to implement WSS UsernameToken when password on the server is salted and hashed?

Surely there must be another way than a WSS4JInInterceptor/CallbackHandler, one that will allow me to digest the received plaintext password and check it against the salted hash in our database.

Any pointers would really be greatly appreciated. Thanks.

1
  • As this is highly specific, I would recommend asking on the Apache CXF mailing list. You're likely to get a much better response there. If you do find an answer outside the site, it'd be great if you could post it here and self-accept.
    – Polynomial
    Commented Jun 24, 2013 at 11:42

1 Answer 1

2

Thanks to Ivan Brencsics from the CXF mailing list for providing this hint. He writes:

If I understand correctly your question, your problem is that you dont [can't] access the password in the CallbackHandler, so you cannot hash it and compare it with the database.

I ran into the same problem recently, and I solved it by registering an org.apache.ws.security.validate.Validator instead of a CallbackHandler.

So for instance:

<jaxws:endpoint ...>
  <jaxws:properties>
    <entry key="ws-security.ut.validator" value-ref="sqlTokenValidator"/>
  </jaxws:properties>
</jaxws:endpoint>
...
<bean id="sqlTokenValidator" class="org.my.SqlTokenValidator"/>

and finally SqlTokenValidator:

public class SqlTokenValidator implements org.apache.ws.security.validate.Validator {

@Override
public Credential validate(Credential credential, RequestData data) 
throws WSSecurityException {
    ...
    UsernameToken usernameToken = credential.getUsernametoken();

    String username = usernameToken.getName();
    String password = usernameToken.getPassword();

   ... hash the password
   ... sql_auth(username, hash password)
   ... if failed throw new WSSecurityException(WSSecurityException.FAILED_AUTHENTICATION);

    return credential;
}

Oh and thanks to Polynomial for suggesting I check out the CXF mailing list. Still don't quite see the appeal of mailing lists over a proper forum ;)

1
  • Update for new WSS4J, validator is now org.apache.wss4j.dom.validate.Validator and the exception is now throw new WSSecurityException( WSSecurityException.ErrorCode.FAILED_AUTHENTICATION); Commented Jan 5, 2015 at 11:24

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .