View Full Version : Curious about chaining authentication providers
crazeinc
Dec 28th, 2004, 04:25 PM
I'm wondering if you could chain the providers together so if the username isn't found in the first provider, it would look in the second provider and so on before it throws a bad credentials exception.
For example. I have a ldap provider that does 99% of the authentication, but I would like to be able to add users to the app without adding them to ldap in certain instances (using the inMemoryDaoImpl). Is there a simple way of doing this, loosely coupled, so the other providers don't know about each other?
Ben Alex
Dec 28th, 2004, 11:58 PM
Yes, it surely does. Basically your competing AuthenticationProviders should each return true to the support(Class) method, but can return null OR a valid Authentication when authenticate(Authentication) is called. If they return null, the next supporting AuthenticationProvider will be tried.
See the JavaDocs for AuthenticationProvider.authenticate(Authentication ) for more details.
crazeinc
Dec 29th, 2004, 12:19 PM
sounds great, thanks, i'll give it a shot.
crazeinc
Jan 3rd, 2005, 02:11 AM
Yes, it surely does. Basically your competing AuthenticationProviders should each return true to the support(Class) method, but can return null OR a valid Authentication when authenticate(Authentication) is called. If they return null, the next supporting AuthenticationProvider will be tried.
See the JavaDocs for AuthenticationProvider.authenticate(Authentication ) for more details.
I'm kinda stratching my head how you return null from provider.authenticate(authentication) without throwing a null-pointer exception?
Ben Alex
Jan 3rd, 2005, 02:02 PM
See CasAuthenticationProvider, where it only authenticates requests containing a CAS_STATEFUL/STATELESS_IDENTIFIER:
if (!supports(authentication.getClass())) {
return null;
}
if (authentication instanceof UsernamePasswordAuthenticationToken
&& (!CasProcessingFilter.CAS_STATEFUL_IDENTIFIER.equa ls(
authentication.getPrincipal().toString())
&& !CasProcessingFilter.CAS_STATELESS_IDENTIFIER.equa ls(
authentication.getPrincipal().toString()))) {
// UsernamePasswordAuthenticationToken not CAS related
return null;
}
If all the AuthenticationProviders do not support a given Authentication, or return null to it, the ProviderManager will throw a ProviderNotFoundException back to the class that called the AuthenticationManager. Thus the calling class never needs to worry about receiving a NullPointerException.
af6140
Jan 11th, 2005, 12:21 PM
What was discussed above is for chaining different types of AuthenticationProvider, how about chaining the same type of AuthenticationProvider?
Ben Alex
Jan 14th, 2005, 03:43 PM
You can chain the same AuthenticationProvider class (but different beans) if you like. Returning null will simply cause the next bean to be polled, until finally one returns a populated Authentication.
None of the Acegi Security AuthenticationProviders are designed to have multiple instances of the same class polled by the same ProviderManager. So you'd need to write your own AuthenticationProvider to do this.
If you say had two databases containing your users, your better approach would be to write a ProviderAuthenticationDao. It would accept a list of AuthenticationDaos. As each returned UsernameNotFoundException, the next would be polled. That would probably be a cleaner approach to this sort of requirement.
sayeed
Feb 1st, 2005, 01:35 AM
I have started exploring the Acegi framework since yesterday. I am really excited with being able to use such a powerful framework with such little effort. I am planning to chain a series of authentication providers using the ProviderManager bean.
Something like this:
<bean id="authenticationManager" class="net.sf.acegisecurity.providers.ProviderManager">
<property name="providers">
<list>
<ref bean="XxxDaoAuthenticationProvider"/>
<ref bean="YyyDaoAuthenticationProvider"/>
</list>
</property>
</bean>
The default net.sf.acegisecurity.providers.dao.DaoAuthenticati onProvider implementation suits my purpose.
But this is where I am getting stuck. Chaining is not happenning if I throw a UsernameNotFoundException in the AuthenticationDao wired to XxxDaoAuthenticationManager. Further, I am not allowed to return a null UserDetails object from the loadUserByUsername() method (violates contract).
The question is: Being a greenhorn, am I missing something OR should I implement my own version of DaoAuthenticationProvider to return a null Authentication object?
Ben Alex
Feb 4th, 2005, 03:04 AM
If the DaoAuthenticationProvider model suits your needs, you simply would have one DaoAuthenticationProvider instance and a custom/fronting AuthenticationDao wired to it.
As mentioned previously, the one custom/fronting AuthenticationDao would be responsible for polling your series of concrete AuthenticationDao beans. The AuthenticationDao beans can thus throw the UsernameNotFoundException, instructing the custom/fronting AuthenticationDao to try the next one.
Does that make sense? Or is there some reason why this would not work in your particular environment?
tigger
Feb 15th, 2005, 06:48 PM
I am trying to get "chaining" to work with first an in memory lookup then a user database lookup.
Have set up the databased users to utilise a PasswordEncoder and a SaltSource (the primary key for the user) using the information suggested elsewhere on this board.
Both sets of users now authenticate fine separately. But when I put them together using a custom AuthenticationDao implementation that loops over the list of AuthenticationDao implementations (two in this case) as suggested above, I realised that there was a problem with the fact that the DaoAuthenticationProvider accepted a single SaltSource and PasswordEncoder, rather than getting these at the level of the AuthenticationDao implementing classes themselves (consequently the databased users worked fine, but the in memory ones did not and obviously could not execute the method specified by the getUserPropertyToUse method).
Am I missing something here in assuming that there is no way to separately specify PasswordEncoders and SaltSources for each of these two sets of users?
Or is there an obvious way I could get round this (I guess maybe using a SystemWideSalt and just setting up the username=password,ROLE list in the applicationContent.xml with encoded passwords)?
(The custom AuthenticationDao implementation iterating over the list of AuthenticationDaos works fine when I don't utilise a PasswordEncoder (or SaltSource), allowing authentication of users from either set: in memory or database... so that bit seems to be fine.)
Thank you...
Ben Alex
Feb 16th, 2005, 08:27 PM
Why not just encode your passwords using the correct encoder and salt? That way when they're in the IoC contanier XML file, they're no longer in cleartext. It should be trivial to write an application or unit test that uses the classes included with Acegi Security to do a one-off encoding of the passwords. You then just use those encoded passwords in the InMemoryDaoImpl declaration.
jagarciaga
Jun 21st, 2005, 05:01 PM
I had the same problem, and used succesfully the custom/fronting AuthenticationDao approach. It works fine. I wonder if such a custom dao is worth being included in the core spring api.
sprite1982
Apr 16th, 2007, 09:34 AM
hi
i'm using acegi
i want to have an idea how to use a db mysql whith acegisecurity
please a clear example because i'm blocked
what we can put in the directory lib, class, the web.xml, acegi context.xml..;
please i need a help.
Powered by vBulletin® Version 4.2.1 Copyright © 2013 vBulletin Solutions, Inc. All rights reserved.