CAS 統(tǒng)一認證集成
1. 前言
在前面的小節(jié)中,我們介紹了兩種統(tǒng)一身份授權規(guī)范 OAuth2.0 和 SAML2.0,本節(jié)我們介紹另一種統(tǒng)一認證解決方案:「CAS」服務。
CAS 是由 JA-SIG 提供的企業(yè)級單點認證解決方案,推出以來在企業(yè) SSO 場景中被廣泛使用。Spring Security 完整的支持了 CAS,為多應用單點認證提供了快速集成方案。
更多關于 CAS 的介紹可以從此獲得:JA-SIG/CAS。
2. CAS 工作原理
CAS 是一套開源的企業(yè)級 SSO 項目,是 B / S 服務架構,支持多種通訊協(xié)議。CAS 的主要成員有 CAS 服務端和 CAS 客戶端。
2.1 CAS 服務端
CAS 服務端是一套基于 Spring 框架構建的應用系統(tǒng),是實現(xiàn) SSO 的核心構成。其軟件層面可分為三個層次:
- Web 服務(Spring MVC、Spring Webflow)
- 票據(jù)
- 認證系統(tǒng)
2.2 CAS 客戶端
CAS 客戶端是指可以和 CAS 服務端進行安全通訊的業(yè)務系統(tǒng)。CAS 通訊支持以下協(xié)議:
- CAS(版本1,2,3)
- SAML 1.1
- OpenID
- OAuth(1.0,2.0)
3. Spring Security 集成 CAS
3.1 交互流程
在Spring Security 集成 CAS 認證的過程中,共有三個核心組成部分:瀏覽器、CAS 認證中心和基于 Spring Security 構建的資源服務。
瀏覽器、認證中心、資源服務之間的交互流程如下:
- 當用戶訪問開放資源時,無需經過 CAS 認證中心或者資源服務器上的安全過濾器;
- 當用戶訪問私密資源時,資源服務器
ExceptionTranslationFilter
將會接收到AccessDeniedException
或是AuthenticationException
,要求用戶進行認證;
- 資源服務器在過濾器
ExceptionTranslationFilter
中查找 CAS 認證相關配置CasAuthenticationEntryPoint
,如有則認定使用了 CAS 認證; - 資源服務器通過讀取配置
CasAuthenticationEntryPoint
, 將用戶瀏覽器地址跳轉到認證中心,并指定返回地址; - 認證中心查看 Cookies 中是否保存了用戶信息,如有直接認證,如果沒有,要求用戶填入其用戶名密碼;
- 認證中心判斷登錄是否成功,瀏覽器將跳回原服務地址,并攜帶票據(jù)參數(shù);
- 回到資源服務后,
CasAuthenticationFilter
會持續(xù)監(jiān)聽/login/cas
地址的請求,過濾器會生成UsernamePasswordAuthenticationToken
用來保存票據(jù)信息,并將認證狀態(tài)置為已通過; - 資源服務的認證管理器
AuthenticationManager
傳遞票據(jù)到認證中心驗證用戶登錄信息; - 認證中心認證完成后,應用服務會檢查 CAS 返回的 XML 內容,判斷是允許訪問、拒絕訪問或者是其他策略;
- 通過之后,資源服務的認證管理器會繼續(xù)獲取用戶的權限信息;
- 如果獲取成功,認證中心將生成認證憑證 Token 并保存到安全上下文;
- 用戶瀏覽器回到最初訪問地址,并且順利獲得資源。
3.2 配置 CAS 客戶端
從前面的流程中我們看到,與 CAS 認證中心集成過程中,Spring Security 用來構建資源服務,也就是 CAS 的認證客戶端。此處我們來看如何通過 Spring Security 配置 CAS 認證客戶端。
3.2.1 服務票據(jù)認證
集成的第一步是配置資源服務獲取到 Token 之后,如何到 CAS 認證中心去驗證。多數(shù)情況下,這一步是必須的。我們需要在 Spring 上下文中創(chuàng)建 ServiceProperties
Bean 對象。
該對象必須配置 service 屬性,其值為一個 URL 地址,用來被過濾器 CasAuthenticationFilter
偵聽。配置代碼如下:
<bean id="serviceProperties"
class="org.springframework.security.cas.ServiceProperties">
<property name="service"
value="https://localhost:8443/cas-sample/login/cas"/>
<property name="sendRenew" value="false"/>
</bean>
接下來配置 CAS 認證相關過濾器信息,這些配置基本固定。
<security:http entry-point-ref="casEntryPoint">
...
<security:custom-filter position="CAS_FILTER" ref="casFilter" />
</security:http>
<bean id="casFilter"
class="org.springframework.security.cas.web.CasAuthenticationFilter">
<property name="authenticationManager" ref="authenticationManager"/>
</bean>
<bean id="casEntryPoint"
class="org.springframework.security.cas.web.CasAuthenticationEntryPoint">
<property name="loginUrl" value="https://localhost:9443/cas/login"/>
<property name="serviceProperties" ref="serviceProperties"/>
</bean>
完成這步后,我們繼續(xù)配置 CAS 認證管理器,添加測試用的用戶信息。
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider ref="casAuthenticationProvider" />
</security:authentication-manager>
<bean id="casAuthenticationProvider"
class="org.springframework.security.cas.authentication.CasAuthenticationProvider">
<property name="authenticationUserDetailsService">
<bean class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper">
<constructor-arg ref="userService" />
</bean>
</property>
<property name="serviceProperties" ref="serviceProperties" />
<property name="ticketValidator">
<bean class="org.jasig.cas.client.validation.Cas20ServiceTicketValidator">
<constructor-arg index="0" value="https://localhost:9443/cas" />
</bean>
</property>
<property name="key" value="an_id_for_this_auth_provider_only"/>
</bean>
<security:user-service id="userService">
<security:user name="joe" password="{noop}joe" authorities="ROLE_USER" />
</security:user-service>
注意,CAS 體系下的認證是交由 CAS 認證中心完成的,這一步中配置的密碼并不會用于認證,此處的配置是為了決定認證后該用戶所具有的權限。
至此,CAS 認證客戶端的配置完成。
3.2.2 單點注銷
CAS 認證協(xié)議中,包含了明確的單點注銷流程,我們可以便捷的集成到我們的認證客戶端之中,配置信息如下:
<security:http entry-point-ref="casEntryPoint">
...
<security:logout logout-success-url="/cas-logout.jsp"/>
<security:custom-filter ref="requestSingleLogoutFilter" before="LOGOUT_FILTER"/>
<security:custom-filter ref="singleLogoutFilter" before="CAS_FILTER"/>
</security:http>
<!-- 該過濾器用于接收來自 CAS 認證中心的登出請求。(由其他應用發(fā)起登出) -->
<bean id="singleLogoutFilter" class="org.jasig.cas.client.session.SingleSignOutFilter"/>
<!-- 該過濾器用于向 CAS 認證中心發(fā)送登出請求。(由本應用發(fā)起登出) -->
<bean id="requestSingleLogoutFilter"
class="org.springframework.security.web.authentication.logout.LogoutFilter">
<constructor-arg value="https://localhost:9443/cas/logout"/>
<constructor-arg>
<bean class=
"org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler"/>
</constructor-arg>
<property name="filterProcessesUrl" value="/logout/cas"/>
</bean>
登出操作由某一 CAS 客戶端發(fā)起,CAS 認證中心接收到之后,會向所有該用戶已登錄應用發(fā)起登出通知,最后實現(xiàn)全部應用的登出效果。
4. 小結
本節(jié)介紹了 CAS 認證體系的工作流程,Spring Security 可方便的實現(xiàn) CAS 認證客戶端功能,CAS 認證體系下支持單點登出操作,需要每一個加入體系的應用配置用于處理單點登出的過濾器。
下節(jié)我們將介紹 Java 早期的安全框架 JAAS,已經如何用 Spring Security 集成 JAAS 認證。