【CAS学习之三】CAS客户端验证

环境
  apache-tomcat-8.5.45
  jdk1.8.0_65
  cas服务端:5.2.6
  cas客户端:cas-sample-java-webapp

一、部署方案
1、网络拓扑

2、组件清单

3、设置hosts

设置PCS101、PCS102、PCS103三台机器的/etc/hosts以及浏览器所在windows主机C:WindowsSystem32driversetchosts

127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.123.101  PCS101
192.168.123.102  PCS102
192.168.123.103  PCS103
192.168.123.101  cas.example.org
192.168.123.102  app1.PCS102.org
192.168.123.103  app2.PCS103.org

二、CAS服务端和客户端https证书设置

首先参考:
java生成Https证书,及证书导入的步骤和过程
关于几种格式证书的区别

1、CAS服务端https证书设置
(1)生成服务器的密匙文件casserver.keystore

[root@PCS101 bin]# keytool -genkey -alias casserver -keyalg RSA -keysize 2048 -keypass 123456 -storepass 123456 -keystore /root/casserver.keystore -validity 365 -dname "CN=cas.example.org,OU=example.com,O=cas,L=JiNan,ST=JiNan,C=CN"
[root@PCS101 bin]# ll /root/casserver.keystore 
-rw-r--r--. 1 root root 2237 Sep 25 11:42 /root/casserver.keystore

#查看密匙文件casserver.keystore命令
[root@PCS101 ~]# keytool -v -list -storepass 123456 -keystore /root/casserver.keystore

Keystore type: JKS
Keystore provider: SUN

Your keystore contains 1 entry

Alias name: casserver
Creation date: Sep 25, 2020
Entry type: PrivateKeyEntry
Certificate chain length: 1
Certificate[1]:
Owner: CN=cas.example.org, OU=example.com, O=cas, L=JiNan, ST=JiNan, C=CN
Issuer: CN=cas.example.org, OU=example.com, O=cas, L=JiNan, ST=JiNan, C=CN
Serial number: 12cb4c39
Valid from: Fri Sep 25 15:40:49 CST 2020 until: Sat Sep 25 15:40:49 CST 2021
Certificate fingerprints:
     MD5:  B0:39:F9:84:B3:2A:9E:B7:97:8B:A2:E1:36:45:6E:CC
     SHA1: 29:4A:78:5E:1D:04:D5:35:80:AB:07:9A:50:01:D3:21:E7:4E:F4:2D
     SHA256: 45:E7:C9:AA:24:CC:87:70:BB:64:40:3B:C7:9B:E0:60:BB:B2:58:76:E6:4F:38:AF:14:44:9B:36:AA:0D:87:A9
     Signature algorithm name: SHA256withRSA
     Version: 3

Extensions: 

#1: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: 02 9A C2 86 BD D9 21 E8   FF 58 7A 0B 2B 82 76 B6  ......!..Xz.+.v.
0010: 2E 84 04 53                                        ...S
]
]



*******************************************
*******************************************

(2)为CAS客户端和浏览器生成证书 casserver.cer

#必须加入-validity 365 否则导入浏览器提示过期
[root@PCS101 bin]# keytool -export -alias casserver -keystore /root/casserver.keystore -file /root/casserver.cer -storepass 123456 -validity 365
Certificate stored in file </root/casserver.cer>
[root@PCS101 bin]# ll /root/casserver.cer 
-rw-r--r--. 1 root root 889 Sep 25 11:43 /root/casserver.cer

#打印cer证书内容
[root@PCS101 ~]# keytool -printcert -file /root/casserver.cer
Owner: CN=cas.example.org, OU=example.com, O=cas, L=JiNan, ST=JiNan, C=CN
Issuer: CN=cas.example.org, OU=example.com, O=cas, L=JiNan, ST=JiNan, C=CN
Serial number: 12cb4c39
Valid from: Fri Sep 25 15:40:49 CST 2020 until: Sat Sep 25 15:40:49 CST 2021
Certificate fingerprints:
     MD5:  B0:39:F9:84:B3:2A:9E:B7:97:8B:A2:E1:36:45:6E:CC
     SHA1: 29:4A:78:5E:1D:04:D5:35:80:AB:07:9A:50:01:D3:21:E7:4E:F4:2D
     SHA256: 45:E7:C9:AA:24:CC:87:70:BB:64:40:3B:C7:9B:E0:60:BB:B2:58:76:E6:4F:38:AF:14:44:9B:36:AA:0D:87:A9
     Signature algorithm name: SHA256withRSA
     Version: 3

Extensions: 

#1: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: 02 9A C2 86 BD D9 21 E8   FF 58 7A 0B 2B 82 76 B6  ......!..Xz.+.v.
0010: 2E 84 04 53                                        ...S
]
]

(3)服务端导入证书文件到cacerts密钥库文件
接下来就是把上面生成的服务器的证书casserver.cer导入到cacerts密钥库文件中(后面的客户端会用到这些)

[root@PCS101 ~]# keytool -import -trustcacerts -alias casserver -storepass changeit -keystore /usr/local/jdk1.8.0_65/jre/lib/security/cacerts -file /root/casserver.cer
Owner: CN=cas.example.org, OU=example.com, O=cas, L=JiNan, ST=JiNan, C=CN
Issuer: CN=cas.example.org, OU=example.com, O=cas, L=JiNan, ST=JiNan, C=CN
Serial number: 12cb4c39
Valid from: Fri Sep 25 15:40:49 CST 2020 until: Sat Sep 25 15:40:49 CST 2021
Certificate fingerprints:
     MD5:  B0:39:F9:84:B3:2A:9E:B7:97:8B:A2:E1:36:45:6E:CC
     SHA1: 29:4A:78:5E:1D:04:D5:35:80:AB:07:9A:50:01:D3:21:E7:4E:F4:2D
     SHA256: 45:E7:C9:AA:24:CC:87:70:BB:64:40:3B:C7:9B:E0:60:BB:B2:58:76:E6:4F:38:AF:14:44:9B:36:AA:0D:87:A9
     Signature algorithm name: SHA256withRSA
     Version: 3

Extensions: 

#1: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: 02 9A C2 86 BD D9 21 E8   FF 58 7A 0B 2B 82 76 B6  ......!..Xz.+.v.
0010: 2E 84 04 53                                        ...S
]
]

Trust this certificate? [no]:  yes
Certificate was added to keystore
[root@PCS101 ~]# keytool -list -storepass changeit -keystore /usr/local/jdk1.8.0_65/jre/lib/security/cacerts |grep cas
casserver, Sep 25, 2020, trustedCertEntry,

(4)CAS服务端tomcat配置server.xml

<Connector port="8443" 
           protocol="org.apache.coyote.http11.Http11NioProtocol"
           maxThreads="200" 
           scheme="https"
           secure="true" 
           SSLEnabled="true"
           keystoreFile="/root/casserver.keystore"
           keystorePass="123456"
           clientAuth="false" 
           sslProtocol="TLS"/>

(5)浏览器导入证书
谷歌浏览器或者高版本的IE可以导入cer格式证书,而低版本的IE或者firefox浏览器需要导入p12格式证书

未导入证书casserver.cer访问 会提示安全证书警告:

导入证书casserver.cer之后访问:

查看导入证书:


(5.1)cer导入浏览器
谷歌浏览器如何导入证书参考
(5.2)将cer格式的证书转换为p12证书

keytool -importkeystore -srckeystore /root/casserver.keystore -destkeystore /root/casserver.p12 -srcalias casserver -destalias casserverp12 -srcstoretype jks -deststoretype pkcs12 -srcstorepass 123456 -deststorepass 123456 -noprompt

(5.3)直接生成p12证书

#根据密钥keystore生成p12证书:
keytool -genkey -v -alias client -keyalg RSA -storetype PKCS12 -keystore /root/casserver.p12 -keypass 123456 -storepass 123456
#将p12证书导出为cer证书(-rfc 指定以Base64编码格式输出):
keytool -export -alias client -storepass 123456 -keystore /root/casserver.p12 -storetype PKCS12 -rfc -file /root/casserver.cer

2、CAS客户端添加CAS服务端授予的证书casserver.cer
(1)生成客户端密钥库文件
单向认证的客户端配置只需生成客户端信任文件caserts即可。
将PCS101-CAS服务端生成的casserver.cer上传到PCS102、PCS103

[root@PCS101 ~]# scp /root/casserver.cer root@PCS102:/root
casserver.cer                                                                                                                             100%  889     1.0MB/s   00:00    
[root@PCS101 ~]# scp /root/casserver.cer root@PCS103:/root
casserver.cer                                                                                                                             100%  889     1.6MB/s   00:00    

(2)PCS102、PCS103导入证书
然后使用命令导入jre,一定要是跑客户端的Tomcat的那个jre,这里是/usr/local/jdk1.8.0_65/jre

[root@PCS102 ~]# keytool -import -trustcacerts -alias casserver -storepass changeit -keystore /usr/local/jdk1.8.0_65/jre/lib/security/cacerts -file /root/casserver.cer
[root@PCS103 ~]# keytool -import -trustcacerts -alias casserver -storepass changeit -keystore /usr/local/jdk1.8.0_65/jre/lib/security/cacerts -file /root/casserver.cer
查看导入的证书清单,密码是changeit
[root@PCS102 ~]# keytool -list -storepass changeit -keystore /usr/local/jdk1.8.0_65/jre/lib/security/cacerts |grep cas
后期可以删除导入的证书,密码也是changeit
[root@PCS102 ~]# keytool -delete -alias casserver -storepass changeit -keystore /usr/local/jdk1.8.0_65/jre/lib/security/cacerts

[root@PCS102 ~]# keytool -import -trustcacerts -alias casserver -storepass changeit -keystore /usr/local/jdk1.8.0_65/jre/lib/security/cacerts -file /root/casserver.cer
Owner: CN=cas.example.org, OU=example.com, O=cas, L=JiNan, ST=JiNan, C=CN
Issuer: CN=cas.example.org, OU=example.com, O=cas, L=JiNan, ST=JiNan, C=CN
Serial number: 12cb4c39
Valid from: Fri Sep 25 15:40:49 CST 2020 until: Sat Sep 25 15:40:49 CST 2021
Certificate fingerprints:
     MD5:  B0:39:F9:84:B3:2A:9E:B7:97:8B:A2:E1:36:45:6E:CC
     SHA1: 29:4A:78:5E:1D:04:D5:35:80:AB:07:9A:50:01:D3:21:E7:4E:F4:2D
     SHA256: 45:E7:C9:AA:24:CC:87:70:BB:64:40:3B:C7:9B:E0:60:BB:B2:58:76:E6:4F:38:AF:14:44:9B:36:AA:0D:87:A9
     Signature algorithm name: SHA256withRSA
     Version: 3

Extensions: 

#1: ObjectId: 2.5.29.14 Criticality=false
SubjectKeyIdentifier [
KeyIdentifier [
0000: 02 9A C2 86 BD D9 21 E8   FF 58 7A 0B 2B 82 76 B6  ......!..Xz.+.v.
0010: 2E 84 04 53                                        ...S
]
]

Trust this certificate? [no]:  yes
Certificate was added to keystore
[root@PCS102 ~]# keytool -list -storepass changeit -keystore /usr/local/jdk1.8.0_65/jre/lib/security/cacerts |grep cas
casserver, Sep 25, 2020, trustedCertEntry, 

3、CAS客户端证书 用来给浏览器的证书

(1)生成服务器的密匙文件

#PCS102:casclient1.keystore
[root@PCS102 ~]# keytool -genkey -alias casclient1 -keyalg RSA -keysize 2048 -keypass 123456 -storepass 123456 -keystore /root/casclient1.keystore -validity 365 -dname "CN=app1.PCS102.org,OU=PCS102.com,O=cas,L=JiNan,ST=JiNan,C=CN"
#PCS103:casclient2.keystore
[root@PCS103 ~]# keytool -genkey -alias casclient2 -keyalg RSA -keysize 2048 -keypass 123456 -storepass 123456 -keystore /root/casclient2.keystore -validity 365 -dname "CN=app2.PCS103.org,OU=PCS103.com,O=cas,L=JiNan,ST=JiNan,C=CN"

(2)生成证书casserver.cer

#PCS102:casclient1.cer
[root@PCS102 ~]# keytool -export -alias casclient1 -keystore /root/casclient1.keystore -file /root/casclient1.cer -storepass 123456 -validity 365
#PCS102:casclient2.cer
[root@PCS103 ~]# keytool -export -alias casclient2 -keystore /root/casclient2.keystore -file /root/casclient2.cer -storepass 123456 -validity 365

(3)客户端将证书文件导入到密钥库文件cacerts

#PCS102:cacerts
[root@PCS102 ~]# keytool -import -trustcacerts -alias casclient1 -storepass changeit -keystore /usr/local/jdk1.8.0_65/jre/lib/security/cacerts -file /root/casclient1.cer
#PCS103:cacerts
[root@PCS103 ~]# keytool -import -trustcacerts -alias casclient2 -storepass changeit -keystore /usr/local/jdk1.8.0_65/jre/lib/security/cacerts -file /root/casclient2.cer

最终各主机cer信任清单:

[root@PCS101 ~]# keytool -list -storepass changeit -keystore /usr/local/jdk1.8.0_65/jre/lib/security/cacerts |grep cas
casserver, Sep 25, 2020, trustedCertEntry, 

[root@PCS102 ~]# keytool -list -storepass changeit -keystore /usr/local/jdk1.8.0_65/jre/lib/security/cacerts |grep cas
casserver, Sep 25, 2020, trustedCertEntry, 
casclient1, Sep 25, 2020, trustedCertEntry,

[root@PCS103 ~]# keytool -list -storepass changeit -keystore /usr/local/jdk1.8.0_65/jre/lib/security/cacerts |grep cas
casserver, Sep 25, 2020, trustedCertEntry, 
casclient2, Sep 25, 2020, trustedCertEntry,

(4)修改PCS102、PCS103三台机器的Tomcat的server.xml,启用https

PCS102:
<Connector port="8443" 
           protocol="org.apache.coyote.http11.Http11NioProtocol"
           maxThreads="200" 
           scheme="https"
           secure="true" 
           SSLEnabled="true"
           keystoreFile="/root/casclient1.keystore"
           keystorePass="123456"
           clientAuth="false" <!--false表示单向认证 true表示双向认证-->
           sslProtocol="TLS"/>    
PCS103:
<Connector port="8443" 
           protocol="org.apache.coyote.http11.Http11NioProtocol"
           maxThreads="200" 
           scheme="https"
           secure="true" 
           SSLEnabled="true"
           keystoreFile="/root/casclient2.keystore"
           keystorePass="123456"
           clientAuth="false" <!--false表示单向认证 true表示双向认证-->
           sslProtocol="TLS"/>        

clientAuth:设置是否双向验证,默认为false,设置为true代表双向验证 设置clientAuth属性为True时,需要手动导入客户端证书才能访问。

(5)浏览器导入casclient1.cer和casclient1.cer证书

 

二、部署cas服务端

参考:【CAS学习之二】部署CAS服务端 

三、准备cas客户端
1、下载
从官网客户端cas-sample-java-webapp

Administrator@PC-20190528ODKR MINGW64 /e/cas/cas-sample-java-webapp (master)
$ git clone https://github.com/cas-projects/cas-sample-java-webapp.git

2、导入idea
cas-sample-java-webapp内置了jetty,我这里导入idea制作war包,然后用tomcat运行。

cas-sample-java-webapp1:
(1)调整pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>iamlabs.unicon.net</groupId>
    <artifactId>cas-sample-java-webapp</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>
    <name>CAS Example Java Web App</name>
    <description>A sample web application that exercises the CAS protocol features via the Java CAS Client.</description>
    <build>
        <finalName>cas-sample-java-webapp</finalName>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.5.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
            <!--
            <plugin>
                <groupId>org.eclipse.jetty</groupId>
                <artifactId>jetty-maven-plugin</artifactId>
                <version>9.3.6.v20151106</version>
                <configuration>
                    <jettyXml>${basedir}/etc/jetty/jetty.xml,${basedir}/etc/jetty/jetty-ssl.xml,${basedir}/etc/jetty/jetty-https.xml</jettyXml>
                    <systemProperties>
                        <systemProperty>
                            <name>org.eclipse.jetty.annotations.maxWait</name>
                            <value>300</value>
                        </systemProperty>
                    </systemProperties>
                    <webApp>
                        <contextPath>/sample</contextPath>
                        <overrideDescriptor>${basedir}/etc/jetty/web.xml</overrideDescriptor>
                    </webApp>
                    <jvmArgs>-Xdebug -Xrunjdwp:transport=dt_socket,address=5002,server=y,suspend=n</jvmArgs>
                </configuration>
            </plugin>
            -->
        </plugins>
    </build>

    <dependencies>
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.1.1</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
        <dependency>
            <groupId>org.jasig.cas.client</groupId>
            <artifactId>cas-client-core</artifactId>
            <version>3.4.1</version>
            <exclusions>
                <exclusion>
                    <groupId>javax.servlet</groupId>
                    <artifactId>servlet-api</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>javax.activation</groupId>
            <artifactId>activation</artifactId>
            <version>1.1.1</version>
        </dependency>
    </dependencies>
</project>

(2)调整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">
    <!--用来控制cas识别的session的保存,以及判断是否是登出请求-->
    <filter>
        <filter-name>CAS Single Sign Out Filter</filter-name>
        <filter-class>org.jasig.cas.client.session.SingleSignOutFilter</filter-class>
        <init-param>
            <param-name>casServerUrlPrefix</param-name>
            <!--这个地址要和keystore中的CN一致,端口无所谓,域名必须一致,前边我在hosts里面配置了这个域名映射-->
            <param-value>https://cas.example.org:8443/cas</param-value>
        </init-param>
    </filter>

    <listener>
        <listener-class>org.jasig.cas.client.session.SingleSignOutHttpSessionListener</listener-class>
    </listener>

    <!--用来跳转登录-->
    <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>
            <!--这个地址要和keystore中的CN一致,端口无所谓,域名必须一致,前边我在hosts里面配置了这个域名映射-->
            <param-value>https://cas.example.org:8443/cas/login</param-value>
        </init-param>
        <init-param>
            <param-name>serverName</param-name>
            <!--这是你客户端的部署地址,认证时会带着这个地址,认证成功后会跳转到这个地址-->
            <param-value>https://app1.PCS102.org:8443</param-value>
        </init-param>
    </filter>

    <!--用来验证ticket-->
    <filter>
        <filter-name>CAS Validation Filter</filter-name>
        <filter-class>org.jasig.cas.client.validation.Cas30ProxyReceivingTicketValidationFilter</filter-class>
        <init-param>
            <param-name>casServerUrlPrefix</param-name>
            <!--这个地址要和keystore中的CN一致,端口无所谓,域名必须一致,前边我在hosts里面配置了这个域名映射-->
            <param-value>https://cas.example.org:8443/cas</param-value>
        </init-param>
        <init-param>
            <param-name>serverName</param-name>
            <!--这是你客户端的部署地址,验证ticket成功后会跳转到这个地址-->
            <param-value>https://app1.PCS102.org:8443</param-value>
        </init-param>
        <init-param>
            <param-name>redirectAfterValidation</param-name>
            <param-value>true</param-value>
        </init-param>
        <init-param>
            <param-name>useSession</param-name>
            <param-value>true</param-value>
        </init-param>
        <!--
        <init-param>
            <param-name>acceptAnyProxy</param-name>
            <param-value>true</param-value>
        </init-param>
        <init-param>
            <param-name>proxyReceptorUrl</param-name>
            <param-value>/sample/proxyUrl</param-value>
        </init-param>
        <init-param>
            <param-name>proxyCallbackUrl</param-name>
            <param-value>https://cas.example.org:9443/sample/proxyUrl</param-value>
        </init-param>
        -->
        <init-param>
            <param-name>authn_method</param-name>
            <param-value>mfa-duo</param-value>
        </init-param>
    </filter>
    <!--用来封装request-->
    <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 Single Sign Out Filter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

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

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

    <filter-mapping>
        <filter-name>CAS HttpServletRequest Wrapper Filter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <welcome-file-list>
        <welcome-file>
            index.jsp
        </welcome-file>
    </welcome-file-list>
</web-app>

(3)构建生成cas-sample-java-webapp.war

(4)登录后首页index.jsp

<%@page contentType="text/html" %>
<%@page pageEncoding="UTF-8" %>
<%@ page import="java.util.Map" %>
<%@ page import="java.util.Iterator" %>
<%@ page import="java.util.List" %>
<%@ page import="org.jasig.cas.client.authentication.AttributePrincipal" %>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">

<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>CAS Example Java Web App</title>
</head>
<body>

<h1>CAS Example Java Web App</h1>
<p>A sample web application that exercises the CAS protocol features via the Java CAS Client.</p>
<hr>
<%-- 点击退出 --%>
<p><b>Authenticated User Id:</b> <a href="logout.jsp" title="Click here to log out"><%= request.getRemoteUser() %>
</a></p>

<%
    //获取了所有你可以从CAS服务器获取的属性
    //前面cas server application.properties里配置了多属性会展示登录用户的一些信息
    if (request.getUserPrincipal() != null) {
        AttributePrincipal principal = (AttributePrincipal) request.getUserPrincipal();

        final Map attributes = principal.getAttributes();

        if (attributes != null) {
            Iterator attributeNames = attributes.keySet().iterator();
            out.println("<b>Attributes:</b>");

            if (attributeNames.hasNext()) {
                out.println("<hr><table border='3pt' width='100%'>");
                out.println("<th colspan='2'>Attributes</th>");
                out.println("<tr><td><b>Key</b></td><td><b>Value</b></td></tr>");

                for (; attributeNames.hasNext(); ) {
                    out.println("<tr><td>");
                    String attributeName = (String) attributeNames.next();
                    out.println(attributeName);
                    out.println("</td><td>");
                    final Object attributeValue = attributes.get(attributeName);

                    if (attributeValue instanceof List) {
                        final List values = (List) attributeValue;
                        out.println("<strong>Multi-valued attribute: " + values.size() + "</strong>");
                        out.println("<ul>");
                        for (Object value : values) {
                            out.println("<li>" + value + "</li>");
                        }
                        out.println("</ul>");
                    } else {
                        out.println(attributeValue);
                    }
                    out.println("</td></tr>");
                }
                out.println("</table>");
            } else {
                out.print("No attributes are supplied by the CAS server.</p>");
            }
        } else {
            out.println("<pre>The attribute map is empty. Review your CAS filter configurations.</pre>");
        }
    } else {
        out.println("<pre>The user principal is empty from the request object. Review the wrapper filter configuration.</pre>");
    }
%>

</body>
</html>

(5)退出页面

<%@page contentType="text/html" %>
<%@page pageEncoding="UTF-8" %>
<%@ page import="java.util.Map" %>
<%@ page import="java.util.Iterator" %>
<%@ page import="org.jasig.cas.client.authentication.AttributePrincipal" %>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">

<%
    //session 失效
    session.invalidate();
%>

<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>CAS Example Java Web App</title>
</head>
<body>
<h1>CAS Example Java Web App</h1>
<p>Application session is now invalidated. You may also issue a request to "/cas/logout" to destroy the CAS SSO Session as well.</p>
<hr>

<a href="index.jsp">Back to Home</a>
</body>
</html>

cas-sample-java-webapp2:

(1)调整pom.xml

同上
(2)调整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">
    <!--用来控制cas识别的session的保存,以及判断是否是登出请求-->
    <filter>
        <filter-name>CAS Single Sign Out Filter</filter-name>
        <filter-class>org.jasig.cas.client.session.SingleSignOutFilter</filter-class>
        <init-param>
            <param-name>casServerUrlPrefix</param-name>
            <!--这个地址要和keystore中的CN一致,端口无所谓,域名必须一致,前边我在hosts里面配置了这个域名映射-->
            <param-value>https://cas.example.org:8443/cas</param-value>
        </init-param>
    </filter>

    <listener>
        <listener-class>org.jasig.cas.client.session.SingleSignOutHttpSessionListener</listener-class>
    </listener>

    <!--用来跳转登录-->
    <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>
            <!--这个地址要和keystore中的CN一致,端口无所谓,域名必须一致,前边我在hosts里面配置了这个域名映射-->
            <param-value>https://cas.example.org:8443/cas/login</param-value>
        </init-param>
        <init-param>
            <param-name>serverName</param-name>
            <!--这是你客户端的部署地址,认证时会带着这个地址,认证成功后会跳转到这个地址-->
            <param-value>https://app2.PCS103.org:8443</param-value>
        </init-param>
    </filter>

    <!--用来验证ticket-->
    <filter>
        <filter-name>CAS Validation Filter</filter-name>
        <filter-class>org.jasig.cas.client.validation.Cas30ProxyReceivingTicketValidationFilter</filter-class>
        <init-param>
            <param-name>casServerUrlPrefix</param-name>
            <!--这个地址要和keystore中的CN一致,端口无所谓,域名必须一致,前边我在hosts里面配置了这个域名映射-->
            <param-value>https://cas.example.org:8443/cas</param-value>
        </init-param>
        <init-param>
            <param-name>serverName</param-name>
            <!--这是你客户端的部署地址,验证ticket成功后会跳转到这个地址-->
            <param-value>https://app2.PCS103.org:8443</param-value>
        </init-param>
        <init-param>
            <param-name>redirectAfterValidation</param-name>
            <param-value>true</param-value>
        </init-param>
        <init-param>
            <param-name>useSession</param-name>
            <param-value>true</param-value>
        </init-param>
        <!--
        <init-param>
            <param-name>acceptAnyProxy</param-name>
            <param-value>true</param-value>
        </init-param>
        <init-param>
            <param-name>proxyReceptorUrl</param-name>
            <param-value>/sample/proxyUrl</param-value>
        </init-param>
        <init-param>
            <param-name>proxyCallbackUrl</param-name>
            <param-value>https://cas.example.org:9443/sample/proxyUrl</param-value>
        </init-param>
        -->
        <init-param>
            <param-name>authn_method</param-name>
            <param-value>mfa-duo</param-value>
        </init-param>
    </filter>
    <!--用来封装request-->
    <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 Single Sign Out Filter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

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

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

    <filter-mapping>
        <filter-name>CAS HttpServletRequest Wrapper Filter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <welcome-file-list>
        <welcome-file>
            index.jsp
        </welcome-file>
    </welcome-file-list>
</web-app>
View Code

(3)构建生成cas-sample-java-webapp.war

四、浏览器访问验证
分别启动PCS101、PCS102、PCS103三台机器上的tomcat。

场景一:
浏览器访问客户端应用:cas-sample-java-webapp1,未登录。
https://app1.PCS102.org:8443/cas-sample-java-webapp/

直接跳转到服务端登录页:

查看F12请求记录:浏览器地址302跳转 https://cas.example.org:8443/cas

登录成功后跳转到app1的index.jsp页面

查看app1的session:

场景二:

浏览器访问客户端应用:cas-sample-java-webapp2,已登录。
https://app2.PCS103.org:8443/cas-sample-java-webapp/

场景三:
浏览器从客户端应用:cas-sample-java-webapp2,点击注销,然后再次访问客户端应用:cas-sample-java-webapp1。
https://app1.PCS102.org:8443/cas-sample-java-webapp/

从app2注销:

再次登录app1,会跳转到CAS服务端登录页面。

参考:cas客户端验证

连接:

服务端代码

客户端代码

原文地址:https://www.cnblogs.com/cac2020/p/13728924.html