开源SSO-CAS实现单点登录

软件及工具:

     1. jdk:  1.8.0_131

     2. tomcat 8.5.34

     3. cas server : case-server-4.0.0-release.zip  点击下载 

     4. cas client: cas-client-3.3.3-release.zip  点击下载

     5. window7 系统

  jdk和 tomcat的安装此处省略...

 steps:

  1.  生成证书

     1.1生成一个别名为 castest的证书

D:\Program Files\Java\jdk1.8.0_131\bin>keytool -genkey -alias castest -keyalg RSA -keystore F:\study\sso\cas\castest.crt
输入密钥库口令:
再次输入新口令:
您的名字与姓氏是什么?
  [Unknown]:  sso.castest.com   => cas服务器跳转域名
您的组织单位名称是什么?
  [Unknown]:  lt
您的组织名称是什么?
  [Unknown]:  lt
您所在的城市或区域名称是什么?
  [Unknown]:  sz
您所在的省/市/自治区名称是什么?
  [Unknown]:  js
该单位的双字母国家/地区代码是什么?
  [Unknown]:  cn
CN=sso.castest.com, OU=lt, O=lt, L=sz, ST=js, C=cn是否正确?
  [否]:  y

输入 <castest> 的密钥口令
        (如果和密钥库口令相同, 按回车):

此处 需要记住密码,后面导入证书  cas 服务器端会使用

   1.2 导出证书

      

D:\Program Files\Java\jdk1.8.0_131\bin>keytool -export -file F:/study/sso/cas/cas.crt -alias castest -keystore F:/study/sso/cas/castest.crt
输入密钥库口令:
存储在文件 <F:/study/sso/cas/cas.crt> 中的证书
1.3  证书导入JRE

   

D:\Program Files\Java\jdk1.8.0_131\bin>keytool -import -keystore "D:\Program Files\Java\jdk1.8.0_131\jre\lib\security\cacerts" -file F:/study/sso/cas/cas.crt -a
lias castest
输入密钥库口令:  密码changeit (jvm默认密匙库密码)
所有者: CN=sso.castest.com, OU=lt, O=lt, L=sz, ST=js, C=cn
发布者: CN=sso.castest.com, OU=lt, O=lt, L=sz, ST=js, C=cn
序列号: f71f9d7
有效期开始日期: Tue May 09 17:27:11 CST 2017, 截止日期: Mon Aug 07 17:27:11 CST
2017
证书指纹:
         MD5: 64:7D:08:00:25:F9:80:9D:DB:67:17:36:4C:5E:01:7E
         SHA1: CF:0F:8F:95:E7:A3:B5:B2:D3:E5:30:A0:EC:58:C9:DD:BC:F4:A6:66
         SHA256: 2A:4E:04:95:5D:68:A1:2A:32:9B:21:0E:B7:CE:14:04:DF:CA:18:E1:62:
83:D7:AF:58:42:B8:0C:69:0B:CC:AF
         签名算法名称: SHA256withRSA
         版本: 3

扩展:

#1: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: 26 BA A1 F6 FD C7 FB D3   5D DC 0B 23 F0 2A 8F 99  &.......]..#.*..
0010: 91 4C CA 8C                                        .L..
]
]

是否信任此证书? [否]:  y
证书已添加到密钥库中

其中:D:\Program Files\Java\jdk1.8.0_131\jre\lib\security\cacerts为客户端JVM的密钥库位置 

如果提示: 
keytool error: java.io.IOException: Keystore was tampered with, or password was incorrect 
那么输入密码:changeit (jvm默认密匙库密码)


2. 配置服务端

       1 、从http://developer.jasig.org/cas/上下载cas服务器端cas-server-4.0.0-release.zip,在modules目录下找到cas-server-webapp-4.0.0.war,将其复制到%TOMCAT_HOME%\webapps下,并将名称改为cas.war

  2、修改%TOMCAT_HOME%\conf\server.xml文件

 
<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol" SSLEnabled="true"
               maxThreads="150" scheme="https" secure="true"
			    keystoreFile="F:/study/sso/cas/castest.crt"
				
				keystorePass="123456"
               clientAuth="false" sslProtocol="TLS" />

我这里用的 protocol 是 org.apache.coyote.http11.Http11NioProtocol

现在可以启动服务器了


3. 测试

  https://localhost:8443

  

如果此时可以正常访问,说明证书安装成功   


打开  cas server  https://localhost:8443/cas

    

输入账号和密码  casuser/Mellon

  

    登录成功 这样 CAS服务器配置成功了


4. 配置客户端

  1.  新建2个JAVA WEB 项目  CasClient01 和 CasClient02

   2. 加压 cas-client-3.3.3 release.zip,在modules目录下找到cas-client-core-3.1.12.jar、commons-collections-3.2.jar、commons-logging-1.1.jar复制到项目WEB-INF/lib下

  3. 添加映射域名,在C:\Windows\System32\drivers\etc\hosts文件中添加
    127.0.0.1 sso.castest.com
  4. 添加 web.xml文件 被添加如下配置

  

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

        <display-name>cas-demo</display-name>
        
        <!-- ======================== 单点登录开始 ======================== -->
        <!-- 用于单点退出,该过滤器用于实现单点登出功能,可选配置-->
        <listener>
                <listener-class>org.jasig.cas.client.session.SingleSignOutHttpSessionListener</listener-class>
        </listener>

        <!-- 该过滤器用于实现单点登出功能,可选配置 。 注意 登出的时候 配置客户端服务地址一定要用 IP 或者域名 否则 不能清除SESSION 
(SSO Server发送logoutRequest 给SSO Client) -->
        <filter>
                <filter-name>CAS Single Sign Out Filter</filter-name>
                <filter-class>org.jasig.cas.client.session.SingleSignOutFilter</filter-class>
        </filter>
        <filter-mapping>
                <filter-name>CAS Single Sign Out Filter</filter-name>
                <url-pattern>/CasClient/*</url-pattern>
        </filter-mapping>

        <!-- 该过滤器负责用户的认证工作,必须启用它 -->
        <filter>
                <filter-name>CASFilter</filter-name>
                <filter-class>org.jasig.cas.client.authentication.AuthenticationFilter</filter-class>
                <init-param>
                        <param-name>casServerLoginUrl</param-name>
                        <param-value>https://sso.castest.com:8443/cas/login</param-value>
                        <!--这里的server是服务端的IP 正式发布可以改成 443 -->
                </init-param>
                <init-param>
                        <param-name>serverName</param-name>
                        <param-value>http://localhost:8080</param-value>
                </init-param>
        </filter>
        <filter-mapping>
                <filter-name>CASFilter</filter-name>
                <url-pattern>/*</url-pattern>
        </filter-mapping>

        <!-- 该过滤器负责对Ticket的校验工作,必须启用它 -->
        <filter>
                <filter-name>CAS Validation Filter</filter-name>
                <filter-class>
                        org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter</filter-class>
                <init-param>
                        <param-name>casServerUrlPrefix</param-name>
                        <param-value>https://sso.castest.com:8443/cas/</param-value><!-- 此处必须为登录url/cas/,带有任何其它路径都会报错,如“https://sso.castest.com:8443/cas/login”,这样也会报错。 -->
                </init-param>
                <init-param>
                        <param-name>serverName</param-name>
                        <param-value>http://localhost:8080</param-value><!-- 服务器真实地址 -->
                </init-param>
        </filter>
        <filter-mapping>
                <filter-name>CAS Validation Filter</filter-name>
                <url-pattern>/*</url-pattern>
        </filter-mapping>

        <!--
                该过滤器负责实现HttpServletRequest请求的包裹,
                比如允许开发者通过HttpServletRequest的getRemoteUser()方法获得SSO登录用户的登录名,可选配置。
        -->
        <filter>
                <filter-name>CAS HttpServletRequest Wrapper Filter</filter-name>
                <filter-class>
                        org.jasig.cas.client.util.HttpServletRequestWrapperFilter</filter-class>
        </filter>
        <filter-mapping>
                <filter-name>CAS HttpServletRequest Wrapper Filter</filter-name>
                <url-pattern>/*</url-pattern>
        </filter-mapping>

        <!--
                该过滤器使得开发者可以通过org.jasig.cas.client.util.AssertionHolder来获取用户的登录名。
                比如AssertionHolder.getAssertion().getPrincipal().getName()。
        -->
        <filter>
                <filter-name>CAS Assertion Thread Local Filter</filter-name>
                <filter-class>org.jasig.cas.client.util.AssertionThreadLocalFilter</filter-class>
        </filter>
        <filter-mapping>
                <filter-name>CAS Assertion Thread Local Filter</filter-name>
                <url-pattern>/*</url-pattern>
        </filter-mapping>
        
        <!-- ======================== 单点登录结束 ======================== -->

        <!-- session超时定义,单位为分钟 -->
        <session-config>
                <session-timeout>2</session-timeout>
        </session-config>

</web-app>


新建 index.jsp 

在  CasClient01中内容为

  

<body>
 
 CasClient01 
 <br/>
  进入  <a href="http://localhost:8080/CasClient02/index.jsp">CasClient02</a>
</body>
在  CasClient02中内容为

<body>
 
 CasClient02 
 <br/>
  进入  <a href="http://localhost:8080/CasClient01/index.jsp">CasClient01</a>
</body>

重启tomcat
5. 测试
访问 http://localhost:8080/CasClient01/index.jsp   跳转到 cas server 登录页面

登录后跳转到实际访问页面 CasClient01下

这时 直接进入 CasClient02 系统 不需要在登录了

至此, 简单的 CAS SERVER 和Cas CLIENT 演示搭建完成。

此时用户的验证是通过配置文件cas\WEB-INF\deployerConfigContext.xml中指定用户名和密码的方式进行验证的
   <!-- 注释
    <bean id="primaryAuthenticationHandler"
          class="org.jasig.cas.authentication.AcceptUsersAuthenticationHandler">
        <property name="users">
            <map>
                <entry key="casuser" value="Mellon"/>
            </map>
        </property>
    </bean>-->


6. 数据库认证方式配置
 打开  cas/WEB-INF/deployerConfigContext.xml
<!-- 注释 primaryAuthenticationHandler
                <entry key-ref="primaryAuthenticationHandler" value-ref="primaryPrincipalResolver" />
				-->
		<!--新增 dbAuthHandler-->
<entry key-ref="dbAuthHandler" value-ref="primaryPrincipalResolver" />

 <!-- 注释
    <bean id="primaryAuthenticationHandler"
          class="org.jasig.cas.authentication.AcceptUsersAuthenticationHandler">
        <property name="users">
            <map>
                <entry key="casuser" value="Mellon"/>
            </map>
        </property>
    </bean>-->

<!-- 新增 Define the DB Connection -->
    <bean id="dataSource"
     class="com.mchange.v2.c3p0.ComboPooledDataSource"
     p:driverClass="com.mysql.jdbc.Driver"
     p:jdbcUrl="jdbc:mysql://ip:3306/mydb?autoReconnect=true&amp;useUnicode=true&amp;characterEncoding=UTF-8"
     p:user="root"
     p:password="password" />
 
    <!-- Define the encode method-->
    <bean id="passwordEncoder"
      class="org.jasig.cas.authentication.handler.DefaultPasswordEncoder"
      c:encodingAlgorithm="MD5"
      p:characterEncoding="UTF-8" />
 
    <bean id="dbAuthHandler"
      class="org.jasig.cas.adaptors.jdbc.QueryDatabaseAuthenticationHandler"
      p:dataSource-ref="dataSource"
      p:sql="select password from t_user where account=?"
     p:passwordEncoder-ref="passwordEncoder"/>

最后,加入以下依赖包:c3p0-0.9.1.2.jar,MySQL-connector-Java5.1.21.jar,cas-server-support-jdbc-4.0.0.jar
重启tomcat服务器,发现已经可以使用数据库用户进行登录了。

数据库授权的相关日志
2017-05-10 16:51:31,306 INFO [org.jasig.cas.web.flow.InitialFlowSetupAction] - <Setting path for cookies to: /cas/>
2017-05-10 16:51:31,353 INFO [com.github.inspektr.audit.support.Slf4jLoggingAuditTrailManager] - <Audit trail record BEGIN
=============================================================
WHO: audit:unknown
WHAT: TGT-1-dQIhUKHfCe0tYlAiTb1bHaEPvzqrqpSjDGAWd0EgqhvIzZeTGe-cas01.example.org
ACTION: TICKET_GRANTING_TICKET_DESTROYED
APPLICATION: CAS
WHEN: Wed May 10 16:51:31 CST 2017
CLIENT IP ADDRESS: 127.0.0.1
SERVER IP ADDRESS: 127.0.0.1
=============================================================

>
2017-05-10 16:51:43,448 INFO [org.jasig.cas.authentication.PolicyBasedAuthenticationManager] - <QueryDatabaseAuthenticationHandler successfully authenticated whl-test+password>
2017-05-10 16:51:43,449 INFO [org.jasig.cas.authentication.PolicyBasedAuthenticationManager] - <Authenticated whl-test with credentials [whl-test+password].>
2017-05-10 16:51:43,449 INFO [com.github.inspektr.audit.support.Slf4jLoggingAuditTrailManager] - <Audit trail record BEGIN
=============================================================
WHO: audit:unknown
WHAT: supplied credentials: [whl-test+password]
ACTION: AUTHENTICATION_SUCCESS
APPLICATION: CAS
WHEN: Wed May 10 16:51:43 CST 2017
CLIENT IP ADDRESS: 127.0.0.1
SERVER IP ADDRESS: 127.0.0.1
=============================================================

>
2017-05-10 16:51:43,452 INFO [com.github.inspektr.audit.support.Slf4jLoggingAuditTrailManager] - <Audit trail record BEGIN
=============================================================
WHO: audit:unknown
WHAT: TGT-1-SRxa7O4HZIfUGQLoXr3N16PThde6DDnnKphlSJdcCYVMn9O9ih-cas01.example.org
ACTION: TICKET_GRANTING_TICKET_CREATED
APPLICATION: CAS
WHEN: Wed May 10 16:51:43 CST 2017
CLIENT IP ADDRESS: 127.0.0.1
SERVER IP ADDRESS: 127.0.0.1
=============================================================

>
2017-05-10 16:51:43,459 INFO [org.jasig.cas.CentralAuthenticationServiceImpl] - <Granted service ticket [ST-1-JygQAcQx9ufoQvBq4Vup-cas01.example.org] for service [http://localhost:8080/CasClient01/index.jsp] for user [whl-test]>
2017-05-10 16:51:43,459 INFO [com.github.inspektr.audit.support.Slf4jLoggingAuditTrailManager] - <Audit trail record BEGIN
=============================================================
WHO: whl-test
WHAT: ST-1-JygQAcQx9ufoQvBq4Vup-cas01.example.org for http://localhost:8080/CasClient01/index.jsp
ACTION: SERVICE_TICKET_CREATED
APPLICATION: CAS
WHEN: Wed May 10 16:51:43 CST 2017
CLIENT IP ADDRESS: 127.0.0.1
SERVER IP ADDRESS: 127.0.0.1
=============================================================

>
2017-05-10 16:51:43,543 INFO [com.github.inspektr.audit.support.Slf4jLoggingAuditTrailManager] - <Audit trail record BEGIN
=============================================================
WHO: audit:unknown
WHAT: ST-1-JygQAcQx9ufoQvBq4Vup-cas01.example.org
ACTION: SERVICE_TICKET_VALIDATED
APPLICATION: CAS
WHEN: Wed May 10 16:51:43 CST 2017
CLIENT IP ADDRESS: 127.0.0.1
SERVER IP ADDRESS: 127.0.0.1
=============================================================

>
2017-05-10 16:51:44,317 INFO [org.jasig.cas.ticket.registry.support.DefaultTicketRegistryCleaner] - <Beginning ticket cleanup.>
2017-05-10 16:51:44,317 INFO [org.jasig.cas.ticket.registry.support.DefaultTicketRegistryCleaner] - <0 tickets found to be removed.>
2017-05-10 16:51:44,317 INFO [org.jasig.cas.ticket.registry.support.DefaultTicketRegistryCleaner] - <Finished ticket cleanup.>


登出配置:
    如果调用  /cas/logout 登出后 回到指定页面
  1.  修改cas-servlet.xml文件的bean的id为logoutAction下的p:followServiceRedirects属性为“true”
  
<bean id="logoutAction" class="org.jasig.cas.web.flow.LogoutAction"
        p:servicesManager-ref="servicesManager"
        p:followServiceRedirects="${cas.logout.followServiceRedirects:false}"/>

或者 修改  cas-properties 
 
# cas.logout.followServiceRedirects=true

  2. 在自己系统要配置的系统“退出”链接后加上“?service=退出返回后的地址”,例如:CAS测试用的两个客户端的配置。例如:<ahref="http://sso.castest.com/cas/logout?service= http://xxxx/casclient01/mainpage">退出</a>
  3. 原理分析
       从web.xml中可以看出 ,所有的请求都给  SafeDispatcherServlet进行处理分发 
  
<servlet>
    <servlet-name>cas</servlet-name>
    <servlet-class>
      org.jasig.cas.web.init.SafeDispatcherServlet
    </servlet-class>
    <init-param>
      <param-name>publishContext</param-name>
      <param-value>false</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>
	
  <servlet-mapping>
    <servlet-name>cas</servlet-name>
    <url-pattern>/login</url-pattern>
  </servlet-mapping>

  <servlet-mapping>
    <servlet-name>cas</servlet-name>
    <url-pattern>/logout</url-pattern>
  </servlet-mapping>

  <servlet-mapping>
    <servlet-name>cas</servlet-name>
    <url-pattern>/validate</url-pattern>
  </servlet-mapping>

  <servlet-mapping>
    <servlet-name>cas</servlet-name>
    <url-pattern>/serviceValidate</url-pattern>
  </servlet-mapping>

  <servlet-mapping>
    <servlet-name>cas</servlet-name>
    <url-pattern>/p3/serviceValidate</url-pattern>
  </servlet-mapping>
  
  <servlet-mapping>
    <servlet-name>cas</servlet-name>
    <url-pattern>/proxy</url-pattern>
  </servlet-mapping>

  <servlet-mapping>
    <servlet-name>cas</servlet-name>
    <url-pattern>/proxyValidate</url-pattern>
  </servlet-mapping>

  <servlet-mapping>
    <servlet-name>cas</servlet-name>
    <url-pattern>/p3/proxyValidate</url-pattern>
  </servlet-mapping>
  
  <servlet-mapping>
    <servlet-name>cas</servlet-name>
    <url-pattern>/CentralAuthenticationService</url-pattern>
  </servlet-mapping>

  <servlet-mapping>
    <servlet-name>cas</servlet-name>
    <url-pattern>/status</url-pattern>
  </servlet-mapping>

  <servlet-mapping>
    <servlet-name>cas</servlet-name>
    <url-pattern>/statistics</url-pattern>
  </servlet-mapping>

  <servlet-mapping>
    <servlet-name>cas</servlet-name>
    <url-pattern>/authorizationFailure.html</url-pattern>
  </servlet-mapping>



7. cas server 添加 restful api 能力
  CAS-server提供了restful api供调用,要开启restful服务,首先要找到与之对应的jar包。
cas源代码里cas-server-integration-restlet这个工程就是支持restful的模块,编译出来后得到一个jar包,3.6之前的版本也可以直接下载到这个jar包。
把jar包cas-server-integration-restlet-3.5.2.jar,放到cas-server-webapp的lib目录下,除了这个jar包之外,还需要几个jar包,分别是:
com.noelios.restlet.ext.servlet,jar
com.noelios.restlet.ext.spring-1.1.0.jar
com.noelios.restlet.jar
org.restlet.ext.spring-1.1.10.jar
org.restlet-1.1.10.jar
都一并放到cas-server-webapp的lib目录下。
然后修改server的web.xml,加入一个restful的servlet
<servlet>  
    <servlet-name>restlet</servlet-name>  
    <servlet-class>com.noelios.restlet.ext.spring.RestletFrameworkServlet</servlet-class>  
    <load-on-startup>1</load-on-startup>  
</servlet>  
   
<servlet-mapping>  
    <servlet-name>restlet</servlet-name>  
    <url-pattern>/v1/*</url-pattern>  
</servlet-mapping> 

再找到WEB-INF\spring-configuration下的ticketExpirationPolicies.xml,把timetokill的这个时间改大一点,10秒有点短,手动测试的时候一下ticket就过期了
<util:constant id="SECONDS" static-field="java.util.concurrent.TimeUnit.SECONDS"/>  
    <bean id="serviceTicketExpirationPolicy" class="org.jasig.cas.ticket.support.MultiTimeUseOrTimeoutExpirationPolicy"  
          c:numberOfUses="1" c:timeToKill="${st.timeToKillInSeconds:10}" c:timeUnit-ref="SECONDS"/> 

server端的配置基本就这么多,然后可以启动server的tomcat
最后就可以用restful的工具来进行测试了,我这里用的是curl
第一步是登录换取tgt
curl -i -k -X  POST -d "username=lhc&password=123456&service=http://192.168.56.101/omw/do/main/index" https://192.168.56.101:8443/cas/v1/tickets/

会得到一个响应:
HTTP/1.1 201 Created  
Date: Tue, 28 Jun 2016 08:03:23 GMT  
Location: https://192.168.56.101:8443/cas/v1/tickets/TGT-3-MIipUxjOlXiXU1Uuj0vZncjZcfeIJFKhJwegBuHDL03kfCV5ME-cas01.example.org  
Accept-Ranges: bytes  
Server: Noelios-Restlet-Engine/1.1.6  
Content-Type: text/html;charset=ISO-8859-1  
Content-Length: 448


把这个响应里的location字段后面的拷贝一下,这是第二步要访问的rest接口的url
curl -i -k -X  POST -d "service=http%3A%2F%2F192.168.56.101%2Fomw%2Fdo%2Fmain%2Findex" https://192.168.56.101:8443/cas/v1/tickets/TGT-3-MIipUxjOlXiXU1Uuj0vZncjZcfeIJFKhJwegBuHDL03kfCV5ME-cas01.example.org 

第二步的响应就是ticket
ST-2-AHrFkuIyZBarRPGHsbaZ-cas01.example.org  
  
最后带上这个ticket访问上面service的地址,就是已经登录的状态  
http://192.168.56.101/omw/do/main/index?ticket=ST-2-AHrFkuIyZBarRPGHsbaZ-cas01.example.org  
  
curl里第二步的时候注意一下,这个url要进行编码。  


其他:
  异常1    错误CAS is Unavailable
             修改超时时间试试:   <bean id="terminateWebSessionListener" class="org.jasig.cas.web.flow.TerminateWebSessionListener"
p:timeToDieInSeconds="100"
 />




  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值