Move port mapping functionality into separate classes to allow reuse. Permit implementations to override the source port (required given some browsers do not respond to HTTP redirects correctly).

This commit is contained in:
Ben Alex
2004-04-27 06:17:53 +00:00
parent c6a1b2b608
commit e555d77d4e
12 changed files with 908 additions and 140 deletions

View File

@@ -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) {

View File

@@ -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;
}
}
}

View File

@@ -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,

View File

@@ -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());
}
}

View File

@@ -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)));
}
}

View File

@@ -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());
}
}
}