1、在tomcat中配置CAS
CAS 原理和協議
從結構上看,CAS 包含兩個部分: CAS Server 和 CAS Client。CAS Server 需要獨立部署,主要負責對用戶的認證工作;CAS Client 負責處理對客戶端受保護資源的訪問請求,需要登錄時,重定向到 CAS Server。圖1 是 CAS 最基本的協議過程:
圖 1. CAS 基礎協議
CAS Client 與受保護的客戶端應用部署在一起,以 Filter 方式保護受保護的資源。對於訪問受保護資源的每個 Web 請求,CAS Client 會分析該請求的 Http 請求中是否包含 Service Ticket,如果沒有,則說明當前用戶尚未登錄,於是將請求重定向到指定好的 CAS Server 登錄地址,並傳遞 Service (也就是要訪問的目的資源地址),以便登錄成功過後轉回該地址。用戶在第 3 步中輸入認證信息,如果登錄成功,CAS Server 隨機產生一個相當長度、唯一、不可偽造的 Service Ticket,並緩存以待將來驗證,之後系統自動重定向到 Service 所在地址,並為客戶端瀏覽器設置一個 Ticket Granted Cookie(TGC),CAS Client 在拿到 Service 和新產生的 Ticket 過後,在第 5,6 步中與 CAS Server 進行身份合適,以確保 Service Ticket 的合法性。
在該協議中,所有與 CAS 的交互均採用 SSL 協議,確保,ST 和 TGC 的安全性。協議工作過程中會有 2 次重定向的過程,但是 CAS Client 與 CAS Server 之間進行 Ticket 驗證的過程對於用戶是透明的。
另外,CAS 協議中還提供了 Proxy (代理)模式,以適應更加高級、復雜的應用場景,具體介紹可以參考 CAS 官方網站上的相關文檔。
准備工作
本文中的例子以 tomcat5.5 為例進行講解,下載地址:
http://tomcat.apache.org/download-55.cgi
到 CAS 官方網站下載 CAS Server 和 Client,地址分別為:
http://www.ja-sig.org/downloads/cas/cas-server-3.1.1-release.zip
http://www.ja-sig.org/downloads/cas-clients/cas-client-java-2.1.1.zip
部署 CAS Server
CAS Server 是一套基於 Java 實現的服務,該服務以一個 Java Web Application 單獨部署在與 servlet2.3 兼容的 Web 伺服器上,另外,由於 Client 與 CAS Server 之間的交互採用 Https 協議,因此部署 CAS Server 的伺服器還需要支持 SSL 協議。當 SSL 配置成功過後,像普通 Web 應用一樣將 CAS Server 部署在伺服器上就能正常運行了,不過,在真正使用之前,還需要擴展驗證用戶的介面。
在 Tomcat 上部署一個完整的 CAS Server 主要按照以下幾個步驟:
配置 Tomcat 使用 Https 協議
如果希望 Tomcat 支持 Https,主要的工作是配置 SSL 協議,其配置過程和配置方法可以參考 Tomcat 的相關文檔。不過在生成證書的過程中,會有需要用到主機名的地方,CAS 建議不要使用 IP 地址,而要使用機器名或域名。
部署 CAS Server
CAS Server 是一個 Web 應用包,將前面下載的 cas-server-3.1.1-release.zip 解開,把其中的 cas-server-webapp-3.1.1.war 拷貝到 tomcat的 webapps 目錄,並更名為 cas.war。由於前面已配置好 tomcat 的 https 協議,可以重新啟動 tomcat,然後訪問:https://localhost:8443/cas ,如果能出現正常的 CAS 登錄頁面,則說明 CAS Server 已經部署成功。
雖然 CAS Server 已經部署成功,但這只是一個預設的實現,在實際使用的時候,還需要根據實際概況做擴展和定製,最主要的是擴展認證 (Authentication) 介面和 CAS Server 的界面。
擴展認證介面
CAS Server 負責完成對用戶的認證工作,它會處理登錄時的用戶憑證 (Credentials) 信息,用戶名/密碼對是最常見的憑證信息。CAS Server 可能需要到資料庫檢索一條用戶帳號信息,也可能在 XML 文件中檢索用戶名/密碼,還可能通過 LDAP Server 獲取等,在這種情況下,CAS 提供了一種靈活但統一的介面和實現分離的方式,實際使用中 CAS 採用哪種方式認證是與 CAS 的基本協議分離開的,用戶可以根據認證的介面去定製和擴展。
擴展 AuthenticationHandler
CAS 提供擴展認證的核心是 AuthenticationHandler 介面,該介面定義如清單 1 下:
清單 1. AuthenticationHandler定義
public interface AuthenticationHandler {
/**
* Method to determine if the credentials supplied are valid.
* @param credentials The credentials to validate.
* @return true if valid, return false otherwise.
* @throws AuthenticationException An AuthenticationException can contain
* details about why a particular authentication request failed.
*/
boolean authenticate(Credentials credentials) throws AuthenticationException;
/**
* Method to check if the handler knows how to handle the credentials
* provided. It may be a simple check of the Credentials class or something
* more complicated such as scanning the information contained in the
* Credentials object.
* @param credentials The credentials to check.
* @return true if the handler supports the Credentials, false othewrise.
*/
boolean supports(Credentials credentials);
}
該介面定義了 2 個需要實現的方法,supports ()方法用於檢查所給的包含認證信息的Credentials 是否受當前 AuthenticationHandler 支持;而 authenticate() 方法則擔當驗證認證信息的任務,這也是需要擴展的主要方法,根據情況與存儲合法認證信息的介質進行交互,返回 boolean 類型的值,true 表示驗證通過,false 表示驗證失敗。
CAS3中還提供了對AuthenticationHandler 介面的一些抽象實現,比如,可能需要在執行authenticate() 方法前後執行某些其他操作,那麼可以讓自己的認證類擴展自清單 2 中的抽象類:
清單 2. 定義
public abstract class
implements AuthenticateHandler{
protected Log log = LogFactory.getLog(this.getClass());
protected boolean preAuthenticate(final Credentials credentials) {
return true;
}
protected boolean postAuthenticate(final Credentials credentials,
final boolean authenticated) {
return authenticated;
}
public final boolean authenticate(final Credentials credentials)
throws AuthenticationException {
if (!preAuthenticate(credentials)) {
return false;
}
final boolean authenticated = doAuthentication(credentials);
return postAuthenticate(credentials, authenticated);
}
protected abstract boolean doAuthentication(final Credentials credentials)
throws AuthenticationException;
}
類新定義了 preAuthenticate() 方法和 postAuthenticate() 方法,而實際的認證工作交由 doAuthentication() 方法來執行。因此,如果需要在認證前後執行一些額外的操作,可以分別擴展 preAuthenticate()和 ppstAuthenticate() 方法,而 doAuthentication() 取代 authenticate() 成為了子類必須要實現的方法。
由於實際運用中,最常用的是用戶名和密碼方式的認證,CAS3 提供了針對該方式的實現,如清單 3 所示:
清單 3. 定義
public abstract class extends
{
...
protected final boolean doAuthentication(final Credentials credentials)
throws AuthenticationException {
return ((UsernamePasswordCredentials) credentials);
}
protected abstract boolean (
final UsernamePasswordCredentials credentials) throws AuthenticationException;
protected final PasswordEncoder getPasswordEncoder() {
return this.passwordEncoder;
}
public final void setPasswordEncoder(final PasswordEncoder passwordEncoder) {
this.passwordEncoder = passwordEncoder;
}
...
}
基於用戶名密碼的認證方式可直接擴展自 ,驗證用戶名密碼的具體操作通過實現 () 方法達到,另外,通常情況下密碼會是加密過的,setPasswordEncoder() 方法就是用於指定適當的加密器。
從以上清單中可以看到,doAuthentication() 方法的參數是 Credentials 類型,這是包含用戶認證信息的一個介面,對於用戶名密碼類型的認證信息,可以直接使用 UsernamePasswordCredentials,如果需要擴展其他類型的認證信息,需要實現Credentials介面,並且實現相應的 介面,其具體方法可以借鑒 UsernamePasswordCredentials 和 UsernamePassword。
JDBC 認證方法
用戶的認證信息通常保存在資料庫中,因此本文就選用這種情況來介紹。將前面下載的 cas-server-3.1.1-release.zip 包解開後,在 moles 目錄下可以找到包 cas-server-support-jdbc-3.1.1.jar,其提供了通過 JDBC 連接資料庫進行驗證的預設實現,基於該包的支持,我們只需要做一些配置工作即可實現 JDBC 認證。
JDBC 認證方法支持多種資料庫,DB2, Oracle, MySql, Microsoft SQL Server 等均可,這里以 DB2 作為例子介紹。並且假設DB2資料庫名: CASTest,資料庫登錄用戶名: db2user,資料庫登錄密碼: db2password,用戶信息表為: userTable,該表包含用戶名和密碼的兩個數據項分別為 userName 和 password。
1. 配置 DataStore
打開文件 %CATALINA_HOME%/webapps/cas/WEB-INF/deployerConfigContext.xml,添加一個新的 bean 標簽,對於 DB2,內容如清單 4 所示:
清單 4. 配置 DataStore
<bean id="casDataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName">
<value>com.ibm.db2.jcc.DB2Driver</value>
</property>
<property name="url">
<value>jdbc:db2://9.125.65.134:50000/CASTest</value>
</property>
<property name="username">
<value>db2user</value>
</property>
<property name="password">
<value>db2password</value>
</property>
</bean>
其中 id 屬性為該 DataStore 的標識,在後面配置 AuthenticationHandler 會被引用,另外,需要提供 DataStore 所必需的資料庫驅動程序、連接地址、資料庫登錄用戶名以及登錄密碼。
2. 配置 AuthenticationHandler
在 cas-server-support-jdbc-3.1.1.jar 包中,提供了 3 個基於 JDBC 的 AuthenticationHandler,分別為 , , 。其中 是用所給的用戶名和密碼去建立資料庫連接,根據連接建立是否成功來判斷驗證成功與否; 通過配置一個 SQL 語句查出密碼,與所給密碼匹配; 通過配置存放用戶驗證信息的表、用戶名欄位和密碼欄位,構造查詢語句來驗證。
使用哪個 AuthenticationHandler,需要在 deployerConfigContext.xml 中設置,默認情況下,CAS 使用一個簡單的 username=password 的 AuthenticationHandler,在文件中可以找到如下一行:<bean class="org.jasig.cas.authentication.handler.support.SimpleTestUsernamePassword
AuthenticationHandler" />,我們可以將其注釋掉,換成我們希望的一個 AuthenticationHandler,比如,使用 或 可以分別選取清單 5 或清單 6 的配置。
清單 5. 使用
<bean class="org.jasig.cas.adaptors.jdbc.">
<property name="dataSource" ref=" casDataSource " />
<property name="sql"
value="select password from userTable where lower(userName) = lower(?)" />
</bean>
清單 6. 使用
<bean id=""
class="org.jasig.cas.adaptors.jdbc."
abstract="false" singleton="true" lazy-init="default"
autowire="default" dependency-check="default">
<property name="tableUsers">
<value>userTable</value>
</property>
<property name="fieldUser">
<value>userName</value>
</property>
<property name="fieldPassword">
<value>password</value>
</property>
<property name="dataSource" ref=" casDataSource " />
</bean>
另外,由於存放在資料庫中的密碼通常是加密過的,所以 AuthenticationHandler 在匹配時需要知道使用的加密方法,在 deployerConfigContext.xml 文件中我們可以為具體的 AuthenticationHandler 類配置一個 property,指定加密器類,比如對於 ,可以修改如清單7所示:
清單 7. 添加 passwordEncoder
<bean class="org.jasig.cas.adaptors.jdbc.">
<property name="dataSource" ref=" casDataSource " />
<property name="sql"
value="select password from userTable where lower(userName) = lower(?)" />
<property name="passwordEncoder" ref="myPasswordEncoder"/>
</bean>
其中 myPasswordEncoder 是對清單 8 中設置的實際加密器類的引用:
清單 8. 指定具體加密器類
<bean id="passwordEncoder"
class="org.jasig.cas.authentication.handler.MyPasswordEncoder"/>
這里 MyPasswordEncoder 是根據實際情況自己定義的加密器,實現 PasswordEncoder 介面及其 encode() 方法。
3. 部署依賴包
在以上配置完成以後,需要拷貝幾個依賴的包到 cas 應用下,包括:
將 cas-server-support-jdbc-3.1.1.jar 拷貝到 %CATALINA_HOME%/webapps/cas/ WEB-INF/lib 目錄。
資料庫驅動,由於這里使用 DB2,將 %DB2_HOME%/java 目錄下的 db2java.zip (更名為 db2java.jar), db2jcc.jar, db2jcc_license_cu.jar 拷貝到 %CATALINA_HOME%/webapps/cas/WEB-INF/lib 目錄。對於其他資料庫,同樣將相應資料庫驅動程序拷貝到該目錄。
DataStore 依賴於 commons-collections-3.2.jar, commons-dbcp-1.2.1.jar, commons-pool-1.3.jar,需要到 apache 網站的 Commons 項目下載以上 3 個包放進 %CATALINA_HOME%/webapps/cas/WEB-INF/lib 目錄。
擴展 CAS Server 界面
CAS 提供了 2 套默認的頁面,分別為「 default 」和「 simple 」,分別在目錄「 cas/WEB-INF/view/jsp/default 」和「 cas/WEB-INF/view/jsp/simple 」下。其中 default 是一個稍微復雜一些的頁面,使用 CSS,而 simple 則是能讓 CAS 正常工作的最簡化的頁面。
在部署 CAS 之前,我們可能需要定製一套新的 CAS Server 頁面,添加一些個性化的內容。最簡單的方法就是拷貝一份 default 或 simple 文件到「 cas/WEB-INF/view/jsp 」目錄下,比如命名為 newUI,接下來是實現和修改必要的頁面,有 4 個頁面是必須的:
casConfirmView.jsp: 當用戶選擇了「 warn 」時會看到的確認界面
casGenericSuccess.jsp: 在用戶成功通過認證而沒有目的Service時會看到的界面
casLoginView.jsp: 當需要用戶提供認證信息時會出現的界面
casLogoutView.jsp: 當用戶結束 CAS 單點登錄系統會話時出現的界面
CAS 的頁面採用 Spring 框架編寫,對於不熟悉 Spring 的使用者,在修改之前需要熟悉該框架。
頁面定製完過後,還需要做一些配置從而讓 CAS 找到新的頁面,拷貝「 cas/WEB-INF/classes/default_views.properties 」,重命名為「 cas/WEB-INF/classes/ newUI_views.properties 」,並修改其中所有的值到相應新頁面。最後是更新「 cas/WEB-INF/cas-servlet.xml 」文件中的 viewResolver,將其修改為如清單 9 中的內容。
清單 9. 指定 CAS 頁面
<bean id="viewResolver"
class="org.springframework.web.servlet.view.ResourceBundleViewResolver" p:order="0">
<property name="basenames">
<list>
<value>${cas.viewResolver.basename}</value>
<value> newUI_views</value>
</list>
</property>
</bean>
部署客戶端應用
單點登錄的目的是為了讓多個相關聯的應用使用相同的登錄過程,本文在講解過程中構造 2個簡單的應用,分別以 casTest1 和 casTest2 來作為示例,它們均只有一個頁面,顯示歡迎信息和當前登錄用戶名。這 2 個應用使用同一套登錄信息,並且只有登錄過的用戶才能訪問,通過本文的配置,實現單點登錄,即只需登錄一次就可以訪問這兩個應用。
與 CAS Server 建立信任關系
假設 CAS Server 單獨部署在一台機器 A,而客戶端應用部署在機器 B 上,由於客戶端應用與 CAS Server 的通信採用 SSL,因此,需要在 A 與 B 的 JRE 之間建立信任關系。
首先與 A 機器一樣,要生成 B 機器上的證書,配置 Tomcat 的 SSL 協議。其次,下載http://blogs.sun.com/andreas/entry/no_more_unable_to_find 的 InstallCert.java,運行「 java InstallCert compA:8443 」命令,並且在接下來出現的詢問中輸入 1。這樣,就將 A 添加到了 B 的 trust store 中。如果多個客戶端應用分別部署在不同機器上,那麼每個機器都需要與 CAS Server 所在機器建立信任關系。
配置 CAS Filter
准備好應用 casTest1 和 casTest2 過後,分別部署在 B 和 C 機器上,由於 casTest1 和casTest2,B 和 C 完全等同,我們以 casTest1 在 B 機器上的配置做介紹,假設 A 和 B 的域名分別為 domainA 和 domainB。
將 cas-client-java-2.1.1.zip 改名為 cas-client-java-2.1.1.jar 並拷貝到 casTest1/WEB-INF/lib目錄下,修改 web.xml 文件,添加 CAS Filter,如清單 10 所示:
清單 10. 添加 CAS Filter
<web-app>
...
<filter>
<filter-name>CAS Filter</filter-name>
<filter-class>e.yale.its.tp.cas.client.filter.CASFilter</filter-class>
<init-param>
<param-name>e.yale.its.tp.cas.client.filter.loginUrl</param-name>
<param-value>https://domainA:8443/cas/login</param-value>
</init-param>
<init-param>
<param-name>e.yale.its.tp.cas.client.filter.validateUrl</param-name>
<param-value>https://domainA:8443/cas/serviceValidate</param-value>
</init-param>
<init-param>
<param-name>e.yale.its.tp.cas.client.filter.serverName</param-name>
<param-value>domainB:8080</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CAS Filter</filter-name>
<url-pattern>/protected-pattern/*</url-pattern>
</filter-mapping>
...
</web-app>
對於所有訪問滿足 casTest1/protected-pattern/ 路徑的資源時,都要求到 CAS Server 登錄,如果需要整個 casTest1 均受保護,可以將 url-pattern 指定為「/*」。
從清單 10 可以看到,我們可以為 CASFilter 指定一些參數,並且有些是必須的,表格 1 和表格 2 中分別是必需和可選的參數:
表格 1. CASFilter 必需的參數
參數名 作用
e.yale.its.tp.cas.client.filter.loginUrl 指定 CAS 提供登錄頁面的 URL
e.yale.its.tp.cas.client.filter.validateUrl 指定 CAS 提供 service ticket 或 proxy ticket 驗證服務的 URL
e.yale.its.tp.cas.client.filter.serverName 指定客戶端的域名和埠,是指客戶端應用所在機器而不是 CAS Server 所在機器,該參數或 serviceUrl 至少有一個必須指定
e.yale.its.tp.cas.client.filter.serviceUrl 該參數指定過後將覆蓋 serverName 參數,成為登錄成功過後重定向的目的地址
表格 2. CASFilter 可選參數
參數名 作用
e.yale.its.tp.cas.client.filter.proxyCallbackUrl 用於當前應用需要作為其他服務的代理(proxy)時獲取 Proxy Granting Ticket 的地址
e.yale.its.tp.cas.client.filter.authorizedProxy 用於允許當前應用從代理處獲取 proxy tickets,該參數接受以空格分隔開的多個 proxy URLs,但實際使用只需要一個成功即可。當指定該參數過後,需要修改 validateUrl 到 proxyValidate,而不再是 serviceValidate
e.yale.its.tp.cas.client.filter.renew 如果指定為 true,那麼受保護的資源每次被訪問時均要求用戶重新進行驗證,而不管之前是否已經通過
e.yale.its.tp.cas.client.filter.wrapRequest 如果指定為 true,那麼 CASFilter 將重新包裝 HttpRequest,並且使 getRemoteUser() 方法返回當前登錄用戶的用戶名
e.yale.its.tp.cas.client.filter.gateway 指定 gateway 屬性
傳遞登錄用戶名
CAS 在登錄成功過後,會給瀏覽器回傳 Cookie,設置新的到的 Service Ticket。但客戶端應用擁有各自的 Session,我們要怎麼在各個應用中獲取當前登錄用戶的用戶名呢?CAS Client 的 Filter 已經做好了處理,在登錄成功後,就可以直接從 Session 的屬性中獲取,如清單 11 所示:
清單 11. 在 Java 中通過 Session 獲取登錄用戶名
// 以下兩者都可以
session.getAttribute(CASFilter.CAS_FILTER_USER);
session.getAttribute("e.yale.its.tp.cas.client.filter.user");
在 JSTL 中獲取用戶名的方法如清單 12 所示:
清單 12. 通過 JSTL 獲取登錄用戶名
<c:out value="${sessionScope[CAS:'e.yale.its.tp.cas.client.filter.user']}"/>
另外,CAS 提供了一個 CASFilterRequestWrapper 類,該類繼承自HttpServletRequestWrapper,主要是重寫了 getRemoteUser() 方法,只要在前面配置 CASFilter 的時候為其設置「 e.yale.its.tp.cas.client.filter.wrapRequest 」參數為 true,就可以通過 getRemoteUser() 方法來獲取登錄用戶名,具體方法如清單 13 所示:
清單 13. 通過 CASFilterRequestWrapper 獲取登錄用戶名
CASFilterRequestWrapper reqWrapper=new CASFilterRequestWrapper(request);
out.println("The logon user:" + reqWrapper.getRemoteUser());
2、cas service參數可以用域名嗎
CAS 的安全性是一個非常重要的 Topic 。 CAS 從 v1 到 v3 ,都很依賴於 SSL ,它假定了這樣一個事實,用戶在一個非常不安全的網路環境中使用 SSO , Hacker 的 Sniffer 會很容易抓住所有的 Http Traffic ,包括通過 Http 傳送的密碼甚至 Ticket ...
3、CAS單點登錄必須要使用域名嗎?不能使用IP 嗎
對,是必須得使用域名,這是由於它是基於COOKIE來實現的. 所有的WEB應用要想使用SSO的都離不開COOKIE. 甚至於可以說幾乎所有的登錄的實現都離不開COOKIE.
4、CAS 登錄異常求助
解決應用程序錯誤的方法步驟: 1.首先排除病毒原因,使用殺毒軟體,比如最新版本的360殺毒快速查殺3-5分鍾,根據檢查結果,點擊立即處理。 2.如果應用程序出錯的提示是缺少某個文件,那就可能是這個文件損壞,根據這個組件查詢是哪個系統組件損壞,重新安裝相關組件,恢復程序文件,一般即可解決。 3.若是相關軟體自身的組件缺失,只需要重新安裝這個軟體即可。比如運行迅雷時提示缺少某個文件,可以嘗試重新安裝
5、cas單點登錄配置,伺服器超時刷新頁面報錯
首先回答你第一個問題,安全證書是tomcat或者apache用於開啟ssl安全的socket鏈接使用的,也就是支持https協議的。一般我們都用tomcat作為應用伺服器,這樣就需要tomcat首先支持https協議,開啟https很簡單,找一下官方的文檔資料,我在這里簡單說一下,首先在部署tomcat的機器上為jdk(確切的說是jre,不過通常我們都在tomcat的伺服器上安裝jdk而不是jre)生成證書,使用jre自帶的keytool工具來生成即可,生成證書的過程中注意一點,就是CN項,也就是第一個欄位,是伺服器的域名,比如本機測試的話可以用localhost。使用以下語句
1. keytool -keystore keystore -alias acegisecurity -genkey -keyalg RSA -validity 9999 -storepass password -keypass password
What is your first and last name?(這個就是CN項)回答localhost即可
其他隨便填寫即可。
2. keytool -export -v -rfc -alias acegisecurity -file acegisecurity.txt -keystore keystore -storepass password
這一步是導出key。
3. 復制 acegisecurity.txt 到 %JAVA_HOME%\jre\lib\security
4. 復制 keystore 到 %CATALINA_HOME %
5. 控制台窗口(如果是Windows系統就是dos窗口)下進入 %JAVA_HOME%\jre\lib\security
6. keytool -import -v -file acegisecurity.txt -keypass password - keystore cacerts -storepass changeit -alias acegisecurity
向虛擬機中導入證書
接下來,用編輯器打開%CATALINA_HOME%/conf/server.xml,找到<Connector port="8443" maxHttpHeaderSize="8192"
maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
enableLookups="false" disableUploadTimeout="true"
acceptCount="100" scheme="https" secure="true"
clientAuth="false" sslProtocol="TLS" />
這一行默認是被注釋掉的,取消注釋,並加入keystoreFile="keystore" keystorePass="password"這兩個屬性,注意keystoreFile屬性可以使用keystore文件的絕對路徑,也可使用基於%CATALINA_HOME%環境變數的相對路徑,keystorePass是訪問keystore的密碼,應和上面製作證書時設定的密碼保持一致。
訪問https://localhost:8443,應彈出一個對話框,告知用戶正要訪問的站點的證書不安全,是否接受,確認接受,應可看到那隻熟悉可愛的小貓。
通過以上步驟就為tomcat配置了ssl。
配置了ssl,然後就是把cas server的war部署到這個tomcat下就可以了,到此,你的cas伺服器就算部署成功了,但是,cas server那個war默認是使用user.properties中的那麼幾個用戶做認證,要實現不同類型的認證方式還需要自己開發,這里不具體講了,可以參考官方文檔,也可以問我。呵呵:)
部署了cas服務,接下來就是接入client application了。
接入application有三種方式,一種是使用acegisecurity,很好用,但是很復雜;一種是使用cas提供的cas client,簡單快捷,適應各種惡劣環境,哈哈;最後一種是lam的一個開源項目,沒試過,不敢說怎麼樣。前兩種不明白可以找官方文檔,也尅問我,哈哈。
就第一個問題說的較詳細,實在打字太多,有點累了。後面的有點粗糙,不過對於有心的人我相信還是很受用的。總結了很久的東西,希望對你有幫助。
6、有人知道 cas單點登錄系統是怎麼樣取得proxyticket的?
CAS 原理和協議
從結構上看,CAS 包含兩個部分: CAS Server 和 CAS Client。CAS Server 需要獨立部署,主要負責對用戶的認證工作;CAS Client 負責處理對客戶端受保護資源的訪問請求,需要登錄時,重定向到 CAS Server。圖1 是 CAS 最基本的協議過程:
圖 1. CAS 基礎協議
CAS Client 與受保護的客戶端應用部署在一起,以 Filter 方式保護受保護的資源。對於訪問受保護資源的每個 Web 請求,CAS Client 會分析該請求的 Http 請求中是否包含 Service Ticket,如果沒有,則說明當前用戶尚未登錄,於是將請求重定向到指定好的 CAS Server 登錄地址,並傳遞 Service (也就是要訪問的目的資源地址),以便登錄成功過後轉回該地址。用戶在第 3 步中輸入認證信息,如果登錄成功,CAS Server 隨機產生一個相當長度、唯一、不可偽造的 Service Ticket,並緩存以待將來驗證,之後系統自動重定向到 Service 所在地址,並為客戶端瀏覽器設置一個 Ticket Granted Cookie(TGC),CAS Client 在拿到 Service 和新產生的 Ticket 過後,在第 5,6 步中與 CAS Server 進行身份合適,以確保 Service Ticket 的合法性。
在該協議中,所有與 CAS 的交互均採用 SSL 協議,確保,ST 和 TGC 的安全性。協議工作過程中會有 2 次重定向的過程,但是 CAS Client 與 CAS Server 之間進行 Ticket 驗證的過程對於用戶是透明的。
另外,CAS 協議中還提供了 Proxy (代理)模式,以適應更加高級、復雜的應用場景,具體介紹可以參考 CAS 官方網站上的相關文檔。
准備工作
本文中的例子以 tomcat5.5 為例進行講解,下載地址:
http://tomcat.apache.org/download-55.cgi
到 CAS 官方網站下載 CAS Server 和 Client,地址分別為:
http://www.ja-sig.org/downloads/cas/cas-server-3.1.1-release.zip
http://www.ja-sig.org/downloads/cas-clients/cas-client-java-2.1.1.zip
部署 CAS Server
CAS Server 是一套基於 Java 實現的服務,該服務以一個 Java Web Application 單獨部署在與 servlet2.3 兼容的 Web 伺服器上,另外,由於 Client 與 CAS Server 之間的交互採用 Https 協議,因此部署 CAS Server 的伺服器還需要支持 SSL 協議。當 SSL 配置成功過後,像普通 Web 應用一樣將 CAS Server 部署在伺服器上就能正常運行了,不過,在真正使用之前,還需要擴展驗證用戶的介面。
在 Tomcat 上部署一個完整的 CAS Server 主要按照以下幾個步驟:
配置 Tomcat 使用 Https 協議
如果希望 Tomcat 支持 Https,主要的工作是配置 SSL 協議,其配置過程和配置方法可以參考 Tomcat 的相關文檔。不過在生成證書的過程中,會有需要用到主機名的地方,CAS 建議不要使用 IP 地址,而要使用機器名或域名。
部署 CAS Server
CAS Server 是一個 Web 應用包,將前面下載的 cas-server-3.1.1-release.zip 解開,把其中的 cas-server-webapp-3.1.1.war 拷貝到 tomcat的 webapps 目錄,並更名為 cas.war。由於前面已配置好 tomcat 的 https 協議,可以重新啟動 tomcat,然後訪問:https://localhost:8443/cas ,如果能出現正常的 CAS 登錄頁面,則說明 CAS Server 已經部署成功。
雖然 CAS Server 已經部署成功,但這只是一個預設的實現,在實際使用的時候,還需要根據實際概況做擴展和定製,最主要的是擴展認證 (Authentication) 介面和 CAS Server 的界面。
擴展認證介面
CAS Server 負責完成對用戶的認證工作,它會處理登錄時的用戶憑證 (Credentials) 信息,用戶名/密碼對是最常見的憑證信息。CAS Server 可能需要到資料庫檢索一條用戶帳號信息,也可能在 XML 文件中檢索用戶名/密碼,還可能通過 LDAP Server 獲取等,在這種情況下,CAS 提供了一種靈活但統一的介面和實現分離的方式,實際使用中 CAS 採用哪種方式認證是與 CAS 的基本協議分離開的,用戶可以根據認證的介面去定製和擴展。
擴展 AuthenticationHandler
CAS 提供擴展認證的核心是 AuthenticationHandler 介面,該介面定義如清單 1 下:
清單 1. AuthenticationHandler定義
public interface AuthenticationHandler {
/**
* Method to determine if the credentials supplied are valid.
* @param credentials The credentials to validate.
* @return true if valid, return false otherwise.
* @throws AuthenticationException An AuthenticationException can contain
* details about why a particular authentication request failed.
*/
boolean authenticate(Credentials credentials) throws AuthenticationException;
/**
* Method to check if the handler knows how to handle the credentials
* provided. It may be a simple check of the Credentials class or something
* more complicated such as scanning the information contained in the
* Credentials object.
* @param credentials The credentials to check.
* @return true if the handler supports the Credentials, false othewrise.
*/
boolean supports(Credentials credentials);
}
該介面定義了 2 個需要實現的方法,supports ()方法用於檢查所給的包含認證信息的Credentials 是否受當前 AuthenticationHandler 支持;而 authenticate() 方法則擔當驗證認證信息的任務,這也是需要擴展的主要方法,根據情況與存儲合法認證信息的介質進行交互,返回 boolean 類型的值,true 表示驗證通過,false 表示驗證失敗。
CAS3中還提供了對AuthenticationHandler 介面的一些抽象實現,比如,可能需要在執行authenticate() 方法前後執行某些其他操作,那麼可以讓自己的認證類擴展自清單 2 中的抽象類:
清單 2. 定義
public abstract class
implements AuthenticateHandler{
protected Log log = LogFactory.getLog(this.getClass());
protected boolean preAuthenticate(final Credentials credentials) {
return true;
}
protected boolean postAuthenticate(final Credentials credentials,
final boolean authenticated) {
return authenticated;
}
public final boolean authenticate(final Credentials credentials)
throws AuthenticationException {
if (!preAuthenticate(credentials)) {
return false;
}
final boolean authenticated = doAuthentication(credentials);
return postAuthenticate(credentials, authenticated);
}
protected abstract boolean doAuthentication(final Credentials credentials)
throws AuthenticationException;
}
類新定義了 preAuthenticate() 方法和 postAuthenticate() 方法,而實際的認證工作交由 doAuthentication() 方法來執行。因此,如果需要在認證前後執行一些額外的操作,可以分別擴展 preAuthenticate()和 ppstAuthenticate() 方法,而 doAuthentication() 取代 authenticate() 成為了子類必須要實現的方法。
由於實際運用中,最常用的是用戶名和密碼方式的認證,CAS3 提供了針對該方式的實現,如清單 3 所示:
清單 3. 定義
public abstract class extends
{
...
protected final boolean doAuthentication(final Credentials credentials)
throws AuthenticationException {
return ((UsernamePasswordCredentials) credentials);
}
protected abstract boolean (
final UsernamePasswordCredentials credentials) throws AuthenticationException;
protected final PasswordEncoder getPasswordEncoder() {
return this.passwordEncoder;
}
public final void setPasswordEncoder(final PasswordEncoder passwordEncoder) {
this.passwordEncoder = passwordEncoder;
}
...
}
基於用戶名密碼的認證方式可直接擴展自 ,驗證用戶名密碼的具體操作通過實現 () 方法達到,另外,通常情況下密碼會是加密過的,setPasswordEncoder() 方法就是用於指定適當的加密器。
從以上清單中可以看到,doAuthentication() 方法的參數是 Credentials 類型,這是包含用戶認證信息的一個介面,對於用戶名密碼類型的認證信息,可以直接使用 UsernamePasswordCredentials,如果需要擴展其他類型的認證信息,需要實現Credentials介面,並且實現相應的 介面,其具體方法可以借鑒 UsernamePasswordCredentials 和 UsernamePassword。
JDBC 認證方法
用戶的認證信息通常保存在資料庫中,因此本文就選用這種情況來介紹。將前面下載的 cas-server-3.1.1-release.zip 包解開後,在 moles 目錄下可以找到包 cas-server-support-jdbc-3.1.1.jar,其提供了通過 JDBC 連接資料庫進行驗證的預設實現,基於該包的支持,我們只需要做一些配置工作即可實現 JDBC 認證。
JDBC 認證方法支持多種資料庫,DB2, Oracle, MySql, Microsoft SQL Server 等均可,這里以 DB2 作為例子介紹。並且假設DB2資料庫名: CASTest,資料庫登錄用戶名: db2user,資料庫登錄密碼: db2password,用戶信息表為: userTable,該表包含用戶名和密碼的兩個數據項分別為 userName 和 password。
1. 配置 DataStore
打開文件 %CATALINA_HOME%/webapps/cas/WEB-INF/deployerConfigContext.xml,添加一個新的 bean 標簽,對於 DB2,內容如清單 4 所示:
清單 4. 配置 DataStore
<bean id="casDataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName">
<value>com.ibm.db2.jcc.DB2Driver</value>
</property>
<property name="url">
<value>jdbc:db2://9.125.65.134:50000/CASTest</value>
</property>
<property name="username">
<value>db2user</value>
</property>
<property name="password">
<value>db2password</value>
</property>
</bean>
其中 id 屬性為該 DataStore 的標識,在後面配置 AuthenticationHandler 會被引用,另外,需要提供 DataStore 所必需的資料庫驅動程序、連接地址、資料庫登錄用戶名以及登錄密碼。
2. 配置 AuthenticationHandler
在 cas-server-support-jdbc-3.1.1.jar 包中,提供了 3 個基於 JDBC 的 AuthenticationHandler,分別為 , , 。其中 是用所給的用戶名和密碼去建立資料庫連接,根據連接建立是否成功來判斷驗證成功與否; 通過配置一個 SQL 語句查出密碼,與所給密碼匹配; 通過配置存放用戶驗證信息的表、用戶名欄位和密碼欄位,構造查詢語句來驗證。
使用哪個 AuthenticationHandler,需要在 deployerConfigContext.xml 中設置,默認情況下,CAS 使用一個簡單的 username=password 的 AuthenticationHandler,在文件中可以找到如下一行:<bean class="org.jasig.cas.authentication.handler.support.SimpleTestUsernamePassword
AuthenticationHandler" />,我們可以將其注釋掉,換成我們希望的一個 AuthenticationHandler,比如,使用 或 可以分別選取清單 5 或清單 6 的配置。
清單 5. 使用
<bean class="org.jasig.cas.adaptors.jdbc.">
<property name="dataSource" ref=" casDataSource " />
<property name="sql"
value="select password from userTable where lower(userName) = lower(?)" />
</bean>
清單 6. 使用
<bean id=""
class="org.jasig.cas.adaptors.jdbc."
abstract="false" singleton="true" lazy-init="default"
autowire="default" dependency-check="default">
<property name="tableUsers">
<value>userTable</value>
</property>
<property name="fieldUser">
<value>userName</value>
</property>
<property name="fieldPassword">
<value>password</value>
</property>
<property name="dataSource" ref=" casDataSource " />
</bean>
另外,由於存放在資料庫中的密碼通常是加密過的,所以 AuthenticationHandler 在匹配時需要知道使用的加密方法,在 deployerConfigContext.xml 文件中我們可以為具體的 AuthenticationHandler 類配置一個 property,指定加密器類,比如對於 ,可以修改如清單7所示:
清單 7. 添加 passwordEncoder
<bean class="org.jasig.cas.adaptors.jdbc.">
<property name="dataSource" ref=" casDataSource " />
<property name="sql"
value="select password from userTable where lower(userName) = lower(?)" />
<property name="passwordEncoder" ref="myPasswordEncoder"/>
</bean>
其中 myPasswordEncoder 是對清單 8 中設置的實際加密器類的引用:
清單 8. 指定具體加密器類
<bean id="passwordEncoder"
class="org.jasig.cas.authentication.handler.MyPasswordEncoder"/>
這里 MyPasswordEncoder 是根據實際情況自己定義的加密器,實現 PasswordEncoder 介面及其 encode() 方法。
3. 部署依賴包
在以上配置完成以後,需要拷貝幾個依賴的包到 cas 應用下,包括:
將 cas-server-support-jdbc-3.1.1.jar 拷貝到 %CATALINA_HOME%/webapps/cas/ WEB-INF/lib 目錄。
資料庫驅動,由於這里使用 DB2,將 %DB2_HOME%/java 目錄下的 db2java.zip (更名為 db2java.jar), db2jcc.jar, db2jcc_license_cu.jar 拷貝到 %CATALINA_HOME%/webapps/cas/WEB-INF/lib 目錄。對於其他資料庫,同樣將相應資料庫驅動程序拷貝到該目錄。
DataStore 依賴於 commons-collections-3.2.jar, commons-dbcp-1.2.1.jar, commons-pool-1.3.jar,需要到 apache 網站的 Commons 項目下載以上 3 個包放進 %CATALINA_HOME%/webapps/cas/WEB-INF/lib 目錄。
擴展 CAS Server 界面
CAS 提供了 2 套默認的頁面,分別為「 default 」和「 simple 」,分別在目錄「 cas/WEB-INF/view/jsp/default 」和「 cas/WEB-INF/view/jsp/simple 」下。其中 default 是一個稍微復雜一些的頁面,使用 CSS,而 simple 則是能讓 CAS 正常工作的最簡化的頁面。
在部署 CAS 之前,我們可能需要定製一套新的 CAS Server 頁面,添加一些個性化的內容。最簡單的方法就是拷貝一份 default 或 simple 文件到「 cas/WEB-INF/view/jsp 」目錄下,比如命名為 newUI,接下來是實現和修改必要的頁面,有 4 個頁面是必須的:
casConfirmView.jsp: 當用戶選擇了「 warn 」時會看到的確認界面
casGenericSuccess.jsp: 在用戶成功通過認證而沒有目的Service時會看到的界面
casLoginView.jsp: 當需要用戶提供認證信息時會出現的界面
casLogoutView.jsp: 當用戶結束 CAS 單點登錄系統會話時出現的界面
CAS 的頁面採用 Spring 框架編寫,對於不熟悉 Spring 的使用者,在修改之前需要熟悉該框架。
頁面定製完過後,還需要做一些配置從而讓 CAS 找到新的頁面,拷貝「 cas/WEB-INF/classes/default_views.properties 」,重命名為「 cas/WEB-INF/classes/ newUI_views.properties 」,並修改其中所有的值到相應新頁面。最後是更新「 cas/WEB-INF/cas-servlet.xml 」文件中的 viewResolver,將其修改為如清單 9 中的內容。
清單 9. 指定 CAS 頁面
<bean id="viewResolver"
class="org.springframework.web.servlet.view.ResourceBundleViewResolver" p:order="0">
<property name="basenames">
<list>
<value>${cas.viewResolver.basename}</value>
<value> newUI_views</value>
</list>
</property>
</bean>
部署客戶端應用
單點登錄的目的是為了讓多個相關聯的應用使用相同的登錄過程,本文在講解過程中構造 2個簡單的應用,分別以 casTest1 和 casTest2 來作為示例,它們均只有一個頁面,顯示歡迎信息和當前登錄用戶名。這 2 個應用使用同一套登錄信息,並且只有登錄過的用戶才能訪問,通過本文的配置,實現單點登錄,即只需登錄一次就可以訪問這兩個應用。
與 CAS Server 建立信任關系
假設 CAS Server 單獨部署在一台機器 A,而客戶端應用部署在機器 B 上,由於客戶端應用與 CAS Server 的通信採用 SSL,因此,需要在 A 與 B 的 JRE 之間建立信任關系。
首先與 A 機器一樣,要生成 B 機器上的證書,配置 Tomcat 的 SSL 協議。其次,下載http://blogs.sun.com/andreas/entry/no_more_unable_to_find 的 InstallCert.java,運行「 java InstallCert compA:8443 」命令,並且在接下來出現的詢問中輸入 1。這樣,就將 A 添加到了 B 的 trust store 中。如果多個客戶端應用分別部署在不同機器上,那麼每個機器都需要與 CAS Server 所在機器建立信任關系。
配置 CAS Filter
准備好應用 casTest1 和 casTest2 過後,分別部署在 B 和 C 機器上,由於 casTest1 和casTest2,B 和 C 完全等同,我們以 casTest1 在 B 機器上的配置做介紹,假設 A 和 B 的域名分別為 domainA 和 domainB。
將 cas-client-java-2.1.1.zip 改名為 cas-client-java-2.1.1.jar 並拷貝到 casTest1/WEB-INF/lib目錄下,修改 web.xml 文件,添加 CAS Filter,如清單 10 所示:
清單 10. 添加 CAS Filter
<web-app>
...
<filter>
<filter-name>CAS Filter</filter-name>
<filter-class>e.yale.its.tp.cas.client.filter.CASFilter</filter-class>
<init-param>
<param-name>e.yale.its.tp.cas.client.filter.loginUrl</param-name>
<param-value>https://domainA:8443/cas/login</param-value>
</init-param>
<init-param>
<param-name>e.yale.its.tp.cas.client.filter.validateUrl</param-name>
<param-value>https://domainA:8443/cas/serviceValidate</param-value>
</init-param>
<init-param>
<param-name>e.yale.its.tp.cas.client.filter.serverName</param-name>
<param-value>domainB:8080</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CAS Filter</filter-name>
<url-pattern>/protected-pattern/*</url-pattern>
</filter-mapping>
...
</web-app>
對於所有訪問滿足 casTest1/protected-pattern/ 路徑的資源時,都要求到 CAS Server 登錄,如果需要整個 casTest1 均受保護,可以將 url-pattern 指定為「/*」。
從清單 10 可以看到,我們可以為 CASFilter 指定一些參數,並且有些是必須的,表格 1 和表格 2 中分別是必需和可選的參數:
表格 1. CASFilter 必需的參數
參數名 作用
e.yale.its.tp.cas.client.filter.loginUrl 指定 CAS 提供登錄頁面的 URL
e.yale.its.tp.cas.client.filter.validateUrl 指定 CAS 提供 service ticket 或 proxy ticket 驗證服務的 URL
e.yale.its.tp.cas.client.filter.serverName 指定客戶端的域名和埠,是指客戶端應用所在機器而不是 CAS Server 所在機器,該參數或 serviceUrl 至少有一個必須指定
e.yale.its.tp.cas.client.filter.serviceUrl 該參數指定過後將覆蓋 serverName 參數,成為登錄成功過後重定向的目的地址
表格 2. CASFilter 可選參數
參數名 作用
e.yale.its.tp.cas.client.filter.proxyCallbackUrl 用於當前應用需要作為其他服務的代理(proxy)時獲取 Proxy Granting Ticket 的地址
e.yale.its.tp.cas.client.filter.authorizedProxy 用於允許當前應用從代理處獲取 proxy tickets,該參數接受以空格分隔開的多個 proxy URLs,但實際使用只需要一個成功即可。當指定該參數過後,需要修改 validateUrl 到 proxyValidate,而不再是 serviceValidate
e.yale.its.tp.cas.client.filter.renew 如果指定為 true,那麼受保護的資源每次被訪問時均要求用戶重新進行驗證,而不管之前是否已經通過
e.yale.its.tp.cas.client.filter.wrapRequest 如果指定為 true,那麼 CASFilter 將重新包裝 HttpRequest,並且使 getRemoteUser() 方法返回當前登錄用戶的用戶名
e.yale.its.tp.cas.client.filter.gateway 指定 gateway 屬性
傳遞登錄用戶名
CAS 在登錄成功過後,會給瀏覽器回傳 Cookie,設置新的到的 Service Ticket。但客戶端應用擁有各自的 Session,我們要怎麼在各個應用中獲取當前登錄用戶的用戶名呢?CAS Client 的 Filter 已經做好了處理,在登錄成功後,就可以直接從 Session 的屬性中獲取,如清單 11 所示:
清單 11. 在 Java 中通過 Session 獲取登錄用戶名
// 以下兩者都可以
session.getAttribute(CASFilter.CAS_FILTER_USER);
session.getAttribute("e.yale.its.tp.cas.client.filter.user");
在 JSTL 中獲取用戶名的方法如清單 12 所示:
清單 12. 通過 JSTL 獲取登錄用戶名
<c:out value="${sessionScope[CAS:'e.yale.its.tp.cas.client.filter.user']}"/>
另外,CAS 提供了一個 CASFilterRequestWrapper 類,該類繼承自HttpServletRequestWrapper,主要是重寫了 getRemoteUser() 方法,只要在前面配置 CASFilter 的時候為其設置「 e.yale.its.tp.cas.client.filter.wrapRequest 」參數為 true,就可以通過 getRemoteUser() 方法來獲取登錄用戶名,具體方法如清單 13 所示:
清單 13. 通過 CASFilterRequestWrapper 獲取登錄用戶名
CASFilterRequestWrapper reqWrapper=new CASFilterRequestWrapper(request);
out.println("The logon user:" + reqWrapper.getRemoteUser());
7、如何配置內網域名
建了DNS伺服器。控制面板-添加刪除程序-添加刪除WINDOWS組件。
裝一下,然後正向查找區域建個A記錄 把域名和IP綁定,就可以使用域名訪問了。
8、CAS 單點登錄 跳轉時報錯
這個是由於CAS Validation Filter這個filter下面的配置中casServerUrlPrefix的路徑配置不正確導致的,一般配置為http://cas伺服器ip:對應的伺服器使用埠/cas,前面也可能是https,這個要看你伺服器的設置了。