應用場景: cas 服務部署在192.168.7.115 ,是一個web 應用,訪問地址爲:https://cas.mycompany.com:8443/cas/ 。web1應用位於192.168.7.90 ,訪問地址爲:http://192.168.7.90:8081/web1 ,web2 應用位於192.168.7.90 ,訪問地址爲:http://192.168.7.90:8082/web2 。web1 和web2 經過cas 服務實現SSO 功能。瀏覽器位於本地localhost 。java
cas 服務器: 192.168.7.115 啓動8443 端口,需配置證書web
web1 : 192.168.7.90瀏覽器
hosts配置: 192.168.7.115 cas.mycompany.com緩存
web.xml裏的配置:服務器
<context-param>cookie
<param-name>casServerUrlPrefix</param-name>session
<param-value>https://cas.mycompany.com:8443/cas/</param-value>app
</context-param>jsp
<context-param>ide
<param-name>serverName</param-name>
<param-value>192.168.7.90:8081</param-value>
</context-param>
<filter>
<filter-name>CAS Authentication Filter</filter-name>
<filter-class>
org.jasig.cas.client.authentication.AuthenticationFilter
</filter-class>
<init-param>
<param-name>casServerLoginUrl</param-name>
<param-value>https://cas.mycompany.com:8443/cas/login</param-value>
</init-param>
</filter>
<filter>
<filter-name>CAS Validation Filter</filter-name>
<filter-class>
org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter
</filter-class>
</filter>
<filter-mapping>
<filter-name>CAS Authentication Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>CAS Validation Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
JDK啓動參數需加上( 驗證CAS 服務器證書的須要) :
-Djavax.net.ssl.trustStore=/home/yz/web1/conf/cas-client-trust-cert.jks
-Djavax.net.ssl.trustStorePassword=casclient!@#
web2 : 192.168.7.90
hosts配置: 192.168.7.115 cas.mycompany.com
web.xml裏的配置:
同web1 裏web.xml 的配置,只是serverName 屬性的值變成了192.168.7.90:8082
JDK 啓動參數需加上( 驗證CAS 服務器證書的須要) :
-Djavax.net.ssl.trustStore=/home/yz/web2/conf/cas-client-trust-cert.jks
-Djavax.net.ssl.trustStorePassword=casclient!@#
本地 :hosts 配置: 192.168.7.115 cas.mycompany.com
注:
1 casServerLoginUrl 參數的值是cas 服務器login 接口的值。web 應用裏的cas client 在認證的時候會redirect 到 cas 服務器,redirect 的url 就是casServerLoginUrl ,由於是redirect ,因此瀏覽器所在機器要配置cas 服務器的域名。
2 casServerUrlPrefix 參數的值是cas 服務的訪問地址。cas client 驗證ticket 的時候,要訪問cas 服務的/serviceValidate 接口,使用的url 就是${ casServerUrlPrefix }serviceValidate ,由於客戶web 應用要驗證cas 的證書,因此證書cn 字段的值必須和casServerUrlPrefix 裏設置的cas 服務器的域名保持一致,而且在web 應用的服務器上配置cas 服務的訪問域名。
2 serverName 參數,cas client 會用來生成service 參數,而且cas 服務器在認證經過、ticket 驗證經過後,會redirect到web 應用,redirect 的url 就是service 參數的值。serverName 參數能夠是IP ,也能夠是域名,只要保證瀏覽器能訪問到便可。
二 CAS 簡單介紹CAS 官方網站: http://www.jasig.org/cas
CAS 的主要文檔:
http://www.ja-sig.org/wiki/display/CASUM/Home
http://www.jasig.org/cas/cas1-architecture
http://www.jasig.org/cas/cas2-architecture
http://www.jasig.org/cas/protocol/
http://www.ja-sig.org/wiki/display/CASUM/Demo
CAS 官方網站上的介紹圖
主要原理:用戶第一次訪問一個CAS 服務的客戶web 應用時(訪問URL :http://192.168.7.90:8081/web1 ),部署在客戶web應用的cas AuthenticationFilter ,會截獲此請求,生成service 參數,而後redirect 到CAS 服務的login 接口,url爲https://cas:8443/cas/login?service=http%3A%2F%2F192.168.7.90%3A8081%2Fweb1%2F ,認證成功後,CAS 服務器會生成認證cookie ,寫入瀏覽器,同時將cookie 緩存到服務器本地,CAS 服務器還會根據service 參數生成ticket,ticket 會保存到服務器,也會加在url 後面,而後將請求redirect 回客戶web 應用,url 爲http://192.168.7.90:8081/web1/?ticket=ST-5-Sx6eyvj7cPPCfn0pMZuMwnbMvxpCBcNAIi6-20 。這時客戶端的AuthenticationFilter 看到ticket 參數後,會跳過,由其後面的TicketValidationFilter 處理,TicketValidationFilter 會利用httpclient 工具訪問cas 服務的/serviceValidate 接口, 將ticket、service 都傳到此接口,由此接口驗證ticket 的有效性,TicketValidationFilter 若是獲得驗證成功的消息,就會把用戶信息寫入web 應用的session 裏。至此爲止,SSO 會話就創建起來了,之後用戶在同一瀏覽器裏訪問此web 應用時,AuthenticationFilter 會在session 裏讀取到用戶信息,因此就不會去CAS 認證,若是在此瀏覽器裏訪問別的web 應用時,AuthenticationFilter 在session 裏讀取不到用戶信息,會去CAS 的login 接口認證,但這時CAS 會讀取到瀏覽器傳來的cookie ,因此CAS 不會要求用戶去登陸頁面登陸,只是會根據service 參數生成一個ticket ,而後再和web 應用作一個驗證ticket的交互而已。
1 AuthenticationFilter
if(url 中無ticket 參數 && session 中沒有TicketValidationFilter 置的assertion 對象){
response.sendRedirect(cas 服務器的/login 接口);// 生成service 參數,添加到url 後面
}
else{
不作處理
}
2 TicketValidationFilter
if(url 中有ticket 參數){
經過httpclient 工具訪問cas 服務器的/serviceValidate 接口驗證ticket 的有效性,驗證失敗,顯示錯誤頁面,驗證成功,則生成標識用戶身份的assertion 對象,放入session 。
}
else{
不作處理
}
注:
1 AuthenticationFilter 在前,TicketValidationFilter 在後。
2 AuthenticationFilter :
1 )url 中無ticket 參數,且session 中沒有TicketValidationFilter 置的assertion 對象,這種狀況說明用戶尚未認證,AuthenticationFilter 會去作認證處理;
2 )url 中無ticket 參數,且session 中有TicketValidationFilter 置的assertion 對象,這種狀況說明用戶已經認證成功,AuthenticationFilter 不作處理;
3 )url 中有ticket 參數,這種狀況說明用戶已經認證成功,但還須要經TicketValidationFilter 去驗證ticket,AuthenticationFilter不作處理。
3 TicketValidationFilter :只有客戶端調用cas 服務器的/login 接口, 併成功認證,redirect 回客戶端時,url 裏才帶有ticket 參數,在這種狀況下,TicketValidationFilter 才作處理。
CAS 服務端總共對外暴露了7 個接口,客戶端經過訪問這7 個接口與服務端交互,這7 個接口爲:/login 、/logout 、/validate、/serviceValidate 、/proxy 、/proxyValidate 、/CentralAuthenticationService 。/login 是認證接口,/logout 是退出接口,負責銷燬認證cookie,/validate 、/serviceValidate 是驗證ticket 用的接口,其中/validate 是CAS1.0 定義的,/serviceValidate是CAS2.0 定義的,其中/serviceValidate 返回xml 格式的數據,/proxy 、/proxyValidate 是支持代理認證功能的接口,/CentralAuthenticationService 接口用於和遠程的web services 交互。對於通常web 應用的單點登陸來說,/login、/logout 、/serviceValidate 這3 個接口已經能夠知足要求 。CAS 協議中已經對這些接口作了定義,連接爲:http://www.jasig.org/cas/protocol 。下面是我對CAS 各個接口實現的的詳細說明。
/login:
登陸流程這部分要考慮到不一樣種類用戶憑證的獲取方案,以及客戶應用傳來的service 、gateway 、renew 參數的不一樣取值組合,CAS 爲了實現流程的高度可配置性,採用了Spring Web Flow 技術。經過閱讀CAS 發佈包裏的login-webflow.xml 、cas-servlet.xml 、applicationContext.xml 這3 個文件,我找出 了登陸有關的全部組件,並畫出了它的處理流程圖。
CAS 默認的登陸處理流程
第一次訪問Web 應用的流程走向
已經登陸web1 後,訪問web1 的資源(web1 沒有啓動session ),或訪問web2 的資源
注:
1 : InitialFlowSetupAction: 是流程的入口。用 request.getContextPath() 的值來設置 cookie 的 Path 值, Cookie 的 path 值是在配置文件裏定義的,但這個 Action 負責將 request.getContextPath() 的值設置爲 Cookie 的 path 值,這是在 cas 部署環境改變的狀況下,靈活地設置 cookie path 的方式;把 cookie 的值以及 service 參數的值放入 requestContext 的 flowscope 裏。
2 : GenerateServiceTicketAction 此 Action 負責根據 service 、 GTC cookie 值生成 ServiceTicket 對象, ServiceTicket 的 ID就是返回給客戶應用的 ticket 參數,若是成功建立 ServiceTicket ,則轉發到 WarnAction ,若是建立失敗,且 gateway 參數爲true ,則直接 redirect 到客戶應用, 不然則須要從新認證。
3 : viewLoginForm 這是登陸頁面, CAS 在此收集用戶憑證。 CAS 提供的默認實現是 /WEB-INF/view/jsp/simple/ui/casLoginView.jsp 。
4 : bindAndValidate 對應 AuthenticationViaFormAction 的 doBind 方法,該方法負責蒐集登陸頁面上用戶錄入的憑證信息(用戶名、密碼等),而後把這些信息封裝到 CAS 內部的 Credentials 對象中。用戶在 casLoginView.jsp 頁面上點擊提交後,會觸發此方法。
5:submit 對應 AuthenticationViaFormAction 的 submit 方法 , 若是 doBind 方法成功執行完, 則觸發 submit 方法,此方法負責調用 centralAuthenticationService 的 grantServiceTicket 方法,完成認證工做,若是認證成功,則生成TicketGrantingTicket 對象,放在緩存裏, TicketGrantingTicket 的 ID 就是 TGC Cookie 的 value 值。
6 : warn CAS 提供了一個功能:用戶在一個 web 應用中跳到另外一個 web 應用時, CAS 能夠跳轉到一個提示頁面,該頁面提示用戶要離開一個應用進入另外一個應用,可讓用戶本身選擇。用戶在登陸頁面 viewLoginForm 上選中了 id=」warn」 的複選框,才能開啓這個功能。
WarnAction 就檢查用戶有沒有開啓這個功能,若是開啓了,則轉發到showWarnView, 若是沒開啓,則直接redirect 到客戶應用。
7 :SendTicketGrantingTicketAction 此Action 負責爲response 生成TGC Cookie ,cookie 的值就是AuthenticationViaFormAction 的 submit 方法生成的 TicketGrantingTicket 對象的 ID 。
8 : viewGenerateLoginSuccess 這是 CAS 的認證成功頁面。
/logout: ( 對應實現類 org.jasig.cas.web.LogoutController )
處理邏輯:
1) removeCookie
2) 在服務端刪除TicketGrantingTicket 對象(此對象封裝了cookie 的value 值)
3 )redirect 到退出頁面,有2 種選擇:
if(LogoutController 的followServiceRedirects 屬性爲true 值,且url 裏的service 參數非空){
redirect 到 sevice 參數標識的url
}
else{
redirect 到內置的casLogoutView (cas/WEB-INF/view/jsp/default/ui/casLogoutView.jsp ),若是url 裏有url 參數,則此url 參數標識的連接會顯示在casLogoutView 頁面上。
}
/serviceValidate: (對應實現類 org.jasig.cas.web.ServiceValidateController )
處理邏輯:
若是service 參數爲空或ticket 參數爲空,則轉發到failureView (/WEB-INF/view/jsp/default/protocol/2.0/casServiceValidationFailure.jsp )
驗證ticket 。以ticket 爲參數,去緩存裏找ServiceTicketImpl 對象,若是能找到,且沒有過時,且ServiceTicketImpl 對象對應的service 屬性和service 參數對應,則驗證經過,驗證經過後,請求轉發至casServiceSuccessView (cas/WEB-INF/view/jsp/default/protocol/2.0/casServiceValidationSuccess.jsp ),驗證不經過,則轉發到failureView 。
Credentials 用戶提供的用於登陸用的憑據信息,如用戶名/ 密碼、證書、IP 地址、Cookie 值等。好比 UsernamePasswordCredentials ,封裝的是用戶名和密碼。CAS 進行認證的第一步,就是把從UI 或request 對象裏取到的用戶憑據封裝成Credentials 對象,而後交給認證管理器去認證。
AuthenticationHandler 認證Handler, 每種AuthenticationHandler 只能處理一種Credentials ,如AbstractUsernamePasswordAuthenticationHandler 只負責處理 U sernamePasswordCredentials 。
Principal 封裝用戶標識,好比 SimplePrincipal, 只是封裝了用戶名。認證成功後, credentialsToPrincipalResolvers 負責由 Credentials 生成 Principal 對象。
CredentialsToPrincipalResolvers 負責由 Credentials 生成 Principal 對象,每種 CredentialsToPrincipalResolvers 只處理 一種Credentials ,好比 UsernamePasswordCredentialsToPrincipalResolver 負責從 U sernamePasswordCredentials中取出用戶名,而後將其賦給生成的 SimplePrincipal 的 ID 屬性。
AuthenticationMetaDataPopulators 負責將 Credentials 的一些屬性賦值給 Authentication 的 attributes 屬性。
Authentication Authentication是認證管理器的最終處理結果, Authentication 封裝了 Principal ,認證時間,及其餘一些屬性(可能來自 Credentials )。
AuthenticationManager 認證管理器獲得 Credentials 對象後,負責調度AuthenticationHandler 去完成認證工做,最後返回的結果是 Authentication 對象。
CentralAuthenticationService CAS 的服務類,對 Web 層提供了一些方法。該類還負責調用 AuthenticationManager 完成認證邏輯。
CAS 認證處理序列圖
CAS 認證類圖