@cryptotaxi247 / netdata-1 / commits / b04cf5930

return 412 instead of 403 when a bearer token is required (#15808)

Costa Tsaousis committed Aug 14, 2023 at 23:18 UTC b04cf59304462691fa69326b10d7255eef3e8c27
4 files changed +38 -15
registry/registry.c
+1
@@ -192,6 +192,7 @@ int registry_request_hello_json(RRDHOST *host, struct web_client *w) {
192
193 buffer_json_member_add_string(w->response.data, "registry", registry.registry_to_announce);
194 buffer_json_member_add_boolean(w->response.data, "anonymous_statistics", netdata_anonymous_statistics_enabled);
195 + buffer_json_member_add_boolean(w->response.data, "X-Netdata-Auth", true);
196
197 buffer_json_member_add_array(w->response.data, "nodes");
198 RRDHOST *h;
web/api/web_api.c
+21 -10
@@ -5,27 +5,27 @@
5 bool netdata_is_protected_by_bearer = false; // this is controlled by cloud, at the point the agent logs in - this should also be saved to /var/lib/netdata
6 DICTIONARY *netdata_authorized_bearers = NULL;
7
8 -static bool web_client_check_acl_and_bearer(struct web_client *w, WEB_CLIENT_ACL endpoint_acl) {
8 +static short int web_client_check_acl_and_bearer(struct web_client *w, WEB_CLIENT_ACL endpoint_acl) {
9 if(endpoint_acl == WEB_CLIENT_ACL_NONE || (endpoint_acl & WEB_CLIENT_ACL_NOCHECK))
10 // the endpoint is totally public
11 - return true;
11 + return HTTP_RESP_OK;
12
13 bool acl_allows = w->acl & endpoint_acl;
14 if(!acl_allows)
15 // the channel we received the request from (w->acl) is not compatible with the endpoint
16 - return false;
16 + return HTTP_RESP_FORBIDDEN;
17
18 if(!netdata_is_protected_by_bearer && !(endpoint_acl & WEB_CLIENT_ACL_BEARER_REQUIRED))
19 // bearer protection is not enabled and is not required by the endpoint
20 - return true;
20 + return HTTP_RESP_OK;
21
22 if(!(endpoint_acl & (WEB_CLIENT_ACL_BEARER_REQUIRED|WEB_CLIENT_ACL_BEARER_OPTIONAL)))
23 // endpoint does not require a bearer
24 - return true;
24 + return HTTP_RESP_OK;
25
26 if((w->acl & (WEB_CLIENT_ACL_ACLK|WEB_CLIENT_ACL_WEBRTC)))
27 // the request is coming from ACLK or WEBRTC (authorized already),
28 - return true;
28 + return HTTP_RESP_OK;
29
30 // at this point we need a bearer to serve the request
31 // either because:
@@ -37,11 +37,11 @@ static bool web_client_check_acl_and_bearer(struct web_client *w, WEB_CLIENT_ACL
37 BEARER_STATUS t = api_check_bearer_token(w);
38 if(t == BEARER_STATUS_AVAILABLE_AND_VALIDATED)
39 // we have a valid bearer on the request
40 - return true;
40 + return HTTP_RESP_OK;
41
42 netdata_log_info("BEARER: bearer is required for request: code %d", t);
43
44 - return false;
44 + return HTTP_RESP_PRECOND_FAIL;
45 }
46
47 int web_client_api_request_vX(RRDHOST *host, struct web_client *w, char *url_path_endpoint, struct web_api_command *api_commands) {
@@ -73,8 +73,19 @@ int web_client_api_request_vX(RRDHOST *host, struct web_client *w, char *url_pat
73 return HTTP_RESP_BAD_REQUEST;
74 }
75
76 - if(unlikely(!web_client_check_acl_and_bearer(w, api_commands[i].acl)))
77 - return web_client_permission_denied(w);
76 + short int code = web_client_check_acl_and_bearer(w, api_commands[i].acl);
77 + if(code != HTTP_RESP_OK) {
78 + if(code == HTTP_RESP_FORBIDDEN)
79 + return web_client_permission_denied(w);
80 +
81 + if(code == HTTP_RESP_PRECOND_FAIL)
82 + return web_client_bearer_required(w);
83 +
84 + buffer_flush(w->response.data);
85 + buffer_sprintf(w->response.data, "Failed with code %d", code);
86 + w->response.code = code;
87 + return code;
88 + }
89
90 char *query_string = (char *)buffer_tostring(w->url_query_string_decoded);
91
web/api/web_api_v2.c
+14 -3
@@ -53,16 +53,27 @@ static time_t bearer_get_token(uuid_t *uuid) {
53 }
54
55 #define HTTP_REQUEST_AUTHORIZATION_BEARER "\r\nAuthorization: Bearer "
56 +#define HTTP_REQUEST_X_NETDATA_AUTH_BEARER "\r\nX-Netdata-Auth: Bearer "
57
58 BEARER_STATUS extract_bearer_token_from_request(struct web_client *w, char *dst, size_t dst_len) {
59 const char *req = buffer_tostring(w->response.data);
60 size_t req_len = buffer_strlen(w->response.data);
60 - const char *bearer = strcasestr(req, HTTP_REQUEST_AUTHORIZATION_BEARER);
61 + const char *bearer = NULL;
62 + const char *bearer_end = NULL;
63 +
64 + bearer = strcasestr(req, HTTP_REQUEST_X_NETDATA_AUTH_BEARER);
65 + if(bearer)
66 + bearer_end = bearer + sizeof(HTTP_REQUEST_X_NETDATA_AUTH_BEARER) - 1;
67 + else {
68 + bearer = strcasestr(req, HTTP_REQUEST_AUTHORIZATION_BEARER);
69 + if(bearer)
70 + bearer_end = bearer + sizeof(HTTP_REQUEST_AUTHORIZATION_BEARER) - 1;
71 + }
72
62 - if(!bearer)
73 + if(!bearer || !bearer_end)
74 return BEARER_STATUS_NO_BEARER_IN_HEADERS;
75
65 - const char *token_start = bearer + sizeof(HTTP_REQUEST_AUTHORIZATION_BEARER) - 1;
76 + const char *token_start = bearer_end;
77
78 while(isspace(*token_start))
79 token_start++;
web/server/web_client.c
+2 -2
@@ -22,8 +22,8 @@ inline int web_client_bearer_required(struct web_client *w) {
22 w->response.data->content_type = CT_TEXT_PLAIN;
23 buffer_flush(w->response.data);
24 buffer_strcat(w->response.data, "An authorization bearer is required to access the resource.");
25 - w->response.code = HTTP_RESP_UNAUTHORIZED;
26 - return HTTP_RESP_UNAUTHORIZED;
25 + w->response.code = HTTP_RESP_PRECOND_FAIL;
26 + return HTTP_RESP_PRECOND_FAIL;
27 }
28
29 static inline int bad_request_multiple_dashboard_versions(struct web_client *w) {