diff --git a/core/src/main/java/org/acegisecurity/config/AccessDeniedHandlerBeanDefinitionLocator.java b/core/src/main/java/org/acegisecurity/config/AccessDeniedHandlerBeanDefinitionLocator.java
new file mode 100644
index 0000000000..d3daa70e90
--- /dev/null
+++ b/core/src/main/java/org/acegisecurity/config/AccessDeniedHandlerBeanDefinitionLocator.java
@@ -0,0 +1,50 @@
+/**
+ *
+ */
+package org.acegisecurity.config;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.acegisecurity.ui.AccessDeniedHandler;
+import org.acegisecurity.ui.ExceptionTranslationFilter;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
+import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
+import org.springframework.beans.factory.support.RootBeanDefinition;
+import org.springframework.util.Assert;
+
+/**
+ * @author vpuri
+ *
+ */
+public class AccessDeniedHandlerBeanDefinitionLocator implements BeanFactoryPostProcessor {
+
+ public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
+
+ Map m = beanFactory.getBeansOfType(AccessDeniedHandler.class);
+
+ List l = new ArrayList(m.values());
+
+
+
+ if (m.size() > 1) {
+ throw new IllegalArgumentException(
+ "More than one AccessDeniedHandler beans detected please refer to the one using "
+ + " [ accessDeniedBeanRef ] " + "attribute");
+ }
+ else if (m.size() == 1) {
+ // use this
+ String[] names = beanFactory.getBeanNamesForType(ExceptionTranslationFilter.class);
+ Assert.notEmpty(names, "No bean of type ExceptionTranslationFilter found in ApplicationContext");
+ RootBeanDefinition definition = (RootBeanDefinition) beanFactory.getBeanDefinition(names[0]);
+ Assert.isAssignable(AccessDeniedHandler.class, l.get(0).getClass());
+ definition.getPropertyValues().addPropertyValue("accessDeniedHandler", l.get(0));
+ }
+ else {
+ // use the default one for now
+ }
+
+ }
+}
diff --git a/core/src/main/java/org/acegisecurity/config/AuthenticationProcessingFilterBeanDefinitionParser.java b/core/src/main/java/org/acegisecurity/config/AuthenticationProcessingFilterBeanDefinitionParser.java
new file mode 100644
index 0000000000..c6ce35ac26
--- /dev/null
+++ b/core/src/main/java/org/acegisecurity/config/AuthenticationProcessingFilterBeanDefinitionParser.java
@@ -0,0 +1,58 @@
+/**
+ *
+ */
+package org.acegisecurity.config;
+
+import org.acegisecurity.ui.webapp.AuthenticationProcessingFilter;
+import org.springframework.beans.factory.support.AbstractBeanDefinition;
+import org.springframework.beans.factory.support.RootBeanDefinition;
+import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;
+import org.springframework.beans.factory.xml.BeanDefinitionParser;
+import org.springframework.beans.factory.xml.ParserContext;
+import org.springframework.util.StringUtils;
+import org.w3c.dom.Element;
+
+/**
+ * @author vpuri
+ *
+ */
+public class AuthenticationProcessingFilterBeanDefinitionParser extends AbstractBeanDefinitionParser implements
+ BeanDefinitionParser {
+
+ // ~ Instance fields
+ // ================================================================================================
+
+ private static final String AUTHENTICATION_URL = "authenticationUrl";
+
+ private static final String ERROR_FORM_URL = "errorFormUrl";
+
+ private static final String DEFAULT_TARGET_URL = "defaultTargetUrl";
+
+ // ~ Methods
+ // ================================================================================================
+
+ protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
+
+ RootBeanDefinition definition = new RootBeanDefinition(AuthenticationProcessingFilter.class);
+
+ setPropertyIfAvailable(element, AUTHENTICATION_URL, "filterProcessesUrl", definition);
+ setPropertyIfAvailable(element, ERROR_FORM_URL, "authenticationFailureUrl", definition);
+ setPropertyIfAvailable(element, DEFAULT_TARGET_URL, "defaultTargetUrl", definition);
+
+ // register BFPP to re-unite all other collaborators
+ RootBeanDefinition postProcessor = new RootBeanDefinition(
+ AuthenticationProcessingFilterDependenciesConfigurer.class);
+ parserContext.getReaderContext().registerWithGeneratedName(postProcessor);
+
+ return definition;
+ }
+
+ private void setPropertyIfAvailable(Element element, String attribute, String property,
+ RootBeanDefinition definition) {
+ String propertyValue = element.getAttribute(attribute);
+ if (StringUtils.hasText(propertyValue)) {
+ definition.getPropertyValues().addPropertyValue(property, propertyValue);
+ }
+ }
+
+}
diff --git a/core/src/main/java/org/acegisecurity/config/AuthenticationProcessingFilterDependenciesConfigurer.java b/core/src/main/java/org/acegisecurity/config/AuthenticationProcessingFilterDependenciesConfigurer.java
new file mode 100644
index 0000000000..e134f41870
--- /dev/null
+++ b/core/src/main/java/org/acegisecurity/config/AuthenticationProcessingFilterDependenciesConfigurer.java
@@ -0,0 +1,43 @@
+/**
+ *
+ */
+package org.acegisecurity.config;
+
+import org.acegisecurity.AuthenticationManager;
+import org.acegisecurity.ui.rememberme.RememberMeServices;
+import org.acegisecurity.ui.webapp.AuthenticationProcessingFilter;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
+import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
+import org.springframework.beans.factory.support.RootBeanDefinition;
+
+/**
+ * @author vpuri
+ *
+ */
+public class AuthenticationProcessingFilterDependenciesConfigurer implements BeanFactoryPostProcessor {
+
+ // ~ Methods
+ // ================================================================================================
+ public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
+
+ String [] authenticationProcessingFilter = beanFactory.getBeanNamesForType(AuthenticationProcessingFilter.class);
+
+ RootBeanDefinition def = (RootBeanDefinition)beanFactory.getBeanDefinition(authenticationProcessingFilter[0]);
+
+ String[] remServiceNames = beanFactory.getBeanNamesForType(RememberMeServices.class);
+
+ RootBeanDefinition rememberMeServices = (RootBeanDefinition) beanFactory.getBeanDefinition(remServiceNames[0]);
+
+ if (remServiceNames.length > 0)
+ def.getPropertyValues()
+ .addPropertyValue("rememberMeServices", rememberMeServices);
+
+ String[] authManager = beanFactory.getBeanNamesForType(AuthenticationManager.class);
+
+ RootBeanDefinition authenticationManager = (RootBeanDefinition) beanFactory.getBeanDefinition(authManager[0]);
+
+ if (authManager.length > 0)
+ def.getPropertyValues().addPropertyValue("authenticationManager", authenticationManager);
+ }
+}
diff --git a/core/src/main/java/org/acegisecurity/config/ExceptionTranslationFilterBeanDefinitionParser.java b/core/src/main/java/org/acegisecurity/config/ExceptionTranslationFilterBeanDefinitionParser.java
new file mode 100644
index 0000000000..ec48ee99e2
--- /dev/null
+++ b/core/src/main/java/org/acegisecurity/config/ExceptionTranslationFilterBeanDefinitionParser.java
@@ -0,0 +1,121 @@
+/**
+ *
+ */
+package org.acegisecurity.config;
+
+import org.acegisecurity.ui.AccessDeniedHandlerImpl;
+import org.acegisecurity.ui.ExceptionTranslationFilter;
+import org.springframework.beans.factory.config.RuntimeBeanReference;
+import org.springframework.beans.factory.support.AbstractBeanDefinition;
+import org.springframework.beans.factory.support.RootBeanDefinition;
+import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;
+import org.springframework.beans.factory.xml.ParserContext;
+import org.springframework.util.StringUtils;
+import org.springframework.util.xml.DomUtils;
+import org.w3c.dom.Element;
+
+/**
+ * Basically accessDeniedUrl is optional, we if unspecified impl will
+ * auto-detect any AccessDeniedHandler in ctx and use it; alternately if there
+ * are > 1 such handlers, we can nominate the one to use via
+ * accessDeniedBeanRef;
+ *
+ * @author vpuri
+ * @since
+ */
+public class ExceptionTranslationFilterBeanDefinitionParser extends AbstractBeanDefinitionParser {
+
+ private static final String ACCESS_DENIED = "access-denied";
+
+ private static final String ACCESS_DENIED_REF = "accessDeniedBeanRef";
+
+ private static final String ACCESS_DENIED_URL = "accessDeniedUrl";
+
+ private static final String ENTRY_POINT = "entry-point";
+
+ private static final String ENTRY_POINT_REF ="entryPointBeanRef";
+
+ protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
+
+ RootBeanDefinition exceptionFilterDef = new RootBeanDefinition(ExceptionTranslationFilter.class);
+
+ // add handler
+ Element accessDeniedElement = DomUtils.getChildElementByTagName(element, ACCESS_DENIED);
+ setAccessDeniedHandlerProperty(parserContext, exceptionFilterDef, accessDeniedElement);
+
+ Element entryPointElement = DomUtils.getChildElementByTagName(element, ENTRY_POINT);
+ setEntryPointProperty(exceptionFilterDef, entryPointElement);
+
+ return exceptionFilterDef;
+ }
+
+ private void setEntryPointProperty(RootBeanDefinition exceptionFilterDef, Element entryPointElement) {
+ if (entryPointElement != null) {
+ setBeanReferenceOrInnerBeanDefinitions(exceptionFilterDef, entryPointElement, "authenticationEntryPoint",
+ entryPointElement.getAttribute(ENTRY_POINT_REF));
+ }
+ }
+
+ /**
+ *
+ * @param parserContext
+ * @param repositoryBeanDef
+ * @param element
+ */
+ private void setAccessDeniedHandlerProperty(ParserContext parserContext, RootBeanDefinition exceptionFilterDef,
+ Element accessDeniedElement) {
+ if (accessDeniedElement != null) {
+ setBeanReferenceOrInnerBeanDefinitions(exceptionFilterDef, accessDeniedElement, "accessDeniedHandler",
+ accessDeniedElement.getAttribute(ACCESS_DENIED_REF));
+ }
+ else {
+ // register BFPP to check if handler exist in application context,
+ // if > 1 throw error saying ref should be specified as there are
+ // more than one
+ RootBeanDefinition accessDeniedHandlerLocatorBeanDef = new RootBeanDefinition(
+ AccessDeniedHandlerBeanDefinitionLocator.class);
+ parserContext.getReaderContext().registerWithGeneratedName(accessDeniedHandlerLocatorBeanDef);
+ }
+ }
+
+ /**
+ *
+ * @param repositoryBeanDef
+ * @param element
+ * @param property
+ * @param reference
+ */
+ private void setBeanReferenceOrInnerBeanDefinitions(RootBeanDefinition exceptionFilterDef,
+ Element element, String property, String beanRef) {
+ // check for encoderBeanRef attribute
+ if (StringUtils.hasLength(beanRef)) {
+ exceptionFilterDef.getPropertyValues().addPropertyValue(property,
+ new RuntimeBeanReference(beanRef));
+ }
+ else {
+ doSetInnerBeanDefinitions(exceptionFilterDef, element, property);
+ }
+ }
+
+ /**
+ *
+ * @param repositoryBeanDef
+ * @param element
+ * @param property
+ */
+ private void doSetInnerBeanDefinitions(RootBeanDefinition exceptionFilterDef, Element accessDeniedElement,
+ String property) {
+ RootBeanDefinition accessDeniedHandlerBeanDef = new RootBeanDefinition(AccessDeniedHandlerImpl.class);
+ setPropertyIfAvailable(accessDeniedElement, ACCESS_DENIED_URL, "errorPage", accessDeniedHandlerBeanDef);
+ exceptionFilterDef.getPropertyValues().addPropertyValue(property, accessDeniedHandlerBeanDef);
+
+ }
+
+ private void setPropertyIfAvailable(Element element, String attribute, String property,
+ RootBeanDefinition definition) {
+ String propertyValue = element.getAttribute(attribute);
+ if (StringUtils.hasText(propertyValue)) {
+ definition.getPropertyValues().addPropertyValue(property, propertyValue);
+ }
+ }
+}
diff --git a/core/src/test/java/org/acegisecurity/config/AuthenticationProcessingFilterNamespaceTests.java b/core/src/test/java/org/acegisecurity/config/AuthenticationProcessingFilterNamespaceTests.java
new file mode 100644
index 0000000000..7a849525b6
--- /dev/null
+++ b/core/src/test/java/org/acegisecurity/config/AuthenticationProcessingFilterNamespaceTests.java
@@ -0,0 +1,25 @@
+/**
+ *
+ */
+package org.acegisecurity.config;
+
+import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+
+import junit.framework.TestCase;
+
+/**
+ * @author vpuri
+ *
+ */
+public class AuthenticationProcessingFilterNamespaceTests extends TestCase {
+
+ public void testAuthenticationFilterBeanDefinition() {
+ ApplicationContext context = new ClassPathXmlApplicationContext(
+ "org/acegisecurity/config/authentication-form-filter.xml");
+ConfigurableListableBeanFactory factory = (ConfigurableListableBeanFactory) context
+ .getAutowireCapableBeanFactory();
+ }
+
+}
diff --git a/core/src/test/java/org/acegisecurity/config/ExceptionTranslationParserTests.java b/core/src/test/java/org/acegisecurity/config/ExceptionTranslationParserTests.java
new file mode 100644
index 0000000000..f38282233a
--- /dev/null
+++ b/core/src/test/java/org/acegisecurity/config/ExceptionTranslationParserTests.java
@@ -0,0 +1,47 @@
+package org.acegisecurity.config;
+
+import javax.servlet.Filter;
+
+import junit.framework.TestCase;
+
+import org.acegisecurity.ui.ExceptionTranslationFilter;
+import org.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint;
+import org.springframework.beans.PropertyValue;
+import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
+import org.springframework.beans.factory.config.RuntimeBeanReference;
+import org.springframework.beans.factory.support.RootBeanDefinition;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+
+public class ExceptionTranslationParserTests extends TestCase {
+
+ public void testParsingBeanReferences() {
+ ApplicationContext context = new ClassPathXmlApplicationContext(
+ "org/acegisecurity/config/exception-translation-beanref.xml");
+ ConfigurableListableBeanFactory factory = (ConfigurableListableBeanFactory) context
+ .getAutowireCapableBeanFactory();
+ String[] beanNames = factory.getBeanNamesForType(Filter.class);
+ assertEquals(1, beanNames.length);
+ RootBeanDefinition def = (RootBeanDefinition) factory.getBeanDefinition(beanNames[0]);
+ assertEquals(ExceptionTranslationFilter.class.getName(), def.getBeanClassName());
+ // check collaborators
+ PropertyValue accessDeniedHandler = def.getPropertyValues().getPropertyValue("accessDeniedHandler");
+ assertNotNull(accessDeniedHandler);
+ assertEquals(accessDeniedHandler.getValue(), new RuntimeBeanReference("theBeanToUse"));
+ PropertyValue entryPoint = def.getPropertyValues().getPropertyValue("authenticationEntryPoint");
+ assertNotNull(entryPoint);
+ assertEquals(entryPoint.getValue(), new RuntimeBeanReference("authenticationProcessingFilterEntryPoint"));
+ }
+
+ public void testRuntimeBeanDependencies() {
+ ApplicationContext context = new ClassPathXmlApplicationContext(
+ "org/acegisecurity/config/exception-translation-beanref.xml");
+ ExceptionTranslationFilter filter = (ExceptionTranslationFilter) context.getBean("exceptionTranslationFilter");
+ AuthenticationProcessingFilterEntryPoint entryPoint = (AuthenticationProcessingFilterEntryPoint) filter
+ .getAuthenticationEntryPoint();
+ assertEquals("/acegilogin.jsp", entryPoint.getLoginFormUrl());
+ assertFalse(entryPoint.getForceHttps());
+
+ }
+
+}
diff --git a/core/src/test/resources/org/acegisecurity/config/authentication-basic-filter.xml b/core/src/test/resources/org/acegisecurity/config/authentication-basic-filter.xml
new file mode 100644
index 0000000000..5eca57c38b
--- /dev/null
+++ b/core/src/test/resources/org/acegisecurity/config/authentication-basic-filter.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/core/src/test/resources/org/acegisecurity/config/authentication-form-filter.xml b/core/src/test/resources/org/acegisecurity/config/authentication-form-filter.xml
new file mode 100644
index 0000000000..3187c14593
--- /dev/null
+++ b/core/src/test/resources/org/acegisecurity/config/authentication-form-filter.xml
@@ -0,0 +1,57 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ org.hsqldb.jdbcDriver
+
+
+ jdbc:hsqldb:mem:test
+
+
+
+ sa
+
+
+
+
+
+
+
+
+
diff --git a/core/src/test/resources/org/acegisecurity/config/exception-translation-autodetect-handler.xml b/core/src/test/resources/org/acegisecurity/config/exception-translation-autodetect-handler.xml
new file mode 100644
index 0000000000..2499d50fa9
--- /dev/null
+++ b/core/src/test/resources/org/acegisecurity/config/exception-translation-autodetect-handler.xml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ /acegilogin.jsp
+
+
+ false
+
+
+
\ No newline at end of file
diff --git a/core/src/test/resources/org/acegisecurity/config/exception-translation-beanref.xml b/core/src/test/resources/org/acegisecurity/config/exception-translation-beanref.xml
new file mode 100644
index 0000000000..67d5426a59
--- /dev/null
+++ b/core/src/test/resources/org/acegisecurity/config/exception-translation-beanref.xml
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ /acegilogin.jsp
+
+
+ false
+
+
+
\ No newline at end of file
diff --git a/core/src/test/resources/org/acegisecurity/config/security-autoconfig-autodetect.xml b/core/src/test/resources/org/acegisecurity/config/security-autoconfig-autodetect.xml
new file mode 100644
index 0000000000..2a9ea4358e
--- /dev/null
+++ b/core/src/test/resources/org/acegisecurity/config/security-autoconfig-autodetect.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file