diff --git a/config/src/main/java/org/springframework/security/config/BeanIds.java b/config/src/main/java/org/springframework/security/config/BeanIds.java index b81b52fa9b..d2b54dfd56 100644 --- a/config/src/main/java/org/springframework/security/config/BeanIds.java +++ b/config/src/main/java/org/springframework/security/config/BeanIds.java @@ -19,6 +19,7 @@ public abstract class BeanIds { public static final String CONTEXT_SOURCE_SETTING_POST_PROCESSOR = PREFIX + "contextSettingPostProcessor"; public static final String USER_DETAILS_SERVICE = PREFIX + "userDetailsService"; + public static final String USER_DETAILS_SERVICE_FACTORY = PREFIX + "userDetailsServiceFactory"; public static final String METHOD_ACCESS_MANAGER = PREFIX + "defaultMethodAccessManager"; diff --git a/config/src/main/java/org/springframework/security/config/http/AuthenticationConfigBuilder.java b/config/src/main/java/org/springframework/security/config/http/AuthenticationConfigBuilder.java index 4ec4d325e1..875028f447 100644 --- a/config/src/main/java/org/springframework/security/config/http/AuthenticationConfigBuilder.java +++ b/config/src/main/java/org/springframework/security/config/http/AuthenticationConfigBuilder.java @@ -22,8 +22,8 @@ import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.beans.factory.xml.ParserContext; import org.springframework.security.authentication.AnonymousAuthenticationProvider; import org.springframework.security.authentication.RememberMeAuthenticationProvider; +import org.springframework.security.config.BeanIds; import org.springframework.security.config.Elements; -import org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper; import org.springframework.security.web.access.AccessDeniedHandlerImpl; import org.springframework.security.web.access.ExceptionTranslationFilter; import org.springframework.security.web.authentication.AnonymousAuthenticationFilter; @@ -119,7 +119,7 @@ final class AuthenticationConfigBuilder { createX509Filter(authenticationManager); createLogoutFilter(); createLoginPageFilterIfNeeded(); - createUserServiceInjector(); + createUserDetailsServiceFactory(); createExceptionTranslationFilter(); } @@ -237,11 +237,12 @@ final class AuthenticationConfigBuilder { BeanDefinitionBuilder openIDProviderBuilder = BeanDefinitionBuilder.rootBeanDefinition(OPEN_ID_AUTHENTICATION_PROVIDER_CLASS); - String userService = openIDLoginElt.getAttribute(ATT_USER_SERVICE_REF); + RootBeanDefinition uds = new RootBeanDefinition(); + uds.setFactoryBeanName(BeanIds.USER_DETAILS_SERVICE_FACTORY); + uds.setFactoryMethodName("authenticationUserDetailsService"); + uds.getConstructorArgumentValues().addGenericArgumentValue(openIDLoginElt.getAttribute(ATT_USER_SERVICE_REF)); - if (StringUtils.hasText(userService)) { - openIDProviderBuilder.addPropertyReference("userDetailsService", userService); - } + openIDProviderBuilder.addPropertyValue("authenticationUserDetailsService", uds); BeanDefinition openIDProvider = openIDProviderBuilder.getBeanDefinition(); openIDProviderId = pc.getReaderContext().registerWithGeneratedName(openIDProvider); @@ -321,14 +322,12 @@ final class AuthenticationConfigBuilder { Element x509Elt = DomUtils.getChildElementByTagName(httpElt, Elements.X509); BeanDefinition provider = new RootBeanDefinition(PreAuthenticatedAuthenticationProvider.class); - String userServiceRef = x509Elt.getAttribute(ATT_USER_SERVICE_REF); + RootBeanDefinition uds = new RootBeanDefinition(); + uds.setFactoryBeanName(BeanIds.USER_DETAILS_SERVICE_FACTORY); + uds.setFactoryMethodName("authenticationUserDetailsService"); + uds.getConstructorArgumentValues().addGenericArgumentValue(x509Elt.getAttribute(ATT_USER_SERVICE_REF)); - if (StringUtils.hasText(userServiceRef)) { - RootBeanDefinition preAuthUserService = new RootBeanDefinition(UserDetailsByNameServiceWrapper.class); - preAuthUserService.setSource(pc.extractSource(x509Elt)); - preAuthUserService.getPropertyValues().addPropertyValue("userDetailsService", new RuntimeBeanReference(userServiceRef)); - provider.getPropertyValues().addPropertyValue("preAuthenticatedUserDetailsService", preAuthUserService); - } + provider.getPropertyValues().addPropertyValue("preAuthenticatedUserDetailsService", uds); x509ProviderId = pc.getReaderContext().registerWithGeneratedName(provider); x509ProviderRef = new RuntimeBeanReference(x509ProviderId); @@ -527,14 +526,14 @@ final class AuthenticationConfigBuilder { return (String) pv.getValue(); } - void createUserServiceInjector() { - BeanDefinitionBuilder userServiceInjector = - BeanDefinitionBuilder.rootBeanDefinition(UserDetailsServiceInjectionBeanPostProcessor.class); - userServiceInjector.addConstructorArgValue(x509ProviderId); - userServiceInjector.addConstructorArgValue(rememberMeServicesId); - userServiceInjector.addConstructorArgValue(openIDProviderId); - userServiceInjector.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); - pc.getReaderContext().registerWithGeneratedName(userServiceInjector.getBeanDefinition()); + private void createUserDetailsServiceFactory() { + if (pc.getRegistry().containsBeanDefinition(BeanIds.USER_DETAILS_SERVICE_FACTORY)) { + // Multiple case + return; + } + RootBeanDefinition bean = new RootBeanDefinition(UserDetailsServiceFactoryBean.class); + bean.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); + pc.getReaderContext().getRegistry().registerBeanDefinition(BeanIds.USER_DETAILS_SERVICE_FACTORY, bean); } List getFilters() { diff --git a/config/src/main/java/org/springframework/security/config/http/RememberMeBeanDefinitionParser.java b/config/src/main/java/org/springframework/security/config/http/RememberMeBeanDefinitionParser.java index c4c259822c..30d4cc1451 100644 --- a/config/src/main/java/org/springframework/security/config/http/RememberMeBeanDefinitionParser.java +++ b/config/src/main/java/org/springframework/security/config/http/RememberMeBeanDefinitionParser.java @@ -10,6 +10,7 @@ import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.beans.factory.xml.BeanDefinitionParser; import org.springframework.beans.factory.xml.ParserContext; +import org.springframework.security.config.BeanIds; import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl; import org.springframework.security.web.authentication.rememberme.PersistentTokenBasedRememberMeServices; import org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter; @@ -87,9 +88,12 @@ class RememberMeBeanDefinitionParser implements BeanDefinitionParser { } if (services != null) { - if (userServiceSet) { - services.getPropertyValues().addPropertyValue("userDetailsService", new RuntimeBeanReference(userServiceRef)); - } + RootBeanDefinition uds = new RootBeanDefinition(); + uds.setFactoryBeanName(BeanIds.USER_DETAILS_SERVICE_FACTORY); + uds.setFactoryMethodName("cachingUserDetailsService"); + uds.getConstructorArgumentValues().addGenericArgumentValue(userServiceRef); + + services.getPropertyValues().addPropertyValue("userDetailsService", uds); if ("true".equals(element.getAttribute(ATT_SECURE_COOKIE))) { services.getPropertyValues().addPropertyValue("useSecureCookie", true); diff --git a/config/src/main/java/org/springframework/security/config/http/UserDetailsServiceFactoryBean.java b/config/src/main/java/org/springframework/security/config/http/UserDetailsServiceFactoryBean.java new file mode 100644 index 0000000000..c52961e535 --- /dev/null +++ b/config/src/main/java/org/springframework/security/config/http/UserDetailsServiceFactoryBean.java @@ -0,0 +1,132 @@ +package org.springframework.security.config.http; + +import java.util.Map; + +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.HierarchicalBeanFactory; +import org.springframework.beans.factory.ListableBeanFactory; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; +import org.springframework.context.ApplicationContextException; +import org.springframework.security.config.authentication.AbstractUserDetailsServiceBeanDefinitionParser; +import org.springframework.security.config.authentication.CachingUserDetailsService; +import org.springframework.security.core.userdetails.AuthenticationUserDetailsService; +import org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.util.StringUtils; + +/** + * Bean used to lookup a named UserDetailsService or AuthenticationUserDetailsService. + * + * @author Luke Taylor + * @since 3.1 + */ +public class UserDetailsServiceFactoryBean implements ApplicationContextAware { + + private ApplicationContext beanFactory; + + UserDetailsService userDetailsService(String id) { + if (!StringUtils.hasText(id)) { + return getUserDetailsService(); + } + + return (UserDetailsService) beanFactory.getBean(id); + } + + UserDetailsService cachingUserDetailsService(String id) { + if (!StringUtils.hasText(id)) { + return getUserDetailsService(); + } + // Overwrite with the caching version if available + String cachingId = id + AbstractUserDetailsServiceBeanDefinitionParser.CACHING_SUFFIX; + + if (beanFactory.containsBeanDefinition(cachingId)) { + return (UserDetailsService) beanFactory.getBean(cachingId); + } + + return (UserDetailsService) beanFactory.getBean(id); + } + + @SuppressWarnings("unchecked") + AuthenticationUserDetailsService authenticationUserDetailsService(String name) { + UserDetailsService uds; + + if (!StringUtils.hasText(name)) { + Map beans = getBeansOfType(AuthenticationUserDetailsService.class); + + if (!beans.isEmpty()) { + if (beans.size() > 1) { + throw new ApplicationContextException("More than one AuthenticationUserDetailsService registered." + + "Please use a specific Id reference in element."); + } + return (AuthenticationUserDetailsService) beans.values().toArray()[0]; + } + + uds = getUserDetailsService(); + } else { + Object bean = beanFactory.getBean(name); + + if (bean instanceof AuthenticationUserDetailsService) { + return (AuthenticationUserDetailsService)bean; + } else if (bean instanceof UserDetailsService) { + uds = cachingUserDetailsService(name); + + if (uds == null) { + uds = (UserDetailsService)bean; + } + } else { + throw new ApplicationContextException("Bean '" + name + "' must be a UserDetailsService or an" + + " AuthenticationUserDetailsService"); + } + } + + return new UserDetailsByNameServiceWrapper(uds); + } + + /** + * Obtains a user details service for use in RememberMeServices etc. Will return a caching version + * if available so should not be used for beans which need to separate the two. + */ + private UserDetailsService getUserDetailsService() { + Map beans = getBeansOfType(CachingUserDetailsService.class); + + if (beans.size() == 0) { + beans = getBeansOfType(UserDetailsService.class); + } + + if (beans.size() == 0) { + throw new ApplicationContextException("No UserDetailsService registered."); + + } else if (beans.size() > 1) { + throw new ApplicationContextException("More than one UserDetailsService registered. Please " + + "use a specific Id reference in or elements."); + } + + return (UserDetailsService) beans.values().toArray()[0]; + } + + public void setApplicationContext(ApplicationContext beanFactory) throws BeansException { + this.beanFactory = beanFactory; + } + + private Map getBeansOfType(Class type) { + Map beans = beanFactory.getBeansOfType(type); + + // Check ancestor bean factories if they exist and the current one has none of the required type + BeanFactory parent = beanFactory.getParentBeanFactory(); + while (parent != null && beans.size() == 0) { + if (parent instanceof ListableBeanFactory) { + beans = ((ListableBeanFactory)parent).getBeansOfType(type); + } + if (parent instanceof HierarchicalBeanFactory) { + parent = ((HierarchicalBeanFactory)parent).getParentBeanFactory(); + } else { + break; + } + } + + return beans; + } + +} diff --git a/config/src/main/java/org/springframework/security/config/http/UserDetailsServiceInjectionBeanPostProcessor.java b/config/src/main/java/org/springframework/security/config/http/UserDetailsServiceInjectionBeanPostProcessor.java deleted file mode 100644 index 2502c6a159..0000000000 --- a/config/src/main/java/org/springframework/security/config/http/UserDetailsServiceInjectionBeanPostProcessor.java +++ /dev/null @@ -1,187 +0,0 @@ -package org.springframework.security.config.http; - -import java.util.Map; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.springframework.beans.BeanWrapperImpl; -import org.springframework.beans.BeansException; -import org.springframework.beans.PropertyValue; -import org.springframework.beans.factory.BeanFactory; -import org.springframework.beans.factory.BeanFactoryAware; -import org.springframework.beans.factory.HierarchicalBeanFactory; -import org.springframework.beans.factory.ListableBeanFactory; -import org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.beans.factory.config.BeanPostProcessor; -import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; -import org.springframework.beans.factory.config.RuntimeBeanReference; -import org.springframework.beans.factory.support.RootBeanDefinition; -import org.springframework.context.ApplicationContextException; -import org.springframework.security.config.authentication.AbstractUserDetailsServiceBeanDefinitionParser; -import org.springframework.security.config.authentication.CachingUserDetailsService; -import org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper; -import org.springframework.security.core.userdetails.UserDetailsService; -import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider; -import org.springframework.security.web.authentication.rememberme.AbstractRememberMeServices; -import org.springframework.util.Assert; - -/** - * Registered by {@link HttpSecurityBeanDefinitionParser} to inject a UserDetailsService into - * the X509Provider, RememberMeServices and OpenIDAuthenticationProvider instances created by - * the namespace. - * - * @author Luke Taylor - * @since 2.0.2 - */ -public class UserDetailsServiceInjectionBeanPostProcessor implements BeanPostProcessor, BeanFactoryAware { - private final Log logger = LogFactory.getLog(getClass()); - - private ConfigurableListableBeanFactory beanFactory; - private final String x509ProviderId; - private final String rememberMeServicesId; - private final String openIDProviderId; - - public UserDetailsServiceInjectionBeanPostProcessor(String x509ProviderId, String rememberMeServicesId, - String openIDProviderId) { - this.x509ProviderId = x509ProviderId; - this.rememberMeServicesId = rememberMeServicesId; - this.openIDProviderId = openIDProviderId; - } - - public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { - if(beanName == null) { - return bean; - } - if (beanName.equals(x509ProviderId)) { - injectUserDetailsServiceIntoX509Provider((PreAuthenticatedAuthenticationProvider) bean); - } else if (beanName.equals(rememberMeServicesId)) { - injectUserDetailsServiceIntoRememberMeServices(bean); - } else if (beanName.equals(openIDProviderId)) { - injectUserDetailsServiceIntoOpenIDProvider(bean); - } - - return bean; - } - - public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { - return bean; - } - - private void injectUserDetailsServiceIntoRememberMeServices(Object rms) { - if (!(rms instanceof AbstractRememberMeServices)) { - logger.info("RememberMeServices is not an instance of AbstractRememberMeServices. UserDetailsService will" + - " not be automatically injected."); - return; - } - - AbstractRememberMeServices services = (AbstractRememberMeServices) rms; - - BeanDefinition beanDefinition = beanFactory.getBeanDefinition(rememberMeServicesId); - PropertyValue pv = beanDefinition.getPropertyValues().getPropertyValue("userDetailsService"); - - if (pv == null) { - // If it doesn't already have a UserDetailsService set, then set it. - services.setUserDetailsService(getUserDetailsService()); - } else { - // If already set, then attempt to locate a caching version of the injected UserDetailsService - UserDetailsService cachingUserService = getCachingUserService(pv.getValue()); - - if (cachingUserService != null) { - services.setUserDetailsService(cachingUserService); - } - } - } - - private void injectUserDetailsServiceIntoX509Provider(PreAuthenticatedAuthenticationProvider provider) { - BeanDefinition beanDefinition = beanFactory.getBeanDefinition(x509ProviderId); - PropertyValue pv = beanDefinition.getPropertyValues().getPropertyValue("preAuthenticatedUserDetailsService"); - UserDetailsByNameServiceWrapper wrapper = new UserDetailsByNameServiceWrapper(); - - if (pv == null) { - wrapper.setUserDetailsService(getUserDetailsService()); - provider.setPreAuthenticatedUserDetailsService(wrapper); - } else { - RootBeanDefinition preAuthUserService = (RootBeanDefinition) pv.getValue(); - Object userService = - preAuthUserService.getPropertyValues().getPropertyValue("userDetailsService").getValue(); - - UserDetailsService cachingUserService = getCachingUserService(userService); - - if (cachingUserService != null) { - wrapper.setUserDetailsService(cachingUserService); - provider.setPreAuthenticatedUserDetailsService(wrapper); - } - } - } - - private void injectUserDetailsServiceIntoOpenIDProvider(Object bean) { - BeanDefinition beanDefinition = beanFactory.getBeanDefinition(openIDProviderId); - PropertyValue pv = beanDefinition.getPropertyValues().getPropertyValue("userDetailsService"); - - if (pv == null) { - BeanWrapperImpl beanWrapper = new BeanWrapperImpl(bean); - beanWrapper.setPropertyValue("userDetailsService", getUserDetailsService()); - } - } - - /** - * Obtains a user details service for use in RememberMeServices etc. Will return a caching version - * if available so should not be used for beans which need to separate the two. - */ - UserDetailsService getUserDetailsService() { - Map beans = getBeansOfType(CachingUserDetailsService.class); - - if (beans.size() == 0) { - beans = getBeansOfType(UserDetailsService.class); - } - - if (beans.size() == 0) { - throw new ApplicationContextException("No UserDetailsService registered."); - - } else if (beans.size() > 1) { - throw new ApplicationContextException("More than one UserDetailsService registered. Please " + - "use a specific Id reference in or elements."); - } - - return (UserDetailsService) beans.values().toArray()[0]; - } - - private UserDetailsService getCachingUserService(Object userServiceRef) { - Assert.isInstanceOf(RuntimeBeanReference.class, userServiceRef, - "userDetailsService property value must be a RuntimeBeanReference"); - - String id = ((RuntimeBeanReference)userServiceRef).getBeanName(); - // Overwrite with the caching version if available - String cachingId = id + AbstractUserDetailsServiceBeanDefinitionParser.CACHING_SUFFIX; - - if (beanFactory.containsBeanDefinition(cachingId)) { - return (UserDetailsService) beanFactory.getBean(cachingId); - } - - return null; - } - - private Map getBeansOfType(Class type) { - Map beans = beanFactory.getBeansOfType(type); - - // Check ancestor bean factories if they exist and the current one has none of the required type - BeanFactory parent = beanFactory.getParentBeanFactory(); - while (parent != null && beans.size() == 0) { - if (parent instanceof ListableBeanFactory) { - beans = ((ListableBeanFactory)parent).getBeansOfType(type); - } - if (parent instanceof HierarchicalBeanFactory) { - parent = ((HierarchicalBeanFactory)parent).getParentBeanFactory(); - } else { - break; - } - } - - return beans; - } - - - public void setBeanFactory(BeanFactory beanFactory) throws BeansException { - this.beanFactory = (ConfigurableListableBeanFactory) beanFactory; - } -} diff --git a/core/src/main/java/org/springframework/security/core/userdetails/User.java b/core/src/main/java/org/springframework/security/core/userdetails/User.java index 5932171ab2..7f662b2670 100644 --- a/core/src/main/java/org/springframework/security/core/userdetails/User.java +++ b/core/src/main/java/org/springframework/security/core/userdetails/User.java @@ -16,7 +16,6 @@ package org.springframework.security.core.userdetails; import java.io.Serializable; -import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Comparator; @@ -49,12 +48,10 @@ public class User implements UserDetails { //~ Constructors =================================================================================================== /** - * @deprecated + * Calls the more complex constructor with all boolean arguments set to {@code true}. */ - public User(String username, String password, boolean enabled, boolean accountNonExpired, - boolean credentialsNonExpired, boolean accountNonLocked, GrantedAuthority[] authorities) { - this(username, password, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, - authorities == null ? null : Arrays.asList(authorities)); + public User(String username, String password, Collection authorities) { + this(username, password, true, true, true, true, authorities); } /** diff --git a/openid/src/main/java/org/springframework/security/openid/OpenIDAuthenticationProvider.java b/openid/src/main/java/org/springframework/security/openid/OpenIDAuthenticationProvider.java index bf18685ee1..d3a0d8a341 100644 --- a/openid/src/main/java/org/springframework/security/openid/OpenIDAuthenticationProvider.java +++ b/openid/src/main/java/org/springframework/security/openid/OpenIDAuthenticationProvider.java @@ -20,7 +20,9 @@ import org.springframework.security.authentication.AuthenticationServiceExceptio import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; +import org.springframework.security.core.userdetails.AuthenticationUserDetailsService; import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.util.Assert; @@ -29,7 +31,7 @@ import org.springframework.util.Assert; * Finalises the OpenID authentication by obtaining local authorities for the authenticated user. *

* The authorities are obtained by calling the configured UserDetailsService. - * The UserDetails it returns must, at minimum, contain the username and GrantedAuthority[] + * The UserDetails it returns must, at minimum, contain the username and GrantedAuthority * objects applicable to the authenticated user. Note that by default, Spring Security ignores the password and * enabled/disabled status of the UserDetails because this is * authentication-related and should have been enforced by another provider server. @@ -42,7 +44,7 @@ import org.springframework.util.Assert; public class OpenIDAuthenticationProvider implements AuthenticationProvider, InitializingBean { //~ Instance fields ================================================================================================ - private UserDetailsService userDetailsService; + private AuthenticationUserDetailsService userDetailsService; //~ Methods ======================================================================================================== @@ -66,7 +68,7 @@ public class OpenIDAuthenticationProvider implements AuthenticationProvider, Ini // handle the various possibilities if (status == OpenIDAuthenticationStatus.SUCCESS) { // Lookup user details - UserDetails userDetails = userDetailsService.loadUserByUsername(response.getIdentityUrl()); + UserDetails userDetails = userDetailsService.loadUserDetails(response); return createSuccessfulAuthentication(userDetails, response); @@ -103,9 +105,16 @@ public class OpenIDAuthenticationProvider implements AuthenticationProvider, Ini } /** - * Used to load the authorities for the authenticated OpenID user. + * Used to load the {@code UserDetails} for the authenticated OpenID user. */ public void setUserDetailsService(UserDetailsService userDetailsService) { + this.userDetailsService = new UserDetailsByNameServiceWrapper(userDetailsService); + } + + /** + * Used to load the {@code UserDetails} for the authenticated OpenID user. + */ + public void setAuthenticationUserDetailsService(AuthenticationUserDetailsService userDetailsService) { this.userDetailsService = userDetailsService; } diff --git a/openid/src/test/java/org/springframework/security/openid/OpenIDAuthenticationProviderTests.java b/openid/src/test/java/org/springframework/security/openid/OpenIDAuthenticationProviderTests.java index 708a2c28a4..d692e27bec 100644 --- a/openid/src/test/java/org/springframework/security/openid/OpenIDAuthenticationProviderTests.java +++ b/openid/src/test/java/org/springframework/security/openid/OpenIDAuthenticationProviderTests.java @@ -183,17 +183,16 @@ public class OpenIDAuthenticationProviderTests extends TestCase { public void testValidation() throws Exception { OpenIDAuthenticationProvider provider = new OpenIDAuthenticationProvider(); - provider.setUserDetailsService(new MockUserDetailsService()); - provider.afterPropertiesSet(); - - provider.setUserDetailsService(null); - try { provider.afterPropertiesSet(); fail("IllegalArgumentException expected, ssoAuthoritiesPopulator is null"); } catch (IllegalArgumentException e) { //expected } + + provider = new OpenIDAuthenticationProvider(); + provider.setUserDetailsService(new MockUserDetailsService()); + provider.afterPropertiesSet(); } static class MockUserDetailsService implements UserDetailsService {