diff --git a/web/src/main/java/org/springframework/security/web/authentication/preauth/j2ee/J2eePreAuthenticatedProcessingFilter.java b/web/src/main/java/org/springframework/security/web/authentication/preauth/j2ee/J2eePreAuthenticatedProcessingFilter.java
index 7a2d231ef1..9afa7276a7 100755
--- a/web/src/main/java/org/springframework/security/web/authentication/preauth/j2ee/J2eePreAuthenticatedProcessingFilter.java
+++ b/web/src/main/java/org/springframework/security/web/authentication/preauth/j2ee/J2eePreAuthenticatedProcessingFilter.java
@@ -13,6 +13,7 @@ import org.springframework.security.web.authentication.preauth.AbstractPreAuthen
* @since 2.0
*/
public class J2eePreAuthenticatedProcessingFilter extends AbstractPreAuthenticatedProcessingFilter {
+
/**
* Return the J2EE user name.
*/
diff --git a/web/src/main/java/org/springframework/security/web/authentication/preauth/j2ee/WebXmlMappableAttributesRetriever.java b/web/src/main/java/org/springframework/security/web/authentication/preauth/j2ee/WebXmlMappableAttributesRetriever.java
index 6bd62cf032..b065246316 100755
--- a/web/src/main/java/org/springframework/security/web/authentication/preauth/j2ee/WebXmlMappableAttributesRetriever.java
+++ b/web/src/main/java/org/springframework/security/web/authentication/preauth/j2ee/WebXmlMappableAttributesRetriever.java
@@ -1,50 +1,123 @@
package org.springframework.security.web.authentication.preauth.j2ee;
+import java.io.IOException;
import java.io.InputStream;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
-import org.springframework.security.core.authority.mapping.XmlMappableAttributesRetriever;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.FactoryConfigurationError;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.context.ResourceLoaderAware;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.ResourceLoader;
+import org.springframework.security.core.authority.mapping.MappableAttributesRetriever;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+import org.xml.sax.EntityResolver;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
/**
- *
- * This MappableAttributesRetriever implementation reads the list of defined J2EE
- * roles from a web.xml file. It's functionality is based on the
- * XmlMappableAttributesRetriever base class.
- *
- * Example on how to configure this MappableAttributesRetriever in the Spring
- * configuration file:
- *
- *
- *
- *
- * <bean id="j2eeMappableRolesRetriever" class="org.springframework.security.ui.preauth.j2ee.WebXmlMappableAttributesRetriever">
- * <property name="webXmlInputStream"><bean factory-bean="webXmlResource" factory-method="getInputStream"/></property>
- * </bean>
- * <bean id="webXmlResource" class="org.springframework.web.context.support.ServletContextResource">
- * <constructor-arg><ref local="servletContext"/></constructor-arg>
- * <constructor-arg><value>/WEB-INF/web.xml</value></constructor-arg>
- * </bean>
- * <bean id="servletContext" class="org.springframework.web.context.support.ServletContextFactoryBean"/>
- *
- *
+ * This MappableAttributesRetriever implementation reads the list of defined J2EE
+ * roles from a web.xml file and returns these from {{@link #getMappableAttributes()}.
*
* @author Ruud Senden
+ * @author Luke Taylor
* @since 2.0
*/
-public class WebXmlMappableAttributesRetriever extends XmlMappableAttributesRetriever {
- private static final String XPATH_EXPR = "/web-app/security-role/role-name/text()";
+public class WebXmlMappableAttributesRetriever implements ResourceLoaderAware, MappableAttributesRetriever, InitializingBean {
+ protected final Log logger = LogFactory.getLog(getClass());
- /**
- * Constructor setting the XPath expression to use
- */
- public WebXmlMappableAttributesRetriever() {
- super.setXpathExpression(XPATH_EXPR);
+ private ResourceLoader resourceLoader;
+ private Set mappableAttributes;
+
+ public void setResourceLoader(ResourceLoader resourceLoader) {
+ this.resourceLoader = resourceLoader;
+ }
+
+
+ public Set getMappableAttributes() {
+ return mappableAttributes;
}
/**
- * @param anInputStream
- * The InputStream to read the XML data from
+ * Loads the web.xml file using the configured ResourceLoader and
+ * parses the role-name elements from it, using these as the set of mappableAttributes.
*/
- public void setWebXmlInputStream(InputStream anInputStream) {
- super.setXmlInputStream(anInputStream);
+
+ public void afterPropertiesSet() throws Exception {
+ Resource webXml = resourceLoader.getResource("/WEB-INF/web.xml");
+ Document doc = getDocument(webXml.getInputStream());
+ NodeList webApp = doc.getElementsByTagName("web-app");
+ if (webApp.getLength() != 1) {
+ throw new IllegalArgumentException("Failed to find 'web-app' element in resource" + webXml);
+ }
+ NodeList securityRoles = ((Element)webApp.item(0)).getElementsByTagName("security-role");
+
+ ArrayList roleNames = new ArrayList();
+
+ for (int i=0; i < securityRoles.getLength(); i++) {
+ Element secRoleElt = (Element) securityRoles.item(i);
+ NodeList roles = secRoleElt.getElementsByTagName("role-name");
+
+ if (roles.getLength() > 0) {
+ String roleName = ((Element)roles.item(0)).getTextContent().trim();
+ roleNames.add(roleName);
+ logger.info("Retrieved role-name '" + roleName + "' from web.xml");
+ } else {
+ logger.info("No security-role elements found in " + webXml);
+ }
+ }
+
+ mappableAttributes = Collections.unmodifiableSet(new HashSet(roleNames));
+ }
+
+ /**
+ * @return Document for the specified InputStream
+ */
+ private Document getDocument(InputStream aStream) {
+ Document doc;
+ try {
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ factory.setValidating(false);
+ DocumentBuilder db = factory.newDocumentBuilder();
+ db.setEntityResolver(new MyEntityResolver());
+ doc = db.parse(aStream);
+ return doc;
+ } catch (FactoryConfigurationError e) {
+ throw new RuntimeException("Unable to parse document object", e);
+ } catch (ParserConfigurationException e) {
+ throw new RuntimeException("Unable to parse document object", e);
+ } catch (SAXException e) {
+ throw new RuntimeException("Unable to parse document object", e);
+ } catch (IOException e) {
+ throw new RuntimeException("Unable to parse document object", e);
+ } finally {
+ try {
+ aStream.close();
+ } catch (IOException e) {
+ logger.warn("Failed to close input stream for web.xml", e);
+ }
+ }
+ }
+
+ /**
+ * We do not need to resolve external entities, so just return an empty
+ * String.
+ */
+ private static final class MyEntityResolver implements EntityResolver {
+ public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
+ return new InputSource(new StringReader(""));
+ }
}
}
diff --git a/web/src/test/java/org/springframework/security/web/authentication/preauth/j2ee/WebXmlJ2eeDefinedRolesRetrieverTests.java b/web/src/test/java/org/springframework/security/web/authentication/preauth/j2ee/WebXmlJ2eeDefinedRolesRetrieverTests.java
index 0f52464461..ee661dd4c5 100755
--- a/web/src/test/java/org/springframework/security/web/authentication/preauth/j2ee/WebXmlJ2eeDefinedRolesRetrieverTests.java
+++ b/web/src/test/java/org/springframework/security/web/authentication/preauth/j2ee/WebXmlJ2eeDefinedRolesRetrieverTests.java
@@ -1,21 +1,34 @@
package org.springframework.security.web.authentication.preauth.j2ee;
-import java.io.InputStream;
+import static org.junit.Assert.*;
+
import java.util.Arrays;
import java.util.List;
import java.util.Set;
-import org.springframework.security.web.authentication.preauth.j2ee.WebXmlMappableAttributesRetriever;
+import org.junit.Test;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.ResourceLoader;
-import junit.framework.TestCase;
+public class WebXmlJ2eeDefinedRolesRetrieverTests {
-public class WebXmlJ2eeDefinedRolesRetrieverTests extends TestCase {
-
- public final void testRole1To4Roles() throws Exception {
- final List ROLE1TO4_EXPECTED_ROLES = Arrays.asList(new String[] { "Role1", "Role2", "Role3", "Role4" });
- InputStream role1to4InputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("webxml/Role1-4.web.xml");
+ @Test
+ public void testRole1To4Roles() throws Exception {
+ List ROLE1TO4_EXPECTED_ROLES = Arrays.asList(new String[] { "Role1", "Role2", "Role3", "Role4" });
+ final Resource webXml = new ClassPathResource("webxml/Role1-4.web.xml");
WebXmlMappableAttributesRetriever rolesRetriever = new WebXmlMappableAttributesRetriever();
- rolesRetriever.setWebXmlInputStream(role1to4InputStream);
+
+ rolesRetriever.setResourceLoader(new ResourceLoader() {
+ public ClassLoader getClassLoader() {
+ return Thread.currentThread().getContextClassLoader();
+ }
+
+ public Resource getResource(String location) {
+ return webXml;
+ }
+ });
+
rolesRetriever.afterPropertiesSet();
Set j2eeRoles = rolesRetriever.getMappableAttributes();
assertNotNull(j2eeRoles);
@@ -25,10 +38,19 @@ public class WebXmlJ2eeDefinedRolesRetrieverTests extends TestCase {
j2eeRoles.containsAll(ROLE1TO4_EXPECTED_ROLES));
}
- public final void testGetZeroJ2eeRoles() throws Exception {
- InputStream noRolesInputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("webxml/NoRoles.web.xml");
+ @Test
+ public void testGetZeroJ2eeRoles() throws Exception {
+ final Resource webXml = new ClassPathResource("webxml/NoRoles.web.xml");
WebXmlMappableAttributesRetriever rolesRetriever = new WebXmlMappableAttributesRetriever();
- rolesRetriever.setWebXmlInputStream(noRolesInputStream);
+ rolesRetriever.setResourceLoader(new ResourceLoader() {
+ public ClassLoader getClassLoader() {
+ return Thread.currentThread().getContextClassLoader();
+ }
+
+ public Resource getResource(String location) {
+ return webXml;
+ }
+ });
rolesRetriever.afterPropertiesSet();
Set j2eeRoles = rolesRetriever.getMappableAttributes();
assertEquals("J2eeRoles expected size: 0, actual size: " + j2eeRoles.size(), 0, j2eeRoles.size());
diff --git a/web/template.mf b/web/template.mf
index 8df9f48953..49e35008c3 100644
--- a/web/template.mf
+++ b/web/template.mf
@@ -24,6 +24,7 @@ Import-Template:
org.springframework.beans.*;version="[3.0.0, 3.1.0)",
org.springframework.context.*;version="[3.0.0, 3.1.0)",
org.springframework.core;version="[3.0.0, 3.1.0)",
+ org.springframework.core.io;version="[3.0.0, 3.1.0)",
org.springframework.dao;version="[3.0.0, 3.1.0)";resolution:=optional,
org.springframework.expression;version="[3.0.0, 3.1.0)";resolution:=optional,
org.springframework.expression.spel.*;version="[3.0.0, 3.1.0)";resolution:=optional,
@@ -31,4 +32,7 @@ Import-Template:
org.springframework.mock.web;version="[3.0.0, 3.1.0)";resolution:=optional,
org.springframework.web.context.*;version="[3.0.0, 3.1.0)";resolution:=optional,
org.springframework.util;version="[3.0.0, 3.1.0)";resolution:=optional,
- javax.servlet.*;version="0"
\ No newline at end of file
+ org.w3c.dom;version="0";resolution:=optional,
+ org.xml.sax;version="0";resolution:=optional,
+ javax.servlet.*;version="0",
+ javax.xml.parsers.*;version="0";resolution:=optional
\ No newline at end of file