mirror of
				https://github.com/spring-projects/spring-security.git
				synced 2025-10-30 22:28:46 +00:00 
			
		
		
		
	Fix concurrent session interaction bug where UserDetails.getUsername() may have been override to be a different value than the original login request, as per email from Herryanto Siatono on acegisecurity-developer 5 November 2005.
This commit is contained in:
		
							parent
							
								
									a807b8d539
								
							
						
					
					
						commit
						aa4fd8586c
					
				| @ -15,12 +15,6 @@ | |||||||
| 
 | 
 | ||||||
| package net.sf.acegisecurity.providers; | package net.sf.acegisecurity.providers; | ||||||
| 
 | 
 | ||||||
| import java.lang.reflect.Constructor; |  | ||||||
| import java.lang.reflect.InvocationTargetException; |  | ||||||
| import java.util.Iterator; |  | ||||||
| import java.util.List; |  | ||||||
| import java.util.Properties; |  | ||||||
| 
 |  | ||||||
| import net.sf.acegisecurity.AbstractAuthenticationManager; | import net.sf.acegisecurity.AbstractAuthenticationManager; | ||||||
| import net.sf.acegisecurity.AccountExpiredException; | import net.sf.acegisecurity.AccountExpiredException; | ||||||
| import net.sf.acegisecurity.Authentication; | import net.sf.acegisecurity.Authentication; | ||||||
| @ -48,11 +42,21 @@ import net.sf.acegisecurity.providers.cas.ProxyUntrustedException; | |||||||
| 
 | 
 | ||||||
| import org.apache.commons.logging.Log; | import org.apache.commons.logging.Log; | ||||||
| import org.apache.commons.logging.LogFactory; | import org.apache.commons.logging.LogFactory; | ||||||
|  | 
 | ||||||
| import org.springframework.beans.factory.InitializingBean; | import org.springframework.beans.factory.InitializingBean; | ||||||
|  | 
 | ||||||
| import org.springframework.context.ApplicationEventPublisher; | import org.springframework.context.ApplicationEventPublisher; | ||||||
| import org.springframework.context.ApplicationEventPublisherAware; | import org.springframework.context.ApplicationEventPublisherAware; | ||||||
|  | 
 | ||||||
| import org.springframework.util.Assert; | import org.springframework.util.Assert; | ||||||
| 
 | 
 | ||||||
|  | import java.lang.reflect.Constructor; | ||||||
|  | import java.lang.reflect.InvocationTargetException; | ||||||
|  | 
 | ||||||
|  | import java.util.Iterator; | ||||||
|  | import java.util.List; | ||||||
|  | import java.util.Properties; | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * Iterates an {@link Authentication} request through a list of {@link |  * Iterates an {@link Authentication} request through a list of {@link | ||||||
| @ -76,17 +80,22 @@ import org.springframework.util.Assert; | |||||||
|  * <code>ProviderNotFoundException</code>. |  * <code>ProviderNotFoundException</code>. | ||||||
|  * </p> |  * </p> | ||||||
|  *  |  *  | ||||||
|  * <p>If a valid <code>Authentication</code> is returned by an <code>AuthenticationProvider</code>, |  * <p> | ||||||
|  * the <code>ProviderManager</code> will publish an |  * If a valid <code>Authentication</code> is returned by an | ||||||
|  * {@link net.sf.acegisecurity.event.authentication.AuthenticationSuccessEvent}. If an |  * <code>AuthenticationProvider</code>, the <code>ProviderManager</code> will | ||||||
|  * <code>AuthenticationException</code> is detected, the final <code>AuthenticationException</code> thrown |  * publish an {@link | ||||||
|  * will be used to publish an appropriate failure event. By default <code>ProviderManager</code> |  * net.sf.acegisecurity.event.authentication.AuthenticationSuccessEvent}. If | ||||||
|  * maps common exceptions to events, but this can be fine-tuned by providing a new |  * an <code>AuthenticationException</code> is detected, the final | ||||||
|  * <code>exceptionMappings</code> <code>java.util.Properties</code> object. In the |  * <code>AuthenticationException</code> thrown will be used to publish an | ||||||
|  * properties object, each of the keys represent the fully qualified classname of |  * appropriate failure event. By default <code>ProviderManager</code> maps | ||||||
|  * the exception, and each of the values represent the name of an event class which subclasses |  * common exceptions to events, but this can be fine-tuned by providing a new | ||||||
|  * {@link net.sf.acegisecurity.event.authentication.AbstractAuthenticationFailureEvent} and |  * <code>exceptionMappings</code><code>java.util.Properties</code> object. In | ||||||
|  * provides its constructor. |  * the properties object, each of the keys represent the fully qualified | ||||||
|  |  * classname of the exception, and each of the values represent the name of an | ||||||
|  |  * event class which subclasses {@link | ||||||
|  |  * net.sf.acegisecurity.event.authentication.AbstractAuthenticationFailureEvent} | ||||||
|  |  * and provides its constructor. | ||||||
|  |  * </p> | ||||||
|  * |  * | ||||||
|  * @author Ben Alex |  * @author Ben Alex | ||||||
|  * @author Wesley Hall |  * @author Wesley Hall | ||||||
| @ -103,13 +112,18 @@ public class ProviderManager extends AbstractAuthenticationManager | |||||||
| 
 | 
 | ||||||
|     //~ Instance fields ======================================================== |     //~ Instance fields ======================================================== | ||||||
| 
 | 
 | ||||||
|  |     private ApplicationEventPublisher applicationEventPublisher; | ||||||
|     private ConcurrentSessionController sessionController = new NullConcurrentSessionController(); |     private ConcurrentSessionController sessionController = new NullConcurrentSessionController(); | ||||||
|     private List providers; |     private List providers; | ||||||
|     private Properties exceptionMappings; |     private Properties exceptionMappings; | ||||||
|     private ApplicationEventPublisher applicationEventPublisher; |  | ||||||
| 
 | 
 | ||||||
|     //~ Methods ================================================================ |     //~ Methods ================================================================ | ||||||
| 
 | 
 | ||||||
|  |     public void setApplicationEventPublisher( | ||||||
|  |         ApplicationEventPublisher applicationEventPublisher) { | ||||||
|  |         this.applicationEventPublisher = applicationEventPublisher; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     /** |     /** | ||||||
|      * Sets the {@link AuthenticationProvider} objects to be used for |      * Sets the {@link AuthenticationProvider} objects to be used for | ||||||
|      * authentication. |      * authentication. | ||||||
| @ -169,29 +183,31 @@ public class ProviderManager extends AbstractAuthenticationManager | |||||||
| 
 | 
 | ||||||
|     public void afterPropertiesSet() throws Exception { |     public void afterPropertiesSet() throws Exception { | ||||||
|         checkIfValidList(this.providers); |         checkIfValidList(this.providers); | ||||||
|  | 
 | ||||||
|         if (exceptionMappings == null) { |         if (exceptionMappings == null) { | ||||||
|             exceptionMappings = new Properties(); |             exceptionMappings = new Properties(); | ||||||
|         	exceptionMappings.put(AccountExpiredException.class.getName(), AuthenticationFailureExpiredEvent.class.getName()); |             exceptionMappings.put(AccountExpiredException.class.getName(), | ||||||
|         	exceptionMappings.put(AuthenticationServiceException.class.getName(), AuthenticationFailureServiceExceptionEvent.class.getName()); |                 AuthenticationFailureExpiredEvent.class.getName()); | ||||||
|         	exceptionMappings.put(LockedException.class.getName(), AuthenticationFailureLockedEvent.class.getName()); |             exceptionMappings.put(AuthenticationServiceException.class.getName(), | ||||||
|         	exceptionMappings.put(CredentialsExpiredException.class.getName(), AuthenticationFailureCredentialsExpiredEvent.class.getName()); |                 AuthenticationFailureServiceExceptionEvent.class.getName()); | ||||||
|         	exceptionMappings.put(DisabledException.class.getName(), AuthenticationFailureDisabledEvent.class.getName()); |             exceptionMappings.put(LockedException.class.getName(), | ||||||
|         	exceptionMappings.put(BadCredentialsException.class.getName(), AuthenticationFailureBadCredentialsEvent.class.getName()); |                 AuthenticationFailureLockedEvent.class.getName()); | ||||||
|         	exceptionMappings.put(ConcurrentLoginException.class.getName(), AuthenticationFailureConcurrentLoginEvent.class.getName()); |             exceptionMappings.put(CredentialsExpiredException.class.getName(), | ||||||
|         	exceptionMappings.put(ProviderNotFoundException.class.getName(), AuthenticationFailureProviderNotFoundEvent.class.getName()); |                 AuthenticationFailureCredentialsExpiredEvent.class.getName()); | ||||||
|         	exceptionMappings.put(ProxyUntrustedException.class.getName(), AuthenticationFailureProxyUntrustedEvent.class.getName()); |             exceptionMappings.put(DisabledException.class.getName(), | ||||||
|  |                 AuthenticationFailureDisabledEvent.class.getName()); | ||||||
|  |             exceptionMappings.put(BadCredentialsException.class.getName(), | ||||||
|  |                 AuthenticationFailureBadCredentialsEvent.class.getName()); | ||||||
|  |             exceptionMappings.put(ConcurrentLoginException.class.getName(), | ||||||
|  |                 AuthenticationFailureConcurrentLoginEvent.class.getName()); | ||||||
|  |             exceptionMappings.put(ProviderNotFoundException.class.getName(), | ||||||
|  |                 AuthenticationFailureProviderNotFoundEvent.class.getName()); | ||||||
|  |             exceptionMappings.put(ProxyUntrustedException.class.getName(), | ||||||
|  |                 AuthenticationFailureProxyUntrustedEvent.class.getName()); | ||||||
|             doAddExtraDefaultExceptionMappings(exceptionMappings); |             doAddExtraDefaultExceptionMappings(exceptionMappings); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |  | ||||||
|      * Provided so subclasses can add extra exception mappings during startup if no |  | ||||||
|      * exception mappings are injected by the IoC container. |  | ||||||
|      *  |  | ||||||
|      * @param exceptionMappings the properties object, which already has entries in it |  | ||||||
|      */ |  | ||||||
|     protected void doAddExtraDefaultExceptionMappings(Properties exceptionMappings) {} |  | ||||||
| 
 |  | ||||||
|     /** |     /** | ||||||
|      * Attempts to authenticate the passed {@link Authentication} object. |      * Attempts to authenticate the passed {@link Authentication} object. | ||||||
|      *  |      *  | ||||||
| @ -215,7 +231,6 @@ public class ProviderManager extends AbstractAuthenticationManager | |||||||
|      * @return a fully authenticated object including credentials. |      * @return a fully authenticated object including credentials. | ||||||
|      * |      * | ||||||
|      * @throws AuthenticationException if authentication fails. |      * @throws AuthenticationException if authentication fails. | ||||||
|      * @throws ProviderNotFoundException DOCUMENT ME! |  | ||||||
|      */ |      */ | ||||||
|     public Authentication doAuthentication(Authentication authentication) |     public Authentication doAuthentication(Authentication authentication) | ||||||
|         throws AuthenticationException { |         throws AuthenticationException { | ||||||
| @ -223,8 +238,6 @@ public class ProviderManager extends AbstractAuthenticationManager | |||||||
| 
 | 
 | ||||||
|         Class toTest = authentication.getClass(); |         Class toTest = authentication.getClass(); | ||||||
| 
 | 
 | ||||||
|         sessionController.checkAuthenticationAllowed(authentication); |  | ||||||
| 
 |  | ||||||
|         AuthenticationException lastException = null; |         AuthenticationException lastException = null; | ||||||
| 
 | 
 | ||||||
|         while (iter.hasNext()) { |         while (iter.hasNext()) { | ||||||
| @ -239,54 +252,69 @@ public class ProviderManager extends AbstractAuthenticationManager | |||||||
| 
 | 
 | ||||||
|                 try { |                 try { | ||||||
|                     result = provider.authenticate(authentication); |                     result = provider.authenticate(authentication); | ||||||
|  |                     sessionController.checkAuthenticationAllowed(result); | ||||||
|                 } catch (AuthenticationException ae) { |                 } catch (AuthenticationException ae) { | ||||||
|                     lastException = ae; |                     lastException = ae; | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 if (result != null) { |                 if (result != null) { | ||||||
|                     sessionController.registerSuccessfulAuthentication(result); |                     sessionController.registerSuccessfulAuthentication(result); | ||||||
|                     applicationEventPublisher.publishEvent(new AuthenticationSuccessEvent(result)); |                     applicationEventPublisher.publishEvent(new AuthenticationSuccessEvent( | ||||||
|  |                             result)); | ||||||
|  | 
 | ||||||
|                     return result; |                     return result; | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (lastException == null) { |         if (lastException == null) { | ||||||
|         	lastException = new ProviderNotFoundException("No authentication provider for " + toTest.getName()); |             lastException = new ProviderNotFoundException( | ||||||
|  |                     "No authentication provider for " + toTest.getName()); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         // Publish the event |         // Publish the event | ||||||
|         String className = exceptionMappings.getProperty(lastException.getClass().getName()); |         String className = exceptionMappings.getProperty(lastException.getClass() | ||||||
|  |                                                                       .getName()); | ||||||
|         AbstractAuthenticationEvent event = null; |         AbstractAuthenticationEvent event = null; | ||||||
|  | 
 | ||||||
|         if (className != null) { |         if (className != null) { | ||||||
|             try { |             try { | ||||||
|                 Class clazz = getClass().getClassLoader().loadClass(className); |                 Class clazz = getClass().getClassLoader().loadClass(className); | ||||||
|                 Constructor constructor = clazz.getConstructor(new Class[] {Authentication.class, AuthenticationException.class}); |                 Constructor constructor = clazz.getConstructor(new Class[] {Authentication.class, AuthenticationException.class}); | ||||||
|                 Object obj = constructor.newInstance(new Object[] {authentication, lastException}); |                 Object obj = constructor.newInstance(new Object[] {authentication, lastException}); | ||||||
|         		Assert.isInstanceOf(AbstractAuthenticationEvent.class, obj, "Must be an AbstractAuthenticationEvent"); |                 Assert.isInstanceOf(AbstractAuthenticationEvent.class, obj, | ||||||
|  |                     "Must be an AbstractAuthenticationEvent"); | ||||||
|                 event = (AbstractAuthenticationEvent) obj; |                 event = (AbstractAuthenticationEvent) obj; | ||||||
|         	} catch (ClassNotFoundException ignored) { |             } catch (ClassNotFoundException ignored) {} | ||||||
|         	} catch (NoSuchMethodException ignored) { |             catch (NoSuchMethodException ignored) {} | ||||||
|         	} catch (IllegalAccessException ignored) { |             catch (IllegalAccessException ignored) {} | ||||||
|         	} catch (InstantiationException ignored) { |             catch (InstantiationException ignored) {} | ||||||
|         	} catch (InvocationTargetException ignored) { |             catch (InvocationTargetException ignored) {} | ||||||
|         } |         } | ||||||
|         } | 
 | ||||||
|         Assert.notNull(event, "A valid event must be available for the exception " + lastException.getClass().getName()); |         Assert.notNull(event, | ||||||
|  |             "A valid event must be available for the exception " | ||||||
|  |             + lastException.getClass().getName()); | ||||||
|         applicationEventPublisher.publishEvent(event); |         applicationEventPublisher.publishEvent(event); | ||||||
| 
 | 
 | ||||||
|         // Throw the exception |         // Throw the exception | ||||||
|         throw lastException; |         throw lastException; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     /** | ||||||
|  |      * Provided so subclasses can add extra exception mappings during startup | ||||||
|  |      * if no exception mappings are injected by the IoC container. | ||||||
|  |      * | ||||||
|  |      * @param exceptionMappings the properties object, which already has | ||||||
|  |      *        entries in it | ||||||
|  |      */ | ||||||
|  |     protected void doAddExtraDefaultExceptionMappings( | ||||||
|  |         Properties exceptionMappings) {} | ||||||
|  | 
 | ||||||
|     private void checkIfValidList(List listToCheck) { |     private void checkIfValidList(List listToCheck) { | ||||||
|         if ((listToCheck == null) || (listToCheck.size() == 0)) { |         if ((listToCheck == null) || (listToCheck.size() == 0)) { | ||||||
|             throw new IllegalArgumentException( |             throw new IllegalArgumentException( | ||||||
|                 "A list of AuthenticationManagers is required"); |                 "A list of AuthenticationManagers is required"); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 |  | ||||||
| 	public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) { |  | ||||||
| 		this.applicationEventPublisher = applicationEventPublisher;		 |  | ||||||
| 	} |  | ||||||
| } | } | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user