Jdk:jdk1.6.0_13
Apache:httpd-2.2.15-win32-x86-openssl-0.9.8m-r2
Tomcat:apache-tomcat-6.0.10
jks2pfx:證書導出工具http://www.myssl.cn/download/jks2pfx.zip
memcache:memcached-1.2.1-win32(需要memcache集群環(huán)境)
1、keytool
Apache、tomcat、jdk需要使用安全證書,進windows command窗口生成證書,命令如下:
--生成證書庫
keytool -genkey -alias 800jit -keyalg RSA -keystore d:/cert/800jitkey
--從證書庫中到處證書
keytool -export -file d:/cert/800jit.crt -alias 800jit -keystore d:/cert/800jitkey
--把證書導入jdk的證書庫
keytool -import -keystore d: /jdk1.6.0_13/jre/lib/security/cacerts -file d:/cert/800jit.crt -alias 800jit
--生成Apache服務器的SSL連接需要配置私鑰文件和證書文件
D:\casex\jks2pfx>JKS2PFX.bat .keystore 800jitkey tomcat server_dev00
生成的server_dev00.crt,server_dev00.key放到D:/work/Apache2.2/conf/
2、openssl
openssl req -config ..\conf\openssl.cnf -new -out olymtech.csr
openssl rsa -in privkey.pem -out olymtech.key
openssl x509 -in olymtech.csr -out olymtech.cert -req -signkey olymtech.key -days 3650
openssl x509 -in olymtech.cert -out olymtech.der.crt -outform DER
keytool -import -keystore d:/work/jdk1.6.0_13/jre/lib/security/cacerts -file d:/casex/ssl/olymtech.crt -alias olymtech
keytool -import -keystore D:/casex/800jitkey -file D:/casex/cas-doc/ssl/olymtech.crt -alias olymtech
Apache+ssl+虛擬機
--修改http.conf文件
取消注釋 LoadModule ssl_module modules/mod_ssl.so
取消注釋 Include conf/extra/httpd-ssl.conf
取消注釋 Include conf/extra/httpd-vhosts.conf
ProxyPass /cas balancer://cas lbmethod=bytraffic stickysession=jsessionid
<proxy balancer://cas/>
BalancerMember ajp://192.168.1.190:10009/cas loadfactor=1 route=jvm1
BalancerMember ajp://192.168.1.190:8009/cas loadfactor=1 route=jvm2
</proxy>
--修改httpd-ssl.conf
在<VirtualHost _default_:443>下增加
ProxyPass /cas balancer://cas/ lbmethod=bytraffic stickysession=jsessionid
ProxyPassReverse /cas balancer://cas/
SSLProxyEngine On
修改
SSLCertificateFile "D:/work/Apache2.2/conf/server_dev00.crt"
SSLCertificateKeyFile "D:/work/Apache2.2/conf/server_dev00.key"
--修改httpd-vhosts.conf
在<VirtualHost *:80>下增加
ProxyPass /cas balancer://cas/ lbmethod=bytraffic stickysession=jsessionid
ProxyPassReverse /cas balancer://cas/
修改server.xml
--配置ssl
<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
maxThreads="150" scheme="https" secure="true"
clientAuth="false" sslProtocol="TLS"
keystoreFile="d:/work/apache-tomcat-6.0.10/conf/800jitkey"
keystorePass="111111" />
訪問流程圖
主要原理:用戶第一次訪問一個CAS 服務的客戶web 應用時(訪問URL :http://192.168.1.90:8081/web1 ),部署在客戶web 應用的cas AuthenticationFilter ,會截獲此請求,生成service 參數,然后redirect 到CAS 服務的login 接口,url為https://cas:8443/cas/login?service=http%3A%2F%2F192.168.1.90%3A8081%2Fweb1%2F ,認證成功后,CAS 服務器會生成認證cookie ,寫入瀏覽器,同時將cookie 緩存到服務器本地,CAS 服務器還會根據service 參數生成ticket,ticket 會保存到服務器,也會加在url 后面,然后將請求redirect 回客戶web 應用,url 為http://192.168.1.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 的交互。
CAS 服務端總共對外定義了9 個接口,客戶端通過訪問這9 個接口與服務端交互,這9個接口為:
接口 | 說明 | 備注 |
/login | 認證接口 |
|
/logout | 退出接口,負責銷毀認證cookie |
|
/validate | 驗證ticket 用的接口,CAS1.0 定義 |
|
/serviceValidate | 驗證ticket 用的接口,CAS2.0 定義,返回xml 格式的數據 |
|
/proxy | 支持代理認證功能的接口 |
|
/proxyValidate | 支持代理認證功能的接口 |
|
/CentralAuthenticationService | 用于和遠程的web services 交互 |
|
/remoteLogin(新增) | 認證接口 |
|
/directLogin(新增) | 認證接口 |
|
詳細說明:
/login:
登錄流程這部分要考慮到不同種類用戶憑證的獲取方案,以及客戶應用傳來的service 、gateway 、renew 參數的不同取值組合,CAS 為了實現流程的高度可配置性,采用了Spring Web Flow 技術。通過CAS 發(fā)布包里的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 部署環(huán)境改變的情況下,靈活地設置 cookie path 的方式;把 cookie 的值以及 service 參數的值放入 requestContext 的 flowscope 里。
2 : GenerateServiceTicketAction 此 Action 負責根據 service 、 GTC cookie 值生成 ServiceTicket 對象, ServiceTicket 的 ID 就是返回給客戶應用的 ticket 參數,如果成功創(chuàng)建 ServiceTicket ,則轉發(fā)到 WarnAction ,如果創(chuàng)建失敗,且 gateway 參數為 true ,則直接redirect 到客戶應用, 否則則需要重新認證。
3 : viewLoginForm 這是登錄頁面, CAS 在此收集用戶憑證。 CAS 提供的默認實現是 /WEB-INF/view/jsp/simple/ui/casLoginView.jsp 。
4 : bindAndValidate 對應 AuthenticationViaFormAction 的 doBind 方法,該方法負責搜集登錄頁面上用戶錄入的憑證信息(用戶名、密碼等),然后把這些信息封裝到 CAS 內部的 Credentials 對象中。用戶在 casLoginView.jsp 頁面上點擊提交后,會觸發(fā)此方法。
5:submit 對應 AuthenticationViaFormAction 的 submit 方法 , 如果 doBind 方法成功執(zhí)行完, 則觸發(fā) submit 方法,此方法負責調用centralAuthenticationService 的 grantServiceTicket 方法,完成認證工作,如果認證成功,則生成 TicketGrantingTicket 對象,放在緩存里, TicketGrantingTicket 的 ID 就是 TGC Cookie 的 value 值。
6 : warn CAS 提供了一個功能:用戶在一個 web 應用中跳到另一個 web 應用時, CAS 可以跳轉到一個提示頁面,該頁面提示用戶要離開一個應用進入另一個應用,可以讓用戶自己選擇。用戶在登錄頁面 viewLoginForm 上選中了 id=”warn” 的復選框,才能開啟這個功能。
WarnAction 就檢查用戶有沒有開啟這個功能,如果開啟了,則轉發(fā)到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 參數為空,則轉發(fā)到failureView (/WEB-INF/view/jsp/default/protocol/2.0/casServiceValidationFailure.jsp )
驗證ticket 。以ticket 為參數,去緩存里找ServiceTicketImpl 對象,如果能找到,且沒有過期,且ServiceTicketImpl 對象對應的service 屬性和service 參數對應,則驗證通過,驗證通過后,請求轉發(fā)至casServiceSuccessView (cas/WEB-INF/view/jsp/default/protocol/2.0/casServiceValidationSuccess.jsp ),驗證不通過,則轉發(fā)到failureView 。
概念
序列圖
類圖
CAS的核心就是其Ticket,及其在Ticket之上的一系列處理操作。CAS的主要票據有TGT、ST、PGT、PGTIOU、PT,其中TGT、ST是CAS1.0協(xié)議中就有的票據,PGT、PGTIOU、PT是CAS2.0協(xié)議中有的票據。
TGT是CAS為用戶簽發(fā)的登錄票據,擁有了TGT,用戶就可以證明自己在CAS成功登錄過。TGT封裝了Cookie值以及此Cookie值對應的用戶信息。用戶在CAS認證成功后,CAS生成cookie,寫入瀏覽器,同時生成一個TGT對象,放入自己的緩存,TGT對象的ID就是cookie的值。當HTTP再次請求到來時,如果傳過來的有CAS生成的cookie,則CAS以此cookie值為key查詢緩存中有無TGT ,如果有的話,則說明用戶之前登錄過,如果沒有,則用戶需要重新登錄。
ST是CAS為用戶簽發(fā)的訪問某一service的票據。用戶訪問service時,service發(fā)現用戶沒有ST,則要求用戶去CAS獲取ST。用戶向CAS發(fā)出獲取ST的請求,如果用戶的請求中包含cookie,則CAS會以此cookie值為key查詢緩存中有無TGT,如果存在TGT,則用此TGT簽發(fā)一個ST,返回給用戶。用戶憑借ST去訪問service,service拿ST去CAS驗證,驗證通過后,允許用戶訪問資源。
Proxy Service的代理憑據。用戶通過CAS成功登錄某一Proxy Service后,CAS生成一個PGT對象,緩存在CAS本地,同時將PGT的值(一個UUID字符串)回傳給Proxy Service,并保存在Proxy Service里。Proxy Service拿到PGT后,就可以為Target Service(back-end service)做代理,為其申請PT。
PGTIOU是CAS協(xié)議中定義的一種附加票據,它增強了傳輸、獲取PGT的安全性。
PGT的傳輸與獲取的過程:Proxy Service調用CAS的serviceValidate接口驗證ST成功后,CAS首先會訪問pgtUrl指向的https url,將生成的 PGT及PGTIOU傳輸給proxy service,proxy service會以PGTIOU為key,PGT為value,將其存儲在Map中;然后CAS會生成驗證ST成功的xml消息,返回給Proxy Service,xml消息中含有PGTIOU,proxy service收到Xml消息后,會從中解析出PGTIOU的值,然后以其為key,在map中找出PGT的值,賦值給代表用戶信息的Assertion對象的pgtId,同時在map中將其刪除。
PT是用戶訪問Target Service(back-end service)的票據。如果用戶訪問的是一個Web應用,則Web應用會要求瀏覽器提供ST,瀏覽器就會用cookie去CAS獲取一個ST,然后就可以訪問這個Web應用了。如果用戶訪問的不是一個Web應用,而是一個C/S結構的應用,因為C/S結構的應用得不到cookie,所以用戶不能自己去CAS獲取ST,而是通過訪問proxy service的接口,憑借proxy service的PGT去獲取一個PT,然后才能訪問到此應用。
CAS Ticket類圖
方法聲明:public synchronized ServiceTicket grantServiceTicket(final String id,final Service service, final ExpirationPolicy expirationPolicy, final boolean credentialsProvided)
方法描述:
1:生成SerivceTicketImpl
2:更新屬性:
this.previousLastTimeUsed = this.lastTimeUsed;
this.lastTimeUsed = System.currentTimeMillis();
this.countOfUses++;
3:給service對象的principal屬性賦值
4:將service對象放入map services
方法聲明:
public TicketGrantingTicket grantTicketGrantingTicket(final String id, final Authentication authentication,final ExpirationPolicy expirationPolicy)
方法描述:在CAS3.3對CAS2.0協(xié)議的實現中,PGT是由ST簽發(fā)的,調用的就是ServiceTicket的grantTicketGrantingTicket方法。方法返回的TicketGrantingTicket對象,表征的是一個PGT對象,其中的ticketGrantingTicket屬性的值是簽發(fā)ST的TGT對象。
方法聲明:void expire()
方法描述:
在CAS的logout接口實現中,要調用TGT對象的expire方法,然后會在緩存中清除此TGT對象。
expire方法的內容:循環(huán)遍歷 services 中的Service對象,調用其logoutOfService方法。具體Service實現類中的logoutOfService方法的實現,要通知具體的應用,客戶要退出。
1:ST是TGT簽發(fā)的。用戶在CAS上認證成功后,CAS生成TGT,用TGT簽發(fā)一個ST,ST的ticketGrantingTicket屬性值是TGT對象,然后把ST的值redirect到客戶應用。
2:PGT是ST簽發(fā)的。用戶憑借ST去訪問Proxy service,Proxy service去CAS驗證ST(同時傳遞PgtUrl參數給CAS),如果ST驗證成功,則CAS用ST簽發(fā)一個PGT,PGT對象里的ticketGrantingTicket是簽發(fā)ST的TGT對象。
3:PT是PGT簽發(fā)的。Proxy service代理back-end service去CAS獲取PT的時候,CAS根據傳來的pgt參數,獲取到PGT對象,然后調用其grantServiceTicket方法,生成一個PT對象。
TGT、ST、PGT、PT之間的關聯(lián)關系
參數 | 是否必須 | 說明 |
com.olymtech.cas.client.filter.loginUrl | 是 | 指定 CAS 提供登錄頁面的 URL |
com.olymtech.cas.client.filter.validateUrl | 是 | 指定 CAS 提供 service ticket 或 proxy ticket 驗證服務的 URL |
com.olymtech.cas.client.filter.serverName | 是 | 指定客戶端的域名和端口,是指客戶端應用所在機器而不是 CAS Server 所在機器,該參數或 serviceUrl 至少有一個必須指定 |
com.olymtech.cas.client.filter.serviceUrl | 否 | 該參數指定過后將覆蓋 serverName 參數,成為登錄成功過后重定向的目的地址 |
com.olymtech.cas.client.filter.wrapRequest | 否 | 如果指定為 true,那么 CASFilter 將重新包裝 HttpRequest,并且使 getRemoteUser() 方法返回當前登錄用戶的用戶名 |
com.olymtech.cas.client.filter.noFilter | 否 | 設置不過濾的路徑,語法如下:/name1/,/name2, |
com.olymtech.cas.client.filter.proxyCallbackUrl | 否 | 用于當前應用需要作為其他服務的代理(proxy)時獲取 Proxy Granting Ticket 的地址 |
com.olymtech.cas.client.filter.authorizedProxy | 否 | 用于允許當前應用從代理處獲取 proxy tickets,該參數接受以空格分隔開的多個 proxy URLs,但實際使用只需要一個成功即可。當指定該參數過后,需要修改 validateUrl 到 proxyValidate,而不再是 serviceValidate |
com.olymtech.cas.client.filter.renew | 否 | 如果指定為 true,那么受保護的資源每次被訪問時均要求用戶重新進行驗證,而不管之前是否已經通過 |
com.olymtech.cas.client.filter.gateway | 否 | 指定 gateway 屬性 |
1、 應用配置說明(結合cas client)
導入key到本地jdk(tomcat使用的jdk必須)
keytool -import -keystore d:/work/jdk1.6.0_13/jre/lib/security/cacerts -file d:/casex/800jit.crt -alias 800jit
在ie中導入證書800jit.crt
修改web程序的web.xml添加
<!-- 用于單點退出 -->
<listener>
<listener-class>org.jasig.cas.client.session.SingleSignOutHttpSessionListener</listener-class>
</listener>
<filter>
<filter-name>CAS Single Sign Out Filter</filter-name>
<filter-class>org.jasig.cas.client.session.SingleSignOutFilter</filter-class>
</filter>
<!-- 用于單點登錄 -->
<filter>
<filter-name>CAS Filter</filter-name>
<filter-class>com.olymtech.cas.client.filter.CASFilter</filter-class>
<init-param>
<param-name>com.olymtech.cas.client.filter.loginUrl</param-name>
<param-value>https://cas.server.com/cas/login</param-value>
</init-param>
<init-param>
<param-name>com.olymtech.cas.client.filter.validateUrl</param-name>
<param-value>https://cas.server.com/cas/serviceValidate</param-value>
</init-param>
<init-param>
<param-name>com.olymtech.cas.client.filter.serverName</param-name>
<param-value>saas.server.com</param-value>
</init-param>
<init-param>
<param-name>com.olymtech.cas.client.filter.wrapRequest</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CAS Single Sign Out Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>CAS Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
在jsp/servlet中得到登陸數據:
<%@ page language="java" import="com.olymtech.cas.client.filter.CASFilterRequestWrapper"%>
<%
CASFilterRequestWrapper reqWrapper=new CASFilterRequestWrapper(request);
String username = reqWrapper.getRemoteUser();
%>
聯(lián)系客服