Browse Source

Intermediate checkin of experimental namespace config work.

Luke Taylor 18 năm trước cách đây
mục cha
commit
627b0b38ad
16 tập tin đã thay đổi với 804 bổ sung26 xóa
  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>