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;
|
||||
|
||||
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.AccountExpiredException;
|
||||
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.LogFactory;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.context.ApplicationEventPublisherAware;
|
||||
|
||||
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
|
||||
|
@ -76,17 +80,22 @@ import org.springframework.util.Assert;
|
|||
* <code>ProviderNotFoundException</code>.
|
||||
* </p>
|
||||
*
|
||||
* <p>If a valid <code>Authentication</code> is returned by an <code>AuthenticationProvider</code>,
|
||||
* the <code>ProviderManager</code> will publish an
|
||||
* {@link net.sf.acegisecurity.event.authentication.AuthenticationSuccessEvent}. If an
|
||||
* <code>AuthenticationException</code> is detected, the final <code>AuthenticationException</code> thrown
|
||||
* will be used to publish an appropriate failure event. By default <code>ProviderManager</code>
|
||||
* maps common exceptions to events, but this can be fine-tuned by providing a new
|
||||
* <code>exceptionMappings</code> <code>java.util.Properties</code> object. In 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>
|
||||
* If a valid <code>Authentication</code> is returned by an
|
||||
* <code>AuthenticationProvider</code>, the <code>ProviderManager</code> will
|
||||
* publish an {@link
|
||||
* net.sf.acegisecurity.event.authentication.AuthenticationSuccessEvent}. If
|
||||
* an <code>AuthenticationException</code> is detected, the final
|
||||
* <code>AuthenticationException</code> thrown will be used to publish an
|
||||
* appropriate failure event. By default <code>ProviderManager</code> maps
|
||||
* common exceptions to events, but this can be fine-tuned by providing a new
|
||||
* <code>exceptionMappings</code><code>java.util.Properties</code> object. In
|
||||
* 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 Wesley Hall
|
||||
|
@ -103,13 +112,18 @@ public class ProviderManager extends AbstractAuthenticationManager
|
|||
|
||||
//~ Instance fields ========================================================
|
||||
|
||||
private ApplicationEventPublisher applicationEventPublisher;
|
||||
private ConcurrentSessionController sessionController = new NullConcurrentSessionController();
|
||||
private List providers;
|
||||
private Properties exceptionMappings;
|
||||
private ApplicationEventPublisher applicationEventPublisher;
|
||||
|
||||
//~ Methods ================================================================
|
||||
|
||||
public void setApplicationEventPublisher(
|
||||
ApplicationEventPublisher applicationEventPublisher) {
|
||||
this.applicationEventPublisher = applicationEventPublisher;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link AuthenticationProvider} objects to be used for
|
||||
* authentication.
|
||||
|
@ -169,29 +183,31 @@ public class ProviderManager extends AbstractAuthenticationManager
|
|||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
checkIfValidList(this.providers);
|
||||
|
||||
if (exceptionMappings == null) {
|
||||
exceptionMappings = new Properties();
|
||||
exceptionMappings.put(AccountExpiredException.class.getName(), AuthenticationFailureExpiredEvent.class.getName());
|
||||
exceptionMappings.put(AuthenticationServiceException.class.getName(), AuthenticationFailureServiceExceptionEvent.class.getName());
|
||||
exceptionMappings.put(LockedException.class.getName(), AuthenticationFailureLockedEvent.class.getName());
|
||||
exceptionMappings.put(CredentialsExpiredException.class.getName(), AuthenticationFailureCredentialsExpiredEvent.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());
|
||||
exceptionMappings.put(AccountExpiredException.class.getName(),
|
||||
AuthenticationFailureExpiredEvent.class.getName());
|
||||
exceptionMappings.put(AuthenticationServiceException.class.getName(),
|
||||
AuthenticationFailureServiceExceptionEvent.class.getName());
|
||||
exceptionMappings.put(LockedException.class.getName(),
|
||||
AuthenticationFailureLockedEvent.class.getName());
|
||||
exceptionMappings.put(CredentialsExpiredException.class.getName(),
|
||||
AuthenticationFailureCredentialsExpiredEvent.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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
|
@ -215,7 +231,6 @@ public class ProviderManager extends AbstractAuthenticationManager
|
|||
* @return a fully authenticated object including credentials.
|
||||
*
|
||||
* @throws AuthenticationException if authentication fails.
|
||||
* @throws ProviderNotFoundException DOCUMENT ME!
|
||||
*/
|
||||
public Authentication doAuthentication(Authentication authentication)
|
||||
throws AuthenticationException {
|
||||
|
@ -223,8 +238,6 @@ public class ProviderManager extends AbstractAuthenticationManager
|
|||
|
||||
Class toTest = authentication.getClass();
|
||||
|
||||
sessionController.checkAuthenticationAllowed(authentication);
|
||||
|
||||
AuthenticationException lastException = null;
|
||||
|
||||
while (iter.hasNext()) {
|
||||
|
@ -239,54 +252,69 @@ public class ProviderManager extends AbstractAuthenticationManager
|
|||
|
||||
try {
|
||||
result = provider.authenticate(authentication);
|
||||
sessionController.checkAuthenticationAllowed(result);
|
||||
} catch (AuthenticationException ae) {
|
||||
lastException = ae;
|
||||
}
|
||||
|
||||
if (result != null) {
|
||||
sessionController.registerSuccessfulAuthentication(result);
|
||||
applicationEventPublisher.publishEvent(new AuthenticationSuccessEvent(result));
|
||||
applicationEventPublisher.publishEvent(new AuthenticationSuccessEvent(
|
||||
result));
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (lastException == null) {
|
||||
lastException = new ProviderNotFoundException("No authentication provider for " + toTest.getName());
|
||||
lastException = new ProviderNotFoundException(
|
||||
"No authentication provider for " + toTest.getName());
|
||||
}
|
||||
|
||||
// Publish the event
|
||||
String className = exceptionMappings.getProperty(lastException.getClass().getName());
|
||||
String className = exceptionMappings.getProperty(lastException.getClass()
|
||||
.getName());
|
||||
AbstractAuthenticationEvent event = null;
|
||||
|
||||
if (className != null) {
|
||||
try {
|
||||
Class clazz = getClass().getClassLoader().loadClass(className);
|
||||
Constructor constructor = clazz.getConstructor(new Class[] {Authentication.class, AuthenticationException.class});
|
||||
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;
|
||||
} catch (ClassNotFoundException ignored) {
|
||||
} catch (NoSuchMethodException ignored) {
|
||||
} catch (IllegalAccessException ignored) {
|
||||
} catch (InstantiationException ignored) {
|
||||
} catch (InvocationTargetException ignored) {
|
||||
} catch (ClassNotFoundException ignored) {}
|
||||
catch (NoSuchMethodException ignored) {}
|
||||
catch (IllegalAccessException ignored) {}
|
||||
catch (InstantiationException 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);
|
||||
|
||||
// Throw the exception
|
||||
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) {
|
||||
if ((listToCheck == null) || (listToCheck.size() == 0)) {
|
||||
throw new IllegalArgumentException(
|
||||
"A list of AuthenticationManagers is required");
|
||||
}
|
||||
}
|
||||
|
||||
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
|
||||
this.applicationEventPublisher = applicationEventPublisher;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue