使用CAS和Spring Security进行重定向循环 [英] Redirect loop with CAS and Spring Security
问题描述
我已经在GlassFish 3.1.2.2上设置了CAS 3.5.2服务器,现在我尝试通过遵循官方文档。我的配置:
I've set up a CAS 3.5.2 server on GlassFish 3.1.2.2 and now I am trying to protect a Jersey REST web service with CAS using Spring Security 3.2.0 by following the official documentation. My configuration:
web.xml
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
id="WebApp_ID" version="3.0">
<display-name>springtest</display-name>
<context-param>
<param-name>log4jConfigLocation</param-name>
<param-value>/WEB-INF/log4j.properties</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
</listener>
<!-- - Location of the XML file that defines the root application context
- Applied by ContextLoaderListener. -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/applicationContext-security.xml
</param-value>
</context-param>
<context-param>
<param-name>webAppRootKey</param-name>
<param-value>cas.root</param-value>
</context-param>
<!-- Include the character encoding Filter as per JASIG recommenation when
doing Single Sign Out https://wiki.jasig.org/display/CASC/Configuring+Single+Sign+Out -->
<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- Included to support Single Logout. Note that the SingleSignOutFilter
is included in the springSecurityFilterChain. However, it could also be placed
as the first filter-mapping in the web.xml -->
<listener>
<listener-class>org.jasig.cas.client.session.SingleSignOutHttpSessionListener</listener-class>
</listener>
<!-- - Loads the root application context of this web app at startup. -
The application context is then available via - WebApplicationContextUtils.getWebApplicationContext(servletContext). -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- Jersey Servlet config -->
<servlet>
<description>JAX-RS Tools Generated - Do not modify</description>
<servlet-name>JAX-RS Servlet</servlet-name>
<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>JAX-RS Servlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
applicationContext-security.xml
applicationContext-security.xml
<?xml version="1.0" encoding="UTF-8"?>
<b:beans xmlns:b="http://www.springframework.org/schema/beans"
xmlns="http://www.springframework.org/schema/security" xmlns:p="http://www.springframework.org/schema/p"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<!-- This section is used to configure CAS. The service is the actual redirect
that will be triggered after the CAS login sequence. -->
<b:bean id="serviceProperties" class="org.springframework.security.cas.ServiceProperties">
<b:property name="service" value="https://localhost:8181/springtest/" />
<b:property name="sendRenew" value="false" />
</b:bean>
<!-- this is what hooks up the CAS entry point -->
<b:bean id="exceptionTranslationFilter"
class="org.springframework.security.web.access.ExceptionTranslationFilter">
<b:property name="authenticationEntryPoint">
<b:ref local="casEntryPoint"client />
</b:property>
</b:bean>
<!-- Enable security, let the casAuthenticationEntryPoint handle all intercepted
urls. The CAS_FILTER needs to be in the right position within the filter
chain. -->
<http entry-point-ref="casEntryPoint">
<intercept-url pattern="/**" access="ROLE_USER" />
<custom-filter position="CAS_FILTER" ref="casFilter" />
</http>
<!-- The CAS filter handles the redirect from the CAS server and starts
the ticket validation. -->
<b:bean id="casFilter"
class="org.springframework.security.cas.web.CasAuthenticationFilter">
<b:property name="authenticationManager" ref="authenticationManager" />
</b:bean>
<!-- The entryPoint intercepts all the CAS authentication requests. It redirects
to the CAS loginUrl for the CAS login page. -->
<b:bean id="casEntryPoint"
class="org.springframework.security.cas.web.CasAuthenticationEntryPoint">
<b:property name="loginUrl" value="https://192.168.10.144/cas/login" />
<b:property name="serviceProperties" ref="serviceProperties" />
</b:bean>
<!-- Required for the casProcessingFilter, so define it explicitly set and
specify an Id Even though the authenticationManager is created by default
when namespace based config is used. -->
<authentication-manager alias="authenticationManager">
<authentication-provider ref="casAuthenticationProvider" />
</authentication-manager>
<!-- Handles the CAS ticket processing. -->
<b:bean id="casAuthenticationProvider"
class="org.springframework.security.cas.authentication.CasAuthenticationProvider">
<b:property name="authenticationUserDetailsService">
<b:bean
class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper">
<b:constructor-arg ref="userService" />
</b:bean>
</b:property>
<b:property name="serviceProperties" ref="serviceProperties" />
<b:property name="ticketValidator">
<b:bean class="org.jasig.cas.client.validation.Cas20ServiceTicketValidator">
<b:constructor-arg index="0"
value="https://192.168.10.144/cas" />
</b:bean>
</b:property>
<b:property name="key" value="myCAS" />
</b:bean>
<!-- The users available for this application. -->
<user-service id="userService">
<user name="joe" password="joe" authorities="ROLE_USER" />
</user-service>
</b:beans>
我已确保服务信任CAS服务器的证书,不知道是否相反方向是必要的。以下消息反复循环,直到浏览器无聊:
I've made sure that the service trusts the CAS server's certificate, don't know if the opposite direction is necessary though. The following messages are looped over and over again, until the browser 'gets bored of it':
log4j DEBUG消息
DEBUG [http-thread-pool-8181(4)] (ExceptionTranslationFilter.java:165) - 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)
...
DEBUG [http-thread-pool-8181(4)] (HttpSessionRequestCache.java:41) - DefaultSavedRequest added to Session: DefaultSavedRequest[https://localhost:8181/springtest/?ticket=ST-44-L0mrrGmf3vNFeGXCRkAj]
DEBUG [http-thread-pool-8181(4)] (ExceptionTranslationFilter.java:185) - Calling Authentication entry point.
DEBUG [http-thread-pool-8181(4)] (HttpSessionSecurityContextRepository.java:300) - SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession.
DEBUG [http-thread-pool-8181(4)] (SecurityContextPersistenceFilter.java:97) - SecurityContextHolder now cleared, as request processing completed
DEBUG [http-thread-pool-8181(1)] (FilterChainProxy.java:337) - /?ticket=ST-45-3m2F3CVknJk6Af2u7d26 at position 1 of 9 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
DEBUG [http-thread-pool-8181(1)] (HttpSessionSecurityContextRepository.java:148) - HttpSession returned null object for SPRING_SECURITY_CONTEXT
DEBUG [http-thread-pool-8181(1)] (HttpSessionSecurityContextRepository.java:90) - No SecurityContext was available from the HttpSession: org.apache.catalina.session.StandardSessionFacade@50e4c821. A new one will be created.
DEBUG [http-thread-pool-8181(1)] (FilterChainProxy.java:337) - /?ticket=ST-45-3m2F3CVknJk6Af2u7d26 at position 2 of 9 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
DEBUG [http-thread-pool-8181(1)] (FilterChainProxy.java:337) - /?ticket=ST-45-3m2F3CVknJk6Af2u7d26 at position 3 of 9 in additional filter chain; firing Filter: 'CasAuthenticationFilter'
DEBUG [http-thread-pool-8181(1)] (CasAuthenticationFilter.java:311) - serviceTicketRequest = false
DEBUG [http-thread-pool-8181(1)] (CasAuthenticationFilter.java:362) - proxyReceptorConfigured = false
DEBUG [http-thread-pool-8181(1)] (CasAuthenticationFilter.java:349) - proxyReceptorRequest = false
DEBUG [http-thread-pool-8181(1)] (CasAuthenticationFilter.java:327) - proxyTicketRequest = false
DEBUG [http-thread-pool-8181(1)] (CasAuthenticationFilter.java:262) - requiresAuthentication = false
DEBUG [http-thread-pool-8181(1)] (FilterChainProxy.java:337) - /?ticket=ST-45-3m2F3CVknJk6Af2u7d26 at position 4 of 9 in additional filter chain; firing Filter: 'RequestCacheAwareFilter'
DEBUG [http-thread-pool-8181(1)] (DefaultSavedRequest.java:325) - pathInfo: arg1=/; arg2=/ (property equals)
DEBUG [http-thread-pool-8181(1)] (DefaultSavedRequest.java:331) - queryString: arg1=ticket=ST-44-L0mrrGmf3vNFeGXCRkAj; arg2=ticket=ST-45-3m2F3CVknJk6Af2u7d26 (property not equals)
DEBUG [http-thread-pool-8181(1)] (HttpSessionRequestCache.java:75) - saved request doesn't match
DEBUG [http-thread-pool-8181(1)] (FilterChainProxy.java:337) - /?ticket=ST-45-3m2F3CVknJk6Af2u7d26 at position 5 of 9 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter'
DEBUG [http-thread-pool-8181(1)] (FilterChainProxy.java:337) - /?ticket=ST-45-3m2F3CVknJk6Af2u7d26 at position 6 of 9 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter'
DEBUG [http-thread-pool-8181(1)] (AnonymousAuthenticationFilter.java:102) - Populated SecurityContextHolder with anonymous token: 'org.springframework.security.authentication.AnonymousAuthenticationToken@6faa1b5a: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@ffff6a82: RemoteIpAddress: 127.0.0.1; SessionId: 3e9339134a98fa96a8dd34676e8f; Granted Authorities: ROLE_ANONYMOUS'
DEBUG [http-thread-pool-8181(1)] (FilterChainProxy.java:337) - /?ticket=ST-45-3m2F3CVknJk6Af2u7d26 at position 7 of 9 in additional filter chain; firing Filter: 'SessionManagementFilter'
DEBUG [http-thread-pool-8181(1)] (FilterChainProxy.java:337) - /?ticket=ST-45-3m2F3CVknJk6Af2u7d26 at position 8 of 9 in additional filter chain; firing Filter: 'ExceptionTranslationFilter'
DEBUG [http-thread-pool-8181(1)] (FilterChainProxy.java:337) - /?ticket=ST-45-3m2F3CVknJk6Af2u7d26 at position 9 of 9 in additional filter chain; firing Filter: 'FilterSecurityInterceptor'
DEBUG [http-thread-pool-8181(1)] (AbstractSecurityInterceptor.java:194) - Secure object: FilterInvocation: URL: /?ticket=ST-45-3m2F3CVknJk6Af2u7d26; Attributes: [ROLE_USER]
DEBUG [http-thread-pool-8181(1)] (AbstractSecurityInterceptor.java:310) - Previously Authenticated: org.springframework.security.authentication.AnonymousAuthenticationToken@6faa1b5a: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@ffff6a82: RemoteIpAddress: 127.0.0.1; SessionId: 3e9339134a98fa96a8dd34676e8f; Granted Authorities: ROLE_ANONYMOUS
DEBUG [http-thread-pool-8181(1)] (AffirmativeBased.java:65) - Voter: org.springframework.security.access.vote.RoleVoter@65b46ab9, returned: -1
DEBUG [http-thread-pool-8181(1)] (AffirmativeBased.java:65) - Voter: org.springframework.security.access.vote.AuthenticatedVoter@27cacbd9, returned: 0
似乎因为CASFilter只是没有意识到提供了有效的服务票证。我是否配置错误?
Seems as the CASFilter just does not realize that a valid service ticket is provided. Did I misconfigure something?
推荐答案
似乎您的serviceProperties定义不正确。具体来说,服务必须是由CasAuthenticationFilter监视的URL。。否则,CasAuthenticationFilter将忽略该请求,然后Spring Security要求对该URL进行身份验证并重新请求ST。
It looks like your serviceProperties are not defined correctly. Specifically the service must be a URL that is monitored by the CasAuthenticationFilter. Otherwise, CasAuthenticationFilter ignores the request and then Spring Security requires authentication for the URL and re-requests the ST.
默认情况下,CasAuthenticationFilter处理对/ j_spring_cas_security_check的请求。因此,您可能想要这样的东西:
By default CasAuthenticationFilter processes requests to /j_spring_cas_security_check. So you probably want something like this:
<b:bean id="serviceProperties" class="org.springframework.security.cas.ServiceProperties">
<b:property name="service" value="https://localhost:8181/springtest/j_spring_cas_security_check" />
<b:property name="sendRenew" value="false" />
</b:bean>
这篇关于使用CAS和Spring Security进行重定向循环的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!