基于CAS+Tomcat配置SSO
一、系统配置
cas server3.1.1
cas client 2.1.1
tomcat5.5
二. Tomcat 配置,启用SSL
a. 在要安装CAS的机器上为Tomcat生成用于SSL通讯的密钥:%JAVA_HOME%/bin/keytool -genkey -alias tomcat -keyalg RSA
这时需要输入密钥密码和其他参数(第一个参数CN必须设置为CAS机器名,本机使用localhost测试),会在系统用户目录中生成.keystore密钥文件。
b. 导出别名为tomcat的密钥文件:%JAVA_HOME%/bin/keytool -export -file /path/server.crt -alias tomcat 这时需要输入上一步设定的密码,结果会在/path/目录生成server.crt信任状。
c. 为客户端的JVM导入密钥::%JAVA_HOME%/bin/keytool -import -keystore $JAVA_HOME/jre/lib/security/cacerts -file /path/server.crt -alias tomcat 注意:输入密码时密码为"changeit",这是默认密码。
d. 修改服务端Tomcat配置文件,启用SSL如下:
<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
maxThreads="150" scheme="https" secure="true"
clientAuth="false" sslProtocol="TLS"
keystoreFile="D:\JAVA\Tomcat5.5\tomcat.keystore"
keystorePass="changeit"
truststoreFile="C:/Program Files/Java/jdk1.5.0_04/jre/lib/security/cacerts" />
三、CAS Server安装
把cas-server-webapp-3.1.1.war copy到tomcat\webapps下重命名为cas;可能需要修改的cas.properties里的cas server name。
https://localhost:8443/cas/longin
默认的cas server的验证是只要用户名和密码一样就可以登陆。可以通过修改deployerConfigContext.xml里的authenticationHandlers为自己的验证机制,如mysql验证用户,如下
<property name="authenticationHandlers">
<list>
<bean class="org.jasig.cas.authentication.handler.support.HttpBasedServiceCredentialsAuthenticationHandler"
p:httpClient-ref="httpClient" />
<bean class="org.jasig.cas.adaptors.jdbc.QueryDatabaseAuthenticationHandler">
<property name="sql" value="select password from user where username=?" />
<property name="dataSource" ref="dataSource" />
</bean>
</list>
</property>
并增加一个mysql dataSource
<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/sso</value></property>
<property name="username"><value>root</value></property>
<property name="password"><value>****</value></property>
</bean>
四、CAS CLIENT配置
以servlet-example为例子
在web.xml增加下面内容
<!-- CAS Filters -->
<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>client:port</param-value><!--client:port就是需要CAS需要拦截的地址和端口,一般就是Client端的IP和port-->
</init-param>
</filter>
<filter-mapping>
<filter-name>CASFilter</filter-name>
<url-pattern>/servlet/*</url-pattern>
</filter-mapping>
其中edu.yale.its.tp.cas.client.filter.serverName的value为需要CAS需要拦截的地址和端口,一般就是Client端的IP/主机名和port
当输入http://localhost:8080/servlet-exampls/servlet/HelloWorld就会要求跳转到cas login窗口要求身份验证。
至此,SSO配置完成;但会出现下面问题
1:假设有A、B两个应用程式,现在在浏览器窗口1输入对A应用程式的请求,会跳转到cas login窗口身份验证;身份验证完成后跳转会A应用程式请求页面
2:在窗口2输入对B应用程式请求,还会需要身份验证
3:在窗口1修改URL为对B应用程式的请求,不需求身份验证
1:假设有A、B两个应用程式,现在在浏览器窗口1输入对A应用程式的请求,会跳转到cas login窗口身份验证;身份验证完成后跳转会A应用程式请求页面
2:在窗口2输入对B应用程式请求,还会需要身份验证
3:在窗口1修改URL为对B应用程式的请求,不需求身份验证
首先为什么在同一个窗口修改URL就可以对B应用程式请求而不需要身份验证
通过查看edu.yale.its.tp.cas.client.filter.CASFilter源码可以发现有这么一段
HttpSession session = ((HttpServletRequest) request).getSession();
// if our attribute's already present and valid, pass through the filter chain
CASReceipt receipt = (CASReceipt) session.getAttribute(CAS_FILTER_RECEIPT);
if (receipt != null && isReceiptAcceptable(receipt)) {
log.trace("CAS_FILTER_RECEIPT attribute was present and acceptable - passing request through filter..");
fc.doFilter(request, response);
return;
}
就是说如果在session里已存在有效的CASRecipt就不再需要身份验证。
那如何解决不同窗口的问题;通过查看CAS SSO原理可以发现,当CAS SERVER验证通过后向client传递ST的时候也同时向USER浏览器里传递一个TGC cookies;初步判定是因为找不到这个cookies导致的问题。具体SSO原理可看“SSO原理”这篇文章
查找cookies:在cas server的cas-servlet.xml里
<bean id="ticketGrantingTicketCookieGenerator" class="org.jasig.cas.web.support.CookieRetrievingCookieGenerator"
p:cookieSecure="true"
p:cookieMaxAge="-1"
p:cookieName="CASTGC"
p:cookiePath="/cas" />
这是传送cookies到user端的bean,其中cookieMaxAge的意思是:Use the given maximum age (in seconds) for cookies created by this generator. Useful special value: -1 ... not persistent, deleted when client shuts down(没持久化)
cooliePath的意思:Use the given path for cookies created by this generator. The cookie is only visible to URLs in this path and below.
摘至:spring api
因此通过修改cookieMaxAge的值控制cookies在User客户端持久化的存活期如;至此就解决了不同窗口请求需要再次验证的问题了。
http://blog.163.com/zhang-_-jie/blog/static/161784378201051213745670/