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` 實現。`RunAsManagerImpl` 類在任何 `ConfigAttribute` 以 `RUN_AS_` 開頭時,都會返回一個替換的 `RunAsUserToken`。如果找到任何此類 `ConfigAttribute`,替換的 `RunAsUserToken` 將包含與原始 `Authentication` 物件相同的 principal、credentials 和 granted authorities,以及每個 `RUN_AS_` `ConfigAttribute` 對應的一個新的 `SimpleGrantedAuthority`。每個新的 `SimpleGrantedAuthority` 都以 `ROLE_` 為字首,後跟 `RUN_AS` `ConfigAttribute`。例如,`RUN_AS_SERVER` 會導致替換的 `RunAsUserToken` 包含一個 `ROLE_RUN_AS_SERVER` granted authority。

替換的 `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` 在建立後是不可變的。