Run-As 身份验证替换

AbstractSecurityInterceptor 能够在安全对象回调阶段临时替换 SecurityContextSecurityContextHolder 中的 Authentication 对象。这仅在原始 Authentication 对象被 AuthenticationManagerAccessDecisionManager 成功处理的情况下才会发生。RunAsManager 指示在 SecurityInterceptorCallback 期间应使用的替换 Authentication 对象(如果有)。

通过在安全对象回调阶段临时替换 Authentication 对象,安全调用可以调用需要不同身份验证和授权凭据的其他对象。它还可以对特定 GrantedAuthority 对象执行任何内部安全检查。由于 Spring Security 提供了许多帮助类,这些类会根据 SecurityContextHolder 的内容自动配置远程协议,因此这些 run-as 替换在调用远程 Web 服务时特别有用。

配置

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 类如果任何 ConfigAttributeRUN_AS_ 开头,则返回一个替换的 RunAsUserToken。如果找到任何此类 ConfigAttribute,则替换的 RunAsUserToken 包含与原始 Authentication 对象相同的 principal、凭据和授予的权限,以及每个 RUN_AS_ ConfigAttribute 的一个新的 SimpleGrantedAuthority。每个新的 SimpleGrantedAuthorityROLE_ 为前缀,后跟 RUN_AS ConfigAttribute。例如,RUN_AS_SERVER 会导致替换的 RunAsUserToken 包含一个 ROLE_RUN_AS_SERVER 授予的权限。

替换的 RunAsUserToken 与任何其他 Authentication 对象一样。它需要由 AuthenticationManager 进行身份验证,可能是通过委托给合适的 AuthenticationProviderRunAsImplAuthenticationProvider 执行此类身份验证。它接受任何呈现的 RunAsUserToken 作为有效。

为了确保恶意代码不会创建 RunAsUserToken 并将其呈现以供 RunAsImplAuthenticationProvider 保证接受,密钥的哈希值存储在所有生成的令牌中。RunAsManagerImplRunAsImplAuthenticationProvider 在 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 在创建后是不可变的。