MINOR: http-rules: Use an action function to eval http-request auth rules
Now http-request auth rules are evaluated in a dedicated function and no longer
handled "in place" during the HTTP rules evaluation. Thus the action name
ACT_HTTP_REQ_AUTH is removed. In additionn, http_reply_40x_unauthorized() is
also removed. This part is now handled in the new action_ptr callback function.
diff --git a/include/types/action.h b/include/types/action.h
index b01380c..00c37fa 100644
--- a/include/types/action.h
+++ b/include/types/action.h
@@ -89,7 +89,6 @@
/* http request actions. */
ACT_HTTP_REQ_TARPIT,
- ACT_HTTP_REQ_AUTH,
/* tcp actions */
ACT_TCP_EXPECT_PX,
diff --git a/src/http_act.c b/src/http_act.c
index ab4a8bb..b18da61 100644
--- a/src/http_act.c
+++ b/src/http_act.c
@@ -25,6 +25,7 @@
#include <common/initcall.h>
#include <common/memory.h>
#include <common/standard.h>
+#include <common/uri_auth.h>
#include <common/version.h>
#include <types/capture.h>
@@ -884,6 +885,85 @@
return ACT_RET_PRS_OK;
}
+
+/* This function executes a auth action. It builds an 401/407 HTX message using
+ * the corresponding proxy's error message. On success, it returns
+ * ACT_RET_ABRT. If an error occurs ACT_RET_ERR is returned.
+ */
+static enum act_return http_action_auth(struct act_rule *rule, struct proxy *px,
+ struct session *sess, struct stream *s, int flags)
+{
+ struct channel *req = &s->req;
+ struct channel *res = &s->res;
+ struct htx *htx = htx_from_buf(&res->buf);
+ struct http_reply *reply;
+ const char *auth_realm;
+ struct http_hdr_ctx ctx;
+ struct ist hdr;
+
+ /* Auth might be performed on regular http-req rules as well as on stats */
+ auth_realm = rule->arg.http.str.ptr;
+ if (!auth_realm) {
+ if (px->uri_auth && s->current_rule_list == &px->uri_auth->http_req_rules)
+ auth_realm = STATS_DEFAULT_REALM;
+ else
+ auth_realm = px->id;
+ }
+
+ if (!(s->txn->flags & TX_USE_PX_CONN)) {
+ s->txn->status = 401;
+ hdr = ist("WWW-Authenticate");
+ }
+ else {
+ s->txn->status = 407;
+ hdr = ist("Proxy-Authenticate");
+ }
+ reply = http_error_message(s);
+ channel_htx_truncate(res, htx);
+
+ if (chunk_printf(&trash, "Basic realm=\"%s\"", auth_realm) == -1)
+ goto fail;
+
+ /* Write the generic 40x message */
+ if (http_reply_to_htx(s, htx, reply) == -1)
+ goto fail;
+
+ /* Remove all existing occurrences of the XXX-Authenticate header */
+ ctx.blk = NULL;
+ while (http_find_header(htx, hdr, &ctx, 1))
+ http_remove_header(htx, &ctx);
+
+ /* Now a the right XXX-Authenticate header */
+ if (!http_add_header(htx, hdr, ist2(b_orig(&trash), b_data(&trash))))
+ goto fail;
+
+ /* Finally forward the reply */
+ htx_to_buf(htx, &res->buf);
+ if (!http_forward_proxy_resp(s, 1))
+ goto fail;
+
+ /* Note: Only eval on the request */
+ s->logs.tv_request = now;
+ req->analysers &= AN_REQ_FLT_END;
+
+ if (s->sess->fe == s->be) /* report it if the request was intercepted by the frontend */
+ _HA_ATOMIC_ADD(&s->sess->fe->fe_counters.intercepted_req, 1);
+
+ if (!(s->flags & SF_ERR_MASK))
+ s->flags |= SF_ERR_LOCAL;
+ if (!(s->flags & SF_FINST_MASK))
+ s->flags |= SF_FINST_R;
+
+ stream_inc_http_err_ctr(s);
+ return ACT_RET_ABRT;
+
+ fail:
+ /* If an error occurred, remove the incomplete HTTP response from the
+ * buffer */
+ channel_htx_truncate(res, htx);
+ return ACT_RET_ERR;
+}
+
/* Parse a "auth" action. It may take 2 optional arguments to define a "realm"
* parameter. It returns ACT_RET_PRS_OK on success, ACT_RET_PRS_ERR on error.
*/
@@ -892,8 +972,9 @@
{
int cur_arg;
- rule->action = ACT_HTTP_REQ_AUTH;
+ rule->action = ACT_CUSTOM;
rule->flags |= ACT_FLAG_FINAL;
+ rule->action_ptr = http_action_auth;
rule->release_ptr = release_http_action;
cur_arg = *orig_arg;
diff --git a/src/http_ana.c b/src/http_ana.c
index e239f7c..cf9570c 100644
--- a/src/http_ana.c
+++ b/src/http_ana.c
@@ -63,7 +63,6 @@
static int http_handle_expect_hdr(struct stream *s, struct htx *htx, struct http_msg *msg);
static int http_reply_100_continue(struct stream *s);
-static int http_reply_40x_unauthorized(struct stream *s, const char *auth_realm);
/* This stream analyser waits for a complete HTTP request. It returns 1 if the
* processing can continue on next analysers, or zero if it either needs more
@@ -2824,7 +2823,6 @@
struct htx *htx;
struct act_rule *rule;
struct http_hdr_ctx ctx;
- const char *auth_realm;
enum rule_result rule_ret = HTTP_RULE_RES_CONT;
int act_opts = 0;
@@ -2920,25 +2918,6 @@
rule_ret = HTTP_RULE_RES_DENY;
goto end;
- case ACT_HTTP_REQ_AUTH:
- /* Auth might be performed on regular http-req rules as well as on stats */
- auth_realm = rule->arg.http.str.ptr;
- if (!auth_realm) {
- if (px->uri_auth && rules == &px->uri_auth->http_req_rules)
- auth_realm = STATS_DEFAULT_REALM;
- else
- auth_realm = px->id;
- }
- /* send 401/407 depending on whether we use a proxy or not. We still
- * count one error, because normal browsing won't significantly
- * increase the counter but brute force attempts will.
- */
- rule_ret = HTTP_RULE_RES_ABRT;
- if (http_reply_40x_unauthorized(s, auth_realm) == -1)
- rule_ret = HTTP_RULE_RES_ERROR;
- stream_inc_http_err_ctr(s);
- goto end;
-
case ACT_HTTP_REDIR:
rule_ret = HTTP_RULE_RES_ABRT;
if (!http_apply_redirect_rule(rule->arg.redir, s, txn))
@@ -4902,71 +4881,6 @@
}
-/* Send a 401-Unauthorized or 407-Unauthorized response to the client, depending
- * ont whether we use a proxy or not. It returns 0 on success and -1 on
- * error. The response channel is updated accordingly.
- */
-static int http_reply_40x_unauthorized(struct stream *s, const char *auth_realm)
-{
- struct channel *res = &s->res;
- struct htx *htx = htx_from_buf(&res->buf);
- struct http_reply *reply;
- struct http_hdr_ctx ctx;
- struct ist hdr;
-
- if (!(s->txn->flags & TX_USE_PX_CONN)) {
- s->txn->status = 401;
- hdr = ist("WWW-Authenticate");
- }
- else {
- s->txn->status = 407;
- hdr = ist("Proxy-Authenticate");
- }
- reply = http_error_message(s);
- channel_htx_truncate(res, htx);
-
- if (chunk_printf(&trash, "Basic realm=\"%s\"", auth_realm) == -1)
- goto fail;
-
- /* Write the generic 40x message */
- if (http_reply_to_htx(s, htx, reply) == -1)
- goto fail;
-
- /* Remove all existing occurrences of the XXX-Authenticate header */
- ctx.blk = NULL;
- while (http_find_header(htx, hdr, &ctx, 1))
- http_remove_header(htx, &ctx);
-
- /* Now a the right XXX-Authenticate header */
- if (!http_add_header(htx, hdr, ist2(b_orig(&trash), b_data(&trash))))
- goto fail;
-
- /* Finally forward the reply */
- htx_to_buf(htx, &res->buf);
- if (!http_forward_proxy_resp(s, 1))
- goto fail;
-
- /* Note: Only eval on the request */
- s->logs.tv_request = now;
- s->req.analysers &= AN_REQ_FLT_END;
-
- if (s->sess->fe == s->be) /* report it if the request was intercepted by the frontend */
- _HA_ATOMIC_ADD(&s->sess->fe->fe_counters.intercepted_req, 1);
-
- if (!(s->flags & SF_ERR_MASK))
- s->flags |= SF_ERR_LOCAL;
- if (!(s->flags & SF_FINST_MASK))
- s->flags |= SF_FINST_R;
-
- return 0;
-
- fail:
- /* If an error occurred, remove the incomplete HTTP response from the
- * buffer */
- channel_htx_truncate(res, htx);
- return -1;
-}
-
/*
* Capture headers from message <htx> according to header list <cap_hdr>, and
* fill the <cap> pointers appropriately.