diff --git a/core/src/main/java/org/acegisecurity/ui/rememberme/RememberMeProcessingFilter.java b/core/src/main/java/org/acegisecurity/ui/rememberme/RememberMeProcessingFilter.java
index 0bb9a8ec70..4169620a14 100644
--- a/core/src/main/java/org/acegisecurity/ui/rememberme/RememberMeProcessingFilter.java
+++ b/core/src/main/java/org/acegisecurity/ui/rememberme/RememberMeProcessingFilter.java
@@ -1,4 +1,4 @@
-/* Copyright 2004, 2005 Acegi Technology Pty Limited
+/* 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.
@@ -15,9 +15,13 @@
package org.acegisecurity.ui.rememberme;
-import org.acegisecurity.context.SecurityContextHolder;
-import org.acegisecurity.event.authentication.InteractiveAuthenticationSuccessEvent;
import org.acegisecurity.Authentication;
+import org.acegisecurity.AuthenticationException;
+import org.acegisecurity.AuthenticationManager;
+
+import org.acegisecurity.context.SecurityContextHolder;
+
+import org.acegisecurity.event.authentication.InteractiveAuthenticationSuccessEvent;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -54,15 +58,21 @@ import javax.servlet.http.HttpServletResponse;
* org.acegisecurity.ui.rememberme.RememberMeServices#autoLogin(HttpServletRequest,
* HttpServletResponse)} method called by this filter. The
* Authentication or null returned by that method
- * will be placed into the SecurityContext.
+ * will be placed into the SecurityContext. The
+ * AuthenticationManager will be used, so that any concurrent
+ * session management or other authentication-specific behaviour can be
+ * achieved. This is the same pattern as with other authentication mechanisms,
+ * which call the AuthenticationManager as part of their
+ * contract.
*
* If authentication is successful, an {@link
- * org.acegisecurity.event.authentication.InteractiveAuthenticationSuccessEvent} will be
- * published to the application context. No events will be published if
- * authentication was unsuccessful, because this would generally be recorded
- * via an AuthenticationManager-specific application event.
+ * org.acegisecurity.event.authentication.InteractiveAuthenticationSuccessEvent}
+ * will be published to the application context. No events will be published
+ * if authentication was unsuccessful, because this would generally be
+ * recorded via an AuthenticationManager-specific application
+ * event.
*
@@ -75,7 +85,7 @@ import javax.servlet.http.HttpServletResponse;
* @version $Id$
*/
public class RememberMeProcessingFilter implements Filter, InitializingBean,
- ApplicationEventPublisherAware {
+ ApplicationEventPublisherAware {
//~ Static fields/initializers =============================================
private static final Log logger = LogFactory.getLog(RememberMeProcessingFilter.class);
@@ -83,24 +93,14 @@ public class RememberMeProcessingFilter implements Filter, InitializingBean,
//~ Instance fields ========================================================
private ApplicationEventPublisher eventPublisher;
+ private AuthenticationManager authenticationManager;
private RememberMeServices rememberMeServices = new NullRememberMeServices();
//~ Methods ================================================================
- public void setApplicationEventPublisher(ApplicationEventPublisher eventPublisher) {
- this.eventPublisher = eventPublisher;
- }
-
- public void setRememberMeServices(RememberMeServices rememberMeServices) {
- this.rememberMeServices = rememberMeServices;
- }
-
- public RememberMeServices getRememberMeServices() {
- return rememberMeServices;
- }
-
public void afterPropertiesSet() throws Exception {
- Assert.notNull(rememberMeServices);
+ Assert.notNull(rememberMeServices, "RememberMeServices required");
+ Assert.notNull(authenticationManager, "AuthenticationManager required");
}
/**
@@ -122,11 +122,29 @@ public class RememberMeProcessingFilter implements Filter, InitializingBean,
HttpServletResponse httpResponse = (HttpServletResponse) response;
if (SecurityContextHolder.getContext().getAuthentication() == null) {
- Authentication rememberMeAuth =
- rememberMeServices.autoLogin(httpRequest, httpResponse);
+ Authentication rememberMeAuth = rememberMeServices.autoLogin(httpRequest,
+ httpResponse);
- if(rememberMeAuth != null) {
- SecurityContextHolder.getContext().setAuthentication(rememberMeAuth);
+ if (rememberMeAuth != null) {
+ // Attempt authenticaton via AuthenticationManager
+ try {
+ authenticationManager.authenticate(rememberMeAuth);
+ } catch (AuthenticationException authenticationException) {
+ if (logger.isDebugEnabled()) {
+ logger.debug(
+ "SecurityContextHolder not populated with remember-me token, as AuthenticationManager rejected Authentication returned by RememberMeServices: '"
+ + rememberMeAuth
+ + "'; invalidating remember-me token",
+ authenticationException);
+ }
+
+ rememberMeServices.loginFail(httpRequest, httpResponse);
+ chain.doFilter(request, response);
+ }
+
+ // Store to SecurityContextHolder
+ SecurityContextHolder.getContext()
+ .setAuthentication(rememberMeAuth);
if (logger.isDebugEnabled()) {
logger.debug(
@@ -138,9 +156,12 @@ public class RememberMeProcessingFilter implements Filter, InitializingBean,
// Fire event
if (this.eventPublisher != null) {
eventPublisher.publishEvent(new InteractiveAuthenticationSuccessEvent(
- SecurityContextHolder.getContext().getAuthentication(),
+ SecurityContextHolder.getContext()
+ .getAuthentication(),
this.getClass()));
}
+
+ chain.doFilter(request, response);
}
} else {
if (logger.isDebugEnabled()) {
@@ -149,9 +170,13 @@ public class RememberMeProcessingFilter implements Filter, InitializingBean,
+ SecurityContextHolder.getContext().getAuthentication()
+ "'");
}
- }
- chain.doFilter(request, response);
+ chain.doFilter(request, response);
+ }
+ }
+
+ public RememberMeServices getRememberMeServices() {
+ return rememberMeServices;
}
/**
@@ -159,6 +184,21 @@ public class RememberMeProcessingFilter implements Filter, InitializingBean,
*
* @param ignored not used
*
+ * @throws ServletException DOCUMENT ME!
*/
public void init(FilterConfig ignored) throws ServletException {}
+
+ public void setApplicationEventPublisher(
+ ApplicationEventPublisher eventPublisher) {
+ this.eventPublisher = eventPublisher;
+ }
+
+ public void setAuthenticationManager(
+ AuthenticationManager authenticationManager) {
+ this.authenticationManager = authenticationManager;
+ }
+
+ public void setRememberMeServices(RememberMeServices rememberMeServices) {
+ this.rememberMeServices = rememberMeServices;
+ }
}
diff --git a/core/src/test/java/org/acegisecurity/ui/rememberme/RememberMeProcessingFilterTests.java b/core/src/test/java/org/acegisecurity/ui/rememberme/RememberMeProcessingFilterTests.java
index ff8a6bf14d..d37d16d2ab 100644
--- a/core/src/test/java/org/acegisecurity/ui/rememberme/RememberMeProcessingFilterTests.java
+++ b/core/src/test/java/org/acegisecurity/ui/rememberme/RememberMeProcessingFilterTests.java
@@ -1,4 +1,4 @@
-/* Copyright 2004, 2005 Acegi Technology Pty Limited
+/* 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.
@@ -20,9 +20,12 @@ import junit.framework.TestCase;
import org.acegisecurity.Authentication;
import org.acegisecurity.GrantedAuthority;
import org.acegisecurity.GrantedAuthorityImpl;
+import org.acegisecurity.MockAuthenticationManager;
import org.acegisecurity.MockFilterConfig;
+
import org.acegisecurity.context.SecurityContextHolder;
import org.acegisecurity.context.SecurityContextImpl;
+
import org.acegisecurity.providers.TestingAuthenticationToken;
import org.springframework.mock.web.MockHttpServletRequest;
@@ -59,13 +62,50 @@ public class RememberMeProcessingFilterTests extends TestCase {
//~ Methods ================================================================
+ private void executeFilterInContainerSimulator(FilterConfig filterConfig,
+ Filter filter, ServletRequest request, ServletResponse response,
+ FilterChain filterChain) throws ServletException, IOException {
+ filter.init(filterConfig);
+ filter.doFilter(request, response, filterChain);
+ filter.destroy();
+ }
+
public static void main(String[] args) {
junit.textui.TestRunner.run(RememberMeProcessingFilterTests.class);
}
+ protected void setUp() throws Exception {
+ super.setUp();
+ SecurityContextHolder.setContext(new SecurityContextImpl());
+ }
+
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ SecurityContextHolder.setContext(new SecurityContextImpl());
+ }
+
+ public void testDetectsAuthenticationManagerProperty()
+ throws Exception {
+ RememberMeProcessingFilter filter = new RememberMeProcessingFilter();
+ filter.setAuthenticationManager(new MockAuthenticationManager());
+
+ filter.afterPropertiesSet();
+ assertTrue(true);
+
+ filter.setAuthenticationManager(null);
+
+ try {
+ filter.afterPropertiesSet();
+ fail("Should have thrown IllegalArgumentException");
+ } catch (IllegalArgumentException expected) {
+ assertTrue(true);
+ }
+ }
+
public void testDetectsRememberMeServicesProperty()
throws Exception {
RememberMeProcessingFilter filter = new RememberMeProcessingFilter();
+ filter.setAuthenticationManager(new MockAuthenticationManager());
// check default is NullRememberMeServices
assertEquals(NullRememberMeServices.class,
@@ -90,6 +130,7 @@ public class RememberMeProcessingFilterTests extends TestCase {
public void testDoFilterWithNonHttpServletRequestDetected()
throws Exception {
RememberMeProcessingFilter filter = new RememberMeProcessingFilter();
+ filter.setAuthenticationManager(new MockAuthenticationManager());
try {
filter.doFilter(null, new MockHttpServletResponse(),
@@ -104,6 +145,7 @@ public class RememberMeProcessingFilterTests extends TestCase {
public void testDoFilterWithNonHttpServletResponseDetected()
throws Exception {
RememberMeProcessingFilter filter = new RememberMeProcessingFilter();
+ filter.setAuthenticationManager(new MockAuthenticationManager());
try {
MockHttpServletRequest request = new MockHttpServletRequest();
@@ -129,6 +171,7 @@ public class RememberMeProcessingFilterTests extends TestCase {
"password",
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_REMEMBERED")});
RememberMeProcessingFilter filter = new RememberMeProcessingFilter();
+ filter.setAuthenticationManager(new MockAuthenticationManager());
filter.setRememberMeServices(new MockRememberMeServices(remembered));
filter.afterPropertiesSet();
@@ -149,6 +192,7 @@ public class RememberMeProcessingFilterTests extends TestCase {
"password",
new GrantedAuthority[] {new GrantedAuthorityImpl("ROLE_REMEMBERED")});
RememberMeProcessingFilter filter = new RememberMeProcessingFilter();
+ filter.setAuthenticationManager(new MockAuthenticationManager());
filter.setRememberMeServices(new MockRememberMeServices(remembered));
filter.afterPropertiesSet();
@@ -162,24 +206,6 @@ public class RememberMeProcessingFilterTests extends TestCase {
SecurityContextHolder.getContext().getAuthentication());
}
- protected void setUp() throws Exception {
- super.setUp();
- SecurityContextHolder.setContext(new SecurityContextImpl());
- }
-
- protected void tearDown() throws Exception {
- super.tearDown();
- SecurityContextHolder.setContext(new SecurityContextImpl());
- }
-
- private void executeFilterInContainerSimulator(FilterConfig filterConfig,
- Filter filter, ServletRequest request, ServletResponse response,
- FilterChain filterChain) throws ServletException, IOException {
- filter.init(filterConfig);
- filter.doFilter(request, response, filterChain);
- filter.destroy();
- }
-
//~ Inner Classes ==========================================================
private class MockFilterChain implements FilterChain {
diff --git a/samples/contacts/src/main/webapp/filter/WEB-INF/applicationContext-acegi-security.xml b/samples/contacts/src/main/webapp/filter/WEB-INF/applicationContext-acegi-security.xml
index d5883c0784..765ebb0987 100644
--- a/samples/contacts/src/main/webapp/filter/WEB-INF/applicationContext-acegi-security.xml
+++ b/samples/contacts/src/main/webapp/filter/WEB-INF/applicationContext-acegi-security.xml
@@ -90,6 +90,7 @@