From e573223c85690e8cdc4a7313c11f131527731fe3 Mon Sep 17 00:00:00 2001 From: chris_schultz Date: Wed, 7 Nov 2007 17:22:38 +0000 Subject: [PATCH] Added support for , specifically . --- .../org/securityfilter/config/SecurityConfig.java | 36 +- .../securityfilter/config/SecurityConstraint.java | 35 +- .../securityfilter/config/UserDataConstraint.java | 159 ++++++++ .../org/securityfilter/filter/SecurityFilter.java | 113 +++++- .../test/config/UserDataConfigTest.java | 448 +++++++++++++++++++++ .../test/http/form/TransportGuaranteeTest.java | 142 +++++++ web/example/WEB-INF/securityfilter-config.xml | 36 +- web/example/regularPage.jsp | 0 8 files changed, 949 insertions(+), 20 deletions(-) create mode 100644 src/share/org/securityfilter/config/UserDataConstraint.java create mode 100644 src/test/org/securityfilter/test/config/UserDataConfigTest.java create mode 100644 src/test/org/securityfilter/test/http/form/TransportGuaranteeTest.java create mode 100644 web/example/regularPage.jsp diff --git a/src/share/org/securityfilter/config/SecurityConfig.java b/src/share/org/securityfilter/config/SecurityConfig.java index 38f1db5..8f2c413 100644 --- a/src/share/org/securityfilter/config/SecurityConfig.java +++ b/src/share/org/securityfilter/config/SecurityConfig.java @@ -1,7 +1,7 @@ /* - * $Header: /cvsroot/securityfilter/securityfilter/src/share/org/securityfilter/config/SecurityConfig.java,v 1.17 2004/01/26 10:54:38 maxcooper Exp $ - * $Revision: 1.17 $ - * $Date: 2004/01/26 10:54:38 $ + * $Header: /cvsroot/securityfilter/securityfilter/src/share/org/securityfilter/config/SecurityConfig.java,v 1.18 2007/11/07 17:22:38 chris_schultz Exp $ + * $Revision: 1.18 $ + * $Date: 2007/11/07 17:22:38 $ * * ==================================================================== * The SecurityFilter Software License, Version 1.1 @@ -72,7 +72,7 @@ import java.util.*; * @author Max Cooper (max@maxcooper.com) * @author Daya Sharma (iamdaya@yahoo.com, billydaya@sbcglobal.net) * @author David Reed (dreed10@neo.rr.com) - * @version $Revision: 1.17 $ $Date: 2004/01/26 10:54:38 $ + * @version $Revision: 1.18 $ $Date: 2007/11/07 17:22:38 $ */ public class SecurityConfig { @@ -267,6 +267,12 @@ public class SecurityConfig { return persistentLoginManager; } + public void loadConfig(URL configURL) + throws IOException, SAXException + { + loadConfig(new InputSource(configURL.openStream())); + } + /** * Loads configuration from the specifued configURL. * @@ -275,8 +281,9 @@ public class SecurityConfig { * @exception IOException if an input/output error occurs * @exception SAXException if the file has invalid xml syntax */ - public void loadConfig(URL configURL) throws IOException, SAXException { - + public void loadConfig(InputSource input) + throws IOException, SAXException + { securityConstraints = new ArrayList(); Digester digester = new Digester(); @@ -351,6 +358,22 @@ public class SecurityConfig { 0 ); + // user-data-constraint + digester.addObjectCreate( + "securityfilter-config/security-constraint/user-data-constraint", + "org.securityfilter.config.UserDataConstraint" + ); + digester.addSetNext( + "securityfilter-config/security-constraint/user-data-constraint", + "setUserDataConstraint", + "org.securityfilter.config.UserDataConstraint" + ); + digester.addCallMethod( + "securityfilter-config/security-constraint/user-data-constraint/transport-guarantee", + "setTransportGuarantee", + 0 + ); + // web-resource-collection digester.addObjectCreate( "securityfilter-config/security-constraint/web-resource-collection", @@ -372,7 +395,6 @@ public class SecurityConfig { 0 ); - InputSource input = new InputSource(configURL.openStream()); digester.parse(input); } diff --git a/src/share/org/securityfilter/config/SecurityConstraint.java b/src/share/org/securityfilter/config/SecurityConstraint.java index 8968581..31222a7 100644 --- a/src/share/org/securityfilter/config/SecurityConstraint.java +++ b/src/share/org/securityfilter/config/SecurityConstraint.java @@ -1,7 +1,7 @@ /* - * $Header: /cvsroot/securityfilter/securityfilter/src/share/org/securityfilter/config/SecurityConstraint.java,v 1.6 2004/01/26 09:29:56 maxcooper Exp $ - * $Revision: 1.6 $ - * $Date: 2004/01/26 09:29:56 $ + * $Header: /cvsroot/securityfilter/securityfilter/src/share/org/securityfilter/config/SecurityConstraint.java,v 1.7 2007/11/07 17:22:38 chris_schultz Exp $ + * $Revision: 1.7 $ + * $Date: 2007/11/07 17:22:38 $ * * ==================================================================== * The SecurityFilter Software License, Version 1.1 @@ -58,15 +58,19 @@ package org.securityfilter.config; import java.util.*; /** - * SecurityConstraint + * SecurityConstraint models the <security-constraint> element + * in a web application's deployment descriptor. * * @author Max Cooper (max@maxcooper.com) * @author Torgeir Veimo (torgeir@pobox.com) - * @version $Revision: 1.6 $ $Date: 2004/01/26 09:29:56 $ + * @author Chris Schultz (chris@christopherschultz.net) + * + * @version $Revision: 1.7 $ $Date: 2007/11/07 17:22:38 $ */ public class SecurityConstraint { private List resourceCollections; private AuthConstraint authConstraint = null; + private UserDataConstraint userDataConstraint; /** * Constructor @@ -111,6 +115,27 @@ public class SecurityConstraint { public AuthConstraint getAuthConstraint() { return authConstraint; } + + /** + * Sets the UserDataConstraint for this SecurityConstraint. + * + * @param userDataConstraint The UserDataConstraint. + */ + public void setUserDataConstraint(UserDataConstraint userDataConstraint) + { + this.userDataConstraint = userDataConstraint; + } + + /** + * Gets the UserDataConstraint for this SecurityConstraint. + * + * @return The UserDataConstraint for this SecurityConstraint, or + * null if none has been set. + */ + public UserDataConstraint getUserDataConstraint() + { + return userDataConstraint; + } } // ------------------------------------------------------------------------ diff --git a/src/share/org/securityfilter/config/UserDataConstraint.java b/src/share/org/securityfilter/config/UserDataConstraint.java new file mode 100644 index 0000000..c2c49e8 --- /dev/null +++ b/src/share/org/securityfilter/config/UserDataConstraint.java @@ -0,0 +1,159 @@ +/* + * $Header: /cvsroot/securityfilter/securityfilter/src/share/org/securityfilter/config/UserDataConstraint.java,v 1.1 2007/11/07 17:22:38 chris_schultz Exp $ + * $Revision: 1.1 $ + * $Date: 2007/11/07 17:22:38 $ + * + * ==================================================================== + * The SecurityFilter Software License, Version 1.1 + * + * (this license is derived and fully compatible with the Apache Software + * License - see http://www.apache.org/LICENSE.txt) + * + * Copyright (c) 2007 SecurityFilter.org. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes software developed by + * SecurityFilter.org (http://www.securityfilter.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The name "SecurityFilter" must not be used to endorse or promote + * products derived from this software without prior written permission. + * For written permission, please contact license@securityfilter.org . + * + * 5. Products derived from this software may not be called "SecurityFilter", + * nor may "SecurityFilter" appear in their name, without prior written + * permission of SecurityFilter.org. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE SECURITY FILTER PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + */ + +package org.securityfilter.config; + +/** + * UserDataConstraint models the <user-data-constraint> element + * in a web application's deployment descriptor. + * + *
+ * <user-data-constraint>
+ *    <description^gt;This is the user data constraint.</description>
+ *    <transport-guarantee>
+ *        NONE
+ *        or INTEGRAL
+ *        or CONFIDENTIAL
+ *    </transport-guarantee^gt;
+ * >/user-data-constraint>
+ * 
+ * + * @author Chris Schultz (chris@christopherschultz.net) + * @version $Revision: 1.1 $ $Date: 2007/11/07 17:22:38 $ + */ +public class UserDataConstraint +{ + /** + * Constant for transport guarantee that indicates no guarantees. + * + * @see #setTransportGuarantee(String) + */ + public static final String TRANSPORT_GUARANTEE_NONE = "NONE"; + + /** + * Constant for transport guarantee that indicates data sent between + * the client and server are sent in such a way that they cannot be changed + * in transit. + * + * @see #setTransportGuarantee(String) + */ + public static final String TRANSPORT_GUARANTEE_INTEGRAL = "INTEGRAL"; + + /** + * Constant for transport guarantee that indicates data sent between + * the client and server are sent in such a way that they cannot be + * observed by third-parties while in transit. + * + * @see #setTransportGuarantee(String) + */ + public static final String TRANSPORT_GUARANTEE_CONFIDENTIAL = "CONFIDENTIAL"; + + /** + * The transport-guarantee for this UserDataConstraint. + */ + private String _transportGuarantee = TRANSPORT_GUARANTEE_NONE; + + public UserDataConstraint() + { + } + + /** + * Sets the transport-guarantee required by this UserDataConstraint. + * + * @param guarantee Valid values (case sensitive) are NONE, + * INTEGRAL, and CONFIDENTIAL. + * + * @throws IllegalArgumentException If guarantee is neither + * NONE nor INTEGRAL + * nor CONFIDENTIAL. + * + * @see #getTransportGuarantee() + * @see #TRANSPORT_GUARANTEE_NONE + * @see #TRANSPORT_GUARANTEE_INTEGRAL + * @see #TRANSPORT_GUARANTEE_CONFIDENTIAL + */ + public void setTransportGuarantee(String guarantee) + throws IllegalArgumentException + { + if(null == guarantee) + { + _transportGuarantee = null; + } + else + { + guarantee = guarantee.trim(); + + if(!(TRANSPORT_GUARANTEE_NONE.equals(guarantee) + || TRANSPORT_GUARANTEE_INTEGRAL.equals(guarantee) + || TRANSPORT_GUARANTEE_CONFIDENTIAL.equals(guarantee))) + throw new IllegalArgumentException("Unknown transport guarantee: " + guarantee); + + _transportGuarantee = guarantee; + } + } + + /** + * Returns the transport guarantee for this UserDataConstraint. + * + * @see #setTransportGuarantee + */ + public String getTransportGuarantee() + { + return _transportGuarantee; + } +} + +// ---------------------------------------------------------------------------- +// EOF diff --git a/src/share/org/securityfilter/filter/SecurityFilter.java b/src/share/org/securityfilter/filter/SecurityFilter.java index dbb5e4f..31ef9e2 100644 --- a/src/share/org/securityfilter/filter/SecurityFilter.java +++ b/src/share/org/securityfilter/filter/SecurityFilter.java @@ -1,7 +1,7 @@ /* - * $Header: /cvsroot/securityfilter/securityfilter/src/share/org/securityfilter/filter/SecurityFilter.java,v 1.24 2006/02/14 09:28:27 maxcooper Exp $ - * $Revision: 1.24 $ - * $Date: 2006/02/14 09:28:27 $ + * $Header: /cvsroot/securityfilter/securityfilter/src/share/org/securityfilter/filter/SecurityFilter.java,v 1.25 2007/11/07 17:22:38 chris_schultz Exp $ + * $Revision: 1.25 $ + * $Date: 2007/11/07 17:22:38 $ * * ==================================================================== * The SecurityFilter Software License, Version 1.1 @@ -72,12 +72,13 @@ import java.util.*; * @author Max Cooper (max@maxcooper.com) * @author Daya Sharma (iamdaya@yahoo.com, billydaya@sbcglobal.net) * @author Torgeir Veimo (torgeir@pobox.com) - * @version $Revision: 1.24 $ $Date: 2006/02/14 09:28:27 $ + * @version $Revision: 1.25 $ $Date: 2007/11/07 17:22:38 $ */ public class SecurityFilter implements Filter { public static final String CONFIG_FILE_KEY = "config"; public static final String DEFAULT_CONFIG_FILE = "/WEB-INF/securityfilter-config.xml"; public static final String VALIDATE_KEY = "validate"; + public static final String SSL_PORT_INIT_PARAMETER_KEY = "ssl-redirect-port"; public static final String TRUE = "true"; @@ -92,6 +93,11 @@ public class SecurityFilter implements Filter { protected URLPatternFactory patternFactory; protected Authenticator authenticator; + /** + * The port to be used when upgrading connections to HTTPS. + */ + protected int sslPort = 443; + /** * Perform filtering operation, and optionally pass the request down the chain. * @@ -150,7 +156,44 @@ public class SecurityFilter implements Filter { // check security constraint, if any if (match != null) { - // TODO: check user-data-constraint + + // Check user-data-constraint (transport-guarantee) + UserDataConstraint userDataConstraint + = match.getSecurityConstraint().getUserDataConstraint(); + if(null != userDataConstraint) + { + String tg = userDataConstraint.getTransportGuarantee(); + if((tg.equals(UserDataConstraint.TRANSPORT_GUARANTEE_INTEGRAL) + || tg.equals(UserDataConstraint.TRANSPORT_GUARANTEE_CONFIDENTIAL)) + && !request.isSecure()) + { + // Servlet Specification Note: + // + // The Servlet Specification does not specify what ought + // to be done when the connection must be "upgraded" + // in order to satisfy the transport-guarantee. + // + // This implementation matches that of the Apache Tomcat + // servlet container (as of version 5.5). + + // Switch from HTTP to HTTPS via redirection. + if(0 <= sslPort) + { + String url = getSecureURL(wrappedRequest); + + hRes.sendRedirect(hRes.encodeRedirectURL(url)); + } + else + { + // SSL port set to a negative: disable redirection. + hRes.sendError(HttpServletResponse.SC_FORBIDDEN, + hReq.getRequestURI()); + } + + return; + } + } + // check auth constraint AuthConstraint authConstraint = match.getSecurityConstraint().getAuthConstraint(); if (authConstraint != null) { @@ -195,6 +238,39 @@ public class SecurityFilter implements Filter { */ public void init(FilterConfig config) throws ServletException { this.config = config; + + String sslPortString = config.getInitParameter(SSL_PORT_INIT_PARAMETER_KEY); + if(null != sslPortString) + { + try + { + this.sslPort = Integer.parseInt(sslPortString); + + if(this.sslPort > 65535) + { + System.err.println("ERROR: Invalid " + + SSL_PORT_INIT_PARAMETER_KEY + + ": " + sslPortString); + System.err.println("WARN: SSL port redirection is disabled."); + this.sslPort = -1; + } + else if(this.sslPort < 0) + { + System.err.println("INFO: SSL port redirection is disabled (was set to " + this.sslPort + ")"); + } + } + catch (NumberFormatException nfe) + { + System.err.println("ERROR: Invalid " + + SSL_PORT_INIT_PARAMETER_KEY + + ": " + sslPortString); + System.err.println("WARN: SSL port redirection is disabled."); + nfe.printStackTrace(); + + this.sslPort = -1; + } + } + try { // parse config file @@ -263,8 +339,8 @@ public class SecurityFilter implements Filter { * @param matcher the thread-local URLPatternMatcher object * @return the matching URLPattern object, or null if there is no match. */ - protected URLPattern matchPattern(String pattern, String httpMethod, URLPatternMatcher matcher) throws Exception { - // PERFORMANCE IMPROVEMENT OPPORTUNITY: cahce pattern matches + protected URLPattern matchPattern(String pattern, String httpMethod, URLPatternMatcher matcher) { + // PERFORMANCE IMPROVEMENT OPPORTUNITY: cache pattern matches Iterator i = patternList.iterator(); while (i.hasNext()) { URLPattern urlPattern = (URLPattern) i.next(); @@ -356,6 +432,29 @@ public class SecurityFilter implements Filter { return saveableURL.toString(); } + protected String getSecureURL(HttpServletRequest request) + { + StringBuffer url = new StringBuffer(); + url.append("https://") + .append(request.getServerName()) + ; + + if(443 != sslPort) + url.append(':') + .append(sslPort) + ; + + url.append(request.getRequestURI()); + + String queryString = request.getQueryString(); + if(null != queryString) + url.append('?') + .append(queryString) + ; + + return url.toString(); + } + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // The following methods are provided for compatibility with various app servers. // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/test/org/securityfilter/test/config/UserDataConfigTest.java b/src/test/org/securityfilter/test/config/UserDataConfigTest.java new file mode 100644 index 0000000..4f2690f --- /dev/null +++ b/src/test/org/securityfilter/test/config/UserDataConfigTest.java @@ -0,0 +1,448 @@ +/* + * $Header: /cvsroot/securityfilter/securityfilter/src/test/org/securityfilter/test/config/UserDataConfigTest.java,v 1.1 2007/11/07 17:22:38 chris_schultz Exp $ + * $Revision: 1.1 $ + * $Date: 2007/11/07 17:22:38 $ + * + * ==================================================================== + * The SecurityFilter Software License, Version 1.1 + * + * (this license is derived and fully compatible with the Apache Software + * License - see http://www.apache.org/LICENSE.txt) + * + * Copyright (c) 2007 SecurityFilter.org. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes software developed by + * SecurityFilter.org (http://www.securityfilter.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The name "SecurityFilter" must not be used to endorse or promote + * products derived from this software without prior written permission. + * For written permission, please contact license@securityfilter.org . + * + * 5. Products derived from this software may not be called "SecurityFilter", + * nor may "SecurityFilter" appear in their name, without prior written + * permission of SecurityFilter.org. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE SECURITY FILTER PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + */ + +package org.securityfilter.test.config; + +import java.io.StringReader; +import java.lang.reflect.Proxy; +import java.lang.reflect.Method; +import java.lang.reflect.InvocationHandler; +import java.net.MalformedURLException; +import java.util.List; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletRequestWrapper; + +import org.xml.sax.InputSource; + +import junit.framework.Assert; +import junit.framework.TestCase; + +import org.securityfilter.filter.SecurityFilter; +import org.securityfilter.config.SecurityConfig; +import org.securityfilter.config.SecurityConstraint; +import org.securityfilter.config.UserDataConstraint; + +import javax.servlet.FilterConfig; +import java.util.Enumeration; +import javax.servlet.ServletContext; + +/** + * UserDataConfigTests - tests to see that the transport guarantee + * configuration has been loaded correctly. + * + * @author Chris Schultz (chris@christopherschultz.net) + * @version $Revision: 1.1 $ $Date: 2007/11/07 17:22:38 $ + */ +public class UserDataConfigTest + extends TestCase +{ + public UserDataConfigTest(String name) + { + super(name); + } + + public void testNoUserDataConstraint() + throws Exception + { + String config = + "\n" + + "\n" + + "" + + + "" + + "\n" + + " " + + " " + + " Secure Page" + + " /securePage.jsp" + + " " + + " " + + " inthisrole" + + " " + + " " + + "\n" + + " " + + " BASIC" + + " " + + "\n" + + " " + + " " + + "\n" + + "" + ; + + SecurityConfig sc = new SecurityConfig(true); + + sc.loadConfig(new InputSource(new StringReader(config))); + + List constraints = sc.getSecurityConstraints(); + + Assert.assertNotNull("Should have some security constraints", + constraints); + + Assert.assertEquals("Should have 1 security constraint.", + 1, + constraints.size()); + + SecurityConstraint constraint + = (SecurityConstraint)constraints.get(0); + + Assert.assertNull("Should not have a UserDataConstraint", + constraint.getUserDataConstraint()); + } + + public void testTransportGuaranteeNone() + throws Exception + { + String config = + "\n" + + "\n" + + "" + + + "" + + "\n" + + " " + + " " + + " Secure Page" + + " /securePage.jsp" + + " " + + " " + + " inthisrole" + + " " + + " " + + " The user data constraint" + + " NONE" + + " " + + " " + + "\n" + + " " + + " BASIC" + + " " + + "\n" + + " " + + " " + + "\n" + + "" + ; + + SecurityConfig sc = new SecurityConfig(true); + + sc.loadConfig(new InputSource(new StringReader(config))); + + List constraints = sc.getSecurityConstraints(); + + Assert.assertNotNull("Should have some security constraints", + constraints); + + Assert.assertEquals("Should have 1 security constraint.", + 1, + constraints.size()); + + SecurityConstraint constraint + = (SecurityConstraint)constraints.get(0); + + Assert.assertNotNull("Should have a UserDataConstraint", + constraint.getUserDataConstraint()); + + Assert.assertEquals("Incorrect transport-guarantee", + UserDataConstraint.TRANSPORT_GUARANTEE_NONE, + constraint.getUserDataConstraint() + .getTransportGuarantee()); + } + + public void testTransportGuaranteeNoneExtraSpaces() + throws Exception + { + String config = + "\n" + + "\n" + + "" + + + "" + + "\n" + + " " + + " " + + " Secure Page" + + " /securePage.jsp" + + " " + + " " + + " inthisrole" + + " " + + " " + + " The user data constraint" + + " NONE" + + " " + + " " + + " " + + "\n" + + " " + + " BASIC" + + " " + + "\n" + + " " + + " " + + "\n" + + "" + ; + + SecurityConfig sc = new SecurityConfig(true); + + sc.loadConfig(new InputSource(new StringReader(config))); + + List constraints = sc.getSecurityConstraints(); + + Assert.assertNotNull("Should have some security constraints", + constraints); + + Assert.assertEquals("Should have 1 security constraint.", + 1, + constraints.size()); + + SecurityConstraint constraint + = (SecurityConstraint)constraints.get(0); + + Assert.assertNotNull("Should have a UserDataConstraint", + constraint.getUserDataConstraint()); + + Assert.assertEquals("Incorrect transport-guarantee", + UserDataConstraint.TRANSPORT_GUARANTEE_NONE, + constraint.getUserDataConstraint() + .getTransportGuarantee()); + } + + public void _testInvalidTransportGuarantee() + throws Exception + { + String config = + "\n" + + "\n" + + "" + + + "" + + "\n" + + " " + + " " + + " Secure Page" + + " /securePage.jsp" + + " " + + " " + + " inthisrole" + + " " + + " " + + " The user data constraint" + + " INVALID" + + " " + + " " + + "\n" + + " " + + " BASIC" + + " " + + "\n" + + " " + + " " + + "\n" + + "" + ; + + SecurityConfig sc = new SecurityConfig(true); + + try + { + sc.loadConfig(new InputSource(new StringReader(config))); + + Assert.fail("INVALID transport guarantee should have failed."); + } + catch (org.xml.sax.SAXParseException spe) + { + // Expected behavior + } + } + + // + // Make sure that the getSecureURL method is working. + // + + private String getSecureURL(String url) + throws MalformedURLException, javax.servlet.ServletException + { + // TODO: This method is /horrible/. We should be using mock objects + // instead of monkeying-around with Proxies and stuff. + final java.net.URL theUrl = new java.net.URL(url); + + InvocationHandler handler = new InvocationHandler() { + public Object invoke(Object o, + Method m, + Object[] args) + { + if("getServerName".equals(m.getName())) + { + return theUrl.getHost(); + } + else if("getRequestURI".equals(m.getName())) + { + return theUrl.getPath(); + } + else if("getQueryString".equals(m.getName())) + { + return theUrl.getQuery(); + } + else + throw new IllegalStateException("Unexpected call to: "+ m); + } + } + ; + + HttpServletRequest request = (HttpServletRequest)Proxy + .newProxyInstance(this.getClass().getClassLoader(), + new Class[] { HttpServletRequest.class }, + handler); + + return new SecurityFilter() + { + public String getSecureURL(HttpServletRequest request) + { + return super.getSecureURL(request); + } + }.getSecureURL(request); + } + + public void testGetSecureURL() + throws Exception + { + String url = "http://www.foo.com/path/resource?query=string&foo=bar"; + + String expected = url.replace("http://", "https://"); + + Assert.assertEquals(expected, getSecureURL(url)); + } + + public void testGetSecureURL_AlreadySecure() + throws Exception + { + String url = "https://www.foo.com/path/resource?query=string&foo=bar"; + + String expected = url; + + Assert.assertEquals(expected, getSecureURL(url)); + } + + public void testGetSecureURL_Port() + throws Exception + { + String url = "http://www.foo.com:42/path/resource?query=string&foo=bar"; + + String expected = url.replace("http://", "https://") + .replace(":42", ""); + + Assert.assertEquals(expected, getSecureURL(url)); + } + + public void testGetSecureURL_NoQueryString() + throws Exception + { + String url = "http://www.foo.com:42/path/resource"; + + String expected = url.replace("http://", "https://") + .replace(":42", ""); + + Assert.assertEquals(expected, getSecureURL(url)); + } + + public void testGetSecureURL_NoSlash() + throws Exception + { + String url = "http://www.foo.com:42"; + + String expected = url.replace("http://", "https://") + .replace(":42", ""); + + Assert.assertEquals(expected, getSecureURL(url)); + } + + public void testGetSecureURL_NoPortNoSlash() + throws Exception + { + String url = "http://www.foo.com"; + + String expected = url.replace("http://", "https://"); + + Assert.assertEquals(expected, getSecureURL(url)); + } +} diff --git a/src/test/org/securityfilter/test/http/form/TransportGuaranteeTest.java b/src/test/org/securityfilter/test/http/form/TransportGuaranteeTest.java new file mode 100644 index 0000000..042183d --- /dev/null +++ b/src/test/org/securityfilter/test/http/form/TransportGuaranteeTest.java @@ -0,0 +1,142 @@ +/* + * $Header: /cvsroot/securityfilter/securityfilter/src/test/org/securityfilter/test/http/form/TransportGuaranteeTest.java,v 1.1 2007/11/07 17:22:39 chris_schultz Exp $ + * $Revision: 1.1 $ + * $Date: 2007/11/07 17:22:39 $ + * + * ==================================================================== + * The SecurityFilter Software License, Version 1.1 + * + * (this license is derived and fully compatible with the Apache Software + * License - see http://www.apache.org/LICENSE.txt) + * + * Copyright (c) 2007 SecurityFilter.org. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, + * if any, must include the following acknowledgment: + * "This product includes software developed by + * SecurityFilter.org (http://www.securityfilter.org/)." + * Alternately, this acknowledgment may appear in the software itself, + * if and wherever such third-party acknowledgments normally appear. + * + * 4. The name "SecurityFilter" must not be used to endorse or promote + * products derived from this software without prior written permission. + * For written permission, please contact license@securityfilter.org . + * + * 5. Products derived from this software may not be called "SecurityFilter", + * nor may "SecurityFilter" appear in their name, without prior written + * permission of SecurityFilter.org. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE SECURITY FILTER PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + */ + +package org.securityfilter.test.http.form; + +import com.meterware.httpunit.*; +import junit.framework.Assert; +import org.securityfilter.example.Constants; +import org.securityfilter.test.http.TestBase; +import org.securityfilter.authenticator.FormAuthenticator; + +/** + * ForwardAfterLoginTest - test forward-afterlogin behavior. + * + * @author Chris Schultz (chris@christopherschultz.net) + * @version $Revision: 1.1 $ $Date: 2007/11/07 17:22:39 $ + */ +public class TransportGuaranteeTest + extends TestBase +{ + public TransportGuaranteeTest(String name) { + super(name); + } + + public void testNoSSLUpgrade() + throws Exception + { + // request the login page + WebConversation session = new WebConversation(); + // Disable automatic redirection so we can detect it ourselves. + session.getClientProperties().setAutoRedirect(false); + WebRequest request = new GetMethodWebRequest(baseUrl + "/regularPage.jsp"); + WebResponse response = session.getResponse(request); + + + String location = response.getHeaderField("Location"); + + Assert.assertNull(location); + } + + public void testIntegralRequirement() + throws Exception + { + // request the login page + WebConversation session = new WebConversation(); + // Disable automatic redirection so we can detect it ourselves. + session.getClientProperties().setAutoRedirect(false); + WebRequest request = new GetMethodWebRequest(baseUrl + "/integral.jsp"); + WebResponse response = session.getResponse(request); + + String location = response.getHeaderField("Location"); + + Assert.assertNotNull(location); + + // Remove any ";jsessionid" parameter. + if(0 <= location.indexOf(";jsessionid=")) + location = location.replaceAll(";jsessionid=[a-fA-F0-9]+", ""); + + // Check for correct redirect (fully-qualified URL) + String url = baseUrl.replace("http://", "https://").replaceAll(":[0-9]+", ""); + + Assert.assertEquals(url + "/integral.jsp", + location); + } + + public void testConfidentialRequirement() + throws Exception + { + // request the login page + WebConversation session = new WebConversation(); + // Disable automatic redirection so we can detect it ourselves. + session.getClientProperties().setAutoRedirect(false); + WebRequest request = new GetMethodWebRequest(baseUrl + "/confidential.html"); + WebResponse response = session.getResponse(request); + + String location = response.getHeaderField("Location"); + + Assert.assertNotNull(location); + + // Remove any ";jsessionid" parameter. + if(0 <= location.indexOf(";jsessionid=")) + location = location.replaceAll(";jsessionid=[a-fA-F0-9]+", ""); + + // Check for correct redirect (fully-qualified URL) + String url = baseUrl.replace("http://", "https://").replaceAll(":[0-9]+", ""); + + Assert.assertEquals(url + "/confidential.html", + location); + } +} diff --git a/web/example/WEB-INF/securityfilter-config.xml b/web/example/WEB-INF/securityfilter-config.xml index bfeb602..863847e 100644 --- a/web/example/WEB-INF/securityfilter-config.xml +++ b/web/example/WEB-INF/securityfilter-config.xml @@ -26,6 +26,40 @@ + + + + Regular Page + /regularPage.jsp + + + No transport guarantee + NONE + + + + + + Integral + /integral.jsp + + + INTEGRAL transport guarantee + INTEGRAL + + + + + + Confidential + /confidential.html + + + CONFIDENTIAL transport guarantee + CONFIDENTIAL + + + FORM @@ -39,4 +73,4 @@ - \ No newline at end of file + diff --git a/web/example/regularPage.jsp b/web/example/regularPage.jsp new file mode 100644 index 0000000..e69de29 -- 2.11.0