Bug 64537 - ProxyPassMatch with mod_proxy_ajp ignores AJP secret
Summary: ProxyPassMatch with mod_proxy_ajp ignores AJP secret
Status: NEEDINFO
Alias: None
Product: Apache httpd-2
Classification: Unclassified
Component: mod_proxy_ajp (show other bugs)
Version: 2.4.43
Hardware: PC Linux
: P2 normal (vote)
Target Milestone: ---
Assignee: Apache HTTPD Bugs Mailing List
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2020-06-19 10:26 UTC by Cedric Roijakkers
Modified: 2022-09-29 10:34 UTC (History)
2 users (show)



Attachments
ap_proxy_define_match_worker() (12.52 KB, patch)
2020-06-19 15:29 UTC, Yann Ylavic
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Cedric Roijakkers 2020-06-19 10:26:56 UTC
We have an application running onder Spring Boot, which uses Tomcat to serve http pages. We are connecting with http to Tomcat using the AJP protocol.

The version of Tomcat used in Spring Boot is 9.0.34, and for the AJP connector we have enabled an AJP secret for extra security.

Now, when proxying to this Tomcat server with ProxyPass, this all works fine:

ProxyPass /foo ajp://ajp_host:ajp_port/tomcat/foo retry=0 secret=le_secret

But recentry, we've introduced some configuration that parts of the proxied URLs need to go to a different backend application. For this, the configuration now looks like this:

ProxyPassMatch "^/foo/bar/([0-9]+)/baz$" "ajp://ajp_host1:ajp_port1/tomcat/foo/bar/$1/baz" retry=0 secret=${le_secret}
ProxyPass /foo ajp://ajp_host2:ajp_port2/tomcat/foo retry=0 secret=le_secret

As you can see, the idea is that certain parts under /foo/bar end up on server one, while all the rest under /foo ends up on server two.

This results in HTTP 403 errors when connecting to server one, as if the AJP secret is not being sent to Tomcat.

So my assumption here, is that ProxyPassMatch ignores the secret being passed as an argument.

Interestingly enough, if we configure both Proxy rules to the same backend server as such:

ProxyPassMatch "^/foo/bar/([0-9]+)/baz$" "ajp://ajp_host1:ajp_port1/tomcat/foo/bar/$1/baz" retry=0 secret=${le_secret}
ProxyPass /foo ajp://ajp_host1:ajp_port1/tomcat/foo retry=0 secret=le_secret

Then everything actually works. I suspect this happens because both the ProxyPass line and the ProxyPassMatch line use the same connection pool to Tomcat under water, which does have the secret set (from the ProxyPass line I presume) and it works by accident.

For now, I've worked around the issue by disabling the secret in Tomcat, and then I can see the traffic nicely being split between the two different Tomcats, but I would like to enable the secret again as soon as the issue is fixed.
Comment 1 Yann Ylavic 2020-06-19 10:52:03 UTC
Does it change anything if you declare the ProxyPass before the ProxyPassMatch?
Comment 2 Cedric Roijakkers 2020-06-19 11:03:11 UTC
In this specific case that would not help, since the ProxyPass /foo declared before the ProxyPassMatch /foo/bar (and the rest of the regex) would send all traffic over the first proxy rule, instead of splitting it over the two, so that defied the purpose of my configuration.
Comment 3 Yann Ylavic 2020-06-19 15:29:36 UTC
Created attachment 37318 [details]
ap_proxy_define_match_worker()

Can you please try this patch?

This looks like the same issue as bug 43513. The fixes are in trunk but were never backported to 2.4.
Comment 4 Cedric Roijakkers 2020-06-29 08:27:49 UTC
I've given your patch a test, and indeed this seems to solve the issue.

I've re-enabled the secret in our Tomcat application, and I can see the secret is now correctly being used in all different connection pools to the different Tomcat instances. The same configuration that was previously generating 403 errors is now working as expected.

Would it be possible to backport this fix to the 2.4 branch for next release? For now, we'll just keep using this patch in our production environment.
Comment 5 Cedric Roijakkers 2020-08-27 11:37:46 UTC
Update from the trenches: we've been running this patch for a few months in production now, and it has solved the problem. Can it be backported to 2.4 and included in a following release?
Comment 6 Cedric Roijakkers 2021-07-09 11:58:59 UTC
I was upgrading our Apache server, and wanted to apply this patch since we've been using it for a long time (and need it), but am I right and has this now beed added to release 2.4.48?
Comment 7 Cedric Roijakkers 2022-09-28 13:05:08 UTC
It's been over a year since my last comment in this thread. We've been running in production with the patch supplied in this bug, everything is working fine. The latest httpd release is now 2.4.54 and this patch has still not made it into the release. We've recently ran into this bug again when using vanilla httpd in a project instead of the custom patched httpd. When will this patch finally make it into a release?
Comment 8 Ruediger Pluem 2022-09-28 14:19:46 UTC
This should be fixed in 2.4.54. The code evolved further from the patch attached here. Please retry with 2.4.54.
Comment 9 Cedric Roijakkers 2022-09-29 10:34:19 UTC
Version 2.4.54 is what I tried with, that got me fooled by looking into this issue again. To be more precise, I based my container on top of docker container httpd:2.4.54-alpine3.16. The full httpd -V output in that container is:

Server version: Apache/2.4.54 (Unix)
Server built:   Jul 18 2022 23:35:13
Server's Module Magic Number: 20120211:124
Server loaded:  APR 1.7.0, APR-UTIL 1.6.1, PCRE 8.45 2021-06-15
Compiled using: APR 1.7.0, APR-UTIL 1.6.1, PCRE 8.45 2021-06-15
Architecture:   64-bit
Server MPM:     event
  threaded:     yes (fixed thread count)
    forked:     yes (variable process count)
Server compiled with....
 -D APR_HAS_SENDFILE
 -D APR_HAS_MMAP
 -D APR_HAVE_IPV6 (IPv4-mapped addresses enabled)
 -D APR_USE_PROC_PTHREAD_SERIALIZE
 -D APR_USE_PTHREAD_SERIALIZE
 -D SINGLE_LISTEN_UNSERIALIZED_ACCEPT
 -D APR_HAS_OTHER_CHILD
 -D AP_HAVE_RELIABLE_PIPED_LOGS
 -D DYNAMIC_MODULE_LIMIT=256
 -D HTTPD_ROOT="/usr/local/apache2"
 -D SUEXEC_BIN="/usr/local/apache2/bin/suexec"
 -D DEFAULT_PIDLOG="logs/httpd.pid"
 -D DEFAULT_SCOREBOARD="logs/apache_runtime_status"
 -D DEFAULT_ERRORLOG="logs/error_log"
 -D AP_TYPES_CONFIG_FILE="conf/mime.types"
 -D SERVER_CONFIG_FILE="conf/httpd.conf"