Hello,

I believe this is a very standard scenario, yet it is being difficult to get answers, so I hope you guys can help me.

I'm creating a web service which needs authentication by username and password; I chose Wss4jSecurityInterceptor and created my WsPasswordCallbackHandler. Tests against hardcoded values worked fine. The issue is that I haven't found so far an example on how to authenticate the received credentials against hashed password. It is a requirement on this WS that it uses a special type of user in our web app, which is stored along with regular users in our database, and the passwords are hashed with a legacy algorithm.

I'm not as experienced as I'd like with security details, but it seems to imply from the availability of digest authentication and implementations such as SimplePasswordValidationCallbackHandler, that the application is expected to store the password as plain text.

So, the only way I came up with to achieve my requirement was: supply a WssConfig that requires plain text password and sets an extended UsernameTokenValidator which hashes the incoming password, so that later comparison with database password retrieved by WsPasswordCallbackHandler works as it should. A snip of my code below.

XML config:
Code:
	<bean id="wss4jSecurityInterceptor" class="org.springframework.ws.soap.security.wss4j.Wss4jSecurityInterceptor">
	    <property name="validationActions" value="UsernameToken"/>
	    <property name="securementActions" value="NoSecurity"/>
	    <property name="validationCallbackHandler">
	    	<ref bean="myWsPasswordCallbackHandler"/>
	    </property>
	     <property name="wssConfig">
	    	<ref bean="myWssConfig"/>
	     </property>
	</bean>
MyWssConfig:
Code:
@Component("myWssConfig")
public class MyWssConfig extends WSSConfig {
	public MyWssConfig() {
		setValidator(WSSecurityEngine.USERNAME_TOKEN, new MyUsernameTokenValidator());
		setRequiredPasswordType(WSConstants.PASSWORD_TEXT);
	}
}
MyUsernameTokenValidator:
Code:
public class MyUsernameTokenValidator extends UsernameTokenValidator {
	@Override
	protected void verifyPlaintextPassword(UsernameToken usernameToken, RequestData data) throws WSSecurityException {
		if (usernameToken != null && usernameToken.getPassword() != null) {
			usernameToken.setPassword(someBean.hashPassword(usernameToken.getPassword()));
		}
		super.verifyDigestPassword(usernameToken, data);
	}
}
MyWsPasswordCallbackHandler:
Code:
@Component("myWsPasswordCallbackHandler")
public class MyWsPasswordCallbackHandler extends AbstractWsPasswordCallbackHandler {
	@Override
	protected void handleUsernameToken(WSPasswordCallback callback) throws IOException {
		callback.setPassword(someBean.getPasswordHash(callback.getIdentifier()));
	}
}
Also, I'm leaving Spring Security out, as it could add extra complexity to work along our custom security schemes; we will add it eventually, just not now. I also preferred WSS4J over XWSS for simplicity reasons. If using either Spring Security or WXSS leads me to a more standard way to do this auth, I'd like to know it.

I'm afraid I'm doing some heavy workaround for something that should be simpler, I only don't know how. I'd like to leave the authentication scheme more flexible (accepting digest and maybe X509 in the future), and this way I'm hardcoding it to plain text Oasis.

What's the "best" way to do this task? Any help is welcome!

Thanks!