本篇文章是对JA-SIG CAS(v3.3)的初步调研总结。
应用场景:cas服务部署在192.168.7.115,是一个web应用,访问地址为:https://cas.mycompany.com:8443/cas/。web1应用位于192.168.7.90,访问地址为:http://192.168.7.90:8081/web1 ,web2应用位于192.168.7.90,访问地址为:http://192.168.7.90:8082/web2。web1和web2通过cas服务实现SSO功能。浏览器位于本地localhost。
cas服务器:192.168.7.115 启动8443端口,需配置证书
web1: 192.168.7.90
hosts配置:192.168.7.115 cas.mycompany.com
web.xml里的配置:
<context-param>
< param-name>casServerUrlPrefix</param-name>
< param-value>https://cas.mycompany.com:8443/cas/</param-value>
< /context-param>
< context-param>
< param-name>serverName</param-name>
< param-value>192.168.7.90:8081</param-value>
< /context-param>
< filter>
< filter-name>CAS Authentication Filter</filter-name>
<filter-class>
org.jasig.cas.client.authentication.AuthenticationFilter
</filter-class>
< init-param>
< param-name>casServerLoginUrl</param-name>
< param-value>https://cas.mycompany.com:8443/cas/login</param-value>
< /init-param>
< /filter>
< filter>
< filter-name>CAS Validation Filter</filter-name>
< filter-class>
org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter
</filter-class>
< /filter>
< filter-mapping>
< filter-name>CAS Authentication Filter</filter-name>
< url-pattern>/*</url-pattern>
< /filter-mapping>
< filter-mapping>
< filter-name>CAS Validation Filter</filter-name>
< url-pattern>/*</url-pattern>
< /filter-mapping>
JDK启动参数需加上(验证CAS服务器证书的需要):
-Djavax.net.ssl.trustStore=/home/yz/web1/conf/cas-client-trust-cert.jks
-Djavax.net.ssl.trustStorePassword=casclient!@#
web2: 192.168.7.90
hosts配置:192.168.7.115 cas.mycompany.com
web.xml里的配置:
同web1里web.xml的配置,只是serverName属性的值变成了192.168.7.90:8082
JDK启动参数需加上(验证CAS服务器证书的需要):
-Djavax.net.ssl.trustStore=/home/yz/web2/conf/cas-client-trust-cert.jks
-Djavax.net.ssl.trustStorePassword=casclient!@#
本地:hosts配置: 192.168.7.115 cas.mycompany.com
注:
1 casServerLoginUrl参数的值是cas服务器login接口的值。web应用里的cas client 在认证的时候会redirect到 cas服务器,redirect的url就是casServerLoginUrl,因为是redirect,所以浏览器所在机器要配置cas服务器的域名。
2 casServerUrlPrefix 参数的值是cas服务的访问地址。cas client验证ticket的时候,要访问cas服务的/serviceValidate接口,使用的url就是${ casServerUrlPrefix }serviceValidate,因为客户web应用要验证cas的证书,所以证书cn字段的值必须和casServerUrlPrefix里设置的cas服务器的域名保持一致,并且在web应用的服务器上配置cas服务的访问域名。
2 serverName参数,cas client会用来生成service参数,并且cas服务器在认证通过、ticket验证通过后,会redirect到web应用,redirect的url就是service参数的值。serverName参数可以是IP,也可以是域名,只要保证浏览器能访问到即可。
CAS官方网站:http://www.jasig.org/cas
CAS的主要文档:
http://www.ja-sig.org/wiki/display/CASUM/Home
http://www.jasig.org/cas/cas1-architecture
http://www.jasig.org/cas/cas2-architecture
http://www.jasig.org/cas/protocol/
http://www.ja-sig.org/wiki/display/CASUM/Demo
CAS官方网站上的介绍图
主要原理:用户第一次访问一个CAS服务的客户web应用时(访问URL:http://192.168.7.90:8081/web1),部署在客户web应用的cas AuthenticationFilter,会截获此请求,生成service参数,然后redirect到CAS服务的login接口,url为https://cas:8443/cas/login?service=http%3A%2F%2F192.168.7.90%3A8081%2Fweb1%2F,认证成功后,CAS服务器会生成认证cookie,写入浏览器,同时将cookie缓存到服务器本地,CAS服务器还会根据service参数生成ticket,ticket会保存到服务器,也会加在url后面,然后将请求redirect回客户web应用,url为http://192.168.7.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的交互而已。
1 AuthenticationFilter
if(url中无ticket参数 && session中没有TicketValidationFilter置的assertion对象){
response.sendRedirect(cas服务器的/login接口);//生成service参数,添加到url后面
}
else{
不做处理
}
2 TicketValidationFilter
if(url中有ticket参数){
通过httpclient工具访问cas服务器的/serviceValidate接口验证ticket的有效性,验证失败,显示错误页面,验证成功,则生成标识用户身份的assertion对象,放入session。
}
else{
不做处理
}
注:
1 AuthenticationFilter在前,TicketValidationFilter在后。
2 AuthenticationFilter:
1)url中无ticket参数,且session中没有TicketValidationFilter置的assertion对象,这种情况说明用户还没有认证,AuthenticationFilter会去做认证处理;
2)url中无ticket参数,且session中有TicketValidationFilter置的assertion对象,这种情况说明用户已经认证成功,AuthenticationFilter不做处理;
3)url中有ticket参数,这种情况说明用户已经认证成功,但还需要经TicketValidationFilter去验证ticket,AuthenticationFilter不做处理。
3 TicketValidationFilter:只有客户端调用cas服务器的/login接口,并成功认证,redirect回客户端时,url里才带有ticket参数,在这种情况下,TicketValidationFilter才做处理。
CAS服务端总共对外暴露了7个接口,客户端通过访问这7个接口与服务端交互,这7个接口为:/login、/logout、/validate、/serviceValidate、/proxy、/proxyValidate、/CentralAuthenticationService。/login是认证接口,/logout是退出接口,负责销毁认证cookie,/validate、/serviceValidate是验证ticket用的接口,其中/validate是CAS1.0定义的,/serviceValidate是CAS2.0定义的,其中/serviceValidate返回xml格式的数据,/proxy、/proxyValidate是支持代理认证功能的接口,/CentralAuthenticationService接口用于和远程的web services交互。对于一般web应用的单点登录来讲,/login、/logout、/serviceValidate这3个接口已经可以满足要求 。CAS协议中已经对这些接口做了定义,链接为:http://www.jasig.org/cas/protocol。下面是我对CAS各个接口实现的的详细说明。
/login:
登录流程这部分要考虑到不同种类用户凭证的获取方案,以及客户应用传来的service、gateway、renew参数的不同取值组合,CAS为了实现流程的高度可配置性,采用了Spring Web Flow技术。通过阅读CAS发布包里的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部署环境改变的情况下,灵活地设置cookie path的方式;把cookie的值以及service参数的值放入requestContext的flowscope里。
2:GenerateServiceTicketAction 此Action负责根据service、GTC cookie值生成ServiceTicket对象,ServiceTicket的ID就是返回给客户应用的ticket参数,如果成功创建ServiceTicket,则转发到WarnAction,如果创建失败,且gateway参数为true,则直接redirect到客户应用,否则则需要重新认证。
3:viewLoginForm 这是登录页面,CAS在此收集用户凭证。CAS提供的默认实现是/WEB-INF/view/jsp/simple/ui/casLoginView.jsp。
4:bindAndValidate 对应AuthenticationViaFormAction的doBind方法,该方法负责搜集登录页面上用户录入的凭证信息(用户名、密码等),然后把这些信息封装到CAS内部的Credentials对象中。用户在casLoginView.jsp页面上点击提交后,会触发此方法。
5:submit 对应AuthenticationViaFormAction的submit方法,如果doBind方法成功执行完,则触发submit方法,此方法负责调用centralAuthenticationService的 grantServiceTicket方法,完成认证工作,如果认证成功,则生成TicketGrantingTicket对象,放在缓存里,TicketGrantingTicket的ID就是TGC Cookie的value值。
6:warn CAS提供了一个功能:用户在一个web应用中跳到另一个web应用时,CAS可以跳转到一个提示页面,该页面提示用户要离开一个应用进入另一个应用,可以让用户自己选择。用户在登录页面viewLoginForm上选中了id=”warn”的复选框,才能开启这个功能。
WarnAction就检查用户有没有开启这个功能,如果开启了,则转发到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参数为空,则转发到failureView(/WEB-INF/view/jsp/default/protocol/2.0/casServiceValidationFailure.jsp)
验证ticket。以ticket为参数,去缓存里找ServiceTicketImpl对象,如果能找到,且没有过期,且ServiceTicketImpl对象对应的service属性和service参数对应,则验证通过,验证通过后,请求转发至casServiceSuccessView(cas/WEB-INF/view/jsp/default/protocol/2.0/casServiceValidationSuccess.jsp),验证不通过,则转发到failureView。
CAS认证处理序列图
CAS认证类图