I published a detailed article on Run-As implementation in combination with @PreAuthorize .
1) Deploy your own RunAsManager , which creates Authentication for use at run time based on any user logic. The following example uses a custom annotation that provides an additional role:
public class AnnotationDrivenRunAsManager extends RunAsManagerImpl { @Override public Authentication buildRunAs(Authentication authentication, Object object, Collection<ConfigAttribute> attributes) { if(!(object instanceof ReflectiveMethodInvocation) || ((ReflectiveMethodInvocation)object).getMethod().getAnnotation(RunAsRole.class) == null) { return super.buildRunAs(authentication, object, attributes); } String roleName = ((ReflectiveMethodInvocation)object).getMethod().getAnnotation(RunAsRole.class).value(); if (roleName == null || roleName.isEmpty()) { return null; } GrantedAuthority runAsAuthority = new SimpleGrantedAuthority(roleName); List<GrantedAuthority> newAuthorities = new ArrayList<GrantedAuthority>();
This implementation will look for the @RunAsRole user-defined annotation for the protected method (for example, @RunAsRole("ROLE_AUDITOR") ) and, if found, will add this authority ( ROLE_AUDITOR in this case) to the list of granted permissions. RunAsRole itself is just a simple custom annotation.
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface RunAsRole { String value(); }
2) To issue a manager launch:
<bean id="runAsManager" class="org.springframework.security.access.intercept.RunAsManagerImpl"> <property name="key" value="my_run_as_key"/> </bean>
3) Register it:
<global-method-security pre-post-annotations="enabled" run-as-manager-ref="runAsManager"> <expression-handler ref="expressionHandler"/> </global-method-security>
4) An example of use in the controller:
@Controller public class TransactionLogController { @PreAuthorize("hasRole('ROLE_REGISTERED_USER')")
EDIT: The key value in RunAsManagerImpl can be whatever you want. Here is an excerpt from Spring docs on its use:
So that the malicious code does not create RunAsUserToken and is present for guaranteed acceptance of RunAsImplAuthenticationProvider , the key hash is stored in all generated tokens. RunAsManagerImpl and RunAsImplAuthenticationProvider created in a bean context with the same key:
<bean id="runAsManager" class="org.springframework.security.access.intercept.RunAsManagerImpl">
<bean id="runAsAuthenticationProvider" class="org.springframework.security.access.intercept.RunAsImplAuthenticationProvider">
Using the same key, each RunAsUserToken can be verified; it was created approved by RunAsManagerImpl . RunAsUserToken unchanged after creation for security reasons.