views:

245

answers:

2

Typically, when you declare different "<authentication-provider>" for your application (webapp in my case), Spring Security takes care of invoking providers one after another, incase of failure. So, say I have DatabaseAuthenticationProvider and LDAPAuthenticationProvider with DatabaseAuthenticationProvider declared first in the config file, at runtime, DatabaseAuthenticationProvider is invoked first and if authentication fails, LDAPAuthentication is tried. This is cool - However, what I need is a runtime switch.

I would like to have an option of chosing between these two approaches (database based authentication / ldap based authentication) and somehow swith the implementation based on thsi global setting.

How do I do it? Is it even possible with Spring-Security?

+1  A: 

How about writing a delegating AuthenticationProvider that knows how to access your runtime switch and the actual instances of Database/LDAP AuthenticationProvider.

I'm thinking of something like:

public class SwitchingAuthenticationProvider implements AuthenticationProvider
{
    private List<AuthenticationProvider> delegateList;
    private int selectedProvider;

    @Override
    public Authentication authenticate(Authentication authentication)
        throws AuthenticationException
    {
        AuthenticationProvider delegateTo = delegateList.get(selectedProvider);
        return delegateTo.authenticate(authentication);
    }

    ....
}
Matt
@Matt This is good. But, how do I populate that list of authentication providers?
Jay
@Matt I know it is a dumb question, but I am just another Spring newbie.
Jay
Jay, I'll write more later, with some more detail, but you could inject them into your SwitchingAuthenticationProvider as just another spring bean.
Matt
+1  A: 

I will leave how to inject your own custom authentication provider to the other myriad of examples from Googleland and here on StackOverflow. It looks like it has to do with marking a particular bean with the xml. But hopefully I can fill in some of the other details for you.

So you've defined the class somewhat like above and I'll add more of the details that you'll need for Spring (i.e. merge the stuff from above as well.

public class SwitchingAuthenticationProvider implements AuthenticationProvider
{
    ....
    public List<AuthenticationProvider> getProviders() { return delegateList; }
    public void setProviders(List<AuthenticationProvider> providers) {
        this.delegateList = providers;
    }
    ....
}

This will allow you to inject a host of providers using spring:

<bean id="customAuthProvider1" class=".....CustomProvider1"> ... </bean>
<bean id="customAuthProvider2" class=".....CustomProvider2"> ... </bean>
...
<bean id="customAuthProviderX" class=".....CustomProviderX"> ... </bean>

<bean id="authenticationProvider" class="....SwitchingAuthenticationProvider">
    <security:custom-authentication-provider/>
    <!-- using property injection (get/setProviders) in the bean class -->
    <property name="providers">
        <list>
            <ref local="customAuthProvider1"/> <!-- Ref of 1st authenticator -->
            <ref local="customAuthProvider2"/> <!-- Ref of 2nd authenticator -->
            ...
            <ref local="customAuthProviderX"/> <!-- and so on for more -->
        </list>
    </property>
</bean>

In the end how you populate the providers could be any means of getting the delegator a collection of providers. How they map up to which one to use is up to you. The collection could be a named mapped, based on the current state of the delegator. It could be a list of more than one to try. It could be two properties, "get/setPrimary" and "get/setSecondary" for fail-over like functionality. Once you have the delegator injected the possibilities are up to you.

Let me know if this isn't answering your question.

Matt
@Matt Thank you. This helps. I will try this out and let you know.
Jay