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.
This commit is contained in:
Christopher Faulet 2020-05-27 15:26:43 +02:00
parent 612f2eafe9
commit b304883754
3 changed files with 82 additions and 88 deletions

View File

@ -89,7 +89,6 @@ enum act_name {
/* http request actions. */ /* http request actions. */
ACT_HTTP_REQ_TARPIT, ACT_HTTP_REQ_TARPIT,
ACT_HTTP_REQ_AUTH,
/* tcp actions */ /* tcp actions */
ACT_TCP_EXPECT_PX, ACT_TCP_EXPECT_PX,

View File

@ -25,6 +25,7 @@
#include <common/initcall.h> #include <common/initcall.h>
#include <common/memory.h> #include <common/memory.h>
#include <common/standard.h> #include <common/standard.h>
#include <common/uri_auth.h>
#include <common/version.h> #include <common/version.h>
#include <types/capture.h> #include <types/capture.h>
@ -884,6 +885,85 @@ static enum act_parse_ret parse_http_deny(const char **args, int *orig_arg, stru
return ACT_RET_PRS_OK; 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" /* 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. * parameter. It returns ACT_RET_PRS_OK on success, ACT_RET_PRS_ERR on error.
*/ */
@ -892,8 +972,9 @@ static enum act_parse_ret parse_http_auth(const char **args, int *orig_arg, stru
{ {
int cur_arg; int cur_arg;
rule->action = ACT_HTTP_REQ_AUTH; rule->action = ACT_CUSTOM;
rule->flags |= ACT_FLAG_FINAL; rule->flags |= ACT_FLAG_FINAL;
rule->action_ptr = http_action_auth;
rule->release_ptr = release_http_action; rule->release_ptr = release_http_action;
cur_arg = *orig_arg; cur_arg = *orig_arg;

View File

@ -63,7 +63,6 @@ static int http_handle_stats(struct stream *s, struct channel *req);
static int http_handle_expect_hdr(struct stream *s, struct htx *htx, struct http_msg *msg); 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_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 /* 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 * processing can continue on next analysers, or zero if it either needs more
@ -2824,7 +2823,6 @@ static enum rule_result http_req_get_intercept_rule(struct proxy *px, struct lis
struct htx *htx; struct htx *htx;
struct act_rule *rule; struct act_rule *rule;
struct http_hdr_ctx ctx; struct http_hdr_ctx ctx;
const char *auth_realm;
enum rule_result rule_ret = HTTP_RULE_RES_CONT; enum rule_result rule_ret = HTTP_RULE_RES_CONT;
int act_opts = 0; int act_opts = 0;
@ -2920,25 +2918,6 @@ static enum rule_result http_req_get_intercept_rule(struct proxy *px, struct lis
rule_ret = HTTP_RULE_RES_DENY; rule_ret = HTTP_RULE_RES_DENY;
goto end; 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: case ACT_HTTP_REDIR:
rule_ret = HTTP_RULE_RES_ABRT; rule_ret = HTTP_RULE_RES_ABRT;
if (!http_apply_redirect_rule(rule->arg.redir, s, txn)) if (!http_apply_redirect_rule(rule->arg.redir, s, txn))
@ -4902,71 +4881,6 @@ static int http_reply_100_continue(struct stream *s)
} }
/* 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 * Capture headers from message <htx> according to header list <cap_hdr>, and
* fill the <cap> pointers appropriately. * fill the <cap> pointers appropriately.