Announcement Announcement Module
Collapse
No announcement yet.
WS authentication against hashed password Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • WS authentication against hashed password

    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!

  • #2
    Until Spring WS 2.0.x you could do it like this with the help of Spring security:

    Code:
    	<bean id="wss4jSecurityInterceptor" 
    		class="org.springframework.ws.soap.security.wss4j.Wss4jSecurityInterceptor">
    		<property name="validationActions" value="UsernameToken"/>
    		<property name="validationCallbackHandler" ref="springPlainTextPasswordValidationCallbackHandler"/>
    	</bean>
    
    	<bean id="springPlainTextPasswordValidationCallbackHandler"
    		class="org.springframework.ws.soap.security.wss4j.callback.SpringPlainTextPasswordValidationCallbackHandler">
    		<property name="authenticationManager" ref="authenticationManager"/>
    	</bean>
    
    	<bean id="authenticationManager"
                     class="org.springframework.security.authentication.ProviderManager">
    		<property name="providers">
    			<list>
    				<ref local="daoAuthenticationProvider"/>
    			</list>
    		</property>
    	</bean>
    
        <bean id="daoAuthenticationProvider"
        	class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
        	<property name="userDetailsService" ref="userDetailsService"/>
        	<property name="passwordEncoder" ref="passwordEncoder"/>
        	<property name="saltSource" ref="saltSource"/>
        </bean>
    
        <bean id="userDetailsService"
        	class="myapp.UserDetailsService">
        	<property name="userDao" ref="userDao"/>
        </bean>
        
        <bean id="passwordEncoder"
        	class="myapp.PasswordEncoder"/>
        	
        <bean id="saltSource"
        	class="org.springframework.security.authentication.dao.ReflectionSaltSource">
        	<property name="userPropertyToUse" value="objectId"/>
        </bean>
    Quite a lot of beans, but works well.

    Unfortunately, this has been broken in WS 2.1.0 (at least as far as I can see), because SpringPlainTextPasswordValidationCallbackHandler is no longer available and its successor, SpringSecurityPasswordValidationCallbackHandler, does no longer provide the possibility to plug-in an AuthenticationManager.

    So, if anybody knows of a possibility to do something similar in 2.1.0 I would be happy to hear from it.

    Comment

    Working...
    X