SEC-1263: Add FactoryBean for namespace AuthenticationManager. <http> now uses AuthenticationManagerFactoryBean. Method security already uses a delegate object to lookup the AuthenticationManager. This now uses the same error message if the bean isn't found, rather than allowing the BeanFactory NoSuchBeanDefinitionException to be thrown directly.

This commit is contained in:
Luke Taylor 2009-10-09 14:41:34 +00:00
parent ac5237c127
commit ed2ddf9323
4 changed files with 48 additions and 19 deletions

View File

@ -9,7 +9,7 @@ package org.springframework.security.config;
* @version $Id: BeanIds.java 3770 2009-07-15 23:09:47Z ltaylor $
*/
public abstract class BeanIds {
private static final String PREFIX = "org.springframework.security";
private static final String PREFIX = "org.springframework.security.";
/** The "global" AuthenticationManager instance, registered by the <authentication-manager> element */
public static final String AUTHENTICATION_MANAGER = PREFIX + "authenticationManager";

View File

@ -1,7 +1,5 @@
package org.springframework.security.config.authentication;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
@ -21,17 +19,18 @@ import org.springframework.security.config.BeanIds;
* @since 3.0
*/
public class AuthenticationManagerFactoryBean implements FactoryBean<AuthenticationManager>, BeanFactoryAware {
private final Log logger = LogFactory.getLog(getClass());
private BeanFactory bf;
public static final String MISSING_BEAN_ERROR_MESSAGE = "Did you forget to add an <authentication-manager> element " +
"to your configuration (with child <authentication-provider> elements) ?";
public AuthenticationManager getObject() throws Exception {
try {
return (AuthenticationManager) bf.getBean(BeanIds.AUTHENTICATION_MANAGER);
} catch (NoSuchBeanDefinitionException e) {
logger.error(BeanIds.AUTHENTICATION_MANAGER + " bean was not found in the application context.");
throw new NoSuchBeanDefinitionException("The namespace AuthenticationManager was not found. " +
"Did you forget to add an <authentication-manager> element to your configuration with " +
"child <authentication-provider> elements ?");
if (BeanIds.AUTHENTICATION_MANAGER.equals(e.getBeanName())) {
throw new NoSuchBeanDefinitionException(BeanIds.AUTHENTICATION_MANAGER, MISSING_BEAN_ERROR_MESSAGE);
}
throw e;
}
}

View File

@ -14,6 +14,7 @@ import org.springframework.beans.BeanMetadataElement;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanReference;
import org.springframework.beans.factory.config.RuntimeBeanReference;
@ -48,6 +49,7 @@ import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.config.BeanIds;
import org.springframework.security.config.Elements;
import org.springframework.security.config.authentication.AuthenticationManagerFactoryBean;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.util.Assert;
@ -77,7 +79,6 @@ public class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionP
private static final String ATT_REF = "ref";
private static final String ATT_ADVICE_ORDER = "order";
// @SuppressWarnings("unchecked")
public BeanDefinition parse(Element element, ParserContext pc) {
CompositeComponentDefinition compositeDef =
new CompositeComponentDefinition(element.getTagName(), pc.extractSource(element));
@ -287,7 +288,6 @@ public class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionP
String runAsManagerId, BeanReference metadataSource, List<BeanMetadataElement> afterInvocationProviders, Object source) {
BeanDefinitionBuilder bldr = BeanDefinitionBuilder.rootBeanDefinition(MethodSecurityInterceptor.class);
bldr.getRawBeanDefinition().setSource(source);
bldr.addPropertyReference("accessDecisionManager", accessManagerId);
bldr.addPropertyValue("authenticationManager", new RootBeanDefinition(AuthenticationManagerDelegator.class));
bldr.addPropertyValue("securityMetadataSource", metadataSource);
@ -335,7 +335,7 @@ public class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionP
* @author Luke Taylor
* @since 3.0
*/
public static final class AuthenticationManagerDelegator implements AuthenticationManager, BeanFactoryAware {
static final class AuthenticationManagerDelegator implements AuthenticationManager, BeanFactoryAware {
private AuthenticationManager delegate;
private final Object delegateMonitor = new Object();
private BeanFactory beanFactory;
@ -344,7 +344,15 @@ public class GlobalMethodSecurityBeanDefinitionParser implements BeanDefinitionP
synchronized(delegateMonitor) {
if (delegate == null) {
Assert.state(beanFactory != null, "BeanFactory must be set to resolve " + BeanIds.AUTHENTICATION_MANAGER);
delegate = beanFactory.getBean(BeanIds.AUTHENTICATION_MANAGER, ProviderManager.class);
try {
delegate = beanFactory.getBean(BeanIds.AUTHENTICATION_MANAGER, ProviderManager.class);
} catch (NoSuchBeanDefinitionException e) {
if (BeanIds.AUTHENTICATION_MANAGER.equals(e.getBeanName())) {
throw new NoSuchBeanDefinitionException(BeanIds.AUTHENTICATION_MANAGER,
AuthenticationManagerFactoryBean.MISSING_BEAN_ERROR_MESSAGE);
}
throw e;
}
}
}

View File

@ -1,34 +1,56 @@
package org.springframework.security.config;
import static org.junit.Assert.*;
import org.junit.After;
import org.junit.Test;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.xml.XmlBeanDefinitionStoreException;
import org.springframework.security.config.authentication.AuthenticationManagerFactoryBean;
import org.springframework.security.config.util.InMemoryXmlApplicationContext;
/**
* Tests which make sure invalid configurations are rejected by the namespace. In particular invalid top-level
* Tests which make sure invalid configurations are rejected by the namespace. In particular invalid top-level
* elements. These are likely to fail after the namespace has been updated using trang, but the spring-security.xsl
* transform has not been applied.
*
* transform has not been applied.
*
* @author Luke Taylor
* @version $Id$
*/
public class InvalidConfigurationTests {
private InMemoryXmlApplicationContext appContext;
@After
public void closeAppContext() {
if (appContext != null) {
appContext.close();
}
}
}
// Parser should throw a SAXParseException
@Test(expected=XmlBeanDefinitionStoreException.class)
public void passwordEncoderCannotAppearAtTopLevel() {
setContext("<password-encoder hash='md5'/>");
}
@Test(expected=XmlBeanDefinitionStoreException.class)
public void authenticationProviderCannotAppearAtTopLevel() {
setContext("<authentication-provider ref='blah'/>");
}
@Test
public void missingAuthenticationManagerGivesSensibleErrorMessage() {
try {
setContext("<http auto-config='true' />");
} catch (BeanCreationException e) {
assertTrue(e.getCause().getCause() instanceof NoSuchBeanDefinitionException);
NoSuchBeanDefinitionException nsbe = (NoSuchBeanDefinitionException) e.getCause().getCause();
assertEquals(BeanIds.AUTHENTICATION_MANAGER, nsbe.getBeanName());
assertTrue(nsbe.getMessage().endsWith(AuthenticationManagerFactoryBean.MISSING_BEAN_ERROR_MESSAGE));
}
}
private void setContext(String context) {
appContext = new InMemoryXmlApplicationContext(context);
}