Uploaded image for project: 'Spring Web Services'
  1. Spring Web Services
  2. SWS-341

Wss4jSecurityInterceptor and AcegiDigestPasswordValidationCallbackHandler do not correctly work together to update the Acegi security context.

    Details

    • Type: Bug
    • Status: Closed
    • Priority: Major
    • Resolution: Fixed
    • Affects Version/s: 1.5
    • Fix Version/s: 1.5.1
    • Component/s: Security
    • Labels:
      None
    • Environment:
      Mac OS X 10.5, Java 1.5

      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>

        Activity

        ibutcher Ian Butcher created issue -
        arjen.poutsma Arjen Poutsma made changes -
        Field Original Value New Value
        Fix Version/s 1.5.1 [ 10917 ]
        Hide
        tareq Tareq Abedrabbo added a comment -

        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)

        Show
        tareq Tareq Abedrabbo added a comment - 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)
        Hide
        tareq Tareq Abedrabbo added a comment -

        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.

        Show
        tareq Tareq Abedrabbo added a comment - 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.
        tareq Tareq Abedrabbo made changes -
        Hide
        ibutcher Ian Butcher added a comment -

        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.

        Show
        ibutcher Ian Butcher added a comment - 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.
        arjen.poutsma Arjen Poutsma made changes -
        Status Open [ 1 ] In Progress [ 3 ]
        Hide
        ibutcher Ian Butcher added a comment -

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

        Show
        ibutcher Ian Butcher added a comment - Tareq I have verified this fix on my sample application. Great work and thanks.
        Hide
        tareq Tareq Abedrabbo added a comment -

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

        Show
        tareq Tareq Abedrabbo added a comment - Unit tests (acegi & spring security). Ian, thanks for the feedback.
        tareq Tareq Abedrabbo made changes -
        Hide
        arjen.poutsma Arjen Poutsma added a comment -

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

        Show
        arjen.poutsma Arjen Poutsma added a comment - Fixed. Thanks for the patch, Tareq, and thanks for the feedback, Ian!
        arjen.poutsma Arjen Poutsma made changes -
        Resolution Fixed [ 1 ]
        Status In Progress [ 3 ] Resolved [ 5 ]
        Hide
        arjen.poutsma Arjen Poutsma added a comment -

        Closing issues for 1.5.1

        Show
        arjen.poutsma Arjen Poutsma added a comment - Closing issues for 1.5.1
        arjen.poutsma Arjen Poutsma made changes -
        Status Resolved [ 5 ] Closed [ 6 ]
        Transition Time In Source Status Execution Times Last Executer Last Execution Date
        Open Open In Progress In Progress
        4d 21h 5m 1 Arjen Poutsma 29/Apr/08 10:55 PM
        In Progress In Progress Resolved Resolved
        23h 26m 1 Arjen Poutsma 30/Apr/08 10:21 PM
        Resolved Resolved Closed Closed
        4d 22h 59m 1 Arjen Poutsma 05/May/08 9:21 PM

          People

          • Assignee:
            arjen.poutsma Arjen Poutsma
            Reporter:
            ibutcher Ian Butcher
          • Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved: