Forráskód Böngészése

Intermediate checkin of experimental namespace config work.

Luke Taylor 18 éve
szülő
commit
627b0b38ad
16 módosított fájl, 804 hozzáadás és 26 törlés
  1. 214 0
      core/src/main/java/org/springframework/security/config/HttpSecurityBeanDefinitionParser.java
  2. 59 0
      core/src/main/java/org/springframework/security/config/HttpSecurityConfigPostProcessor.java
  3. 57 0
      core/src/main/java/org/springframework/security/config/InterceptMethodsBeanDefinitionDecorator.java
  4. 1 4
      core/src/main/java/org/springframework/security/config/LdapBeanDefinitionParser.java
  5. 51 0
      core/src/main/java/org/springframework/security/config/LogoutBeanDefinitionParser.java
  6. 4 2
      core/src/main/java/org/springframework/security/config/SecurityNamespaceHandler.java
  7. 61 0
      core/src/main/java/org/springframework/security/config/UserServiceBeanDefinitionParser.java
  8. 32 0
      core/src/main/java/org/springframework/security/util/AuthorityUtils.java
  9. 181 19
      core/src/main/resources/org/springframework/security/config/spring-security-2.0.xsd
  10. 23 0
      core/src/test/java/org/springframework/security/config/HttpSecurityBeanDefinitionParserTests.java
  11. 22 0
      core/src/test/java/org/springframework/security/config/InterceptMethodsBeanDefinitionDecoratorTests.java
  12. 16 0
      core/src/test/java/org/springframework/security/config/TestBusinessBean.java
  13. 24 0
      core/src/test/java/org/springframework/security/config/TestBusinessBeanImpl.java
  14. 32 0
      core/src/test/resources/org/springframework/security/config/http-security.xml
  15. 0 1
      core/src/test/resources/org/springframework/security/config/ldap-embedded-default.xml
  16. 27 0
      core/src/test/resources/org/springframework/security/config/method-security.xml

+ 214 - 0
core/src/main/java/org/springframework/security/config/HttpSecurityBeanDefinitionParser.java

@@ -0,0 +1,214 @@
+package org.springframework.security.config;
+
+import org.springframework.beans.factory.xml.ParserContext;
+import org.springframework.beans.factory.xml.BeanDefinitionParser;
+import org.springframework.beans.factory.support.RootBeanDefinition;
+import org.springframework.beans.factory.support.BeanDefinitionBuilder;
+import org.springframework.beans.factory.support.BeanDefinitionRegistry;
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.util.xml.DomUtils;
+import org.springframework.util.Assert;
+import org.springframework.util.StringUtils;
+import org.springframework.security.util.FilterChainProxy;
+import org.springframework.security.intercept.web.PathBasedFilterInvocationDefinitionMap;
+import org.springframework.security.intercept.web.FilterSecurityInterceptor;
+import org.springframework.security.intercept.web.FilterInvocationDefinitionMap;
+import org.springframework.security.ConfigAttributeEditor;
+import org.springframework.security.ConfigAttributeDefinition;
+import org.springframework.security.ui.ExceptionTranslationFilter;
+import org.springframework.security.ui.webapp.AuthenticationProcessingFilter;
+import org.springframework.security.ui.webapp.AuthenticationProcessingFilterEntryPoint;
+import org.springframework.security.context.HttpSessionContextIntegrationFilter;
+import org.w3c.dom.Element;
+
+import java.util.List;
+import java.util.Iterator;
+
+/**
+ * Sets up HTTP security: filter stack and protected URLs.
+ *
+ *
+ * @author luke
+ * @version $Id$
+ */
+public class HttpSecurityBeanDefinitionParser implements BeanDefinitionParser {
+
+    public static final String DEFAULT_FILTER_CHAIN_PROXY_ID = "_filterChainProxy";
+
+    public static final String DEFAULT_HTTP_SESSION_FILTER_ID = "_httpSessionContextIntegrationFilter";
+    public static final String DEFAULT_LOGOUT_FILTER_ID = "_logoutFilter";
+    public static final String DEFAULT_EXCEPTION_TRANSLATION_FILTER_ID = "_exceptionTranslationFilter";
+    public static final String DEFAULT_FILTER_SECURITY_INTERCEPTOR_ID = "_filterSecurityInterceptor";
+    public static final String DEFAULT_FORM_LOGIN_FILTER_ID = "_formLoginFilter";
+    public static final String DEFAULT_FORM_LOGIN_ENTRY_POINT_ID = "_formLoginEntryPoint";
+
+    public static final String LOGOUT_ELEMENT = "logout";
+    public static final String FORM_LOGIN_ELEMENT = "form-login";
+
+    private static final String PATH_ATTRIBUTE = "path";
+    private static final String FILTERS_ATTRIBUTE = "filters";
+    private static final String ACCESS_CONFIG_ATTRIBUTE = "access";
+
+    private static final String LOGIN_URL_ATTRIBUTE = "loginUrl";
+
+    private static final String FORM_LOGIN_TARGET_URL_ATTRIBUTE = "defaultTargetUrl";
+    private static final String DEFAULT_FORM_LOGIN_TARGET_URL = "/index";
+
+    private static final String FORM_LOGIN_AUTH_FAILURE_URL_ATTRIBUTE = "defaultTargetUrl";
+    // TODO: Change AbstractProcessingFilter to not need a failure URL and just write a failure message
+    // to the response if one isn't set.
+    private static final String DEFAULT_FORM_LOGIN_AUTH_FAILURE_URL = "/loginError";
+
+    public BeanDefinition parse(Element element, ParserContext parserContext) {
+        // Create HttpSCIF, FilterInvocationInterceptor, ExceptionTranslationFilter
+
+        // Find other filter beans.
+
+        // Create appropriate bean list for config attributes to create FIDS
+
+        // Add any secure URLs with specific filter chains to FIDS as separate ConfigAttributes
+
+        // Add secure URLS with roles to objectDefinitionSource for FilterSecurityInterceptor
+
+        RootBeanDefinition filterChainProxy = new RootBeanDefinition(FilterChainProxy.class);
+
+        RootBeanDefinition httpSCIF = new RootBeanDefinition(HttpSessionContextIntegrationFilter.class);
+
+        //TODO: Set session creation parameters based on session-creation attribute
+
+        BeanDefinitionBuilder filterSecurityInterceptorBuilder
+                = BeanDefinitionBuilder.rootBeanDefinition(FilterSecurityInterceptor.class);
+
+
+        BeanDefinitionBuilder exceptionTranslationFilterBuilder
+                = BeanDefinitionBuilder.rootBeanDefinition(ExceptionTranslationFilter.class);
+
+        // Autowire for entry point (for now)
+        exceptionTranslationFilterBuilder.setAutowireMode(RootBeanDefinition.AUTOWIRE_BY_TYPE);
+
+        // TODO: Get path type attribute and determine FilDefInvS class
+        PathBasedFilterInvocationDefinitionMap filterChainInvocationDefSource
+                = new PathBasedFilterInvocationDefinitionMap();
+
+        filterChainProxy.getPropertyValues().addPropertyValue("filterInvocationDefinitionSource",
+                filterChainInvocationDefSource);
+
+        PathBasedFilterInvocationDefinitionMap interceptorFilterInvDefSource
+                = new PathBasedFilterInvocationDefinitionMap();
+
+        filterSecurityInterceptorBuilder.addPropertyValue("objectDefinitionSource", interceptorFilterInvDefSource);
+
+        // Again pick up auth manager
+        filterSecurityInterceptorBuilder.setAutowireMode(RootBeanDefinition.AUTOWIRE_BY_TYPE);
+
+        parseInterceptUrls(DomUtils.getChildElementsByTagName(element, "intercept-url"),
+                filterChainInvocationDefSource, interceptorFilterInvDefSource);
+        // TODO: if empty, set a default set a default /**, omitting login url
+
+        BeanDefinitionRegistry registry = parserContext.getRegistry();
+
+        Element logoutElt = DomUtils.getChildElementByTagName(element, LOGOUT_ELEMENT);
+
+        if (logoutElt != null) {
+            BeanDefinition logoutFilter = new LogoutBeanDefinitionParser().parse(logoutElt, parserContext);
+        }
+
+        Element formLoginElt = DomUtils.getChildElementByTagName(element, FORM_LOGIN_ELEMENT);
+
+        if (formLoginElt != null) {
+            BeanDefinitionBuilder formLoginFilterBuilder =
+                    BeanDefinitionBuilder.rootBeanDefinition(AuthenticationProcessingFilter.class);
+            BeanDefinitionBuilder formLoginEntryPointBuilder =
+                    BeanDefinitionBuilder.rootBeanDefinition(AuthenticationProcessingFilterEntryPoint.class);
+
+            // Temporary login value
+            formLoginEntryPointBuilder.addPropertyValue("loginFormUrl", "/login");
+
+
+            String loginUrl = formLoginElt.getAttribute(LOGIN_URL_ATTRIBUTE);
+
+            if (StringUtils.hasText(loginUrl)) {
+                formLoginFilterBuilder.addPropertyValue("filterProcessesUrl", loginUrl);
+            }
+
+            String defaultTargetUrl = formLoginElt.getAttribute(FORM_LOGIN_TARGET_URL_ATTRIBUTE);
+
+            if (!StringUtils.hasText(defaultTargetUrl)) {
+                defaultTargetUrl = DEFAULT_FORM_LOGIN_TARGET_URL;
+            }
+
+            formLoginFilterBuilder.addPropertyValue("defaultTargetUrl", defaultTargetUrl);
+
+            String authenticationFailureUrl = formLoginElt.getAttribute(FORM_LOGIN_AUTH_FAILURE_URL_ATTRIBUTE);
+
+            if (!StringUtils.hasText(authenticationFailureUrl)) {
+                authenticationFailureUrl = DEFAULT_FORM_LOGIN_AUTH_FAILURE_URL;
+            }
+
+            formLoginFilterBuilder.addPropertyValue("authenticationFailureUrl", authenticationFailureUrl);
+            // Set autowire to pick up the authentication manager.
+            formLoginFilterBuilder.setAutowireMode(RootBeanDefinition.AUTOWIRE_BY_TYPE);
+
+
+            registry.registerBeanDefinition(DEFAULT_FORM_LOGIN_FILTER_ID,
+                    formLoginFilterBuilder.getBeanDefinition());
+            registry.registerBeanDefinition(DEFAULT_FORM_LOGIN_ENTRY_POINT_ID,
+                    formLoginEntryPointBuilder.getBeanDefinition());
+        }
+
+        registry.registerBeanDefinition(DEFAULT_FILTER_CHAIN_PROXY_ID, filterChainProxy);
+        registry.registerBeanDefinition(DEFAULT_HTTP_SESSION_FILTER_ID, httpSCIF);
+        registry.registerBeanDefinition(DEFAULT_EXCEPTION_TRANSLATION_FILTER_ID,
+                exceptionTranslationFilterBuilder.getBeanDefinition());
+        registry.registerBeanDefinition(DEFAULT_FILTER_SECURITY_INTERCEPTOR_ID,
+                filterSecurityInterceptorBuilder.getBeanDefinition());
+
+
+        // Register the post processor which will tie up the loose ends in the configuration once the
+        // app context has been created and all beans are available.
+
+        registry.registerBeanDefinition("__httpConfigBeanFactoryPostProcessor",
+                new RootBeanDefinition(HttpSecurityConfigPostProcessor.class));        
+
+        return null;
+    }
+
+    /**
+     * Parses the intercept-url elements and populates the FilterChainProxy's FilterInvocationDefinitionSource
+     */
+    private void parseInterceptUrls(List urlElts, FilterInvocationDefinitionMap filterChainInvocationDefSource,
+            FilterInvocationDefinitionMap interceptorFilterInvDefSource) {
+
+        Iterator urlEltsIterator = urlElts.iterator();
+
+        ConfigAttributeEditor attributeEditor = new ConfigAttributeEditor();
+
+        while (urlEltsIterator.hasNext()) {
+            Element urlElt = (Element) urlEltsIterator.next();
+
+            String path = urlElt.getAttribute(PATH_ATTRIBUTE);
+
+            Assert.hasText(path, "path attribute cannot be empty or null");
+
+            String access = urlElt.getAttribute(ACCESS_CONFIG_ATTRIBUTE);
+
+            // Convert the comma-separated list of access attributes to a ConfigAttributeDefinition
+            if (StringUtils.hasText(access)) {
+                attributeEditor.setAsText(access);
+
+                ConfigAttributeDefinition attributeDef = (ConfigAttributeDefinition) attributeEditor.getValue();
+
+                interceptorFilterInvDefSource.addSecureUrl(path, attributeDef);
+            }
+
+            String filters = urlElt.getAttribute(FILTERS_ATTRIBUTE);
+
+            if (StringUtils.hasText(filters)) {
+                attributeEditor.setAsText(filters);
+            }
+
+
+
+        }
+    }
+}

+ 59 - 0
core/src/main/java/org/springframework/security/config/HttpSecurityConfigPostProcessor.java

@@ -0,0 +1,59 @@
+package org.springframework.security.config;
+
+import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
+import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
+import org.springframework.beans.BeansException;
+import org.springframework.security.util.FilterChainProxy;
+import org.springframework.security.context.HttpSessionContextIntegrationFilter;
+import org.springframework.security.AuthenticationManager;
+import org.springframework.util.Assert;
+
+import javax.servlet.Filter;
+import java.util.Map;
+
+/**
+ * Responsible for tying up the HTTP security configuration - building ordered filter stack and linking up
+ * with other beans.
+ *
+ * @author Luke Taylor
+ * @version $Id$
+ */
+public class HttpSecurityConfigPostProcessor implements BeanFactoryPostProcessor {
+    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
+        FilterChainProxy filterChainProxy =
+                (FilterChainProxy) beanFactory.getBean(HttpSecurityBeanDefinitionParser.DEFAULT_FILTER_CHAIN_PROXY_ID);
+
+        HttpSessionContextIntegrationFilter httpSCIF = (HttpSessionContextIntegrationFilter)
+                beanFactory.getBean(HttpSecurityBeanDefinitionParser.DEFAULT_HTTP_SESSION_FILTER_ID);
+
+        AuthenticationManager authManager =
+                (AuthenticationManager) getBeanOfType(AuthenticationManager.class, beanFactory);
+
+
+        //
+        Map filters = beanFactory.getBeansOfType(Filter.class);
+
+
+
+
+
+
+
+
+    }
+
+    private void configureFilterChain(ConfigurableListableBeanFactory beanFactory) {
+
+
+    }
+
+
+
+    private Object getBeanOfType(Class clazz, ConfigurableListableBeanFactory beanFactory) {
+        Map beans = beanFactory.getBeansOfType(clazz);
+
+        Assert.isTrue(beans.size() == 1, "Required a single bean of type " + clazz + " but found " + beans.size());
+
+        return beans.values().toArray()[0];
+    }
+}

+ 57 - 0
core/src/main/java/org/springframework/security/config/InterceptMethodsBeanDefinitionDecorator.java

@@ -0,0 +1,57 @@
+package org.springframework.security.config;
+
+import org.springframework.aop.config.AbstractInterceptorDrivenBeanDefinitionDecorator;
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.beans.factory.support.RootBeanDefinition;
+import org.springframework.security.intercept.method.aopalliance.MethodSecurityInterceptor;
+import org.springframework.security.intercept.method.MethodDefinitionMap;
+import org.springframework.security.ConfigAttributeEditor;
+import org.springframework.security.ConfigAttributeDefinition;
+import org.springframework.util.xml.DomUtils;
+import org.w3c.dom.Node;
+import org.w3c.dom.Element;
+
+import java.util.List;
+import java.util.Iterator;
+
+/**
+ * @author luke
+ * @version $Id$
+ */
+public class InterceptMethodsBeanDefinitionDecorator extends AbstractInterceptorDrivenBeanDefinitionDecorator {
+    protected BeanDefinition createInterceptorDefinition(Node node) {
+        Element interceptMethodsElt = (Element)node;
+        RootBeanDefinition interceptor = new RootBeanDefinition(MethodSecurityInterceptor.class);
+
+        Element beanNode = (Element)interceptMethodsElt.getParentNode();
+        // Get the class from the parent bean...
+        String targetClassName = beanNode.getAttribute("class");
+        Class targetClass;
+
+        try {
+            targetClass = Thread.currentThread().getContextClassLoader().loadClass(targetClassName);
+        } catch (ClassNotFoundException e) {
+            throw new IllegalArgumentException("Couldn't load class " + targetClassName, e);
+        }
+
+        // Parse the included methods
+        List methods = DomUtils.getChildElementsByTagName(interceptMethodsElt, "protect");
+        MethodDefinitionMap methodMap = new MethodDefinitionMap();
+        ConfigAttributeEditor attributeEditor = new ConfigAttributeEditor();
+
+        for (Iterator i = methods.iterator(); i.hasNext();) {
+            Element protectmethodElt = (Element) i.next();
+            String accessConfig = protectmethodElt.getAttribute("access");
+            attributeEditor.setAsText(accessConfig);
+
+            methodMap.addSecureMethod(targetClass, protectmethodElt.getAttribute("method"), 
+                    (ConfigAttributeDefinition) attributeEditor.getValue());
+        }
+
+        interceptor.getPropertyValues().addPropertyValue("objectDefinitionSource", methodMap);
+
+        interceptor.setAutowireMode(RootBeanDefinition.AUTOWIRE_BY_TYPE);
+
+        return interceptor;
+    }
+}

+ 1 - 4
core/src/main/java/org/springframework/security/config/LdapBeanDefinitionParser.java

@@ -51,11 +51,8 @@ public class LdapBeanDefinitionParser extends AbstractBeanDefinitionParser {
 
     // Defaults
     private static final String DEFAULT_ROOT_SUFFIX = "dc=springframework,dc=org";
-
-    private static final String DEFAULT_PROVIDER_BEAN_ID = "_ldapProvider";
-
+    private static final String DEFAULT_PROVIDER_BEAN_ID = "_ldapAuthenticationProvider";
     private static final String DEFAULT_DN_PATTERN = "uid={0},ou=people";
-
     private static final String DEFAULT_GROUP_CONTEXT = "ou=groups";
 
 

+ 51 - 0
core/src/main/java/org/springframework/security/config/LogoutBeanDefinitionParser.java

@@ -0,0 +1,51 @@
+package org.springframework.security.config;
+
+import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
+import org.springframework.beans.factory.xml.ParserContext;
+import org.springframework.beans.factory.support.BeanDefinitionBuilder;
+import org.springframework.beans.factory.support.AbstractBeanDefinition;
+import org.springframework.beans.factory.BeanDefinitionStoreException;
+import org.springframework.security.ui.logout.LogoutFilter;
+import org.springframework.security.ui.logout.LogoutHandler;
+import org.springframework.security.ui.logout.SecurityContextLogoutHandler;
+import org.springframework.util.StringUtils;
+import org.w3c.dom.Element;
+
+/**
+ * @author Luke Taylor
+ * @version $Id$
+ */
+public class LogoutBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
+    public static final String DEFAULT_LOGOUT_SUCCESS_URL = "/";
+
+    protected Class getBeanClass(Element element) {
+        return LogoutFilter.class;
+    }
+
+    protected void doParse(Element element, BeanDefinitionBuilder builder) {
+        String logoutUrl = element.getAttribute("logoutUrl");
+
+        if (StringUtils.hasText(logoutUrl)) {
+            builder.addPropertyValue("filterProcessesUrl", logoutUrl);
+        }
+
+        String logoutSuccessUrl = element.getAttribute("logoutSuccessUrl");
+
+        if (!StringUtils.hasText(logoutSuccessUrl)) {
+            logoutSuccessUrl = DEFAULT_LOGOUT_SUCCESS_URL;
+        }
+
+        builder.addConstructorArg(logoutSuccessUrl);
+        builder.addConstructorArg(new LogoutHandler[] {new SecurityContextLogoutHandler()});
+    }
+
+    protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext) throws BeanDefinitionStoreException {
+        String id = super.resolveId(element, definition, parserContext);
+
+        if (StringUtils.hasText(id)) {
+            return id;
+        }
+
+        return HttpSecurityBeanDefinitionParser.DEFAULT_LOGOUT_FILTER_ID;
+    }
+}

+ 4 - 2
core/src/main/java/org/springframework/security/config/SecurityNamespaceHandler.java

@@ -12,7 +12,9 @@ import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
 public class SecurityNamespaceHandler extends NamespaceHandlerSupport {
     public void init() {
         registerBeanDefinitionParser("ldap", new LdapBeanDefinitionParser());
-
-
+        registerBeanDefinitionParser("http", new HttpSecurityBeanDefinitionParser());
+        registerBeanDefinitionParser("authentication-provider", new AuthenticationProviderBeanDefinitionParser());
+        registerBeanDefinitionParser("autoconfig", new AutoConfigBeanDefinitionParser());
+        registerBeanDefinitionDecorator("intercept-methods", new InterceptMethodsBeanDefinitionDecorator());
     }
 }

+ 61 - 0
core/src/main/java/org/springframework/security/config/UserServiceBeanDefinitionParser.java

@@ -0,0 +1,61 @@
+package org.springframework.security.config;
+
+import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
+import org.springframework.beans.factory.xml.ParserContext;
+import org.springframework.beans.factory.support.BeanDefinitionBuilder;
+import org.springframework.beans.factory.support.AbstractBeanDefinition;
+import org.springframework.beans.factory.BeanDefinitionStoreException;
+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.xml.DomUtils;
+import org.springframework.util.StringUtils;
+import org.w3c.dom.Element;
+
+import java.util.List;
+import java.util.Iterator;
+
+/**
+ * @author luke
+ * @version $Id$
+ */
+public class UserServiceBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
+
+    public static final String DEFAULT_ID = "_userDetailsService";
+
+    protected Class getBeanClass(Element element) {
+        return InMemoryDaoImpl.class;
+    }
+
+
+    protected void doParse(Element element, BeanDefinitionBuilder builder) {
+        List userElts = DomUtils.getChildElementsByTagName(element, "user");
+        UserMap users = new UserMap();
+
+        for (Iterator i = userElts.iterator(); i.hasNext();) {
+            Element userElt = (Element) i.next();
+            String userName = userElt.getAttribute("name");
+            String password = userElt.getAttribute("password");
+
+            users.addUser(new User(userName, password, true, true, true, true,
+                    AuthorityUtils.commaSeparatedStringToAuthorityArray(userElt.getAttribute("authorities"))));
+        }
+
+        builder.addPropertyValue("userMap", users);
+
+
+    }
+
+    protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext) throws BeanDefinitionStoreException {
+        String id = super.resolveId(element, definition, parserContext);
+
+        if (StringUtils.hasText(id)) {
+            return id;
+        }
+
+        // TODO: Check for duplicate using default id here.
+
+        return DEFAULT_ID;
+    }
+}

+ 32 - 0
core/src/main/java/org/springframework/security/util/AuthorityUtils.java

@@ -0,0 +1,32 @@
+package org.springframework.security.util;
+
+import org.springframework.security.GrantedAuthority;
+import org.springframework.security.GrantedAuthorityImpl;
+import org.springframework.util.StringUtils;
+
+/**
+ * @author luke
+ * @version $Id$
+ */
+public abstract class AuthorityUtils {
+
+    /**
+     * Creates a array of GrantedAuthority objects from a comma-separated string
+     * representation (e.g. "ROLE_A, ROLE_B, ROLE_C").
+     *
+     * @param authorityString the comma-separated string
+     * @return the authorities created by tokenizing the string
+     */
+    public static GrantedAuthority[] commaSeparatedStringToAuthorityArray(String authorityString) {
+        String[] authorityStrings = StringUtils.tokenizeToStringArray(authorityString, ",");
+        GrantedAuthority[] authorities = new GrantedAuthority[authorityStrings.length];
+
+        for (int i=0; i < authorityStrings.length; i++) {
+            authorities[i] = new GrantedAuthorityImpl(authorityStrings[i]);
+        }
+
+        return authorities;
+    }
+
+
+}

+ 181 - 19
core/src/main/resources/org/springframework/security/config/spring-security-2.0.xsd

@@ -1,22 +1,184 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-
-<xsd:schema xmlns="http://www.springframework.org/schema/security"
-	xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+<?xml version="1.0" encoding="UTF-8"?>
+<xs:schema xmlns="http://www.springframework.org/schema/security"
+	xmlns:xs="http://www.w3.org/2001/XMLSchema"
 	targetNamespace="http://www.springframework.org/schema/security"
 	xmlns:beans="http://www.springframework.org/schema/beans"
 	elementFormDefault="qualified" attributeFormDefault="unqualified">
-
-
-    <xsd:import namespace="http://www.springframework.org/schema/beans" />
-
-	<xsd:element name="autoconfig" />
-
-
-	<xsd:element name="ldap">
-		<xsd:complexType>
-			<xsd:attribute name="url" type="xsd:string" />            
-			<xsd:attribute name="ldif" default="classpath:*.ldif"/>			
-		</xsd:complexType>
-	</xsd:element>    
-
-</xsd:schema>
+  <xs:element name="autoconfig">
+    <xs:annotation>
+      <xs:documentation>Provides automatic security configration for a application</xs:documentation>
+    </xs:annotation>
+    <xs:complexType/>
+  </xs:element>
+  <xs:element name="ldap">
+    <xs:annotation>
+      <xs:documentation>Sets up an ldap authentication provider, optionally with an embedded ldap server</xs:documentation>
+    </xs:annotation>
+    <xs:complexType>
+      <xs:attributeGroup ref="ldap.attlist"/>
+    </xs:complexType>
+  </xs:element>
+  <xs:attributeGroup name="ldap.attlist">
+    <xs:attribute name="url" type="xs:string">
+      <xs:annotation>
+        <xs:documentation>Specifies the ldap server Url. If omitted, an embedded server will be created    </xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+    <xs:attribute name="ldif" default="classpath:*.ldif" type="xs:string">
+      <xs:annotation>
+        <xs:documentation>Explicitly specify an ldif file resource to load </xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+  </xs:attributeGroup>
+  <xs:element name="intercept-methods">
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element maxOccurs="unbounded" ref="protect"/>
+      </xs:sequence>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="protect">
+    <xs:annotation>
+      <xs:documentation>Defines a protected method and the access control configuration attributes that apply to it</xs:documentation>
+    </xs:annotation>
+    <xs:complexType>
+      <xs:attributeGroup ref="protect.attlist"/>
+    </xs:complexType>
+  </xs:element>
+  <xs:attributeGroup name="protect.attlist">
+    <xs:attribute name="method" use="required" type="xs:string">
+      <xs:annotation>
+        <xs:documentation>A method name </xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+    <xs:attribute name="access" use="required" type="xs:string">
+      <xs:annotation>
+        <xs:documentation>Access configuration attributes list that applies to the method, e.g. "ROLE_A,ROLE_B"</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+  </xs:attributeGroup>
+  <xs:element name="http">
+    <xs:annotation>
+      <xs:documentation>Container element for HTTP security configuration</xs:documentation>
+    </xs:annotation>
+    <xs:complexType>
+      <xs:sequence>
+        <xs:element maxOccurs="unbounded" ref="intercept-url"/>
+        <xs:element minOccurs="0" ref="form-login"/>
+        <xs:element minOccurs="0" ref="logout"/>
+      </xs:sequence>
+      <xs:attributeGroup ref="http.attlist"/>
+    </xs:complexType>
+  </xs:element>
+  <xs:attributeGroup name="http.attlist">
+    <xs:attribute name="createSession" default="ifRequired">
+      <xs:annotation>
+        <xs:documentation>Controls the eagerness with which an HTTP session is created.</xs:documentation>
+      </xs:annotation>
+      <xs:simpleType>
+        <xs:restriction base="xs:token">
+          <xs:enumeration value="ifRequired"/>
+          <xs:enumeration value="always"/>
+          <xs:enumeration value="never"/>
+        </xs:restriction>
+      </xs:simpleType>
+    </xs:attribute>
+    <xs:attribute name="pathType" default="ant">
+      <xs:annotation>
+        <xs:documentation>Defines the type of path used to define URLs in child elements. </xs:documentation>
+      </xs:annotation>
+      <xs:simpleType>
+        <xs:restriction base="xs:token">
+          <xs:enumeration value="regex"/>
+          <xs:enumeration value="ant"/>
+        </xs:restriction>
+      </xs:simpleType>
+    </xs:attribute>
+    <xs:attribute name="lowerCaseComparisons" default="true">
+      <xs:annotation>
+        <xs:documentation>Whether test URLs should be converted to lower case prior to comparing with defined path patterns.</xs:documentation>
+      </xs:annotation>
+      <xs:simpleType>
+        <xs:restriction base="xs:token">
+          <xs:enumeration value="true"/>
+          <xs:enumeration value="true"/>
+        </xs:restriction>
+      </xs:simpleType>
+    </xs:attribute>
+  </xs:attributeGroup>
+  <xs:element name="intercept-url">
+    <xs:complexType>
+      <xs:attributeGroup ref="intercept-url.attlist"/>
+    </xs:complexType>
+  </xs:element>
+  <xs:attributeGroup name="intercept-url.attlist">
+    <xs:attribute name="path" use="required" type="xs:string"/>
+    <xs:attribute name="access" type="xs:string"/>
+    <xs:attribute name="filters" type="xs:string"/>
+  </xs:attributeGroup>
+  <xs:element name="logout">
+    <xs:complexType>
+      <xs:attributeGroup ref="logout.attlist"/>
+    </xs:complexType>
+  </xs:element>
+  <xs:attributeGroup name="logout.attlist">
+    <xs:attribute name="logoutUrl" default="/j_spring_security_logout" type="xs:string"/>
+    <xs:attribute name="logoutSuccessUrl" default="/" type="xs:string"/>
+    <xs:attribute name="invalidateSession" default="true">
+      <xs:simpleType>
+        <xs:restriction base="xs:token">
+          <xs:enumeration value="true"/>
+          <xs:enumeration value="false"/>
+        </xs:restriction>
+      </xs:simpleType>
+    </xs:attribute>
+  </xs:attributeGroup>
+  <xs:element name="form-login">
+    <xs:annotation>
+      <xs:documentation>Sets up a form login configuration</xs:documentation>
+    </xs:annotation>
+    <xs:complexType>
+      <xs:attributeGroup ref="form-login.attlist"/>
+    </xs:complexType>
+  </xs:element>
+  <xs:attributeGroup name="form-login.attlist">
+    <xs:attribute name="loginUrl" default="/j_spring_security_check" type="xs:string">
+      <xs:annotation>
+        <xs:documentation>The URL that the form is submitted to</xs:documentation>
+      </xs:annotation>
+    </xs:attribute>
+  </xs:attributeGroup>
+  <xs:element name="authentication-provider">
+    <xs:complexType>
+      <xs:choice>
+        <xs:element ref="user-service"/>
+        <xs:element ref="jdbc-user-service"/>
+      </xs:choice>
+    </xs:complexType>
+  </xs:element>
+  <xs:element name="user-service">
+    <xs:complexType>
+      <xs:choice>
+        <xs:element minOccurs="0" maxOccurs="unbounded" ref="user"/>
+        <xs:element ref="jdbc-user-service"/>
+      </xs:choice>
+      <xs:attributeGroup ref="user-service.attlist"/>
+    </xs:complexType>
+  </xs:element>
+  <xs:attributeGroup name="user-service.attlist">
+    <xs:attribute name="properties" type="xs:string"/>
+  </xs:attributeGroup>
+  <xs:element name="user">
+    <xs:complexType>
+      <xs:attributeGroup ref="user.attlist"/>
+    </xs:complexType>
+  </xs:element>
+  <xs:attributeGroup name="user.attlist">
+    <xs:attribute name="name" use="required" type="xs:string"/>
+    <xs:attribute name="password" use="required" type="xs:string"/>
+    <xs:attribute name="authorities" use="required" type="xs:string"/>
+  </xs:attributeGroup>
+  <xs:element name="jdbc-user-service">
+    <xs:complexType/>
+  </xs:element>
+</xs:schema>

+ 23 - 0
core/src/test/java/org/springframework/security/config/HttpSecurityBeanDefinitionParserTests.java

@@ -0,0 +1,23 @@
+package org.springframework.security.config;
+
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * @author Luke Taylor
+ * @version $Id$
+ */
+public class HttpSecurityBeanDefinitionParserTests {
+    private static ClassPathXmlApplicationContext appContext;
+
+    @BeforeClass
+    public static void loadContext() {
+        appContext = new ClassPathXmlApplicationContext("org/springframework/security/config/http-security.xml");
+    }
+
+    @Test
+    public void testContextContainsExpectedBeansAndData() {
+    }
+
+}

+ 22 - 0
core/src/test/java/org/springframework/security/config/InterceptMethodsBeanDefinitionDecoratorTests.java

@@ -0,0 +1,22 @@
+package org.springframework.security.config;
+
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * @author luke
+ * @version $Id$
+ */
+public class InterceptMethodsBeanDefinitionDecoratorTests {
+    private static ClassPathXmlApplicationContext appContext;
+
+    @BeforeClass
+    public static void loadContext() {
+        appContext = new ClassPathXmlApplicationContext("org/springframework/security/config/method-security.xml");
+    }
+
+    @Test
+    public void contextShouldContainCorrectBeans() {
+    }
+}

+ 16 - 0
core/src/test/java/org/springframework/security/config/TestBusinessBean.java

@@ -0,0 +1,16 @@
+package org.springframework.security.config;
+
+/**
+ * @author luke
+ * @version $Id$
+ */
+public interface TestBusinessBean {
+
+    void setInteger(int i);
+
+    int getInteger();
+
+    void setString(String s);
+
+    void doSomething();
+}

+ 24 - 0
core/src/test/java/org/springframework/security/config/TestBusinessBeanImpl.java

@@ -0,0 +1,24 @@
+package org.springframework.security.config;
+
+/**
+ * @author luke
+ * @version $Id$
+ */
+public class TestBusinessBeanImpl implements TestBusinessBean {
+    public void setInteger(int i) {
+    }
+
+    public int getInteger() {
+        return 1314;
+    }
+
+    public void setString(String s) {
+    }
+
+    public String getString() {
+        return "A string.";
+    }
+
+    public void doSomething() {
+    }
+}

+ 32 - 0
core/src/test/resources/org/springframework/security/config/http-security.xml

@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<beans xmlns="http://www.springframework.org/schema/beans"
+    xmlns:security="http://www.springframework.org/schema/security"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
+http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.xsd">
+
+    <security:autoconfig />    
+
+    <security:http createSession="ifRequired" pathType="ant" lowerCaseComparisons="true">
+        <security:intercept-url path="/unprotected" filters="none"/>
+        <security:intercept-url path="/somepath" filters="filter1,filter2,filter3" access="ROLE_SPECIAL,ROLE_USER" />
+        <security:intercept-url path="/**" access="ROLE_USER" />
+
+        <!-- Default form login configuration. Will create filter and entry point -->
+        <security:form-login loginUrl="/j_spring_security_check"  />
+
+        <!-- Default logout configuration -->
+        <security:logout logoutUrl="/j_spring_security_logout" logoutSuccessUrl="/" invalidateSession="true" />
+
+    </security:http>    
+
+
+    <security:authentication-provider>
+        <security:user-service>
+            <security:user name="bob" password="bobspassword" authorities="ROLE_A,ROLE_B" />
+            <security:user name="bill" password="billspassword" authorities="ROLE_A,ROLE_B,AUTH_OTHER" />
+        </security:user-service>
+    </security:authentication-provider>    
+
+</beans>

+ 0 - 1
core/src/test/resources/org/springframework/security/config/ldap-embedded-default.xml

@@ -10,5 +10,4 @@ http://www.springframework.org/schema/security http://www.springframework.org/sc
     <security:ldap />
     
 
-
 </beans>

+ 27 - 0
core/src/test/resources/org/springframework/security/config/method-security.xml

@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<beans xmlns="http://www.springframework.org/schema/beans"
+    xmlns:security="http://www.springframework.org/schema/security"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
+http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.xsd">
+
+    <security:autoconfig />
+
+    <bean id="someBusinessObject" class="org.springframework.security.config.TestBusinessBeanImpl">
+        <!-- This will add a security interceptor to the bean -->
+        <security:intercept-methods>
+            <security:protect method="set*" access="ROLE_ADMIN" />
+            <security:protect method="get*" access="ROLE_ADMIN,ROLE_USER" />
+            <security:protect method="doSomething" access="ROLE_USER" />
+        </security:intercept-methods>
+    </bean>
+
+    <security:authentication-provider>
+        <security:user-service>
+            <security:user name="bob" password="bobspassword" authorities="ROLE_A,ROLE_B" />
+            <security:user name="bill" password="billspassword" authorities="ROLE_A,ROLE_B,AUTH_OTHER" />
+        </security:user-service>
+    </security:authentication-provider>
+
+</beans>