Merge ~ahasenack/ubuntu/+source/apache2:focal-apache2-ajp-secret into ubuntu/+source/apache2:ubuntu/devel

Proposed by Andreas Hasenack
Status: Merged
Approved by: Andreas Hasenack
Approved revision: cd2d8271579104b7dc9e8254c7bee4d4c1021e17
Merge reported by: Andreas Hasenack
Merged at revision: cd2d8271579104b7dc9e8254c7bee4d4c1021e17
Proposed branch: ~ahasenack/ubuntu/+source/apache2:focal-apache2-ajp-secret
Merge into: ubuntu/+source/apache2:ubuntu/devel
Diff against target: 259 lines (+231/-0)
4 files modified
debian/changelog (+7/-0)
debian/patches/mod_proxy_ajp-secret-parameter-doc.patch (+32/-0)
debian/patches/mod_proxy_ajp-secret-parameter.patch (+190/-0)
debian/patches/series (+2/-0)
Reviewer Review Type Date Requested Status
Christian Ehrhardt  (community) Approve
Thomas (community) test Approve
Canonical Server Pending
Review via email: mp+380324@code.launchpad.net

Description of the change

Bring into apache 2.4.41 a 2.4.42 feature required to have apache proxy connections to a tomcat9 9.0.31 server via AJP. The bug contains the details.

This is almost a straight pull from upstream's commit. I noted my changes in the DEP3 headers of the patches.

Here are testing instructions:
sudo apt install tomcat9 apache2 tomcat9-examples
sudo a2enmod proxy_ajp
# edit /etc/apache2/sites-enabled/000-default.conf and add this line:
ProxyPass "/examples" "ajp://localhost:8009/examples"
sudo systemctl restart apache2

# edit /etc/tomcat9/server.xml, locate the "Define an AJP 1.3 Connector on port 8009" section and define the connector like this:
    <Connector protocol="AJP/1.3"
               address="0.0.0.0"
               secret="supersecret"
               port="8009" />

# if we didn't add a secret to the connector configuration, tomcat9 would fail to start it, because a secret is mandatory by default since 9.0.13.

# restart tomcat9
sudo systemctl restart tomcat9

# Let's confirm tomcat9 is working
curl http://localhost:8080

# And the examples page which is what we will proxy through apache later:
curl http://localhost:8080/examples/

# we want to access that via apache, but it won't work now because we didn't configure the same secret on apache's side. You will get back a nasty 403:
curl http://localhost/examples/
<!doctype html><html lang="en"><head><title>HTTP Status 403 ......

# now let's add the secret keyword to apache's /etc/apache2/sites-enabled/000-default.conf:

        ProxyPass "/examples" "ajp://localhost:8009/examples" secret=supersecret

# apache2 will fail to restart, as it doesn't understand the "secret" parameter
sudo systemctl restart apache2

# update to the apache packages from the ppa
sudo add-apt-repository ppa:ahasenack/apache2-mod-ajp-secret -y -u
sudo apt install apache2 -y

# Try the examples page via apache again, and this time we get the examples through apache
curl http://localhost/examples/

To post a comment you must log in.
Revision history for this message
Thomas (lostexception) wrote :

Don't know if this is relevant, but Andreas' mod_proxy_ajp now works for my use case. The only problem I had is that (unlike the URLs and paths) the secret on the Apache side *must not* be quoted, but this is probably by design.

review: Approve (test)
Revision history for this message
Christian Ehrhardt  (paelzer) wrote :

+1 from a packaging POV as well

There is a very minor whitespace damage (empty line at the end of d/p/series), but other than that I'm totally happy with the suggested MP.

review: Approve
Revision history for this message
Andreas Hasenack (ahasenack) wrote :

> Don't know if this is relevant, but Andreas' mod_proxy_ajp now works for my
> use case. The only problem I had is that (unlike the URLs and paths) the
> secret on the Apache side *must not* be quoted, but this is probably by
> design.

I was hit by that same problem when I was testing it, and also found it surprising.

Revision history for this message
Andreas Hasenack (ahasenack) wrote :

> +1 from a packaging POV as well
>
> There is a very minor whitespace damage (empty line at the end of d/p/series),
> but other than that I'm totally happy with the suggested MP.

Oops, fixed, thanks

Revision history for this message
Andreas Hasenack (ahasenack) wrote :

I just realized that the test procedure from this MP could easily be made a DEP8 test in the tomcat9 package

Revision history for this message
Andreas Hasenack (ahasenack) wrote :
Revision history for this message
Andreas Hasenack (ahasenack) wrote :

Tagging and uploading cd2d8271579104b7dc9e8254c7bee4d4c1021e17

$ git push pkg upload/2.4.41-4ubuntu2
Enumerating objects: 23, done.
Counting objects: 100% (23/23), done.
Delta compression using up to 4 threads
Compressing objects: 100% (12/12), done.
Writing objects: 100% (15/15), 4.93 KiB | 84.00 KiB/s, done.
Total 15 (delta 10), reused 3 (delta 3)
remote: Checking connectivity: 15, done.
To ssh://git.launchpad.net/~usd-import-team/ubuntu/+source/apache2

$ dput ubuntu ../apache2_2.4.41-4ubuntu2_source.changes
Checking signature on .changes
gpg: ../apache2_2.4.41-4ubuntu2_source.changes: Valid signature from AC983EB5BF6BCBA9
Checking signature on .dsc
gpg: ../apache2_2.4.41-4ubuntu2.dsc: Valid signature from AC983EB5BF6BCBA9
Uploading to ubuntu (via ftp to upload.ubuntu.com):
  Uploading apache2_2.4.41-4ubuntu2.dsc: done.
  Uploading apache2_2.4.41-4ubuntu2.debian.tar.xz: done.
  Uploading apache2_2.4.41-4ubuntu2_source.buildinfo: done.
  Uploading apache2_2.4.41-4ubuntu2_source.changes: done.
Successfully uploaded packages.

Revision history for this message
Andreas Hasenack (ahasenack) wrote :

This migrated.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/debian/changelog b/debian/changelog
2index b23967b..1e8587a 100644
3--- a/debian/changelog
4+++ b/debian/changelog
5@@ -1,3 +1,10 @@
6+apache2 (2.4.41-4ubuntu2) focal; urgency=medium
7+
8+ * d/p/mod_proxy_ajp-secret-parameter*.patch: add new "secret"
9+ parameter to mod_proxy_ajp (LP: #1865340)
10+
11+ -- Andreas Hasenack <andreas@canonical.com> Thu, 05 Mar 2020 15:51:00 -0300
12+
13 apache2 (2.4.41-4ubuntu1) focal; urgency=medium
14
15 * Merge with Debian unstable. Remaining changes:
16diff --git a/debian/patches/mod_proxy_ajp-secret-parameter-doc.patch b/debian/patches/mod_proxy_ajp-secret-parameter-doc.patch
17new file mode 100644
18index 0000000..c422949
19--- /dev/null
20+++ b/debian/patches/mod_proxy_ajp-secret-parameter-doc.patch
21@@ -0,0 +1,32 @@
22+From 4de7604dd086c7bebdcab4ae9dbbec24b59edabc Mon Sep 17 00:00:00 2001
23+From: Jean-Frederic Clere <jfclere@apache.org>
24+Date: Thu, 27 Feb 2020 10:31:45 +0000
25+Subject: [PATCH] Doc for secret in AJP.
26+
27+git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1874564 13f79535-47bb-0310-9956-ffa450edef68
28+---
29+ docs/manual/mod/mod_proxy_ajp.html.en | 1 +
30+ docs/manual/mod/mod_proxy_ajp.xml | 1 +
31+ 2 files changed, 2 insertions(+)
32+
33+ Ubuntu notes:
34+ - removed reference to the "secret" parameter being available since
35+ apache 2.4.42, since this is 2.4.41 at the moment.
36+ - removed hunk that patched the xml source file, since it's not shipped in
37+ the release tarball
38+
39+Origin: https://github.com/apache/httpd/commit/4de7604dd086c7bebdcab4ae9dbbec24b59edabc
40+Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/apache2/+bug/1865340
41+Last-Update: 2020-03-05
42+diff --git a/docs/manual/mod/mod_proxy_ajp.html.en b/docs/manual/mod/mod_proxy_ajp.html.en
43+index f8427717792..b5e765ba3c9 100644
44+--- a/docs/manual/mod/mod_proxy_ajp.html.en
45++++ b/docs/manual/mod/mod_proxy_ajp.html.en
46+@@ -482,6 +482,7 @@ attribute_value := (string)</pre></div>
47+ <tr><td>?req_attribute</td><td>0x0A</td><td>String</td><td>Name (the name of the
48+ attribute follows)</td></tr>
49+ <tr><td>?ssl_key_size</td><td>0x0B</td><td>Integer</td><td /></tr>
50++ <tr><td>?secret</td><td>0x0C</td><td>String</td><td /></tr>
51+ <tr><td>are_done</td><td>0xFF</td><td>-</td><td>request_terminator</td></tr>
52+ </table>
53+ <p>The <code>context</code> and <code>servlet_path</code> are not
54diff --git a/debian/patches/mod_proxy_ajp-secret-parameter.patch b/debian/patches/mod_proxy_ajp-secret-parameter.patch
55new file mode 100644
56index 0000000..6a4fbd5
57--- /dev/null
58+++ b/debian/patches/mod_proxy_ajp-secret-parameter.patch
59@@ -0,0 +1,190 @@
60+From d8b6d798c177dfdb90cef1a29395afcc043f3c86 Mon Sep 17 00:00:00 2001
61+From: Rainer Jung <rjung@apache.org>
62+Date: Mon, 24 Feb 2020 15:18:33 +0000
63+Subject: [PATCH] mod_proxy_ajp: Add "secret" parameter to proxy workers to
64+ implement legacy AJP13 authentication. PR 53098. The attribute is now
65+ suggested/required by tomcat.
66+
67+Backport of r1738878 from trunk.
68+
69+Backported by: covener
70+Reviewed by: covener, jorton, rjung
71+
72+
73+git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1874456 13f79535-47bb-0310-9956-ffa450edef68
74+---
75+ CHANGES | 3 +++
76+ docs/manual/mod/mod_proxy.xml | 6 ++++--
77+ modules/proxy/ajp.h | 4 +++-
78+ modules/proxy/ajp_header.c | 16 ++++++++--------
79+ modules/proxy/mod_proxy.c | 6 ++++++
80+ modules/proxy/mod_proxy.h | 2 ++
81+ modules/proxy/mod_proxy_ajp.c | 6 +++++-
82+ 7 files changed, 31 insertions(+), 12 deletions(-)
83+
84+ Ubuntu notes:
85+ - removed CHANGES hunk
86+ - updated mod_proxy html instead of xml (no xml in the release tarball)
87+ - dropped reference to release 2.4.42 in the html doc update since this
88+ is 2.4.41 still
89+
90+Origin: https://github.com/apache/httpd/commit/d8b6d798c177dfdb90cef1a29395afcc043f3c86
91+Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/apache2/+bug/1865340
92+Last-Update: 2020-03-05
93+
94+diff --git a/docs/manual/mod/mod_proxy.html.en b/docs/manual/mod/mod_proxy.html.en
95+index d533ddeed0..b3c272d3ee 100644
96+--- a/docs/manual/mod/mod_proxy.html.en
97++++ b/docs/manual/mod/mod_proxy.html.en
98+@@ -1360,8 +1360,9 @@ ProxyPass "/mirror/foo" "http://backend.example.com"</pre>
99+ </td></tr>
100+ <tr><td>secret</td>
101+ <td>-</td>
102+- <td><p>Value of secret used by <code class="module"><a href="../mod/mod_proxy_ajp.html">mod_proxy_ajp</a></code>.
103+- See the documentation of this module for more details.</p>
104++ <td>Value of secret used by <module>mod_proxy_ajp</module>.
105++ It must be identical to the secret configured on the server side of the
106++ AJP connection.<br />
107+ </td></tr>
108+ <tr><td>upgrade</td>
109+ <td>WebSocket</td>
110+diff --git a/modules/proxy/ajp.h b/modules/proxy/ajp.h
111+index c119a7ee64f..a950ee9edd2 100644
112+--- a/modules/proxy/ajp.h
113++++ b/modules/proxy/ajp.h
114+@@ -414,11 +414,13 @@ apr_status_t ajp_ilink_receive(apr_socket_t *sock, ajp_msg_t *msg);
115+ * @param r current request
116+ * @param buffsize max size of the AJP packet.
117+ * @param uri requested uri
118++ * @param secret authentication secret
119+ * @return APR_SUCCESS or error
120+ */
121+ apr_status_t ajp_send_header(apr_socket_t *sock, request_rec *r,
122+ apr_size_t buffsize,
123+- apr_uri_t *uri);
124++ apr_uri_t *uri,
125++ const char *secret);
126+
127+ /**
128+ * Read the ajp message and return the type of the message.
129+diff --git a/modules/proxy/ajp_header.c b/modules/proxy/ajp_header.c
130+index ab1092e95a0..76989c8df7f 100644
131+--- a/modules/proxy/ajp_header.c
132++++ b/modules/proxy/ajp_header.c
133+@@ -214,7 +214,8 @@ AJPV13_REQUEST/AJPV14_REQUEST=
134+
135+ static apr_status_t ajp_marshal_into_msgb(ajp_msg_t *msg,
136+ request_rec *r,
137+- apr_uri_t *uri)
138++ apr_uri_t *uri,
139++ const char *secret)
140+ {
141+ int method;
142+ apr_uint32_t i, num_headers = 0;
143+@@ -294,17 +295,15 @@ static apr_status_t ajp_marshal_into_msgb(ajp_msg_t *msg,
144+ i, elts[i].key, elts[i].val);
145+ }
146+
147+-/* XXXX need to figure out how to do this
148+- if (s->secret) {
149++ if (secret) {
150+ if (ajp_msg_append_uint8(msg, SC_A_SECRET) ||
151+- ajp_msg_append_string(msg, s->secret)) {
152++ ajp_msg_append_string(msg, secret)) {
153+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(03228)
154+- "Error ajp_marshal_into_msgb - "
155++ "ajp_marshal_into_msgb: "
156+ "Error appending secret");
157+ return APR_EGENERAL;
158+ }
159+ }
160+- */
161+
162+ if (r->user) {
163+ if (ajp_msg_append_uint8(msg, SC_A_REMOTE_USER) ||
164+@@ -672,7 +671,8 @@ static apr_status_t ajp_unmarshal_response(ajp_msg_t *msg,
165+ apr_status_t ajp_send_header(apr_socket_t *sock,
166+ request_rec *r,
167+ apr_size_t buffsize,
168+- apr_uri_t *uri)
169++ apr_uri_t *uri,
170++ const char *secret)
171+ {
172+ ajp_msg_t *msg;
173+ apr_status_t rc;
174+@@ -684,7 +684,7 @@ apr_status_t ajp_send_header(apr_socket_t *sock,
175+ return rc;
176+ }
177+
178+- rc = ajp_marshal_into_msgb(msg, r, uri);
179++ rc = ajp_marshal_into_msgb(msg, r, uri, secret);
180+ if (rc != APR_SUCCESS) {
181+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, APLOGNO(00988)
182+ "ajp_send_header: ajp_marshal_into_msgb failed");
183+diff --git a/modules/proxy/mod_proxy.c b/modules/proxy/mod_proxy.c
184+index ba4a9374077..2521c6511ba 100644
185+--- a/modules/proxy/mod_proxy.c
186++++ b/modules/proxy/mod_proxy.c
187+@@ -327,6 +327,12 @@ static const char *set_worker_param(apr_pool_t *p,
188+ worker->s->response_field_size = (s ? s : HUGE_STRING_LEN);
189+ worker->s->response_field_size_set = 1;
190+ }
191++ else if (!strcasecmp(key, "secret")) {
192++ if (PROXY_STRNCPY(worker->s->secret, val) != APR_SUCCESS) {
193++ return apr_psprintf(p, "Secret length must be < %d characters",
194++ (int)sizeof(worker->s->secret));
195++ }
196++ }
197+ else {
198+ if (set_worker_hc_param_f) {
199+ return set_worker_hc_param_f(p, s, worker, key, val, NULL);
200+diff --git a/modules/proxy/mod_proxy.h b/modules/proxy/mod_proxy.h
201+index 15c2d961025..895b9370882 100644
202+--- a/modules/proxy/mod_proxy.h
203++++ b/modules/proxy/mod_proxy.h
204+@@ -362,6 +362,7 @@ PROXY_WORKER_HC_FAIL )
205+ #define PROXY_WORKER_MAX_HOSTNAME_SIZE 64
206+ #define PROXY_BALANCER_MAX_HOSTNAME_SIZE PROXY_WORKER_MAX_HOSTNAME_SIZE
207+ #define PROXY_BALANCER_MAX_STICKY_SIZE 64
208++#define PROXY_WORKER_MAX_SECRET_SIZE 64
209+
210+ #define PROXY_RFC1035_HOSTNAME_SIZE 256
211+
212+@@ -464,6 +465,7 @@ typedef struct {
213+ char hostname_ex[PROXY_RFC1035_HOSTNAME_SIZE]; /* RFC1035 compliant version of the remote backend address */
214+ apr_size_t response_field_size; /* Size of proxy response buffer in bytes. */
215+ unsigned int response_field_size_set:1;
216++ char secret[PROXY_WORKER_MAX_SECRET_SIZE]; /* authentication secret (e.g. AJP13) */
217+ } proxy_worker_shared;
218+
219+ #define ALIGNED_PROXY_WORKER_SHARED_SIZE (APR_ALIGN_DEFAULT(sizeof(proxy_worker_shared)))
220+diff --git a/modules/proxy/mod_proxy_ajp.c b/modules/proxy/mod_proxy_ajp.c
221+index 7b22109a35f..8579fb5d860 100644
222+--- a/modules/proxy/mod_proxy_ajp.c
223++++ b/modules/proxy/mod_proxy_ajp.c
224+@@ -193,6 +193,7 @@ static int ap_proxy_ajp_request(apr_pool_t *p, request_rec *r,
225+ apr_off_t content_length = 0;
226+ int original_status = r->status;
227+ const char *original_status_line = r->status_line;
228++ const char *secret = NULL;
229+
230+ if (psf->io_buffer_size_set)
231+ maxsize = psf->io_buffer_size;
232+@@ -202,12 +203,15 @@ static int ap_proxy_ajp_request(apr_pool_t *p, request_rec *r,
233+ maxsize = AJP_MSG_BUFFER_SZ;
234+ maxsize = APR_ALIGN(maxsize, 1024);
235+
236++ if (*conn->worker->s->secret)
237++ secret = conn->worker->s->secret;
238++
239+ /*
240+ * Send the AJP request to the remote server
241+ */
242+
243+ /* send request headers */
244+- status = ajp_send_header(conn->sock, r, maxsize, uri);
245++ status = ajp_send_header(conn->sock, r, maxsize, uri, secret);
246+ if (status != APR_SUCCESS) {
247+ conn->close = 1;
248+ ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, APLOGNO(00868)
249+
250diff --git a/debian/patches/series b/debian/patches/series
251index 207d9c8..3278e1a 100644
252--- a/debian/patches/series
253+++ b/debian/patches/series
254@@ -11,3 +11,5 @@ spelling-errors.patch
255
256 # Patches added by Ubuntu
257 086_svn_cross_compiles
258+mod_proxy_ajp-secret-parameter-doc.patch
259+mod_proxy_ajp-secret-parameter.patch

Subscribers

People subscribed via source and target branches