SEC-1094: Simplified WebXml attribute mapping. Removed generic jaxen-based implementation on which it was based in favour of simple DOM model traversal. Updated sample.
This commit is contained in:
+1
@@ -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.
|
||||
*/
|
||||
|
||||
+106
-33
@@ -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;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* Example on how to configure this MappableAttributesRetriever in the Spring
|
||||
* configuration file:
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
*
|
||||
* <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"/>
|
||||
*
|
||||
* </pre>
|
||||
* This <tt>MappableAttributesRetriever</tt> implementation reads the list of defined J2EE
|
||||
* roles from a <tt>web.xml</tt> 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<String> mappableAttributes;
|
||||
|
||||
public void setResourceLoader(ResourceLoader resourceLoader) {
|
||||
this.resourceLoader = resourceLoader;
|
||||
}
|
||||
|
||||
|
||||
public Set<String> getMappableAttributes() {
|
||||
return mappableAttributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param anInputStream
|
||||
* The InputStream to read the XML data from
|
||||
* Loads the web.xml file using the configured <tt>ResourceLoader</tt> and
|
||||
* parses the role-name elements from it, using these as the set of <tt>mappableAttributes</tt>.
|
||||
*/
|
||||
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<String> roleNames = new ArrayList<String>();
|
||||
|
||||
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<String>(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(""));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+34
-12
@@ -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<String> 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<String> 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<String> 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<String> j2eeRoles = rolesRetriever.getMappableAttributes();
|
||||
assertEquals("J2eeRoles expected size: 0, actual size: " + j2eeRoles.size(), 0, j2eeRoles.size());
|
||||
|
||||
Reference in New Issue
Block a user