Switch Once - Stateless Impersonation

For testing APIs, there is a need to allow certain privileged users to impersonate other users. We already provide this feature in our web applications through Spring Security's "Switch User" filter.

The API apps are a little different from traditional web apps in that the security context is stateless - a user's authorization information is not preserved between requests. Spring's switch-user functionality assumes the traditional stateful setup, so out-of-the-box  does not support the stateless API model.

What we want to happen in a single request:

New Filter SwitchUserOnceFilter - Configuring A Web App

A new filter was created in csf-security to handle this functionality: edu.mit.csf.security.spring.filter.SwitchUserOnceFilter

For a web app to use this filter, it must be configured as a bean using this XML:

	<bean id="switchUserOnceFilter" class="edu.mit.csf.security.spring.filter.SwitchUserOnceFilter">
		<property name="userDetailsService" ref="mitAuthorizationUserDetailService"/>
		<property name="targetUrl" value="/"/>
		<property name="switchUserRole" value="ESAPIS_IMPERSONATE" />
	</bean>

IMPORTANT: the switchUserRole property specifies the role that a user must have in order to perform impersonation. So any user who needs to do impersonation must have this role, and must authenticate to the API as themself.

The switchUserOnce filter should be configured into the Spring Security chain of filters BEFORE the filterSecurityInterceptor entry, e.g.:

            <security:filter-chain pattern="/**" filters="esapisSecurityContextNonPersistenceFilter,
           		logoutFilter,
				hashAuthenticationProcessingFilter,
           		esapisAuthenticationProcessingFilter,
           		basicAuthenticationProcessingFilter,
           		exceptionTranslationFilter,
           		switchUserOnceFilter,
           		filterSecurityInterceptor"
            />

Placing the switchUserOnceFilter before the filterSecurityInterceptor ensures that filterSecurityInterceptor applies its authorization rules to the user we are impersonating, not the authenticated user.

Performing Impersonation

To actually do impersonation, the user must authenticate to the API application with their own credentials, whether this is via an X509 certificate or Touchstone login. The user must also supply a special request header that specifies the kerberos name of the user they want to impersonate. This header is:

X-Switch-User-Once

and as a request header, would look like this (impersonating David):

X-Switch-User-Once: dtanner

For reference, this header name is a static field in the filter: SwitchUserOnceFilter.SWITCH_USER_ONCE_HEADER