- For a digest password, the CallbackHandler implementation was given the username and an identifier of WSPasswordCallback.USERNAME_TOKEN. It was then expected to set the password on the callback, and the processor did the comparison.
- For a plaintext password, the CallbackHandler implementation was given the username, password, and an identifier of WSPasswordCallback.USERNAME_TOKEN_UNKNOWN, and was expected to do all validation of the plaintext password itself, throwing an exception if validation failed.
- For a password of some unspecified non-standard type, WSS4J would throw an exception by default. However, if wssConfig.getHandleCustomPasswordTypes() returned true, then it would again dispatch the username, password, and an identifier of WSPasswordCallback.USERNAME_TOKEN_UNKNOWN to the CallbackHandler implementation for validation.
- For the case of a UsernameToken with no password element, it would again dispatch the username, password, and an identifier of WSPasswordCallback.USERNAME_TOKEN_UNKNOWN to the CallbackHandler implementation for validation.
- The standard plaintext password case is treated exactly the same as a non-standard password type, or the case of no password at all, by sending the callback handler a type of WSPasswordCallback.USERNAME_TOKEN_UNKNOWN.
- The treatment of passwords for both the standard digest and plaintext cases are inconsistent.
- A potential security hole exists where the user may not be aware that the CallbackHandler implementation *must* throw an exception on WSPasswordCallback.USERNAME_TOKEN_UNKNOWN when the password is not recognised.
- The CallbackHandler interface is being used in a non-standard way - it is only meant to supply a password, not do the validation.
- UsernameTokens with no password (i.e. used for key derivation) are stored using the same result (WSConstants.UT) as UsernameTokens that have been validated. This could lead to a security hole where a user assumes that because a UsernameToken has been processed, password validation has taken place.
- For the digest case, the CallbackHandler is given the username, password type and an identifier of WSPasswordCallback.USERNAME_TOKEN. It must set the password on the callback, and the validator does the comparison. This is the same as the old behaviour.
- The plaintext case has exactly the same behaviour as the digest case. The identifier is now WSPasswordCallback.USERNAME_TOKEN and not WSPasswordCallback.USERNAME_TOKEN_UNKNOWN, and the CallbackHandler does not do any authentication, but must set the password on the callback.
- The custom password type case defaults to the same behaviour as the plaintext case, assuming wssConfig.getHandleCustomPasswordTypes() returns true.
- For the case of a username token with no password element, the default behaviour is simply to ignore it, and to store it as a new result of type WSConstants.UT_NOPASSWORD.
So what if you want to validate the plaintext password against a directory store, rather than have the CallbackHandler set the password? Instead of implementing this behaviour in your CallbackHandler implementation, you can simply @Override the verifyPlaintextPassword(UsernameToken usernameToken) method in the validator instead. By simply plugging in a validator on the UsernameTokenProcessor (such as the NoOpValidator), it is possible to do any kind of custom validation (or none at all) on the token. This is a much better solution than having to write a custom processor, and replace the existing UsernameTokenProcessor.
I got stuck when using WSS4J in Spring WS.ReplyDelete
Signature validation is working, but there seems to be no CallbackHandler for delegating authentication to LDAP (like in XWSS): see http://static.springsource.org/spring-ws/sites/2.0/reference/html/security.html#security-certificate-authentication
In JIRA (https://issues.apache.org/jira/browse/WSS-266) you mentioned something about using a customized UsernameTokenValidator... could you please provide an example of how to do this?
How to hook this in into the Wss4jSecurityInterceptor?
<property name="validationActions" value="Signature" />
<property name="validationSignatureCrypto" ref="serverValidationCrypto" />
<property name="enableSignatureConfirmation" value="true" />
<ref bean="certificateValidationHandler" />
What version of WSS4J are you using? The validator stuff only applies to 1.6.0.ReplyDelete
I believe you are using the wss4j1.6.0 all you have to do in your bean delineation is add a explicit reference for the callback handler class which needs to be initialized with the user name/user alias and password.
I did not find any documentation on how to plug in custom validator. For example, how do I make CXF use NoOpValidator? I am using Apache CXF 2.4.0. In my case, I want to supply them programmatically.
To see how to configure a Validator implementation programatically in CXF 2.4.0 take a look at the SAMLTokenTest:ReplyDelete
final Map customMap = new HashMap();
CustomSamlValidator validator = new CustomSamlValidator();
It solves my problem. Thank you very much.ReplyDelete
I posted a comment with a Spring XML example of using a custom Validator here: http://coheigea.blogspot.com/2011/04/wss4j-16-introducing-validators.htmlReplyDelete
These look like really worthwhile changes. However, I'm having a problem. I don't want to use a password but I don't know what to set the action to in my Spring Bean config. If I set it to "Username", then I get an 'actions don't match' error down the line because when the SOAP is received without a password the integer representation is set to 8192 (UT_NOPASSWORD) where as the action list is still set to 1 (UT). There does not appear to be a corresponding text representation of UT_NOPASSWORD.
Hoping you can help.
For the record, this task was addressed by:ReplyDelete
I ran into the same problem as Paul R. above. Finally tracked it into the Processor that Paul found which taught me enough to make the right search to find this :-) Just wanted to say THANK YOU for providing the fix to the NoPassword problem. Was not looking forward to hacking around with the Processor and maintaining a duplicate code line!
do any one have a working sample ?(for learn)ReplyDelete
so you are expecting us to keep clean text passwords ??? What is the point of such implementation ?ReplyDelete
You can alternatively use the JAASUsernameTokenValidator to validate the password against an LDAP backend.ReplyDelete