This is an automated email from the ASF dual-hosted git repository. rmaucher pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/tomcat.git
commit 8bd952e0cce2230a2ff2409652a151a1a348f44c Author: opencode <[email protected]> AuthorDate: Mon Oct 12 14:36:34 2026 +0200 Do not resolve REMOTE_IDENT to the authenticated user in rewrite valve REMOTE_IDENT is the RFC 931 ident protocol user name, a variable Tomcat never supported since there is no ident client. ResolverImpl resolved it as request.getRemoteUser(), silently turning any rule filtering on %{REMOTE_IDENT} into an authentication check, and vice versa turning access control intent on ident into an unintended authentication test. Drop the case so REMOTE_IDENT resolves to undefined, which the substitution machinery expands to an empty string, matching mod_rewrite with ident disabled and the empty REMOTE_IDENT CGI environment value that CGIServlet already produces. List REMOTE_IDENT among the not implemented variables, add a regression test that authenticates a request before the rewrite valve and asserts REMOTE_USER still resolves while REMOTE_IDENT is empty, and add a changelog entry for this change in rule semantics. --- .../catalina/valves/rewrite/ResolverImpl.java | 6 ++- .../catalina/valves/rewrite/TestRewriteValve.java | 47 ++++++++++++++++++++++ webapps/docs/changelog.xml | 7 ++++ 3 files changed, 59 insertions(+), 1 deletion(-) diff --git a/java/org/apache/catalina/valves/rewrite/ResolverImpl.java b/java/org/apache/catalina/valves/rewrite/ResolverImpl.java index 9f7877d86a..01d1ef0679 100644 --- a/java/org/apache/catalina/valves/rewrite/ResolverImpl.java +++ b/java/org/apache/catalina/valves/rewrite/ResolverImpl.java @@ -80,6 +80,7 @@ public class ResolverImpl extends Resolver { * <li>SERVER_ADMIN</li> * <li>API_VERSION</li> * <li>IS_SUBREQ</li> + * <li>REMOTE_IDENT (no RFC 931 ident protocol support)</li> * </ul> */ @Override @@ -101,7 +102,10 @@ public class ResolverImpl extends Resolver { case "REMOTE_HOST" -> request.getRemoteHost(); case "REMOTE_PORT" -> String.valueOf(request.getRemotePort()); case "REMOTE_USER" -> request.getRemoteUser(); - case "REMOTE_IDENT" -> request.getRemoteUser(); + // REMOTE_IDENT is the RFC 931 ident protocol user name, which + // Tomcat does not support. It must not resolve to the remote + // user, as that would silently turn ident-based rules into + // authentication checks. case "REQUEST_METHOD" -> request.getMethod(); case "SCRIPT_FILENAME" -> request.getServletContext().getRealPath(request.getServletPath()); case "REQUEST_PATH" -> request.getRequestPathMB().toString(); diff --git a/test/org/apache/catalina/valves/rewrite/TestRewriteValve.java b/test/org/apache/catalina/valves/rewrite/TestRewriteValve.java index e566bf7b02..dcd32c8139 100644 --- a/test/org/apache/catalina/valves/rewrite/TestRewriteValve.java +++ b/test/org/apache/catalina/valves/rewrite/TestRewriteValve.java @@ -22,6 +22,7 @@ import java.io.PrintWriter; import java.net.HttpURLConnection; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; +import java.security.Principal; import java.time.LocalDate; import java.util.Arrays; import java.util.HashMap; @@ -359,6 +360,52 @@ public class TestRewriteValve extends TomcatBaseTest { "/c/x", "/c/x", null, expected + "TUE" + expected); } + @Test + public void testRemoteIdentIsNotTheRemoteUser() throws Exception { + // REMOTE_IDENT is the RFC 931 ident protocol user name, which Tomcat + // does not support. It must resolve to undefined (expanding to an + // empty string), not to the authenticated user name that REMOTE_USER + // returns. + String config = "RewriteRule ^/c/x$ - " + + "[E=X-Test:user=%{REMOTE_USER}+ident=%{REMOTE_IDENT}]\n"; + + Tomcat tomcat = getTomcatInstance(); + Context ctx = getProgrammaticRootContext(); + + // Authenticate the request before the rewrite valve runs + ctx.getPipeline().addValve(new ValveBase() { + @Override + public void invoke(Request request, Response response) + throws IOException, ServletException { + request.setUserPrincipal(new Principal() { + @Override + public String getName() { + return "testuser"; + } + }); + getNext().invoke(request, response); + } + }); + + RewriteValve rewriteValve = new RewriteValve(); + ctx.getPipeline().addValve(rewriteValve); + rewriteValve.setConfiguration(config); + + Tomcat.addServlet(ctx, "snoop", new SnoopServlet()); + ctx.addServletMapping("/c/*", "snoop"); + + tomcat.start(); + + ByteChunk res = new ByteChunk(); + int rc = methodUrl("http://localhost:" + getPort() + "/c/x", res, + DEFAULT_CLIENT_TIMEOUT_MS, null, null, Method.GET, true); + Assert.assertEquals(200, rc); + res.setCharset(StandardCharsets.UTF_8); + RequestDescriptor requestDesc = SnoopResult.parse(res.toString()); + Assert.assertEquals("user=testuser+ident=", + requestDesc.getAttribute("X-Test")); + } + @Test public void testRewriteMissingCurlyBraceOnVar() throws Exception { try { diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml index 97bfacff93..fa3f64049f 100644 --- a/webapps/docs/changelog.xml +++ b/webapps/docs/changelog.xml @@ -375,6 +375,13 @@ mod_rewrite values (month 1-12, day of week 0-6 with Sunday being 0). (remm) </fix> + <fix> + Stop resolving the <code>REMOTE_IDENT</code> server variable of the + rewrite valve to the authenticated user name. <code>REMOTE_IDENT</code> + is the RFC 931 ident protocol user name, which Tomcat does not support. + It now resolves to undefined, expanding to an empty string, instead of + silently turning ident-based rules into authentication checks. (remm) + </fix> </changelog> </subsection> <subsection name="Coyote"> --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
