diff --git a/src/extension/security/cas/src/main/java/org/geoserver/security/cas/GeoServerCasAuthenticationFilter.java b/src/extension/security/cas/src/main/java/org/geoserver/security/cas/GeoServerCasAuthenticationFilter.java index 9ddf4dc84e9..f6d611541e0 100644 --- a/src/extension/security/cas/src/main/java/org/geoserver/security/cas/GeoServerCasAuthenticationFilter.java +++ b/src/extension/security/cas/src/main/java/org/geoserver/security/cas/GeoServerCasAuthenticationFilter.java @@ -16,6 +16,7 @@ import java.util.List; import java.util.Optional; import java.util.logging.Level; +import java.util.logging.Logger; import java.util.stream.Collectors; import javax.servlet.FilterChain; import javax.servlet.ServletException; @@ -24,6 +25,8 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; +import org.geoserver.ows.URLMangler; +import org.geoserver.ows.util.ResponseUtils; import org.geoserver.platform.GeoServerExtensions; import org.geoserver.security.LogoutFilterChain; import org.geoserver.security.config.SecurityNamedServiceConfig; @@ -31,6 +34,7 @@ import org.geoserver.security.filter.GeoServerPreAuthenticatedUserNameFilter; import org.geoserver.security.impl.GeoServerRole; import org.geoserver.security.impl.RoleCalculator; +import org.geotools.util.logging.Logging; import org.jasig.cas.client.configuration.ConfigurationKeys; import org.jasig.cas.client.proxy.ProxyGrantingTicketStorage; import org.jasig.cas.client.session.SingleSignOutHandler; @@ -59,6 +63,8 @@ public class GeoServerCasAuthenticationFilter extends GeoServerPreAuthenticatedUserNameFilter implements LogoutHandler { + private static final Logger LOGGER = Logging.getLogger(GeoServerCasAuthenticationFilter.class); + protected Cas20ProxyTicketValidator validator; protected ServiceAuthenticationDetailsSource casAuthenticationDetailsSource; protected String casLogoutURL; @@ -136,14 +142,15 @@ protected Assertion getCASAssertion(HttpServletRequest request) { protected static String retrieveService(HttpServletRequest request) { - String serviceBaseUrl = null; - String proxyBaseUrl = GeoServerExtensions.getProperty("PROXY_BASE_URL"); - if (StringUtils.hasLength(proxyBaseUrl)) { - serviceBaseUrl = proxyBaseUrl; - } else { - serviceBaseUrl = request.getRequestURL().toString(); - } - StringBuffer buff = new StringBuffer(serviceBaseUrl); + String requestBaseUrl = ResponseUtils.baseURL(request); + String requestPath = request.getRequestURI().substring(request.getContextPath().length()); + + // Will run the URL through various manglers, to handle proxying, etc. + String serviceBaseUrl = + ResponseUtils.buildURL( + requestBaseUrl, requestPath, null, URLMangler.URLType.SERVICE); + + StringBuilder buff = new StringBuilder(serviceBaseUrl); if (StringUtils.hasLength(request.getQueryString())) { String query = request.getQueryString(); diff --git a/src/extension/security/cas/src/test/java/org/geoserver/security/cas/GeoServerCasAuthenticationFilterTest.java b/src/extension/security/cas/src/test/java/org/geoserver/security/cas/GeoServerCasAuthenticationFilterTest.java new file mode 100644 index 00000000000..e7d8c42b141 --- /dev/null +++ b/src/extension/security/cas/src/test/java/org/geoserver/security/cas/GeoServerCasAuthenticationFilterTest.java @@ -0,0 +1,143 @@ +/* (c) 2024 Open Source Geospatial Foundation - all rights reserved + * This code is licensed under the GPL 2.0 license, available at the root + * application directory. + */ +package org.geoserver.security.cas; + +import static org.junit.Assert.assertEquals; + +import org.geoserver.config.GeoServer; +import org.geoserver.config.GeoServerInfo; +import org.geoserver.ows.HTTPHeadersCollector; +import org.geoserver.ows.ProxifyingURLMangler; +import org.geoserver.test.GeoServerSystemTestSupport; +import org.junit.Test; +import org.springframework.mock.web.MockHttpServletRequest; + +public class GeoServerCasAuthenticationFilterTest extends GeoServerSystemTestSupport { + + @Test + public void testRetrieveServiceWithNoProxyBaseUrl() { + GeoServer geoServer = getGeoServer(); + String oldValue = System.getProperty("PROXY_BASE_URL"); + try { + setProxyBase(geoServer, null); + setSystemProperty("PROXY_BASE_URL", null); + + MockHttpServletRequest request = + buildMockRequest( + "http", + "localhost", + 8080, + "/geoserver", + "/geoserver/myworkspace/wms?SERVICE=WMS"); + + String serviceUrl = GeoServerCasAuthenticationFilter.retrieveService(request); + + assertEquals("http://localhost:8080/geoserver/myworkspace/wms?SERVICE=WMS", serviceUrl); + } finally { + // Reset to make sure we don't interfere with other tests at all + setSystemProperty("PROXY_BASE_URL", oldValue); + } + } + + @Test + public void testRetrieveServiceWithProxyBaseUrlSystemProperty() { + + String oldValue = System.getProperty("PROXY_BASE_URL"); + try { + setSystemProperty("PROXY_BASE_URL", "https://example.com/geoserver"); + + MockHttpServletRequest request = + buildMockRequest( + "http", + "localhost", + 8080, + "/geoserver", + "/geoserver/myworkspace/wms?SERVICE=WMS"); + + String serviceUrl = GeoServerCasAuthenticationFilter.retrieveService(request); + + assertEquals("https://example.com/geoserver/myworkspace/wms?SERVICE=WMS", serviceUrl); + } finally { + // Reset to make sure we don't interfere with other tests at all + setSystemProperty("PROXY_BASE_URL", oldValue); + } + } + + @Test + public void testRetrieveServiceWithProxyBaseUrlConfig() { + GeoServer geoServer = getGeoServer(); + try { + setProxyBase(geoServer, "https://example.com/geoserver"); + + MockHttpServletRequest request = + buildMockRequest( + "http", + "localhost", + 8080, + "/geoserver", + "/geoserver/myworkspace/wms?SERVICE=WMS"); + + String serviceUrl = GeoServerCasAuthenticationFilter.retrieveService(request); + + assertEquals("https://example.com/geoserver/myworkspace/wms?SERVICE=WMS", serviceUrl); + } finally { + setProxyBase(geoServer, null); + } + } + + @Test + public void testRetrieveServiceWithProxyBaseUrlConfigAndParameterization() { + GeoServer geoServer = getGeoServer(); + try { + setProxyBase(geoServer, "https://${X-Forwarded-Host}/geoserver"); + + MockHttpServletRequest request = + buildMockRequest( + "http", + "localhost", + 8080, + "/geoserver", + "/geoserver/myworkspace/wms?SERVICE=WMS"); + + // Add headers + request.addHeader( + ProxifyingURLMangler.Headers.FORWARDED_HOST.asString(), "example.com"); + HTTPHeadersCollector filter = new HTTPHeadersCollector(); + filter.collectHeaders(request); + + String serviceUrl = GeoServerCasAuthenticationFilter.retrieveService(request); + + assertEquals("https://example.com/geoserver/myworkspace/wms?SERVICE=WMS", serviceUrl); + } finally { + setProxyBase(geoServer, null); + } + } + + private MockHttpServletRequest buildMockRequest( + String scheme, String serverName, int port, String contextPath, String uri) { + MockHttpServletRequest request = new MockHttpServletRequest(); + request.setScheme(scheme); + request.setServerName(serverName); + request.setServerPort(port); + request.setContextPath(contextPath); + request.setRequestURI(uri); + return request; + } + + private void setProxyBase(GeoServer gs, String s) { + final GeoServerInfo global = gs.getGlobal(); + global.getSettings().setProxyBaseUrl(s); + global.getSettings().setUseHeadersProxyURL(s != null); + gs.save(global); + } + + private void setSystemProperty(String key, String value) { + if (value == null) { + System.clearProperty(key); + } else { + System.setProperty(key, value); + } + } +} diff --git a/src/gwc/pom.xml b/src/gwc/pom.xml index 280c1001490..50434b01a6c 100644 --- a/src/gwc/pom.xml +++ b/src/gwc/pom.xml @@ -131,6 +131,12 @@ tests test + + org.geotools + gt-iau-wkt + ${gt.version} + test +