原创apereo cas 4.2从0开始

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了原创apereo cas 4.2从0开始相关的知识,希望对你有一定的参考价值。

转载请声明来自:http://www.cnblogs.com/chixinzei/p/7504272.html   谢谢!

目前已实现功能

数据库验证,druid数据源,页面定制,restful登录,shibboleth idp saml2.0整合

 

 

cas相关参考文档

http://www.cnblogs.com/xwdreamer/archive/2011/11/10/2296939.html spring webflow

https://apereo.github.io/cas/4.2.x/ CAS官方文档

http://docs.spring.io/spring-webflow/docs/2.4.5.RELEASE/reference/html Spring webflow 官方文档

与Shibboleth IDP端 SAML2.0整合文档:

https://apereo.github.io/cas/4.2.x/integration/Shibboleth.html 官网cas和Shibboleth IDP 整合

http://wwwcomy.iteye.com/blog/2236016 Shibboleth IDP安装中文博客

https://wiki.shibboleth.net/confluence/display/SHIB2/IdPInstall Shibboleth IDP安装


工作环境准备

运行基础:jdk8.0.131,cas-server:4.2.1(基于gradle),cas-client:3.3.3(基于maven),win7 64,tomcat8.5,mysql 5.6.21,idea-2017.2

ssl配置相关准备

1.http访问配置

取消cas https验证:http://www.cnblogs.com/xiaojf/p/6617693.html

2.https访问配置

准备本地tomcat证书生成与配置:文档参考:http://www.bug315.com/article/412.htm

若要在本地使用SSL访问cas,则只需要修改cas-server-webapp\\src\\main\\resources\\services\\HTTPSandIMAPS-10000001.json的属性tgc.secure=false即可,意思是cas的cookie是否只在ssl下生成(如果为true,则登陆后cookie也不会存放登录信息和票据,依然重定向到登录界面)

默认jdk密匙库口令:changeit

 

1)cmd 移动到tomcat目录下,生成server key :

keytool -genkey -alias tomcat -keyalg RSA -storepass changeit -keystore server.keystore -validity 3600

解释:

-alias 表示证书的别名,一个keystore文件中可以存放多个alias。 

-keyalg RSA 表示密钥算法的名称为RSA算法 

-keypass changeit 表示密钥的口令是changeit  

-storepass changeit 表示密钥库(生成的keystore文件)的密钥是changeit

-keystore server.keystore 表示指定密匙库的名称

-validity 3600  表示证书有效期3600天,也就是大概10年

 

删除证书命令:

先移动到jdk的密匙总库目录:

如:D:\\Program Files\\Java\\jdk1.8.0_131\\jre\\lib\\security

执行删除jdk密匙库证书:

keytool -delete -alias tomcat -keystore cacerts

删除后可以再次将证书导入jdk密匙库

 

2)输入参数:

名字和姓氏:149p874e84.51mypc.cn (域名)

组织单位名称:149p874e84.51mypc.cn

组织名称:149p874e84.51mypc.cn

所在城市:jinjiang

所在省:fujian

国家/地区代码:zh

 

3)证书导入的JDK的证书信任库中

keytool -export -trustcacerts -alias tomcat -file server.cer -keystore  server.keystore -storepass changeit 

 keytool -import -trustcacerts -alias tomcat -file server.cer -keystore  "jdk目录/jre/lib/security/cacerts" -storepass changeit

4)修改tomcat server.xml增加https支持,不需要删除原来的http连接

<!--开启https连接,如果是非外部ide启动,则keystoreFile配置为server.keystore即可!--> 

<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true" 

maxThreads="150" scheme="https" secure="true" 

clientAuth="false" sslProtocol="TLS" 

keystoreFile="D:/Program Files (x86)/apache-tomcat-8.5.16(8086)/server.keystore" keystorePass="changeit"/>

3.支持配置多个验证拦截器。

简单用户名和密码配置修改:/cas-server-support-x509/src/test/resources/deployerConfigContext.xml

casuser,Mellon。

技术分享

另外此用户名密码也可以配置在cas.properties中:

技术分享

两者都存在时优先使用properties的配置

xml存在,而properties不存在时,则读取xml。


CAS服务端配置修改

⒈jdbc简单查询校验:

 

1.1mysql建表:

CREATE TABLE `t_user` ( 

`id` bigint(15) NOT NULL COMMENT主键, 

`account` varchar(30) DEFAULT NULL COMMENT账号, 

`password` varchar(255) DEFAULT NULL COMMENT密码, 

`valid` tinyint(1) DEFAULT NULL COMMENT 是否有效, 

PRIMARY KEY(`id`) 

) ENGINE=InnoDB DEFAULT CHARSET=utf8; 

--插入1条数据: 

INSERT INTO `t_user` 

(`id`, 

`account`, 

`password`, 

`valid`) 

VALUES 

(1, 

admin, 

md5加密后的密码, 

1);

 

1.2 cas-server-webapp\\build.gradle 引入jdbc支持包依赖:

compile project(‘:cas-server-support-jdbc‘) 

compile group: ‘mysql‘, name: ‘mysql-connector-java‘, version: mysqlConnectorJavaVersion

 

 

1.3 deployerConfigContext.xml

关闭简单用户密码校验,改为jdbc校验,密码MD5加密,配合druid

<!--修改登录方式为jdbc验证,注意,需要注释掉QueryAndEncodeDatabaseAuthenticationHandler的注解注入,有冲突-->
<!--<alias name="acceptUsersAuthenticationHandler" alias="primaryAuthenticationHandler" />-->
<alias name="queryDatabaseAuthenticationHandler" alias="primaryAuthenticationHandler"/>
<bean id="queryDatabaseAuthenticationHandler"
          class="org.jasig.cas.adaptors.jdbc.QueryDatabaseAuthenticationHandler">
    <!--<property name="dataSource" ref="queryDatabaseDataSource"></property>-->
    <!--<property name="sql" value="select password from t_user where account=?"></property>-->
    <property name="passwordEncoder" ref="MD5PasswordEncoder"></property>
</bean>
<!-- 添加MD5密码加密功能 -->
<bean id="MD5PasswordEncoder" class="org.jasig.cas.authentication.handler.DefaultPasswordEncoder">
    <constructor-arg index="0">
        <value>MD5</value>
    </constructor-arg>
</bean>

<!-- 数据源配置 -->
<alias name="dataSource" alias="queryDatabaseDataSource"/>
<!-- 阿里 druid 数据库连接池 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
    <!-- 数据库基本信息配置 -->
    <property name="url" value="${cas.druid.database.url}"/>
    <property name="username" value="${cas.druid.database.username}"/>
    <property name="password" value="${cas.druid.database.password}"/>
    <property name="driverClassName" value="${cas.druid.database.driverClassName}"/>
    <property name="filters" value="${cas.druid.database.filters}"/>
    <!-- 最大并发连接数 -->
    <property name="maxActive" value="${cas.druid.database.maxActive}"/>
    <!-- 初始化连接数量 -->
    <property name="initialSize" value="${cas.druid.database.initialSize}"/>
    <!-- 配置获取连接等待超时的时间 -->
    <property name="maxWait" value="${cas.druid.database.maxWait}"/>
    <!-- 最小空闲连接数 -->
    <property name="minIdle" value="${cas.druid.database.minIdle}"/>
    <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
    <property name="timeBetweenEvictionRunsMillis" value="${cas.druid.database.timeBetweenEvictionRunsMillis}"/>
    <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
    <property name="minEvictableIdleTimeMillis" value="${cas.druid.database.minEvictableIdleTimeMillis}"/>
    <property name="validationQuery" value="${cas.druid.database.validationQuery}"/>
    <property name="testWhileIdle" value="${cas.druid.database.testWhileIdle}"/>
    <property name="testOnBorrow" value="${cas.druid.database.testOnBorrow}"/>
    <property name="testOnReturn" value="${cas.druid.database.testOnReturn}"/>
    <property name="maxOpenPreparedStatements" value="${cas.druid.database.maxOpenPreparedStatements}"/>
    <!-- 打开 removeAbandoned 功能 -->
    <property name="removeAbandoned" value="${cas.druid.database.removeAbandoned}"/>
    <!-- 1800 秒,也就是 30 分钟 -->
    <property name="removeAbandonedTimeout" value="${cas.druid.database.removeAbandonedTimeout}"/>
    <!-- 关闭 abanded 连接时输出错误日志 -->
    <property name="logAbandoned" value="${cas.druid.database.logAbandoned}"/>
    <property name="proxyFilters">
        <list>
            <ref bean="log-filter"/>
        </list>
    </property>
</bean>
<bean id="log-filter" class="com.alibaba.druid.filter.logging.Slf4jLogFilter">
    <property name="connectionLogEnabled" value="${cas.druid.database.connectionLogEnabled}"/>
    <property name="statementLogEnabled" value="${cas.druid.database.statementLogEnabled}"/>
    <property name="resultSetLogEnabled" value="${cas.druid.database.resultSetLogEnabled}"/>
    <property name="statementExecutableSqlLogEnable" value="${cas.druid.database.statementExecutableSqlLogEnable}"/>
</bean>

 

1.4 cas.propertie中新增配置:

#sql通过用户名查询密码
cas.jdbc.authn.query.sql=select password  from  t_user  where account=? and  valid=true

#druid config by xbwu
cas.druid.database.url=jdbc:mysql://localhost:3306/xbwudb?characterEncoding=utf8
cas.druid.database.username=root
cas.druid.database.password=root
cas.druid.database.driverClassName=com.mysql.jdbc.Driver
cas.druid.database.filters=stat,wall
cas.druid.database.maxActive=20
cas.druid.database.initialSize=1
cas.druid.database.maxWait=60000
cas.druid.database.minIdle=10
cas.druid.database.timeBetweenEvictionRunsMillis=60000
cas.druid.database.minEvictableIdleTimeMillis=300000
cas.druid.database.validationQuery=SELECT ‘x‘
cas.druid.database.testWhileIdle= true
cas.druid.database.testOnBorrow=false
cas.druid.database.testOnReturn=false
cas.druid.database.maxOpenPreparedStatements=20
cas.druid.database.removeAbandoned=true
cas.druid.database.removeAbandonedTimeout=1800
cas.druid.database.logAbandoned=true

cas.druid.database.connectionLogEnabled=false
cas.druid.database.statementLogEnabled=false
cas.druid.database.resultSetLogEnabled=true
cas.druid.database.statementExecutableSqlLogEnable=true

 

1.5 web.xml新增druid控制台:

<!-- 连接池 启用 Web 监控统计功能    start-->
<filter>
    <filter-name> DruidWebStatFilter </filter-name>
    <filter-class> com.alibaba.druid.support.http.WebStatFilter </filter-class>
    <init-param >
        <param-name> exclusions </param-name>
        <param-value> *. js ,*. gif ,*. jpg ,*. png ,*. css ,*. ico ,/ druid /* </param-value>
    </init-param>
</filter >
<filter-mapping>
    <filter-name> DruidWebStatFilter </filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
<servlet >
    <servlet-name> DruidStatView </servlet-name>
    <servlet-class> com.alibaba.druid.support.http.StatViewServlet </servlet-class>
</servlet >
<servlet-mapping>
    <servlet-name> DruidStatView </servlet-name>
    <url-pattern>/druid/console/*</url-pattern>
</servlet-mapping>
<!-- 连接池 启用 Web 监控统计功能    end—>

 

1.6 cas-server-webapp\\src\\main\\resources\\log4j2.xml新增druid日志配置

<?xml version="1.0" encoding="UTF-8" ?>
<!-- Specify the refresh internal in seconds. -->
<!-- OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL -->
<Configuration monitorInterval="60">
    <Appenders>
        <Console name="console" target="SYSTEM_OUT">
            <PatternLayout pattern="%d %p [%c] - %n&lt;%m&gt;%n"/>
        </Console>
        <RollingFile name="file" fileName="../logs/cas.log" append="true"
                     filePattern="cas-%d{yyyy-MM-dd-HH}-%i.log">
            <PatternLayout pattern="%d %p [%c] - %n&lt;%m&gt;%n"/>
            <Policies>
                <OnStartupTriggeringPolicy />
                <SizeBasedTriggeringPolicy size="10 MB"/>
                <TimeBasedTriggeringPolicy />
            </Policies>
        </RollingFile>
        <RollingFile name="auditlogfile" fileName="../logs/cas_audit.log" append="true"
                     filePattern="cas_audit-%d{yyyy-MM-dd-HH}-%i.log">
            <PatternLayout pattern="%d %p [%c] - %m%n"/>
            <Policies>
                <OnStartupTriggeringPolicy />
                <SizeBasedTriggeringPolicy size="10 MB"/>
                <TimeBasedTriggeringPolicy />
            </Policies>
        </RollingFile>
        <RollingFile name="perfFileAppender" fileName="../logs/perfStats.log" append="true"
                     filePattern="perfStats-%d{yyyy-MM-dd-HH}-%i.log">
            <PatternLayout pattern="%m%n"/>
            <Policies>
                <OnStartupTriggeringPolicy />
                <SizeBasedTriggeringPolicy size="10 MB"/>
                <TimeBasedTriggeringPolicy />
            </Policies>
        </RollingFile>
    </Appenders>
    <Loggers>
        <AsyncLogger  name="org.jasig" level="info" additivity="false" includeLocation="true">
            <AppenderRef ref="console"/>
            <AppenderRef ref="file"/>
        </AsyncLogger>
        <!--不配置appender(输出形式)默认使用AsyncRoot的appender-->
        <AsyncLogger  name="org.springframework" level="warn" />
        <AsyncLogger name="org.springframework.webflow" level="warn" />
        <AsyncLogger name="org.springframework.web" level="warn" />
        <AsyncLogger name="org.pac4j" level="warn" />
        <!--
        <AsyncLogger name="org.opensaml" level="debug" additivity="false"><AppenderRef ref="console"/><AppenderRef ref="file"/></AsyncLogger><AsyncLogger name="org.ldaptive" level="debug" additivity="false"><AppenderRef ref="console"/><AppenderRef ref="file"/></AsyncLogger><AsyncLogger name="com.hazelcast" level="debug" additivity="false"><AppenderRef ref="console"/><AppenderRef ref="file"/></AsyncLogger>
        -->
        <AsyncLogger name="perfStatsLogger" level="info" additivity="false" includeLocation="true">
            <AppenderRef ref="perfFileAppender"/>
        </AsyncLogger>
        <AsyncLogger name="org.jasig.cas.web.flow" level="info" additivity="true" includeLocation="true">
            <AppenderRef ref="file"/>
        </AsyncLogger>
        <AsyncLogger name="org.jasig.inspektr.audit.support" level="info" includeLocation="true">
            <AppenderRef ref="console"/>
            <AppenderRef ref="auditlogfile"/>
            <AppenderRef ref="file"/>
        </AsyncLogger>
        <!--druid连接池信息打印-->
        <AsyncLogger name="druid.sql.Statement" level="debug" additivity="false" includeLocation="true">
            <AppenderRef ref="console"/>
            <AppenderRef ref="file"/>
        </AsyncLogger>
        <!--<AsyncLogger name="druid.sql.DataSource" level="debug" additivity="false" includeLocation="true"><AppenderRef ref="console"/></AsyncLogger><AsyncLogger name="druid.sql.Connection" level="debug" additivity="false" includeLocation="true"><AppenderRef ref="console"/></AsyncLogger>-->
        <!--<AsyncLogger name="druid.sql.ResultSet" level="debug" additivity="false" includeLocation="true"><AppenderRef ref="console"/></AsyncLogger>-->
        <AsyncLogger name="druid.sql" level="error" additivity="false" includeLocation="true">
            <AppenderRef ref="console"/>
        </AsyncLogger>
        <!--根输出配置,输出等级-->
        <!-- OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL -->
        <!--如果上面的日志输出配置了appender,并且输出等级跟根配置有重叠-->
        <!--比如上面配置debug,则两者的info级别以上日志都会在相同的输出appender中(console)输出,也就是说控制台会输出2次-->
        <!--所以尽量根输出配置高一点,比如error等级-->
        <!--如果我们确实有这种需求(不想遵循父类的Appender),可以在自定义配置中加上additivity="false"参数-->
        <AsyncRoot level="info">
            <AppenderRef ref="console"/>
            <AppenderRef ref="file"/>
        </AsyncRoot>
    </Loggers>
</Configuration>

 

1.7 页面样式定制化修改配置:

1.7.1 复制cas-server-webapp\\src\\main\\webapp\\WEB-INF下的view文件夹一份,命名为:view_custom

技术分享

1.7.2 修改cas-server-webapp\\src\\main\\webapp\\WEB-INF\\cas.properties内容:

技术分享

1.7.3 样式文件-修改cas-server-webapp\\src\\main\\resources\\cas-theme-default.properties的内容:

技术分享

4.复制css和js各一份出来,重命名为上面的名字:

技术分享

 

 

2.服务器支持restfull调用登录

cas-server-webapp\\build.gradle 增加依赖:compile project(‘:cas-server-support-rest‘)

cas-server-webapp\\src\\main\\webapp\\WEB-INF\\cas.properties 加长一次性票据有效期:st.timeToKillInSeconds=20 20秒有效

cas单点登录restfull请求登录范例:

参考官方文档:https://apereo.github.io/cas/5.1.x/protocol/REST-Protocol.html

2.1 请求获取TGT

请求方式:POST

head设置:Content-Type: application/x-www-form-urlencoded

范例:{cas服务器地址}/cas/v1/tickets?username=battags&password=password&additionalParam1=paramvalue

demo: http://localhost:8080/cas/v1/tickets?username=admin&password=1234qwer

正确返回:

返回头:

HTTP/1.1 201

Cache-Control: no-store

Location: http://localhost:8080/cas/v1/tickets/TGT-1-fHlelcwDXNYOiFpiiGwnTtyArXD4rjNdtelyBaBaBWWNHHHvav-www.casServer.com

Content-Type: text/html;charset=UTF-8

Content-Length: 376

Date: Mon, 07 Aug 2017 01:42:35 GMT

2.2 拿到TGT,请求一次性票据ST

请求方式:POST

head设置:Content-Type: application/x-www-form-urlencoded

范例:{cas服务器地址}/cas/v1/tickets/{TGT id}?service={form encoded parameter for the service url}

demo:http://localhost:8080/cas/v1/tickets/TGT-1-fHlelcwDXNYOiFpiiGwnTtyArXD4rjNdtelyBaBaBWWNHHHvav-www.casServer.com?service=http%3A%2F%2FcasTest02.com%3A8082%2F

正确返回:

返回头:

HTTP/1.1 200

Cache-Control: no-store

Content-Disposition: inline;filename=f.txt

Content-Type: application/x-msdownload;charset=UTF-8

Content-Length: 43

Date: Mon, 07 Aug 2017 01:45:56 GMT

返回内容:

ST-1-0wjyNMlwOK3kevi5Fa6w-www.casServer.com

2.3 拿着一次性票据,请求服务器验证

请求方式:GET

范例:{cas服务器地址}/cas/p3/serviceValidate?service={service url}&ticket={service ticket}

demo:http://localhost:8080/cas/p3/serviceValidate?ticket=ST-1-0wjyNMlwOK3kevi5Fa6w-www.casServer.com&service=http%3A%2F%2FcasTest02.com%3A8082%2F

正确返回:

<cas:serviceResponse xmlns:cas=‘http://www.yale.edu/tp/cas‘>

<cas:authenticationSuccess>

<cas:user>admin</cas:user>

<cas:attributes>

<cas:longTermAuthenticationRequestTokenUsed>false</cas:longTermAuthenticationRequestTokenUsed>

<cas:isFromNewLogin>true</cas:isFromNewLogin>

<cas:authenticationDate>2017-08-07T10:09:02.521+08:00</cas:authenticationDate>

</cas:attributes>

</cas:authenticationSuccess>

</cas:serviceResponse>

一次性票据过期返回:

<cas:serviceResponse xmlns:cas=‘http://www.yale.edu/tp/cas‘>

<cas:authenticationFailure code=‘INVALID_TICKET‘>

未能够识别出目标 &#039;ST-1-0wjyNMlwOK3kevi5Fa6w-www.casServer.com&#039;票根

</cas:authenticationFailure>

</cas:serviceResponse>


CAS客户端

1.单点登录拦截器配置:web.xml

<!-- ========================单点登录开始 ======================== -->
<!--用于单点退出,该过滤器用于实现单点登出功能,可选配置 -->
<listener>
    <listener-class>org.jasig.cas.client.session.SingleSignOutHttpSessionListener</listener-class>
</listener>
<!--该过滤器用于实现单点登出功能,可选配置。并且需要服务端的cas.properties修改属性:cas.logout.followServiceRedirects=true -->
<filter>
    <filter-name>CASSingle Sign OutFilter</filter-name>
    <filter-class>org.jasig.cas.client.session.SingleSignOutFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>CASSingle Sign OutFilter</filter-name>
    <url-pattern>/*</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>http://localhost:8080/login</param-value>
    </init-param>
    <init-param>
        <param-name>serverName</param-name>
        <param-value>http://casTest01.com:8081</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>CASFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
<!--该过滤器负责对Ticket的校验工作,必须启用它 -->
<filter>
    <filter-name>CASValidationFilter</filter-name>
    <filter-class>
            org.jasig.cas.client.validation.Cas20ProxyReceivingTi<!-- ========================单点登录开始 ======================== -->
<!--用于单点退出,该过滤器用于实现单点登出功能,可选配置 -->
<listener>
    <listener-class>org.jasig.cas.client.session.SingleSignOutHttpSessionListener</listener-class>
</listener>
<!--该过滤器用于实现单点登出功能,可选配置。并且需要服务端的cas.properties修改属性:cas.logout.followServiceRedirects=true -->
<filter>
    <filter-name>CASSingle Sign OutFilter</filter-name>
    <filter-class>org.jasig.cas.client.session.SingleSignOutFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>CASSingle Sign OutFilter</filter-name>
    <url-pattern>/*</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>
    <!--cas server登录地址完整url -->
        <param-value>http://localhost:8080/login</param-value>
    </init-param>
    <init-param>
        <param-name>serverName</param-name>
    <!--用于cas server记录登录的 client访问域名,以及重定向返回 -->
        <param-value>http://casTest01.com:8081</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>CASFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
<!--该过滤器负责对Ticket的校验工作,必须启用它 -->
<filter>
    <filter-name>CASValidationFilter</filter-name>
    <filter-class>
            org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter
        </filter-class>
    <init-param>
        <param-name>casServerUrlPrefix</param-name>
    <!--用于cas server访问域名-->
        <param-value>http://localhost:8080/</param-value>
    </init-param>
    <init-param>
        <param-name>serverName</param-name>
    <!--用于cas client访问域名-->
        <param-value>http://casTest01.com:8081</param-value>
    </init-param>
    <init-param>
        <param-name>encoding</param-name>
        <param-value>UTF-8</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>CASValidationFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 该过滤器负责实现HttpServletRequest请求的包裹, 比如允许开发者通过HttpServletRequest的getRemoteUser()方法获得SSO登录用户的登录名,可选配置。 -->
<filter>
    <filter-name>CASHttpServletRequest WrapperFilter</filter-name>
    <filter-class>
            org.jasig.cas.client.util.HttpServletRequestWrapperFilter
        </filter-class>
</filter>
<filter-mapping>
    <filter-name>CASHttpServletRequest WrapperFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 该过滤器使得开发者可以通过org.jasig.cas.client.util.AssertionHolder来获取用户的登录名。 比如AssertionHolder.getAssertion().getPrincipal().getName()。 -->
<filter>
    <filter-name>CASAssertion Thread LocalFilter</filter-name>
    <filter-class>org.jasig.cas.client.util.AssertionThreadLocalFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>CASAssertion Thread LocalFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
<!-- ========================单点登录结束 ======================== -->
cketValidationFilter
        </filter-class>
    <init-param>
        <param-name>casServerUrlPrefix</param-name>
        <param-value>http://localhost:8080/</param-value>
    </init-param>
    <init-param>
        <param-name>serverName</param-name>
        <param-value>http://casTest01.com:8081</param-value>
    </init-param>
    <init-param>
        <param-name>encoding</param-name>
        <param-value>UTF-8</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>CASValidationFilter</fi<!-- ========================单点登录开始 ======================== -->
<!--用于单点退出,该过滤器用于实现单点登出功能,可选配置 -->
<listener>
    <listener-class>org.jasig.cas.client.session.SingleSignOutHttpSessionListener</listener-class>
</listener>
<!--该过滤器用于实现单点登出功能,可选配置。并且需要服务端的cas.properties修改属性:cas.logout.followServiceRedirects=true -->
<filter>
    <filter-name>CASSingle Sign OutFilter</filter-name>
    <filter-class>org.jasig.cas.client.session.SingleSignOutFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>CASSingle Sign OutFilter</filter-name>
    <url-pattern>/*</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>
    <!--cas server登录地址完整url -->
        <param-value>http://localhost:8080/login</param-value>
    </init-param>
    <init-param>
        <param-name>serverName</param-name>
    <!--用于cas server记录登录的 client访问域名,以及重定向返回 -->
        <param-value>http://casTest01.com:8081</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>CASFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
<!--该过滤器负责对Ticket的校验工作,必须启用它 -->
<filter>
    <filter-name>CASValidationFilter</filter-name>
    <filter-class>
            org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter
        </filter-class>
    <init-param>
        <param-name>casServerUrlPrefix</param-name>
    <!--用于cas server访问域名-->
        <param-value>http://localhost:8080/</param-value>
    </init-param>
    <init-param>
        <param-name>serverName</param-name>
    <!--用于cas client访问域名-->
        <param-value>http://casTest01.com:8081</param-value>
    </init-param>
    <init-param>
        <param-name>encoding</param-name>
        <param-value>UTF-8</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>CASValidationFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 该过滤器负责实现HttpServletRequest请求的包裹, 比如允许开发者通过HttpServletRequest的getRemoteUser()方法获得SSO登录用户的登录名,可选配置。 -->
<filter>
    <filter-name>CASHttpServletRequest WrapperFilter</filter-name>
    <filter-class>
            org.jasig.cas.client.util.HttpServletRequestWrapperFilter
        </filter-class>
</filter>
<filter-mapping>
    <filter-name>CASHttpServletRequest WrapperFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 该过滤器使得开发者可以通过org.jasig.cas.client.util.AssertionHolder来获取用户的登录名。 比如AssertionHolder.getAssertion().getPrincipal().getName()。 -->
<filter>
    <filter-name>CASAssertion Thread LocalFilter</filter-name>
    <filter-class>org.jasig.cas.client.util.AssertionThreadLocalFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>CASAssertion Thread LocalFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
<!-- ========================单点登录结束 ======================== -->
lter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 该过滤器负责实现HttpServletRequest请求的包裹, 比如允许开发者通过HttpServletRequest的getRemoteUser()方法获得SSO登录用户的登录名,可选配置。 -->
<filter>
    <filter-name>CASHttpServletRequest WrapperFilter</filter-name>
    <filter-class>
            org.jasig.cas.client.util.HttpServletRequestWrapperFilter
        </filter-class>
</filter>
<filter-mapping>
    <filter-name>CASHttpServletRequest WrapperFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 该过滤器使得开发者可以通过org.jasig.cas.client.util.AssertionHolder来获取用户的登录名。 比如AssertionHolder.getAssertion().getPrincipal().getName()。 -->
<filter>
    <filter-name>CASAssertion Thread LocalFilter</filter-name>
    <filter-class>org.jasig.cas.client.util.AssertionThreadLocalFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>CASAssertion Thread LocalFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
<!-- ========================单点登录结束 ======================== -->

番外篇!--与shibboleth idp saml2.0 联合配置

1.工作环境准备

1.1 运行基础

jdk8.0.131 tomcat8.5.16 cas-4.2.1(基于gradle) ,shibboleth-identityprovider-2.4.5,win7 64,mysql 5.6.21,花生壳免费域名映射(否则自己需要再下一个shibboleth的sp服务器用于测试)

1.2 ssl配置

tomcat必须配置ssl连接,此tomcat用于启动cas-server和shib-idp(我一个是用idea启动,ssl访问端口设置不同而已),参考上面的《本地tomcat证书生成与配置》

2. 安装shibboleth-identityprovider-2.4.5

参考文档:https://wiki.shibboleth.net/confluence/display/SHIB2/IdPInstall

2.1 添加cas client  包支持

把cas的客户端jar包(cas-client-core-3.4.1.jar)丢到idp解压的lib目录下,例如:D:\\Program Files (x86)\\shibboleth-identityprovider-2.4.5\\lib,这样安装好的idp就会有这个jar包

2.2 执行install.bat安装idp

技术分享

2.3 修改idp的元数据文件

D:\\Program Files (x86)\\shibboleth-idp-server\\metadata\\idp-metadata.xml

这里面的几个idp接口访问端口要改一下,因为我用的花生壳所以端口号是指定好了的,把文件里面的:8443全部替换成空串即可。

 

3.cas-server所需配合部分

上面先告一段落,开始修改cas-server的整合部分:

参考:https://apereo.github.io/cas/4.2.x/integration/Shibboleth.html

3.1  修改idp安装目录配置文件

idp安装目录/conf/handler.xml

把里面的ph:LoginHandler xsi:type="ph:RemoteUser"节点替换成以下内容:

<!-- Remote User handler for CAS support -->
    <ph:LoginHandler xsi:type="ph:RemoteUser">
        <ph:AuthenticationMethod>
            urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified
          </ph:AuthenticationMethod>
        <ph:AuthenticationMethod>
            urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport
          </ph:AuthenticationMethod>
    </ph:LoginHandler>

3.2 修改idp.war包的web.xml文件

 

增加以下内容:

<!-- For CAS client support -->
<context-param>
    <param-name>serverName</param-name>
    <param-value>${idp域名+端口}</param-value>
</context-param>
<!-- CAS client filters -->
<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>${cas服务器域名加端口加项目名}/login</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>CAS Authentication Filter</filter-name>
    <url-pattern>/Authn/RemoteUser</url-pattern>
</filter-mapping>
<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>${cas服务器域名加端口加项目名}</param-value>
    </init-param>
    <init-param>
        <param-name>redirectAfterValidation</param-name>
        <param-value>true</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>CAS Validation Filter</filter-name>
    <url-pattern>/Authn/RemoteUser</url-pattern>
</filter-mapping>
<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>/Authn/RemoteUser</url-pattern>
</filter-mapping>

3.3 cas-server增加saml2.0支持包 cas-server-support-saml-mdui

 

3.4 cas-server-webapp的deployerConfigContext.xml添加:

<!--saml2.0支持-->
<bean id="samlMetadataUIParserAction"
              class="org.jasig.cas.support.saml.web.flow.mdui.SamlMetadataUIParserAction"
              c:entityIdParameterName="entityId"
              c:metadataAdapter-ref="metadataAdapter"/>
<!--元数据配置-->
<bean id="metadataAdapter"
              class="org.jasig.cas.support.saml.web.flow.mdui.StaticMetadataResolverAdapter"
              c:metadataResources-ref="metadataResources"
              p:refreshIntervalInMinutes="300"
              p:requireValidMetadata="true" />
<!--元数据源配置,动态获取idp上的元数据-->
<util:map id="metadataResources">
    <entry key="${完整idp域名https访问地址包括项目名}/entities/">
        <bean class="org.opensaml.saml.metadata.resolver.filter.impl.MetadataFilterChain">
            <property name="filters">
                <list />
            </property>
        </bean>
    </entry>
</util:map>
<!--元数据过滤器配置-->
<bean id="metadataFilters"
              class="org.opensaml.saml.metadata.resolver.filter.impl.MetadataFilterChain">
    <property name="filters">
        <list>
            <!--
                    <bean class="org.opensaml.saml.metadata.resolver.filter.impl.RequiredValidUntilFilter"
                          c:maxValidity="0"  />
                    -->
            <bean class="org.opensaml.saml.metadata.resolver.filter.impl.SignatureValidationFilter"
                          c:engine-ref="trustEngine" p:requireSignature="false"  />
        </list>
    </property>
</bean>
<bean id="trustEngine"
              class="org.opensaml.xmlsec.signature.support.impl.ExplicitKeySignatureTrustEngine"
              c:keyInfoResolver-ref="keyInfoResolver"
              c:resolver-ref="credentialResolver" />
<bean id="keyInfoResolver"
              class="org.opensaml.xmlsec.keyinfo.impl.BasicProviderKeyInfoCredentialResolver">
    <constructor-arg name="keyInfoProviders">
        <list>
            <bean class="org.opensaml.xmlsec.keyinfo.impl.provider.RSAKeyValueProvider" />
            <bean class="org.opensaml.xmlsec.keyinfo.impl.provider.DSAKeyValueProvider" />
            <bean class="org.opensaml.xmlsec.keyinfo.impl.provider.DEREncodedKeyValueProvider" />
            <bean class="org.opensaml.xmlsec.keyinfo.impl.provider.InlineX509DataProvider" />
        </list>
    </constructor-arg>
</bean>
<bean id="credentialResolver"
              class="org.opensaml.security.credential.impl.StaticCredentialResolver"
              c:credential-ref="credentialFactoryBean" />
<bean id="credentialFactoryBean"
              class="net.shibboleth.idp.profile.spring.relyingparty.security.credential.BasicResourceCredentialFactoryBean"
              p:publicKeyInfo="classpath:inc-md-pub.pem" ></bean>

3.5 修改cas-server-webapp的login-webflow.xml内容

在view-state id="viewLoginForm" 节点提交动作新增saml2.0校验,修改大致如下:

<view-state id="viewLoginForm" view="casLoginView" model="credential">
    <binder>
        <binding property="username" required="true"/>
        <binding property="password" required="true"/>
        <!--
            <binding property="rememberMe" />
            -->
    </binder>
    <on-entry>
        <set name="viewScope.commandName" value="‘credential‘"/>
        <!--进入该视图节点时,进行saml2.0元数据校验-->
        <evaluate expression="samlMetadataUIParserAction" />
    </on-entry>
    <transition on="submit" bind="true" validate="true" to="realSubmit"/>
</view-state>

 

 

4.使用testshib作为sp端免费测试

参考教程:https://www.testshib.org/register.html

4.1 将我们的cas-server和idp.war都部署到开启了ssl的tomcat上进行启动吧!然后开启我们的花生壳内网映射!

技术分享

4.2 开始上传idp端元数据文件

 技术分享

4.3 修改idp端的元数据提供者配置

在idp安装目录下找到D:\\Program Files (x86)\\shibboleth-idp-server\\conf\\relying-party.xml

在节点<metadata:MetadataProvider id="ShibbolethMetadata" xsi:type="metadata:ChainingMetadataProvider">内插入testshib的idp元数据提供,插入后是这样子:

<metadata:MetadataProvider id="ShibbolethMetadata" xsi:type="metadata:ChainingMetadataProvider">
    <!-- Load the IdP‘s own metadata.  This is necessary for artifact support. -->
    <metadata:MetadataProvider id="IdPMD" xsi:type="metadata:FilesystemMetadataProvider"
                                   metadataFile="D:\\Program Files (x86)\\shibboleth-idp-server/metadata/idp-metadata.xml"
                                   maxRefreshDelay="P1D" />
    <!--test shib-->
    <metadata:MetadataProvider id="HTTPMetadataTESTSHIB"
                  xsi:type="metadata:FileBackedHTTPMetadataProvider"
                  backingFile="D:\\Program Files (x86)\\shibboleth-idp-server/metadata/testshib-providers.xml"
                  metadataURL="http://www.testshib.org/metadata/testshib-providers.xml"/>

4.4 开始测试

访问测试sp地址:https://sp.testshib.org/,在修改下方的idp访问地址,go!

 

技术分享

技术分享

技术分享

技术分享

技术分享

以上是关于原创apereo cas 4.2从0开始的主要内容,如果未能解决你的问题,请参考以下文章

CAS5.0.X 使用经历

史上最详细的 Apereo CAS 5.3开发教程:二Apereo CAS 5.3 Server环境搭建,登录名,密码从数据库中获取

Apereo CAS - 1

CAS单点登录服务器搭建

CAS 5.x搭建常见问题系列.Failure to find org.apereo.cas:cas-server-support-pm-jdbc:jar:5.1.9

CAS单点登录:开启OAuth2.0协议