mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-09-23 14:51:27 +02:00
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:
parent
612f2eafe9
commit
b304883754
@ -89,7 +89,6 @@ enum act_name {
|
||||
|
||||
/* http request actions. */
|
||||
ACT_HTTP_REQ_TARPIT,
|
||||
ACT_HTTP_REQ_AUTH,
|
||||
|
||||
/* tcp actions */
|
||||
ACT_TCP_EXPECT_PX,
|
||||
|
@ -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 @@ static enum act_parse_ret parse_http_deny(const char **args, int *orig_arg, stru
|
||||
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 @@ static enum act_parse_ret parse_http_auth(const char **args, int *orig_arg, stru
|
||||
{
|
||||
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;
|
||||
|
@ -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_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 @@ static enum rule_result http_req_get_intercept_rule(struct proxy *px, struct lis
|
||||
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 @@ static enum rule_result http_req_get_intercept_rule(struct proxy *px, struct lis
|
||||
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 @@ 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
|
||||
* fill the <cap> pointers appropriately.
|
||||
|
Loading…
x
Reference in New Issue
Block a user