[SWS-341] Wss4jSecurityInterceptor and AcegiDigestPasswordValidationCallbackHandler do not correctly work together to update the Acegi security context. Created: 25/Apr/08  Updated: 05/May/08  Resolved: 30/Apr/08

Status: Closed
Project: Spring Web Services
Component/s: Security
Affects Version/s: 1.5
Fix Version/s: 1.5.1

Type: Bug Priority: Major
Reporter: Ian Butcher Assignee: Arjen Poutsma
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified
Environment:

Mac OS X 10.5, Java 1.5


Attachments: Text File AcegiDigestPasswordValidationCallbackHandler.patch     Text File DigestPasswordValidationCallbackHandlerUnitTests.patch    

 Description   

I am trying to hook up digest password handling and acegi authorization. I have managed to do this successfully with the plain text equivalent. I think I've managed to get close to the problem. When you configure the plain text acegi handler you wire in a ProviderManager.

<bean id="acegiHandler"
class="org.springframework.ws.soap.security.wss4j.callback.acegi.AcegiPlainTextPasswordValidationCallbackHandler">
<property name="authenticationManager" ref="authenticationManager"/>
</bean>

<bean id="authenticationManager" class="org.acegisecurity.providers.ProviderManager">
<property name="providers">
<bean class="org.acegisecurity.providers.dao.DaoAuthenticationProvider">
<property name="userDetailsService" ref="inMemoryDaoImpl"/>
</bean>
</property>
</bean>

<bean id="wsSecurityInterceptor" class="org.springframework.ws.soap.security.wss4j.Wss4jSecurityInterceptor">
<property name="validationActions" value="UsernameToken"/>
<property name="validationCallbackHandler">
<!-<ref local="acegiDigestPasswordHandler"/>->
<ref local="acegiHandler"/>
</property>
</bean>

<bean id="inMemoryDaoImpl" class="org.acegisecurity.userdetails.memory.InMemoryDaoImpl">
<property name="userMap">
<value>
Ernie=Bert,ROLE_SUPERVISOR
</value>
</property>
</bean>

It is the AbstractUserDetailsAuthenticationProvider (called by the AuthenticationManager) which, upon successful authentication, that actually sets the setAuthenticated(true) on the UsernamePasswordAuthenticationToken (see UsernamePasswordAuthenticationToken(principal, authentication.getCredentials(), user.getAuthorities()); ).

protected Authentication createSuccessAuthentication(Object principal, Authentication authentication,
UserDetails user)

{ // Ensure we return the original credentials the user supplied, // so subsequent attempts are successful even with encoded passwords. // Also ensure we return the original getDetails(), so that future // authentication events after cache expiry contain the details // IB this constructor sets 'authenticated' to true UsernamePasswordAuthenticationToken result = new UsernamePasswordAuthenticationToken(principal, authentication.getCredentials(), user.getAuthorities()); result.setDetails(authentication.getDetails()); return result; }

In the case of AcegiDigestPasswordValidationCallbackHandler you don't wire in a AuthenticationManager so even thought the credentials are valid it is never set to authentication in acegi SecurityContext. So the authorization fails even though the Principal has the correct GrantedAuthorities.

<bean id="wsSecurityInterceptor" class="org.springframework.ws.soap.security.wss4j.Wss4jSecurityInterceptor">
<property name="validationActions" value="UsernameToken"/>
<property name="validationCallbackHandler">
<ref local="acegiDigestPasswordHandler"/>
<!-<ref local="acegiHandler"/>->
</property>
</bean>

<bean id="inMemoryDaoImpl" class="org.acegisecurity.userdetails.memory.InMemoryDaoImpl">
<property name="userMap">
<value>
Ernie=Bert,ROLE_SUPERVISOR
</value>
</property>
</bean>

<bean id="acegiDigestPasswordHandler"
class="org.springframework.ws.soap.security.wss4j.callback.acegi.AcegiDigestPasswordValidationCallbackHandler">
<property name="userDetailsService">
<ref local="inMemoryDaoImpl"/>
</property>
</bean>



 Comments   
Comment by Tareq Abedrabbo [ 25/Apr/08 ]

Line 81 in UsernamePasswordAuthenticationToken:
UsernamePasswordAuthenticationToken authRequest =
new UsernamePasswordAuthenticationToken(principal, principal.getPassword());
This constructor sets authenticated to false.

The following constructor sets authenticated to true but needs GrantedAuthority[] as an argument:
UsernamePasswordAuthenticationToken(Object principal, Object credentials, GrantedAuthority[] authorities)

Comment by Tareq Abedrabbo [ 29/Apr/08 ]

After investigation, I think that setAuthenticated is not the culprit. The problem comes from the way WSS4J handles digest passwords. Unlike with plain text passwords, WSS4J takes the responsibility of validating digest passwords and thus "steals" the flow.
This can be seen in AcegiDigestPasswordValidationCallbackHandler.handleUsernameToken: only the password of the user is passed to the callback whereas the granted authorities are lost. Thus, when UsernamePasswordAuthenticationToken is initialized in handleUsernameTokenPrincipal(), the authorities are not passed.
It seems that the only way to solve the issue is by reloading the user details in handleUsernameTokenPrincipal. The impact on performace can be alleviated by the usage of an appropriate UserCache.

Ian,
I've tested the attached patch with a configuration similar to the one you posted and it seemed to work. It would be great if you could confirm that it solves the issue for you or if you could post the complete acegi configuration you used.

Comment by Ian Butcher [ 29/Apr/08 ]

I'll take a look in the next couple of days. My sample project is 'between configurations'. I am profiling different autht strategies.

Thanks,

Ian.

Comment by Ian Butcher [ 30/Apr/08 ]

Tareq I have verified this fix on my sample application. Great work and thanks.

Comment by Tareq Abedrabbo [ 30/Apr/08 ]

Unit tests (acegi & spring security).
Ian, thanks for the feedback.

Comment by Arjen Poutsma [ 30/Apr/08 ]

Fixed. Thanks for the patch, Tareq, and thanks for the feedback, Ian!

Comment by Arjen Poutsma [ 05/May/08 ]

Closing issues for 1.5.1

Generated at Thu Dec 14 17:00:57 UTC 2017 using JIRA 6.4.14#64029-sha1:ae256fe0fbb912241490ff1cecfb323ea0905ca5.