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
CXF relies on WSS4J in large part to implement WS-Security. Within your own services, WS-Security can be activated by using WS-SecurityPolicy, which provides a comprehensive and sophisticated validation of the security properties of a received message.
Overview. Apache CXF™ is an open source services framework. CXF helps you build and develop services using frontend programming APIs, like JAX-WS and JAX-RS. These services can speak a variety of protocols such as SOAP, XML/HTTP, RESTful HTTP, or CORBA and work over a variety of transports such as HTTP, JMS or JBI.
Class WSS4JOutInterceptor Property name for a map of action IDs ( Integer ) to action class names.
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/>.
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);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With