CAS单点登录系列(5)-简单实施SSO之二

   在本系列文章的第3篇中,讲解了使用CAS实施单点登录的简单过程。

   首先,CAS客户端的配置使用最简单的配置方式,全部配置都放在web.xml文件中。虽然这种配置方式很明了,但存在几个缺点。这种配置方式不仅使web.xml文件显得臃肿,而且相关属性的配置不够灵活,不易于管理。
   其次,采用了keytool生成证书。尽管直接借助于keytool能够获得自签名的X.509证书,但keytool工具不支持签署其他证书。因此,在需要签署其他证书的时候,必须使用其他证书管理工具。
   鉴于以上问题,本节将采用Spring过滤链的配置方式配置CAS Client,将臃肿的配置信息从web.xml中抽取出来,简化web.xml文件。使用OpenSSL管理证书,以弥补keyool的种种不足。

 

1.准备环境
操作系统:32位Window XP
CAS服务器:Cas Server 3.3.3
CAS客户端:Cas Client 3.1.10
Web服务器:Tomcat 6.0.18
数据库:MySQL 5.0
JDK:jdk1.5.0_10

2.基础环境准备
   JDK安装后,复制两份 jdk1.5.0_10,分别命名为jdk_casjdk_client
   同样,复制两份 Tomcat 6.0.18,分别命名为apache-tomcat-casapache-tomcat-client
   配置Tomcat对应的JDK。打开apache-tomcat-cas/bin/catalina.bat 文件,在rem Guess CATALINA_HOME if not defined这行之前添加:set JAVA_HOME=您的安装路径/jdk_cas ,然后保存。同样方式配置apache-tomcat-client ,这样启动apache-tomcat-cas将使用jdk_cas,启动apache-tomcat-client将使用jdk_client。

 

3.生成证书
   OpenSSL工具的安装配置请参考本系列文章的第1篇,接下来将生成根证书和服务器证书。
   创建三个目录C:/openssl、C:/openssl/root、C:/openssl/server。然后在命令行下进入C:/openssl目录。
   (注:整个过程中涉及到密码的地方均使用password )
3.1.创建根证书
//创建私钥
openssl genrsa -out root/root-key.pem 1024

//创建证书请求
openssl req -new -out root/root-req.csr -key root/root-key.pem
//证书信息,按顺序输入,最后一个选项An optional company name直接回车
CN
GuangDong
GuangZhou
JavaEECas
Programmer
root
[email protected]
password

//自签署根证书
openssl x509 -req -in root/root-req.csr -out root/root-cert.pem -signkey root/root-key.pem -days 3650

//将根证书导出成浏览器支持的.p12(PKCS12)格式
openssl pkcs12 -export -clcerts -in root/root-cert.pem -inkey root/root-key.pem -out root/root.p12

3.2.创建服务器证书
//创建私钥
openssl genrsa -out server/server-key.pem 1024

//创建证书请求
openssl req -new -out server/server-req.csr -key server/server-key.pem
//证书信息
CN
GuangDong
GuangZhou
JavaEECas
Programmer
localhost
[email protected]
password

//签署服务器证书
openssl x509 -req -in server/server-req.csr -out server/server-cert.pem -signkey server/server-key.pem -CA root/root-cert.pem -CAkey root/root-key.pem -CAcreateserial -days 3650

//将客户证书导出成浏览器支持的.p12(PKCS12)格式
openssl pkcs12 -export -clcerts -in server/server-cert.pem -inkey server/server-key.pem -out server/server.p12

 

4.启用HTTPS
4.1.在apache-tomcat-cas中启用HTTPS

   打开apache-tomcat-cas/conf/server.xml,在<Connector port=”8080” …/>下面添加以下代码:

Xml代码 复制代码
  1. <Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"  
  2.    maxThreads="150" minSpareThreads="2" maxSpareThreads="10"  
  3.    scheme="https" secure="true"  
  4.    clientAuth="false" sslProtocol="TLS"  
  5.    keystoreFile="C:/openssl/server/server.p12" keystoreType="PKCS12" keystorePass="password"  
  6.    truststoreFile="C:/openssl/root/root.p12" truststoreType="PKCS12" truststorePass="password" />  
<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
   maxThreads="150" minSpareThreads="2" maxSpareThreads="10"
   scheme="https" secure="true"
   clientAuth="false" sslProtocol="TLS"
   keystoreFile="C:/openssl/server/server.p12" keystoreType="PKCS12" keystorePass="password"
   truststoreFile="C:/openssl/root/root.p12" truststoreType="PKCS12" truststorePass="password" />

    其中,keystoreFile和truststoreFile根据实际情况进行修改。

4.2.导入证书
   为了使客户端信任CAS Server,我们必须在客户端导入根证书。操作步骤:
1、打开Internet选项->证书->受信任的根证书颁发机构->导入->下一步,选择root.p12文件

 

2、输入密码


3、 选择证书存储位置

接着“下一步”直到导入成功。

 

4、查看已导入的证书

 

4.3.测试HTTPS
   启动Tomcat,访问https://localhost:8443/,如果能够看到以下界面,地址栏右边出现锁图标,则说明HTTPS启用成功。

 

5.使用RDBMS认证
   我们将采用“小蚂蚁-CAS单点登录系列(4)-使用RDBMS认证 ”一节所使用的cas3作为CAS认证服务器,将其拷贝到apache-tomcat-cas/webapps目录下。同时,别忘了把mysql驱动拷贝到cas3/WEB-INF/lib或apache-tomcat-cas/lib目录下。
   重新启动Tomcat,如果测试使用数据库认证信息登录成功,说明CAS认证服务器配置完成。

6.配置客户端
   创建Web应用client3,添加三个包cas-client-core-3.1.10.jar、commons-logging-1.0.4.jar、spring-2.5.6.jar。
6.1.修改apache-tomcat-client端口
   总共有三个端口需要修改,分别是默认的Server元素的port="8005"、Connector元素port="8080"、Connector元素port="8009",笔者分别修改为9005、9090、9009。
6.2.Web.xml配置

Xml代码 复制代码
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee"    
  3.     xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"    
  4.     xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"    
  5.     id="WebApp_ID" version="2.5">  
  6.        
  7.     <display-name>client3.1.10</display-name>  
  8.      
  9.     <context-param>  
  10.         <param-name>contextConfigLocation</param-name>  
  11.         <param-value>  
  12.             /WEB-INF/classes/spring-appContext.xml   
  13.         </param-value>  
  14.     </context-param>  
  15.        
  16.     <!-- Character Encoding filter -->  
  17.     <filter>  
  18.         <filter-name>encodingFilter</filter-name>  
  19.         <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>  
  20.         <init-param>  
  21.             <param-name>encoding</param-name>  
  22.             <param-value>UTF-8</param-value>  
  23.         </init-param>  
  24.         <init-param>  
  25.             <param-name>forceEncoding</param-name>  
  26.             <param-value>true</param-value>  
  27.         </init-param>  
  28.     </filter>  
  29.        
  30.     <filter>  
  31.         <filter-name>CAS Single Sign Out Filter</filter-name>  
  32.         <filter-class>org.jasig.cas.client.session.SingleSignOutFilter</filter-class>  
  33.     </filter>  
  34.   
  35.     <filter>  
  36.         <filter-name>CAS Authentication Filter</filter-name>  
  37.         <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>  
  38.         <init-param>  
  39.             <param-name>targetBeanName</param-name>  
  40.             <param-value>authenticationFilter</param-value>  
  41.         </init-param>  
  42.     </filter>  
  43.   
  44.     <filter>  
  45.         <filter-name>CAS Validation Filter</filter-name>  
  46.         <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>  
  47.         <init-param>  
  48.             <param-name>targetBeanName</param-name>  
  49.             <param-value>ticketValidationFilter</param-value>  
  50.         </init-param>  
  51.     </filter>  
  52.   
  53.     <filter>  
  54.         <filter-name>CAS HttpServletRequestWrapperFilter</filter-name>  
  55.         <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>  
  56.         <init-param>  
  57.             <param-name>targetBeanName</param-name>  
  58.             <param-value>casHttpServletRequestWrapperFilter</param-value>  
  59.         </init-param>  
  60.     </filter>  
  61.        
  62.     <!-- 使得开发者可以在任意场合使用final Assertion assertion = AssertionHolder.getAssertion() -->  
  63.     <filter>  
  64.         <filter-name>CAS AssertionThreadLocalFilter</filter-name>  
  65.         <filter-class>org.jasig.cas.client.util.AssertionThreadLocalFilter</filter-class>  
  66.     </filter>  
  67.        
  68.     <!-- Character Encoding -->  
  69.     <filter-mapping>  
  70.         <filter-name>encodingFilter</filter-name>  
  71.         <url-pattern>/*</url-pattern>  
  72.     </filter-mapping>  
  73.        
  74.     <filter-mapping>  
  75.         <filter-name>CAS Single Sign Out Filter</filter-name>  
  76.         <url-pattern>/*</url-pattern>  
  77.     </filter-mapping>  
  78.   
  79.     <filter-mapping>  
  80.         <filter-name>CAS Authentication Filter</filter-name>  
  81.         <url-pattern>/secure/*</url-pattern>  
  82.     </filter-mapping>  
  83.   
  84.     <filter-mapping>  
  85.         <filter-name>CAS Validation Filter</filter-name>  
  86.         <url-pattern>/secure/*</url-pattern>  
  87.     </filter-mapping>  
  88.   
  89.     <filter-mapping>  
  90.         <filter-name>CAS HttpServletRequestWrapperFilter</filter-name>  
  91.         <url-pattern>/secure/*</url-pattern>  
  92.     </filter-mapping>  
  93.        
  94.     <filter-mapping>  
  95.         <filter-name>CAS AssertionThreadLocalFilter</filter-name>  
  96.         <url-pattern>/secure/*</url-pattern>  
  97.     </filter-mapping>  
  98.   
  99.     <listener>  
  100.         <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>  
  101.     </listener>  
  102.        
  103.     <listener>  
  104.         <listener-class>org.jasig.cas.client.session.SingleSignOutHttpSessionListener</listener-class>  
  105.     </listener>  
  106.   
  107. </web-app>  
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" 
	xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" 
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" 
	id="WebApp_ID" version="2.5">
	
	<display-name>client3.1.10</display-name>
  
	<context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            /WEB-INF/classes/spring-appContext.xml
        </param-value>
    </context-param>
    
    <!-- Character Encoding filter -->
	<filter>
		<filter-name>encodingFilter</filter-name>
		<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
		<init-param>
			<param-name>encoding</param-name>
			<param-value>UTF-8</param-value>
		</init-param>
		<init-param>
			<param-name>forceEncoding</param-name>
			<param-value>true</param-value>
		</init-param>
	</filter>
    
	<filter>
		<filter-name>CAS Single Sign Out Filter</filter-name>
		<filter-class>org.jasig.cas.client.session.SingleSignOutFilter</filter-class>
	</filter>

    <filter>
        <filter-name>CAS Authentication Filter</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
        <init-param>
            <param-name>targetBeanName</param-name>
            <param-value>authenticationFilter</param-value>
        </init-param>
    </filter>

    <filter>
        <filter-name>CAS Validation Filter</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
        <init-param>
            <param-name>targetBeanName</param-name>
            <param-value>ticketValidationFilter</param-value>
        </init-param>
    </filter>

    <filter>
        <filter-name>CAS HttpServletRequestWrapperFilter</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
        <init-param>
            <param-name>targetBeanName</param-name>
            <param-value>casHttpServletRequestWrapperFilter</param-value>
        </init-param>
    </filter>
    
    <!-- 使得开发者可以在任意场合使用final Assertion assertion = AssertionHolder.getAssertion() -->
    <filter>
        <filter-name>CAS AssertionThreadLocalFilter</filter-name>
        <filter-class>org.jasig.cas.client.util.AssertionThreadLocalFilter</filter-class>
    </filter>
    
    <!-- Character Encoding -->
	<filter-mapping>
		<filter-name>encodingFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
    
	<filter-mapping>
		<filter-name>CAS Single Sign Out Filter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>

    <filter-mapping>
        <filter-name>CAS Authentication Filter</filter-name>
        <url-pattern>/secure/*</url-pattern>
    </filter-mapping>

    <filter-mapping>
        <filter-name>CAS Validation Filter</filter-name>
        <url-pattern>/secure/*</url-pattern>
    </filter-mapping>

    <filter-mapping>
        <filter-name>CAS HttpServletRequestWrapperFilter</filter-name>
        <url-pattern>/secure/*</url-pattern>
    </filter-mapping>
    
    <filter-mapping>
        <filter-name>CAS AssertionThreadLocalFilter</filter-name>
        <url-pattern>/secure/*</url-pattern>
    </filter-mapping>

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    
	<listener>
		<listener-class>org.jasig.cas.client.session.SingleSignOutHttpSessionListener</listener-class>
	</listener>

</web-app>
 

6.3.添加资源文件
   在类路径下新建文件cas-client.properties,内容如下:
   cas.server.url=https://localhost:8443/cas3
   cas.client.serverName=localhost:9090

   第一行指定CAS服务器地址 ,第二行指定客户端服务名称,格式为:主机名:端口号
6.4.添加Spring配置文件
   在类路径下新建文件spring-appContext.xml,内容如下:

Xml代码 复制代码
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <beans xmlns="http://www.springframework.org/schema/beans"  
  3.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  4.        xmlns:p="http://www.springframework.org/schema/p"  
  5.        xsi:schemaLocation="http://www.springframework.org/schema/beans    
  6.             http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">  
  7.   
  8.     <!-- 定义环境变量 -->  
  9.     <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">  
  10.         <property name="ignoreResourceNotFound" value="true" />  
  11.         <property name="location" value="classpath:cas-client.properties"/>  
  12.     </bean>  
  13.   
  14.     <!-- 认证过滤器配置 -->  
  15.     <bean  
  16.         name="authenticationFilter"  
  17.         class="org.jasig.cas.client.authentication.AuthenticationFilter"  
  18.         p:casServerLoginUrl="${cas.server.url}/login"  
  19.         p:renew="false"  
  20.         p:gateway="false"  
  21.         p:serverName="${cas.client.serverName}" />  
  22.        
  23.         <!-- 验证过滤器配置 -->  
  24.     <bean  
  25.         name="ticketValidationFilter"  
  26.         class="org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter"  
  27.         p:serverName="${cas.client.serverName}">  
  28.         <property name="ticketValidator">  
  29.             <bean class="org.jasig.cas.client.validation.Cas20ServiceTicketValidator">  
  30.                 <constructor-arg index="0" value="${cas.server.url}" />  
  31.             </bean>  
  32.         </property>  
  33.     </bean>  
  34.        
  35.     <!--    
  36.     <bean  
  37.         name="ticketValidationFilter"  
  38.         class="org.jasig.cas.client.validation.Cas10TicketValidationFilter"  
  39.         p:serverName="${cas.client.serverName}">  
  40.         <property name="ticketValidator">  
  41.             <bean class="org.jasig.cas.client.validation.Cas10TicketValidator">  
  42.                 <constructor-arg index="0" value="${cas.server.url}" />  
  43.             </bean>  
  44.         </property>  
  45.     </bean>  
  46.      -->  
  47.   
  48.     <bean id="casHttpServletRequestWrapperFilter"  
  49.             class="org.jasig.cas.client.util.HttpServletRequestWrapperFilter"/>  
  50. </beans>  
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
       		http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">

	<!-- 定义环境变量 -->
	<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
		<property name="ignoreResourceNotFound" value="true" />
		<property name="location" value="classpath:cas-client.properties"/>
	</bean>

    <!-- 认证过滤器配置 -->
    <bean
		name="authenticationFilter"
		class="org.jasig.cas.client.authentication.AuthenticationFilter"
		p:casServerLoginUrl="${cas.server.url}/login"
		p:renew="false"
		p:gateway="false"
		p:serverName="${cas.client.serverName}" />
	
        <!-- 验证过滤器配置 -->
	<bean
		name="ticketValidationFilter"
		class="org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter"
		p:serverName="${cas.client.serverName}">
		<property name="ticketValidator">
			<bean class="org.jasig.cas.client.validation.Cas20ServiceTicketValidator">
				<constructor-arg index="0" value="${cas.server.url}" />
			</bean>
		</property>
	</bean>
	
	<!-- 
	<bean
		name="ticketValidationFilter"
		class="org.jasig.cas.client.validation.Cas10TicketValidationFilter"
		p:serverName="${cas.client.serverName}">
		<property name="ticketValidator">
			<bean class="org.jasig.cas.client.validation.Cas10TicketValidator">
				<constructor-arg index="0" value="${cas.server.url}" />
			</bean>
		</property>
	</bean>
	 -->

    <bean id="casHttpServletRequestWrapperFilter"
            class="org.jasig.cas.client.util.HttpServletRequestWrapperFilter"/>
</beans>
 

6.5.导入根证书
   由于CAS Server启用了HTTPS,要使Web客户端信任其身份,必须为jdk_client 导入根证书。
keytool -import -v -trustcacerts -storepass changeit -alias root -file root/root-cert.pem -keystore E:/DevelopTools/JDK/jdk_client/jre/lib/security/cacerts

 

7.综合测试
7.1.启动apache-tomcat-cas
7.2.启动apache-tomcat-client
7.3.访问client3

   访问http://localhost:9090/client3/secure/securedpage.jsp页面,将被引导到CAS登录页面。输入凭证信息,认证通过后将出现以下页面:

 

   访问http://localhost:9090/client3/secure/debug.jsp页面,可以看到通过三种不同的方式获取用户名。

 

   在http://localhost:9090/client3/secure/securedpage.jsp页面中,单击“退出”链接将单点退出系统。

 

8.可能遇到的问题
8.1报错
'unable to find valid certification path to requested target'
原因
Web应用服务器端没有导入根证书
解决方法
在jdk_client导入根证书。

 

 

至此,本节内容结束,有遗漏或疏忽的地方请大家指出,谢谢!

你可能感兴趣的:(spring,tomcat,bean,Web,SSO)