diff --git a/changelog.txt b/changelog.txt index 3a7448d617..634de7cf23 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,4 +1,4 @@ -Changes in version 0.5 (2004-xx-xx) +Changes in version 0.5 (2004-04-28) ----------------------------------- * Added single sign on support via Yale Central Authentication Service (CAS) @@ -13,7 +13,9 @@ Changes in version 0.5 (2004-xx-xx) * Added definable prefixes to avoid expectation of "ROLE_" GrantedAuthoritys * Added pluggable AuthenticationEntryPoints to SecurityEnforcementFilter * Added Apache Ant path syntax support to SecurityEnforcementFilter +* Added filter to automate entry into secure channels, such as HTTPS * Updated JAR to Spring 1.0.1 +* Updated several classes to use absolute (not relative) redirection URLs * Refactored filters to use Spring application context lifecycle support * Improved constructor detection of nulls in User and other key objects * Fixed FilterInvocation.getRequestUrl() to also include getPathInfo() diff --git a/core/src/main/java/org/acegisecurity/securechannel/ChannelDecisionManager.java b/core/src/main/java/org/acegisecurity/securechannel/ChannelDecisionManager.java index 2b01df8f68..6547af3193 100644 --- a/core/src/main/java/org/acegisecurity/securechannel/ChannelDecisionManager.java +++ b/core/src/main/java/org/acegisecurity/securechannel/ChannelDecisionManager.java @@ -29,10 +29,11 @@ public interface ChannelDecisionManager { //~ Methods ================================================================ /** - * Decided whether the presented {@link FilterInvocation} provides - * sufficient security based on the requested {@link + * Decided whether the presented {@link FilterInvocation} provides the + * appropriate level of channel security based on the requested {@link * ConfigAttributeDefinition}. */ public void decide(FilterInvocation invocation, - ConfigAttributeDefinition config) throws SecureChannelRequiredException; + ConfigAttributeDefinition config) + throws InsecureChannelRequiredException, SecureChannelRequiredException; } diff --git a/core/src/main/java/org/acegisecurity/securechannel/ChannelDecisionManagerImpl.java b/core/src/main/java/org/acegisecurity/securechannel/ChannelDecisionManagerImpl.java index 749ddcc50c..a2a93d0dce 100644 --- a/core/src/main/java/org/acegisecurity/securechannel/ChannelDecisionManagerImpl.java +++ b/core/src/main/java/org/acegisecurity/securechannel/ChannelDecisionManagerImpl.java @@ -26,14 +26,31 @@ import java.util.Iterator; /** *
- * Requires a secure channel for a web request if a {@link
- * ConfigAttribute#getAttribute()} keyword is detected.
+ * Ensures configuration attribute requested channel security is present by
+ * review of HttpServletRequest.isSecure() responses.
*
- * The default keyword string is REQUIRES_SECURE_CHANNEL, but this
- * may be overriden to any value. The ConfigAttribute must
- * exactly match the case of the keyword string.
+ * The class responds to two and only two case-sensitive keywords: {@link
+ * #getInsecureKeyword()} and {@link #getSecureKeyword}. If either of these
+ * keywords are detected, HttpServletRequest.isSecure() is used
+ * to determine the channel security offered. If the channel security differs
+ * from that requested by the keyword, the relevant exception is thrown.
+ *
+ * If both the secureKeyword and insecureKeyword
+ * configuration attributes are detected, the request will be deemed to be
+ * requesting a secure channel. This is a reasonable approach, as when in
+ * doubt, the decision manager assumes the most secure outcome is desired. Of
+ * course, you should indicate one configuration attribute or the other
+ * (not both).
+ *
+ * The default secureKeyword and insecureKeyword is
+ * REQUIRES_SECURE_CHANNEL and
+ * REQUIRES_INSECURE_CHANNEL respectively.
*
+ * Depending on the implementation, a secure or insecure channel will be + * launched. + *
* * @author Ben Alex * @version $Id$ @@ -37,12 +42,14 @@ public interface ChannelEntryPoint { *
* Implementations should modify the headers on the
* ServletResponse as necessary to commence the user agent
- * using the secure channel.
+ * using the implementation's supported channel type (ie secure or
+ * insecure).
*
SecureChannelRequiredException
- * @param response so that the user agent can begin using a secure channel
+ * SecureChannelRequiredException or
+ * InsecureChannelRequiredException
+ * @param response so that the user agent can begin using a new channel
*/
public void commence(ServletRequest request, ServletResponse response)
throws IOException, ServletException;
diff --git a/core/src/main/java/org/acegisecurity/securechannel/ChannelProcessingFilter.java b/core/src/main/java/org/acegisecurity/securechannel/ChannelProcessingFilter.java
index 3e33b9e80f..8efef64f4c 100644
--- a/core/src/main/java/org/acegisecurity/securechannel/ChannelProcessingFilter.java
+++ b/core/src/main/java/org/acegisecurity/securechannel/ChannelProcessingFilter.java
@@ -37,7 +37,7 @@ import javax.servlet.http.HttpServletResponse;
/**
- * Ensures a request is delivered over a secure channel.
+ * Ensures a web request is delivered over the required channel.
*
*
* Internally uses a {@link FilterInvocation} to represent the request, so that
@@ -62,7 +62,8 @@ public class ChannelProcessingFilter implements InitializingBean, Filter {
//~ Instance fields ========================================================
private ChannelDecisionManager channelDecisionManager;
- private ChannelEntryPoint channelEntryPoint;
+ private ChannelEntryPoint insecureChannelEntryPoint;
+ private ChannelEntryPoint secureChannelEntryPoint;
private FilterInvocationDefinitionSource filterInvocationDefinitionSource;
//~ Methods ================================================================
@@ -76,14 +77,6 @@ public class ChannelProcessingFilter implements InitializingBean, Filter {
return channelDecisionManager;
}
- public void setChannelEntryPoint(ChannelEntryPoint channelEntryPoint) {
- this.channelEntryPoint = channelEntryPoint;
- }
-
- public ChannelEntryPoint getChannelEntryPoint() {
- return channelEntryPoint;
- }
-
public void setFilterInvocationDefinitionSource(
FilterInvocationDefinitionSource filterInvocationDefinitionSource) {
this.filterInvocationDefinitionSource = filterInvocationDefinitionSource;
@@ -93,6 +86,23 @@ public class ChannelProcessingFilter implements InitializingBean, Filter {
return filterInvocationDefinitionSource;
}
+ public void setInsecureChannelEntryPoint(
+ ChannelEntryPoint insecureChannelEntryPoint) {
+ this.insecureChannelEntryPoint = insecureChannelEntryPoint;
+ }
+
+ public ChannelEntryPoint getInsecureChannelEntryPoint() {
+ return insecureChannelEntryPoint;
+ }
+
+ public void setSecureChannelEntryPoint(ChannelEntryPoint channelEntryPoint) {
+ this.secureChannelEntryPoint = channelEntryPoint;
+ }
+
+ public ChannelEntryPoint getSecureChannelEntryPoint() {
+ return secureChannelEntryPoint;
+ }
+
public void afterPropertiesSet() throws Exception {
if (filterInvocationDefinitionSource == null) {
throw new IllegalArgumentException(
@@ -104,9 +114,14 @@ public class ChannelProcessingFilter implements InitializingBean, Filter {
"channelDecisionManager must be specified");
}
- if (channelEntryPoint == null) {
+ if (secureChannelEntryPoint == null) {
throw new IllegalArgumentException(
- "channelEntryPoint must be specified");
+ "secureChannelEntryPoint must be specified");
+ }
+
+ if (insecureChannelEntryPoint == null) {
+ throw new IllegalArgumentException(
+ "insecureChannelEntryPoint must be specified");
}
}
@@ -128,20 +143,32 @@ public class ChannelProcessingFilter implements InitializingBean, Filter {
if (attr != null) {
if (logger.isDebugEnabled()) {
- logger.debug("Request : " + request.toString()
+ logger.debug("Request: " + fi.getFullRequestUrl()
+ "; ConfigAttributes: " + attr.toString());
}
try {
channelDecisionManager.decide(fi, attr);
- } catch (SecureChannelRequiredException channelException) {
+ } catch (SecureChannelRequiredException secureException) {
if (logger.isDebugEnabled()) {
- logger.debug("Channel insufficient ("
- + channelException.getMessage()
- + "); delegating to channelEntryPoint");
+ logger.debug("Channel insufficient security ("
+ + secureException.getMessage()
+ + "); delegating to secureChannelEntryPoint");
}
- channelEntryPoint.commence(request, response);
+ secureChannelEntryPoint.commence(request, response);
+
+ return;
+ } catch (InsecureChannelRequiredException insecureException) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Channel too much security ("
+ + insecureException.getMessage()
+ + "); delegating to insecureChannelEntryPoint");
+ }
+
+ insecureChannelEntryPoint.commence(request, response);
+
+ return;
}
}
diff --git a/core/src/main/java/org/acegisecurity/securechannel/InsecureChannelRequiredException.java b/core/src/main/java/org/acegisecurity/securechannel/InsecureChannelRequiredException.java
new file mode 100644
index 0000000000..16838d6f49
--- /dev/null
+++ b/core/src/main/java/org/acegisecurity/securechannel/InsecureChannelRequiredException.java
@@ -0,0 +1,50 @@
+/* Copyright 2004 Acegi Technology Pty Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.sf.acegisecurity.securechannel;
+
+import net.sf.acegisecurity.AccessDeniedException;
+
+
+/**
+ * Thrown if a secure web channel is detected, but is not required.
+ *
+ * @author Ben Alex
+ * @version $Id$
+ */
+public class InsecureChannelRequiredException extends AccessDeniedException {
+ //~ Constructors ===========================================================
+
+ /**
+ * Constructs an InsecureChannelRequiredException with the
+ * specified message.
+ *
+ * @param msg the detail message.
+ */
+ public InsecureChannelRequiredException(String msg) {
+ super(msg);
+ }
+
+ /**
+ * Constructs an InsecureChannelRequiredException with the
+ * specified message and root cause.
+ *
+ * @param msg the detail message.
+ * @param t root cause
+ */
+ public InsecureChannelRequiredException(String msg, Throwable t) {
+ super(msg, t);
+ }
+}
diff --git a/core/src/main/java/org/acegisecurity/securechannel/RetryWithHttpEntryPoint.java b/core/src/main/java/org/acegisecurity/securechannel/RetryWithHttpEntryPoint.java
new file mode 100644
index 0000000000..133aec7b09
--- /dev/null
+++ b/core/src/main/java/org/acegisecurity/securechannel/RetryWithHttpEntryPoint.java
@@ -0,0 +1,120 @@
+/* Copyright 2004 Acegi Technology Pty Limited
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.sf.acegisecurity.securechannel;
+
+import net.sf.acegisecurity.util.PortMapper;
+import net.sf.acegisecurity.util.PortResolver;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.springframework.beans.factory.InitializingBean;
+
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+
+/**
+ * Commences an insecure channel by retrying the original request using HTTP.
+ *
+ *
+ * This entry point should suffice in most circumstances. However, it is not + * intended to properly handle HTTP POSTs or other usage where a standard + * redirect would cause an issue. + *
+ * + * @author Ben Alex + * @version $Id$ + */ +public class RetryWithHttpEntryPoint implements InitializingBean, + ChannelEntryPoint { + //~ Static fields/initializers ============================================= + + private static final Log logger = LogFactory.getLog(RetryWithHttpEntryPoint.class); + + //~ Instance fields ======================================================== + + private PortMapper portMapper; + private PortResolver portResolver; + + //~ Methods ================================================================ + + public void setPortMapper(PortMapper portMapper) { + this.portMapper = portMapper; + } + + public PortMapper getPortMapper() { + return portMapper; + } + + public void setPortResolver(PortResolver portResolver) { + this.portResolver = portResolver; + } + + public PortResolver getPortResolver() { + return portResolver; + } + + public void afterPropertiesSet() throws Exception { + if (portMapper == null) { + throw new IllegalArgumentException("portMapper is required"); + } + + if (portResolver == null) { + throw new IllegalArgumentException("portResolver is required"); + } + } + + public void commence(ServletRequest request, ServletResponse response) + throws IOException, ServletException { + HttpServletRequest req = (HttpServletRequest) request; + + String pathInfo = req.getPathInfo(); + String queryString = req.getQueryString(); + String contextPath = req.getContextPath(); + String destination = req.getServletPath() + + ((pathInfo == null) ? "" : pathInfo) + + ((queryString == null) ? "" : ("?" + queryString)); + + String redirectUrl = contextPath; + + Integer httpsPort = new Integer(portResolver.getServerPort(req)); + Integer httpPort = portMapper.lookupHttpPort(httpsPort); + + if (httpPort != null) { + boolean includePort = true; + + if (httpPort.intValue() == 80) { + includePort = false; + } + + redirectUrl = "http://" + req.getServerName() + + ((includePort) ? (":" + httpPort) : "") + contextPath + + destination; + } + + if (logger.isDebugEnabled()) { + logger.debug("Redirecting to: " + redirectUrl); + } + + ((HttpServletResponse) response).sendRedirect(redirectUrl); + } +} diff --git a/core/src/main/java/org/acegisecurity/securechannel/RetryWithHttpsEntryPoint.java b/core/src/main/java/org/acegisecurity/securechannel/RetryWithHttpsEntryPoint.java index 27c5bb5fa1..f2ff31af28 100644 --- a/core/src/main/java/org/acegisecurity/securechannel/RetryWithHttpsEntryPoint.java +++ b/core/src/main/java/org/acegisecurity/securechannel/RetryWithHttpsEntryPoint.java @@ -15,6 +15,9 @@ package net.sf.acegisecurity.securechannel; +import net.sf.acegisecurity.util.PortMapper; +import net.sf.acegisecurity.util.PortResolver; + import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -22,10 +25,6 @@ import org.springframework.beans.factory.InitializingBean; import java.io.IOException; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; - import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; @@ -53,71 +52,34 @@ public class RetryWithHttpsEntryPoint implements InitializingBean, //~ Instance fields ======================================================== - private Map httpsPortMappings; - - //~ Constructors =========================================================== - - public RetryWithHttpsEntryPoint() { - httpsPortMappings = new HashMap(); - httpsPortMappings.put(new Integer(80), new Integer(443)); - httpsPortMappings.put(new Integer(8080), new Integer(8443)); - } + private PortMapper portMapper; + private PortResolver portResolver; //~ Methods ================================================================ - /** - *- * Set to override the default http port to https port mappings of 80:443, - * and 8080:8443. - *
- * In a Spring XML ApplicationContext, a definition would look something - * like this: - *- * <property name="httpsPortMapping"> - * <map> - * <entry key="80"><value>443</value></entry> - * <entry key="8080"><value>8443</value></entry> - * </map> - * </property> - *- * - * @param newMappings A Map consisting of String keys and String values, - * where for each entry the key is the string representation of an - * integer http port number, and the value is the string - * representation of the corresponding integer https port number. - * - * @throws IllegalArgumentException if input map does not consist of String - * keys and values, each representing an integer port number in - * the range 1-65535 for that mapping. - */ - public void setHttpsPortMappings(HashMap newMappings) { - httpsPortMappings.clear(); + public void setPortMapper(PortMapper portMapper) { + this.portMapper = portMapper; + } - Iterator it = newMappings.entrySet().iterator(); + public PortMapper getPortMapper() { + return portMapper; + } - while (it.hasNext()) { - Map.Entry entry = (Map.Entry) it.next(); - Integer httpPort = new Integer((String) entry.getKey()); - Integer httpsPort = new Integer((String) entry.getValue()); + public void setPortResolver(PortResolver portResolver) { + this.portResolver = portResolver; + } - if ((httpPort.intValue() < 1) || (httpPort.intValue() > 65535) - || (httpsPort.intValue() < 1) || (httpsPort.intValue() > 65535)) { - throw new IllegalArgumentException( - "one or both ports out of legal range: " + httpPort + ", " - + httpsPort); - } - - httpsPortMappings.put(httpPort, httpsPort); - - if (httpsPortMappings.size() < 1) { - throw new IllegalArgumentException("must map at least one port"); - } - } + public PortResolver getPortResolver() { + return portResolver; } public void afterPropertiesSet() throws Exception { - if (httpsPortMappings == null) { - throw new IllegalArgumentException("httpsPortMappings required"); + if (portMapper == null) { + throw new IllegalArgumentException("portMapper is required"); + } + + if (portResolver == null) { + throw new IllegalArgumentException("portResolver is required"); } } @@ -134,25 +96,25 @@ public class RetryWithHttpsEntryPoint implements InitializingBean, String redirectUrl = contextPath; - Integer httpPort = new Integer(req.getServerPort()); - Integer httpsPort = (Integer) httpsPortMappings.get(httpPort); + Integer httpPort = new Integer(portResolver.getServerPort(req)); + Integer httpsPort = portMapper.lookupHttpsPort(httpPort); if (httpsPort != null) { - String serverName = req.getServerName(); - redirectUrl = "https://" + serverName + ":" + httpsPort - + contextPath + destination; + boolean includePort = true; + + if (httpsPort.intValue() == 443) { + includePort = false; + } + + redirectUrl = "https://" + req.getServerName() + + ((includePort) ? (":" + httpsPort) : "") + contextPath + + destination; + } + + if (logger.isDebugEnabled()) { + logger.debug("Redirecting to: " + redirectUrl); } ((HttpServletResponse) response).sendRedirect(redirectUrl); } - - /** - * Returns the translated (Integer -> Integer) version of the original port - * mapping specified via setHttpsPortMapping() - * - * @return DOCUMENT ME! - */ - protected Map getTranslatedHttpsPortMappings() { - return httpsPortMappings; - } } diff --git a/core/src/test/java/org/acegisecurity/securechannel/ChannelDecisionManagerImplTests.java b/core/src/test/java/org/acegisecurity/securechannel/ChannelDecisionManagerImplTests.java new file mode 100644 index 0000000000..96f748ea39 --- /dev/null +++ b/core/src/test/java/org/acegisecurity/securechannel/ChannelDecisionManagerImplTests.java @@ -0,0 +1,182 @@ +/* Copyright 2004 Acegi Technology Pty Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.sf.acegisecurity.securechannel; + +import junit.framework.TestCase; + +import net.sf.acegisecurity.ConfigAttributeDefinition; +import net.sf.acegisecurity.MockFilterChain; +import net.sf.acegisecurity.MockHttpServletRequest; +import net.sf.acegisecurity.MockHttpServletResponse; +import net.sf.acegisecurity.SecurityConfig; +import net.sf.acegisecurity.intercept.web.FilterInvocation; + + +/** + * Tests {@link ChannelDecisionManagerImpl}. + * + * @author Ben Alex + * @version $Id$ + */ +public class ChannelDecisionManagerImplTests extends TestCase { + //~ Methods ================================================================ + + public final void setUp() throws Exception { + super.setUp(); + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(ChannelDecisionManagerImplTests.class); + } + + public void testDetectsInvalidInsecureKeyword() throws Exception { + ChannelDecisionManagerImpl cdm = new ChannelDecisionManagerImpl(); + cdm.setInsecureKeyword(""); + + try { + cdm.afterPropertiesSet(); + fail("Should have thrown IllegalArgumentException"); + } catch (IllegalArgumentException expected) { + assertEquals("insecureKeyword required", expected.getMessage()); + } + + cdm.setInsecureKeyword(null); + + try { + cdm.afterPropertiesSet(); + fail("Should have thrown IllegalArgumentException"); + } catch (IllegalArgumentException expected) { + assertEquals("insecureKeyword required", expected.getMessage()); + } + } + + public void testDetectsInvalidSecureKeyword() throws Exception { + ChannelDecisionManagerImpl cdm = new ChannelDecisionManagerImpl(); + cdm.setSecureKeyword(""); + + try { + cdm.afterPropertiesSet(); + fail("Should have thrown IllegalArgumentException"); + } catch (IllegalArgumentException expected) { + assertEquals("secureKeyword required", expected.getMessage()); + } + + cdm.setSecureKeyword(null); + + try { + cdm.afterPropertiesSet(); + fail("Should have thrown IllegalArgumentException"); + } catch (IllegalArgumentException expected) { + assertEquals("secureKeyword required", expected.getMessage()); + } + } + + public void testDetectsNullsPassedToMainMethod() { + ChannelDecisionManagerImpl cdm = new ChannelDecisionManagerImpl(); + + try { + cdm.decide(null, new ConfigAttributeDefinition()); + fail("Should have thrown IllegalArgumentException"); + } catch (IllegalArgumentException expected) { + assertEquals("Nulls cannot be provided", expected.getMessage()); + } + + try { + cdm.decide(new FilterInvocation(new MockHttpServletRequest("x"), + new MockHttpServletResponse(), new MockFilterChain()), null); + fail("Should have thrown IllegalArgumentException"); + } catch (IllegalArgumentException expected) { + assertEquals("Nulls cannot be provided", expected.getMessage()); + } + } + + public void testDetectsWhenInsecureChannelNeededAndInsecureSchemeUsed() { + ConfigAttributeDefinition attr = new ConfigAttributeDefinition(); + attr.addConfigAttribute(new SecurityConfig( + "SOME_CONFIG_ATTRIBUTE_TO_IGNORE")); + attr.addConfigAttribute(new SecurityConfig("REQUIRES_INSECURE_CHANNEL")); + + MockHttpServletRequest request = new MockHttpServletRequest("foo=bar"); + request.setScheme("http"); + + ChannelDecisionManagerImpl cdm = new ChannelDecisionManagerImpl(); + cdm.decide(new FilterInvocation(request, new MockHttpServletResponse(), + new MockFilterChain()), attr); + assertTrue(true); + } + + public void testDetectsWhenInsecureChannelNeededAndSecureSchemeUsed() { + ConfigAttributeDefinition attr = new ConfigAttributeDefinition(); + attr.addConfigAttribute(new SecurityConfig( + "SOME_CONFIG_ATTRIBUTE_TO_IGNORE")); + attr.addConfigAttribute(new SecurityConfig("REQUIRES_INSECURE_CHANNEL")); + + MockHttpServletRequest request = new MockHttpServletRequest("foo=bar"); + request.setScheme("https"); + + ChannelDecisionManagerImpl cdm = new ChannelDecisionManagerImpl(); + + try { + cdm.decide(new FilterInvocation(request, + new MockHttpServletResponse(), new MockFilterChain()), attr); + } catch (InsecureChannelRequiredException expected) { + assertTrue(true); + } + } + + public void testDetectsWhenSecureChannelNeeded() { + ConfigAttributeDefinition attr = new ConfigAttributeDefinition(); + attr.addConfigAttribute(new SecurityConfig( + "SOME_CONFIG_ATTRIBUTE_TO_IGNORE")); + attr.addConfigAttribute(new SecurityConfig("REQUIRES_SECURE_CHANNEL")); + + MockHttpServletRequest request = new MockHttpServletRequest("foo=bar"); + request.setScheme("http"); + + ChannelDecisionManagerImpl cdm = new ChannelDecisionManagerImpl(); + + try { + cdm.decide(new FilterInvocation(request, + new MockHttpServletResponse(), new MockFilterChain()), attr); + } catch (SecureChannelRequiredException expected) { + assertTrue(true); + } + } + + public void testGetterSetters() throws Exception { + ChannelDecisionManagerImpl cdm = new ChannelDecisionManagerImpl(); + cdm.afterPropertiesSet(); + assertEquals("REQUIRES_INSECURE_CHANNEL", cdm.getInsecureKeyword()); + assertEquals("REQUIRES_SECURE_CHANNEL", cdm.getSecureKeyword()); + + cdm.setInsecureKeyword("MY_INSECURE"); + cdm.setSecureKeyword("MY_SECURE"); + + assertEquals("MY_INSECURE", cdm.getInsecureKeyword()); + assertEquals("MY_SECURE", cdm.getSecureKeyword()); + } + + public void testIgnoresOtherConfigAttributes() { + ConfigAttributeDefinition attr = new ConfigAttributeDefinition(); + attr.addConfigAttribute(new SecurityConfig("XYZ")); + + ChannelDecisionManagerImpl cdm = new ChannelDecisionManagerImpl(); + cdm.decide(new FilterInvocation(new MockHttpServletRequest("x"), + new MockHttpServletResponse(), new MockFilterChain()), attr); + assertTrue(true); + } +} +; diff --git a/core/src/test/java/org/acegisecurity/securechannel/ChannelProcessingFilterTests.java b/core/src/test/java/org/acegisecurity/securechannel/ChannelProcessingFilterTests.java new file mode 100644 index 0000000000..0f962b615d --- /dev/null +++ b/core/src/test/java/org/acegisecurity/securechannel/ChannelProcessingFilterTests.java @@ -0,0 +1,339 @@ +/* Copyright 2004 Acegi Technology Pty Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.sf.acegisecurity.securechannel; + +import junit.framework.TestCase; + +import net.sf.acegisecurity.ConfigAttributeDefinition; +import net.sf.acegisecurity.MockFilterConfig; +import net.sf.acegisecurity.MockHttpServletRequest; +import net.sf.acegisecurity.MockHttpServletResponse; +import net.sf.acegisecurity.SecurityConfig; +import net.sf.acegisecurity.intercept.web.FilterInvocation; +import net.sf.acegisecurity.intercept.web.FilterInvocationDefinitionSource; +import net.sf.acegisecurity.intercept.web.RegExpBasedFilterInvocationDefinitionMap; + +import java.io.IOException; + +import java.util.Iterator; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; + + +/** + * Tests {@link ChannelProcessingFilter}. + * + * @author Ben Alex + * @version $Id$ + */ +public class ChannelProcessingFilterTests extends TestCase { + //~ Methods ================================================================ + + public final void setUp() throws Exception { + super.setUp(); + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(ChannelProcessingFilterTests.class); + } + + public void testCallsInsecureEntryPointWhenTooMuchChannelSecurity() + throws Exception { + ConfigAttributeDefinition attr = new ConfigAttributeDefinition(); + attr.addConfigAttribute(new SecurityConfig("REQUIRES_INSECURE_CHANNEL")); + + MockFilterInvocationDefinitionMap fids = new MockFilterInvocationDefinitionMap("/path", + attr); + + ChannelProcessingFilter filter = new ChannelProcessingFilter(); + filter.setInsecureChannelEntryPoint(new MockEntryPoint(true)); + filter.setSecureChannelEntryPoint(new MockEntryPoint(false)); + filter.setFilterInvocationDefinitionSource(fids); + filter.setChannelDecisionManager(new ChannelDecisionManagerImpl()); + + MockHttpServletRequest request = new MockHttpServletRequest("info=now"); + request.setServletPath("/path"); + request.setScheme("https"); + + MockHttpServletResponse response = new MockHttpServletResponse(); + MockFilterChain chain = new MockFilterChain(false); + + filter.doFilter(request, response, chain); + assertTrue(true); + } + + public void testCallsSecureEntryPointWhenTooLittleChannelSecurity() + throws Exception { + ConfigAttributeDefinition attr = new ConfigAttributeDefinition(); + attr.addConfigAttribute(new SecurityConfig("REQUIRES_SECURE_CHANNEL")); + + MockFilterInvocationDefinitionMap fids = new MockFilterInvocationDefinitionMap("/path", + attr); + + ChannelProcessingFilter filter = new ChannelProcessingFilter(); + filter.setInsecureChannelEntryPoint(new MockEntryPoint(false)); + filter.setSecureChannelEntryPoint(new MockEntryPoint(true)); + filter.setFilterInvocationDefinitionSource(fids); + filter.setChannelDecisionManager(new ChannelDecisionManagerImpl()); + + MockHttpServletRequest request = new MockHttpServletRequest("info=now"); + request.setServletPath("/path"); + request.setScheme("http"); + + MockHttpServletResponse response = new MockHttpServletResponse(); + MockFilterChain chain = new MockFilterChain(false); + + filter.doFilter(request, response, chain); + assertTrue(true); + } + + public void testDetectsMissingChannelDecisionManager() + throws Exception { + ChannelProcessingFilter filter = new ChannelProcessingFilter(); + filter.setSecureChannelEntryPoint(new RetryWithHttpsEntryPoint()); + filter.setFilterInvocationDefinitionSource(new RegExpBasedFilterInvocationDefinitionMap()); + + try { + filter.afterPropertiesSet(); + fail("Should have thrown IllegalArgumentException"); + } catch (IllegalArgumentException expected) { + assertEquals("channelDecisionManager must be specified", + expected.getMessage()); + } + } + + public void testDetectsMissingFilterInvocationDefinitionMap() + throws Exception { + ChannelProcessingFilter filter = new ChannelProcessingFilter(); + filter.setInsecureChannelEntryPoint(new RetryWithHttpEntryPoint()); + filter.setSecureChannelEntryPoint(new RetryWithHttpsEntryPoint()); + filter.setChannelDecisionManager(new ChannelDecisionManagerImpl()); + + try { + filter.afterPropertiesSet(); + fail("Should have thrown IllegalArgumentException"); + } catch (IllegalArgumentException expected) { + assertEquals("filterInvocationDefinitionSource must be specified", + expected.getMessage()); + } + } + + public void testDetectsMissingInsecureChannelEntryPoint() + throws Exception { + ChannelProcessingFilter filter = new ChannelProcessingFilter(); + filter.setSecureChannelEntryPoint(new RetryWithHttpsEntryPoint()); + filter.setFilterInvocationDefinitionSource(new RegExpBasedFilterInvocationDefinitionMap()); + filter.setChannelDecisionManager(new ChannelDecisionManagerImpl()); + + try { + filter.afterPropertiesSet(); + fail("Should have thrown IllegalArgumentException"); + } catch (IllegalArgumentException expected) { + assertEquals("insecureChannelEntryPoint must be specified", + expected.getMessage()); + } + } + + public void testDetectsMissingSecureChannelEntryPoint() + throws Exception { + ChannelProcessingFilter filter = new ChannelProcessingFilter(); + filter.setInsecureChannelEntryPoint(new RetryWithHttpEntryPoint()); + filter.setFilterInvocationDefinitionSource(new RegExpBasedFilterInvocationDefinitionMap()); + filter.setChannelDecisionManager(new ChannelDecisionManagerImpl()); + + try { + filter.afterPropertiesSet(); + fail("Should have thrown IllegalArgumentException"); + } catch (IllegalArgumentException expected) { + assertEquals("secureChannelEntryPoint must be specified", + expected.getMessage()); + } + } + + public void testDoFilterWithNonHttpServletRequestDetected() + throws Exception { + ChannelProcessingFilter filter = new ChannelProcessingFilter(); + + try { + filter.doFilter(null, new MockHttpServletResponse(), + new MockFilterChain()); + fail("Should have thrown ServletException"); + } catch (ServletException expected) { + assertEquals("HttpServletRequest required", expected.getMessage()); + } + } + + public void testDoFilterWithNonHttpServletResponseDetected() + throws Exception { + ChannelProcessingFilter filter = new ChannelProcessingFilter(); + + try { + filter.doFilter(new MockHttpServletRequest(null, null), null, + new MockFilterChain()); + fail("Should have thrown ServletException"); + } catch (ServletException expected) { + assertEquals("HttpServletResponse required", expected.getMessage()); + } + } + + public void testDoesNotInterruptRequestsWithCorrectChannelSecurity() + throws Exception { + ConfigAttributeDefinition attr = new ConfigAttributeDefinition(); + attr.addConfigAttribute(new SecurityConfig("REQUIRES_SECURE_CHANNEL")); + + MockFilterInvocationDefinitionMap fids = new MockFilterInvocationDefinitionMap("/path", + attr); + + ChannelProcessingFilter filter = new ChannelProcessingFilter(); + filter.setInsecureChannelEntryPoint(new RetryWithHttpEntryPoint()); + filter.setSecureChannelEntryPoint(new RetryWithHttpsEntryPoint()); + filter.setFilterInvocationDefinitionSource(fids); + filter.setChannelDecisionManager(new ChannelDecisionManagerImpl()); + + MockHttpServletRequest request = new MockHttpServletRequest("info=now"); + request.setServletPath("/path"); + request.setScheme("https"); + + MockHttpServletResponse response = new MockHttpServletResponse(); + MockFilterChain chain = new MockFilterChain(true); + + filter.doFilter(request, response, chain); + assertTrue(true); + } + + public void testDoesNotInterruptRequestsWithNoConfigAttribute() + throws Exception { + ChannelProcessingFilter filter = new ChannelProcessingFilter(); + filter.setInsecureChannelEntryPoint(new RetryWithHttpEntryPoint()); + filter.setSecureChannelEntryPoint(new RetryWithHttpsEntryPoint()); + filter.setFilterInvocationDefinitionSource(new RegExpBasedFilterInvocationDefinitionMap()); + filter.setChannelDecisionManager(new ChannelDecisionManagerImpl()); + + MockHttpServletRequest request = new MockHttpServletRequest("info=now"); + MockHttpServletResponse response = new MockHttpServletResponse(); + MockFilterChain chain = new MockFilterChain(true); + + filter.doFilter(request, response, chain); + assertTrue(true); + } + + public void testGetterSetters() { + ChannelProcessingFilter filter = new ChannelProcessingFilter(); + filter.setInsecureChannelEntryPoint(new RetryWithHttpEntryPoint()); + filter.setSecureChannelEntryPoint(new RetryWithHttpsEntryPoint()); + filter.setFilterInvocationDefinitionSource(new RegExpBasedFilterInvocationDefinitionMap()); + filter.setChannelDecisionManager(new ChannelDecisionManagerImpl()); + + assertTrue(filter.getInsecureChannelEntryPoint() != null); + assertTrue(filter.getSecureChannelEntryPoint() != null); + assertTrue(filter.getFilterInvocationDefinitionSource() != null); + assertTrue(filter.getChannelDecisionManager() != null); + } + + public void testLifecycle() throws Exception { + ChannelProcessingFilter filter = new ChannelProcessingFilter(); + filter.setInsecureChannelEntryPoint(new RetryWithHttpEntryPoint()); + filter.setSecureChannelEntryPoint(new RetryWithHttpsEntryPoint()); + filter.setFilterInvocationDefinitionSource(new RegExpBasedFilterInvocationDefinitionMap()); + filter.setChannelDecisionManager(new ChannelDecisionManagerImpl()); + filter.afterPropertiesSet(); + + filter.init(new MockFilterConfig()); + filter.destroy(); + } + + //~ Inner Classes ========================================================== + + private class MockEntryPoint implements ChannelEntryPoint { + private boolean expectToBeCalled; + + public MockEntryPoint(boolean expectToBeCalled) { + this.expectToBeCalled = expectToBeCalled; + } + + private MockEntryPoint() { + super(); + } + + public void commence(ServletRequest request, ServletResponse response) + throws IOException, ServletException { + if (expectToBeCalled) { + assertTrue(true); + } else { + fail("Did not expect this ChannelEntryPoint to be called"); + } + } + } + + private class MockFilterChain implements FilterChain { + private boolean expectToProceed; + + public MockFilterChain(boolean expectToProceed) { + this.expectToProceed = expectToProceed; + } + + private MockFilterChain() { + super(); + } + + public void doFilter(ServletRequest request, ServletResponse response) + throws IOException, ServletException { + if (expectToProceed) { + assertTrue(true); + } else { + fail("Did not expect filter chain to proceed"); + } + } + } + + private class MockFilterInvocationDefinitionMap + implements FilterInvocationDefinitionSource { + private ConfigAttributeDefinition toReturn; + private String servletPath; + + public MockFilterInvocationDefinitionMap(String servletPath, + ConfigAttributeDefinition toReturn) { + this.servletPath = servletPath; + this.toReturn = toReturn; + } + + private MockFilterInvocationDefinitionMap() { + super(); + } + + public ConfigAttributeDefinition getAttributes(Object object) + throws IllegalArgumentException { + FilterInvocation fi = (FilterInvocation) object; + + if (servletPath.equals(fi.getHttpRequest().getServletPath())) { + return toReturn; + } else { + return null; + } + } + + public Iterator getConfigAttributeDefinitions() { + return null; + } + + public boolean supports(Class clazz) { + return true; + } + } +} diff --git a/core/src/test/java/org/acegisecurity/securechannel/RetryWithHttpEntryPointTests.java b/core/src/test/java/org/acegisecurity/securechannel/RetryWithHttpEntryPointTests.java new file mode 100644 index 0000000000..b0bf002fe9 --- /dev/null +++ b/core/src/test/java/org/acegisecurity/securechannel/RetryWithHttpEntryPointTests.java @@ -0,0 +1,171 @@ +/* Copyright 2004 Acegi Technology Pty Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.sf.acegisecurity.securechannel; + +import junit.framework.TestCase; + +import net.sf.acegisecurity.MockHttpServletRequest; +import net.sf.acegisecurity.MockHttpServletResponse; +import net.sf.acegisecurity.MockPortResolver; +import net.sf.acegisecurity.util.PortMapperImpl; + +import java.util.HashMap; +import java.util.Map; + + +/** + * Tests {@link RetryWithHttpEntryPoint}. + * + * @author Ben Alex + * @version $Id$ + */ +public class RetryWithHttpEntryPointTests extends TestCase { + //~ Methods ================================================================ + + public final void setUp() throws Exception { + super.setUp(); + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(RetryWithHttpEntryPointTests.class); + } + + public void testDetectsMissingPortMapper() throws Exception { + RetryWithHttpEntryPoint ep = new RetryWithHttpEntryPoint(); + ep.setPortResolver(new MockPortResolver(80, 443)); + + try { + ep.afterPropertiesSet(); + fail("Should have thrown IllegalArgumentException"); + } catch (IllegalArgumentException expected) { + assertEquals("portMapper is required", expected.getMessage()); + } + } + + public void testDetectsMissingPortResolver() throws Exception { + RetryWithHttpEntryPoint ep = new RetryWithHttpEntryPoint(); + ep.setPortMapper(new PortMapperImpl()); + + try { + ep.afterPropertiesSet(); + fail("Should have thrown IllegalArgumentException"); + } catch (IllegalArgumentException expected) { + assertEquals("portResolver is required", expected.getMessage()); + } + } + + public void testGettersSetters() { + RetryWithHttpEntryPoint ep = new RetryWithHttpEntryPoint(); + ep.setPortMapper(new PortMapperImpl()); + ep.setPortResolver(new MockPortResolver(8080, 8443)); + assertTrue(ep.getPortMapper() != null); + assertTrue(ep.getPortResolver() != null); + } + + public void testNormalOperation() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest("open=true"); + request.setScheme("https"); + request.setServerName("www.example.com"); + request.setContextPath("/bigWebApp"); + request.setServletPath("/hello"); + request.setPathInfo("/pathInfo.html"); + request.setServerPort(443); + + MockHttpServletResponse response = new MockHttpServletResponse(); + + RetryWithHttpEntryPoint ep = new RetryWithHttpEntryPoint(); + ep.setPortMapper(new PortMapperImpl()); + ep.setPortResolver(new MockPortResolver(80, 443)); + ep.afterPropertiesSet(); + + ep.commence(request, response); + System.out.println(response.getRedirect()); + assertEquals("http://www.example.com/bigWebApp/hello/pathInfo.html?open=true", + response.getRedirect()); + } + + public void testNormalOperationWithNullPathInfoAndNullQueryString() + throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(null); + request.setScheme("https"); + request.setServerName("www.example.com"); + request.setContextPath("/bigWebApp"); + request.setServletPath("/hello"); + request.setPathInfo(null); + request.setServerPort(443); + + MockHttpServletResponse response = new MockHttpServletResponse(); + + RetryWithHttpEntryPoint ep = new RetryWithHttpEntryPoint(); + ep.setPortMapper(new PortMapperImpl()); + ep.setPortResolver(new MockPortResolver(80, 443)); + ep.afterPropertiesSet(); + + ep.commence(request, response); + System.out.println(response.getRedirect()); + assertEquals("http://www.example.com/bigWebApp/hello", + response.getRedirect()); + } + + public void testOperationWhenTargetPortIsUnknown() + throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest("open=true"); + request.setScheme("https"); + request.setServerName("www.example.com"); + request.setContextPath("/bigWebApp"); + request.setServletPath("/hello"); + request.setPathInfo("/pathInfo.html"); + request.setServerPort(8768); + + MockHttpServletResponse response = new MockHttpServletResponse(); + + RetryWithHttpEntryPoint ep = new RetryWithHttpEntryPoint(); + ep.setPortMapper(new PortMapperImpl()); + ep.setPortResolver(new MockPortResolver(8768, 1234)); + ep.afterPropertiesSet(); + + ep.commence(request, response); + System.out.println(response.getRedirect()); + assertEquals("/bigWebApp", response.getRedirect()); + } + + public void testOperationWithNonStandardPort() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest("open=true"); + request.setScheme("https"); + request.setServerName("www.example.com"); + request.setContextPath("/bigWebApp"); + request.setServletPath("/hello"); + request.setPathInfo("/pathInfo.html"); + request.setServerPort(9999); + + MockHttpServletResponse response = new MockHttpServletResponse(); + + PortMapperImpl portMapper = new PortMapperImpl(); + Map map = new HashMap(); + map.put("8888", "9999"); + portMapper.setPortMappings(map); + + RetryWithHttpEntryPoint ep = new RetryWithHttpEntryPoint(); + ep.setPortResolver(new MockPortResolver(8888, 9999)); + ep.setPortMapper(portMapper); + ep.afterPropertiesSet(); + + ep.commence(request, response); + System.out.println(response.getRedirect()); + assertEquals("http://www.example.com:8888/bigWebApp/hello/pathInfo.html?open=true", + response.getRedirect()); + } +} diff --git a/core/src/test/java/org/acegisecurity/securechannel/RetryWithHttpsEntryPointTests.java b/core/src/test/java/org/acegisecurity/securechannel/RetryWithHttpsEntryPointTests.java new file mode 100644 index 0000000000..85048908a7 --- /dev/null +++ b/core/src/test/java/org/acegisecurity/securechannel/RetryWithHttpsEntryPointTests.java @@ -0,0 +1,171 @@ +/* Copyright 2004 Acegi Technology Pty Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.sf.acegisecurity.securechannel; + +import junit.framework.TestCase; + +import net.sf.acegisecurity.MockHttpServletRequest; +import net.sf.acegisecurity.MockHttpServletResponse; +import net.sf.acegisecurity.MockPortResolver; +import net.sf.acegisecurity.util.PortMapperImpl; + +import java.util.HashMap; +import java.util.Map; + + +/** + * Tests {@link RetryWithHttpsEntryPoint}. + * + * @author Ben Alex + * @version $Id$ + */ +public class RetryWithHttpsEntryPointTests extends TestCase { + //~ Methods ================================================================ + + public final void setUp() throws Exception { + super.setUp(); + } + + public static void main(String[] args) { + junit.textui.TestRunner.run(RetryWithHttpsEntryPointTests.class); + } + + public void testDetectsMissingPortMapper() throws Exception { + RetryWithHttpsEntryPoint ep = new RetryWithHttpsEntryPoint(); + ep.setPortResolver(new MockPortResolver(80, 443)); + + try { + ep.afterPropertiesSet(); + fail("Should have thrown IllegalArgumentException"); + } catch (IllegalArgumentException expected) { + assertEquals("portMapper is required", expected.getMessage()); + } + } + + public void testDetectsMissingPortResolver() throws Exception { + RetryWithHttpsEntryPoint ep = new RetryWithHttpsEntryPoint(); + ep.setPortMapper(new PortMapperImpl()); + + try { + ep.afterPropertiesSet(); + fail("Should have thrown IllegalArgumentException"); + } catch (IllegalArgumentException expected) { + assertEquals("portResolver is required", expected.getMessage()); + } + } + + public void testGettersSetters() { + RetryWithHttpsEntryPoint ep = new RetryWithHttpsEntryPoint(); + ep.setPortMapper(new PortMapperImpl()); + ep.setPortResolver(new MockPortResolver(8080, 8443)); + assertTrue(ep.getPortMapper() != null); + assertTrue(ep.getPortResolver() != null); + } + + public void testNormalOperation() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest("open=true"); + request.setScheme("http"); + request.setServerName("www.example.com"); + request.setContextPath("/bigWebApp"); + request.setServletPath("/hello"); + request.setPathInfo("/pathInfo.html"); + request.setServerPort(80); + + MockHttpServletResponse response = new MockHttpServletResponse(); + + RetryWithHttpsEntryPoint ep = new RetryWithHttpsEntryPoint(); + ep.setPortMapper(new PortMapperImpl()); + ep.setPortResolver(new MockPortResolver(80, 443)); + ep.afterPropertiesSet(); + + ep.commence(request, response); + System.out.println(response.getRedirect()); + assertEquals("https://www.example.com/bigWebApp/hello/pathInfo.html?open=true", + response.getRedirect()); + } + + public void testNormalOperationWithNullPathInfoAndNullQueryString() + throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest(null); + request.setScheme("http"); + request.setServerName("www.example.com"); + request.setContextPath("/bigWebApp"); + request.setServletPath("/hello"); + request.setPathInfo(null); + request.setServerPort(80); + + MockHttpServletResponse response = new MockHttpServletResponse(); + + RetryWithHttpsEntryPoint ep = new RetryWithHttpsEntryPoint(); + ep.setPortMapper(new PortMapperImpl()); + ep.setPortResolver(new MockPortResolver(80, 443)); + ep.afterPropertiesSet(); + + ep.commence(request, response); + System.out.println(response.getRedirect()); + assertEquals("https://www.example.com/bigWebApp/hello", + response.getRedirect()); + } + + public void testOperationWhenTargetPortIsUnknown() + throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest("open=true"); + request.setScheme("http"); + request.setServerName("www.example.com"); + request.setContextPath("/bigWebApp"); + request.setServletPath("/hello"); + request.setPathInfo("/pathInfo.html"); + request.setServerPort(8768); + + MockHttpServletResponse response = new MockHttpServletResponse(); + + RetryWithHttpsEntryPoint ep = new RetryWithHttpsEntryPoint(); + ep.setPortMapper(new PortMapperImpl()); + ep.setPortResolver(new MockPortResolver(8768, 1234)); + ep.afterPropertiesSet(); + + ep.commence(request, response); + System.out.println(response.getRedirect()); + assertEquals("/bigWebApp", response.getRedirect()); + } + + public void testOperationWithNonStandardPort() throws Exception { + MockHttpServletRequest request = new MockHttpServletRequest("open=true"); + request.setScheme("http"); + request.setServerName("www.example.com"); + request.setContextPath("/bigWebApp"); + request.setServletPath("/hello"); + request.setPathInfo("/pathInfo.html"); + request.setServerPort(8888); + + MockHttpServletResponse response = new MockHttpServletResponse(); + + PortMapperImpl portMapper = new PortMapperImpl(); + Map map = new HashMap(); + map.put("8888", "9999"); + portMapper.setPortMappings(map); + + RetryWithHttpsEntryPoint ep = new RetryWithHttpsEntryPoint(); + ep.setPortResolver(new MockPortResolver(8888, 9999)); + ep.setPortMapper(portMapper); + ep.afterPropertiesSet(); + + ep.commence(request, response); + System.out.println(response.getRedirect()); + assertEquals("https://www.example.com:9999/bigWebApp/hello/pathInfo.html?open=true", + response.getRedirect()); + } +} diff --git a/docs/reference/src/index.xml b/docs/reference/src/index.xml index 8396b05fbb..3f2590ec33 100644 --- a/docs/reference/src/index.xml +++ b/docs/reference/src/index.xml @@ -519,33 +519,23 @@