Skip to content

Switch User, ‘su’ like behavior in Spring Security

Does your spring web application have an admin interface to manage users? Does your admin need to “login as user” in production scenarios to assist user behavior?

If you’re thinking of a feature similar to Unix ‘su’ and if you’re using Spring 3.x then you’re lucky. Spring Security provides an out-of-the-box solution.

The below example assumes a JSF / Spring 3.x webapp. It should work for a JSP or other view technologies.

spring-security.xml: Add the filter bean and configure filter position in http

  ...
  ...

  <!-- Register a 'su' filter -->	
  <bean id="switchUserProcessingFilter" class="org.springframework.security.web.authentication.switchuser.SwitchUserFilter"> 
     <property name="userDetailsService" ref="yourCustomDetailService" />
     <!--No need to change this, unless you need a fancy name that you configure in faces-nav.xml -->
     <property name="switchUserUrl" value="/j_spring_security_switch_user" />
     <property name="switchFailureUrl" value="your-url" />
     <!--No need to change this, unless you need a fancy name that you configure in faces-nav.xml -->     
     <property name="exitUserUrl" value="/j_spring_security_exit_user" />
     <!--The page to redirect to after switchUser is authorized. Typically the same page as 'login success' home page -->
     <property name="targetUrl" value="your-url" />	    
  </bean>

  <http auto-config="false" entry-point-ref="authenticationEntryPoint">
      <!-- other filters -->
      ....
      <custom-filter position="SWITCH_USER_FILTER" ref="switchUserProcessingFilter" />		
   </http>
....

JSF Admin Page for Richfaces 3.x. (For Primefaces or Icefaces their relevant tags would work, too).

<h:form>
  Switch User:		    
  <t:inputText value="#{userController.switchUsername}/>	     	
  Click <h:commandLink value="here" action="#{userController.switchUser}"/> to switch to user.	    	 		    	
</h:form>

Spring @Controller for binding, validating, adding username query param as ‘j_username’ and forwarding it to ‘switchUserUrl’.

If you use jsps, jquery, or other view technologies, you would need similar logic.

Note that unlike a user login flow, you wouldn’t need to send j_password in the query param. SwitchUserFilter assumes a higher authority (super user, admin user) invokes the workflow, and as such, downgrading to a non-admin user is not a security risk.


@Controller
public class UserController {
    private String switchUsername;
    ...

    public String switchUser() throws IOException, ServletException {		
	if ( StringUtils.isEmpty( this.switchUsername ) ) {
            FacesUtils.reportError("username is required");
            return null;
	}
	
	String path = /j_spring_security_switch_user + "?j_username=" + switchUsername;
	
        // Forward the original request with username as query params			
	ExternalContext context = FacesUtils.getExternalContext();
	RequestDispatcher dispatcher = ((ServletRequest) context.getRequest()).getRequestDispatcher(path);
	dispatcher.forward( (ServletRequest) context.getRequest(), (ServletResponse) context.getResponse() );
	FacesUtils.getFacesContext().responseComplete();
	return null;
    }
}

On successful admin login, switchUserFilter now redirects to ‘targeturl’ and with appropriate AuthenticationToken initialized and the rest of your flow should work as is. When user logs off, of course, the switch user logs off. It would be nice to have an option like ‘returnToSuperUser’ so when user logs out, it returns to admin. You can do that by overriding SwitchUserFilter#attemptExitUser.

Can you switchUser from an already Switched user? In theory, it looks like you can. Read SwitchUserFilter. I can’t imagine why you would want to do it though.

[Slashdot] [Digg] [Reddit] [del.icio.us] [Facebook] [Technorati] [Google] [StumbleUpon]

Post a Comment

Your email is never published nor shared. Required fields are marked *
*
*