SSO与CAS
一. SSO (Single Sign-on)原理
SSO 分為Web-SSO和桌面SSO。桌面 SSO 體現在操作系統級別上。Web-SSO體現在客戶端,主要特點是: SSO 應用之間使用 Web 協議 ( 如 HTTPS) ,并且只有一個登錄入口。我們所講的SSO,指 Web SSO 。
SSO 的體系中,有下面三種角色:
? User(多個)
? Web應用(多個)
? SSO認證中心(一個)
SSO 實現模式千奇百怪,但萬變不離其宗,包含以下三個原則:
? 所有的登錄都在 SSO 認證中心進行。
? SSO 認證中心通過一些方法來告訴 Web 應用當前訪問用戶究竟是不是通過認證的用戶。
? SSO 認證中心和所有的 Web 應用建立一種信任關系。
二. CAS 的基本原理
CAS(Central Authentication Service) 是 Yale 大學發起的構建 Web SSO 的 Java開源項目。
?
1. CAS 的結構體系
? CAS Server
CAS Server 負責完成對用戶信息的認證,需要單獨部署,CAS Server 會處理用戶名 / 密碼等憑證 (Credentials) 。
? CAS Client
CAS Client部署在客戶端,當有對本地 Web 應用受保護資源的訪問請求,并且需要對請求方進行身份認證,重定向到 CAS Server 進行認證。
?
2. CAS 協議
?
基礎協議
上圖是一個基礎的 CAS 協議, CAS Client 以 過濾器的方式保護 Web 應用的受保護資源,過濾從客戶端過來的每一個 Web 請求,同時, CAS Client 會分析 HTTP 請求中是否包請求 Service Ticket( 上圖中的 Ticket) ,如果沒有,則說明該用戶是沒有經過認證的, CAS Client 會重定向用戶請求到 CAS Server ( Step 2 )。 Step 3 是用戶認證過程,如果用戶提供了正確的認證信息 , CAS Server 會產生一個隨機的 Service Ticket ,會向 User 發送一個 Ticket granting cookie (TGC) 給 User 的瀏覽器,并且重定向用戶到 CAS Client (附帶剛才產生的 Service Ticket),Step 5 和 Step6 是 CAS Client 和 CAS Server 之間完成了一個對用戶的身份核實,用 Ticket 查到 Username ,認證通過。
3. CAS 如何實現 SSO
當用戶訪問Helloservice2再次被重定向到 CAS Server 的時候, CAS Server 會主動獲到這個 TGC cookie ,然后做下面的事情:
?
1) 如果 User 的持有 TGC 且其還沒失效,那么就走基礎協議圖的 Step4 ,達到了 SSO 的效果。
2) 如果 TGC 失效,那么用戶還是要重新認證 ( 走基礎協議圖的 Step3) 。
?
三. 實踐配置
下面我們以tomcat 5.5 為例進行說明(這里,我將Server和Client同時放在了同一個Tomcat服務器下)。
軟件環境:tomcat 5.5 ant-1.6.5, jdk1.5.0_06
下載cas-server-3.0.4.zip和cas-client和cas-server-jdbc-3.0.5-rc2.jar和mysql 5.0.16和tomcat 5.5.15
http://www.ja-sig.org/downloads/cas/cas-server-3.0.4.zip http://www.yale.edu/tp/cas/cas-client-2.0.11.zip
http://developer.ja-sig.org/maven/cas/jars/cas-server-jdbc-3.0.5-rc2.jar
http://www.mysql.com
http://tomcat.apache.org/
(一) 將一個或者一些頁面進行支持HTTPS傳輸協議(意義:對某些頁面進行了安全傳輸)(重點掌握)
1. 產生SERVER的證書庫文件
keytool -genkey -alias tomcat -keyalg RSA [-keystore keystore-file]
并將證書文件放在web容器的目錄下。
?
2. (在server端)配置tomcat使用HTTPS
$CATALINA_HOME/conf/server.xml里
<Connector port="8443" maxHttpHeaderSize="8192"
keystorePass="changeit" keystoreFile="/conf/.keystore"
maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
enableLookups="false" disableUploadTimeout="true"
acceptCount="100" scheme="https" secure="true"
clientAuth="false" sslProtocol="TLS" />
注意:keystorePass="changeit"(這個問證書庫文件的密碼,也就是上面配置產生的一個密碼) keystoreFile="/.keystore"(這是證書庫文件的存放路徑,其中根目錄"/"為tomcat的安裝路徑)
3. 在WEB-INF/web.xml文件中增加
<security-constraint>
<web-resource-collection >
<web-resource-name >SSL</web-resource-name> <!--名字隨便取-->
<url-pattern>/jsp2/el/*</url-pattern>
</web-resource-collection>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
解釋:transport-guarantee元素指定了客戶端和服務端的通信關系,有NONE,INTEGRAL,CONFIDENTIAL。NONE表示著應用不需要任何傳輸保障。INTEGRAL表示著在數據在客戶端到服務端的過程中不能有任何改變。CONFIDENTIAL表示在傳輸過程中防止其他傳輸內容的干擾。在使用SSl時常用的就INTEGRAL或CONFIDENTIL。
4. 進行訪問測試
(二) 實現CAS系統
1. 產生SERVER的證書庫文件
keytool -genkey -alias tomcat -keyalg RSA [-keystore keystore-file]
并將證書文件放在web容器的目錄下。
2. (在server端)配置tomcat使用HTTPS
$CATALINA_HOME/conf/server.xml里
<Connector port="8443" maxHttpHeaderSize="8192"
keystorePass="changeit" keystoreFile="/.keystore"
maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
enableLookups="false" disableUploadTimeout="true"
acceptCount="100" scheme="https" secure="true"
clientAuth="false" sslProtocol="TLS" />
注意:keystorePass="changeit"(這個問證書庫文件的密碼,也就是上面配置產生的一個密碼) keystoreFile="/.keystore"(這是證書庫文件的存放路徑,其中根目錄"/"為tomcat的安裝路徑)
3. 將cas-server-3.0.4.zip解壓,并將target/cas.war拷貝到webapps下。
4. 將cas-client-2.0.11.zip解壓,把cas-client-2.0.11/java/lib/casclient.jar拷貝到client服務器上(這里為同一tomcat)的
webapps/servlets-examples/WEB-INF/lib目錄下(如果沒有就建一個)
5. 在要使用CAS的客戶端應用里設置(以servlets-examples這個APP為例,在應用時,所有客戶端均進行類似配置),我們使用ServletFilter(CAS client里提供的)來實現SSO的檢查。
修改servlets-examples/WEB-INF/web.xml
<filter>
<filter-name>CASFilter</filter-name>
<filter-class>edu.yale.its.tp.cas.client.filter.CASFilter</filter-class>
<init-param><param-name>edu.yale.its.tp.cas.client.filter.loginUrl</param-name>
<param-value>https://your.cas.server.name:port<!--這里是CAS server的loginURL-->/cas/login</param-value>
</init-param>
<init-param><param-name>edu.yale.its.tp.cas.client.filter.validateUrl</param-name>
<param-value>https://your.cas.server.name:port<!--這里是CAS server的URL驗證器--> /cas/proxyValidate</param-value>
</init-param>
<init-param>
<param-name>edu.yale.its.tp.cas.client.filter.serverName</param-name>
<param-value>your.client.server.name:port <!--client:port就是需要CAS需要攔截的地址和端口,一般就是這個TOMCAT所啟動的IP(默認為localhost)和port(默認8080)--></param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CASFilter</filter-name>
<url-pattern>/servlet/*</url-pattern>
</filter-mapping>
配置好的例子:
<filter>
<filter-name>CASFilter</filter-name>
<filter-class>edu.yale.its.tp.cas.client.filter.CASFilter</filter-class>
<init-param>
<param-name>edu.yale.its.tp.cas.client.filter.loginUrl</param-name>
<param-value>https://localhost:8443/cas/login</param-value>
</init-param>
<init-param>
<param-name>edu.yale.its.tp.cas.client.filter.validateUrl</param-name>
<param-value>https://localhost:8443/cas/proxyValidate</param-value>
</init-param>
<init-param>
<param-name>edu.yale.its.tp.cas.client.filter.serverName</param-name>
<param-value>localhost:8080</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CASFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
?
6. .導出SERVER端的的證書文件(證書文件只包含公鑰)
keytool -export -file myserver.crt -alias my-alias-name -keystore keystore-file
// keytool -export -file myserver.crt -alias tomcat -keystore .keystore
7. 在客戶端的JVM里的證書庫cacerts中導入信任的SERVER的證書(根據情況有可能需要管理員權限)
keytool -import -keystore cacerts -file myserver.crt -alias hostname(別名)
然后將cacerts 復制到%JAVA_HOME%/jre/lib/security/目錄下
//keytool -import -keystore cacerts -file myserver.crt -alias tomcat
?
8. 測試.
把server和client分別起來(這里為同一個Tomcat,實際應用時可以在多個服務器上,且client可以為多個應用),檢查啟動的LOG是否正常,如果一切OK,就訪問
http://localhost:8080/servlets-examples/servlet/HelloWorldExample
系統會自動跳轉到一個驗證頁面,隨便輸入一個相同的賬號,密碼,驗正通過之后就會訪問
到真正的HelloWorldExample這個servlet了
?
四. 結合實際的環境的擴展
1 多個web應用如何實現單點登陸
(!--大家思考一下:如果我想在配置一個客戶端,需要什么步驟?)
下面以jsp-examples為例子,進行下面得闡述:
(1)在/webapps/jsp-examples/WEB-INF/web.xml文件中進行配置:
<filter>
<filter-name>CASFilter</filter-name>
<filter-class>
edu.yale.its.tp.cas.client.filter.CASFilter
</filter-class>
<init-param>
<param-name>
edu.yale.its.tp.cas.client.filter.loginUrl
</param-name>
<param-value>https://localhost:8443/cas/login</param-value>
</init-param>
<init-param>
<param-name>
edu.yale.its.tp.cas.client.filter.validateUrl
</param-name>
<param-value>
https://localhost:8443/cas/proxyValidate
</param-value>
</init-param>
<init-param>
<param-name>
edu.yale.its.tp.cas.client.filter.serverName
</param-name>
<param-value>localhost:8080</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CASFilter</filter-name>
<url-pattern>/jsp2/simpletag/*</url-pattern>
</filter-mapping>
(2)在webapps/jsp-examples/WEB-INF/lib增加引用得jar包,casclient.jar。
2 認證業務方法的擴展:
2.1.1 配置CAS使用數據庫進行驗證
在MySql中的Test庫中新建user表
Create TABLE `app_user` (
`username` varchar(30) NOT NULL default '',
`password` varchar(45) NOT NULL default '',
PRIMARY KEY (`username`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
添加以下用戶:
Insert INTO `app_user` (`username`,`password`) VALUES
('test',' test '),
(' test 1',' test 1');
2.1.2 修改cas項目中的deployerConfigContext.xml文件
<bean class="org.jasig.cas.authentication.handler.support.SimpleTestUsernamePasswordAuthenticationHandler" />
注釋掉該行,在其下加入:
<bean class="org.jasig.cas.adaptors.jdbc.QueryDatabaseAuthenticationHandler">
<property name="sql" value="select password from app_user where username=?" />
<property name="dataSource" ref="dataSource" />
</bean>
并添加一個bean:
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource" destroy-method="close">
<property name="driverClassName"><value>com.mysql.jdbc.Driver</value></property>
<property name="url"><value>jdbc:mysql://localhost:3306/test</value></property>
<property name="username"><value>root</value></property>
<property name="password"><value>root</value></property>
</bean>
2.1.3 拷貝cas-server-jdbc-3.0.6.jar和mysql-connector-java-3.1.11-bin.jar到webapps/cas/WEB-INF/lib下。
3 如何在這取得用戶名稱
<%@page contentType="text/html;charset=GBK"%>
<%
String username=(String)session.getAttribute("edu.yale.its.tp.cas.client.filter.user");
%>
<p>當前得登陸用戶:<%=username%></p>
<%
username = (String)session.getAttribute("edu.yale.its.tp.cas.client.filter.user");
%>
4 登陸頁面的擴展:
(1) 現在CAS系統中存在的兩套登陸頁面{project.home}/webapp/WEB-INF/view/jsp/default/ui/和{project.home}/webapp/WEB-INF/view/jsp/simple/ui
(2) {project.home}/webapp/WEB-INF/cas-servlet.xml
<bean
id="viewResolver"
class="org.springframework.web.servlet.view.ResourceBundleViewResolver">
<property
name="basename"
value="simple_views" />
<property
name="order"
value="0" />
</bean>
這個bean中basename屬性決定由哪個屬性文件加載,simple_views. properties還是default_views. Properties
而屬性文件:
{project.home}/webapp/WEB-INF/classes/default_views.properties
{project.home}/webapp/WEB-INF/classes/simple_views.properties
### Login view (/login)
casLoginView.(class)=org.springframework.web.servlet.view.JstlView
casLoginView.url=/WEB-INF/view/jsp/default/ui/casLoginView.jsp
(登陸頁面)
### Login confirmation view (logged in, warn=true)
casLoginConfirmView.(class)=org.springframework.web.servlet.view.JstlView
casLoginConfirmView.url=/WEB-INF/view/jsp/default/ui/casConfirmView.jsp
(當選擇"警告"按鈕時,系統顯示的頁面)
### Logged-in view (logged in, no service provided)
casLoginGenericSuccessView.(class)=org.springframework.web.servlet.view.JstlView
casLoginGenericSuccessView.url=/WEB-INF/view/jsp/default/ui/casGenericSuccess.jsp(成功登陸頁面)
每個屬性文件決定具體加載頁面的名稱。
?
?
五. CAS 安全性
? TGC/PGT 安全性
TGC 也有自己的存活周期。下面是 CAS 的 applicationContext.xml 中,通過 TimeoutExpirationPolicy來設置 CAS TGC 存活周期的參數,參數默認是 120 分鐘,在合適的范圍內設置最小值,太短,會影響 SSO 體驗,太長,會增加安全性風險。
<bean
id="grantingTicketExpirationPolicy" class="org.jasig.cas.ticket.support.TimeoutExpirationPolicy">
<!-- This argument is the time a ticket can exist before its considered expired. -->
<constructor-arg
index="0"
value="7200000" />//單位為:毫秒
</bean>
? Service Ticket/Proxy Ticket 安全性
設用戶拿到 Service Ticket 之后,他請求 helloservice 的過程又被中斷了, Service Ticket 就被空置了,事實上,此時, Service Ticket 仍然有效。 CAS 規定 Service Ticket 只能存活一定的時間,然后 CAS Server 會讓它失效。通過在 applicationContext.xml 中配置下面的參數,可以讓 Service Ticket 在訪問多少次或者多少秒內失效。
<!-- Expiration policies -->
<bean
id="serviceTicketExpirationPolicy"
class="org.jasig.cas.ticket.support.MultiTimeUseOrTimeoutExpirationPolicy">
<!-- This argument is the number of times that a ticket can be used before its considered expired. -->
<constructor-arg
index="0"
value="1" />
<!-- This argument is the time a ticket can exist before its considered expired. -->
<constructor-arg
index="1"
value="300000" />//單位:毫秒
</bean>
該參數在業務應用的條件范圍內,越小越安全。
?
總結
- 上一篇: js获取url中的参数,url中传递中文
- 下一篇: CAS_SSO单点登录实例详细步骤(转)