mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2026-02-05 01:11:51 +01:00
MINOR: http-ana: Use proxy's error replies to emit 401/407 responses
There is no reason to not use proxy's error replies to emit 401/407 responses. The function http_reply_40x_unauthorized(), responsible to emit those responses, is not really complex. It only adds a WWW-Authenticate/Proxy-Authenticate header to a generic message. So now, error replies can be defined for 401 and 407 status codes, using errorfile or http-error directives. When an http-request auth rule is evaluated, the corresponding error reply is used. For 401 responses, all occurrences of the WWW-Authenticate header are removed and replaced by a new one with a basic authentication challenge for the configured realm. For 407 responses, the same is done on the Proxy-Authenticate header. If the error reply must not be altered, "http-request return" rule must be used instead.
This commit is contained in:
parent
ae43b6c446
commit
612f2eafe9
@ -2522,8 +2522,8 @@ errorfile <code> <file>
|
||||
|
||||
Arguments :
|
||||
<code> is the HTTP status code. Currently, HAProxy is capable of
|
||||
generating codes 200, 400, 403, 404, 405, 408, 410, 425, 429,
|
||||
500, 502, 503, and 504.
|
||||
generating codes 200, 400, 401, 403, 404, 405, 407, 408, 410,
|
||||
425, 429, 500, 502, 503, and 504.
|
||||
|
||||
<file> designates a file containing the full HTTP response. It is
|
||||
recommended to follow the common practice of appending ".http" to
|
||||
@ -3859,8 +3859,8 @@ errorfile <code> <file>
|
||||
yes | yes | yes | yes
|
||||
Arguments :
|
||||
<code> is the HTTP status code. Currently, HAProxy is capable of
|
||||
generating codes 200, 400, 403, 404, 405, 408, 410, 425, 429, 500,
|
||||
502, 503, and 504.
|
||||
generating codes 200, 400, 401, 403, 404, 405, 407, 408, 410,
|
||||
425, 429, 500, 502, 503, and 504.
|
||||
|
||||
<file> designates a file containing the full HTTP response. It is
|
||||
recommended to follow the common practice of appending ".http" to
|
||||
@ -3908,8 +3908,8 @@ errorfiles <name> [<code> ...]
|
||||
<name> is the name of an existing http-errors section.
|
||||
|
||||
<code> is a HTTP status code. Several status code may be listed.
|
||||
Currently, HAProxy is capable of generating codes 200, 400, 403,
|
||||
404, 405, 408, 410, 425, 429, 500, 502, 503, and 504.
|
||||
Currently, HAProxy is capable of generating codes 200, 400, 401,
|
||||
403, 404, 405, 407, 408, 410, 425, 429, 500, 502, 503, and 504.
|
||||
|
||||
Errors defined in the http-errors section with the name <name> are imported
|
||||
in the current proxy. If no status code is specified, all error files of the
|
||||
@ -3934,8 +3934,8 @@ errorloc302 <code> <url>
|
||||
yes | yes | yes | yes
|
||||
Arguments :
|
||||
<code> is the HTTP status code. Currently, HAProxy is capable of
|
||||
generating codes 200, 400, 403, 404, 405, 408, 410, 425, 429, 500,
|
||||
502, 503, and 504.
|
||||
generating codes 200, 400, 401, 403, 404, 405, 407, 408, 410,
|
||||
425, 429, 500, 502, 503, and 504.
|
||||
|
||||
<url> it is the exact contents of the "Location" header. It may contain
|
||||
either a relative URI to an error page hosted on the same site,
|
||||
@ -3966,8 +3966,8 @@ errorloc303 <code> <url>
|
||||
yes | yes | yes | yes
|
||||
Arguments :
|
||||
<code> is the HTTP status code. Currently, HAProxy is capable of
|
||||
generating codes 200, 400, 403, 404, 405, 408, 410, 425, 429, 500,
|
||||
502, 503, and 504.
|
||||
generating codes 200, 400, 401, 403, 404, 405, 407, 408, 410,
|
||||
425, 429, 500, 502, 503, and 504.
|
||||
|
||||
<url> it is the exact contents of the "Location" header. It may contain
|
||||
either a relative URI to an error page hosted on the same site,
|
||||
@ -4942,8 +4942,8 @@ http-error status <code> [content-type <type>]
|
||||
Arguments :
|
||||
staus <code> is the HTTP status code. It must be specified.
|
||||
Currently, HAProxy is capable of generating codes
|
||||
200, 400, 403, 404, 405, 408, 410, 425, 429, 500,
|
||||
502, 503, and 504.
|
||||
200, 400, 401, 403, 404, 405, 407, 408, 410, 425, 429,
|
||||
500, 502, 503, and 504.
|
||||
|
||||
content-type <type> is the response content type, for instance
|
||||
"text/plain". This parameter is ignored and should be
|
||||
@ -5095,6 +5095,14 @@ http-request auth [realm <realm>] [ { if | unless } <condition> ]
|
||||
"realm" parameter is supported, it sets the authentication realm that is
|
||||
returned with the response (typically the application's name).
|
||||
|
||||
The corresponding proxy's error message is used. It may be customized using
|
||||
an "errorfile" or an "http-error" directive. For 401 responses, all
|
||||
occurrences of the WWW-Authenticate header are removed and replaced by a new
|
||||
one with a basic authentication challenge for realm "<realm>". For 407
|
||||
responses, the same is done on the Proxy-Authenticate header. If the error
|
||||
message must not be altered, consider to use "http-request return" rule
|
||||
instead.
|
||||
|
||||
Example:
|
||||
acl auth_ok http_auth_group(L1) G1
|
||||
http-request auth unless auth_ok
|
||||
|
||||
@ -82,9 +82,11 @@ enum ht_auth_m {
|
||||
enum {
|
||||
HTTP_ERR_200 = 0,
|
||||
HTTP_ERR_400,
|
||||
HTTP_ERR_401,
|
||||
HTTP_ERR_403,
|
||||
HTTP_ERR_404,
|
||||
HTTP_ERR_405,
|
||||
HTTP_ERR_407,
|
||||
HTTP_ERR_408,
|
||||
HTTP_ERR_410,
|
||||
HTTP_ERR_421,
|
||||
|
||||
22
src/http.c
22
src/http.c
@ -215,9 +215,11 @@ const char *HTTP_407_fmt =
|
||||
const int http_err_codes[HTTP_ERR_SIZE] = {
|
||||
[HTTP_ERR_200] = 200, /* used by "monitor-uri" */
|
||||
[HTTP_ERR_400] = 400,
|
||||
[HTTP_ERR_401] = 401,
|
||||
[HTTP_ERR_403] = 403,
|
||||
[HTTP_ERR_404] = 404,
|
||||
[HTTP_ERR_405] = 405,
|
||||
[HTTP_ERR_407] = 407,
|
||||
[HTTP_ERR_408] = 408,
|
||||
[HTTP_ERR_410] = 410,
|
||||
[HTTP_ERR_421] = 421,
|
||||
@ -248,6 +250,15 @@ const char *http_err_msgs[HTTP_ERR_SIZE] = {
|
||||
"\r\n"
|
||||
"<html><body><h1>400 Bad request</h1>\nYour browser sent an invalid request.\n</body></html>\n",
|
||||
|
||||
[HTTP_ERR_401] =
|
||||
"HTTP/1.1 401 Unauthorized\r\n"
|
||||
"Content-length: 112\r\n"
|
||||
"Cache-Control: no-cache\r\n"
|
||||
"Connection: close\r\n"
|
||||
"Content-Type: text/html\r\n"
|
||||
"\r\n"
|
||||
"<html><body><h1>401 Unauthorized</h1>\nYou need a valid user and password to access this content.\n</body></html>\n",
|
||||
|
||||
[HTTP_ERR_403] =
|
||||
"HTTP/1.1 403 Forbidden\r\n"
|
||||
"Content-length: 93\r\n"
|
||||
@ -275,6 +286,15 @@ const char *http_err_msgs[HTTP_ERR_SIZE] = {
|
||||
"\r\n"
|
||||
"<html><body><h1>405 Method Not Allowed</h1>\nA request was made of a resource using a request method not supported by that resource\n</body></html>\n",
|
||||
|
||||
[HTTP_ERR_407] =
|
||||
"HTTP/1.1 407 Unauthorized\r\n"
|
||||
"Content-length: 112\r\n"
|
||||
"Cache-Control: no-cache\r\n"
|
||||
"Connection: close\r\n"
|
||||
"Content-Type: text/html\r\n"
|
||||
"\r\n"
|
||||
"<html><body><h1>407 Unauthorized</h1>\nYou need a valid user and password to access this content.\n</body></html>\n",
|
||||
|
||||
[HTTP_ERR_408] =
|
||||
"HTTP/1.1 408 Request Time-out\r\n"
|
||||
"Content-length: 110\r\n"
|
||||
@ -396,9 +416,11 @@ int http_get_status_idx(unsigned int status)
|
||||
switch (status) {
|
||||
case 200: return HTTP_ERR_200;
|
||||
case 400: return HTTP_ERR_400;
|
||||
case 401: return HTTP_ERR_401;
|
||||
case 403: return HTTP_ERR_403;
|
||||
case 404: return HTTP_ERR_404;
|
||||
case 405: return HTTP_ERR_405;
|
||||
case 407: return HTTP_ERR_407;
|
||||
case 408: return HTTP_ERR_408;
|
||||
case 410: return HTTP_ERR_410;
|
||||
case 421: return HTTP_ERR_421;
|
||||
|
||||
@ -4910,61 +4910,54 @@ 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 htx_sl *sl;
|
||||
struct ist code, body;
|
||||
int status;
|
||||
unsigned int flags = (HTX_SL_F_IS_RESP|HTX_SL_F_VER_11);
|
||||
struct http_reply *reply;
|
||||
struct http_hdr_ctx ctx;
|
||||
struct ist hdr;
|
||||
|
||||
if (!(s->txn->flags & TX_USE_PX_CONN)) {
|
||||
status = 401;
|
||||
code = ist("401");
|
||||
body = ist("<html><body><h1>401 Unauthorized</h1>\n"
|
||||
"You need a valid user and password to access this content.\n"
|
||||
"</body></html>\n");
|
||||
s->txn->status = 401;
|
||||
hdr = ist("WWW-Authenticate");
|
||||
}
|
||||
else {
|
||||
status = 407;
|
||||
code = ist("407");
|
||||
body = ist("<html><body><h1>407 Unauthorized</h1>\n"
|
||||
"You need a valid user and password to access this content.\n"
|
||||
"</body></html>\n");
|
||||
s->txn->status = 407;
|
||||
hdr = ist("Proxy-Authenticate");
|
||||
}
|
||||
|
||||
sl = htx_add_stline(htx, HTX_BLK_RES_SL, flags,
|
||||
ist("HTTP/1.1"), code, ist("Unauthorized"));
|
||||
if (!sl)
|
||||
goto fail;
|
||||
sl->info.res.status = status;
|
||||
s->txn->status = status;
|
||||
reply = http_error_message(s);
|
||||
channel_htx_truncate(res, htx);
|
||||
|
||||
if (chunk_printf(&trash, "Basic realm=\"%s\"", auth_realm) == -1)
|
||||
goto fail;
|
||||
|
||||
if (!htx_add_header(htx, ist("Content-length"), ist("112")) ||
|
||||
!htx_add_header(htx, ist("Cache-Control"), ist("no-cache")) ||
|
||||
!htx_add_header(htx, ist("Connection"), ist("close")) ||
|
||||
!htx_add_header(htx, ist("Content-Type"), ist("text/html")))
|
||||
goto fail;
|
||||
if (status == 401 && !htx_add_header(htx, ist("WWW-Authenticate"), ist2(trash.area, trash.data)))
|
||||
goto fail;
|
||||
if (status == 407 && !htx_add_header(htx, ist("Proxy-Authenticate"), ist2(trash.area, trash.data)))
|
||||
goto fail;
|
||||
if (!htx_add_endof(htx, HTX_BLK_EOH))
|
||||
/* Write the generic 40x message */
|
||||
if (http_reply_to_htx(s, htx, reply) == -1)
|
||||
goto fail;
|
||||
|
||||
while (body.len) {
|
||||
size_t sent = htx_add_data(htx, body);
|
||||
if (!sent)
|
||||
goto fail;
|
||||
body.ptr += sent;
|
||||
body.len -= sent;
|
||||
}
|
||||
/* 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);
|
||||
|
||||
if (!htx_add_endof(htx, HTX_BLK_EOM))
|
||||
/* 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:
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user