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:
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.
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