mirror of
				https://github.com/spring-projects/spring-security.git
				synced 2025-10-31 06:38:42 +00:00 
			
		
		
		
	SEC-629: authentication-provider doesn't support caching.
http://jira.springframework.org/browse/SEC-629. Added support for cache-ref elements on jdbc-user-service and ldap-user-service
This commit is contained in:
		
							parent
							
								
									db6fafaf56
								
							
						
					
					
						commit
						1463b9769d
					
				| @ -1,8 +1,12 @@ | ||||
| package org.springframework.security.config; | ||||
| 
 | ||||
| import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser; | ||||
| import org.springframework.beans.factory.xml.BeanDefinitionParser; | ||||
| import org.springframework.beans.factory.xml.ParserContext; | ||||
| import org.springframework.beans.factory.config.BeanDefinition; | ||||
| import org.springframework.beans.factory.config.RuntimeBeanReference; | ||||
| import org.springframework.beans.factory.support.AbstractBeanDefinition; | ||||
| import org.springframework.beans.factory.support.BeanDefinitionBuilder; | ||||
| import org.springframework.beans.factory.support.RootBeanDefinition; | ||||
| import org.springframework.beans.factory.BeanDefinitionStoreException; | ||||
| import org.springframework.util.StringUtils; | ||||
| 
 | ||||
| @ -12,16 +16,53 @@ import org.w3c.dom.Element; | ||||
|  * @author Luke Taylor | ||||
|  * @version $Id$ | ||||
|  */ | ||||
| public class AbstractUserDetailsServiceBeanDefinitionParser extends AbstractSingleBeanDefinitionParser { | ||||
| public abstract class AbstractUserDetailsServiceBeanDefinitionParser implements BeanDefinitionParser { | ||||
| 	private static final String CACHE_REF = "cache-ref"; | ||||
| 	public static final String CACHING_SUFFIX = ".caching"; | ||||
| 	 | ||||
|     protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext) throws BeanDefinitionStoreException { | ||||
|         String id = super.resolveId(element, definition, parserContext); | ||||
| 	/**  UserDetailsService bean Id. For use in a stateful context (i.e. in AuthenticationProviderBDP) */ | ||||
| 	private String id; | ||||
| 	 | ||||
| 	protected abstract Class getBeanClass(Element element); | ||||
| 	 | ||||
|     protected abstract void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder);	 | ||||
| 	 | ||||
| 	public BeanDefinition parse(Element element, ParserContext parserContext) { | ||||
| 		BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(getBeanClass(element));  | ||||
| 		 | ||||
| 		doParse(element, parserContext, builder); | ||||
| 		 | ||||
| 		RootBeanDefinition userService = (RootBeanDefinition) builder.getBeanDefinition(); | ||||
| 		String beanId = resolveId(element, userService, parserContext); | ||||
| 		 | ||||
| 		parserContext.getRegistry().registerBeanDefinition(beanId, userService); | ||||
| 		 | ||||
| 		String cacheRef = element.getAttribute(CACHE_REF); | ||||
| 		 | ||||
| 		// Register a caching version of the user service if there's a cache-ref | ||||
| 		if (StringUtils.hasText(cacheRef)) { | ||||
| 			BeanDefinitionBuilder cachingUSBuilder = BeanDefinitionBuilder.rootBeanDefinition(CachingUserDetailsService.class); | ||||
| 			cachingUSBuilder.addConstructorArgReference(beanId); | ||||
| 			 | ||||
| 			cachingUSBuilder.addPropertyValue("userCache", new RuntimeBeanReference(cacheRef)); | ||||
| 			BeanDefinition cachingUserService = cachingUSBuilder.getBeanDefinition(); | ||||
| 			parserContext.getRegistry().registerBeanDefinition(beanId + CACHING_SUFFIX, cachingUserService);			 | ||||
| 		} | ||||
| 
 | ||||
| 		id = beanId; | ||||
| 		 | ||||
| 		return null; | ||||
| 	} | ||||
| 
 | ||||
|     private String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext)  | ||||
|     		throws BeanDefinitionStoreException { | ||||
| 
 | ||||
|         String id = element.getAttribute("id"); | ||||
| 
 | ||||
|         if (StringUtils.hasText(id)) { | ||||
|             return id; | ||||
|         } | ||||
| 
 | ||||
|         // If it's nested in a parent auth-provider, generate an id automatically | ||||
|         if(Elements.AUTHENTICATION_PROVIDER.equals(element.getParentNode().getNodeName())) { | ||||
|             return parserContext.getReaderContext().generateBeanName(definition); | ||||
|         } | ||||
| @ -34,4 +75,8 @@ public class AbstractUserDetailsServiceBeanDefinitionParser extends AbstractSing | ||||
| 
 | ||||
|         return BeanIds.USER_DETAILS_SERVICE; | ||||
|     } | ||||
| 
 | ||||
| 	String getId() { | ||||
| 		return id; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @ -1,14 +1,19 @@ | ||||
| package org.springframework.security.config; | ||||
| 
 | ||||
| import org.springframework.security.providers.dao.DaoAuthenticationProvider; | ||||
| import org.springframework.beans.BeansException; | ||||
| import org.springframework.beans.PropertyValue; | ||||
| import org.springframework.beans.factory.config.BeanDefinition; | ||||
| import org.springframework.beans.factory.config.BeanFactoryPostProcessor; | ||||
| import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; | ||||
| import org.springframework.beans.factory.config.RuntimeBeanReference; | ||||
| 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.beans.factory.support.RootBeanDefinition; | ||||
| import org.springframework.util.xml.DomUtils; | ||||
| import org.springframework.core.Ordered; | ||||
| import org.springframework.security.providers.dao.DaoAuthenticationProvider; | ||||
| import org.springframework.util.StringUtils; | ||||
| 
 | ||||
| import org.springframework.util.xml.DomUtils; | ||||
| import org.w3c.dom.Element; | ||||
| 
 | ||||
| /** | ||||
| @ -36,40 +41,88 @@ class AuthenticationProviderBeanDefinitionParser implements BeanDefinitionParser | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         ConfigUtils.getRegisteredProviders(parserContext).add(authProvider); | ||||
| 
 | ||||
|         String ref = element.getAttribute(ATT_USER_DETAILS_REF); | ||||
|         Element userServiceElt = DomUtils.getChildElementByTagName(element, Elements.USER_SERVICE); | ||||
|         Element jdbcUserServiceElt = DomUtils.getChildElementByTagName(element, Elements.JDBC_USER_SERVICE); | ||||
|         Element ldapUserServiceElt = DomUtils.getChildElementByTagName(element, Elements.LDAP_USER_SERVICE); | ||||
| 
 | ||||
|         // We need to register the provider to access it in the post processor to check if it has a cache | ||||
|         final String id = parserContext.getReaderContext().generateBeanName(authProvider); | ||||
|         parserContext.getRegistry().registerBeanDefinition(id, authProvider);                     | ||||
| 
 | ||||
|         String ref = element.getAttribute(ATT_USER_DETAILS_REF);         | ||||
|          | ||||
|         if (StringUtils.hasText(ref)) {        	 | ||||
|             if (userServiceElt != null || jdbcUserServiceElt != null || ldapUserServiceElt != null) { | ||||
|                 parserContext.getReaderContext().error("The ref attribute cannot be used in combination with child" + | ||||
|                 parserContext.getReaderContext().error("The " + ATT_USER_DETAILS_REF + " attribute cannot be used in combination with child" + | ||||
|                         "elements '" + Elements.USER_SERVICE + "', '" + Elements.JDBC_USER_SERVICE + "' or '" + | ||||
|                         Elements.LDAP_USER_SERVICE + "'", element); | ||||
|             } | ||||
| 
 | ||||
|             authProvider.getPropertyValues().addPropertyValue("userDetailsService", new RuntimeBeanReference(ref)); | ||||
| 
 | ||||
|             return null; | ||||
|         } | ||||
| 
 | ||||
|         // Use the child elements to create the UserDetailsService | ||||
|         BeanDefinition userDetailsService = null; | ||||
| 
 | ||||
|         if (userServiceElt != null) { | ||||
|             userDetailsService = new UserServiceBeanDefinitionParser().parse(userServiceElt, parserContext); | ||||
|         } else if (jdbcUserServiceElt != null) { | ||||
|             userDetailsService = new JdbcUserServiceBeanDefinitionParser().parse(jdbcUserServiceElt, parserContext); | ||||
|         } else if (ldapUserServiceElt != null) { | ||||
|             userDetailsService = new LdapUserServiceBeanDefinitionParser().parse(ldapUserServiceElt, parserContext); | ||||
|         } else { | ||||
|             parserContext.getReaderContext().error("A user-service is required", element); | ||||
| 	        // Use the child elements to create the UserDetailsService | ||||
| 	        AbstractUserDetailsServiceBeanDefinitionParser parser = null; | ||||
| 	        Element elt = null; | ||||
| 	 | ||||
| 	        if (userServiceElt != null) { | ||||
| 	        	elt = userServiceElt; | ||||
| 	        	parser = new UserServiceBeanDefinitionParser(); | ||||
| 	        } else if (jdbcUserServiceElt != null) { | ||||
| 	        	elt = jdbcUserServiceElt; | ||||
| 	        	parser = new JdbcUserServiceBeanDefinitionParser(); | ||||
| 	        } else if (ldapUserServiceElt != null) { | ||||
| 	        	elt = ldapUserServiceElt; | ||||
| 	        	parser = new LdapUserServiceBeanDefinitionParser(); | ||||
| 	        } else { | ||||
| 	            parserContext.getReaderContext().error("A user-service is required", element); | ||||
| 	        } | ||||
| 	         | ||||
| 	        parser.parse(elt, parserContext); | ||||
| 	        ref = parser.getId(); | ||||
|         } | ||||
|          | ||||
|         authProvider.getPropertyValues().addPropertyValue("userDetailsService", userDetailsService); | ||||
|         authProvider.getPropertyValues().addPropertyValue("userDetailsService", new RuntimeBeanReference(ref));         | ||||
| 
 | ||||
|         BeanDefinitionBuilder cacheResolverBldr = BeanDefinitionBuilder.rootBeanDefinition(AuthenticationProviderCacheResolver.class);         | ||||
|         cacheResolverBldr.addConstructorArg(id); | ||||
|         cacheResolverBldr.addConstructorArg(ref);         | ||||
|         cacheResolverBldr.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); | ||||
|         BeanDefinition cacheResolver = cacheResolverBldr.getBeanDefinition(); | ||||
|         parserContext.getRegistry().registerBeanDefinition( | ||||
|         		parserContext.getReaderContext().generateBeanName(cacheResolver), cacheResolver); | ||||
| 
 | ||||
|         ConfigUtils.getRegisteredProviders(parserContext).add(new RuntimeBeanReference(id));         | ||||
|          | ||||
|         return null; | ||||
|     } | ||||
|      | ||||
|     /** | ||||
|      * Checks whether the registered user service bean has an associated cache and, if so, sets it on the  | ||||
|      * authentication provider. | ||||
|      */ | ||||
|     static class AuthenticationProviderCacheResolver implements BeanFactoryPostProcessor, Ordered { | ||||
|     	private String providerId; | ||||
|     	private String userServiceId; | ||||
|     	 | ||||
| 		public AuthenticationProviderCacheResolver(String providerId, String userServiceId) { | ||||
| 			this.providerId = providerId; | ||||
| 			this.userServiceId = userServiceId; | ||||
| 		} | ||||
| 
 | ||||
| 		public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { | ||||
| 			RootBeanDefinition provider = (RootBeanDefinition) beanFactory.getBeanDefinition(providerId); | ||||
| 			 | ||||
| 			String cachingId = userServiceId + AbstractUserDetailsServiceBeanDefinitionParser.CACHING_SUFFIX; | ||||
| 			 | ||||
| 			if (beanFactory.containsBeanDefinition(cachingId)) { | ||||
| 				RootBeanDefinition cachingUserService = (RootBeanDefinition) beanFactory.getBeanDefinition(cachingId); | ||||
| 			 | ||||
| 				PropertyValue userCacheProperty = cachingUserService.getPropertyValues().getPropertyValue("userCache"); | ||||
| 				 | ||||
| 				provider.getPropertyValues().addPropertyValue(userCacheProperty); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		public int getOrder() { | ||||
| 			return HIGHEST_PRECEDENCE; | ||||
| 		} | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -0,0 +1,44 @@ | ||||
| package org.springframework.security.config; | ||||
| 
 | ||||
| import org.springframework.security.providers.dao.UserCache; | ||||
| import org.springframework.security.providers.dao.cache.NullUserCache; | ||||
| import org.springframework.security.userdetails.UserDetailsService; | ||||
| import org.springframework.security.userdetails.UserDetails; | ||||
| import org.springframework.util.Assert; | ||||
| 
 | ||||
| /** | ||||
|  * | ||||
|  * @author Luke Taylor | ||||
|  * @since 2.0 | ||||
|  */ | ||||
| class CachingUserDetailsService implements UserDetailsService { | ||||
| 	private UserCache userCache = new NullUserCache(); | ||||
| 	private UserDetailsService delegate; | ||||
| 
 | ||||
| 	CachingUserDetailsService(UserDetailsService delegate) { | ||||
| 		this.delegate = delegate; | ||||
| 	} | ||||
| 
 | ||||
| 	public UserCache getUserCache() { | ||||
| 		return userCache; | ||||
| 	} | ||||
| 
 | ||||
| 	public void setUserCache(UserCache userCache) { | ||||
| 		this.userCache = userCache; | ||||
| 	} | ||||
| 
 | ||||
| 	public UserDetails loadUserByUsername(String username) { | ||||
| 		UserDetails user = userCache.getUserFromCache(username); | ||||
| 		 | ||||
| 		if (user == null) { | ||||
| 			user = delegate.loadUserByUsername(username); | ||||
| 		} | ||||
| 		 | ||||
| 		Assert.notNull(user, "UserDetailsService " + delegate + " returned null for username " + username + ". " + | ||||
| 				"This is an interface contract violation"); | ||||
| 		 | ||||
| 		userCache.putUserInCache(user); | ||||
| 		 | ||||
| 		return user; | ||||
| 	} | ||||
| } | ||||
| @ -74,8 +74,16 @@ public abstract class ConfigUtils { | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     /** | ||||
|      * 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.  | ||||
|      */ | ||||
|     static UserDetailsService getUserDetailsService(ConfigurableListableBeanFactory bf) { | ||||
|         Map services = bf.getBeansOfType(UserDetailsService.class); | ||||
|         Map services = bf.getBeansOfType(CachingUserDetailsService.class); | ||||
|          | ||||
|         if (services.size() == 0) { | ||||
|         	services = bf.getBeansOfType(UserDetailsService.class); | ||||
|         } | ||||
| 
 | ||||
|         if (services.size() == 0) { | ||||
|             throw new IllegalArgumentException("No UserDetailsService registered."); | ||||
|  | ||||
| @ -260,7 +260,9 @@ public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser { | ||||
|         registry.registerBeanDefinition(BeanIds.FILTER_SECURITY_INTERCEPTOR, filterSecurityInterceptorBuilder.getBeanDefinition()); | ||||
| 
 | ||||
|         // Register the post processor which will tie up the loose ends in the configuration once the app context has been created and all beans are available. | ||||
|         registry.registerBeanDefinition(BeanIds.HTTP_POST_PROCESSOR, new RootBeanDefinition(HttpSecurityConfigPostProcessor.class)); | ||||
|         RootBeanDefinition postProcessor = new RootBeanDefinition(HttpSecurityConfigPostProcessor.class); | ||||
|         postProcessor.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); | ||||
|         registry.registerBeanDefinition(BeanIds.HTTP_POST_PROCESSOR, postProcessor); | ||||
| 
 | ||||
|         return null; | ||||
|     } | ||||
|  | ||||
| @ -16,6 +16,8 @@ import org.springframework.beans.factory.NoSuchBeanDefinitionException; | ||||
| import org.springframework.beans.factory.config.BeanDefinition; | ||||
| import org.springframework.beans.factory.config.BeanFactoryPostProcessor; | ||||
| import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; | ||||
| import org.springframework.beans.factory.config.RuntimeBeanReference; | ||||
| import org.springframework.beans.factory.support.RootBeanDefinition; | ||||
| import org.springframework.core.OrderComparator; | ||||
| import org.springframework.core.Ordered; | ||||
| import org.springframework.security.concurrent.ConcurrentSessionFilter; | ||||
| @ -52,30 +54,46 @@ public class HttpSecurityConfigPostProcessor implements BeanFactoryPostProcessor | ||||
|         configureFilterChain(beanFactory); | ||||
|     } | ||||
| 
 | ||||
|     private void injectUserDetailsServiceIntoRememberMeServices(ConfigurableListableBeanFactory beanFactory) { | ||||
|     private void injectUserDetailsServiceIntoRememberMeServices(ConfigurableListableBeanFactory bf) { | ||||
|         try { | ||||
|             BeanDefinition rememberMeServices = beanFactory.getBeanDefinition(BeanIds.REMEMBER_ME_SERVICES); | ||||
|             BeanDefinition rememberMeServices = bf.getBeanDefinition(BeanIds.REMEMBER_ME_SERVICES); | ||||
|             PropertyValue pv = rememberMeServices.getPropertyValues().getPropertyValue("userDetailsService"); | ||||
| 
 | ||||
|             if (pv == null) { | ||||
|                 rememberMeServices.getPropertyValues().addPropertyValue("userDetailsService", | ||||
|                     ConfigUtils.getUserDetailsService(beanFactory)); | ||||
|                     ConfigUtils.getUserDetailsService(bf)); | ||||
|             } else { | ||||
|             	RuntimeBeanReference cachingUserService = getCachingUserService(bf, pv.getValue()); | ||||
|             	 | ||||
|             	if (cachingUserService != null) { | ||||
|             		rememberMeServices.getPropertyValues().addPropertyValue("userDetailsService", cachingUserService); | ||||
|             	}            	 | ||||
|             } | ||||
|         } catch (NoSuchBeanDefinitionException e) { | ||||
|             // ignore | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private void injectUserDetailsServiceIntoX509Provider(ConfigurableListableBeanFactory beanFactory) { | ||||
|     private void injectUserDetailsServiceIntoX509Provider(ConfigurableListableBeanFactory bf) { | ||||
|         try { | ||||
|             BeanDefinition x509AuthProvider = beanFactory.getBeanDefinition(BeanIds.X509_AUTH_PROVIDER); | ||||
|             BeanDefinition x509AuthProvider = bf.getBeanDefinition(BeanIds.X509_AUTH_PROVIDER); | ||||
|             PropertyValue pv = x509AuthProvider.getPropertyValues().getPropertyValue("preAuthenticatedUserDetailsService"); | ||||
| 
 | ||||
|             if (pv == null) { | ||||
|                 UserDetailsByNameServiceWrapper preAuthUserService = new UserDetailsByNameServiceWrapper(); | ||||
|                 preAuthUserService.setUserDetailsService(ConfigUtils.getUserDetailsService(beanFactory)); | ||||
|                 preAuthUserService.setUserDetailsService(ConfigUtils.getUserDetailsService(bf)); | ||||
|                 x509AuthProvider.getPropertyValues().addPropertyValue("preAuthenticatedUserDetailsService", | ||||
|                         preAuthUserService); | ||||
|             } else { | ||||
|             	RootBeanDefinition preAuthUserService = (RootBeanDefinition) pv.getValue(); | ||||
|             	Object userService =  | ||||
|             		preAuthUserService.getPropertyValues().getPropertyValue("userDetailsService").getValue(); | ||||
|             	 | ||||
|             	RuntimeBeanReference cachingUserService = getCachingUserService(bf, userService); | ||||
|             	 | ||||
|             	if (cachingUserService != null) { | ||||
|             		preAuthUserService.getPropertyValues().addPropertyValue("userDetailsService", cachingUserService); | ||||
|             	} | ||||
|             } | ||||
|         } catch (NoSuchBeanDefinitionException e) { | ||||
|             // ignore | ||||
| @ -96,6 +114,21 @@ public class HttpSecurityConfigPostProcessor implements BeanFactoryPostProcessor | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     private RuntimeBeanReference getCachingUserService(ConfigurableListableBeanFactory bf, 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 (bf.containsBeanDefinition(cachingId)) { | ||||
|     		return new RuntimeBeanReference(cachingId); | ||||
|     	} | ||||
|     	 | ||||
|     	return null; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Sets the authentication manager, (and remember-me services, if required) on any instances of | ||||
|      * AbstractProcessingFilter | ||||
| @ -148,7 +181,7 @@ public class HttpSecurityConfigPostProcessor implements BeanFactoryPostProcessor | ||||
|      * <ol> | ||||
|      * <li>If only one, use that one.</li> | ||||
|      * <li>If more than one, use the form login entry point (if form login is being used), then try basic</li> | ||||
|      * <li>If still null, throw an exception (for now). TODO: Examine additional beans and types and make decision</li> | ||||
|      * <li>If still null, throw an exception (for now).</li> | ||||
|      * </ol> | ||||
|      * | ||||
|      */ | ||||
| @ -257,6 +290,6 @@ public class HttpSecurityConfigPostProcessor implements BeanFactoryPostProcessor | ||||
|     } | ||||
| 
 | ||||
|     public int getOrder() { | ||||
|         return HIGHEST_PRECEDENCE; | ||||
|         return HIGHEST_PRECEDENCE + 1; | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -2,6 +2,7 @@ package org.springframework.security.config; | ||||
| 
 | ||||
| import org.springframework.security.userdetails.jdbc.JdbcUserDetailsManager; | ||||
| import org.springframework.beans.factory.support.BeanDefinitionBuilder; | ||||
| import org.springframework.beans.factory.xml.ParserContext; | ||||
| import org.springframework.beans.factory.BeanDefinitionStoreException; | ||||
| 
 | ||||
| import org.w3c.dom.Element; | ||||
| @ -17,7 +18,7 @@ public class JdbcUserServiceBeanDefinitionParser extends AbstractUserDetailsServ | ||||
|         return JdbcUserDetailsManager.class; | ||||
|     } | ||||
| 
 | ||||
|     protected void doParse(Element element, BeanDefinitionBuilder builder) { | ||||
|     protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { | ||||
|         // TODO: Set authenticationManager property | ||||
|         String dataSource = element.getAttribute(ATT_DATA_SOURCE); | ||||
|         // An explicit dataSource was specified, so use it | ||||
|  | ||||
| @ -4,6 +4,7 @@ import org.springframework.beans.factory.config.BeanDefinition; | ||||
| import org.springframework.beans.factory.config.PropertiesFactoryBean; | ||||
| import org.springframework.beans.factory.support.BeanDefinitionBuilder; | ||||
| import org.springframework.beans.factory.support.RootBeanDefinition; | ||||
| import org.springframework.beans.factory.xml.ParserContext; | ||||
| import org.springframework.beans.factory.BeanDefinitionStoreException; | ||||
| import org.springframework.security.userdetails.memory.InMemoryDaoImpl; | ||||
| import org.springframework.security.userdetails.memory.UserMap; | ||||
| @ -36,7 +37,7 @@ public class UserServiceBeanDefinitionParser extends AbstractUserDetailsServiceB | ||||
|         return InMemoryDaoImpl.class; | ||||
|     } | ||||
| 
 | ||||
|     protected void doParse(Element element, BeanDefinitionBuilder builder) { | ||||
|     protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { | ||||
|         String userProperties = element.getAttribute(ATT_PROPERTIES); | ||||
|         List userElts = DomUtils.getChildElementsByTagName(element, ELT_USER); | ||||
| 
 | ||||
|  | ||||
| @ -1,66 +0,0 @@ | ||||
| /* Copyright 2004, 2005, 2006 Acegi Technology Pty Limited | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
| package org.springframework.security.providers; | ||||
| 
 | ||||
| import org.springframework.security.AuthenticationException; | ||||
| import org.springframework.security.userdetails.UserDetails; | ||||
| 
 | ||||
| /** | ||||
|  * Populates the <code>UserDetails</code> associated with a CAS authenticated | ||||
|  * user. | ||||
|  * | ||||
|  * <p> | ||||
|  * Intended to grant authorities (roles) for providers that do not support | ||||
|  * authorities/roles directly. It merely authenticates their identity. | ||||
|  * As Spring Security needs to know the authorities granted to a user in | ||||
|  * order to construct a valid <code>Authentication</code> object, implementations | ||||
|  * of this interface will provide this information. | ||||
|  * </p> | ||||
|  * | ||||
|  * <p> | ||||
|  * A {@link UserDetails} is returned by implementations. The | ||||
|  * <code>UserDetails</code> must, at minimum, contain the username and | ||||
|  * <code>GrantedAuthority[]</code> objects applicable to the authenticated | ||||
|  * user. Note that 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. The | ||||
|  * <code>UserDetails</code> returned by implementations is stored in the | ||||
|  * generated <code>AuthenticationToken</code>, so additional properties | ||||
|  * such as email addresses, telephone numbers etc can easily be stored. | ||||
|  * </p> | ||||
|  * | ||||
|  * <p> | ||||
|  * Implementations should not perform any caching. They will only be called | ||||
|  * when a refresh is required. | ||||
|  * </p> | ||||
|  * | ||||
|  * @author Ben Alex | ||||
|  * @author Ray Krueger | ||||
|  * @version $Id$ | ||||
|  */ | ||||
| public interface UserDetailsService { | ||||
|     /** | ||||
|      * Obtains the granted authorities for the specified user.<P>May throw any | ||||
|      * <code>AuthenticationException</code> or return <code>null</code> if the authorities are unavailable.</p> | ||||
|      * | ||||
|      * @param casUserId as obtained from the CAS validation service | ||||
|      * | ||||
|      * @return the details of the indicated user (at minimum the granted authorities and the username) | ||||
|      * | ||||
|      * @throws org.springframework.security.AuthenticationException DOCUMENT ME! | ||||
|      */ | ||||
|     UserDetails getUserDetails(String casUserId) | ||||
|         throws AuthenticationException; | ||||
| } | ||||
| @ -30,6 +30,10 @@ ref = | ||||
|     ## Defines a reference to a Spring bean Id. | ||||
|     attribute ref {xsd:string} | ||||
| 
 | ||||
| cache-ref = | ||||
|     ## Defines a reference to a cache for use with a UserDetailsService. | ||||
|     attribute cache-ref {xsd:string} | ||||
| 
 | ||||
| user-service-ref = | ||||
|     ## A reference to a user-service (or UserDetailsService bean) Id | ||||
|     attribute user-service-ref {xsd:string} | ||||
| @ -104,6 +108,8 @@ ldap-us.attlist &= | ||||
|     group-search-base-attribute? | ||||
| ldap-us.attlist &= | ||||
|     group-role-attribute-attribute? | ||||
| ldap-us.attlist &= | ||||
|     cache-ref? | ||||
| 
 | ||||
| ldap-authentication-provider = | ||||
|     ## Sets up an ldap authentication provider | ||||
| @ -391,6 +397,8 @@ jdbc-user-service = | ||||
| jdbc-user-service.attlist &= | ||||
| 	  ## The bean ID of the DataSource which provides the required tables. | ||||
|     attribute data-source-ref {xsd:string} | ||||
| jdbc-user-service.attlist &= | ||||
|     cache-ref? | ||||
| 
 | ||||
| any-user-service = user-service | jdbc-user-service | ldap-user-service | ||||
|      | ||||
|  | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -1,16 +1,17 @@ | ||||
| package org.springframework.security.config; | ||||
| 
 | ||||
| import static org.junit.Assert.assertNotNull; | ||||
| import static org.junit.Assert.assertSame; | ||||
| import static org.junit.Assert.assertTrue; | ||||
| 
 | ||||
| import org.junit.Test; | ||||
| import org.junit.After; | ||||
| 
 | ||||
| import org.junit.Test; | ||||
| import org.springframework.security.AuthenticationManager; | ||||
| import org.springframework.security.providers.ProviderManager; | ||||
| import org.springframework.security.providers.UsernamePasswordAuthenticationToken; | ||||
| import org.springframework.security.providers.dao.DaoAuthenticationProvider; | ||||
| import org.springframework.security.userdetails.jdbc.JdbcUserDetailsManager; | ||||
| import org.springframework.security.util.InMemoryXmlApplicationContext; | ||||
| import org.springframework.security.AuthenticationManager; | ||||
| import org.springframework.security.providers.UsernamePasswordAuthenticationToken; | ||||
| 
 | ||||
| import javax.sql.DataSource; | ||||
| 
 | ||||
| /** | ||||
|  * @author Ben Alex | ||||
| @ -18,7 +19,7 @@ import javax.sql.DataSource; | ||||
|  * @version $Id$ | ||||
|  */ | ||||
| public class JdbcUserServiceBeanDefinitionParserTests { | ||||
|     private InMemoryXmlApplicationContext appContext; | ||||
|     private static String USER_CACHE_XML = "<b:bean id='userCache' class='org.springframework.security.providers.dao.MockUserCache'/>";	 | ||||
| 
 | ||||
|     private static String DATA_SOURCE = | ||||
|             "    <b:bean id='populator' class='org.springframework.security.config.DataSourcePopulator'>" + | ||||
| @ -29,6 +30,8 @@ public class JdbcUserServiceBeanDefinitionParserTests { | ||||
|             "        <b:constructor-arg value='jdbcnamespaces'/>" + | ||||
|             "    </b:bean>"; | ||||
| 
 | ||||
|     private InMemoryXmlApplicationContext appContext; | ||||
|      | ||||
|     @After | ||||
|     public void closeAppContext() { | ||||
|         if (appContext != null) { | ||||
| @ -45,8 +48,18 @@ public class JdbcUserServiceBeanDefinitionParserTests { | ||||
| 
 | ||||
|     @Test | ||||
|     public void beanIdIsParsedCorrectly() { | ||||
|         setContext("<jdbc-user-service id='customUserService' data-source-ref='dataSource'/>" + DATA_SOURCE); | ||||
|         JdbcUserDetailsManager mgr = (JdbcUserDetailsManager) appContext.getBean("customUserService"); | ||||
|         setContext("<jdbc-user-service id='myUserService' data-source-ref='dataSource'/>" + DATA_SOURCE); | ||||
|         JdbcUserDetailsManager mgr = (JdbcUserDetailsManager) appContext.getBean("myUserService"); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void cacheRefIsparsedCorrectly() { | ||||
|         setContext("<jdbc-user-service id='myUserService' cache-ref='userCache' data-source-ref='dataSource'/>"  | ||||
|         		+ DATA_SOURCE +USER_CACHE_XML); | ||||
|         JdbcUserDetailsManager mgr = (JdbcUserDetailsManager) appContext.getBean("myUserService"); | ||||
|         CachingUserDetailsService cachingUserService =  | ||||
|         	(CachingUserDetailsService) appContext.getBean("myUserService" + AbstractUserDetailsServiceBeanDefinitionParser.CACHING_SUFFIX); | ||||
|         assertSame(cachingUserService.getUserCache(), appContext.getBean("userCache")); | ||||
|     }     | ||||
|      | ||||
|     @Test | ||||
| @ -59,6 +72,19 @@ public class JdbcUserServiceBeanDefinitionParserTests { | ||||
|         mgr.authenticate(new UsernamePasswordAuthenticationToken("rod", "koala")); | ||||
|     } | ||||
| 
 | ||||
|     @Test | ||||
|     public void cacheIsInjectedIntoAuthenticationProvider() { | ||||
|         setContext( | ||||
|                 "<authentication-provider>" + | ||||
|                 "    <jdbc-user-service cache-ref='userCache' data-source-ref='dataSource'/>" + | ||||
|                 "</authentication-provider>" + DATA_SOURCE + USER_CACHE_XML); | ||||
|         ProviderManager mgr = (ProviderManager) appContext.getBean(BeanIds.AUTHENTICATION_MANAGER); | ||||
|         DaoAuthenticationProvider provider = (DaoAuthenticationProvider) mgr.getProviders().get(0); | ||||
|         assertSame(provider.getUserCache(), appContext.getBean("userCache")); | ||||
|         provider.authenticate(new UsernamePasswordAuthenticationToken("rod","koala")); | ||||
|         assertNotNull("Cache should contain user after authentication", provider.getUserCache().getUserFromCache("rod"));       | ||||
|     } | ||||
| 
 | ||||
|     private void setContext(String context) { | ||||
|         appContext = new InMemoryXmlApplicationContext(context); | ||||
|     } | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user