Supporting multiple security providers is a valuable feature. There are several common use cases where this is quite beneficial.
Let's explore these scenarios in more detail.
One very handy use case is where you want to migrate users from an old login system to a new one. For example, your project may have several tools that have all been using their own custom database solution. However, you finally want to centralize everyone's details in a common LDAP server. With both systems keyed up, as new users are issued new credentials, they can log in with no interruption of service. Once everyone has been migrated, you can remove the old security provider.
It also makes it easy to have redundant security providers, such as having more than one LDAP URL to point at.
Earlier, we saw the configuration for an AuthenticationManager
that looked like this:
@Object def auth_manager(self): auth_manager = AuthenticationManager() auth_manager.auth_providers = [self.auth_provider()] return auth_manager
AuthenticationManager
supports a list of providers. It will iterate over each one until a successful match is made. To support the migration use case, it can be altered to look like this:
@Object def auth_manager(self): auth_manager = AuthenticationManager() auth_manager.auth_providers = [ self.old_auth_provider(), self.new_auth_provider()] return auth_manager
With this setup, our system will first try to use the old authentication provider. However, if it fails, Spring Python Security will try the new authentication provider.
It is possible our application may have to support multiple users. Imagine we had developed our application and had complete Spring Python Security configuration as well, handling users based on a DatabaseUserDetailsService
. Some time after that, our company acquires another company, bringing on board many new employees that need access to the system. It might be too much effort to migrate them into the new system. Or at least, it might be too expensive. Instead, it would be much easier to configure another authentication provider to point at their current system. The only other feature needed would be to add the extra roles from the new users to the access decision manager.
The solution would look much like the previous use case. The company can now easily decide whether to continue in this fashion, or start a migration of the new users into the already existing system as shown in the previous use case.
We just recently walked through configuring security access to an LDAP server. In the current version of Spring Python, it only supports one URL. To handle two LDAP servers in a redundant solution, all you have to do is configure two instances of each and then plug them in to the AuthenticationManager
.
from springpython.config import PythonConfig from springpython.config import Object from springpython.security.providers.Ldap import * class LdapAppContext(PythonConfig): def __init__(self): super(LdapAppContext, self).__init__() @Object def auth_manager(self): auth_manager = AuthenticationManager() auth_manager.auth_providers = [ self.auth_provider1(), self.auth_provider2()] return auth_manager @Object def auth_provider1(self): provider = LdapAuthenticationProvider() provider.ldap_authenticator = self.authenticator1() provider.ldap_authorities_populator = self.authorities_populator1() return provider @Object def auth_provider2(self): provider = LdapAuthenticationProvider() provider.ldap_authenticator = self.authenticator2() provider.ldap_authorities_populator = self.authorities_populator2() return provider @Object def context1(self): return DefaultSpringSecurityContextSource( url="ldap://server1:53389/dc=springpythonbook,dc=com") @Object def context2(self): return DefaultSpringSecurityContextSource( url="ldap://server2:53389/dc=springpythonbook,dc=com") @Object def authenticator1(self): return BindAuthenticator( context_source=self.context1(), user_dn_patterns="uid={0},ou=people") @Object def authenticator2(self): return BindAuthenticator( context_source=self.context2(), user_dn_patterns="uid={0},ou=people") @Object def authorities_populator1(self): return DefaultLdapAuthoritiesPopulator( context_source=self.context1(), group_search_base="ou=groups") @Object def authorities_populator2(self): return DefaultLdapAuthoritiesPopulator( context_source=self.context2(), group_search_base="ou=groups")
While it is possible Spring Python will eventually support multiple URLs, the ability to combine existing components gives you an already working solution right now.
3.138.204.96