1

I have an existing Java/Spring/Hibernate webapp, with a classic database authentication. I just migrated it with success to a Crowd SSO platform. Everything works as expected, but now I would like to configure Spring Security to fallback to my previous authentication system if the Crowd server is down.

I never configured such cascading authentication, and what I read with google didn't help me so far. Do you know how I can achieve that?

Here is my Spring security configuration:

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns:beans="http://www.springframework.org/schema/beans"
         xmlns="http://www.springframework.org/schema/security"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://www.springframework.org/schema/beans
         http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
         http://www.springframework.org/schema/util
         http://www.springframework.org/schema/util/spring-util-3.0.xsd
         http://www.springframework.org/schema/security
         http://www.springframework.org/schema/security/spring-security-3.1.xsd"
         xmlns:util="http://www.springframework.org/schema/util"
         default-autowire="byName">

<http entry-point-ref="crowdAuthenticationProcessingFilterEntryPoint">
    <intercept-url pattern="/**/login" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
    <intercept-url pattern="/**/logout" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
    <intercept-url pattern="/**/login.html" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
    <intercept-url pattern="/admin/**" access="ROLE_ADMINISTRATOR"/>
    <intercept-url pattern="/**" access="ROLE_ADMINISTRATOR"/>
    <custom-filter position="FORM_LOGIN_FILTER" ref="authenticationProcessingFilter"/>
    <custom-filter position="LOGOUT_FILTER" ref="logoutFilter"/>
</http>

<!-- My previous authentication filter -->
<beans:bean id="authenticationFilter"
            class="my.package.security.CustomAuthenticationProcessingFilter">
    <beans:property name="authenticationManager" ref="formAuthenticationManager"/>
    <beans:property name="filterProcessesUrl" value="/login"/>
    <beans:property name="continueChainBeforeSuccessfulAuthentication" value="false"/>
    <beans:property name="postOnly" value="true"/>
    <beans:property name="authenticationSuccessHandler" ref="authenticationHandler"/>
    <beans:property name="authenticationFailureHandler" ref="authenticationHandler"/>
</beans:bean>
<beans:bean id="authenticationHandler" class="my.package.security.CustomAuthenticationHandler">
    <beans:property name="alwaysUseDefaultTargetUrl" value="false"/>
</beans:bean>
<beans:bean id="customAuthenticationProvider"
            class="my.package.security.MyDaoAuthenticationProvider">
    <beans:property name="SaltSource">
        <beans:bean class="org.springframework.security.authentication.dao.ReflectionSaltSource">
            <beans:property name="userPropertyToUse" value="salt"/>
        </beans:bean>
    </beans:property>
</beans:bean>

<!-- Crowd config -->
<beans:bean id="crowdUserDetailsService" class="my.package.security.CustomCrowdUserDetailsServiceImpl">
    <beans:property name="authenticationManager" ref="crowdAuthenticationManager"/>
    <beans:property name="groupMembershipManager" ref="crowdGroupMembershipManager"/>
    <beans:property name="userManager" ref="crowdUserManager"/>
    <beans:property name="authorityPrefix" value=""/>
    <beans:property name="userController" ref="userController"/>
</beans:bean>


<beans:bean id="crowdAuthenticationProvider" class="com.atlassian.crowd.integration.springsecurity.RemoteCrowdAuthenticationProvider">
    <beans:constructor-arg ref="crowdAuthenticationManager"/>
    <beans:constructor-arg ref="httpAuthenticator"/>
    <beans:constructor-arg ref="crowdUserDetailsService"/>
</beans:bean>

<authentication-manager alias="authenticationManager">
    <authentication-provider ref='crowdAuthenticationProvider' />
</authentication-manager>

<beans:bean id="crowdAuthenticationProcessingFilterEntryPoint" class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
    <beans:constructor-arg value="/login.html"/>
</beans:bean>

<beans:bean id="authenticationProcessingFilter" class="com.atlassian.crowd.integration.springsecurity.CrowdSSOAuthenticationProcessingFilter">
    <beans:property name="httpAuthenticator" ref="httpAuthenticator"/>
    <beans:property name="authenticationManager" ref="authenticationManager"/>
    <beans:property name="filterProcessesUrl" value="/login"/>
    <beans:property name="authenticationFailureHandler">
        <beans:bean class="com.atlassian.crowd.integration.springsecurity.UsernameStoringAuthenticationFailureHandler">
            <beans:property name="defaultFailureUrl" value="/login.html?login_error=1"/>
        </beans:bean>
    </beans:property>
    <beans:property name="authenticationSuccessHandler">
        <beans:bean class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler">
            <beans:property name="defaultTargetUrl" value="/flexibility.html"/>
        </beans:bean>
    </beans:property>
</beans:bean>

<beans:bean id="crowdLogoutHandler" class="com.atlassian.crowd.integration.springsecurity.CrowdLogoutHandler">
    <beans:property name="httpAuthenticator" ref="httpAuthenticator"/>
</beans:bean>

<beans:bean id="logoutFilter" class="org.springframework.security.web.authentication.logout.LogoutFilter">
    <beans:constructor-arg value="/login.html"/>
    <beans:constructor-arg>
        <beans:list>
            <beans:ref bean="crowdLogoutHandler"/>
            <beans:bean class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler"/>
        </beans:list>
    </beans:constructor-arg>
    <beans:property name="filterProcessesUrl" value="/logout"/>
</beans:bean>

Kara
  • 6,115
  • 16
  • 50
  • 57
Asterius
  • 2,180
  • 2
  • 19
  • 27

1 Answers1

1

What you need is an authentication manager configured with multiple authentication providers. This gives an example

Community
  • 1
  • 1
6ton
  • 4,174
  • 1
  • 22
  • 37
  • If I add in my , I can see that my DAOProvider is well used (with the debugger), but seems strange that authentication.getDetails() remains an instance of CrowdSSOAuthenticationDetails. And the login still does not work. It seems like the security context is not stored : the response sends the redirect to the after login page, but that new request bring me back to the login page... – Asterius Sep 30 '14 at 15:19
  • Ok, I had to extend Crowd beans to support both authentication modes and made them work together. But I accept your answer since it was the first step to solve my question – Asterius Oct 02 '14 at 11:32