四天了,终于把Spring Security CAS 实例搞定,迫不及待的把过程中遇到的问题记录一下!
本实例实现:1、与CAS Server 实现认证;2、支持Proxy Ticket获取;3、支持通过Proxy Ticket 认证;
具体的配置请见《Spring Security Reference-29. CAS Authentication》
一、问题排除
1、CAS Server 搭建
现在http://www.ja-sig.org/cas自动跳转到https://www.apereo.org/ ,最新版CAS 3.5.3 Release与CAS 4.0.1 Release中不包含二进制的war包,而是要自行生成,具体参考:《sso-cas全攻略(java版)------部署cas server端应用》
2、Maven添加依赖spring-security-cas后,启动报错:NoSuchMethodError: org.slf4j.helpers.Util.report
原因:log系统桥接问题,spring-security-cas中应用logback作为log工具而,本实例应用log4j,存在log系统桥接问题。关于log桥接相关信息可参考:《Java Log 系统介绍以及切换》
解决方案:把spring-security-cas中与log相关的配置都排除掉
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-cas</artifactId>
<version>${org.springframework-security-version}</version>
<exclusions>
<!-- Exclude Commons Logging in favor of SLF4j -->
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
<!-- Exclude logback in favor of Log4j -->
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
</exclusion>
<exclusion>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</exclusion>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
</exclusion>
</exclusions>
</dependency>
3、spring-security-cas排除log相关依赖后,运行报错:java.lang.ClassNotFoundException: org.w3c.dom.ElementTraversal原因:未明
解决方案:添加maven 依赖
<dependency>
<groupId>xml-apis</groupId>
<artifactId>xml-apis</artifactId>
<version>1.4.01</version>
</dependency>
4、启动报错:java.lang.ClassNotFoundException: net.sf.ehcache.Ehcache
原因:spring-security-cas的pom关于ehcache的定义带 <optional>true</optional>,所以ehcache需要额外引入
解决方案:在pom文件中添加
<!-- need to suport cache -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${org.springframework-security-version}</version>
</dependency>
<!-- cache -->
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>2.9.0</version>
</dependency>
5、启动报错:java.lang.NullPointerException at net.sf.ehcache.Cache.initialise(Cache.java:1083)
原因:《Spring Security Reference-29. CAS Authentication》坑爹,casAuthenticationProvider的statelessTicketCache属性中缺少cacheManager的定义。
解决方案:
<beans:property name="statelessTicketCache">
<beans:bean
class="org.springframework.security.cas.authentication.EhCacheBasedTicketCache">
<beans:property name="cache">
<beans:bean class="net.sf.ehcache.Cache" init-method="initialise"
destroy-method="dispose">
<beans:constructor-arg value="casTickets" />
<beans:constructor-arg value="50" />
<beans:constructor-arg value="true" />
<beans:constructor-arg value="false" />
<beans:constructor-arg value="3600" />
<beans:constructor-arg value="900" />
<span style="color:#ff0000;"><beans:property name="cacheManager">
<beans:bean
class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" />
</beans:property></span>
</beans:bean>
</beans:property>
</beans:bean>
</beans:property>
5、获取proxyTicket返回为null
通过如下代码获取proxyTicket返回为空,把spring-security-cas代码都翻了一遍后,发现当前的配置没有错,问题出在Cas Server,返回的认证成功信息中未包含proxyGrantingTicket,看来是需要把Cas Server代码再翻一遍了。
原因:CAS Server返回的认证成功信息中未包含proxyGrantingTicket,进一步的原因未明
解决方案:待~~~~~
二、定义的CAS(在Spring Context中)
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
<span style="white-space:pre"> </span>xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<span style="white-space:pre"> </span>xsi:schemaLocation="http://www.springframework.org/schema/beans
<span style="white-space:pre"> </span> http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
<span style="white-space:pre"> </span> http://www.springframework.org/schema/security
<span style="white-space:pre"> </span> http://www.springframework.org/schema/security/spring-security.xsd">
<span style="white-space:pre"> </span><beans:bean id="serviceProperties"
<span style="white-space:pre"> </span>class="org.springframework.security.cas.ServiceProperties">
<span style="white-space:pre"> </span><beans:property name="service"
<span style="white-space:pre"> </span>value="http://localhost:9080/demo/login/cas" />
<span style="white-space:pre"> </span><beans:property name="sendRenew" value="false" />
<span style="white-space:pre"> </span><beans:property name="authenticateAllArtifacts" value="true" />
<span style="white-space:pre"> </span></beans:bean>
<span style="white-space:pre"> </span><beans:bean id="pgtStorage"
<span style="white-space:pre"> </span>class="org.jasig.cas.client.proxy.ProxyGrantingTicketStorageImpl" />
<span style="white-space:pre"> </span><http entry-point-ref="casEntryPoint">
<span style="white-space:pre"> </span><intercept-url pattern="/security/index" access="hasRole('ADMIN')" />
<span style="white-space:pre"> </span><custom-filter position="CAS_FILTER" ref="casFilter" />
<span style="white-space:pre"> </span><csrf disabled="true" />
<span style="white-space:pre"> </span></http>
<span style="white-space:pre"> </span><global-method-security pre-post-annotations="enabled" />
<span style="white-space:pre"> </span><beans:bean id="casFilter"
<span style="white-space:pre"> </span>class="org.springframework.security.cas.web.CasAuthenticationFilter">
<span style="white-space:pre"> </span><beans:property name="authenticationManager" ref="casAuthenticationManager" />
<span style="white-space:pre"> </span><beans:property name="proxyGrantingTicketStorage" ref="pgtStorage" />
<span style="white-space:pre"> </span><beans:property name="proxyReceptorUrl" value="/login/cas/proxyreceptor" />
<span style="white-space:pre"> </span><beans:property name="serviceProperties" ref="serviceProperties" />
<span style="white-space:pre"> </span><beans:property name="authenticationDetailsSource">
<span style="white-space:pre"> </span><beans:bean
<span style="white-space:pre"> </span>class="org.springframework.security.cas.web.authentication.ServiceAuthenticationDetailsSource">
<span style="white-space:pre"> </span><beans:constructor-arg ref="serviceProperties" />
<span style="white-space:pre"> </span></beans:bean>
<span style="white-space:pre"> </span></beans:property>
<span style="white-space:pre"> </span></beans:bean>
<span style="white-space:pre"> </span><beans:bean id="casEntryPoint"
<span style="white-space:pre"> </span>class="org.springframework.security.cas.web.CasAuthenticationEntryPoint">
<span style="white-space:pre"> </span><beans:property name="loginUrl" value="https://localhost:8443/cas/login" />
<span style="white-space:pre"> </span><beans:property name="serviceProperties" ref="serviceProperties" />
<span style="white-space:pre"> </span></beans:bean>
<span style="white-space:pre"> </span><authentication-manager alias="casAuthenticationManager">
<span style="white-space:pre"> </span><authentication-provider ref="casAuthenticationProvider" />
<span style="white-space:pre"> </span></authentication-manager>
<span style="white-space:pre"> </span><beans:bean id="casAuthenticationProvider"
<span style="white-space:pre"> </span>class="org.springframework.security.cas.authentication.CasAuthenticationProvider">
<span style="white-space:pre"> </span><beans:property name="authenticationUserDetailsService">
<span style="white-space:pre"> </span><beans:bean
<span style="white-space:pre"> </span>class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper">
<span style="white-space:pre"> </span><beans:constructor-arg ref="myUserDetailsService" />
<span style="white-space:pre"> </span></beans:bean>
<span style="white-space:pre"> </span></beans:property>
<span style="white-space:pre"> </span><beans:property name="serviceProperties" ref="serviceProperties" />
<span style="white-space:pre"> </span><beans:property name="ticketValidator">
<span style="white-space:pre"> </span><beans:bean
<span style="white-space:pre"> </span>class="org.jasig.cas.client.validation.Cas20ProxyTicketValidator">
<span style="white-space:pre"> </span><beans:constructor-arg value="https://localhost:8443/cas" />
<span style="white-space:pre"> </span><beans:property name="proxyCallbackUrl"
<span style="white-space:pre"> </span>value="http://localhost:9080/demo/login/cas/proxyreceptor" />
<span style="white-space:pre"> </span><beans:property name="proxyGrantingTicketStorage"
<span style="white-space:pre"> </span>ref="pgtStorage" />
<span style="white-space:pre"> </span><beans:property name="acceptAnyProxy" value="true" />
<span style="white-space:pre"> </span></beans:bean>
<span style="white-space:pre"> </span></beans:property>
<span style="white-space:pre"> </span><beans:property name="key"
<span style="white-space:pre"> </span>value="an_id_for_this_auth_provider_only" />
<span style="white-space:pre"> </span><beans:property name="statelessTicketCache">
<span style="white-space:pre"> </span><beans:bean
<span style="white-space:pre"> </span>class="org.springframework.security.cas.authentication.EhCacheBasedTicketCache">
<span style="white-space:pre"> </span><beans:property name="cache">
<span style="white-space:pre"> </span><beans:bean class="net.sf.ehcache.Cache" init-method="initialise"
<span style="white-space:pre"> </span>destroy-method="dispose">
<span style="white-space:pre"> </span><beans:constructor-arg value="casTickets" />
<span style="white-space:pre"> </span><beans:constructor-arg value="50" />
<span style="white-space:pre"> </span><beans:constructor-arg value="true" />
<span style="white-space:pre"> </span><beans:constructor-arg value="false" />
<span style="white-space:pre"> </span><beans:constructor-arg value="3600" />
<span style="white-space:pre"> </span><beans:constructor-arg value="900" />
<span style="white-space:pre"> </span><beans:property name="cacheManager">
<span style="white-space:pre"> </span><beans:bean
<span style="white-space:pre"> </span>class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean" />
<span style="white-space:pre"> </span></beans:property>
<span style="white-space:pre"> </span></beans:bean>
<span style="white-space:pre"> </span></beans:property>
<span style="white-space:pre"> </span></beans:bean>
<span style="white-space:pre"> </span></beans:property>
<span style="white-space:pre"> </span></beans:bean>
<span style="white-space:pre"> </span><beans:bean id="myUserDetailsService"
<span style="white-space:pre"> </span>class="com.winssage.spring.security.userdetails.WinssageUserDetailsService">
<span style="white-space:pre"> </span><!-- <beans:property name="bcryptPasswordEncoder" ref="bcryptEncoder" /> -->
<span style="white-space:pre"> </span></beans:bean>
</beans:beans>