Connexxion : Connecting Life with Technology

Byte by Byte Impressions on Technology, People and Process !

Acegi : Using SwitchUserProcessingFilter : Playing another user

Posted by vikashazrati on Monday, July 16, 2007

Recently on one of our projects we had the need to allow the ROLE_ADMIN to login as another user without knowing or changing the password of that user. For example ‘Jack’ has the ROLE_ADMIN and ‘Suzy’ has the ROLE_USER. Now ‘Jack’ wants to login as suzy without knowing her password and carry out some tasks on her behalf acting as her when ‘Suzy’ is unavailable and some work needs to be done, of course you should provide a mechanism to audit and log whenever ‘Jack’ wants to play a different role.This is fairly easy to implement using Acegi

The SwitchUserProcessingFilter in Acegi helps to achieve this functionality. The below steps will show how to configure and use it

1. In the filter chain for acegi, include the filter SwitchUserProcessingFilter as

<!– ======================== FILTER CHAIN ======================= –>
<bean id=”filterChainProxy” class=”org.acegisecurity.util.FilterChainProxy”>
<property name=”filterInvocationDefinitionSource”>
<value>
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
PATTERN_TYPE_APACHE_ANT
/images/**=#NONE#
/scripts/**=#NONE#
/styles/**=#NONE#
/ **=httpSessionContextIntegrationFilter,authenticationProcessingFilter,securityContextHolderAwareRequestFilter,rememberMeProcessingFilter,anonymousProcessingFilter,
exceptionTranslationFilter,filterInvocationInterceptor,switchUserProcessingFilter
</value>
</property>
</bean>

Make sure that this filter is placed AFTER filterInvocationInterceptor and FilterSecurityInterceptor else any role would be able to “Role play” rather than ROLE_ADMIN role. Remember it is filter chaining.

2. Define the bean definition for SwitchUserProcessingFilter as

<bean id=”switchUserProcessingFilter” class=”org.acegisecurity.ui.switchuser.SwitchUserProcessingFilter”>
<property name=”userDetailsService” ref=”userDao” />
<property name=”switchUserUrl”><value>/j_acegi_switch_user</value></property>
<property name=”exitUserUrl”><value>/j_acegi_exit_user</value></property>
<property name=”targetUrl”><value>/mainMenu.html</value></property>
</bean>

here you would just need to change the targetUrl depending on where you need to go after the SWITCH.

userDao is the Dao which you use for your daoAuthenticationProvider

<bean id=”daoAuthenticationProvider” class=”org.acegisecurity.providers.dao.DaoAuthenticationProvider”>
<property name=”userDetailsService” ref=”userDao”/>
<property name=”userCache” ref=”userCache”/>
<property name=”passwordEncoder” ref=”passwordEncoder”/>
</bean>

3. In your filterInvokationFilter be sure to restrict the access just for ROLE_ADMIN, you definitely don’t want all your users logging in as someone else.

<bean id=”filterInvocationInterceptor” class=”org.acegisecurity.intercept.web.FilterSecurityInterceptor”>
<property name=”authenticationManager” ref=”authenticationManager”/>
<property name=”accessDecisionManager” ref=”accessDecisionManager”/>
<property name=”objectDefinitionSource”>
<value>
PATTERN_TYPE_APACHE_ANT
……
……
/j_acegi_switch_user*=ROLE_ADMIN
</value>
</property>
</bean>

4. Now whenever the ROLE_ADMIN wants to role play as another user
The ROLE_ADMIN logs in with his username and password. Then,there should be a link which has the following

http://localhost:8080/j_acegi_switch_user?j_username=vikas

where ‘vikas’ is the username of the user that the ROLE_ADMIN wants to play as. Since only the ROLE_ADMIN should be allowed to see this link you can use the Acegi taglibs to make the link available only to ROLE_ADMIN

<authz:authorize ifAllGranted=”ROLE_ADMIN”>
<< Switch User Link Here>>
</authz:authorize>

When the switch happens On successful switch, the user’s SecurityContextHolder will be updated to reflect the specified user and will also contain an additional SwitchUserGrantedAuthority which contains the original user. To ‘exit’ from a user context, the user will then need to access a URL (see exitUserUrl) that will switch back to the original user as identified by the SWITCH_USER_GRANTED_AUTHORITY

To exit from the Role play there should be a link to say

http://localhost:8080/j_acegi_exit_user

This would bring the ROLE_ADMIN to his own account.

Nested switching and exit is also possible. What this means is that if Jack and Suzy both have ROLE_ADMIN, then Jack can switch to become Suzy who can further switch to become John. Now once the user exits from John realm he comes to Suzy and then on another exit back to Jack.

Conclusion: Switching users is can be easily configured using Acegi. However remember that with ‘Great Power comes Great Responsibility’ so use this with care.

4 Responses to “Acegi : Using SwitchUserProcessingFilter : Playing another user”

  1. Francoise Says:

    Thanks for your post
    it helps me to make SwitchUserProcessingFilter work
    Francoise

  2. Tinawju Says:

    Good site! chanel handbag and purse [url=http://bags.freepimphost.com/chanel-purse]chanel handbag and purse[/url]

  3. Sunil Says:

    Hi Vikas,

    Thanks for providing this useful information.
    But I have a different requirement, an Admin user wants to login (switch) to another user’s account while maintaining his/her account working.
    Say an Admin user can access the profile of any user and there is a link provided , which should open that user’s home page in a new window when Admin user clicks on the link and Admin user’s window should be remain unaffected.
    It might be weired but this is the requirement.

    Thanks in advance,
    Sunil

  4. Sunil Pratap Says:

    Hi Vikas,

    I have configured MethodSecurityInterceptor for ACL purpose.
    I have an interface where all business methods are declared and then i have an abstract base class which implements few of the methods declare in the interface and other methods are implemented by concrete classes.
    Now I wanna intercept method invocations to the concrete classes for the methods define in concrete classes as well as in abstract class.
    I am adding all the methods defined in the base interface in the objectDefinitionSource of the MethodSecurityInterceptor as these are implemented by either of abstract class or the concrete classes.
    Now i am using BeanNameAutoProxyCreator bean to apply this interceptor to all the concrete classes. but what i found is that spring is not intercepting method calls for the methods defined in the abstract class.
    When I created a separate concrete class backed by a separate interface it’s working fine.
    I guess problem is with Spring IOC container not with the ACEGI. Does anybody has faced this kind of problem before? I don’t know how to fix this :(
    Any help is much appreciated.

    Thanks
    Sunil

Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>