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,28 +183,30 @@ 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(),
|
||||||
doAddExtraDefaultExceptionMappings(exceptionMappings);
|
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.
|
* 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,
|
||||||
event = (AbstractAuthenticationEvent) obj;
|
"Must be an AbstractAuthenticationEvent");
|
||||||
} catch (ClassNotFoundException ignored) {
|
event = (AbstractAuthenticationEvent) obj;
|
||||||
} catch (NoSuchMethodException ignored) {
|
} catch (ClassNotFoundException ignored) {}
|
||||||
} catch (IllegalAccessException ignored) {
|
catch (NoSuchMethodException ignored) {}
|
||||||
} catch (InstantiationException ignored) {
|
catch (IllegalAccessException ignored) {}
|
||||||
} catch (InvocationTargetException 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);
|
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…
Reference in New Issue