1、使用Yale CAS 实现SSO的方法目录一、Yale CAS简介2二、CAS 原理和协议2三、准备工作4四、部署CAS Server5步骤1.配置CAS Server应用服务器的Https 协议5生成服务器证书5配置Tomcat的https8步骤2.部署CAS Server8扩展认证接口8JDBC 认证方法11五、部署CAS Client15步骤1.与 CAS Server 建立信任关系15步骤2.配置 CAS Filter15一、Yale CAS简介什么是单点登陆单点登录(Single Sign On),简称为 SSO,是目前比较流行的企业业务整合的解决方案之一。SSO的定义是在多个应用系
2、统中,用户只需要登录一次就可以访问所有相互信任的应用系统。它包括可以将这次主要的登录映射到其他应用中用于同一个用户的登录的机制。单点登陆的技术实现机制当用户第一次访问应用系统1的时候,因为还没有登录,会被引导到认证系统中进行登录;根据用户提供的登录信息,认证系统进行身份效验,如果通过效验,应该返回给用户一个认证的凭据ticket;用户再访问别的应用的时候就会将这个ticket带上,作为自己认证的凭据,应用系统接受到请求之后会把ticket送到认证系统进行效验,检查ticket的合法性。如果通过效验,用户就可以在不用再次登录的情况下访问应用系统2和应用系统3了。要实现SSO,需要以下主要的功能:
3、1、所有应用系统共享一个身份认证系统。统一的认证系统是SSO的前提之一。认证系统的主要功能是将用户的登录信息和用户信息库相比较,对用户进行登录认证;认证成功后,认证系统应该生成统一的认证标志(ticket),返还给用户。另外,认证系统还应该对ticket进行效验,判断其有效性。 2、所有应用系统能够识别和提取ticket信息要实现SSO的功能,让用户只登录一次,就必须让应用系统能够识别已经登录过的用户。应用系统应该能对ticket进行识别和提取,通过与认证系统的通讯,能自动判断当前用户是否登录过,从而完成单点登录的功能。另外:1、单一的用户信息数据库并不是必须的,有许多系统不能将所有的用户信息
4、都集中存储,应该允许用户信息放置在不同的存储中,如下图所示。事实上,只要统一认证系统,统一ticket的产生和效验,无论用户信息存储在什么地方,都能实现单点登录。2、统一的认证系统并不是说只有单个的认证服务器认证服务器之间要通过标准的通讯协议,互相交换认证信息,就能完成更高级别的单点登录。如:当用户在访问应用系统1时,由第一个认证服务器进行认证后,得到由此服务器产生的ticket。当他访问应用系统2的时候,认证服务器2能够识别此ticket是由第一个服务器产生的,通过认证服务器之间标准的通讯协议(例如SAML)来交换认证信息,仍然能够完成SSO的功能。WEB-SSO的实现用户在访问页面1的时候
5、进行了登录,但是客户端的每个请求都是单独的连接,当客户再次访问页面2的时候,如何才能告诉Web服务器,客户刚才已经登录过了呢?浏览器和服务器之间有约定:通过使用cookie技术来维护应用的状态。Cookie是可以被Web服务器设置的字符串,并且可以保存在浏览器中。当浏览器访问了页面1时,web服务器设置了一个cookie,并将这个cookie和页面1一起返回给浏览器,浏览器接到cookie之后,就会保存起来,在它访问页面2的时候会把这个cookie也带上,Web服务器接到请求时也能读出cookie的值,根据cookie值的内容就可以判断和恢复一些用户的信息状态。Web-SSO完全可以利用Coo
6、kie结束来完成用户登录信息的保存,将浏览器中的Cookie和上文中的Ticket结合起来,完成SSO的功能。为了完成一个简单的SSO的功能,需要两个部分的合作:1、统一的身份认证服务。2、修改Web应用,使得每个应用都通过这个统一的认证服务来进行身份效验。CAS 是 Yale (耶鲁)大学发起的一个开源项目,旨在为 Web 应用系统提供一种可靠的单点登录方法,CAS 在 2004 年 12 月正式成为 JA-SIG 的一个项目。CAS 具有以下特点: 开源的企业级单点登录解决方案。 CAS Server 为需要独立部署的 Web 应用。 CAS Client 支持非常多的客户端(这里指单点登
7、录系统中的各个 Web 应用),包括 Java, .Net, PHP, Perl, Apache, uPortal, Ruby 等。 二、CAS 原理和协议从结构上看,CAS 包含两个部分: CAS Server 和 CAS Client。CAS Server 需要独立部署,主要负责对用户的认证工作;CAS Client 负责处理对客户端受保护资源的访问请求,需要登录时,重定向到 CAS Server。图1 是 CAS 最基本的协议过程:图 1. CAS 基础协议CAS Client 与受保护的客户端应用部署在一起,以 Filter 方式保护受保护的资源。对于访问受保护资源的每个 Web 请求
8、CAS Client 会分析该请求的 Http 请求中是否包含 Service Ticket,如果没有,则说明当前用户尚未登录,于是将请求重定向到指定好的 CAS Server 登录地址,并传递 Service (也就是要访问的目的资源地址),以便登录成功过后转回该地址。用户在第 3 步中输入认证信息,如果登录成功,CAS Server 随机产生一个相当长度、唯一、不可伪造的 Service Ticket,并缓存以待将来验证,之后系统自动重定向到 Service 所在地址,并为客户端浏览器设置一个 Ticket Granted Cookie(TGC),CAS Client 在拿到 Servi
9、ce 和新产生的 Ticket 过后,在第 5,6 步中与 CAS Server 进行身份合适,以确保 Service Ticket 的合法性。在该协议中,所有与 CAS 的交互均采用 SSL 协议,确保,ST 和 TGC 的安全性。协议工作过程中会有 2 次重定向的过程,但是 CAS Client 与 CAS Server 之间进行 Ticket 验证的过程对于用户是透明的。三、准备工作1apache-tomcat-5.5.26下载地址:2到 CAS 官方网站下载 CAS Server 和 Client,地址分别为:http:/www.ja-sig.org/downloads/cas/cas
10、server-3.1.1-release.zip http:/www.ja-sig.org/downloads/cas-clients/cas-client-java-2.1.1.zip 备注:CAS Server端,以及多个CAS Client端都可以分别部署到独立的应用服务器中,为了测试跨域的SSO功能,本测试采用的方式是:Tomcat1: CAS Server (机器名 yanjz)Tomcat2: CAS ClientA (机器名 domainA)Tomcat3: CAS ClientB (机器名 domainB)Tomcat1、Tomcat2、Tomcat3分别为apache-to
11、mcat-5.5.26.zip的压缩拷贝。CAS ServerdomainA应用服务器1domainB应用服务器2的dWeb BrowserrTomcat2-App1 filterTomcat3 - App2 filter重定向到Server的LoginService Ticket返回Service Ticket输入用户名,密码(验证)Ticket Granted Cookie(TGC)Service Ticket四、部署CAS ServerCAS Server 是一套基于 Java 实现的服务,该服务以一个 Java Web Application 单独部署在与 servlet2.3 兼容的
12、 Web 服务器上,另外,由于 Client 与 CAS Server 之间的交互采用 Https 协议,因此部署 CAS Server 的服务器还需要支持 SSL 协议。当 SSL 配置成功过后,像普通 Web 应用一样将 CAS Server 部署在服务器上就能正常运行了,不过,在真正使用之前,还需要扩展验证用户的接口。在 Tomcat 上部署一个完整的 CAS Server 主要按照以下几个步骤:步骤1. 配置CAS Server应用服务器的Https 协议如果希望 Tomcat 支持 Https,主要的工作是配置 SSL 协议,其配置过程和配置方法可以参考 Tomcat 的相关文档。不
13、过在生成证书的过程中,会有需要用到主机名的地方,CAS 建议不要使用 IP 地址,而要使用机器名或域名。生成服务器证书/* 第一步设置JAVA_HOME 启动cmd命令行窗口,输入如下命令设置JAVA_HOME */ setJAVA_HOME=C:/jdk1.5.0_15 /* 第二步(不是必须)删除已经存在的服务器端证书 如果jre目录下已经存在服务器证书需呀删除证书 输入如下命令删除指定别名yanjzKey的证书 */ %JAVA_HOME%/bin/keytool-delete-aliasyanjzKey-keypasschangeit-keystore%JAVA_HOME%/JRE/L
14、IB/SECURITY/CACERTS /* 第三步生成服务端证书 输入如下命令在当前目录中生成服务端证书tomcat.jks 注意: 1.密码随意输入,比如:111111 2.要求输入姓名时,需要输入作为CASServer的机器的域名,没有域的话输入机器名 3. -validity 3650 有效期10年*/ %JAVA_HOME%/bin/keytool-genkey-aliascasserver-keyalgRSA-keystoretomcat.jks -validity 3650%JAVA_HOME%/bin/keytool-genkey-aliascasserver-keyalgRS
15、A-keystoredw_identity.jks -validity 3650/* 第四步导出证书 输入如下命令在当前目录中导出证书cas.cer */ %JAVA_HOME%/bin/keytool-export-filecas.cer-aliascasserver-keystoretomcat.jks /* 第五步将证书导入到jre/lib/security的cacerts中 注意: 1.此时输入的密码是changeit,而不是之前的111111 */ %JAVA_HOME%/bin/keytool-import-keystore%JAVA_HOME%/JRE/LIB/SECURITY/
16、CACERTS-filecas.cer-aliasyanjzKey %JAVA_HOME%/bin/keytool-import-filecas.cer-keypasschangeit-aliasyanjzKey /* 第五步查询证书导入到jre/lib/security的cacerts中证书确认 */ %JAVA_HOME%/bin/keytool-list-v-keystore%JAVA_HOME%/JRE/LIB/SECURITY/CACERTS配置Tomcat的https修改Tomcat1的conf/server.xml文件中 !- - 说明:以上配置中的keystoreFile为已经
17、生成的服务器证书的地址keystorePass为自定义的服务器证书的密码配置weblogic的https 第一个passphrase密码是111111第二个passphrase密码 是changeitpassphrase密码 是changeit步骤2. 部署CAS ServerCAS Server 是一个 Web 应用包,将前面下载的 cas-server-3.1.1-release.zip 解开,把其中的 cas-server-webapp-3.1.1.war 拷贝到 tomcat的 webapps 目录,并更名为 casServer.war。由于前面已配置好 tomcat 的 https
18、协议,可以重新启动 tomcat,然后访问:https:/localhost:8443/casServer,如果能出现正常的 CAS 登录页面,则说明 CAS Server 已经部署成功。虽然 CAS Server 已经部署成功,但这只是一个缺省的实现,在实际使用的时候,还需要根据实际概况做扩展和定制,最主要的是扩展认证 (Authentication) 接口和 CAS Server 的界面。扩展认证接口CAS Server 负责完成对用户的认证工作,它会处理登录时的用户凭证 (Credentials) 信息,用户名/密码对是最常见的凭证信息。CAS Server 可能需要到数据库检索一条用户
19、帐号信息,也可能在 XML 文件中检索用户名/密码,还可能通过 LDAP Server 获取等,在这种情况下,CAS 提供了一种灵活但统一的接口和实现分离的方式,实际使用中 CAS 采用哪种方式认证是与 CAS 的基本协议分离开的,用户可以根据认证的接口去定制和扩展。扩展 AuthenticationHandler CAS 提供扩展认证的核心是 AuthenticationHandler 接口,该接口定义如清单 1 下:清单 1. AuthenticationHandler定义 publicinterfaceAuthenticationHandler /* *Methodtodetermine
20、ifthecredentialssuppliedarevalid. *paramcredentialsThecredentialstovalidate. *returntrueifvalid,returnfalseotherwise. *throwsAuthenticationExceptionAnAuthenticationExceptioncancontain *detailsaboutwhyaparticularauthenticationrequestfailed. */ booleanauthenticate(Credentialscredentials)throwsAuthenti
21、cationException; /* *Methodtocheckifthehandlerknowshowtohandlethecredentials *provided.ItmaybeasimplecheckoftheCredentialsclassorsomething *morecomplicatedsuchasscanningtheinformationcontainedinthe *Credentialsobject. *paramcredentialsThecredentialstocheck. *returntrueifthehandlersupportstheCredenti
22、als,falseothewrise. */ booleansupports(Credentialscredentials); 该接口定义了 2 个需要实现的方法,supports ()方法用于检查所给的包含认证信息的Credentials 是否受当前 AuthenticationHandler 支持;而 authenticate() 方法则担当验证认证信息的任务,这也是需要扩展的主要方法,根据情况与存储合法认证信息的介质进行交互,返回 boolean 类型的值,true 表示验证通过,false 表示验证失败。CAS3中还提供了对AuthenticationHandler 接口的一些抽象实现
23、比如,可能需要在执行authenticate() 方法前后执行某些其他操作,那么可以让自己的认证类扩展自清单 2 中的抽象类:清单 2. AbstractPreAndPostProcessingAuthenticationHandler定义 publicabstractclassAbstractPreAndPostProcessingAuthenticationHandler implementsAuthenticateHandler protectedLoglog=LogFactory.getLog(this.getClass(); protectedbooleanpreAuthentic
24、ate(finalCredentialscredentials) returntrue; protectedbooleanpostAuthenticate(finalCredentialscredentials, finalbooleanauthenticated) returnauthenticated; publicfinalbooleanauthenticate(finalCredentialscredentials) throwsAuthenticationException if(!preAuthenticate(credentials) returnfalse; finalbool
25、eanauthenticated=doAuthentication(credentials); returnpostAuthenticate(credentials,authenticated); protectedabstractbooleandoAuthentication(finalCredentialscredentials) throwsAuthenticationException; AbstractPreAndPostProcessingAuthenticationHandler 类新定义了 preAuthenticate() 方法和 postAuthenticate() 方法,
26、而实际的认证工作交由 doAuthentication() 方法来执行。因此,如果需要在认证前后执行一些额外的操作,可以分别扩展 preAuthenticate()和 ppstAuthenticate() 方法,而 doAuthentication() 取代 authenticate() 成为了子类必须要实现的方法。由于实际运用中,最常用的是用户名和密码方式的认证,CAS3 提供了针对该方式的实现,如清单 3 所示:清单 3. AbstractUsernamePasswordAuthenticationHandler 定义 publicabstractclassAbstractUsername
27、PasswordAuthenticationHandlerextends AbstractPreAndPostProcessingAuthenticationHandler . protectedfinalbooleandoAuthentication(finalCredentialscredentials) throwsAuthenticationException returnauthenticateUsernamePasswordInternal(UsernamePasswordCredentials)credentials); protectedabstractbooleanauthe
28、nticateUsernamePasswordInternal( finalUsernamePasswordCredentialscredentials)throwsAuthenticationException; protectedfinalPasswordEncodergetPasswordEncoder() returnthis.passwordEncoder; publicfinalvoidsetPasswordEncoder(finalPasswordEncoderpasswordEncoder) this.passwordEncoder=passwordEncoder; . 基于用
29、户名密码的认证方式可直接扩展自 AbstractUsernamePasswordAuthenticationHandler,验证用户名密码的具体操作通过实现 authenticateUsernamePasswordInternal() 方法达到,另外,通常情况下密码会是加密过的,setPasswordEncoder() 方法就是用于指定适当的加密器。从以上清单中可以看到,doAuthentication() 方法的参数是 Credentials 类型,这是包含用户认证信息的一个接口,对于用户名密码类型的认证信息,可以直接使用 UsernamePasswordCredentials,如果需要扩展
30、其他类型的认证信息,需要实现Credentials接口,并且实现相应的 CredentialsToPrincipalResolver 接口,其具体方法可以借鉴 UsernamePasswordCredentials 和 UsernamePasswordCredentialsToPrincipalResolver。JDBC 认证方法 用户的认证信息通常保存在数据库中,因此本文就选用这种情况来介绍。将前面下载的 cas-server-3.1.1-release.zip 包解开后,在 modules 目录下可以找到包 cas-server-support-jdbc-3.1.1.jar,其提供了通过
31、JDBC 连接数据库进行验证的缺省实现,基于该包的支持,我们只需要做一些配置工作即可实现 JDBC 认证。JDBC 认证方法支持多种数据库,DB2, Oracle, MySql, Microsoft SQL Server 等均可,这里以 DB2 作为例子介绍。并且假设Oracle数据库名: orcl,数据库登录用户名: wuxi,数据库登录密码: wuxi,用户信息表为: UIM_USER,该表包含用户名和密码的两个数据项分别为 USERID 和 PWD。1). 配置 DataStore 打开文件 %CATALINA_HOME%/webapps/casServer/WEB-INF/deploy
32、erConfigContext.xml,添加一个新的 bean 标签,对于 Oracle,内容如清单 4 所示:清单 4. 配置 DataStore oracle.jdbc.driver.OracleDriver jdbc:oracle:thin:192.168.0.175:1521:orcl wuxi wuxi 其中 id 属性为该 DataStore 的标识,在后面配置 AuthenticationHandler 会被引用,另外,需要提供 DataStore 所必需的数据库驱动程序、连接地址、数据库登录用户名以及登录密码。2). 配置 AuthenticationHandler 在 cas
33、server-support-jdbc-3.1.1.jar 包中,提供了 3 个基于 JDBC 的 AuthenticationHandler,分别为 BindModeSearchDatabaseAuthenticationHandler, QueryDatabaseAuthenticationHandler, SearchModeSearchDatabaseAuthenticationHandler。其中 BindModeSearchDatabaseAuthenticationHandler 是用所给的用户名和密码去建立数据库连接,根据连接建立是否成功来判断验证成功与否;QueryData
34、baseAuthenticationHandler 通过配置一个 SQL 语句查出密码,与所给密码匹配;SearchModeSearchDatabaseAuthenticationHandler 通过配置存放用户验证信息的表、用户名字段和密码字段,构造查询语句来验证。使用哪个 AuthenticationHandler,需要在 deployerConfigContext.xml 中设置,默认情况下,CAS 使用一个简单的 username=password 的 AuthenticationHandler,在文件中可以找到如下一行:,我们可以将其注释掉,换成我们希望的一个 Authenticat
35、ionHandler,比如,使用QueryDatabaseAuthenticationHandler 或 SearchModeSearchDatabaseAuthenticationHandler 可以分别选取清单 5 或清单 6 的配置。清单 5. 使用 QueryDatabaseAuthenticationHandler 清单 6. 使用 SearchModeSearchDatabaseAuthenticationHandler UIM_USER USERID PWD 另外,由于存放在数据库中的密码通常是加密过的,所以 AuthenticationHandler 在匹配时需要知道使用的加密
36、方法,在 deployerConfigContext.xml 文件中我们可以为具体的 AuthenticationHandler 类配置一个 property,指定加密器类,比如对于 QueryDatabaseAuthenticationHandler,可以修改如清单7所示:清单 7. 添加 passwordEncoder 其中 myPasswordEncoder 是对清单 8 中设置的实际加密器类的引用:清单 8. 指定具体加密器类 这里 MyPasswordEncoder 是根据实际情况自己定义的加密器,实现 PasswordEncoder 接口及其 encode() 方法。3). 部署依赖包 在以上配置完成以后,需要拷贝几个依赖的包到 casServer应用下,包括: 将 cas-server-support-jdbc-3.1.1.jar 拷贝到 %CATALINA_HOME%/webapps/casServer/ WEB-INF/lib 目录。 数据库驱动ojdbc14.jar拷贝到 %CATALINA_HOME%/webapps/casServer/WEB-INF/lib 目录。对于其他数据库,同样将相应数据库驱动程序拷