From e5c736210428ba09ede36b9cfeab063091d1ee0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Bl=C3=A4sing?= Date: Sun, 16 Jul 2023 21:48:54 +0200 Subject: [PATCH] Fix compatibility with mod_rewrite in proxy mode mod_rewrite passes cookies to the backend servers when run in proxy mode. For us this is helpful as our single-sign-on solution is cookie based. We use mod_rewrite to map backend APIs to our frontend servers and thus fix the CORS problem. When testing urlrewritefilter as an alternative solution I noticed, that my requests were all redirected to our authentication servers and the dropped cookies would cause that behavior. This triggered my investigation. --- container-test/example-webapp/pom.xml | 6 +++++ .../urlrewriteviacontainer/CookieServlet.java | 25 +++++++++++++++++++ .../src/main/webapp/WEB-INF/web.xml | 14 +++++++---- .../WebappModStyleHttpITTest.java | 19 +++++++++++++- .../utils/ModRewriteConfLoader.java | 2 ++ .../utils/ModRewriteConfLoaderTest.java | 11 ++++++-- 6 files changed, 69 insertions(+), 8 deletions(-) create mode 100644 container-test/example-webapp/src/main/java/org/tuckey/web/filters/urlrewriteviacontainer/CookieServlet.java diff --git a/container-test/example-webapp/pom.xml b/container-test/example-webapp/pom.xml index 348233d9..1d5fe9b2 100644 --- a/container-test/example-webapp/pom.xml +++ b/container-test/example-webapp/pom.xml @@ -66,6 +66,12 @@ 6.0.0 provided + + + commons-httpclient + commons-httpclient + 3.1 + diff --git a/container-test/example-webapp/src/main/java/org/tuckey/web/filters/urlrewriteviacontainer/CookieServlet.java b/container-test/example-webapp/src/main/java/org/tuckey/web/filters/urlrewriteviacontainer/CookieServlet.java new file mode 100644 index 00000000..46539595 --- /dev/null +++ b/container-test/example-webapp/src/main/java/org/tuckey/web/filters/urlrewriteviacontainer/CookieServlet.java @@ -0,0 +1,25 @@ + +package org.tuckey.web.filters.urlrewriteviacontainer; + +import jakarta.servlet.ServletException; +import jakarta.servlet.http.Cookie; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.Writer; + +public class CookieServlet extends HttpServlet { + + @Override + protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + try (Writer writer = resp.getWriter()) { + writer.write("Cookie-Servlet\n"); + for(Cookie cookie: req.getCookies()) { + writer.write(cookie.getName()); + writer.write((": ")); + writer.write(cookie.getValue()); + } + } + } +} \ No newline at end of file diff --git a/container-test/example-webapp/src/main/webapp/WEB-INF/web.xml b/container-test/example-webapp/src/main/webapp/WEB-INF/web.xml index aae9f7ee..f5bd1885 100644 --- a/container-test/example-webapp/src/main/webapp/WEB-INF/web.xml +++ b/container-test/example-webapp/src/main/webapp/WEB-INF/web.xml @@ -39,6 +39,7 @@ # simple test rule RewriteRule ^/mod/simple/test$ /mod/index.jsp [L] + RewriteRule ^/mod/cookie$ http://localhost:8080/webapp/cookie [P] ]]> @@ -55,11 +56,14 @@ /* + + Cookie Test + org.tuckey.web.filters.urlrewriteviacontainer.CookieServlet + - - - - - + + Cookie Test + /cookie + diff --git a/container-test/test-with-testcontainers/src/test/java/org/tuckey/web/filters/urlrewriteviacontainer/WebappModStyleHttpITTest.java b/container-test/test-with-testcontainers/src/test/java/org/tuckey/web/filters/urlrewriteviacontainer/WebappModStyleHttpITTest.java index 14466c5a..361df4e4 100644 --- a/container-test/test-with-testcontainers/src/test/java/org/tuckey/web/filters/urlrewriteviacontainer/WebappModStyleHttpITTest.java +++ b/container-test/test-with-testcontainers/src/test/java/org/tuckey/web/filters/urlrewriteviacontainer/WebappModStyleHttpITTest.java @@ -43,6 +43,8 @@ import jakarta.servlet.ServletException; import java.io.IOException; +import org.apache.commons.httpclient.Cookie; + import static org.junit.jupiter.api.Assertions.*; /** @@ -63,7 +65,13 @@ public void beforeEach() throws Exception { @AfterEach public void afterEach() throws InterruptedException { - super.tearDown(); + tearDown(); + } + + @Override + public void setUp() throws Exception { + super.setUp(); + client.getState().clearCookies(); } @Test @@ -91,4 +99,13 @@ public void testStatus1() throws IOException { assertFalse(method.getResponseBodyAsString().contains("Error")); } + @Test + public void testCookiePassing() throws ServletException, IOException, SAXException { + GetMethod method = new GetMethod(getBaseUrl() + "/mod/cookie"); + method.setFollowRedirects(false); + method.setRequestHeader("Cookie", new Cookie("localhost", "Dummy", "TestValue").toExternalForm()); + client.executeMethod(method); + assertEquals(200, method.getStatusCode()); + assertEquals("Cookie-Servlet\nDummy: TestValue", method.getResponseBodyAsString()); + } } diff --git a/src/main/java/org/tuckey/web/filters/urlrewrite/utils/ModRewriteConfLoader.java b/src/main/java/org/tuckey/web/filters/urlrewrite/utils/ModRewriteConfLoader.java index 047c9abb..28779918 100644 --- a/src/main/java/org/tuckey/web/filters/urlrewrite/utils/ModRewriteConfLoader.java +++ b/src/main/java/org/tuckey/web/filters/urlrewrite/utils/ModRewriteConfLoader.java @@ -213,6 +213,8 @@ private NormalRule processRule(String line) { } else { log.error("cannot parse " + line); } + // mod_rewrite passes cookies through to the backend unmodified + rule.setDropCookies("false"); return rule; } diff --git a/src/test/java/org/tuckey/web/filters/urlrewrite/utils/ModRewriteConfLoaderTest.java b/src/test/java/org/tuckey/web/filters/urlrewrite/utils/ModRewriteConfLoaderTest.java index 7100c184..e0b9f54a 100644 --- a/src/test/java/org/tuckey/web/filters/urlrewrite/utils/ModRewriteConfLoaderTest.java +++ b/src/test/java/org/tuckey/web/filters/urlrewrite/utils/ModRewriteConfLoaderTest.java @@ -7,6 +7,7 @@ import java.io.IOException; import java.io.InputStream; +import java.lang.reflect.Field; public class ModRewriteConfLoaderTest extends TestCase { @@ -30,19 +31,25 @@ public void testEngine2() { assertFalse(conf.isEngineEnabled()); } - public void testLoadFromFile() throws IOException { + public void testLoadFromFile() throws Exception { InputStream is = ModRewriteConfLoaderTest.class.getResourceAsStream(BASE_PATH + "htaccess-test1.txt"); loader.process(is, conf); assertTrue(conf.isEngineEnabled()); assertEquals(1, conf.getRules().size()); + Field dropCookiesField = NormalRule.class.getDeclaredField("dropCookies"); + dropCookiesField.setAccessible(true); + assertFalse(dropCookiesField.getBoolean(conf.getRules().get(0))); } - public void testLoadFromFile2() throws IOException { + public void testLoadFromFile2() throws Exception { InputStream is = ModRewriteConfLoaderTest.class.getResourceAsStream(BASE_PATH + "htaccess-test1.txt"); Conf conf = new Conf(null, is, "htaccess-test1.txt", null, true); assertTrue(conf.isEngineEnabled()); assertTrue(conf.isOk()); assertEquals(1, conf.getRules().size()); + Field dropCookiesField = NormalRule.class.getDeclaredField("dropCookies"); + dropCookiesField.setAccessible(true); + assertFalse(dropCookiesField.getBoolean(conf.getRules().get(0))); } public void testSimple2() {