diff --git a/core/src/main/java/org/springframework/security/config/BeanIds.java b/core/src/main/java/org/springframework/security/config/BeanIds.java
index a18f5b00ad..020f90b0fa 100644
--- a/core/src/main/java/org/springframework/security/config/BeanIds.java
+++ b/core/src/main/java/org/springframework/security/config/BeanIds.java
@@ -11,7 +11,7 @@ public abstract class BeanIds {
/** Package protected as end users shouldn't really be using this BFPP directly */
static final String INTERCEPT_METHODS_BEAN_FACTORY_POST_PROCESSOR = "_interceptMethodsBeanfactoryPP";
static final String CONTEXT_SOURCE_SETTING_POST_PROCESSOR = "_contextSettingPostProcessor";
- static final String HTTP_POST_PROCESSOR = "_httpConfigBeanFactoryPostProcessor";
+ static final String HTTP_POST_PROCESSOR = "_httpConfigBeanFactoryPostProcessor";
public static final String JDBC_USER_DETAILS_MANAGER = "_jdbcUserDetailsManager";
public static final String USER_DETAILS_SERVICE = "_userDetailsService";
@@ -43,5 +43,5 @@ public abstract class BeanIds {
public static final String METHOD_DEFINITION_ATTRIBUTES = "_methodDefinitionAttributes";
public static final String EMBEDDED_APACHE_DS = "_apacheDirectoryServerContainer";
public static final String CONTEXT_SOURCE = "_securityContextSource";
- public static final String PORT_MAPPER = "_portMapper";
+ public static final String PORT_MAPPER = "_portMapper";
}
diff --git a/core/src/main/java/org/springframework/security/config/UserServiceBeanDefinitionParser.java b/core/src/main/java/org/springframework/security/config/UserServiceBeanDefinitionParser.java
index a5fa4e7f18..cea8c76d6b 100644
--- a/core/src/main/java/org/springframework/security/config/UserServiceBeanDefinitionParser.java
+++ b/core/src/main/java/org/springframework/security/config/UserServiceBeanDefinitionParser.java
@@ -1,10 +1,16 @@
package org.springframework.security.config;
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.beans.factory.config.BeanDefinitionHolder;
+import org.springframework.beans.factory.config.PropertiesFactoryBean;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
+import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.security.userdetails.memory.InMemoryDaoImpl;
import org.springframework.security.userdetails.memory.UserMap;
import org.springframework.security.userdetails.User;
import org.springframework.security.util.AuthorityUtils;
+import org.springframework.util.StringUtils;
+import org.springframework.util.Assert;
import org.springframework.util.xml.DomUtils;
import org.w3c.dom.Element;
@@ -22,13 +28,30 @@ public class UserServiceBeanDefinitionParser extends AbstractUserDetailsServiceB
static final String ATT_NAME = "name";
static final String ELT_USER = "user";
static final String ATT_AUTHORITIES = "authorities";
+ static final String ATT_PROPERTIES = "properties";
protected Class getBeanClass(Element element) {
return InMemoryDaoImpl.class;
}
protected void doParse(Element element, BeanDefinitionBuilder builder) {
+ String userProperties = element.getAttribute(ATT_PROPERTIES);
List userElts = DomUtils.getChildElementsByTagName(element, ELT_USER);
+
+ if (StringUtils.hasText(userProperties)) {
+ Assert.isTrue(userElts.isEmpty(), "Use of a properties file ('" + ATT_PROPERTIES + "' attribute) and <" +
+ ELT_USER + "> elements are mutually exclusive.");
+
+ BeanDefinition bd = new RootBeanDefinition(PropertiesFactoryBean.class);
+ bd.getPropertyValues().addPropertyValue("location", userProperties);
+ builder.addPropertyValue("userProperties", bd);
+
+ return;
+ }
+
+ Assert.notEmpty(userElts, "You must supply user definitions, either with <" + ELT_USER + "> child elements or a " +
+ "properties file (specified with the '" + ATT_PROPERTIES + "' attribute)" );
+
UserMap users = new UserMap();
for (Iterator i = userElts.iterator(); i.hasNext();) {
diff --git a/core/src/test/java/org/springframework/security/config/UserServiceBeanDefinitionParserTests.java b/core/src/test/java/org/springframework/security/config/UserServiceBeanDefinitionParserTests.java
new file mode 100644
index 0000000000..cdc687c561
--- /dev/null
+++ b/core/src/test/java/org/springframework/security/config/UserServiceBeanDefinitionParserTests.java
@@ -0,0 +1,71 @@
+package org.springframework.security.config;
+
+import org.springframework.security.util.InMemoryXmlApplicationContext;
+import org.springframework.security.userdetails.UserDetailsService;
+import org.springframework.context.support.AbstractXmlApplicationContext;
+import org.springframework.beans.FatalBeanException;
+
+import org.junit.Test;
+import org.junit.After;
+
+/**
+ * @author Luke Taylor
+ * @version $Id$
+ */
+public class UserServiceBeanDefinitionParserTests {
+ private AbstractXmlApplicationContext appContext;
+
+ @After
+ public void closeAppContext() {
+ if (appContext != null) {
+ appContext.close();
+ }
+ }
+
+ @Test
+ public void userServiceWithValidPropertiesFileWorksSuccessfully() {
+ setContext(
+ "");
+ UserDetailsService userService = (UserDetailsService) appContext.getBean("service");
+ userService.loadUserByUsername("bob");
+ userService.loadUserByUsername("joe");
+ }
+
+ @Test
+ public void userServiceWithEmbeddedUsersWorksSuccessfully() {
+ setContext(
+ "" +
+ " " +
+ "");
+ UserDetailsService userService = (UserDetailsService) appContext.getBean("service");
+ userService.loadUserByUsername("joe");
+ }
+
+ @Test(expected=FatalBeanException.class)
+ public void userWithBothPropertiesAndEmbeddedUsersThrowsException() {
+ setContext(
+ "" +
+ " " +
+ "");
+ UserDetailsService userService = (UserDetailsService) appContext.getBean("service");
+ userService.loadUserByUsername("joe");
+ }
+
+ @Test(expected= FatalBeanException.class)
+ public void multipleTopLevelUseWithoutIdThrowsException() {
+ setContext(
+ "" +
+ "");
+
+ }
+
+ @Test(expected= FatalBeanException.class)
+ public void userServiceWithMissingPropertiesFileThrowsException() {
+ setContext("");
+ }
+
+ private void setContext(String context) {
+ appContext = new InMemoryXmlApplicationContext(context);
+ }
+}
diff --git a/core/src/test/resources/org/springframework/security/config/users.properties b/core/src/test/resources/org/springframework/security/config/users.properties
new file mode 100644
index 0000000000..d2369d9a08
--- /dev/null
+++ b/core/src/test/resources/org/springframework/security/config/users.properties
@@ -0,0 +1,2 @@
+joe=joespassword,ROLE_A
+bob=bobspassword,ROLE_A,ROLE_B