mod_proxy: Add support for an optional third argument to ProxyRemote*
to configure the Basic auth credentials to send to the remote proxy.
(Note that credentials are always sent w/o waiting for a challenge as
with proxy-chain-auth, and only Basic is supported - both of which are
not exactly ideal - but better than nothing.)
* modules/proxy/mod_proxy.h (struct proxy_remote): Add creds field.
* modules/proxy/mod_proxy.c (proxy_handler): Pass forward proxy
credentials via r->notes.
(add_proxy): Take credentials and base64-encode into ->creds field if
passed.
(add_proxy_noregex, add_proxy_regex): Take optional creds argument.
* modules/proxy/proxy_util.c (ap_proxy_determine_connection):
Use proxy credentials from r->notes if available.
(ap_proxy_create_hdrbrgd): Set Proxy-Authorization header from
credentials in r->notes if present.
PR: 37355
Github: closes #135
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1881790 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/changes-entries/pr37355.txt b/changes-entries/pr37355.txt
new file mode 100644
index 0000000..3fbf5c7
--- /dev/null
+++ b/changes-entries/pr37355.txt
@@ -0,0 +1,3 @@
+ *) mod_proxy: Add optional third argument for ProxyRemote, which
+ configures Basic authentication credentials to pass to the remote
+ proxy. PR 37355. [Joe Orton]
diff --git a/docs/manual/mod/mod_proxy.xml b/docs/manual/mod/mod_proxy.xml
index 99659a0..ec7c2af 100644
--- a/docs/manual/mod/mod_proxy.xml
+++ b/docs/manual/mod/mod_proxy.xml
@@ -671,9 +671,10 @@
<directivesynopsis>
<name>ProxyRemote</name>
<description>Remote proxy used to handle certain requests</description>
-<syntax>ProxyRemote <var>match</var> <var>remote-server</var></syntax>
+<syntax>ProxyRemote <var>match</var> <var>remote-server</var> [<var>username:password</var>]</syntax>
<contextlist><context>server config</context><context>virtual host</context>
</contextlist>
+<compatibility>The optional third argument is usable only in httpd 2.5.1 and later.</compatibility>
<usage>
<p>This defines remote proxies to this proxy. <var>match</var> is either the
@@ -707,6 +708,15 @@
<p>This option also supports reverse proxy configuration; a backend
webserver can be embedded within a virtualhost URL space even if that
server is hidden by another forward proxy.</p>
+
+ <p>An optional third argument <var>username:password</var> may be
+ given, which defines the Basic authentication credentials to pass
+ to the configured remote proxy. The credentials will always be
+ sent without first waiting for the remote proxy to send a Basic
+ authentication challenge. The <a
+ href="mod_proxy_http.html#env">Proxy-Chain-Auth</a> environment
+ variable has no effect if this argument is used.</p>
+
</usage>
</directivesynopsis>
diff --git a/modules/proxy/mod_proxy.c b/modules/proxy/mod_proxy.c
index 33060b0..c01cdc6 100644
--- a/modules/proxy/mod_proxy.c
+++ b/modules/proxy/mod_proxy.c
@@ -1461,11 +1461,20 @@
/* handle the scheme */
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01142)
"Trying to run scheme_handler against proxy");
+
+ if (ents[i].creds) {
+ apr_table_set(r->notes, "proxy-basic-creds", ents[i].creds);
+ ap_log_rerror(APLOG_MARK, APLOG_TRACE1, 0, r,
+ "Using proxy auth creds %s", ents[i].creds);
+ }
+
access_status = proxy_run_scheme_handler(r, worker,
conf, url,
ents[i].hostname,
ents[i].port);
+ if (ents[i].creds) apr_table_unset(r->notes, "proxy-basic-creds");
+
/* Did the scheme handler process the request? */
if (access_status != DECLINED) {
const char *cl_a;
@@ -1917,8 +1926,8 @@
return new;
}
-static const char *
- add_proxy(cmd_parms *cmd, void *dummy, const char *f1, const char *r1, int regex)
+static const char *add_proxy(cmd_parms *cmd, void *dummy, const char *f1,
+ const char *r1, const char *creds, int regex)
{
server_rec *s = cmd->server;
proxy_server_conf *conf =
@@ -1976,19 +1985,24 @@
new->port = port;
new->regexp = reg;
new->use_regex = regex;
+ if (creds) {
+ new->creds = apr_pstrcat(cmd->pool, "Basic ",
+ ap_pbase64encode(cmd->pool, (char *)creds),
+ NULL);
+ }
return NULL;
}
-static const char *
- add_proxy_noregex(cmd_parms *cmd, void *dummy, const char *f1, const char *r1)
+static const char *add_proxy_noregex(cmd_parms *cmd, void *dummy, const char *f1,
+ const char *r1, const char *creds)
{
- return add_proxy(cmd, dummy, f1, r1, 0);
+ return add_proxy(cmd, dummy, f1, r1, creds, 0);
}
-static const char *
- add_proxy_regex(cmd_parms *cmd, void *dummy, const char *f1, const char *r1)
+static const char *add_proxy_regex(cmd_parms *cmd, void *dummy, const char *f1,
+ const char *r1, const char *creds)
{
- return add_proxy(cmd, dummy, f1, r1, 1);
+ return add_proxy(cmd, dummy, f1, r1, creds, 1);
}
PROXY_DECLARE(const char *) ap_proxy_de_socketfy(apr_pool_t *p, const char *url)
@@ -3046,9 +3060,9 @@
"location, in regular expression syntax"),
AP_INIT_FLAG("ProxyRequests", set_proxy_req, NULL, RSRC_CONF,
"on if the true proxy requests should be accepted"),
- AP_INIT_TAKE2("ProxyRemote", add_proxy_noregex, NULL, RSRC_CONF,
+ AP_INIT_TAKE23("ProxyRemote", add_proxy_noregex, NULL, RSRC_CONF,
"a scheme, partial URL or '*' and a proxy server"),
- AP_INIT_TAKE2("ProxyRemoteMatch", add_proxy_regex, NULL, RSRC_CONF,
+ AP_INIT_TAKE23("ProxyRemoteMatch", add_proxy_regex, NULL, RSRC_CONF,
"a regex pattern and a proxy server"),
AP_INIT_FLAG("ProxyPassInterpolateEnv", ap_set_flag_slot_char,
(void*)APR_OFFSETOF(proxy_dir_conf, interpolate_env),
diff --git a/modules/proxy/mod_proxy.h b/modules/proxy/mod_proxy.h
index 6f7d0b2..664ee0b 100644
--- a/modules/proxy/mod_proxy.h
+++ b/modules/proxy/mod_proxy.h
@@ -116,6 +116,7 @@
const char *protocol; /* the scheme used to talk to this proxy */
const char *hostname; /* the hostname of this proxy */
ap_regex_t *regexp; /* compiled regex (if any) for the remote */
+ const char *creds; /* auth credentials (if any) for the proxy */
int use_regex; /* simple boolean. True if we have a regex pattern */
apr_port_t port; /* the port for this proxy */
};
diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c
index 85af865..7d9ea17 100644
--- a/modules/proxy/proxy_util.c
+++ b/modules/proxy/proxy_util.c
@@ -2562,11 +2562,15 @@
* So let's make it configurable by env.
* The logic here is the same used in mod_proxy_http.
*/
- proxy_auth = apr_table_get(r->headers_in, "Proxy-Authorization");
+ proxy_auth = apr_table_get(r->notes, "proxy-basic-creds");
+ if (proxy_auth == NULL)
+ proxy_auth = apr_table_get(r->headers_in, "Proxy-Authorization");
+
if (proxy_auth != NULL &&
proxy_auth[0] != '\0' &&
- (r->user == NULL || /* we haven't yet authenticated */
- apr_table_get(r->subprocess_env, "Proxy-Chain-Auth"))) {
+ (r->user == NULL /* we haven't yet authenticated */
+ || apr_table_get(r->subprocess_env, "Proxy-Chain-Auth")
+ || apr_table_get(r->notes, "proxy-basic-creds"))) {
forward->proxy_auth = apr_pstrdup(conn->pool, proxy_auth);
}
}
@@ -2798,7 +2802,8 @@
nbytes = apr_snprintf(buffer, sizeof(buffer),
"CONNECT %s:%d HTTP/1.0" CRLF,
forward->target_host, forward->target_port);
- /* Add proxy authorization from the initial request if necessary */
+ /* Add proxy authorization from the configuration, or initial
+ * request if necessary */
if (forward->proxy_auth != NULL) {
nbytes += apr_snprintf(buffer + nbytes, sizeof(buffer) - nbytes,
"Proxy-Authorization: %s" CRLF,
@@ -3741,7 +3746,7 @@
apr_bucket *e;
int do_100_continue;
conn_rec *origin = p_conn->connection;
- const char *fpr1;
+ const char *fpr1, *creds;
proxy_dir_conf *dconf = ap_get_module_config(r->per_dir_config, &proxy_module);
/*
@@ -3920,6 +3925,11 @@
return HTTP_BAD_REQUEST;
}
+ creds = apr_table_get(r->notes, "proxy-basic-creds");
+ if (creds) {
+ apr_table_mergen(r->headers_in, "Proxy-Authorization", creds);
+ }
+
/* send request headers */
headers_in_array = apr_table_elts(r->headers_in);
headers_in = (const apr_table_entry_t *) headers_in_array->elts;