Browse Source

SEC-271: Added more BeanDefinitionParsers and extend spring-security.xsd to have more elements

Vishal Puri 18 years ago
parent
commit
51f306a19a

+ 1 - 4
core/src/main/java/org/acegisecurity/config/AuthenticationMechanismBeanDefinitionParser.java

@@ -3,9 +3,6 @@
  */
 package org.acegisecurity.config;
 
-import java.util.ArrayList;
-import java.util.List;
-
 import org.acegisecurity.providers.ProviderManager;
 import org.springframework.beans.factory.config.BeanDefinitionHolder;
 import org.springframework.beans.factory.config.RuntimeBeanReference;
@@ -28,7 +25,7 @@ import org.w3c.dom.NodeList;
 public class AuthenticationMechanismBeanDefinitionParser extends AbstractBeanDefinitionParser implements
 		BeanDefinitionParser {
 
-	private static final Object AUTHENTICATION_JDBC = "authentication-jdbc";
+	private static final String AUTHENTICATION_JDBC = "authentication-jdbc";
 
 	private static final String REF = "ref";
 

+ 2 - 2
core/src/main/java/org/acegisecurity/config/AuthenticationRepositoryBeanDefinitionParser.java

@@ -25,7 +25,7 @@ import org.w3c.dom.NodeList;
  */
 public class AuthenticationRepositoryBeanDefinitionParser extends AbstractBeanDefinitionParser   {
 
-//	~ Instance fields ================================================================================================
+	//	~ Instance fields ================================================================================================
 
 	private static final String REPOSITORY_BEAN_REF = "repositoryBeanRef";
 
@@ -49,7 +49,7 @@ public class AuthenticationRepositoryBeanDefinitionParser extends AbstractBeanDe
 	
 	
 	
-//	~ Method ================================================================================================
+	//	~ Method ================================================================================================
 	/**
 	 * TODO: Document Me !!!
 	 */

+ 175 - 16
core/src/main/java/org/acegisecurity/config/PrincipalRepositoryBeanDefinitionParser.java

@@ -3,9 +3,22 @@
  */
 package org.acegisecurity.config;
 
+import java.util.Properties;
+
+import org.acegisecurity.GrantedAuthorityImpl;
+import org.acegisecurity.userdetails.User;
+import org.acegisecurity.userdetails.UserDetails;
 import org.acegisecurity.userdetails.jdbc.JdbcDaoImpl;
+import org.acegisecurity.userdetails.memory.InMemoryDaoImpl;
+import org.acegisecurity.userdetails.memory.UserAttribute;
+import org.acegisecurity.userdetails.memory.UserMap;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.beans.factory.config.PropertiesFactoryBean;
 import org.springframework.beans.factory.config.RuntimeBeanReference;
 import org.springframework.beans.factory.support.AbstractBeanDefinition;
+import org.springframework.beans.factory.support.BeanDefinitionBuilder;
+import org.springframework.beans.factory.support.ManagedList;
 import org.springframework.beans.factory.support.RootBeanDefinition;
 import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;
 import org.springframework.beans.factory.xml.BeanDefinitionParser;
@@ -15,44 +28,128 @@ import org.w3c.dom.Element;
 import org.w3c.dom.Node;
 import org.w3c.dom.NodeList;
 
-/**
+/**   
  * @author vpuri
  * 
  */
 public class PrincipalRepositoryBeanDefinitionParser extends AbstractBeanDefinitionParser implements
 		BeanDefinitionParser {
 	
-	//	~ Instance fields ================================================================================================
+	//	~ Static fields/initializers =====================================================================================
+
+    private static final Log logger = LogFactory.getLog(PrincipalRepositoryBeanDefinitionParser.class);
+
+	// ~ Instance fields
+	// ================================================================================================
 	private static final String JDBC = "jdbc";
+
 	private static final String DATASOURCE_REF = "dataSourceBeanRef";
+
 	private static final String DATASOURCE = "dataSource";
+
 	private static final String JDBCTEMPLATE_REF = "jdbcTemplateBeanRef";
+
 	private static final String JDBCTEMPLATE = "jdbcTemplate";
+
 	private static final String AUTHORITIES_BY_USERNAME_QUERY = "authoritiesByUsernameQuery";
+
 	private static final String ROLE_PREFIX = "rolePrefix";
-	private static final String USERNAME_BASED_PRIMARY_KEY="usernameBasedPrimaryKey";
-	
-	//authoritiesByUsernameQuery=""  rolePrefix="" usernameBasedPrimaryKey="true"  usersByUsernameQuery=""
+
+	private static final String USERNAME_BASED_PRIMARY_KEY = "usernameBasedPrimaryKey";
+
+	private static final String PROPERTIES = "properties";
+
+	private static final String RESOURCE = "resource";
+
+	private static final String USER_PROPERTIES = "userProperties";
+
+	private static final String USER_DEFINITION = "user-definition";
+
+	private static final Object GRANTED_AUTHORITY = "granted-authority";
+
+	private static final String USERNAME = "username";
+
+	private static final String PASSWORD = "password";
+
+	private static final String ENABLED = "enabled";
+
+	private static final String GRANTED_AUTHORITY_REF = "granted-authority-ref";
+
+	private static final String AUTHORITY = "authority";
 	
-	//	~ Method ================================================================================================
+	private static final String AUTHORITY_BEAN_REF="authorityBeanRef";
+
+	// ~ Method
+	// ================================================================================================
+	/**
+	 * 
+	 */
 	
 	protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
-
 		NodeList userDetailsServiceChildren = element.getChildNodes();
-		RootBeanDefinition userDetailsServiceJdbcDefinition = null;
+		RootBeanDefinition userDetailsServiceDefinition = null;
 		for (int i = 0, n = userDetailsServiceChildren.getLength(); i < n; i++) {
 			Node userDetailsService = userDetailsServiceChildren.item(i);
 
 			if (JDBC.equals(userDetailsService.getLocalName()) && userDetailsService.getNodeType() == Node.ELEMENT_NODE) {
 				Element ele = (Element) userDetailsService;
-				userDetailsServiceJdbcDefinition = parseUserDetailsServiceJdbcDefinition(ele);
-				userDetailsServiceJdbcDefinition.setSource(parserContext.extractSource(element));
-				parserContext.getReaderContext().registerWithGeneratedName(userDetailsServiceJdbcDefinition);
+				userDetailsServiceDefinition = parseUserDetailsServiceJdbcDefinition(ele);
+				userDetailsServiceDefinition.setSource(parserContext.extractSource(element));
+				parserContext.getReaderContext().registerWithGeneratedName(userDetailsServiceDefinition);
+			}
+			if (PROPERTIES.equals(userDetailsService.getLocalName())
+					&& userDetailsService.getNodeType() == Node.ELEMENT_NODE) {
+				Element ele = (Element) userDetailsService;
+
+				userDetailsServiceDefinition = new RootBeanDefinition(InMemoryDaoImpl.class);
+				userDetailsServiceDefinition.getPropertyValues().addPropertyValue(USER_PROPERTIES,
+						new RuntimeBeanReference(createPropertiesBeanDefinition(ele, parserContext)));
+				userDetailsServiceDefinition.setSource(parserContext.extractSource(element));
+				parserContext.getReaderContext().registerWithGeneratedName(userDetailsServiceDefinition);
+			}
+			if (USER_DEFINITION.equals(userDetailsService.getLocalName())
+					&& userDetailsService.getNodeType() == Node.ELEMENT_NODE) {
+				Element ele = (Element) userDetailsService;
+
+				// create a UserMap which interns uses UserMapEditor
+				userDetailsServiceDefinition = createUserDefinition(ele, parserContext);
 			}
 		}
-		return userDetailsServiceJdbcDefinition;
+		return userDetailsServiceDefinition;
+	}
+
+	private RootBeanDefinition createUserDefinition(Element ele, ParserContext parserContext) {
+		RootBeanDefinition definition = new RootBeanDefinition(InMemoryDaoImpl.class);
+
+		UserAttribute userAttribute = new UserAttribute();
+		UserMap userMap = new UserMap();
+
+		setPassword(ele, userAttribute);
+		setEnabled(ele, userAttribute);
+		setAuthorities(ele, userAttribute);
+
+		UserDetails user = new User(ele.getAttribute(USERNAME), userAttribute.getPassword(), userAttribute.isEnabled(),
+				true, true, true, userAttribute.getAuthorities());
+		userMap.addUser(user);
+		definition.getPropertyValues().addPropertyValue("userMap", userMap);
+		return definition;
+
+	}
+
+	private String createPropertiesBeanDefinition(Element ele, ParserContext parserContext) {
+		// properties element
+		RootBeanDefinition defintion = new RootBeanDefinition(PropertiesFactoryBean.class);
+		String propertyValue = ele.getAttribute(RESOURCE);
+		defintion.getPropertyValues().addPropertyValue(RESOURCE, propertyValue);
+		defintion.setSource(parserContext.extractSource(ele));
+		return parserContext.getReaderContext().registerWithGeneratedName(defintion);
 	}
 
+	/**
+	 * 
+	 * @param elementToParse
+	 * @return
+	 */
 	private RootBeanDefinition parseUserDetailsServiceJdbcDefinition(Element elementToParse) {
 		// parse attributes
 		RootBeanDefinition definition = new RootBeanDefinition(JdbcDaoImpl.class);
@@ -63,14 +160,76 @@ public class PrincipalRepositoryBeanDefinitionParser extends AbstractBeanDefinit
 		setPropertyIfAvailable(elementToParse, USERNAME_BASED_PRIMARY_KEY, USERNAME_BASED_PRIMARY_KEY, definition);
 		return definition;
 	}
-	
-	private void setPropertyIfAvailable(Element el, String attribute, String property, RootBeanDefinition definition) {
-		String propertyValue = el.getAttribute(attribute);
+
+	protected void doParseProperties(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
+		Properties parsedProps = parserContext.getDelegate().parsePropsElement(element);
+		builder.addPropertyValue(PROPERTIES, parsedProps);
+	}
+
+	/**
+	 * 
+	 * @param element
+	 * @param attribute
+	 * @param property
+	 * @param 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, new RuntimeBeanReference(propertyValue));
+			if (propertyValue.equals(DATASOURCE_REF) || propertyValue.equals(JDBCTEMPLATE_REF)) {
+				definition.getPropertyValues().addPropertyValue(property, new RuntimeBeanReference(propertyValue));
+			}
+			else {
+				definition.getPropertyValues().addPropertyValue(property, propertyValue);
+			}
 		}
 	}
 
+	private void setPassword(Element element, UserAttribute userAttribute) {
+		String propertyValue = element.getAttribute(PASSWORD);
+		if (StringUtils.hasText(propertyValue)) {
+			userAttribute.setPassword(propertyValue);
+		}
+	}
+
+	private void setEnabled(Element element, UserAttribute userAttribute) {
+		String propertyValue = element.getAttribute(ENABLED);
+		if (StringUtils.hasText(propertyValue)) {
+			if (propertyValue.equals("true")) {
+				userAttribute.setEnabled(Boolean.TRUE);
+			}
+			else {
+				userAttribute.setEnabled(Boolean.FALSE);
+			}
+		}
+	}
+
+	private void setAuthorities(Element ele, UserAttribute userAttribute) {
+		// get authorities
+		NodeList childNodes = ele.getChildNodes();
 
+		ManagedList authorities = new ManagedList();
+
+		for (int i = 0, n = childNodes.getLength(); i < n; i++) {
+			Node authorityNode = childNodes.item(i);
+
+			if (GRANTED_AUTHORITY.equals(authorityNode.getLocalName())
+					&& authorityNode.getNodeType() == Element.ELEMENT_NODE) {
+				Element propertyValue = (Element) authorityNode;
+				authorities.add(new GrantedAuthorityImpl(propertyValue.getAttribute(AUTHORITY)));
+			}
+
+			if (GRANTED_AUTHORITY_REF.equals(authorityNode.getLocalName())
+					&& authorityNode.getNodeType() == Element.ELEMENT_NODE) {
+				Element propertyValue = (Element) authorityNode;
+				String attribute = propertyValue.getAttribute(AUTHORITY_BEAN_REF);
+				if (StringUtils.hasLength(attribute)) {
+					authorities.add(new RuntimeBeanReference(attribute));
+				}
+			}
+		}
+		userAttribute.setAuthorities(authorities);
+	}
 
 }

+ 1 - 0
core/src/main/java/org/acegisecurity/config/SecurityNamespaceHandler.java

@@ -25,6 +25,7 @@ public class SecurityNamespaceHandler extends NamespaceHandlerSupport {
 		registerBeanDefinitionParser("authentication-mechanism", new AuthenticationMechanismBeanDefinitionParser());
 		registerBeanDefinitionParser("authentication-remember-me-services", new RememberMeServicesBeanDefinitionParser());
 		registerBeanDefinitionParser("authentication-remember-me-filter", new RememberMeFilterBeanDefinitionParser());
+		registerBeanDefinitionParser("logout-support", new LogoutFilterBeanDefinitionParser());
 	}
 
 }

+ 54 - 40
core/src/main/java/org/acegisecurity/ui/logout/SecurityContextLogoutHandler.java

@@ -18,60 +18,74 @@ package org.acegisecurity.ui.logout;
 import org.acegisecurity.Authentication;
 
 import org.acegisecurity.context.SecurityContextHolder;
+import org.springframework.core.Ordered;
 import org.springframework.util.Assert;
 
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import javax.servlet.http.HttpSession;
 
-
 /**
- * Performs a logout by modifying the {@link org.acegisecurity.context.SecurityContextHolder}.
- *
- * <p>Will also invalidate the {@link HttpSession} if {@link #isInvalidateHttpSession()} is
- * <code>true</code> and the session is not <code>null</code>.
- *
+ * Performs a logout by modifying the
+ * {@link org.acegisecurity.context.SecurityContextHolder}.
+ * 
+ * <p>
+ * Will also invalidate the {@link HttpSession} if
+ * {@link #isInvalidateHttpSession()} is <code>true</code> and the session is
+ * not <code>null</code>.
+ * 
  * @author Ben Alex
- * @version $Id$
+ * @version $Id: SecurityContextLogoutHandler.java 1784 2007-02-24 21:00:24Z
+ * luke_t $
  */
-public class SecurityContextLogoutHandler implements LogoutHandler {
-    //~ Methods ========================================================================================================
+public class SecurityContextLogoutHandler implements LogoutHandler, Ordered {
+	// ~ Methods
+	// ========================================================================================================
+
+	private boolean invalidateHttpSession = true;
+
+	private int order = Integer.MAX_VALUE; //~ default
 
-    private boolean invalidateHttpSession = true;
+	/**
+	 * Requires the request to be passed in.
+	 * 
+	 * @param request from which to obtain a HTTP session (cannot be null)
+	 * @param response not used (can be <code>null</code>)
+	 * @param authentication not used (can be <code>null</code>)
+	 */
+	public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
+		Assert.notNull(request, "HttpServletRequest required");
+		if (invalidateHttpSession) {
+			HttpSession session = request.getSession(false);
+			if (session != null) {
+				session.invalidate();
+			}
+		}
 
-    /**
-     * Requires the request to be passed in.
-     *
-     * @param request from which to obtain a HTTP session (cannot be null)
-     * @param response not used (can be <code>null</code>)
-     * @param authentication not used (can be <code>null</code>)
-     */
-    public void logout(HttpServletRequest request, HttpServletResponse response, Authentication authentication) {
-        Assert.notNull(request, "HttpServletRequest required");
-        if (invalidateHttpSession) {
-            HttpSession session = request.getSession(false);
-            if (session != null) {
-                session.invalidate();
-            }
-        }
+		SecurityContextHolder.clearContext();
+	}
 
-        SecurityContextHolder.clearContext();
-    }
+	public boolean isInvalidateHttpSession() {
+		return invalidateHttpSession;
+	}
 
-    public boolean isInvalidateHttpSession() {
-        return invalidateHttpSession;
-    }
+	/**
+	 * Causes the {@link HttpSession} to be invalidated when this
+	 * {@link LogoutHandler} is invoked. Defaults to true.
+	 * 
+	 * @param invalidateHttpSession true if you wish the session to be
+	 * invalidated (default) or false if it should not be
+	 */
+	public void setInvalidateHttpSession(boolean invalidateHttpSession) {
+		this.invalidateHttpSession = invalidateHttpSession;
+	}
 
-    /**
-     * Causes the {@link HttpSession} to be invalidated when this
-     * {@link LogoutHandler} is invoked. Defaults to true.
-     *
-     * @param invalidateHttpSession true if you wish the session to be
-     * invalidated (default) or false if it should not be
-     */
-    public void setInvalidateHttpSession(boolean invalidateHttpSession) {
-        this.invalidateHttpSession = invalidateHttpSession;
-    }
+	public int getOrder() {
+		return order;
+	}
 
+	public void setOrder(int order) {
+		this.order = order;
+	}
 
 }

+ 18 - 14
core/src/main/java/org/acegisecurity/ui/rememberme/TokenBasedRememberMeServices.java

@@ -15,36 +15,30 @@
 
 package org.acegisecurity.ui.rememberme;
 
-import org.acegisecurity.Authentication;
+import java.util.Date;
 
-import org.acegisecurity.providers.rememberme.RememberMeAuthenticationToken;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
 
+import org.acegisecurity.Authentication;
+import org.acegisecurity.providers.rememberme.RememberMeAuthenticationToken;
 import org.acegisecurity.ui.AuthenticationDetailsSource;
 import org.acegisecurity.ui.AuthenticationDetailsSourceImpl;
 import org.acegisecurity.ui.logout.LogoutHandler;
-
 import org.acegisecurity.userdetails.UserDetails;
 import org.acegisecurity.userdetails.UserDetailsService;
 import org.acegisecurity.userdetails.UsernameNotFoundException;
-
 import org.apache.commons.codec.binary.Base64;
 import org.apache.commons.codec.digest.DigestUtils;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
-
 import org.springframework.beans.factory.InitializingBean;
-
+import org.springframework.core.Ordered;
 import org.springframework.util.Assert;
 import org.springframework.util.StringUtils;
-
 import org.springframework.web.bind.RequestUtils;
 
-import java.util.Date;
-
-import javax.servlet.http.Cookie;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-
 
 /**
  * Identifies previously remembered users by a Base-64 encoded cookie.
@@ -88,7 +82,7 @@ import javax.servlet.http.HttpServletResponse;
  * @author Ben Alex
  * @version $Id$
  */
-public class TokenBasedRememberMeServices implements RememberMeServices, InitializingBean, LogoutHandler {
+public class TokenBasedRememberMeServices implements RememberMeServices, InitializingBean, LogoutHandler, Ordered {
     //~ Static fields/initializers =====================================================================================
 
     public static final String ACEGI_SECURITY_HASHED_REMEMBER_ME_COOKIE_KEY = "ACEGI_SECURITY_HASHED_REMEMBER_ME_COOKIE";
@@ -103,6 +97,7 @@ public class TokenBasedRememberMeServices implements RememberMeServices, Initial
     private UserDetailsService userDetailsService;
     private long tokenValiditySeconds = 1209600; // 14 days
     private boolean alwaysRemember = false;
+    private int order = Integer.MAX_VALUE; //~ default
 
     //~ Methods ========================================================================================================
 
@@ -354,4 +349,13 @@ public class TokenBasedRememberMeServices implements RememberMeServices, Initial
     public void setAlwaysRemember(boolean alwaysRemember) {
         this.alwaysRemember = alwaysRemember;
     }
+
+	public int getOrder() {
+		return order;
+	}
+
+	public void setOrder(int order) {
+		this.order = order;
+	}
+
 }

+ 76 - 14
core/src/main/resources/org/acegisecurity/config/spring-security-2.0.xsd

@@ -3,9 +3,10 @@
 <xsd:schema xmlns="http://www.springframework.org/schema/security"
 	xmlns:xsd="http://www.w3.org/2001/XMLSchema"
 	targetNamespace="http://www.springframework.org/schema/security"
+	xmlns:util="http://www.springframework.org/schema/util"
 	elementFormDefault="qualified" attributeFormDefault="unqualified">
 
-
+	<xsd:import namespace="http://www.springframework.org/schema/util" />
 
 	<xsd:element name="session-context-integration">
 		<xsd:complexType>
@@ -157,17 +158,41 @@
 		</xsd:complexType>
 	</xsd:element>
 
+	<xsd:element name="logout-support" type="LogoutFilter" />
+
+	<xsd:complexType name="LogoutFilter">
+		<!-- <xsd:all>
+			<xsd:element name="clear-context" minOccurs="0" maxOccurs="1">
+			<xsd:complexType>
+			<xsd:attribute name="invalidateHttpSession"
+			type="xsd:boolean" default="true" use="optional" />
+			</xsd:complexType>
+			</xsd:element>
+			<xsd:element name="clear-remember-me" minOccurs="0" maxOccurs="1">>
+			<xsd:complexType>
+			<xsd:attribute name="rememberMeServicesBeanRef"
+			type="xsd:string" use="optional" />
+			</xsd:complexType>
+			</xsd:element>
+			</xsd:all> -->
+		<!-- Write other attributes -->
+		<xsd:attribute name="id" type="xsd:ID" />
+		<xsd:attribute name="redirectAfterLogoutUrl" type="xsd:string"
+			default="/" />
+		<xsd:attribute name="logoutUrl" type="xsd:string"
+			default="/logout" />
+	</xsd:complexType>
 
-	<xsd:element name="principal-repository"
-		type="PrincipalRepository" />
+	<xsd:element name="principal-repository" type="PrincipalRepository" />
 
 	<xsd:complexType name="PrincipalRepository">
-		<xsd:sequence>
-			<xsd:element ref="jdbc" minOccurs="0"
-				maxOccurs="1" />
-			<xsd:element ref="ldap" minOccurs="0"
-				maxOccurs="1" />
-		</xsd:sequence>
+		<xsd:choice>
+			<xsd:element ref="jdbc" minOccurs="0" maxOccurs="1" />
+			<xsd:element ref="ldap" minOccurs="0" maxOccurs="1" />
+			<xsd:element ref="properties" minOccurs="0" maxOccurs="1" />
+			<xsd:element ref="user-definition" minOccurs="0"
+				maxOccurs="unbounded" />
+		</xsd:choice>
 		<xsd:attribute name="id" type="xsd:ID">
 			<xsd:annotation>
 				<xsd:documentation>
@@ -182,21 +207,58 @@
 	<xsd:element name="jdbc">
 		<xsd:complexType>
 			<xsd:attribute name="dataSourceBeanRef" type="xsd:string" />
-			<xsd:attribute name="authoritiesByUsernameQuery" type="xsd:string" use="optional"/>
-			<xsd:attribute name="jdbcTemplateBeanRef" type="xsd:string" use="optional"/>
-			<xsd:attribute name="rolePrefix" type="xsd:string" use="optional"/>
-			<xsd:attribute name="usernameBasedPrimaryKey" type="xsd:boolean" use="optional"/>
-			<xsd:attribute name="usersByUsernameQuery" type="xsd:string" use="optional"/>
+			<xsd:attribute name="authoritiesByUsernameQuery"
+				type="xsd:string" use="optional" />
+			<xsd:attribute name="jdbcTemplateBeanRef" type="xsd:string"
+				use="optional" />
+			<xsd:attribute name="rolePrefix" type="xsd:string"
+				use="optional" />
+			<xsd:attribute name="usernameBasedPrimaryKey"
+				type="xsd:boolean" use="optional" />
+			<xsd:attribute name="usersByUsernameQuery" type="xsd:string"
+				use="optional" />
 		</xsd:complexType>
 	</xsd:element>
 
+
 	<xsd:element name="ldap">
 		<xsd:complexType>
 			<xsd:attribute name="not-yet-defined" type="xsd:string" />
 		</xsd:complexType>
 	</xsd:element>
 
+	<xsd:element name="properties">
+		<xsd:complexType>
+			<xsd:attribute name="resource" type="xsd:string" />
+		</xsd:complexType>
+	</xsd:element>
 
+	<xsd:element name="user-definition">
+		<xsd:complexType>
+			<xsd:sequence>
+				<xsd:element name="granted-authority" minOccurs="0"
+					maxOccurs="unbounded">
+					<xsd:complexType>
+						<xsd:attribute name="authority"
+							type="xsd:string" use="required" />
+					</xsd:complexType>
+				</xsd:element>
+				<xsd:element name="granted-authority-ref" minOccurs="0"
+					maxOccurs="unbounded">
+					<xsd:complexType>
+						<xsd:attribute name="authorityBeanRef"
+							type="xsd:string" use="required" />
+					</xsd:complexType>
+				</xsd:element>
+			</xsd:sequence>
+			<xsd:attribute name="username" type="xsd:string"
+				use="required" />
+			<xsd:attribute name="password" type="xsd:string" />
+			<xsd:attribute name="enabled" type="xsd:boolean" />
+			<xsd:anyAttribute namespace="##local"
+				processContents="strict" />
+		</xsd:complexType>
+	</xsd:element>
 
 
 	<xsd:element name="authentication-repository"

+ 1 - 1
core/src/test/java/org/acegisecurity/config/RememberMeBeanDefinitionParserTest.java

@@ -8,7 +8,7 @@ import org.springframework.context.support.ClassPathXmlApplicationContext;
 public class RememberMeBeanDefinitionParserTest extends TestCase {
 	
 	public void testRememberMeDefaults() {
-		ApplicationContext context = new ClassPathXmlApplicationContext("org/acegisecurity/config/remember-me-defaults.xml");
+		ApplicationContext context = new ClassPathXmlApplicationContext("org/acegisecurity/config/principal-repository-properties.xml");
 		
 		
 	}

+ 1 - 1
core/src/test/resources/org/acegisecurity/config/security-namespaces.xml

@@ -72,7 +72,7 @@
 	<security:principal-repository id="id">
 		<security:ldap x="you can do the attributes and suitable nested elements"/>
 		<security:jdbc x="you can do the attributes and suitable nested elements"/>
-		<security:properties resource="resourceStringToPropertiesFile"> <!-- if they specify a resource attrib, that means throw exception if they nest some user-definition data) -->
+		<security:properties location="resourceStringToPropertiesFile"> <!-- if they specify a resource attrib, that means throw exception if they nest some user-definition data) -->
 			<security:user-definition username="ben" password="nottellingYou" enabled="true" it="more stuff if you want">
 				<security:granted-authority authority="ROLE_ANONYMOUS"/>
 				<ref bean="fooBarAuthority"/>