Run-As 认证替换
AbstractSecurityInterceptor 能够在安全对象回调阶段临时替换 SecurityContext 和 SecurityContextHolder 中的 Authentication 对象。这只会在原始 Authentication 对象成功通过 AuthenticationManager 和 AccessDecisionManager 处理后发生。RunAsManager 指示在 SecurityInterceptorCallback 期间应使用的替换 Authentication 对象(如果有)。
通过在安全对象回调阶段临时替换 Authentication 对象,受保护的调用可以调用需要不同认证和授权凭据的其他对象。它还可以针对特定的 GrantedAuthority 对象执行任何内部安全检查。由于 Spring Security 提供了许多根据 SecurityContextHolder 的内容自动配置远程协议的辅助类,因此在调用远程 Web 服务时,这些 run-as 替换特别有用。
配置
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 的具体实现。如果任何 ConfigAttribute 以 RUN_AS_ 开头,则 RunAsManagerImpl 类返回一个替换的 RunAsUserToken。如果找到任何此类 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 在创建后是不可变的。