diff --git a/core/src/main/java/org/acegisecurity/ui/AbstractProcessingFilter.java b/core/src/main/java/org/acegisecurity/ui/AbstractProcessingFilter.java index 82445d37b9..86388f9a88 100644 --- a/core/src/main/java/org/acegisecurity/ui/AbstractProcessingFilter.java +++ b/core/src/main/java/org/acegisecurity/ui/AbstractProcessingFilter.java @@ -27,6 +27,9 @@ import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.InitializingBean; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; + import org.springframework.util.Assert; import java.io.IOException; @@ -112,6 +115,14 @@ import javax.servlet.http.HttpServletResponse; * exceptionMappings will be redirected to the * authenticationFailureUrl *

+ * + *

+ * If authentication is successful, an {@link + * net.sf.acegisecurity.ui.InteractiveAuthenticationSuccesEvent} 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. + *

* * @author Ben Alex * @author colin sampaleanu @@ -119,7 +130,7 @@ import javax.servlet.http.HttpServletResponse; * @version $Id$ */ public abstract class AbstractProcessingFilter implements Filter, - InitializingBean { + InitializingBean, ApplicationContextAware { //~ Static fields/initializers ============================================= public static final String ACEGI_SECURITY_TARGET_URL_KEY = "ACEGI_SECURITY_TARGET_URL"; @@ -128,6 +139,7 @@ public abstract class AbstractProcessingFilter implements Filter, //~ Instance fields ======================================================== + private ApplicationContext context; private AuthenticationManager authenticationManager; private Properties exceptionMappings = new Properties(); private RememberMeServices rememberMeServices = new NullRememberMeServices(); @@ -172,6 +184,10 @@ public abstract class AbstractProcessingFilter implements Filter, return alwaysUseDefaultTargetUrl; } + public void setApplicationContext(ApplicationContext context) { + this.context = context; + } + public void setContinueChainBeforeSuccessfulAuthentication( boolean continueChainBeforeSuccessfulAuthentication) { this.continueChainBeforeSuccessfulAuthentication = continueChainBeforeSuccessfulAuthentication; @@ -189,6 +205,14 @@ public abstract class AbstractProcessingFilter implements Filter, */ public abstract String getDefaultFilterProcessesUrl(); + public void setDefaultTargetUrl(String defaultTargetUrl) { + this.defaultTargetUrl = defaultTargetUrl; + } + + public String getDefaultTargetUrl() { + return defaultTargetUrl; + } + public void setExceptionMappings(Properties exceptionMappings) { this.exceptionMappings = exceptionMappings; } @@ -197,6 +221,14 @@ public abstract class AbstractProcessingFilter implements Filter, return new Properties(exceptionMappings); } + public void setFilterProcessesUrl(String filterProcessesUrl) { + this.filterProcessesUrl = filterProcessesUrl; + } + + public String getFilterProcessesUrl() { + return filterProcessesUrl; + } + public void setRememberMeServices(RememberMeServices rememberMeServices) { this.rememberMeServices = rememberMeServices; } @@ -235,22 +267,6 @@ public abstract class AbstractProcessingFilter implements Filter, return authenticationManager; } - public void setDefaultTargetUrl(String defaultTargetUrl) { - this.defaultTargetUrl = defaultTargetUrl; - } - - public String getDefaultTargetUrl() { - return defaultTargetUrl; - } - - public void setFilterProcessesUrl(String filterProcessesUrl) { - this.filterProcessesUrl = filterProcessesUrl; - } - - public String getFilterProcessesUrl() { - return filterProcessesUrl; - } - public void afterPropertiesSet() throws Exception { Assert.hasLength(filterProcessesUrl, "filterProcessesUrl must be specified"); @@ -403,6 +419,12 @@ public abstract class AbstractProcessingFilter implements Filter, rememberMeServices.loginSuccess(request, response, authResult); + // Fire event + if (this.context != null) { + context.publishEvent(new InteractiveAuthenticationSuccesEvent( + authResult, this.getClass())); + } + response.sendRedirect(response.encodeRedirectURL(targetUrl)); } diff --git a/core/src/main/java/org/acegisecurity/ui/InteractiveAuthenticationSuccesEvent.java b/core/src/main/java/org/acegisecurity/ui/InteractiveAuthenticationSuccesEvent.java new file mode 100644 index 0000000000..c709a826e1 --- /dev/null +++ b/core/src/main/java/org/acegisecurity/ui/InteractiveAuthenticationSuccesEvent.java @@ -0,0 +1,71 @@ +/* Copyright 2004, 2005 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 net.sf.acegisecurity.ui; + +import net.sf.acegisecurity.Authentication; + +import org.springframework.context.ApplicationEvent; + +import org.springframework.util.Assert; + + +/** + * Indicates an interactive authentication was successful. + * + *

+ * The ApplicationEvent's source will be the + * Authentication object. + *

+ * + * @author Ben Alex + * @version $Id$ + */ +public class InteractiveAuthenticationSuccesEvent extends ApplicationEvent { + //~ Instance fields ======================================================== + + private Class generatedBy; + + //~ Constructors =========================================================== + + public InteractiveAuthenticationSuccesEvent(Authentication authentication, + Class generatedBy) { + super(authentication); + Assert.notNull(generatedBy); + this.generatedBy = generatedBy; + } + + //~ Methods ================================================================ + + /** + * Getters for the Authentication request that caused the + * event. Also available from super.getSource(). + * + * @return the authentication request + */ + public Authentication getAuthentication() { + return (Authentication) super.getSource(); + } + + /** + * Getter for the Class that generated this event. This can be + * useful for generating additional logging information. + * + * @return + */ + public Class getGeneratedBy() { + return generatedBy; + } +} 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 6a59a9abec..ad742722f4 100644 --- a/core/src/main/java/org/acegisecurity/ui/rememberme/RememberMeProcessingFilter.java +++ b/core/src/main/java/org/acegisecurity/ui/rememberme/RememberMeProcessingFilter.java @@ -16,12 +16,16 @@ package net.sf.acegisecurity.ui.rememberme; import net.sf.acegisecurity.context.SecurityContextHolder; +import net.sf.acegisecurity.ui.InteractiveAuthenticationSuccesEvent; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.InitializingBean; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; + import org.springframework.util.Assert; import java.io.IOException; @@ -52,6 +56,14 @@ import javax.servlet.http.HttpServletResponse; * will be placed into the SecurityContext. *

* + *

+ * If authentication is successful, an {@link + * net.sf.acegisecurity.ui.InteractiveAuthenticationSuccesEvent} 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. + *

+ * *

* Do not use this class directly. Instead configure * web.xml to use the {@link @@ -61,17 +73,23 @@ import javax.servlet.http.HttpServletResponse; * @author Ben Alex * @version $Id$ */ -public class RememberMeProcessingFilter implements Filter, InitializingBean { +public class RememberMeProcessingFilter implements Filter, InitializingBean, + ApplicationContextAware { //~ Static fields/initializers ============================================= private static final Log logger = LogFactory.getLog(RememberMeProcessingFilter.class); //~ Instance fields ======================================================== + private ApplicationContext context; private RememberMeServices rememberMeServices = new NullRememberMeServices(); //~ Methods ================================================================ + public void setApplicationContext(ApplicationContext context) { + this.context = context; + } + public void setRememberMeServices(RememberMeServices rememberMeServices) { this.rememberMeServices = rememberMeServices; } @@ -112,6 +130,13 @@ public class RememberMeProcessingFilter implements Filter, InitializingBean { + SecurityContextHolder.getContext().getAuthentication() + "'"); } + + // Fire event + if (this.context != null) { + context.publishEvent(new InteractiveAuthenticationSuccesEvent( + SecurityContextHolder.getContext().getAuthentication(), + this.getClass())); + } } else { if (logger.isDebugEnabled()) { logger.debug( diff --git a/core/src/main/java/org/acegisecurity/ui/x509/X509ProcessingFilter.java b/core/src/main/java/org/acegisecurity/ui/x509/X509ProcessingFilter.java index b40ef1e353..5f2db93ba5 100644 --- a/core/src/main/java/org/acegisecurity/ui/x509/X509ProcessingFilter.java +++ b/core/src/main/java/org/acegisecurity/ui/x509/X509ProcessingFilter.java @@ -21,6 +21,7 @@ import net.sf.acegisecurity.AuthenticationManager; import net.sf.acegisecurity.context.SecurityContextHolder; import net.sf.acegisecurity.providers.x509.X509AuthenticationToken; import net.sf.acegisecurity.ui.AbstractProcessingFilter; +import net.sf.acegisecurity.ui.InteractiveAuthenticationSuccesEvent; import net.sf.acegisecurity.ui.WebAuthenticationDetails; import org.apache.commons.logging.Log; @@ -28,6 +29,9 @@ import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.InitializingBean; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; + import org.springframework.util.Assert; import java.io.IOException; @@ -55,6 +59,14 @@ import javax.servlet.http.HttpServletResponse; *

* *

+ * If authentication is successful, an {@link + * net.sf.acegisecurity.ui.InteractiveAuthenticationSuccesEvent} 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. + *

+ * + *

* Do not use this class directly. Instead configure * web.xml to use the {@link * net.sf.acegisecurity.util.FilterToBeanProxy}. @@ -63,17 +75,23 @@ import javax.servlet.http.HttpServletResponse; * @author Luke Taylor * @version $Id$ */ -public class X509ProcessingFilter implements Filter, InitializingBean { +public class X509ProcessingFilter implements Filter, InitializingBean, + ApplicationContextAware { //~ Static fields/initializers ============================================= private static final Log logger = LogFactory.getLog(X509ProcessingFilter.class); //~ Instance fields ======================================================== + private ApplicationContext context; private AuthenticationManager authenticationManager; //~ Methods ================================================================ + public void setApplicationContext(ApplicationContext context) { + this.context = context; + } + public void setAuthenticationManager( AuthenticationManager authenticationManager) { this.authenticationManager = authenticationManager; @@ -167,6 +185,12 @@ public class X509ProcessingFilter implements Filter, InitializingBean { } SecurityContextHolder.getContext().setAuthentication(authResult); + + // Fire event + if (this.context != null) { + context.publishEvent(new InteractiveAuthenticationSuccesEvent( + authResult, this.getClass())); + } } /**