WS-security (usernametoken) for CXF - encrypted passwords possible?
Asked Answered
O

2

7

I'm trying to get together with CXF's WS-security implementation(usernametoken). I've done everything as said at http://cxf.apache.org/docs/ws-security.html. My PasswordCallbackHandler seems to be working, but what bothers me is a part:

    if (pc.getIdentifier().equals("joe")) {
        // set the password on the callback. This will be compared to the
        // password which was sent from the client.
        pc.setPassword("password");
    }

as said

Note that for up to and including CXF 2.3.x, the password validation of the special case of a plain-text password (or any other yet unknown password type) is delegated to the callback class, see org.apache.ws.security.processor.UsernameTokenProcessor#handleUsernameToken() method javadoc of the WSS4J project. In that case, the ServerPasswordCallback should be something like the following one:

so up to cxf 2.3.x it was done like that

   if (pc.getIdentifer().equals("joe") {
       if (!pc.getPassword().equals("password")) {
            throw new IOException("wrong password");
       }
    }

My issue is: I don't want to pc.setPassword("plainTextPassword") as I want to store it in any resource. This up-to-2.3.x design would allow me to do this since I could encrypt it manually. Are there any ways of setting encrypted password in callback or doing usernametoken authentication for stored, encrypted passwords ?

I'm using cxf 2.5.x

Ohalloran answered 19/1, 2012 at 12:2 Comment(3)
Hello! As far as I'm concerned, the WSS4J doing all work of encrypting for you. If you want to encrypt the password one more time in the callback, why won't use a custom encryptor inside it?Node
I wanted to store encrypted password (i.e. by sha) and then challange incoming with the stored one). Point was to store encrypted passwordOhalloran
The question is relevant to me, because I (the software) don't know the user's actual password. I only have a one-way (crypt) of the password, so I cannot provide the actual password to the WSS4J callback, but I can check if the supplied password is valid. I'm sure it can be done somehow...Huambo
H
6

The answer (which I've tried) is found in this blog page:

http://coheigea.blogspot.com/2011/06/custom-token-validation-in-apache-cxf.html

The essence is to create a subclass of org.apache.ws.security.validate.UsernameTokenValidator, and override the verifyPlaintextPassword method. In that method, the UsernameToken (which provides getName and getPassword) is passed. Throw an exception if they're not valid.

To install the custom validator in a spring configuration, add e.g.

  <jaxws:properties>
    <entry key="ws-security.ut.validator">
        <bean class="com.example.webservice.MyCustomUsernameTokenValidator" />
    </entry>
  </jaxws:properties>

into the <jaxws:endpoint/>.

Huambo answered 11/9, 2012 at 19:48 Comment(0)
R
2

Callback Handlers are there to provide the plaintext password or verify a digest password where the plaintext password is known.

But if you don't know the plaintext i.e. its one way hashed, then the callback interface is not appropriate and you should create a class that implements the Validator interface.

Here is my example implementation of that interface that uses a JPA repository in which the password is already stored as a BCrypt hash.

Use with the ws-security.ut.validator property documented here

i.e. as a CXF property <entry key="ws-security.ut.validator" value-ref="com.package.CustomUsernameTokenValidator" />

public class CustomUsernameTokenValidator implements Validator {
    @Autowired
    ProfileRepository profileRepository;
    @Override
    public Credential validate(Credential credential, RequestData requestData) throws WSSecurityException {
        Profile profile = profileRepository.findByName(credential.getUsernametoken().getName());
        if (profile != null) {
            if (BCrypt.checkpw(credential.getUsernametoken().getPassword(), profile.getPassword())) {
                return credential;
            }
        }
        throw new WSSecurityException(WSSecurityException.ErrorCode.FAILED_AUTHENTICATION);     
    }
}
Radiator answered 22/3, 2015 at 21:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.