Browse Source

SEC-630: Support for "properties" attribute in user-service namespace element.

Luke Taylor 17 years ago
parent
commit
9836bda5b3

+ 2 - 2
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";
 }

+ 23 - 0
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();) {

+ 71 - 0
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(
+                "<user-service id='service' " +
+                        "properties='classpath:org/springframework/security/config/users.properties'/>");
+        UserDetailsService userService = (UserDetailsService) appContext.getBean("service");
+        userService.loadUserByUsername("bob");
+        userService.loadUserByUsername("joe");
+    }
+
+    @Test
+    public void userServiceWithEmbeddedUsersWorksSuccessfully() {
+        setContext(
+                "<user-service id='service'>" +
+                "    <user name='joe' password='joespassword' authorities='ROLE_A'/>" +
+                "</user-service>");
+        UserDetailsService userService = (UserDetailsService) appContext.getBean("service");
+        userService.loadUserByUsername("joe");
+    }
+
+    @Test(expected=FatalBeanException.class)
+    public void userWithBothPropertiesAndEmbeddedUsersThrowsException() {
+        setContext(
+                "<user-service id='service' properties='doesntmatter.props'>" +
+                "    <user name='joe' password='joespassword' authorities='ROLE_A'/>" +
+                "</user-service>");
+        UserDetailsService userService = (UserDetailsService) appContext.getBean("service");
+        userService.loadUserByUsername("joe");
+    }
+
+    @Test(expected= FatalBeanException.class)
+    public void multipleTopLevelUseWithoutIdThrowsException() {
+        setContext(
+                "<user-service properties='classpath:org/springframework/security/config/users.properties'/>" +
+                "<user-service properties='classpath:org/springframework/security/config/users.properties'/>");
+
+    }
+
+    @Test(expected= FatalBeanException.class)
+    public void userServiceWithMissingPropertiesFileThrowsException() {
+        setContext("<user-service id='service' properties='classpath:doesntexist.properties'/>");
+    }
+
+    private void setContext(String context) {
+        appContext = new InMemoryXmlApplicationContext(context);
+    }
+}

+ 2 - 0
core/src/test/resources/org/springframework/security/config/users.properties

@@ -0,0 +1,2 @@
+joe=joespassword,ROLE_A
+bob=bobspassword,ROLE_A,ROLE_B