浏览代码

Refactoring of UserDetailsService injection (for X509, OpenID and RememberMeServices) to use a factory bean rather than a post-processor.

Luke Taylor 15 年之前
父节点
当前提交
d3d9c5db59

+ 1 - 0
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";
 

+ 20 - 21
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 <http> case
+            return;
+        }
+        RootBeanDefinition bean = new RootBeanDefinition(UserDetailsServiceFactoryBean.class);
+        bean.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
+        pc.getReaderContext().getRegistry().registerBeanDefinition(BeanIds.USER_DETAILS_SERVICE_FACTORY, bean);
     }
 
     List<OrderDecorator> getFilters() {

+ 7 - 3
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);

+ 132 - 0
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<String,?> 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 <openid-login/> 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<String,?> 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 <remember-me/> <openid-login/> or <x509 /> elements.");
+        }
+
+        return (UserDetailsService) beans.values().toArray()[0];
+    }
+
+    public void setApplicationContext(ApplicationContext beanFactory) throws BeansException {
+        this.beanFactory = beanFactory;
+    }
+
+    private Map<String,?> getBeansOfType(Class<?> type) {
+        Map<String,?> 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;
+    }
+
+}

+ 0 - 187
config/src/main/java/org/springframework/security/config/http/UserDetailsServiceInjectionBeanPostProcessor.java

@@ -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<String,?> 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 <remember-me/> <openid-login/> or <x509 /> 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<String,?> getBeansOfType(Class<?> type) {
-        Map<String,?> 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;
-    }
-}

+ 3 - 6
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<GrantedAuthority> authorities) {
+        this(username, password, true, true, true, true, authorities);
     }
 
     /**

+ 13 - 4
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.
  * <p>
  * The authorities are obtained by calling the configured <tt>UserDetailsService</tt>.
- * The <code>UserDetails</code> it returns must, at minimum, contain the username and <code>GrantedAuthority[]</code>
+ * The <code>UserDetails</code> it returns must, at minimum, contain the username and <code>GrantedAuthority</code>
  * objects applicable to the authenticated user. Note that by default, Spring Security ignores the password and
  * enabled/disabled status of the <code>UserDetails</code> 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<OpenIDAuthenticationToken> 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<OpenIDAuthenticationToken>(userDetailsService);
+    }
+
+    /**
+     * Used to load the {@code UserDetails} for the authenticated OpenID user.
+     */
+    public void setAuthenticationUserDetailsService(AuthenticationUserDetailsService<OpenIDAuthenticationToken> userDetailsService) {
         this.userDetailsService = userDetailsService;
     }
 

+ 4 - 5
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 {