Bug 68495 - Unable to find match between the canonical context and the URI presented by the user agent
Summary: Unable to find match between the canonical context and the URI presented by t...
Status: RESOLVED FIXED
Alias: None
Product: Tomcat 9
Classification: Unclassified
Component: Catalina (show other bugs)
Version: 9.0.85
Hardware: PC All
: P2 normal (vote)
Target Milestone: -----
Assignee: Tomcat Developers Mailing List
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2024-01-17 06:13 UTC by Daniel Tschernatsch
Modified: 2024-03-02 10:31 UTC (History)
1 user (show)



Attachments
Sample web application to reproduce bug (5.90 KB, application/octet-stream)
2024-03-01 17:08 UTC, Noah Adams
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Daniel Tschernatsch 2024-01-17 06:13:24 UTC
It seems that Bug 66488 was never really fixed. Because we saw several occastion where the request URL was overwritten by other Header data like User agent (or parts of the URL were deleted) like in these two instances:

using Tomcat Embedded 9.0.83
java.lang.IllegalStateException: Unable to find match between the canonical context path [/app1] and the URI presented by the user agent [f=70d24a53-fe99-4f9c-a512-5f5abd5bce3]

or

using the Standalone Tomcat 9.0.85
java.lang.IllegalStateException: Unable to find match between the canonical context path [/app2] and the URI presented by the user agent [--WebKitFormBoundaryMVjw2B39oX3x4Oii]

The exception is thrown when a POST request was sent by the browser after the session timed out.

Workaround: Downgrade to Tomcat 9.0.35 (we didn't check later Versions in between the affected ones, yet).
Comment 1 Mark Thomas 2024-01-17 09:42:33 UTC
Are you using any sort of monitoring agent? There have been multiple issues around how these access MessageByte instances.
Comment 2 Mark Thomas 2024-01-25 17:15:21 UTC
No response after a week.

If the requested information is not provided, the issue will be closed as WORKSFORME.
Comment 3 Mark Thomas 2024-02-06 07:39:31 UTC
Closing as WORKSFORME due to lack of response from OP.

If you still experience this issue and wish to re-open this bug please provide the minimum steps necessary - including any web application with source - to reproduce this issue.
Comment 4 Noah Adams 2024-02-29 20:31:46 UTC
Also encountering this bug on upgrading from Tomcat 9.0.73 to 9.0.85

After the upgrade I can replicate by logging in, bringing up a page, letting my session expire and then submitting a POST.  It brings up the login page and then after logging in throws a server error 500.

Downgrading back to 9.0.73 worked to fix it.  I am not running any sort of monitoring agent.  It looks like the POST is getting mangled into a broken GET somehow?

From the access log:

10.64.249.226 - AN00040 [29/Feb/2024:13:53:24 -0600] "POST e=ryan&fname=ryan&bed=&ssn=&idnum=&topNavSearc HTTP/1.1" 500 1891

Error thrown:

Feb 29, 2024 1:53:24 PM org.apache.catalina.core.StandardHostValve custom
SEVERE: Exception Processing ErrorPage[errorCode=500, location=/error/ServletError.jsp]
java.lang.IllegalStateException: Unable to find match between the canonical context path [/conline] and the URI presented by the user agent [e=ryan&fname=ryan&bed=&ssn=&idnum=&topNavSearc]


We are running tomcat using Java 8 on a RHEL 7 machine.
Comment 5 Mark Thomas 2024-02-29 21:55:47 UTC
No reproducible test case provided as required in comment #3 - returning to WORKSFORME
Comment 6 Noah Adams 2024-03-01 03:48:09 UTC
Lol, I'll try to get you the test case tomorrow.  I assure you that this is a bug.
Comment 7 Noah Adams 2024-03-01 17:08:51 UTC
Created attachment 39607 [details]
Sample web application to reproduce bug

I am attaching a very simple web application that reliably reproduces this bug. To create this, I started with the "Hello World" Tomcat sample war and modified only hello.jsp, web.xml and added a Login.jsp.

This application is expecting an authentication realm named "cortrac-login". You could change this in web.xml. We are using Active Directory for authentication, but I wouldn't think that would matter.

To reproduce the bug:
1) Navigate to sample/hello.jsp. It should prompt you to login.
2) After logging in, let the session expire. I set the session timeout to 1 minute for easy testing
3) Click the button on the page. If your session expired, you should be prompted to login again and after you do, you will see the error.

Note the 2 lines in the hello.jsp
<%= request.getParameter("navCurrentRid") %> 
<%= request.getContextPath() %>


These 2 lines appear to be the core of the bug.  The request.getParameter seems to be corrupting the URI causing the request.getContextPath to error.

Please let me know if you need more information.
  -Noah

Error returned:

Type Exception Report

Message An exception occurred processing [/hello.jsp] at line [21]

Description The server encountered an unexpected condition that prevented it from fulfilling the request.

Exception

org.apache.jasper.JasperException: An exception occurred processing [/hello.jsp] at line [21]

18: </table>
19: 
20: <%= request.getParameter("navCurrentRid") %> 
21: <%= request.getContextPath() %>
22: 
23:                  <form  action="" method="post" id="quicksearchform" name="quicksearchform">
24: <input id="lname" name="lname" type="hidden"><input id="fname" name="fname" type="hidden"><input id="bed" name="bed" type="hidden"><input id="ssn" name="ssn" type="hidden"><input id="idnum" name="idnum" type="hidden"><input id="topNavSearch" name="topNavSearch" type="hidden" value="true">


Stacktrace:
	org.apache.jasper.servlet.JspServletWrapper.handleJspException(JspServletWrapper.java:610)
	org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:489)
	org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:379)
	org.apache.jasper.servlet.JspServlet.service(JspServlet.java:327)
	javax.servlet.http.HttpServlet.service(HttpServlet.java:623)
	org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
	org.apache.catalina.filters.HttpHeaderSecurityFilter.doFilter(HttpHeaderSecurityFilter.java:129)
Root Cause

java.lang.IllegalStateException: Unable to find match between the canonical context path [/sample] and the URI presented by the user agent [e=&fname=&bed=&ss]
	org.apache.catalina.connector.Request.getContextPath(Request.java:2136)
	org.apache.catalina.connector.RequestFacade.getContextPath(RequestFacade.java:583)
	org.apache.jsp.hello_jsp._jspService(hello_jsp.java:139)
	org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
	javax.servlet.http.HttpServlet.service(HttpServlet.java:623)
	org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:466)
	org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:379)
	org.apache.jasper.servlet.JspServlet.service(JspServlet.java:327)
	javax.servlet.http.HttpServlet.service(HttpServlet.java:623)
	org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
	org.apache.catalina.filters.HttpHeaderSecurityFilter.doFilter(HttpHeaderSecurityFilter.java:129)
Note The full stack trace of the root cause is available in the server logs.
Comment 8 Noah Adams 2024-03-01 17:09:53 UTC
Reopening the ticket based on providing a test case as requested.
Comment 9 Noah Adams 2024-03-01 18:54:58 UTC
Before you ask, I just replicated this on a clean install of 9.0.85

RHEL 9 JDK 8

I only edited tomcat_users.xml to uncomment the admin user and change the password

Note that to get the sample app to work with the UserDatabase realm, I had to edit the web.xml to change:  

<auth-constraint>
     <role-name>*</role-name>
</auth-constraint>

to:

<auth-constraint>
     <role-name>manager-gui</role-name>
</auth-constraint>

The cortrac-login realm name that I mentioned above doesn't seem to matter.

After this, the same steps as above replicate 

1) Navigate to sample/hello.jsp. It should prompt you to login.
2) After logging in, let the session expire. I set the session timeout to 1 minute for easy testing
3) Click the button on the page. If your session expired, you should be prompted to login again and after you do, you will see the error.
Comment 10 Chuck Caldarale 2024-03-01 22:30:21 UTC
I was able to reproduce the problem on 9.0.85, but not on 9.0.86 (nor on 11.0.0-M17). Looks like something fixed it recently, but there's nothing obvious to me in the changelog for 9.0.86.
Comment 11 Remy Maucherat 2024-03-01 23:52:09 UTC
Ok so maybe there's still something with the query string then.
Comment 12 Mark Thomas 2024-03-02 10:10:32 UTC
Thanks for the test case. I am able recreate the issue now.

The root cause is a combination of this code in the FormAuthenticator:
https://github.com/apache/tomcat/blob/9.0.x/java/org/apache/catalina/authenticator/FormAuthenticator.java#L637

and the changes to MessageBytes back in 9.0.0-M5 and the fix for bug 66627 in 9.0.77.

This has been partially fix in 9.0.86 as a side-effect of bug 68026 but it looks as if query string is still affected.

I have a more robust fix in mind that I want to test before committing. Assuming all goes well this should be fixed later today and included in the next release round.
Comment 13 Remy Maucherat 2024-03-02 10:14:08 UTC
I was planning to do:
    public String getQueryString() {
        return coyoteRequest.queryString().toStringType();
    }

Since the idea from the FormAuthenticator is to change the MessageBytes type to String and toString no longer does it (but toStringType does).
Comment 14 Mark Thomas 2024-03-02 10:26:37 UTC
That was my first thought but:
1. I didn't want correct behaviour of the FormAuthenticator to depend on caching decisions in Request that could - in theory - change over time
2. I didn't cache query string when I last looked at it as there were some usage patterns that could trigger conversion back to byte

My plan (which looks to work) is to call toStringType() directly from FormAuthenticator
Comment 15 Mark Thomas 2024-03-02 10:31:21 UTC
Fixed in:
- 11.0.x for 11.0.0-M18 onwards
- 10.1.x for 10.1.20 onwards
-  9.0.x for  9.0.87 onwards
-  8.5.x for  8.5.100 onwards