Run-As Authentication Replacement
AbstractSecurityInterceptor 能够在安全对象回调阶段临时替换 SecurityContext 和 SecurityContextHolder 中的 Authentication 对象。此情况仅发生在原始 Authentication 对象已由 AuthenticationManager 和 AccessDecisionManager 成功处理的情况下。RunAsManager 指示应在 SecurityInterceptorCallback 期间使用的替换 Authentication 对象(如果存在)。
通过在安全对象回调阶段临时替换 Authentication 对象,安全调用可以调用需要其他身份验证和授权凭证的其他对象。它还可以对特定 GrantedAuthority 对象执行任何内部安全检查。由于 Spring Security 提供了许多帮助类,这些帮助类可以根据 SecurityContextHolder 的内容自动配置远程协议,因此在调用远程 Web 服务时,这些替代特别有用。
Configuration
Spring Security 提供了 RunAsManager 接口:
Authentication buildRunAs(Authentication authentication, Object object,
List<ConfigAttribute> config);
boolean supports(ConfigAttribute attribute);
boolean supports(Class clazz);
第一个方法返回 Authentication 对象,该对象应在方法调用期间替换现有的 Authentication 对象。如果方法返回 null,则表示不应进行替换。第二个方法由 AbstractSecurityInterceptor 用于对其配置属性进行启动验证。supports(Class) 方法由安全拦截器实现调用,以确保已配置的 RunAsManager 支持安全拦截器呈现的安全对象类型。
Spring Security 为 RunAsManager 提供了一个具体的实现。RunAsManagerImpl 类返回一个替换 RunAsUserToken(如果任何 ConfigAttribute 以 RUN_AS_ 开头)。如果找到这样的 ConfigAttribute,则替换 RunAsUserToken 包含与原始 Authentication 对象相同的负责人、凭证和授权,并为每个 RUN_AS_ ConfigAttribute 添加一个新 SimpleGrantedAuthority。每个新 SimpleGrantedAuthority 都以 ROLE_ 为前缀,后跟 RUN_AS ConfigAttribute。例如,RUN_AS_SERVER 导致替换 RunAsUserToken 包含 ROLE_RUN_AS_SERVER 授权。
替换 RunAsUserToken 就像任何其他 Authentication 对象。它需要由 AuthenticationManager(可能通过委派给合适的 AuthenticationProvider)进行验证。RunAsImplAuthenticationProvider 执行此类身份验证。它接受任何介绍的 RunAsUserToken 为有效。
为了确保恶意代码不会创建 RunAsUserToken 并且向 RunAsImplAuthenticationProvider 展示以保证接受,密钥的哈希存储在所有生成的令牌中。RunAsManagerImpl 和 RunAsImplAuthenticationProvider 在 Bean 上下文中使用相同的密钥创建:
<bean id="runAsManager"
class="org.springframework.security.access.intercept.RunAsManagerImpl">
<property name="key" value="my_run_as_password"/>
</bean>
<bean id="runAsAuthenticationProvider"
class="org.springframework.security.access.intercept.RunAsImplAuthenticationProvider">
<property name="key" value="my_run_as_password"/>
</bean>
通过使用同一个密钥,可以验证每个 RunAsUserToken,因为它是由一个经过认可的 RunAsManagerImpl 创建的。出于安全原因,RunAsUserToken 在创建后不可变。