2014-02-21 50 views
1

我已经在GlassFish 3.1.2.2上设置了一个CAS 3.5.2服务器,现在我试图使用Spring Security 3.2.0通过以下the official documentation用CAS保护Jersey REST Web服务。我的配置:用CAS和Spring安全重定向循环

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

<?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服务器的证书,不知道是不是相反的方向尽管如此。下面的消息循环一遍又一遍,直到浏览器“感到厌烦的是”:

的log4j DEBUG消息

DEBUG &#91;http-thread-pool-8181(4)&#93; &#40;ExceptionTranslationFilter.java&#58;165&#41; - 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 &#91;http-thread-pool-8181(4)&#93; &#40;HttpSessionRequestCache.java&#58;41&#41; - DefaultSavedRequest added to Session: DefaultSavedRequest[https://localhost:8181/springtest/?ticket=ST-44-L0mrrGmf3vNFeGXCRkAj] 

DEBUG &#91;http-thread-pool-8181(4)&#93; &#40;ExceptionTranslationFilter.java&#58;185&#41; - Calling Authentication entry point. 

DEBUG &#91;http-thread-pool-8181(4)&#93; &#40;HttpSessionSecurityContextRepository.java&#58;300&#41; - SecurityContext is empty or contents are anonymous - context will not be stored in HttpSession. 

DEBUG &#91;http-thread-pool-8181(4)&#93; &#40;SecurityContextPersistenceFilter.java&#58;97&#41; - SecurityContextHolder now cleared, as request processing completed 

DEBUG &#91;http-thread-pool-8181(1)&#93; &#40;FilterChainProxy.java&#58;337&#41; - /?ticket=ST-45-3m2F3CVknJk6Af2u7d26 at position 1 of 9 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter' 

DEBUG &#91;http-thread-pool-8181(1)&#93; &#40;HttpSessionSecurityContextRepository.java&#58;148&#41; - HttpSession returned null object for SPRING_SECURITY_CONTEXT 

DEBUG &#91;http-thread-pool-8181(1)&#93; &#40;HttpSessionSecurityContextRepository.java&#58;90&#41; - No SecurityContext was available from the HttpSession: [email protected] A new one will be created. 

DEBUG &#91;http-thread-pool-8181(1)&#93; &#40;FilterChainProxy.java&#58;337&#41; - /?ticket=ST-45-3m2F3CVknJk6Af2u7d26 at position 2 of 9 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter' 

DEBUG &#91;http-thread-pool-8181(1)&#93; &#40;FilterChainProxy.java&#58;337&#41; - /?ticket=ST-45-3m2F3CVknJk6Af2u7d26 at position 3 of 9 in additional filter chain; firing Filter: 'CasAuthenticationFilter' 

DEBUG &#91;http-thread-pool-8181(1)&#93; &#40;CasAuthenticationFilter.java&#58;311&#41; - serviceTicketRequest = false 

DEBUG &#91;http-thread-pool-8181(1)&#93; &#40;CasAuthenticationFilter.java&#58;362&#41; - proxyReceptorConfigured = false 

DEBUG &#91;http-thread-pool-8181(1)&#93; &#40;CasAuthenticationFilter.java&#58;349&#41; - proxyReceptorRequest = false 

DEBUG &#91;http-thread-pool-8181(1)&#93; &#40;CasAuthenticationFilter.java&#58;327&#41; - proxyTicketRequest = false 

DEBUG &#91;http-thread-pool-8181(1)&#93; &#40;CasAuthenticationFilter.java&#58;262&#41; - requiresAuthentication = false 

DEBUG &#91;http-thread-pool-8181(1)&#93; &#40;FilterChainProxy.java&#58;337&#41; - /?ticket=ST-45-3m2F3CVknJk6Af2u7d26 at position 4 of 9 in additional filter chain; firing Filter: 'RequestCacheAwareFilter' 

DEBUG &#91;http-thread-pool-8181(1)&#93; &#40;DefaultSavedRequest.java&#58;325&#41; - pathInfo: arg1=/; arg2=/ (property equals) 

DEBUG &#91;http-thread-pool-8181(1)&#93; &#40;DefaultSavedRequest.java&#58;331&#41; - queryString: arg1=ticket=ST-44-L0mrrGmf3vNFeGXCRkAj; arg2=ticket=ST-45-3m2F3CVknJk6Af2u7d26 (property not equals) 

DEBUG &#91;http-thread-pool-8181(1)&#93; &#40;HttpSessionRequestCache.java&#58;75&#41; - saved request doesn't match 

DEBUG &#91;http-thread-pool-8181(1)&#93; &#40;FilterChainProxy.java&#58;337&#41; - /?ticket=ST-45-3m2F3CVknJk6Af2u7d26 at position 5 of 9 in additional filter chain; firing Filter: 'SecurityContextHolderAwareRequestFilter' 

DEBUG &#91;http-thread-pool-8181(1)&#93; &#40;FilterChainProxy.java&#58;337&#41; - /?ticket=ST-45-3m2F3CVknJk6Af2u7d26 at position 6 of 9 in additional filter chain; firing Filter: 'AnonymousAuthenticationFilter' 

DEBUG &#91;http-thread-pool-8181(1)&#93; &#40;AnonymousAuthenticationFilter.java&#58;102&#41; - Populated SecurityContextHolder with anonymous token: 'org.sprin[email protected]6faa1b5a: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.sprin[email protected]ffff6a82: RemoteIpAddress: 127.0.0.1; SessionId: 3e9339134a98fa96a8dd34676e8f; Granted Authorities: ROLE_ANONYMOUS' 

DEBUG &#91;http-thread-pool-8181(1)&#93; &#40;FilterChainProxy.java&#58;337&#41; - /?ticket=ST-45-3m2F3CVknJk6Af2u7d26 at position 7 of 9 in additional filter chain; firing Filter: 'SessionManagementFilter' 

DEBUG &#91;http-thread-pool-8181(1)&#93; &#40;FilterChainProxy.java&#58;337&#41; - /?ticket=ST-45-3m2F3CVknJk6Af2u7d26 at position 8 of 9 in additional filter chain; firing Filter: 'ExceptionTranslationFilter' 

DEBUG &#91;http-thread-pool-8181(1)&#93; &#40;FilterChainProxy.java&#58;337&#41; - /?ticket=ST-45-3m2F3CVknJk6Af2u7d26 at position 9 of 9 in additional filter chain; firing Filter: 'FilterSecurityInterceptor' 

DEBUG &#91;http-thread-pool-8181(1)&#93; &#40;AbstractSecurityInterceptor.java&#58;194&#41; - Secure object: FilterInvocation: URL: /?ticket=ST-45-3m2F3CVknJk6Af2u7d26; Attributes: [ROLE_USER] 

DEBUG &#91;http-thread-pool-8181(1)&#93; &#40;AbstractSecurityInterceptor.java&#58;310&#41; - Previously Authenticated: org.sprin[email protected]6faa1b5a: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.sprin[email protected]ffff6a82: RemoteIpAddress: 127.0.0.1; SessionId: 3e9339134a98fa96a8dd34676e8f; Granted Authorities: ROLE_ANONYMOUS 

DEBUG &#91;http-thread-pool-8181(1)&#93; &#40;AffirmativeBased.java&#58;65&#41; - Voter: [email protected], returned: -1 

DEBUG &#91;http-thread-pool-8181(1)&#93; &#40;AffirmativeBased.java&#58;65&#41; - Voter: [email protected]cbd9, returned: 0 

似乎在CASFilter只是不知道,有效的服务票证提供。我配错了吗?

回答

3

它看起来像你的serviceProperties没有正确定义。特别是the service must be a URL that is monitored by the CasAuthenticationFilter。否则,CasAuthenticationFilter将忽略该请求,然后Spring Security需要对URL进行身份验证并重新请求ST。

默认情况下,CasAuthenticationFilter将请求处理为/ j_spring_cas_security_check。所以,你可能想是这样的:

<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> 
4

刚抬头,在最近的版本中的默认网址现在是/login/cas而不是/j_spring_cas_security_checkhttps://jira.spring.io/browse/SEC-3053

+0

哪个版本SprignSec的是这改变了吗? – Jeef

+0

这为我节省了一天。我正在使用spring-security-cas 4.1.3.RELEASE –

+0

@Jeef它在http://stackoverflow.com/a/35136587/517134解释 –