使用 Spring Security + CAS 获取循环重定向,但应该可以正常工作
Getting a Loop Redirect with Spring Security + CAS, but should be working
我正在尝试将基本应用程序从仅使用 Spring 安全更改为使用 CAS,以启用 SSO。但是我在某处遇到了重定向循环,但我无法找出问题所在。我做了另外两个模拟应用程序,在 CAS 上没有问题,因为它们正在运行。我正在使用 Java 配置代替取自 here 的 XML 配置。我已经为示例尝试了 XML 配置,但我仍然得到相同的结果。
我的猜测是 authenticationManager 有问题,它无法从 Spring 安全性中检测到用户。至少,该日志指示一个 AnonymousUser 并抛出一个 AccessDeniedException。但它适用于其他两个具有相似配置的模拟应用程序(我什至尝试复制它,但错误仍然发生)。几天来我一直在尝试解决此问题,但没有成功,因此我们将不胜感激。我正在使用 Tomcat 8、Spring 4.2 和 Ja-sig CAS 4.0.0,都在 Windows 8.
上
我的网络安全配置:
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private DataSource dataSource;
@Autowired
@Resource(name="CASuserDetailsService")
private AuthenticationUserDetailsService userDetailsService;
@Bean
public ServiceProperties serviceProperties() {
ServiceProperties serviceProperties = new ServiceProperties();
serviceProperties.setService("https://localhost:8443/i9t-YM/j_spring_cas_security_check");
serviceProperties.setSendRenew(false);
return serviceProperties;
}
@Bean
public CasAuthenticationProvider casAuthenticationProvider() {
CasAuthenticationProvider casAuthenticationProvider = new CasAuthenticationProvider();
casAuthenticationProvider.setAuthenticationUserDetailsService(authenticationUserDetailsService());
casAuthenticationProvider.setServiceProperties(serviceProperties());
casAuthenticationProvider.setTicketValidator(cas20ServiceTicketValidator());
casAuthenticationProvider.setKey("some_id_for_this_cas_prov");
return casAuthenticationProvider;
}
@Bean
public AuthenticationUserDetailsService authenticationUserDetailsService() {
return userDetailsService;
}
@Bean
public Cas20ServiceTicketValidator cas20ServiceTicketValidator() {
return new Cas20ServiceTicketValidator("https://localhost:8443/cas");
}
@Bean
public CasAuthenticationFilter casAuthenticationFilter() throws Exception {
CasAuthenticationFilter casAuthenticationFilter = new CasAuthenticationFilter();
casAuthenticationFilter.setAuthenticationManager(authenticationManager());
casAuthenticationFilter.setFilterProcessesUrl("https://localhost:8443/i9t-YM/j_spring_cas_security_check");
return casAuthenticationFilter;
}
@Bean
public CasAuthenticationEntryPoint casAuthenticationEntryPoint() {
CasAuthenticationEntryPoint casAuthenticationEntryPoint = new CasAuthenticationEntryPoint();
casAuthenticationEntryPoint.setLoginUrl("https://localhost:8443/cas/login");
casAuthenticationEntryPoint.setServiceProperties(serviceProperties());
return casAuthenticationEntryPoint;
}
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(casAuthenticationProvider());
//Yes, joe is with a md5 poassword on the database, but i'm using it here as a mockup to see if it works. Also, if there's no ".password", it'll throw an ConstructorCantBeNull or something like that.
auth.inMemoryAuthentication().withUser("joe").password("joe").roles("USER");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.addFilter(casAuthenticationFilter());
http.exceptionHandling().authenticationEntryPoint(casAuthenticationEntryPoint());
http.authorizeRequests().antMatchers("/**").access("hasRole('ROLE_USER')");
// http.authorizeRequests().antMatchers("/resource", "/secure/**").access("hasRole('ROLE_USER')");
// http.authorizeRequests().antMatchers("/resources/**").permitAll();
// http.httpBasic().and().authorizeRequests().antMatchers("/index.html", "/home.html", "/login.html", "/")
// .permitAll().anyRequest().authenticated()
// //.and().addFilterAfter(new CsrfHeaderFilter(), CsrfFilter.class)
// //.csrf().csrfTokenRepository(csrfTokenRepository())
// ;
}
private CsrfTokenRepository csrfTokenRepository() {
HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
repository.setHeaderName("X-XSRF-TOKEN");
return repository;
}
}
TestCasAuthenticationUserDetailsService(请注意,我已尝试通过多种方式使其工作...)
@Service("CASuserDetailsService")
public class TestCasAuthenticationUserDetailsService implements AuthenticationUserDetailsService, UserDetailsService {
@Autowired
private DataSource dataSource;
@Override
public UserDetails loadUserDetails(Authentication token) throws UsernameNotFoundException {
List<GrantedAuthority> authorities = new ArrayList<>();
System.out.println(token.getName());
System.out.println(token.toString());
authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
return new User(token.getName(), token.getName(), authorities);
}
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
List<GrantedAuthority> authorities = new ArrayList<>();
System.out.println(username);
authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
return new User(username, username, authorities);
}
}
我的web.xml:
<servlet>
<servlet-name>springServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring-context.xml
<!-- /WEB-INF/spring-security.xml -->
</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<error-page>
<exception-type>java.lang.Exception</exception-type>
<location>/erro.html</location>
</error-page>
<error-page>
<error-code>404</error-code>
<location>/404.html</location>
</error-page>
<!-- CAS -->
<filter>
<filter-name>CAS-SSO-Filter</filter-name>
<filter-class>org.jasig.cas.client.session.SingleSignOutFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>CAS-SSO-Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<listener>
<listener-class>org.jasig.cas.client.session.SingleSignOutHttpSessionListener</listener-class>
</listener>
<!-- Force SSL -->
<security-constraint>
<web-resource-collection>
<web-resource-name>i9t-YM</web-resource-name>
<url-pattern>/*</url-pattern>
</web-resource-collection>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
来自模拟应用程序的 applicationContext-security.xml:
<security:http auto-config="true" entry-point-ref="casEntryPoint">
<security:intercept-url pattern="/*" access="ROLE_USER" />
<security:custom-filter position="CAS_FILTER"
ref="casFilter" />
</security:http>
<security:user-service id="userService">
<security:user name="joe" authorities="ROLE_USER" />
</security:user-service>
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider
ref="casAuthenticationProvider" />
</security:authentication-manager>
<bean id="serviceProperties" class="org.springframework.security.cas.ServiceProperties">
<property name="service"
value="https://localhost:8443/casTest/j_spring_cas_security_check" />
<property name="sendRenew" value="false" />
</bean>
<bean id="casFilter"
class="org.springframework.security.cas.web.CasAuthenticationFilter">
<property name="authenticationManager" ref="authenticationManager" />
</bean>
<bean id="casEntryPoint"
class="org.springframework.security.cas.web.CasAuthenticationEntryPoint">
<property name="loginUrl" value="https://localhost:8443/cas/login" />
<property name="serviceProperties" ref="serviceProperties" />
</bean>
<bean id="casAuthenticationProvider"
class="org.springframework.security.cas.authentication.CasAuthenticationProvider">
<property name="authenticationUserDetailsService">
<bean
class=" org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper">
<constructor-arg ref="userService" />
</bean>
</property>
<property name="serviceProperties" ref="serviceProperties" />
<property name="ticketValidator">
<bean class="org.jasig.cas.client.validation.Cas20ServiceTicketValidator">
<constructor-arg index="0" value="https://localhost:8443/cas" />
<!-- <property name="proxyGrantingTicketStorage" ref="proxyGrantingTicketStorage" /> -->
<!-- <property name="proxyCallbackUrl" value="https://localhost:8443/cas/secure/receptor" /> -->
</bean>
</property>
<property name="key" value="some_id_for_this_cas_prov" />
</bean>
<bean id="proxyGrantingTicketStorage" class="org.jasig.cas.client.proxy.ProxyGrantingTicketStorageImpl" />
SSL 也适用于他们。
出现循环时记录的错误:
2015-08-27 11:29:59,026 INFO [org.jasig.cas.CentralAuthenticationServiceImpl] - <Granted service ticket [ST-10-yA1U32bOGJ6Gg5HShohm-cas01.example.org] for service [https://localhost:8443/i9t-YM/j_spring_cas_security_check] for user [joe]>
2015-08-27 11:29:59,027 INFO [com.github.inspektr.audit.support.Slf4jLoggingAuditTrailManager] - <Audit trail record BEGIN
=============================================================
WHO: joe
WHAT: ST-10-yA1U32bOGJ6Gg5HShohm-cas01.example.org for https://localhost:8443/i9t-YM/j_spring_cas_security_check
ACTION: SERVICE_TICKET_CREATED
APPLICATION: CAS
WHEN: Thu Aug 27 11:29:59 BRT 2015
CLIENT IP ADDRESS: 0:0:0:0:0:0:0:1
SERVER IP ADDRESS: 0:0:0:0:0:0:0:1
=============================================================
>
/j_spring_cas_security_check?ticket=ST-10-yA1U32bOGJ6Gg5HShohm-cas01.example.org at position 1 of 12 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
/j_spring_cas_security_check?ticket=ST-10-yA1U32bOGJ6Gg5HShohm-cas01.example.org at position 2 of 12 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
HttpSession returned null object for SPRING_SECURITY_CONTEXT
No SecurityContext was available from the HttpSession: org.apache.catalina.session.StandardSessionFacade@1c993da0. A new one will be created.
/j_spring_cas_security_check?ticket=ST-10-yA1U32bOGJ6Gg5HShohm-cas01.example.org at position 3 of 12 in additional filter chain; firing Filter: 'HeaderWriterFilter'
/j_spring_cas_security_check?ticket=ST-10-yA1U32bOGJ6Gg5HShohm-cas01.example.org at position 4 of 12 in additional filter chain; firing Filter: 'CsrfFilter'
/j_spring_cas_security_check?ticket=ST-10-yA1U32bOGJ6Gg5HShohm-cas01.example.org at position 5 of 12 in additional filter chain; firing Filter: 'LogoutFilter'
Request 'GET /j_spring_cas_security_check' doesn't match 'POST /logout
/j_spring_cas_security_check?ticket=ST-10-yA1U32bOGJ6Gg5HShohm-cas01.example.org at position 6 of 12 in additional filter chain; firing Filter: 'CasAuthenticationFilter'
Checking match of request : '/j_spring_cas_security_check'; against 'https://localhost:8443/i9t-ym/j_spring_cas_security_check'
serviceTicketRequest = false
proxyReceptorConfigured = false
proxyReceptorRequest = false
proxyTicketRequest = false
requiresAuthentication = false
/j_spring_cas_security_check?ticket=ST-10-yA1U32bOGJ6Gg5HShohm-cas01.example.org at position 7 of 12 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
pathInfo: both null (property equals)
queryString: arg1=ticket=ST-9-DElbuW6RP24GocThfiBt-cas01.example.org; arg2=ticket=ST-10-yA1U32bOGJ6Gg5HShohm-cas01.example.org (property not equals)
saved request doesn't match
/j_spring_cas_security_check?ticket=ST-10-yA1U32bOGJ6Gg5HShohm-cas01.example.org at position 8 of 12 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
/j_spring_cas_security_check?ticket=ST-10-yA1U32bOGJ6Gg5HShohm-cas01.example.org at position 9 of 12 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
Populated SecurityContextHolder with anonymous token: 'org.springframework.security.authentication.AnonymousAuthenticationToken@905571d8: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@0: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: 0CA64FA23DD44EECC261887599F2541B; Granted Authorities: ROLE_ANONYMOUS'
/j_spring_cas_security_check?ticket=ST-10-yA1U32bOGJ6Gg5HShohm-cas01.example.org at position 10 of 12 in additional filter chain; firing Filter: 'SessionManagementFilter'
/j_spring_cas_security_check?ticket=ST-10-yA1U32bOGJ6Gg5HShohm-cas01.example.org at position 11 of 12 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
/j_spring_cas_security_check?ticket=ST-10-yA1U32bOGJ6Gg5HShohm-cas01.example.org at position 12 of 12 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
Request '/j_spring_cas_security_check' matched by universal pattern '/**'
Secure object: FilterInvocation: URL: /j_spring_cas_security_check?ticket=ST-10-yA1U32bOGJ6Gg5HShohm-cas01.example.org; Attributes: [hasRole('ROLE_USER')]
Previously Authenticated: org.springframework.security.authentication.AnonymousAuthenticationToken@905571d8: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@0: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: 0CA64FA23DD44EECC261887599F2541B; Granted Authorities: ROLE_ANONYMOUS
Voter: org.springframework.security.web.access.expression.WebExpressionVoter@2c4d2096, returned: -1
Access is denied (user is anonymous); redirecting to authentication entry point
org.springframework.security.access.AccessDeniedException: Access is denied
at org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:83)
at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:232)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:123)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:90)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:114)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:122)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:169)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:48)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:205)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:120)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.csrf.CsrfFilter.doFilterInternal(CsrfFilter.java:96)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:91)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:53)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:176)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:219)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:614)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:142)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:617)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:518)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1091)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:668)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1527)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1484)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)
Trying to match using Ant [pattern='/**', GET]
Request '/j_spring_cas_security_check' matched by universal pattern '/**'
Trying to match using NegatedRequestMatcher [requestMatcher=Ant [pattern='/**/favicon.ico']]
Checking match of request : '/j_spring_cas_security_check'; against '/**/favicon.ico'
matches = true
Trying to match using NegatedRequestMatcher [requestMatcher=MediaTypeRequestMatcher [contentNegotiationStrategy=org.springframework.web.accept.ContentNegotiationManager@37c9ddce, matchingMediaTypes=[application/json], useEquals=false, ignoredMediaTypes=[*/*]]]
httpRequestMediaTypes=[text/html, application/xhtml+xml, application/xml;q=0.9, */*;q=0.8]
Processing text/html
application/json .isCompatibleWith text/html = false
Processing application/xhtml+xml
application/json .isCompatibleWith application/xhtml+xml = false
Processing application/xml;q=0.9
application/json .isCompatibleWith application/xml;q=0.9 = false
Processing */*;q=0.8
Ignoring
Did not match any media types
matches = true
Trying to match using NegatedRequestMatcher [requestMatcher=RequestHeaderRequestMatcher [expectedHeaderName=X-Requested-With, expectedHeaderValue=XMLHttpRequest]]
matches = true
All requestMatchers returned true
DefaultSavedRequest added to Session: DefaultSavedRequest[https://localhost:8443/i9t-YM/j_spring_cas_security_check?ticket=ST-10-yA1U32bOGJ6Gg5HShohm-cas01.example.org]
Calling Authentication entry point.
SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
SecurityContextHolder now cleared, as request processing completed
我在这里尝试了其他问题的许多解决方案,但我不知道我是否只是在做一些我看不到的非常愚蠢的事情,或者我是否搞砸了配置。
有什么遗漏的,告诉我,我会补充的。提前致谢!
编辑:它不是从应用程序验证票证,但它应该可以工作。另一个应用程序按预期工作:
2015-08-28 08:44:39,049 INFO [org.jasig.cas.CentralAuthenticationServiceImpl] - <Granted service ticket [ST-44-QmOXrKwachmUcM16DqV4-cas01.example.org] for service [https://localhost:8443/casTest/j_spring_cas_security_check] for user [joe]>
2015-08-28 08:44:39,049 INFO [com.github.inspektr.audit.support.Slf4jLoggingAuditTrailManager] - <Audit trail record BEGIN
=============================================================
WHO: joe
WHAT: ST-44-QmOXrKwachmUcM16DqV4-cas01.example.org for https://localhost:8443/casTest/j_spring_cas_security_check
ACTION: SERVICE_TICKET_CREATED
APPLICATION: CAS
WHEN: Fri Aug 28 08:44:39 BRT 2015
CLIENT IP ADDRESS: 0:0:0:0:0:0:0:1
SERVER IP ADDRESS: 0:0:0:0:0:0:0:1
=============================================================
>
2015-08-28 08:44:39,063 INFO [com.github.inspektr.audit.support.Slf4jLoggingAuditTrailManager] - <Audit trail record BEGIN
=============================================================
WHO: audit:unknown
WHAT: ST-44-QmOXrKwachmUcM16DqV4-cas01.example.org
ACTION: SERVICE_TICKET_VALIDATED
APPLICATION: CAS
WHEN: Fri Aug 28 08:44:39 BRT 2015
CLIENT IP ADDRESS: 127.0.0.1
SERVER IP ADDRESS: 127.0.0.1
=============================================================
>
EDIT2:一个非常奇怪的补充:其他示例应用程序单独使用 servlet,并且正在使用 spring 3.2。现在,我尝试模仿将原始版本复制到此示例,并尝试将其降级直到它起作用。问题是我无法让它在任何 @Controller 注释或类似注释中工作...但是重定向消失了。如果我更新我的 Maven,并从 4.2 升级到 3.2,循环就消失了。但是如果我在 4.2 上,除了版本什么都不改变,那就是循环!
CAS 服务器已将服务票据(ticket
参数)返回给 j_spring_cas_security_check url。它应该工作。在 org.jasig.cas
包上启用 DEBUG 日志以了解 CAS 客户端中发生的情况:服务票据验证是否成功?
因此,"answer" 只是将 Spring 安全性从 4.0.2 降级到 3.2.8。然后我只需要通过评论 spring-security-xml:
再次从 XML 模板更改为 Java 配置
<param-value>
/WEB-INF/spring-context.xml
<!-- /WEB-INF/spring-security.xml -->
</param-value>
不确定这是否是 "actual" 答案,因为我不知道是否有针对 Spring Security 4 的特定配置使其工作不同于 3.2,但自那以后我从 4.2 开始使用的 Spring 功能只是 Spring 的,它们不需要降级即可工作。
pom.xml
<spring.version>4.3.2.RELEASE</spring.version>
<spring.security.version>4.1.3.RELEASE</spring.security.version>
spring-security.xml
<bean id="serviceProperties" class="org.springframework.security.cas.ServiceProperties">
<!-- spring security 3.x -->
<!--
<property name="service" value="http://localhost:8080/j_spring_cas_security_check"/>
-->
<property name="service" value="http://localhost:8080/login/cas"/>
<property name="sendRenew" value="false"/>
</bean>
参考:
Migrating from Spring Security 3.x to 4.x (XML Configuration)
Migrating from Spring Security 3.x to 4.x (Java Configuration)
CasAuthenticationFilter filterProcessesUrl 属性 默认值从“/j_spring_cas_security_check”更改为“/login/cas”。这意味着如果未明确指定 filterProcessesUrl 属性,则需要更新配置。例如,如果使用 Spring Security 3.2.x 的应用程序包含类似于以下的配置:
CasAuthenticationFilter filter = new CasAuthenticationFilter();
filter.setAuthenticationManager(authenticationManager);
当 Spring 安全性 4.x:
时,需要将配置更新为类似于以下内容
xml 配置:
<bean id="casFilter"
class="org.springframework.security.cas.web.CasAuthenticationFilter">
<b:property name="authenticationManager" ref="authenticationManager"/>
<b:property name="filterProcessesUrl" value="/j_spring_cas_security_check"/>
</bean>
java 配置:
CasAuthenticationFilter filter = new CasAuthenticationFilter();
filter.setFilterProcessesUrl("/j_spring_cas_security_check");
filter.setAuthenticationManager(authenticationManager);
或者,可以更新 ServiceProperties 以使用新的默认值:
xml 配置:
<bean id="serviceProperties"
class="org.springframework.security.cas.ServiceProperties">
<property name="service"
value="https://example.com/cas-sample/login/cas"/>
</bean>
java 配置:
ServiceProperties properties = new ServiceProperties();
properties.setService("https://example.com/cas-sample/login/cas");
serviceProperties.setAuthenticateAllArtifacts(true);
自 Spring 安全性 4.x 以来,CAS 的端点从 /j_spring_cas_security_check
更改为 /login/cas
(参见 )
在我的例子中,这个循环是由于 Apache 内部不正确的重写规则造成的。 /login/cas
路径被更改为 /secured/cas
,再次落入安全 url 并因此调用 CAS 登录页面。
我正在尝试将基本应用程序从仅使用 Spring 安全更改为使用 CAS,以启用 SSO。但是我在某处遇到了重定向循环,但我无法找出问题所在。我做了另外两个模拟应用程序,在 CAS 上没有问题,因为它们正在运行。我正在使用 Java 配置代替取自 here 的 XML 配置。我已经为示例尝试了 XML 配置,但我仍然得到相同的结果。 我的猜测是 authenticationManager 有问题,它无法从 Spring 安全性中检测到用户。至少,该日志指示一个 AnonymousUser 并抛出一个 AccessDeniedException。但它适用于其他两个具有相似配置的模拟应用程序(我什至尝试复制它,但错误仍然发生)。几天来我一直在尝试解决此问题,但没有成功,因此我们将不胜感激。我正在使用 Tomcat 8、Spring 4.2 和 Ja-sig CAS 4.0.0,都在 Windows 8.
上我的网络安全配置:
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private DataSource dataSource;
@Autowired
@Resource(name="CASuserDetailsService")
private AuthenticationUserDetailsService userDetailsService;
@Bean
public ServiceProperties serviceProperties() {
ServiceProperties serviceProperties = new ServiceProperties();
serviceProperties.setService("https://localhost:8443/i9t-YM/j_spring_cas_security_check");
serviceProperties.setSendRenew(false);
return serviceProperties;
}
@Bean
public CasAuthenticationProvider casAuthenticationProvider() {
CasAuthenticationProvider casAuthenticationProvider = new CasAuthenticationProvider();
casAuthenticationProvider.setAuthenticationUserDetailsService(authenticationUserDetailsService());
casAuthenticationProvider.setServiceProperties(serviceProperties());
casAuthenticationProvider.setTicketValidator(cas20ServiceTicketValidator());
casAuthenticationProvider.setKey("some_id_for_this_cas_prov");
return casAuthenticationProvider;
}
@Bean
public AuthenticationUserDetailsService authenticationUserDetailsService() {
return userDetailsService;
}
@Bean
public Cas20ServiceTicketValidator cas20ServiceTicketValidator() {
return new Cas20ServiceTicketValidator("https://localhost:8443/cas");
}
@Bean
public CasAuthenticationFilter casAuthenticationFilter() throws Exception {
CasAuthenticationFilter casAuthenticationFilter = new CasAuthenticationFilter();
casAuthenticationFilter.setAuthenticationManager(authenticationManager());
casAuthenticationFilter.setFilterProcessesUrl("https://localhost:8443/i9t-YM/j_spring_cas_security_check");
return casAuthenticationFilter;
}
@Bean
public CasAuthenticationEntryPoint casAuthenticationEntryPoint() {
CasAuthenticationEntryPoint casAuthenticationEntryPoint = new CasAuthenticationEntryPoint();
casAuthenticationEntryPoint.setLoginUrl("https://localhost:8443/cas/login");
casAuthenticationEntryPoint.setServiceProperties(serviceProperties());
return casAuthenticationEntryPoint;
}
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(casAuthenticationProvider());
//Yes, joe is with a md5 poassword on the database, but i'm using it here as a mockup to see if it works. Also, if there's no ".password", it'll throw an ConstructorCantBeNull or something like that.
auth.inMemoryAuthentication().withUser("joe").password("joe").roles("USER");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.addFilter(casAuthenticationFilter());
http.exceptionHandling().authenticationEntryPoint(casAuthenticationEntryPoint());
http.authorizeRequests().antMatchers("/**").access("hasRole('ROLE_USER')");
// http.authorizeRequests().antMatchers("/resource", "/secure/**").access("hasRole('ROLE_USER')");
// http.authorizeRequests().antMatchers("/resources/**").permitAll();
// http.httpBasic().and().authorizeRequests().antMatchers("/index.html", "/home.html", "/login.html", "/")
// .permitAll().anyRequest().authenticated()
// //.and().addFilterAfter(new CsrfHeaderFilter(), CsrfFilter.class)
// //.csrf().csrfTokenRepository(csrfTokenRepository())
// ;
}
private CsrfTokenRepository csrfTokenRepository() {
HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
repository.setHeaderName("X-XSRF-TOKEN");
return repository;
}
}
TestCasAuthenticationUserDetailsService(请注意,我已尝试通过多种方式使其工作...)
@Service("CASuserDetailsService")
public class TestCasAuthenticationUserDetailsService implements AuthenticationUserDetailsService, UserDetailsService {
@Autowired
private DataSource dataSource;
@Override
public UserDetails loadUserDetails(Authentication token) throws UsernameNotFoundException {
List<GrantedAuthority> authorities = new ArrayList<>();
System.out.println(token.getName());
System.out.println(token.toString());
authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
return new User(token.getName(), token.getName(), authorities);
}
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
List<GrantedAuthority> authorities = new ArrayList<>();
System.out.println(username);
authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
return new User(username, username, authorities);
}
}
我的web.xml:
<servlet>
<servlet-name>springServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/spring-context.xml
<!-- /WEB-INF/spring-security.xml -->
</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<error-page>
<exception-type>java.lang.Exception</exception-type>
<location>/erro.html</location>
</error-page>
<error-page>
<error-code>404</error-code>
<location>/404.html</location>
</error-page>
<!-- CAS -->
<filter>
<filter-name>CAS-SSO-Filter</filter-name>
<filter-class>org.jasig.cas.client.session.SingleSignOutFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>CAS-SSO-Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<listener>
<listener-class>org.jasig.cas.client.session.SingleSignOutHttpSessionListener</listener-class>
</listener>
<!-- Force SSL -->
<security-constraint>
<web-resource-collection>
<web-resource-name>i9t-YM</web-resource-name>
<url-pattern>/*</url-pattern>
</web-resource-collection>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
来自模拟应用程序的 applicationContext-security.xml:
<security:http auto-config="true" entry-point-ref="casEntryPoint">
<security:intercept-url pattern="/*" access="ROLE_USER" />
<security:custom-filter position="CAS_FILTER"
ref="casFilter" />
</security:http>
<security:user-service id="userService">
<security:user name="joe" authorities="ROLE_USER" />
</security:user-service>
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider
ref="casAuthenticationProvider" />
</security:authentication-manager>
<bean id="serviceProperties" class="org.springframework.security.cas.ServiceProperties">
<property name="service"
value="https://localhost:8443/casTest/j_spring_cas_security_check" />
<property name="sendRenew" value="false" />
</bean>
<bean id="casFilter"
class="org.springframework.security.cas.web.CasAuthenticationFilter">
<property name="authenticationManager" ref="authenticationManager" />
</bean>
<bean id="casEntryPoint"
class="org.springframework.security.cas.web.CasAuthenticationEntryPoint">
<property name="loginUrl" value="https://localhost:8443/cas/login" />
<property name="serviceProperties" ref="serviceProperties" />
</bean>
<bean id="casAuthenticationProvider"
class="org.springframework.security.cas.authentication.CasAuthenticationProvider">
<property name="authenticationUserDetailsService">
<bean
class=" org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper">
<constructor-arg ref="userService" />
</bean>
</property>
<property name="serviceProperties" ref="serviceProperties" />
<property name="ticketValidator">
<bean class="org.jasig.cas.client.validation.Cas20ServiceTicketValidator">
<constructor-arg index="0" value="https://localhost:8443/cas" />
<!-- <property name="proxyGrantingTicketStorage" ref="proxyGrantingTicketStorage" /> -->
<!-- <property name="proxyCallbackUrl" value="https://localhost:8443/cas/secure/receptor" /> -->
</bean>
</property>
<property name="key" value="some_id_for_this_cas_prov" />
</bean>
<bean id="proxyGrantingTicketStorage" class="org.jasig.cas.client.proxy.ProxyGrantingTicketStorageImpl" />
SSL 也适用于他们。 出现循环时记录的错误:
2015-08-27 11:29:59,026 INFO [org.jasig.cas.CentralAuthenticationServiceImpl] - <Granted service ticket [ST-10-yA1U32bOGJ6Gg5HShohm-cas01.example.org] for service [https://localhost:8443/i9t-YM/j_spring_cas_security_check] for user [joe]>
2015-08-27 11:29:59,027 INFO [com.github.inspektr.audit.support.Slf4jLoggingAuditTrailManager] - <Audit trail record BEGIN
=============================================================
WHO: joe
WHAT: ST-10-yA1U32bOGJ6Gg5HShohm-cas01.example.org for https://localhost:8443/i9t-YM/j_spring_cas_security_check
ACTION: SERVICE_TICKET_CREATED
APPLICATION: CAS
WHEN: Thu Aug 27 11:29:59 BRT 2015
CLIENT IP ADDRESS: 0:0:0:0:0:0:0:1
SERVER IP ADDRESS: 0:0:0:0:0:0:0:1
=============================================================
>
/j_spring_cas_security_check?ticket=ST-10-yA1U32bOGJ6Gg5HShohm-cas01.example.org at position 1 of 12 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
/j_spring_cas_security_check?ticket=ST-10-yA1U32bOGJ6Gg5HShohm-cas01.example.org at position 2 of 12 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
HttpSession returned null object for SPRING_SECURITY_CONTEXT
No SecurityContext was available from the HttpSession: org.apache.catalina.session.StandardSessionFacade@1c993da0. A new one will be created.
/j_spring_cas_security_check?ticket=ST-10-yA1U32bOGJ6Gg5HShohm-cas01.example.org at position 3 of 12 in additional filter chain; firing Filter: 'HeaderWriterFilter'
/j_spring_cas_security_check?ticket=ST-10-yA1U32bOGJ6Gg5HShohm-cas01.example.org at position 4 of 12 in additional filter chain; firing Filter: 'CsrfFilter'
/j_spring_cas_security_check?ticket=ST-10-yA1U32bOGJ6Gg5HShohm-cas01.example.org at position 5 of 12 in additional filter chain; firing Filter: 'LogoutFilter'
Request 'GET /j_spring_cas_security_check' doesn't match 'POST /logout
/j_spring_cas_security_check?ticket=ST-10-yA1U32bOGJ6Gg5HShohm-cas01.example.org at position 6 of 12 in additional filter chain; firing Filter: 'CasAuthenticationFilter'
Checking match of request : '/j_spring_cas_security_check'; against 'https://localhost:8443/i9t-ym/j_spring_cas_security_check'
serviceTicketRequest = false
proxyReceptorConfigured = false
proxyReceptorRequest = false
proxyTicketRequest = false
requiresAuthentication = false
/j_spring_cas_security_check?ticket=ST-10-yA1U32bOGJ6Gg5HShohm-cas01.example.org at position 7 of 12 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
pathInfo: both null (property equals)
queryString: arg1=ticket=ST-9-DElbuW6RP24GocThfiBt-cas01.example.org; arg2=ticket=ST-10-yA1U32bOGJ6Gg5HShohm-cas01.example.org (property not equals)
saved request doesn't match
/j_spring_cas_security_check?ticket=ST-10-yA1U32bOGJ6Gg5HShohm-cas01.example.org at position 8 of 12 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
/j_spring_cas_security_check?ticket=ST-10-yA1U32bOGJ6Gg5HShohm-cas01.example.org at position 9 of 12 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
Populated SecurityContextHolder with anonymous token: 'org.springframework.security.authentication.AnonymousAuthenticationToken@905571d8: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@0: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: 0CA64FA23DD44EECC261887599F2541B; Granted Authorities: ROLE_ANONYMOUS'
/j_spring_cas_security_check?ticket=ST-10-yA1U32bOGJ6Gg5HShohm-cas01.example.org at position 10 of 12 in additional filter chain; firing Filter: 'SessionManagementFilter'
/j_spring_cas_security_check?ticket=ST-10-yA1U32bOGJ6Gg5HShohm-cas01.example.org at position 11 of 12 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
/j_spring_cas_security_check?ticket=ST-10-yA1U32bOGJ6Gg5HShohm-cas01.example.org at position 12 of 12 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
Request '/j_spring_cas_security_check' matched by universal pattern '/**'
Secure object: FilterInvocation: URL: /j_spring_cas_security_check?ticket=ST-10-yA1U32bOGJ6Gg5HShohm-cas01.example.org; Attributes: [hasRole('ROLE_USER')]
Previously Authenticated: org.springframework.security.authentication.AnonymousAuthenticationToken@905571d8: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@0: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: 0CA64FA23DD44EECC261887599F2541B; Granted Authorities: ROLE_ANONYMOUS
Voter: org.springframework.security.web.access.expression.WebExpressionVoter@2c4d2096, returned: -1
Access is denied (user is anonymous); redirecting to authentication entry point
org.springframework.security.access.AccessDeniedException: Access is denied
at org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:83)
at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:232)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:123)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:90)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:114)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:122)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:169)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:48)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:205)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:120)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.csrf.CsrfFilter.doFilterInternal(CsrfFilter.java:96)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:91)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:53)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:176)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:219)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:614)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:142)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:617)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:518)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1091)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:668)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1527)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1484)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)
Trying to match using Ant [pattern='/**', GET]
Request '/j_spring_cas_security_check' matched by universal pattern '/**'
Trying to match using NegatedRequestMatcher [requestMatcher=Ant [pattern='/**/favicon.ico']]
Checking match of request : '/j_spring_cas_security_check'; against '/**/favicon.ico'
matches = true
Trying to match using NegatedRequestMatcher [requestMatcher=MediaTypeRequestMatcher [contentNegotiationStrategy=org.springframework.web.accept.ContentNegotiationManager@37c9ddce, matchingMediaTypes=[application/json], useEquals=false, ignoredMediaTypes=[*/*]]]
httpRequestMediaTypes=[text/html, application/xhtml+xml, application/xml;q=0.9, */*;q=0.8]
Processing text/html
application/json .isCompatibleWith text/html = false
Processing application/xhtml+xml
application/json .isCompatibleWith application/xhtml+xml = false
Processing application/xml;q=0.9
application/json .isCompatibleWith application/xml;q=0.9 = false
Processing */*;q=0.8
Ignoring
Did not match any media types
matches = true
Trying to match using NegatedRequestMatcher [requestMatcher=RequestHeaderRequestMatcher [expectedHeaderName=X-Requested-With, expectedHeaderValue=XMLHttpRequest]]
matches = true
All requestMatchers returned true
DefaultSavedRequest added to Session: DefaultSavedRequest[https://localhost:8443/i9t-YM/j_spring_cas_security_check?ticket=ST-10-yA1U32bOGJ6Gg5HShohm-cas01.example.org]
Calling Authentication entry point.
SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
SecurityContextHolder now cleared, as request processing completed
我在这里尝试了其他问题的许多解决方案,但我不知道我是否只是在做一些我看不到的非常愚蠢的事情,或者我是否搞砸了配置。 有什么遗漏的,告诉我,我会补充的。提前致谢!
编辑:它不是从应用程序验证票证,但它应该可以工作。另一个应用程序按预期工作:
2015-08-28 08:44:39,049 INFO [org.jasig.cas.CentralAuthenticationServiceImpl] - <Granted service ticket [ST-44-QmOXrKwachmUcM16DqV4-cas01.example.org] for service [https://localhost:8443/casTest/j_spring_cas_security_check] for user [joe]>
2015-08-28 08:44:39,049 INFO [com.github.inspektr.audit.support.Slf4jLoggingAuditTrailManager] - <Audit trail record BEGIN
=============================================================
WHO: joe
WHAT: ST-44-QmOXrKwachmUcM16DqV4-cas01.example.org for https://localhost:8443/casTest/j_spring_cas_security_check
ACTION: SERVICE_TICKET_CREATED
APPLICATION: CAS
WHEN: Fri Aug 28 08:44:39 BRT 2015
CLIENT IP ADDRESS: 0:0:0:0:0:0:0:1
SERVER IP ADDRESS: 0:0:0:0:0:0:0:1
=============================================================
>
2015-08-28 08:44:39,063 INFO [com.github.inspektr.audit.support.Slf4jLoggingAuditTrailManager] - <Audit trail record BEGIN
=============================================================
WHO: audit:unknown
WHAT: ST-44-QmOXrKwachmUcM16DqV4-cas01.example.org
ACTION: SERVICE_TICKET_VALIDATED
APPLICATION: CAS
WHEN: Fri Aug 28 08:44:39 BRT 2015
CLIENT IP ADDRESS: 127.0.0.1
SERVER IP ADDRESS: 127.0.0.1
=============================================================
>
EDIT2:一个非常奇怪的补充:其他示例应用程序单独使用 servlet,并且正在使用 spring 3.2。现在,我尝试模仿将原始版本复制到此示例,并尝试将其降级直到它起作用。问题是我无法让它在任何 @Controller 注释或类似注释中工作...但是重定向消失了。如果我更新我的 Maven,并从 4.2 升级到 3.2,循环就消失了。但是如果我在 4.2 上,除了版本什么都不改变,那就是循环!
CAS 服务器已将服务票据(ticket
参数)返回给 j_spring_cas_security_check url。它应该工作。在 org.jasig.cas
包上启用 DEBUG 日志以了解 CAS 客户端中发生的情况:服务票据验证是否成功?
因此,"answer" 只是将 Spring 安全性从 4.0.2 降级到 3.2.8。然后我只需要通过评论 spring-security-xml:
再次从 XML 模板更改为 Java 配置<param-value>
/WEB-INF/spring-context.xml
<!-- /WEB-INF/spring-security.xml -->
</param-value>
不确定这是否是 "actual" 答案,因为我不知道是否有针对 Spring Security 4 的特定配置使其工作不同于 3.2,但自那以后我从 4.2 开始使用的 Spring 功能只是 Spring 的,它们不需要降级即可工作。
pom.xml
<spring.version>4.3.2.RELEASE</spring.version>
<spring.security.version>4.1.3.RELEASE</spring.security.version>
spring-security.xml
<bean id="serviceProperties" class="org.springframework.security.cas.ServiceProperties">
<!-- spring security 3.x -->
<!--
<property name="service" value="http://localhost:8080/j_spring_cas_security_check"/>
-->
<property name="service" value="http://localhost:8080/login/cas"/>
<property name="sendRenew" value="false"/>
</bean>
参考:
Migrating from Spring Security 3.x to 4.x (XML Configuration)
Migrating from Spring Security 3.x to 4.x (Java Configuration)
CasAuthenticationFilter filterProcessesUrl 属性 默认值从“/j_spring_cas_security_check”更改为“/login/cas”。这意味着如果未明确指定 filterProcessesUrl 属性,则需要更新配置。例如,如果使用 Spring Security 3.2.x 的应用程序包含类似于以下的配置:
CasAuthenticationFilter filter = new CasAuthenticationFilter();
filter.setAuthenticationManager(authenticationManager);
当 Spring 安全性 4.x:
时,需要将配置更新为类似于以下内容xml 配置:
<bean id="casFilter"
class="org.springframework.security.cas.web.CasAuthenticationFilter">
<b:property name="authenticationManager" ref="authenticationManager"/>
<b:property name="filterProcessesUrl" value="/j_spring_cas_security_check"/>
</bean>
java 配置:
CasAuthenticationFilter filter = new CasAuthenticationFilter();
filter.setFilterProcessesUrl("/j_spring_cas_security_check");
filter.setAuthenticationManager(authenticationManager);
或者,可以更新 ServiceProperties 以使用新的默认值:
xml 配置:
<bean id="serviceProperties"
class="org.springframework.security.cas.ServiceProperties">
<property name="service"
value="https://example.com/cas-sample/login/cas"/>
</bean>
java 配置:
ServiceProperties properties = new ServiceProperties();
properties.setService("https://example.com/cas-sample/login/cas");
serviceProperties.setAuthenticateAllArtifacts(true);
自 Spring 安全性 4.x 以来,CAS 的端点从 /j_spring_cas_security_check
更改为 /login/cas
(参见
在我的例子中,这个循环是由于 Apache 内部不正确的重写规则造成的。 /login/cas
路径被更改为 /secured/cas
,再次落入安全 url 并因此调用 CAS 登录页面。