Reputation: 709
I've been configuring SSO solution using CAS for existing application with Spring Security integrated. I went through many answers on Stackoverflow but unfortunately anyone could help me. Could you please assist me with this issue from perspective of my configuration? Thank you in advance!
Here is my core security configuration:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:security="http://www.springframework.org/schema/security"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd">
<description>This context sets up security configurations of the core module.</description>
<!-- Enabled support for @Secured annotations on Spring bean methods -->
<security:global-method-security secured-annotations="enabled"
access-decision-manager-ref="accessDecisionManager"/>
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider ref="casAuthenticationProvider"/>
</security:authentication-manager>
<bean id="casAuthenticationProvider" class="org.springframework.security.cas.authentication.CasAuthenticationProvider">
<property name="authenticationUserDetailsService">
<bean class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper">
<constructor-arg ref="userDetailsService"/>
</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"/>
</bean>
</property>
<property name="key" value="an_id_for_this_auth_provider_only"/>
</bean>
<security:http entry-point-ref="casEntryPoint">
<security:custom-filter ref="casFilter" position="CAS_FILTER"/>
</security:http>
<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="exceptionTranslationFilter"
class="org.springframework.security.web.access.ExceptionTranslationFilter">
<property name="authenticationEntryPoint" ref="casEntryPoint"/>
</bean>
<bean id="serviceProperties" class="org.springframework.security.cas.ServiceProperties">
<property name="service" value="http://localhost:8080/myApp/j_spring_cas_security_check"/>
<property name="sendRenew" value="false"/>
</bean>
<!-- Service that retrieves UserDetails from DB for authentication -->
<bean id="userDetailsService" class="com.xxx.yyy.core.security.userdetails.DefaultUserDetailsService">
<property name="pmUserService" ref="pmUserService"/>
</bean>
<bean class="org.springframework.security.authentication.dao.ReflectionSaltSource" id="randomSaltSource">
<property name="userPropertyToUse" value="salt"/>
</bean>
<bean id="accessDecisionManager" class="org.springframework.security.access.vote.AffirmativeBased">
<property name="decisionVoters">
<!-- At least one voter must agree that the user can access a resource -->
<bean class="org.springframework.security.access.vote.RoleVoter">
<!-- Override the default is 'ROLE_' prefix for role names -->
<property name="rolePrefix">
<util:constant static-field="com.xxx.yyy.core.security.SecurityConstants.AUTHORITY_PREFIX"/>
</property>
</bean>
</property>
</bean>
...and additional security module:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:security="http://www.springframework.org/schema/security"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring- util-3.0.xsd">
<description>This context sets up security configurations of the web module</description>
<import resource="web-security-urls.xml"/>
<!-- Spring Security Filter Chain -->
<bean id="filterChainProxy" class="org.springframework.security.web.FilterChainProxy">
<security:filter-chain-map path-type="ant">
<security:filter-chain pattern="/**"
filters="securityContextPersistenceFilter,
logoutFilter,
authenticationFilter,
anonymousAuthenticationFilter,
exceptionTranslationFilter,
filterSecurityInterceptor"/>
</security:filter-chain-map>
</bean>
<!-- Responsible for propagation of SecurityContext on ThreadLocal from HttpSession -->
<bean id="securityContextPersistenceFilter"
class="org.springframework.security.web.context.SecurityContextPersistenceFilter"/>
<!-- define the logout exit point -->
<bean id="logoutFilter" class="org.springframework.security.web.authentication.logout.LogoutFilter">
<!-- go to login page upon successful logout -->
<constructor-arg value="/"/>
<!-- Classes that get run when a user logs out -->
<constructor-arg>
<list>
<bean class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler"/>
</list>
</constructor-arg>
<property name="filterProcessesUrl" value="/j_spring_security_logout"/>
</bean>
<!-- Enable expression evaluation for Spring Security -->
<bean class="org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler"/>
<bean class="org.springframework.security.web.access.DefaultWebInvocationPrivilegeEvaluator">
<constructor-arg ref="filterSecurityInterceptor"/>
</bean>
And also we have separate module web-security-urls.xml
where o.s.s.web.access.intercept.FilterSecurityInterceptor
is configured to declare secure URLs
Upvotes: 0
Views: 2552
Reputation: 35
I dont know if you still have this problem. I was facing the same and it is nerve-wracking. The issue of infinite redirect results when CasAuthenticationFilter
is not able to determine if the incoming URL ( redirected URL from CAS server ) needs authentication.
if (!requiresAuthentication(request, response)) {
chain.doFilter(request, response);
return;
}
The requires authentication checks if the request is identified as "filterable" URL.
private static final class FilterProcessUrlRequestMatcher implements RequestMatcher {
private final String filterProcessesUrl;
private FilterProcessUrlRequestMatcher(String filterProcessesUrl) {
Assert.hasLength(filterProcessesUrl, "filterProcessesUrl must be specified");
Assert.isTrue(UrlUtils.isValidRedirectUrl(filterProcessesUrl), filterProcessesUrl + " isn't a valid redirect URL");
this.filterProcessesUrl = filterProcessesUrl;
}
public boolean matches(HttpServletRequest request) {
String uri = request.getRequestURI();
int pathParamIndex = uri.indexOf(';');
if (pathParamIndex > 0) {
// strip everything after the first semi-colon
uri = uri.substring(0, pathParamIndex);
}
if ("".equals(request.getContextPath())) {
return uri.endsWith(filterProcessesUrl);
}
return uri.endsWith(request.getContextPath() + filterProcessesUrl);
}
}
With a context path , the check basically checks if the "service URL" ends with request.getContextPath() + filterProcessesUrl
So, URL in the "service" property of ServiceProperties object needs to match to what is provided in filterProcessesUrl. For example :
<bean id="serviceProperties" class="org.springframework.security.cas.ServiceProperties">
<property name="service"
value="https://localhost:9444/SpringSecurity2.5/tbr/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" />
<property name="authenticationSuccessHandler">
<bean
class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler" />
</property>
<property name="filterProcessesUrl" value="/tbr/j_spring_cas_security_check"/>
</bean>
Note the matching pattern for /tbr/j_spring_cas_security_check in both these configurations.
Upvotes: 0
Reputation: 2536
I am not sure if this is the exact problem, but looks like you might be missing a filter url here due to which you are getting a infinite redirect loop.
<bean id="casFilter" class="org.springframework.security.cas.web.CasAuthenticationFilter">
<property name="authenticationManager" ref="authenticationManager"/>
</bean>
you can add the filter url to filter only a particular url pattern
<property name="filterProcessesUrl" value="/j_spring_cas_security_check"/>
This helped me when i was stuck in the same type of problem.
Upvotes: 0