o Move the web.xml converter code, tests and xsl files from core into the acegifier sample app.
o Switched to dom4j for more flexible xml handling and easier formatting of the XML output. o Modified the test web.xml to match the contacts-filter app to allow easy testing in an acegi application.
This commit is contained in:
parent
74588c8e53
commit
a95964461d
|
@ -0,0 +1,116 @@
|
|||
package acegifier;
|
||||
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.util.Assert;
|
||||
import org.dom4j.Document;
|
||||
import org.dom4j.DocumentHelper;
|
||||
import org.dom4j.DocumentException;
|
||||
import org.dom4j.io.SAXReader;
|
||||
import org.dom4j.io.DocumentSource;
|
||||
import org.dom4j.io.DocumentResult;
|
||||
|
||||
import javax.xml.transform.Source;
|
||||
import javax.xml.transform.Transformer;
|
||||
import javax.xml.transform.TransformerException;
|
||||
import javax.xml.transform.TransformerFactory;
|
||||
import javax.xml.transform.stream.StreamSource;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* A utility to translate a web.xml file into a set of acegi security spring beans.
|
||||
*
|
||||
* Also produces a new "acegified" web.xml file with the necessary filters installed
|
||||
* and the security elements defined by the servlet DTD removed.
|
||||
*
|
||||
* <p>
|
||||
* This class wraps the XSL transform which actually does most of the work.
|
||||
* </p>
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
*/
|
||||
public class WebXmlConverter {
|
||||
private static final String WEB_TO_SPRING_XSL_FILE = "web-to-spring.xsl";
|
||||
private static final String NEW_WEB_XSLT_FILE = "acegi-web.xsl";
|
||||
|
||||
private Transformer acegiSecurityTransformer, newWebXmlTransformer;
|
||||
|
||||
/**
|
||||
* The name of the spring-beans file which the beans will be stored in.
|
||||
* This is required when writing the new web.xml content.
|
||||
*/
|
||||
private String acegiOutputFileName = "applicationContext-acegi-security.xml";
|
||||
|
||||
/** The web.xml content to be converted */
|
||||
private Source xmlSource;
|
||||
/** The results of the conversion */
|
||||
private Document newWebXml, acegiBeansXml;
|
||||
|
||||
public WebXmlConverter() throws Exception {
|
||||
TransformerFactory tf = TransformerFactory.newInstance();
|
||||
|
||||
acegiSecurityTransformer = tf.newTransformer(createTransformerSource(WEB_TO_SPRING_XSL_FILE));
|
||||
newWebXmlTransformer = tf.newTransformer(createTransformerSource(NEW_WEB_XSLT_FILE));
|
||||
}
|
||||
|
||||
private Source createTransformerSource(String fileName) throws IOException {
|
||||
ClassPathResource resource = new ClassPathResource(fileName);
|
||||
return new StreamSource(resource.getInputStream());
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the transformations on the input source.
|
||||
* Creates new web.xml content and a set of acegi-security Spring beans which can be
|
||||
* accessed through the appropriate getter methods.
|
||||
*/
|
||||
public void doConversion() throws IOException, TransformerException {
|
||||
Assert.notNull(xmlSource, "The XML input must be set");
|
||||
|
||||
// Create the modified web.xml file
|
||||
newWebXmlTransformer.setParameter("acegi-security-context-file", acegiOutputFileName);
|
||||
// newWebXmlTransformer.setParameter("cas-proxy-url", "http://localhost:8433/cas/proxy");
|
||||
DocumentResult result = new DocumentResult();
|
||||
newWebXmlTransformer.transform(xmlSource, result);
|
||||
newWebXml = result.getDocument();
|
||||
|
||||
result = new DocumentResult();
|
||||
acegiSecurityTransformer.transform(xmlSource, result);
|
||||
acegiBeansXml = result.getDocument();
|
||||
}
|
||||
|
||||
/** Set the input as an xml string */
|
||||
public void setInput(String xml) throws DocumentException {
|
||||
Document document = DocumentHelper.parseText(xml);
|
||||
xmlSource = new DocumentSource(document);
|
||||
}
|
||||
|
||||
/** set the input as an InputStream */
|
||||
public void setInput(InputStream xmlIn) throws Exception {
|
||||
SAXReader reader = new SAXReader();
|
||||
Document document = reader.read(xmlIn);
|
||||
xmlSource = new DocumentSource(document);
|
||||
}
|
||||
|
||||
public String getAcegiOutputFileName() {
|
||||
return acegiOutputFileName;
|
||||
}
|
||||
|
||||
public void setAcegiOutputFileName(String acegiOutputFileName) {
|
||||
this.acegiOutputFileName = acegiOutputFileName;
|
||||
}
|
||||
|
||||
/** Returns the converted web.xml content */
|
||||
public Document getNewWebXml() {
|
||||
return newWebXml;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the created spring-beans xml content which should be used in
|
||||
* the application context file.
|
||||
*/
|
||||
public Document getAcegiBeans() {
|
||||
return acegiBeansXml;
|
||||
}
|
||||
|
||||
}
|
|
@ -3,22 +3,26 @@ package acegifier.web;
|
|||
import org.springframework.web.servlet.mvc.SimpleFormController;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
import org.springframework.validation.BindException;
|
||||
import org.springframework.validation.Errors;
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
|
||||
import org.springframework.beans.BeansException;
|
||||
import net.sf.acegisecurity.util.InMemoryResource;
|
||||
import org.w3c.dom.Document;
|
||||
import org.xml.sax.SAXParseException;
|
||||
import org.dom4j.Document;
|
||||
import org.dom4j.io.XMLWriter;
|
||||
import org.dom4j.io.OutputFormat;
|
||||
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import net.sf.acegisecurity.util.WebXmlToAcegiSecurityConverter;
|
||||
import net.sf.acegisecurity.util.FilterChainProxy;
|
||||
import acegifier.WebXmlConverter;
|
||||
|
||||
/**
|
||||
* Takes a submitted web.xml, applies the transformer to it and returns the resulting
|
||||
|
@ -28,10 +32,8 @@ import net.sf.acegisecurity.util.WebXmlToAcegiSecurityConverter;
|
|||
* @version $Id$
|
||||
*/
|
||||
public class AcegifierController extends SimpleFormController {
|
||||
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
|
||||
|
||||
public AcegifierController() {
|
||||
dbf.setValidating(false);
|
||||
}
|
||||
|
||||
public ModelAndView onSubmit(
|
||||
|
@ -39,23 +41,20 @@ public class AcegifierController extends SimpleFormController {
|
|||
throws Exception {
|
||||
|
||||
AcegifierForm conversion = (AcegifierForm)command;
|
||||
|
||||
ByteArrayInputStream in = new ByteArrayInputStream(conversion.getWebXml().getBytes());
|
||||
DocumentBuilder db = dbf.newDocumentBuilder();
|
||||
Document doc = null;
|
||||
WebXmlToAcegiSecurityConverter converter = null;
|
||||
WebXmlConverter converter = null;
|
||||
int nBeans = 0;
|
||||
Document newWebXml = null, acegiBeans = null;
|
||||
|
||||
try {
|
||||
doc = db.parse(in);
|
||||
converter = new WebXmlToAcegiSecurityConverter();
|
||||
converter.setInput(doc);
|
||||
converter = new WebXmlConverter();
|
||||
converter.setInput(in);
|
||||
converter.doConversion();
|
||||
nBeans = createBeanFactory(converter.getAcegiBeansXml());
|
||||
newWebXml = converter.getNewWebXml();
|
||||
acegiBeans = converter.getAcegiBeans();
|
||||
nBeans = validateAcegiBeans(conversion, acegiBeans, errors);
|
||||
} catch (SAXParseException spe) {
|
||||
errors.rejectValue("webXml","parseFailure","Your Web XML Document failed to parse: " + spe.getMessage());
|
||||
} catch (BeansException be) {
|
||||
errors.rejectValue("webXml","invalidBeans","There was a problem validating the Spring beans: " + be.getMessage());
|
||||
}
|
||||
|
||||
if(errors.hasErrors()) {
|
||||
|
@ -63,19 +62,49 @@ public class AcegifierController extends SimpleFormController {
|
|||
}
|
||||
|
||||
Map model = new HashMap();
|
||||
model.put("webXml", converter.getNewWebXml());
|
||||
model.put("acegiBeansXml", converter.getAcegiBeansXml());
|
||||
model.put("webXml", prettyPrint(newWebXml));
|
||||
model.put("acegiBeansXml", prettyPrint(acegiBeans));
|
||||
model.put("nBeans", new Integer(nBeans));
|
||||
|
||||
return new ModelAndView("acegificationResults", model);
|
||||
}
|
||||
|
||||
/** Creates a BeanFactory from the transformed XML to make sure the results are valid */
|
||||
private int createBeanFactory(String beansXml) {
|
||||
/** Creates a formatted XML string from the supplied document */
|
||||
private String prettyPrint(Document document) throws IOException {
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||
OutputFormat format = OutputFormat.createPrettyPrint();
|
||||
format.setTrimText(false);
|
||||
XMLWriter writer = new XMLWriter(output, format);
|
||||
writer.write(document);
|
||||
writer.flush();
|
||||
writer.close();
|
||||
return output.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the acegi beans, based on the input form data, and returns the number
|
||||
* of spring beans defined in the document.
|
||||
*/
|
||||
private int validateAcegiBeans(AcegifierForm conversion, Document beans, Errors errors) throws IOException {
|
||||
DefaultListableBeanFactory bf = createBeanFactory(beans);
|
||||
|
||||
//TODO: actually do some proper validation!
|
||||
|
||||
try {
|
||||
bf.getBean("filterChainProxy", FilterChainProxy.class);
|
||||
} catch (BeansException be) {
|
||||
errors.rejectValue("webXml","beansInvalid","There was an error creating or accessing the bean factory " + be.getMessage());
|
||||
}
|
||||
return bf.getBeanDefinitionCount();
|
||||
}
|
||||
|
||||
/** Creates a BeanFactory from the spring beans XML document */
|
||||
private DefaultListableBeanFactory createBeanFactory(Document beans) {
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
XmlBeanDefinitionReader beanReader = new XmlBeanDefinitionReader(bf);
|
||||
beanReader.loadBeanDefinitions(new InMemoryResource(beans.asXML().getBytes()));
|
||||
|
||||
return beanReader.loadBeanDefinitions(new InMemoryResource(beansXml));
|
||||
return bf;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
package acegifier;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
import net.sf.acegisecurity.UserDetails;
|
||||
import net.sf.acegisecurity.intercept.web.FilterSecurityInterceptor;
|
||||
import net.sf.acegisecurity.intercept.web.SecurityEnforcementFilter;
|
||||
import net.sf.acegisecurity.providers.ProviderManager;
|
||||
import net.sf.acegisecurity.providers.dao.DaoAuthenticationProvider;
|
||||
import net.sf.acegisecurity.providers.dao.memory.InMemoryDaoImpl;
|
||||
import net.sf.acegisecurity.util.InMemoryResource;
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.dom4j.Document;
|
||||
import org.dom4j.io.OutputFormat;
|
||||
import org.dom4j.io.XMLWriter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
|
||||
/**
|
||||
* Tests the WebXmlConverter by applying it to a sample web.xml file.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
* @version $Id$
|
||||
*/
|
||||
public class WebXmlConverterTests extends TestCase {
|
||||
|
||||
public void testFileConversion() throws Exception {
|
||||
WebXmlConverter converter = new WebXmlConverter();
|
||||
|
||||
Resource r = new ClassPathResource("test-web.xml");
|
||||
converter.setInput(r.getInputStream());
|
||||
converter.doConversion();
|
||||
|
||||
DefaultListableBeanFactory bf = new DefaultListableBeanFactory();
|
||||
XmlBeanDefinitionReader beanReader = new XmlBeanDefinitionReader(bf);
|
||||
|
||||
beanReader.loadBeanDefinitions(
|
||||
new InMemoryResource(converter.getAcegiBeans().asXML().getBytes()));
|
||||
assertNotNull(bf.getBean("filterChainProxy"));
|
||||
|
||||
ProviderManager pm = (ProviderManager) bf.getBean("authenticationManager");
|
||||
assertNotNull(pm);
|
||||
assertEquals(3, pm.getProviders().size());
|
||||
|
||||
DaoAuthenticationProvider dap =
|
||||
(DaoAuthenticationProvider) bf.getBean("daoAuthenticationProvider");
|
||||
assertNotNull(dap);
|
||||
|
||||
InMemoryDaoImpl dao = (InMemoryDaoImpl) dap.getAuthenticationDao();
|
||||
UserDetails user = dao.loadUserByUsername("superuser");
|
||||
assertEquals("password",user.getPassword());
|
||||
assertEquals(2, user.getAuthorities().length);
|
||||
assertNotNull(bf.getBean("anonymousProcessingFilter"));
|
||||
assertNotNull(bf.getBean("anonymousAuthenticationProvider"));
|
||||
assertNotNull(bf.getBean("httpSessionContextIntegrationFilter"));
|
||||
assertNotNull(bf.getBean("rememberMeProcessingFilter"));
|
||||
assertNotNull(bf.getBean("rememberMeAuthenticationProvider"));
|
||||
|
||||
SecurityEnforcementFilter sef =
|
||||
(SecurityEnforcementFilter) bf.getBean("securityEnforcementFilter");
|
||||
assertNotNull(sef);
|
||||
assertNotNull(sef.getAuthenticationEntryPoint());
|
||||
FilterSecurityInterceptor fsi = sef.getFilterSecurityInterceptor();
|
||||
System.out.println(prettyPrint(converter.getAcegiBeans()));
|
||||
|
||||
}
|
||||
|
||||
private String prettyPrint(Document document) throws IOException {
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||
OutputFormat format = OutputFormat.createPrettyPrint();
|
||||
format.setNewlines(true);
|
||||
format.setTrimText(false);
|
||||
XMLWriter writer = new XMLWriter(output, format);
|
||||
writer.write(document);
|
||||
writer.flush();
|
||||
writer.close();
|
||||
return output.toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,126 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd">
|
||||
|
||||
<web-app>
|
||||
<display-name>Contacts Sample Application</display-name>
|
||||
|
||||
<context-param>
|
||||
<param-name>contextConfigLocation</param-name>
|
||||
<param-value>
|
||||
/WEB-INF/applicationContext-common-business.xml
|
||||
/WEB-INF/applicationContext-common-authorization.xml
|
||||
</param-value>
|
||||
</context-param>
|
||||
|
||||
<context-param>
|
||||
<param-name>log4jConfigLocation</param-name>
|
||||
<param-value>/WEB-INF/classes/log4j.properties</param-value>
|
||||
</context-param>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>contacts</servlet-name>
|
||||
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
|
||||
<load-on-startup>1</load-on-startup>
|
||||
</servlet>
|
||||
|
||||
<listener>
|
||||
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
|
||||
</listener>
|
||||
|
||||
<listener>
|
||||
<listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
|
||||
</listener>
|
||||
<!--
|
||||
The HttpSessionEventPublisher will publish
|
||||
HttpSessionCreatedEvent and HttpSessionDestroyedEvent
|
||||
to the WebApplicationContext
|
||||
-->
|
||||
<listener>
|
||||
<listener-class>net.sf.acegisecurity.ui.session.HttpSessionEventPublisher</listener-class>
|
||||
</listener>
|
||||
<!--
|
||||
- Provides web services endpoint. See remoting-servlet.xml.
|
||||
-->
|
||||
<servlet>
|
||||
<servlet-name>remoting</servlet-name>
|
||||
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
|
||||
<load-on-startup>2</load-on-startup>
|
||||
</servlet>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>contacts</servlet-name>
|
||||
<url-pattern>*.htm</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>remoting</servlet-name>
|
||||
<url-pattern>/remoting/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<welcome-file-list>
|
||||
<welcome-file>index.jsp</welcome-file>
|
||||
</welcome-file-list>
|
||||
|
||||
<security-constraint>
|
||||
<web-resource-collection>
|
||||
<url-pattern>/index.jsp</url-pattern>
|
||||
</web-resource-collection>
|
||||
<auth-constraint>
|
||||
<role-name>*</role-name>
|
||||
</auth-constraint>
|
||||
</security-constraint>
|
||||
|
||||
<security-constraint>
|
||||
<web-resource-collection>
|
||||
<url-pattern>/hello.htm</url-pattern>
|
||||
</web-resource-collection>
|
||||
<auth-constraint>
|
||||
<role-name>*</role-name>
|
||||
</auth-constraint>
|
||||
</security-constraint>
|
||||
|
||||
<security-constraint>
|
||||
<web-resource-collection>
|
||||
<url-pattern>/logoff.jsp</url-pattern>
|
||||
</web-resource-collection>
|
||||
<auth-constraint>
|
||||
<role-name>*</role-name>
|
||||
</auth-constraint>
|
||||
</security-constraint>
|
||||
|
||||
<security-constraint>
|
||||
<web-resource-collection>
|
||||
<url-pattern>/acegilogin.jsp*</url-pattern>
|
||||
</web-resource-collection>
|
||||
<auth-constraint>
|
||||
<role-name>*</role-name>
|
||||
</auth-constraint>
|
||||
</security-constraint>
|
||||
|
||||
<security-constraint>
|
||||
<web-resource-collection>
|
||||
<url-pattern>/*</url-pattern>
|
||||
</web-resource-collection>
|
||||
<auth-constraint>
|
||||
<role-name>user</role-name>
|
||||
</auth-constraint>
|
||||
</security-constraint>
|
||||
|
||||
<login-config>
|
||||
<auth-method>form</auth-method>
|
||||
<form-login-config>
|
||||
<form-login-page>/acegilogin.jsp</form-login-page>
|
||||
<form-error-page>/acegilogin.jsp?login_error=1</form-error-page>
|
||||
</form-login-config>
|
||||
|
||||
</login-config>
|
||||
|
||||
<security-role>
|
||||
<role-name>user</role-name>
|
||||
</security-role>
|
||||
|
||||
<security-role>
|
||||
<role-name>dummy</role-name>
|
||||
</security-role>
|
||||
|
||||
</web-app>
|
|
@ -19,6 +19,10 @@
|
|||
</context-param>
|
||||
-->
|
||||
|
||||
<welcome-file-list>
|
||||
<welcome-file>/convert.htm</welcome-file>
|
||||
</welcome-file-list>
|
||||
|
||||
<listener>
|
||||
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
|
||||
</listener>
|
||||
|
|
Loading…
Reference in New Issue