diff --git a/core/src/main/java/org/acegisecurity/intercept/web/SecurityEnforcementFilter.java b/core/src/main/java/org/acegisecurity/intercept/web/SecurityEnforcementFilter.java
index 0ed9cef42a..7a6005331e 100644
--- a/core/src/main/java/org/acegisecurity/intercept/web/SecurityEnforcementFilter.java
+++ b/core/src/main/java/org/acegisecurity/intercept/web/SecurityEnforcementFilter.java
@@ -18,6 +18,7 @@ package net.sf.acegisecurity.intercept.web;
import net.sf.acegisecurity.AccessDeniedException;
import net.sf.acegisecurity.AuthenticationException;
import net.sf.acegisecurity.ui.AbstractProcessingFilter;
+import net.sf.acegisecurity.util.PortResolver;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -74,6 +75,10 @@ import javax.servlet.http.HttpServletResponse;
* AuthenticationException
is detected. Note that this may also
* switch the current protocol from http to https for a an SSL login.
*
+ *
+ * portResolver
is used to determine the "real" port that a
+ * request was received on.
+ *
*
*
*
@@ -95,6 +100,7 @@ public class SecurityEnforcementFilter implements Filter, InitializingBean {
private AuthenticationEntryPoint authenticationEntryPoint;
private FilterSecurityInterceptor filterSecurityInterceptor;
+ private PortResolver portResolver;
//~ Methods ================================================================
@@ -116,6 +122,14 @@ public class SecurityEnforcementFilter implements Filter, InitializingBean {
return filterSecurityInterceptor;
}
+ public void setPortResolver(PortResolver portResolver) {
+ this.portResolver = portResolver;
+ }
+
+ public PortResolver getPortResolver() {
+ return portResolver;
+ }
+
public void afterPropertiesSet() throws Exception {
if (authenticationEntryPoint == null) {
throw new IllegalArgumentException(
@@ -126,6 +140,10 @@ public class SecurityEnforcementFilter implements Filter, InitializingBean {
throw new IllegalArgumentException(
"filterSecurityInterceptor must be specified");
}
+
+ if (portResolver == null) {
+ throw new IllegalArgumentException("portResolver must be specified");
+ }
}
public void destroy() {}
@@ -151,14 +169,31 @@ public class SecurityEnforcementFilter implements Filter, InitializingBean {
} catch (AuthenticationException authentication) {
HttpServletRequest httpRequest = (HttpServletRequest) request;
+ int port = portResolver.getServerPort(request);
+ boolean includePort = true;
+
+ if ("http".equals(request.getScheme().toLowerCase())
+ && (port == 80)) {
+ includePort = false;
+ }
+
+ if ("https".equals(request.getScheme().toLowerCase())
+ && (port == 443)) {
+ includePort = false;
+ }
+
+ String targetUrl = request.getScheme() + "://"
+ + request.getServerName() + ((includePort) ? (":" + port) : "")
+ + httpRequest.getContextPath() + fi.getRequestUrl();
+
if (logger.isDebugEnabled()) {
logger.debug(
"Authentication failed - adding target URL to Session: "
- + fi.getFullRequestUrl());
+ + targetUrl);
}
((HttpServletRequest) request).getSession().setAttribute(AbstractProcessingFilter.ACEGI_SECURITY_TARGET_URL_KEY,
- fi.getFullRequestUrl());
+ targetUrl);
authenticationEntryPoint.commence(request, response);
} catch (AccessDeniedException accessDenied) {
if (logger.isDebugEnabled()) {
diff --git a/core/src/main/java/org/acegisecurity/ui/webapp/AuthenticationProcessingFilterEntryPoint.java b/core/src/main/java/org/acegisecurity/ui/webapp/AuthenticationProcessingFilterEntryPoint.java
index 21133b8b76..14dfb791c8 100644
--- a/core/src/main/java/org/acegisecurity/ui/webapp/AuthenticationProcessingFilterEntryPoint.java
+++ b/core/src/main/java/org/acegisecurity/ui/webapp/AuthenticationProcessingFilterEntryPoint.java
@@ -16,15 +16,16 @@
package net.sf.acegisecurity.ui.webapp;
import net.sf.acegisecurity.intercept.web.AuthenticationEntryPoint;
+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 java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
-
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
@@ -43,20 +44,11 @@ import javax.servlet.http.HttpServletResponse;
*
* By setting the forceHttps property to true, you may configure the
* class to force the protocol used for the login form to be
- * https
, even if the original intercepted request for a resource
- * used the http
protocol. When this happens, after a successful
- * login (via https), the original resource will still be accessed as http,
- * via the original request URL. For the forced https feature to work, the
- * class must have a valid mapping from an http port in the original request
- * to an https port for the login page (the same server name will be used,
- * only the scheme and port will be changed). By default, http requests to
- * port 80 will be mapped to login page https requests on port 443 (standard
- * https port), and port 8080 will be mapped to port 8443. These mappings may
- * be customized by setting the httpsPortMappings property. Any
- * intercepted http request on a port which does not have a mapping will
- * result in the protocol remaining as http. Any intercepted request which is
- * already https will always result in the login page being accessed as https,
- * regardless of the state of the forceHttps property.
+ * HTTPS
, even if the original intercepted request for a resource
+ * used the HTTP
protocol. When this happens, after a successful
+ * login (via HTTPS), the original resource will still be accessed as HTTP,
+ * via the original request URL. For the forced HTTPS feature to work, the
+ * {@link PortMapper} is consulted to determine the HTTP:HTTPS pairs.
*
*
* @author Ben Alex
@@ -65,20 +57,17 @@ import javax.servlet.http.HttpServletResponse;
*/
public class AuthenticationProcessingFilterEntryPoint
implements AuthenticationEntryPoint, InitializingBean {
+ //~ Static fields/initializers =============================================
+
+ private static final Log logger = LogFactory.getLog(AuthenticationProcessingFilterEntryPoint.class);
+
//~ Instance fields ========================================================
- private HashMap httpsPortMappings;
+ private PortMapper portMapper;
+ private PortResolver portResolver;
private String loginFormUrl;
private boolean forceHttps = false;
- //~ Constructors ===========================================================
-
- public AuthenticationProcessingFilterEntryPoint() {
- httpsPortMappings = new HashMap();
- httpsPortMappings.put(new Integer(80), new Integer(443));
- httpsPortMappings.put(new Integer(8080), new Integer(8443));
- }
-
//~ Methods ================================================================
/**
@@ -88,8 +77,6 @@ public class AuthenticationProcessingFilterEntryPoint
* https
, then
*
* @param forceHttps
- *
- * @todo Generated comment
*/
public void setForceHttps(boolean forceHttps) {
this.forceHttps = forceHttps;
@@ -99,56 +86,6 @@ public class AuthenticationProcessingFilterEntryPoint
return forceHttps;
}
- /**
- *
- * 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();
-
- Iterator it = newMappings.entrySet().iterator();
-
- while (it.hasNext()) {
- Map.Entry entry = (Map.Entry) it.next();
- Integer httpPort = new Integer((String) entry.getKey());
- Integer httpsPort = new Integer((String) entry.getValue());
-
- 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");
- }
- }
- }
-
/**
* The URL where the AuthenticationProcessingFilter
login page
* can be found. Should be relative to the web-app context path, and
@@ -164,40 +101,79 @@ public class AuthenticationProcessingFilterEntryPoint
return loginFormUrl;
}
+ 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 ((loginFormUrl == null) || "".equals(loginFormUrl)) {
throw new IllegalArgumentException("loginFormUrl must be specified");
}
+
+ if (portMapper == null) {
+ throw new IllegalArgumentException("portMapper must be specified");
+ }
+
+ if (portResolver == null) {
+ throw new IllegalArgumentException("portResolver must be specified");
+ }
}
public void commence(ServletRequest request, ServletResponse response)
throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
+ String scheme = request.getScheme();
+ String serverName = request.getServerName();
+ int serverPort = portResolver.getServerPort(request);
String contextPath = req.getContextPath();
- String redirectUrl = contextPath + loginFormUrl;
+ boolean includePort = true;
+
+ if ("http".equals(scheme.toLowerCase()) && (serverPort == 80)) {
+ includePort = false;
+ }
+
+ if ("https".equals(scheme.toLowerCase()) && (serverPort == 443)) {
+ includePort = false;
+ }
+
+ String redirectUrl = scheme + "://" + serverName
+ + ((includePort) ? (":" + serverPort) : "") + contextPath
+ + loginFormUrl;
if (forceHttps && req.getScheme().equals("http")) {
- Integer httpPort = new Integer(req.getServerPort());
- Integer httpsPort = (Integer) httpsPortMappings.get(httpPort);
+ Integer httpPort = new Integer(portResolver.getServerPort(request));
+ Integer httpsPort = (Integer) portMapper.lookupHttpsPort(httpPort);
if (httpsPort != null) {
- String serverName = req.getServerName();
- redirectUrl = "https://" + serverName + ":" + httpsPort
- + contextPath + loginFormUrl;
+ if (httpsPort.intValue() == 443) {
+ includePort = false;
+ } else {
+ includePort = true;
+ }
+
+ redirectUrl = "https://" + serverName
+ + ((includePort) ? (":" + httpsPort) : "") + contextPath
+ + loginFormUrl;
}
}
+ 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 HashMap getTranslatedHttpsPortMappings() {
- return httpsPortMappings;
- }
}
diff --git a/core/src/main/java/org/acegisecurity/util/PortMapper.java b/core/src/main/java/org/acegisecurity/util/PortMapper.java
new file mode 100644
index 0000000000..8a5d8349c5
--- /dev/null
+++ b/core/src/main/java/org/acegisecurity/util/PortMapper.java
@@ -0,0 +1,54 @@
+/* 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.util;
+
+/**
+ * PortMapper
implementations provide callers with information
+ * about which HTTP ports are associated with which HTTPS ports on the system,
+ * and vice versa.
+ *
+ * @author Ben Alex
+ * @version $Id$
+ */
+public interface PortMapper {
+ //~ Methods ================================================================
+
+ /**
+ * Locates the HTTP port associated with the specified HTTPS port.
+ *
+ *
+ * Returns null
if unknown.
+ *
+ *
+ * @param httpsPort
+ *
+ * @return the HTTP port or null
if unknown
+ */
+ public Integer lookupHttpPort(Integer httpsPort);
+
+ /**
+ * Locates the HTTPS port associated with the specified HTTP port.
+ *
+ *
+ * Returns null
if unknown.
+ *
+ *
+ * @param httpPort
+ *
+ * @return the HTTPS port or null
if unknown
+ */
+ public Integer lookupHttpsPort(Integer httpPort);
+}
diff --git a/core/src/main/java/org/acegisecurity/util/PortMapperImpl.java b/core/src/main/java/org/acegisecurity/util/PortMapperImpl.java
new file mode 100644
index 0000000000..2bd699f350
--- /dev/null
+++ b/core/src/main/java/org/acegisecurity/util/PortMapperImpl.java
@@ -0,0 +1,134 @@
+/* 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.util;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+
+/**
+ * Concrete implementation of {@link PortMapper} that obtains HTTP:HTTPS pairs
+ * from the application context.
+ *
+ *
+ * By default the implementation will assume 80:443 and 8080:8443 are
+ * HTTP:HTTPS pairs respectively. If different pairs are required, use {@link
+ * #setPortMappings(Map)}.
+ *
+ *
+ * @author Ben Alex
+ * @author colin sampaleanu
+ * @version $Id$
+ */
+public class PortMapperImpl implements PortMapper {
+ //~ Instance fields ========================================================
+
+ private Map httpsPortMappings;
+
+ //~ Constructors ===========================================================
+
+ public PortMapperImpl() {
+ httpsPortMappings = new HashMap();
+ httpsPortMappings.put(new Integer(80), new Integer(443));
+ httpsPortMappings.put(new Integer(8080), new Integer(8443));
+ }
+
+ //~ 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 setPortMappings(Map newMappings) {
+ if (newMappings == null) {
+ throw new IllegalArgumentException(
+ "A valid list of HTTPS port mappings must be provided");
+ }
+
+ httpsPortMappings.clear();
+
+ Iterator it = newMappings.entrySet().iterator();
+
+ while (it.hasNext()) {
+ Map.Entry entry = (Map.Entry) it.next();
+ Integer httpPort = new Integer((String) entry.getKey());
+ Integer httpsPort = new Integer((String) entry.getValue());
+
+ 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");
+ }
+ }
+
+ /**
+ * Returns the translated (Integer -> Integer) version of the original port
+ * mapping specified via setHttpsPortMapping()
+ *
+ * @return DOCUMENT ME!
+ */
+ public Map getTranslatedPortMappings() {
+ return httpsPortMappings;
+ }
+
+ public Integer lookupHttpPort(Integer httpsPort) {
+ Iterator iter = httpsPortMappings.keySet().iterator();
+
+ while (iter.hasNext()) {
+ Integer httpPort = (Integer) iter.next();
+
+ if (httpsPortMappings.get(httpPort).equals(httpsPort)) {
+ return httpPort;
+ }
+ }
+
+ return null;
+ }
+
+ public Integer lookupHttpsPort(Integer httpPort) {
+ return (Integer) httpsPortMappings.get(httpPort);
+ }
+}
diff --git a/core/src/main/java/org/acegisecurity/util/PortResolver.java b/core/src/main/java/org/acegisecurity/util/PortResolver.java
new file mode 100644
index 0000000000..92ca9cc40e
--- /dev/null
+++ b/core/src/main/java/org/acegisecurity/util/PortResolver.java
@@ -0,0 +1,46 @@
+/* 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.util;
+
+import javax.servlet.ServletRequest;
+
+
+/**
+ * A PortResolver
determines the port a web request was received
+ * on.
+ *
+ *
+ * This interface is necessary because
+ * ServletRequest.getServerPort()
may not return the correct port
+ * in certain circumstances. For example, if the browser does not construct
+ * the URL correctly after a redirect.
+ *
+ *
+ * @author Ben Alex
+ * @version $Id$
+ */
+public interface PortResolver {
+ //~ Methods ================================================================
+
+ /**
+ * Indicates the port the ServletRequest
was received on.
+ *
+ * @param request that the method should lookup the port for
+ *
+ * @return the port the request was received on
+ */
+ public int getServerPort(ServletRequest request);
+}
diff --git a/core/src/main/java/org/acegisecurity/util/PortResolverImpl.java b/core/src/main/java/org/acegisecurity/util/PortResolverImpl.java
new file mode 100644
index 0000000000..c886963e03
--- /dev/null
+++ b/core/src/main/java/org/acegisecurity/util/PortResolverImpl.java
@@ -0,0 +1,92 @@
+/* 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.util;
+
+import org.springframework.beans.factory.InitializingBean;
+
+import javax.servlet.ServletRequest;
+
+
+/**
+ * Concrete implementation of {@link PortResolver} that obtains the port from
+ * ServletRequest.getServerPort()
.
+ *
+ *
+ * If either the alwaysHttpPort
or alwaysHttpsPort
+ * properties are set, these ports will be used instead of those
+ * obtained from the ServletRequest.getServerPort()
method.
+ * Setting these properties will cause the
+ * ServletRequest.getScheme()
method to be used to determine
+ * whether a request was HTTP or HTTPS, and then return the port defined by
+ * the always[Scheme]Port
property. You can configure zero, one
+ * or both of these properties.
+ *
+ *
+ * @author Ben Alex
+ * @version $Id$
+ */
+public class PortResolverImpl implements InitializingBean, PortResolver {
+ //~ Instance fields ========================================================
+
+ private int alwaysHttpPort = 0;
+ private int alwaysHttpsPort = 0;
+
+ //~ Methods ================================================================
+
+ public void setAlwaysHttpPort(int alwaysHttpPort) {
+ this.alwaysHttpPort = alwaysHttpPort;
+ }
+
+ public int getAlwaysHttpPort() {
+ return alwaysHttpPort;
+ }
+
+ public void setAlwaysHttpsPort(int alwaysHttpsPort) {
+ this.alwaysHttpsPort = alwaysHttpsPort;
+ }
+
+ public int getAlwaysHttpsPort() {
+ return alwaysHttpsPort;
+ }
+
+ public int getServerPort(ServletRequest request) {
+ if ("http".equals(request.getScheme().toLowerCase())
+ && (alwaysHttpPort != 0)) {
+ return alwaysHttpPort;
+ }
+
+ if ("https".equals(request.getScheme().toLowerCase())
+ && (alwaysHttpsPort != 0)) {
+ return alwaysHttpsPort;
+ }
+
+ return request.getServerPort();
+ }
+
+ public void afterPropertiesSet() throws Exception {
+ if ((alwaysHttpPort != 0)
+ && ((alwaysHttpPort > 65535) || (alwaysHttpPort < 0))) {
+ throw new IllegalArgumentException(
+ "alwaysHttpPort must be between 1 and 65535");
+ }
+
+ if ((alwaysHttpsPort != 0)
+ && ((alwaysHttpsPort > 65535) || (alwaysHttpsPort < 0))) {
+ throw new IllegalArgumentException(
+ "alwaysHttpsPort must be between 1 and 65535");
+ }
+ }
+}
diff --git a/core/src/test/java/org/acegisecurity/MockHttpServletRequest.java b/core/src/test/java/org/acegisecurity/MockHttpServletRequest.java
index 009a7d93ed..f5874c4e43 100644
--- a/core/src/test/java/org/acegisecurity/MockHttpServletRequest.java
+++ b/core/src/test/java/org/acegisecurity/MockHttpServletRequest.java
@@ -53,13 +53,13 @@ public class MockHttpServletRequest implements HttpServletRequest {
private Map paramMap = new HashMap();
private Principal principal;
private String contextPath = "";
+ private String pathInfo; // null for no extra path
private String queryString = null;
private String requestURL;
private String scheme;
private String serverName;
private String servletPath;
private int serverPort;
- private String pathInfo; // null for no extra path
//~ Constructors ===========================================================
@@ -197,11 +197,10 @@ public class MockHttpServletRequest implements HttpServletRequest {
throw new UnsupportedOperationException("mock method not implemented");
}
-
public void setPathInfo(String pathInfo) {
this.pathInfo = pathInfo;
}
-
+
public String getPathInfo() {
return pathInfo;
}
@@ -283,7 +282,11 @@ public class MockHttpServletRequest implements HttpServletRequest {
}
public boolean isSecure() {
- throw new UnsupportedOperationException("mock method not implemented");
+ if ("https".equals(scheme)) {
+ return true;
+ } else {
+ return false;
+ }
}
public void setServerName(String serverName) {
diff --git a/core/src/test/java/org/acegisecurity/MockPortResolver.java b/core/src/test/java/org/acegisecurity/MockPortResolver.java
new file mode 100644
index 0000000000..e22bf73a4a
--- /dev/null
+++ b/core/src/test/java/org/acegisecurity/MockPortResolver.java
@@ -0,0 +1,54 @@
+/* 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;
+
+import net.sf.acegisecurity.util.PortResolver;
+
+import javax.servlet.ServletRequest;
+
+
+/**
+ * Always returns the constructor-specified HTTP and HTTPS ports.
+ *
+ * @author Ben Alex
+ * @version $Id$
+ */
+public class MockPortResolver implements PortResolver {
+ //~ Instance fields ========================================================
+
+ private int http = 80;
+ private int https = 443;
+
+ //~ Constructors ===========================================================
+
+ public MockPortResolver(int http, int https) {
+ this.http = http;
+ this.https = https;
+ }
+
+ private MockPortResolver() {}
+
+ //~ Methods ================================================================
+
+ public int getServerPort(ServletRequest request) {
+ if ((request.getScheme() != null)
+ && request.getScheme().equals("https")) {
+ return https;
+ } else {
+ return http;
+ }
+ }
+}
diff --git a/core/src/test/java/org/acegisecurity/intercept/web/SecurityEnforcementFilterTests.java b/core/src/test/java/org/acegisecurity/intercept/web/SecurityEnforcementFilterTests.java
index 20c5e4010b..72706f305c 100644
--- a/core/src/test/java/org/acegisecurity/intercept/web/SecurityEnforcementFilterTests.java
+++ b/core/src/test/java/org/acegisecurity/intercept/web/SecurityEnforcementFilterTests.java
@@ -23,6 +23,7 @@ import net.sf.acegisecurity.MockAuthenticationEntryPoint;
import net.sf.acegisecurity.MockHttpServletRequest;
import net.sf.acegisecurity.MockHttpServletResponse;
import net.sf.acegisecurity.MockHttpSession;
+import net.sf.acegisecurity.MockPortResolver;
import net.sf.acegisecurity.ui.webapp.AuthenticationProcessingFilter;
import java.io.IOException;
@@ -120,6 +121,9 @@ public class SecurityEnforcementFilterTests extends TestCase {
filter.setAuthenticationEntryPoint(new MockAuthenticationEntryPoint(
"/login.jsp"));
assertTrue(filter.getAuthenticationEntryPoint() != null);
+
+ filter.setPortResolver(new MockPortResolver(80, 443));
+ assertTrue(filter.getPortResolver() != null);
}
public void testRedirectedToLoginFormAndSessionShowsOriginalTargetWhenAuthenticationException()
@@ -128,6 +132,10 @@ public class SecurityEnforcementFilterTests extends TestCase {
MockHttpServletRequest request = new MockHttpServletRequest(null,
new MockHttpSession());
request.setServletPath("/secure/page.html");
+ request.setServerPort(80);
+ request.setScheme("http");
+ request.setServerName("www.example.com");
+ request.setContextPath("/mycontext");
request.setRequestURL(
"http://www.example.com/mycontext/secure/page.html");
@@ -143,15 +151,51 @@ public class SecurityEnforcementFilterTests extends TestCase {
filter.setFilterSecurityInterceptor(interceptor);
filter.setAuthenticationEntryPoint(new MockAuthenticationEntryPoint(
"/login.jsp"));
+ filter.setPortResolver(new MockPortResolver(80, 443));
filter.afterPropertiesSet();
MockHttpServletResponse response = new MockHttpServletResponse();
filter.doFilter(request, response, chain);
- assertEquals("/login.jsp", response.getRedirect());
+ assertEquals("/mycontext/login.jsp", response.getRedirect());
assertEquals("http://www.example.com/mycontext/secure/page.html",
request.getSession().getAttribute(AuthenticationProcessingFilter.ACEGI_SECURITY_TARGET_URL_KEY));
}
+ public void testRedirectedToLoginFormAndSessionShowsOriginalTargetWithExoticPortWhenAuthenticationException()
+ throws Exception {
+ // Setup our HTTP request
+ MockHttpServletRequest request = new MockHttpServletRequest(null,
+ new MockHttpSession());
+ request.setServletPath("/secure/page.html");
+ request.setServerPort(8080);
+ request.setScheme("http");
+ request.setServerName("www.example.com");
+ request.setContextPath("/mycontext");
+ request.setRequestURL(
+ "http://www.example.com:8080/mycontext/secure/page.html");
+
+ // Setup our expectation that the filter chain will not be invoked, as access is denied
+ MockFilterChain chain = new MockFilterChain(false);
+
+ // Setup the FilterSecurityInterceptor thrown an authentication failure exceptions
+ MockFilterSecurityInterceptor interceptor = new MockFilterSecurityInterceptor(false,
+ true);
+
+ // Test
+ SecurityEnforcementFilter filter = new SecurityEnforcementFilter();
+ filter.setFilterSecurityInterceptor(interceptor);
+ filter.setAuthenticationEntryPoint(new MockAuthenticationEntryPoint(
+ "/login.jsp"));
+ filter.setPortResolver(new MockPortResolver(8080, 8443));
+ filter.afterPropertiesSet();
+
+ MockHttpServletResponse response = new MockHttpServletResponse();
+ filter.doFilter(request, response, chain);
+ assertEquals("/mycontext/login.jsp", response.getRedirect());
+ assertEquals("http://www.example.com:8080/mycontext/secure/page.html",
+ request.getSession().getAttribute(AuthenticationProcessingFilter.ACEGI_SECURITY_TARGET_URL_KEY));
+ }
+
public void testStartupDetectsMissingAuthenticationEntryPoint()
throws Exception {
SecurityEnforcementFilter filter = new SecurityEnforcementFilter();
@@ -182,6 +226,22 @@ public class SecurityEnforcementFilterTests extends TestCase {
}
}
+ public void testStartupDetectsMissingPortResolver()
+ throws Exception {
+ SecurityEnforcementFilter filter = new SecurityEnforcementFilter();
+ filter.setFilterSecurityInterceptor(new MockFilterSecurityInterceptor(
+ false, false));
+ filter.setAuthenticationEntryPoint(new MockAuthenticationEntryPoint(
+ "/login.jsp"));
+
+ try {
+ filter.afterPropertiesSet();
+ fail("Should have thrown IllegalArgumentException");
+ } catch (IllegalArgumentException expected) {
+ assertEquals("portResolver must be specified", expected.getMessage());
+ }
+ }
+
public void testSuccessfulAccessGrant() throws Exception {
// Setup our HTTP request
MockHttpServletRequest request = new MockHttpServletRequest(null,
diff --git a/core/src/test/java/org/acegisecurity/ui/webapp/AuthenticationProcessingFilterEntryPointTests.java b/core/src/test/java/org/acegisecurity/ui/webapp/AuthenticationProcessingFilterEntryPointTests.java
index ba1f33dd4c..b7ed9b5f6e 100644
--- a/core/src/test/java/org/acegisecurity/ui/webapp/AuthenticationProcessingFilterEntryPointTests.java
+++ b/core/src/test/java/org/acegisecurity/ui/webapp/AuthenticationProcessingFilterEntryPointTests.java
@@ -19,8 +19,11 @@ 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;
/**
@@ -43,6 +46,8 @@ public class AuthenticationProcessingFilterEntryPointTests extends TestCase {
public void testDetectsMissingLoginFormUrl() throws Exception {
AuthenticationProcessingFilterEntryPoint ep = new AuthenticationProcessingFilterEntryPoint();
+ ep.setPortMapper(new PortMapperImpl());
+ ep.setPortResolver(new MockPortResolver(80, 443));
try {
ep.afterPropertiesSet();
@@ -52,10 +57,45 @@ public class AuthenticationProcessingFilterEntryPointTests extends TestCase {
}
}
+ public void testDetectsMissingPortMapper() throws Exception {
+ AuthenticationProcessingFilterEntryPoint ep = new AuthenticationProcessingFilterEntryPoint();
+ ep.setLoginFormUrl("xxx");
+ ep.setPortResolver(new MockPortResolver(80, 443));
+
+ try {
+ ep.afterPropertiesSet();
+ fail("Should have thrown IllegalArgumentException");
+ } catch (IllegalArgumentException expected) {
+ assertEquals("portMapper must be specified", expected.getMessage());
+ }
+ }
+
+ public void testDetectsMissingPortResolver() throws Exception {
+ AuthenticationProcessingFilterEntryPoint ep = new AuthenticationProcessingFilterEntryPoint();
+ ep.setLoginFormUrl("xxx");
+ ep.setPortMapper(new PortMapperImpl());
+
+ try {
+ ep.afterPropertiesSet();
+ fail("Should have thrown IllegalArgumentException");
+ } catch (IllegalArgumentException expected) {
+ assertEquals("portResolver must be specified", expected.getMessage());
+ }
+ }
+
public void testGettersSetters() {
AuthenticationProcessingFilterEntryPoint ep = new AuthenticationProcessingFilterEntryPoint();
ep.setLoginFormUrl("/hello");
+ ep.setPortMapper(new PortMapperImpl());
+ ep.setPortResolver(new MockPortResolver(8080, 8443));
assertEquals("/hello", ep.getLoginFormUrl());
+ assertTrue(ep.getPortMapper() != null);
+ assertTrue(ep.getPortResolver() != null);
+
+ ep.setForceHttps(false);
+ assertFalse(ep.getForceHttps());
+ ep.setForceHttps(true);
+ assertTrue(ep.getForceHttps());
}
public void testHttpsOperation() throws Exception {
@@ -70,30 +110,40 @@ public class AuthenticationProcessingFilterEntryPointTests extends TestCase {
AuthenticationProcessingFilterEntryPoint ep = new AuthenticationProcessingFilterEntryPoint();
ep.setLoginFormUrl("/hello");
+ ep.setPortMapper(new PortMapperImpl());
ep.setForceHttps(true);
+ ep.setPortMapper(new PortMapperImpl());
+ ep.setPortResolver(new MockPortResolver(80, 443));
ep.afterPropertiesSet();
ep.commence(request, response);
- assertEquals("https://www.example.com:443/bigWebApp/hello",
+ assertEquals("https://www.example.com/bigWebApp/hello",
response.getRedirect());
request.setServerPort(8080);
+ ep.setPortResolver(new MockPortResolver(8080, 8443));
+ ep.commence(request, response);
+ System.out.println(response.getRedirect());
+ assertEquals("https://www.example.com:8443/bigWebApp/hello",
+ response.getRedirect());
+
+ // Now test an unusual custom HTTP:HTTPS is handled properly
+ request.setServerPort(8888);
ep.commence(request, response);
assertEquals("https://www.example.com:8443/bigWebApp/hello",
response.getRedirect());
- // check that unknown port leaves things as-is
- request.setServerPort(8888);
- ep.commence(request, response);
- assertEquals("/bigWebApp/hello", response.getRedirect());
+ PortMapperImpl portMapper = new PortMapperImpl();
+ Map map = new HashMap();
+ map.put("8888", "9999");
+ portMapper.setPortMappings(map);
ep = new AuthenticationProcessingFilterEntryPoint();
ep.setLoginFormUrl("/hello");
+ ep.setPortMapper(new PortMapperImpl());
ep.setForceHttps(true);
-
- HashMap map = new HashMap();
- map.put("8888", "9999");
- ep.setHttpsPortMappings(map);
+ ep.setPortMapper(portMapper);
+ ep.setPortResolver(new MockPortResolver(8888, 9999));
ep.afterPropertiesSet();
ep.commence(request, response);
@@ -104,50 +154,50 @@ public class AuthenticationProcessingFilterEntryPointTests extends TestCase {
public void testNormalOperation() throws Exception {
AuthenticationProcessingFilterEntryPoint ep = new AuthenticationProcessingFilterEntryPoint();
ep.setLoginFormUrl("/hello");
+ ep.setPortMapper(new PortMapperImpl());
+ ep.setPortResolver(new MockPortResolver(80, 443));
+ ep.afterPropertiesSet();
MockHttpServletRequest request = new MockHttpServletRequest(
"/some_path");
request.setContextPath("/bigWebApp");
+ request.setScheme("http");
+ request.setServerName("www.example.com");
+ request.setContextPath("/bigWebApp");
+ request.setServerPort(80);
MockHttpServletResponse response = new MockHttpServletResponse();
ep.afterPropertiesSet();
ep.commence(request, response);
- assertEquals("/bigWebApp/hello", response.getRedirect());
+ assertEquals("http://www.example.com/bigWebApp/hello",
+ response.getRedirect());
}
- public void testSetSslPortMapping() {
+ public void testOperationWhenHttpsRequestsButHttpsPortUnknown()
+ throws Exception {
AuthenticationProcessingFilterEntryPoint ep = new AuthenticationProcessingFilterEntryPoint();
- HashMap map = new HashMap();
+ ep.setLoginFormUrl("/hello");
+ ep.setPortMapper(new PortMapperImpl());
+ ep.setPortResolver(new MockPortResolver(8888, 1234));
+ ep.setForceHttps(true);
+ ep.afterPropertiesSet();
- try {
- ep.setHttpsPortMappings(map);
- } catch (IllegalArgumentException expected) {
- assertEquals("must map at least one port", expected.getMessage());
- }
+ MockHttpServletRequest request = new MockHttpServletRequest(
+ "/some_path");
+ request.setContextPath("/bigWebApp");
+ request.setScheme("http");
+ request.setServerName("www.example.com");
+ request.setContextPath("/bigWebApp");
+ request.setServerPort(8888); // NB: Port we can't resolve
- map.put(new Integer(0).toString(), new Integer(443).toString());
+ MockHttpServletResponse response = new MockHttpServletResponse();
- try {
- ep.setHttpsPortMappings(map);
- } catch (IllegalArgumentException expected) {
- assertTrue(expected.getMessage().startsWith("one or both ports out of legal range"));
- }
+ ep.afterPropertiesSet();
+ ep.commence(request, response);
- map.clear();
- map.put(new Integer(80).toString(), new Integer(100000).toString());
-
- try {
- ep.setHttpsPortMappings(map);
- } catch (IllegalArgumentException expected) {
- assertTrue(expected.getMessage().startsWith("one or both ports out of legal range"));
- }
-
- map.clear();
- map.put(new Integer(80).toString(), new Integer(443).toString());
- ep.setHttpsPortMappings(map);
- map = ep.getTranslatedHttpsPortMappings();
- assertTrue(map.size() == 1);
- assertTrue(((Integer) map.get(new Integer(80))).equals(new Integer(443)));
+ // Response doesn't switch to HTTPS, as we didn't know HTTP port 8888 to HTTP port mapping
+ assertEquals("http://www.example.com:8888/bigWebApp/hello",
+ response.getRedirect());
}
}
diff --git a/core/src/test/java/org/acegisecurity/util/PortMapperImplTests.java b/core/src/test/java/org/acegisecurity/util/PortMapperImplTests.java
new file mode 100644
index 0000000000..048a09401c
--- /dev/null
+++ b/core/src/test/java/org/acegisecurity/util/PortMapperImplTests.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.util;
+
+import junit.framework.TestCase;
+
+import java.util.HashMap;
+import java.util.Map;
+
+
+/**
+ * Tests {@link PortMapperImpl}.
+ *
+ * @author Ben Alex
+ * @version $Id$
+ */
+public class PortMapperImplTests extends TestCase {
+ //~ Constructors ===========================================================
+
+ public PortMapperImplTests() {
+ super();
+ }
+
+ public PortMapperImplTests(String arg0) {
+ super(arg0);
+ }
+
+ //~ Methods ================================================================
+
+ public final void setUp() throws Exception {
+ super.setUp();
+ }
+
+ public static void main(String[] args) {
+ junit.textui.TestRunner.run(PortMapperImplTests.class);
+ }
+
+ public void testDefaultMappingsAreKnown() throws Exception {
+ PortMapperImpl portMapper = new PortMapperImpl();
+ assertEquals(new Integer(80),
+ portMapper.lookupHttpPort(new Integer(443)));
+ assertEquals(new Integer(8080),
+ portMapper.lookupHttpPort(new Integer(8443)));
+ assertEquals(new Integer(443),
+ portMapper.lookupHttpsPort(new Integer(80)));
+ assertEquals(new Integer(8443),
+ portMapper.lookupHttpsPort(new Integer(8080)));
+ }
+
+ public void testDetectsEmptyMap() throws Exception {
+ PortMapperImpl portMapper = new PortMapperImpl();
+
+ try {
+ portMapper.setPortMappings(new HashMap());
+ fail("Should have thrown IllegalArgumentException");
+ } catch (IllegalArgumentException expected) {
+ assertTrue(true);
+ }
+ }
+
+ public void testDetectsNullMap() throws Exception {
+ PortMapperImpl portMapper = new PortMapperImpl();
+
+ try {
+ portMapper.setPortMappings(null);
+ fail("Should have thrown IllegalArgumentException");
+ } catch (IllegalArgumentException expected) {
+ assertTrue(true);
+ }
+ }
+
+ public void testGetTranslatedPortMappings() {
+ PortMapperImpl portMapper = new PortMapperImpl();
+ assertEquals(2, portMapper.getTranslatedPortMappings().size());
+ }
+
+ public void testRejectsOutOfRangeMappings() {
+ PortMapperImpl portMapper = new PortMapperImpl();
+ Map map = new HashMap();
+ map.put("79", "80559");
+
+ try {
+ portMapper.setPortMappings(map);
+ fail("Should have thrown IllegalArgumentException");
+ } catch (IllegalArgumentException expected) {
+ assertTrue(true);
+ }
+ }
+
+ public void testReturnsNullIfHttpPortCannotBeFound() {
+ PortMapperImpl portMapper = new PortMapperImpl();
+ assertTrue(portMapper.lookupHttpPort(new Integer("34343")) == null);
+ }
+
+ public void testSupportsCustomMappings() {
+ PortMapperImpl portMapper = new PortMapperImpl();
+ Map map = new HashMap();
+ map.put("79", "442");
+
+ portMapper.setPortMappings(map);
+
+ assertEquals(new Integer(79),
+ portMapper.lookupHttpPort(new Integer(442)));
+ assertEquals(new Integer(442),
+ portMapper.lookupHttpsPort(new Integer(79)));
+ }
+}
diff --git a/core/src/test/java/org/acegisecurity/util/PortResolverImplTests.java b/core/src/test/java/org/acegisecurity/util/PortResolverImplTests.java
new file mode 100644
index 0000000000..b789b09429
--- /dev/null
+++ b/core/src/test/java/org/acegisecurity/util/PortResolverImplTests.java
@@ -0,0 +1,144 @@
+/* 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.util;
+
+import junit.framework.TestCase;
+
+import net.sf.acegisecurity.MockHttpServletRequest;
+
+
+/**
+ * Tests {@link PortResolverImpl}.
+ *
+ * @author Ben Alex
+ * @version $Id$
+ */
+public class PortResolverImplTests extends TestCase {
+ //~ Constructors ===========================================================
+
+ public PortResolverImplTests() {
+ super();
+ }
+
+ public PortResolverImplTests(String arg0) {
+ super(arg0);
+ }
+
+ //~ Methods ================================================================
+
+ public final void setUp() throws Exception {
+ super.setUp();
+ }
+
+ public static void main(String[] args) {
+ junit.textui.TestRunner.run(PortResolverImplTests.class);
+ }
+
+ public void testGettersSetters() throws Exception {
+ PortResolverImpl pr = new PortResolverImpl();
+ assertEquals(0, pr.getAlwaysHttpPort());
+ assertEquals(0, pr.getAlwaysHttpsPort());
+
+ pr.setAlwaysHttpPort(80);
+ pr.setAlwaysHttpsPort(443);
+ assertEquals(80, pr.getAlwaysHttpPort());
+ assertEquals(443, pr.getAlwaysHttpsPort());
+ }
+
+ public void testNormalOperation() throws Exception {
+ PortResolverImpl pr = new PortResolverImpl();
+ pr.afterPropertiesSet();
+
+ MockHttpServletRequest request = new MockHttpServletRequest("X");
+ request.setScheme("http");
+ request.setServerPort(1021);
+ assertEquals(1021, pr.getServerPort(request));
+ }
+
+ public void testOverridesHttp() throws Exception {
+ PortResolverImpl pr = new PortResolverImpl();
+ pr.setAlwaysHttpPort(495);
+ pr.afterPropertiesSet();
+
+ MockHttpServletRequest request = new MockHttpServletRequest("X");
+ request.setServerPort(7676);
+ request.setScheme("HTtP"); // proves case insensitive handling
+ assertEquals(495, pr.getServerPort(request));
+
+ request.setScheme("https");
+ assertEquals(7676, pr.getServerPort(request));
+ }
+
+ public void testOverridesHttps() throws Exception {
+ PortResolverImpl pr = new PortResolverImpl();
+ pr.setAlwaysHttpsPort(987);
+ pr.afterPropertiesSet();
+
+ MockHttpServletRequest request = new MockHttpServletRequest("X");
+ request.setServerPort(6949);
+ request.setScheme("HTtPs"); // proves case insensitive handling
+ assertEquals(987, pr.getServerPort(request));
+
+ request.setScheme("http");
+ assertEquals(6949, pr.getServerPort(request));
+ }
+
+ public void testRejectsOutOfRangeHttp() throws Exception {
+ PortResolverImpl pr = new PortResolverImpl();
+ pr.setAlwaysHttpPort(9999999);
+
+ try {
+ pr.afterPropertiesSet();
+ fail("Should have thrown IllegalArgumentException");
+ } catch (IllegalArgumentException expected) {
+ assertEquals("alwaysHttpPort must be between 1 and 65535",
+ expected.getMessage());
+ }
+
+ pr.setAlwaysHttpPort(-49);
+
+ try {
+ pr.afterPropertiesSet();
+ fail("Should have thrown IllegalArgumentException");
+ } catch (IllegalArgumentException expected) {
+ assertEquals("alwaysHttpPort must be between 1 and 65535",
+ expected.getMessage());
+ }
+ }
+
+ public void testRejectsOutOfRangeHttps() throws Exception {
+ PortResolverImpl pr = new PortResolverImpl();
+ pr.setAlwaysHttpsPort(9999999);
+
+ try {
+ pr.afterPropertiesSet();
+ fail("Should have thrown IllegalArgumentException");
+ } catch (IllegalArgumentException expected) {
+ assertEquals("alwaysHttpsPort must be between 1 and 65535",
+ expected.getMessage());
+ }
+
+ pr.setAlwaysHttpsPort(-49);
+
+ try {
+ pr.afterPropertiesSet();
+ fail("Should have thrown IllegalArgumentException");
+ } catch (IllegalArgumentException expected) {
+ assertEquals("alwaysHttpsPort must be between 1 and 65535",
+ expected.getMessage());
+ }
+ }
+}