CAS (Central Authentication Service) 是 Yale 大学的 ITS 开发的一套 JAVA 实现的开源
的 SSO(single sign-on) 的服务(主要是2.0,到3.0为ja-sig)。
关键字
TGC(ticket-granting cookie)--------- 受权的票据证明
KDC( Key Distribution Center ) ---------- 密钥发放中心
Service ticket(ST) --------- 服务票据, 由 KDC 的 TGS 发放。 任何一台 Workstation 都需要拥有一张有效的 Service Ticket 才能访问域内部的应用 (Applications) 。 如果能正确接收 Service Ticket ,说明在 CASClient-CASServer 之间的信任关系已经被正确建立起来 , 通常为一张数字加密的证书
Ticket Granting tieckt(TGT) --------- 票据授权票据,由 KDC 的 AS 发放。即获取这样一张票据后,以后申请各种其他服务票据 (ST) 便不必再向 KDC 提交身份认证信息 ( 准确术语是 Credentials) 。
authentication service (AS) --------- 认证用服务,索取 Crendential ,发放 TGT
ticket-granting service (TGS) --------- 票据授权服务,索取 TGT ,发放 ST
CAS 单点服务器的认证过程,所有应用服务器收到应用请求后,检查 ST 和 TGT ,如果没有或不对,转到 CAS 认证服务器登陆页面,通过安全认证后得到 ST 和 TGT 再重定向到相关应用服务器,在会话生命周期之内如果再定向到别的应用,将出示
ST 和 TGT 进行认证 , 注意 , 取得 TGT 的过程是通过 SSL 安全协议的 ( 换句话说就是如果不用 ssl 协议 , 每访问一个应用服务,就得重新到认证服务中心认证一次 ) ,关于 SSL 的相关描述可以查看附录 .
白话描述 :
单点登陆 , 无非就是提供给用户一次登陆 , 多个系统共享用户信息的操作 .
这个是怎么操作的呢 ? 有简单的方法 , 当用户访问其他系统的时候 , 写个 URL 带上用户的 ID 和 PASS 提交到相应的系统就可以了 . 这也是一种方法
那 CAS 是怎么操作的呢 ? 或则是 KRB(Kerberos 是一个加密认证协议,允许网络用户不使用明文密码访问服务,一个普通
的协议实现包括 LOGIN 服务存在伪造欺骗对 Key Distribution Center 的响应 。
) 怎么操作的呢 ?
他并不是很复杂 , 他先是建立一个 专门认证用户的 服务 (SERVER) 这个服务只做一件事 , 负责验证用户的 ID 和 PASS 是否是正确 , 在正确的情况提供用户一个名为 TGT 的票据 ,
相当你要去游乐场玩 , 首先你要在门口检查你的身份 ( 即 CHECK 你的 ID 和 PASS), 如果你通过验证 , 游乐场的门卫 (AS) 即提供给你一张门卡 (TGT).
这张卡片的用处就是告诉 游乐场的各个场所 , 你是通过正门进来 , 而不是后门偷爬进来的 , 并且也是获取进入场所一把钥匙 .
好的 , 现在你有张卡 , 但是这对你来不重要 , 因为你来游乐场不是为了拿这张卡的 , 好的 , 我们向你的目的出发 , 恩 , 你来到一个摩天楼 , 你想进入玩玩 ,
这时摩天轮的服务员 (client) 拦下你 , 向你要求摩天轮的 (ST) 票据 , 你说你只有一个门卡 (TGT), 好的 , 那你只要把 TGT 放在一旁的票据授权机 (TGS) 上刷一下 ,
票据授权机 (TGS) 就根据你现在所在的摩天轮 , 给你一张摩天轮的票据 (ST), 哈 , 你有摩天轮的票据 , 现在你可以畅通无阻的进入摩天轮里游玩了 .
当然如果你玩完摩天轮后 , 想去游乐园的咖啡厅休息下 , 那你一样只要带着那张门卡 (TGT). 到相应的咖啡厅的票据授权机 (TGS) 刷一下 , 得到咖啡厅的票据 (ST) 就可以进入咖啡厅
当你离开游乐场后 , 想用这张 TGT 去刷打的回家的费用 , 呵呵 , 对不起 , 你的 TGT 已经过期了 , 在你离开游乐场那刻开始 , 你的 TGT 就已经销毁了 ~
Yale CAS Server 的配置过程
CAS (Central Authentication Service) 是 Yale 大学的 ITS 开发的一套 JAVA 实现的开源
的 SSO(single sign-on) 的服务。该服务是以一个 java web app(eg:cas.war) 来进行服务的,
使用时需要将 cas.war 发布到一个 servlet2.3 兼容的服务器上,并且服务器需要支持 SSL ,
在需要使用该服务的其他服务器(客户),只要进行简单的配置就可以实现 SSO 了。
CAS 的客户端可以有很多种,因为验证的结果是以 XML 的格式返回的, CAS 的客户端已
打包进去的有 java,perl,python,asp,apache module 等好几种客户端示例,你还可以根据
需要实现一个自己的客户端,非常简单 !~
下面我们以 tomcat 5.0 作为 CAS Server(server1) ,另外一台 tomcat5.0 为 client(client1)
为例进行说明。
1. 下载 cas-server 和 cas-client( 可选,建议使用)
http://www.ja-sig.org/downloads/cas/cas-server-3.0.5.zip
http://www.ja-sig.org/downloads/cas-clients/cas-client-java-2.1.1.zip
2. 将 cas-server-3.0.5.zip 解压,并将 lib/cas.war 拷贝到 server1 的 webapps 下
3. 产生 SERVER 的证书
PS: 参数与各系统本身一致
%JAVA_HOME%\bin\keytool -delete -alias tomcat -keypass changeit
%JAVA_HOME%\bin\keytool -genkey -alias tomcat -keypass changeit -keyalg RSA
%JAVA_HOME%\bin\keytool -export -alias tomcat -keypass changeit -file %FILE_NAME%
%JAVA_HOME%\bin\keytool -import -file server.crt -keypass changeit -keystore %JAVA_HOME%/jre/lib/security/cacerts
%JAVA_HOME%\bin\keytool -import -file server.crt -keystore %JAVA_HOME%\jre\lib\security\cacerts
4. 在 server1 配置 tomcat 使用 HTTPS
$CATALINA_HOME/conf/server.xml 里
<Connector className="org.apache.coyote.tomcat5.CoyoteConnector"
port="8443" minProcessors="5" maxProcessors="75"
enableLookups="true" disableUploadTimeout="true"
acceptCount="100" debug="0" scheme="https"
secure="true">
<Factory className="org.apache.coyote.tomcat5.CoyoteServerSocketFactory"
keystoreFile="/path/to/your/keystore-file"
keystorePass="your-password" clientAuth="false" protocol="TLS" />
</Connector>
5. 在要使用 CAS 的客户端 client1 里设置(以 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(eg:server1):port/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(eg:server1):port/cas/proxyValidate</param-value>
</init-param>
<init-param>
<param-name>edu.yale.its.tp.cas.client.filter.serviceUrl</param-name>
<param-value>your.client.server.ip(eg:127.0.0.1):port</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CASFilter</filter-name>
<url-pattern>/servlet/*</url-pattern>
</filter-mapping>
PS: 在 client 端配置 filter 时 , 需要将 CAS 的 filter 放在 web.xml 最上端 ,. 如果在你的 web.xml 有类似 encodingFilter 的 filter 也需要将这个 filter 放在 CAS filter 下面 , 否则你会发现每次访问时都需要你进行验证 .
6. 将 cas-client-java-2.1.1.zip 解压,把 java/lib/casclient.jar 拷贝到 client1 服务器上的
webapps/servlets-examples/WEB-INF/lib 目录下(如果没有就建一个)
7. 导出 SERVER 的证书,用来给所有需要用到的客户端导入
keytool -export -file server.crt -alias my-alias-name -keystore keystore-file
8. 在客户端的 JVM 里导入信任的 SERVER 的证书 ( 根据情况有可能需要管理员权限 )
keytool -import -keystore $JAVA_HOME/jre/lib/security/cacerts -file server.crt -alias my-alias-name
9.test & done.
把 server1 和 client1 分别起来,检查启动的 LOG 是否正常,如果一切 OK ,就访问
http://client1:8080/servlets-examples/servlet/HelloWorldExample
系统会自动跳转到一个验证页面,随便输入一个相同的账号 , 密码,严正通过之后就会访问
到真正的 HelloWorldExample 这个 servlet 了
实现自已的认证代码 (java 代码和相关注释 , 需要 cas-server-3.0.5.jar 包 )
package com.mcm.sso;
import org.jasig.cas.authentication.handler.support.AbstractUsernamePasswordAuthenticationHandler;
import org.jasig.cas.authentication.principal.UsernamePasswordCredentials;
import org.springframework.util.StringUtils;
public class MyUsernamePasswordAuthenticationHandler extends
AbstractUsernamePasswordAuthenticationHandler {
public boolean authenticateUsernamePasswordInternal(
final UsernamePasswordCredentials credentials) {
final String username = credentials.getUsername();
final String password = credentials.getPassword();
// 此处实现你的登陆验证代码
if (StringUtils.hasText(username) && StringUtils.hasText(password) ) {
getLog().debug(
" User [ " + username + " ] was successfully authenticated with ucix. " );
return true ;
}
getLog().debug( " User [ " + username + " ] failed authentication " );
return false ;
}
protected void afterPropertiesSetInternal() throws Exception {
super .afterPropertiesSetInternal();
}
}
然后将这个类配置到 deployerConfigContext.xml 文件里 , 替代 <bean class="org.jasig.cas.authentication.handler.support.SimpleTestUsernamePasswordAuthenticationHandler" />
可能要用到数据库连接之类的配置,具体可参照 spring framework 相关文档
在 client 端取到登陆相关信息及登出系统
1. 取得用用户 ID
以下两种方式都可以
session.getAttribute(CASFilter.CAS_FILTER_USER);
session.getAttribute("edu.yale.its.tp.cas.client.filter.user");
也可以直接取得认证 java 对象
session.getAttribute(CASFilter.CAS_FILTER_RECEIPT);
session.getAttribute("edu.yale.its.tp.cas.client.filter.receipt");
JSP2.0 标准写法
<c:out value="${sessionScope['edu.yale.its.tp.cas.client.filter.user']}"/>
在 jsp 中使用 CAS Tag Library 标签
除实现以上功能完还可以实现登出之类的相关功能,具体参照 cas 官方文档
http://www.ja-sig.org/products/cas/client/jsp/index.html
附录
1 . SSL(Server Socket Layer) 简介
在网络上信息在源 - 宿的传递过程中会经过其它的计算机。一般情况下,中间的计算机不会监听路过的信息。但在使用网上银行或者进行信用卡交易的时候有可能被监视,从而导致个人隐私的泄露。由于 Internet 和 Intranet 体系结构的原因,总有某些人能够读取并替换用户发出的信息。随着网上支付的不断发展,人们对信息安全的要求越来越高。因此 Netscape 公司提出了 SSL 协议,旨在达到在开放网络 (Internet) 上安全保密地传输信息的目的,这种协议在 WEB 上获得了广泛的应用。 之后 IETF(ietf.org) 对 SSL 作了标准化,即 RFC2246 ,并将其称为 TLS ( Transport Layer Security ),从技术上讲, TLS1.0 与 SSL3.0 的差别非常微小。
2 . SSL 工作原理
SSL 协议使用不对称加密技术实现会话双方之间信息的安全传递。可以实现信息传递的保密性、完整性,并且会话双方能鉴别对方身份。不同于常用的 http 协议,我们在与网站建立 SSL 安全连接时使用 https 协议,即采用 https://ip:port/ 的方式来访问。当我们与一个网站建立 https 连接时,我们的浏览器与 Web Server 之间要经过一个握手的过程来完成身份鉴定与密钥交换,从而建立安全连接。具体过程如下:
用户浏览器将其 SSL 版本号、加密设置参数、与 session 有关的数据以及其它一些必要信息发送到服务器。
服务器将其 SSL 版本号、加密设置参数、与 session 有关的数据以及其它一些必要信息发送给浏览器,同时发给浏览器的还有服务器的证书。如果配置服务器的 SSL 需要验证用户身份,还要发出请求要求浏览器提供用户证书。
客户端检查服务器证书,如果检查失败,提示不能建立 SSL 连接。如果成功,那么继续。客户端浏览器为本次会话生成 pre-master secret ,并将其用服务器公钥加密后发送给服务器。如果服务器要求鉴别客户身份,客户端还要再对另外一些数据签名后并将其与客户端证书一起发送给服务器。
如果服务器要求鉴别客户身份,则检查签署客户证书的 CA 是否可信。如果不在信任列表中,结束本次会话。如果检查通过,服务器用自己的私钥解密收到的 pre-master secret ,并用它通过某些算法生成本次会话的 master secret 。
客户端与服务器均使用此 master secret 生成本次会话的会话密钥 ( 对称密钥 ) 。在双方 SSL 握手结束后传递任何消息均使用此会话密钥。这样做的主要原因是对称加密比非对称加密的运算量低一个数量级以上,能够显著提高双方会话时的运算速度。
客户端通知服务器此后发送的消息都使用这个会话密钥进行加密。并通知服务器客户端已经完成本次 SSL 握手。
服务器通知客户端此后发送的消息都使用这个会话密钥进行加密。并通知客户端服务器已经完成本次 SSL 握手。
本次握手过程结束,会话已经建立。双方使用同一个会话密钥分别对发送以及接受的信息进行加、解密。