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