/*
- * $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
* @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 {
return persistentLoginManager;
}
+ public void loadConfig(URL configURL)
+ throws IOException, SAXException
+ {
+ loadConfig(new InputSource(configURL.openStream()));
+ }
+
/**
* Loads configuration from the specifued configURL.
*
* @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();
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",
0
);
- InputSource input = new InputSource(configURL.openStream());
digester.parse(input);
}
/*
- * $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
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
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
+ * <code>null</code> if none has been set.
+ */
+ public UserDataConstraint getUserDataConstraint()
+ {
+ return userDataConstraint;
+ }
}
// ------------------------------------------------------------------------
--- /dev/null
+/*
+ * $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.
+ *
+ * <pre>
+ * <user-data-constraint>
+ * <description^gt;This is the user data constraint.</description>
+ * <transport-guarantee>
+ * <i><code>NONE</code>
+ * or <code>INTEGRAL</code>
+ * or <code>CONFIDENTIAL</code></i>
+ * </transport-guarantee^gt;
+ * >/user-data-constraint>
+ * </pre>
+ *
+ * @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 <code>NONE</code>,
+ * <code>INTEGRAL</code>, and <code>CONFIDENTIAL</code>.
+ *
+ * @throws IllegalArgumentException If <code>guarantee</code> is neither
+ * <code>NONE</code> nor <code>INTEGRAL</code>
+ * nor <code>CONFIDENTIAL</code>.
+ *
+ * @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
/*
- * $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
* @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";
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.
*
// 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) {
*/
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
* @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();
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. //
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
--- /dev/null
+/*
+ * $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 =
+ "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"
+ + "\n"
+ + "<!DOCTYPE securityfilter-config PUBLIC\n"
+ + " \""
+ + "-//SecurityFilter.org//DTD Security Filter Configuration 2.0//EN"
+ + "\"\n"
+ + " \""
+ + "http://www.securityfilter.org/dtd/securityfilter-config_2_0.dtd"
+ + "\">"
+
+ + "<securityfilter-config>"
+ + "\n"
+ + " <security-constraint>"
+ + " <web-resource-collection>"
+ + " <web-resource-name>Secure Page</web-resource-name>"
+ + " <url-pattern>/securePage.jsp</url-pattern>"
+ + " </web-resource-collection>"
+ + " <auth-constraint>"
+ + " <role-name>inthisrole</role-name>"
+ + " </auth-constraint>"
+ + " </security-constraint>"
+ + "\n"
+ + " <login-config>"
+ + " <auth-method>BASIC</auth-method>"
+ + " </login-config>"
+ + "\n"
+ + " <realm className=\"org.securityfilter.realm.catalina.CatalinaRealmAdapter\">"
+ + " </realm>"
+ + "\n"
+ + "</securityfilter-config>"
+ ;
+
+ 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 =
+ "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"
+ + "\n"
+ + "<!DOCTYPE securityfilter-config PUBLIC\n"
+ + " \""
+ + "-//SecurityFilter.org//DTD Security Filter Configuration 2.0//EN"
+ + "\"\n"
+ + " \""
+ + "http://www.securityfilter.org/dtd/securityfilter-config_2_0.dtd"
+ + "\">"
+
+ + "<securityfilter-config>"
+ + "\n"
+ + " <security-constraint>"
+ + " <web-resource-collection>"
+ + " <web-resource-name>Secure Page</web-resource-name>"
+ + " <url-pattern>/securePage.jsp</url-pattern>"
+ + " </web-resource-collection>"
+ + " <auth-constraint>"
+ + " <role-name>inthisrole</role-name>"
+ + " </auth-constraint>"
+ + " <user-data-constraint>"
+ + " <description>The user data constraint</description>"
+ + " <transport-guarantee>NONE</transport-guarantee>"
+ + " </user-data-constraint>"
+ + " </security-constraint>"
+ + "\n"
+ + " <login-config>"
+ + " <auth-method>BASIC</auth-method>"
+ + " </login-config>"
+ + "\n"
+ + " <realm className=\"org.securityfilter.realm.catalina.CatalinaRealmAdapter\">"
+ + " </realm>"
+ + "\n"
+ + "</securityfilter-config>"
+ ;
+
+ 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 =
+ "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"
+ + "\n"
+ + "<!DOCTYPE securityfilter-config PUBLIC\n"
+ + " \""
+ + "-//SecurityFilter.org//DTD Security Filter Configuration 2.0//EN"
+ + "\"\n"
+ + " \""
+ + "http://www.securityfilter.org/dtd/securityfilter-config_2_0.dtd"
+ + "\">"
+
+ + "<securityfilter-config>"
+ + "\n"
+ + " <security-constraint>"
+ + " <web-resource-collection>"
+ + " <web-resource-name>Secure Page</web-resource-name>"
+ + " <url-pattern>/securePage.jsp</url-pattern>"
+ + " </web-resource-collection>"
+ + " <auth-constraint>"
+ + " <role-name>inthisrole</role-name>"
+ + " </auth-constraint>"
+ + " <user-data-constraint>"
+ + " <description>The user data constraint</description>"
+ + " <transport-guarantee> NONE"
+ + " </transport-guarantee>"
+ + " </user-data-constraint>"
+ + " </security-constraint>"
+ + "\n"
+ + " <login-config>"
+ + " <auth-method>BASIC</auth-method>"
+ + " </login-config>"
+ + "\n"
+ + " <realm className=\"org.securityfilter.realm.catalina.CatalinaRealmAdapter\">"
+ + " </realm>"
+ + "\n"
+ + "</securityfilter-config>"
+ ;
+
+ 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 =
+ "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"
+ + "\n"
+ + "<!DOCTYPE securityfilter-config PUBLIC\n"
+ + " \""
+ + "-//SecurityFilter.org//DTD Security Filter Configuration 2.0//EN"
+ + "\"\n"
+ + " \""
+ + "http://www.securityfilter.org/dtd/securityfilter-config_2_0.dtd"
+ + "\">"
+
+ + "<securityfilter-config>"
+ + "\n"
+ + " <security-constraint>"
+ + " <web-resource-collection>"
+ + " <web-resource-name>Secure Page</web-resource-name>"
+ + " <url-pattern>/securePage.jsp</url-pattern>"
+ + " </web-resource-collection>"
+ + " <auth-constraint>"
+ + " <role-name>inthisrole</role-name>"
+ + " </auth-constraint>"
+ + " <user-data-constraint>"
+ + " <description>The user data constraint</description>"
+ + " <transport-guarantee>INVALID</transport-guarantee>"
+ + " </user-data-constraint>"
+ + " </security-constraint>"
+ + "\n"
+ + " <login-config>"
+ + " <auth-method>BASIC</auth-method>"
+ + " </login-config>"
+ + "\n"
+ + " <realm className=\"org.securityfilter.realm.catalina.CatalinaRealmAdapter\">"
+ + " </realm>"
+ + "\n"
+ + "</securityfilter-config>"
+ ;
+
+ 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));
+ }
+}
--- /dev/null
+/*
+ * $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);
+ }
+}
</auth-constraint>
</security-constraint>
+ <!-- Configuration for transport-guarantee tests -->
+ <security-constraint>
+ <web-resource-collection>
+ <web-resource-name>Regular Page</web-resource-name>
+ <url-pattern>/regularPage.jsp</url-pattern>
+ </web-resource-collection>
+ <user-data-constraint>
+ <description>No transport guarantee</description>
+ <transport-guarantee>NONE</transport-guarantee>
+ </user-data-constraint>
+ </security-constraint>
+
+ <security-constraint>
+ <web-resource-collection>
+ <web-resource-name>Integral</web-resource-name>
+ <url-pattern>/integral.jsp</url-pattern>
+ </web-resource-collection>
+ <user-data-constraint>
+ <description>INTEGRAL transport guarantee</description>
+ <transport-guarantee>INTEGRAL</transport-guarantee>
+ </user-data-constraint>
+ </security-constraint>
+
+ <security-constraint>
+ <web-resource-collection>
+ <web-resource-name>Confidential</web-resource-name>
+ <url-pattern>/confidential.html</url-pattern>
+ </web-resource-collection>
+ <user-data-constraint>
+ <description>CONFIDENTIAL transport guarantee</description>
+ <transport-guarantee>CONFIDENTIAL</transport-guarantee>
+ </user-data-constraint>
+ </security-constraint>
+
<login-config>
<auth-method>FORM</auth-method>
<form-login-config>
<realm-param name="exampleProperty" value="it works!" />
</realm>
-</securityfilter-config>
\ No newline at end of file
+</securityfilter-config>