@cryptotaxi247 / netdata-1 / commits / 416e9f4a4

Add HTTP basic authentication to some exporting connectors (#11394)

Vladimir Kobal committed Aug 4, 2021 at 16:26 UTC 416e9f4a4a4d5f395592f3aaa8212755bbb5851e
17 files changed +128 -6
exporting/README.md
+2
@@ -164,6 +164,8 @@ You can configure each connector individually using the available [options](#opt
164 [opentsdb:http:my_opentsdb_http_instance]
165 enabled = yes
166 destination = localhost:4242
167 + username = my_username
168 + password = my_password
169
170 [opentsdb:https:my_opentsdb_https_instance]
171 enabled = yes
exporting/clean_connectors.c
+4
@@ -15,6 +15,8 @@ static void clean_instance_config(struct instance_config *config)
15 freez((void *)config->type_name);
16 freez((void *)config->name);
17 freez((void *)config->destination);
18 + freez((void *)config->username);
19 + freez((void *)config->password);
20 freez((void *)config->prefix);
21 freez((void *)config->hostname);
22
@@ -49,6 +51,8 @@ void simple_connector_cleanup(struct instance *instance)
51 struct simple_connector_data *simple_connector_data =
52 (struct simple_connector_data *)instance->connector_specific_data;
53
54 + freez(simple_connector_data->auth_string);
55 +
56 buffer_free(instance->buffer);
57 buffer_free(simple_connector_data->buffer);
58 buffer_free(simple_connector_data->header);
exporting/exporting.conf
+5
@@ -17,6 +17,9 @@
17 # [graphite:my_graphite_instance]
18 # enabled = no
19 # destination = localhost
20 + # Credentials for basic HTTP authentication
21 + # username = my_username
22 + # password = my_password
23 # data source = average
24 # prefix = netdata
25 # hostname = my_hostname
@@ -31,6 +34,8 @@
34 # enabled = no
35 # destination = localhost
36 # remote write URL path = /receive
37 + # username = my_username
38 + # password = my_password
39 # data source = average
40 # prefix = netdata
41 # hostname = my_hostname
exporting/exporting_engine.h
+4
@@ -66,6 +66,8 @@ struct instance_config {
66
67 const char *name;
68 const char *destination;
69 + const char *username;
70 + const char *password;
71 const char *prefix;
72 const char *hostname;
73
@@ -104,6 +106,8 @@ struct simple_connector_data {
106 void *connector_specific_data;
107
108 char connected_to[CONNECTED_TO_MAX];
109 +
110 + char *auth_string;
111
112 size_t total_buffered_metrics;
113
exporting/graphite/README.md
+6 -1
@@ -22,7 +22,12 @@ directory and set the following options:
22 ```
23
24 Add `:http` or `:https` modifiers to the connector type if you need to use other than a plaintext protocol. For example: `graphite:http:my_graphite_instance`,
25 -`graphite:https:my_graphite_instance`.
25 +`graphite:https:my_graphite_instance`. You can set basic HTTP authentication credentials using
26 +
27 +```conf
28 + username = my_username
29 + password = my_password
30 +```
31
32 The Graphite connector is further configurable using additional settings. See the [exporting reference
33 doc](/exporting/README.md#options) for details.
exporting/graphite/graphite.c
+2
@@ -218,10 +218,12 @@ void graphite_http_prepare_header(struct instance *instance)
218 simple_connector_data->last_buffer->header,
219 "POST /api/put HTTP/1.1\r\n"
220 "Host: %s\r\n"
221 + "%s"
222 "Content-Type: application/graphite\r\n"
223 "Content-Length: %lu\r\n"
224 "\r\n",
225 instance->config.destination,
226 + simple_connector_data->auth_string ? simple_connector_data->auth_string : "",
227 buffer_strlen(simple_connector_data->last_buffer->buffer));
228
229 return;
exporting/init_connectors.c
+70 -1
@@ -105,8 +105,57 @@ int init_connectors(struct engine *engine)
105 return 0;
106 }
107
108 +// TODO: use a base64 encoder from a library
109 +static size_t base64_encode(unsigned char *input, size_t input_size, char *output, size_t output_size)
110 +{
111 + uint32_t value;
112 + static char lookup[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
113 + "abcdefghijklmnopqrstuvwxyz"
114 + "0123456789+/";
115 + if ((input_size / 3 + 1) * 4 >= output_size) {
116 + error("Output buffer for encoding size=%zu is not large enough for %zu-bytes input", output_size, input_size);
117 + return 0;
118 + }
119 + size_t count = 0;
120 + while (input_size > 3) {
121 + value = ((input[0] << 16) + (input[1] << 8) + input[2]) & 0xffffff;
122 + output[0] = lookup[value >> 18];
123 + output[1] = lookup[(value >> 12) & 0x3f];
124 + output[2] = lookup[(value >> 6) & 0x3f];
125 + output[3] = lookup[value & 0x3f];
126 + //error("Base-64 encode (%04x) -> %c %c %c %c\n", value, output[0], output[1], output[2], output[3]);
127 + output += 4;
128 + input += 3;
129 + input_size -= 3;
130 + count += 4;
131 + }
132 + switch (input_size) {
133 + case 2:
134 + value = (input[0] << 10) + (input[1] << 2);
135 + output[0] = lookup[(value >> 12) & 0x3f];
136 + output[1] = lookup[(value >> 6) & 0x3f];
137 + output[2] = lookup[value & 0x3f];
138 + output[3] = '=';
139 + //error("Base-64 encode (%06x) -> %c %c %c %c\n", (value>>2)&0xffff, output[0], output[1], output[2], output[3]);
140 + count += 4;
141 + break;
142 + case 1:
143 + value = input[0] << 4;
144 + output[0] = lookup[(value >> 6) & 0x3f];
145 + output[1] = lookup[value & 0x3f];
146 + output[2] = '=';
147 + output[3] = '=';
148 + //error("Base-64 encode (%06x) -> %c %c %c %c\n", value, output[0], output[1], output[2], output[3]);
149 + count += 4;
150 + break;
151 + case 0:
152 + break;
153 + }
154 + return count;
155 +}
156 +
157 /**
109 - * Initialize a ring buffer for a simple connector
158 + * Initialize a ring buffer and credentials for a simple connector
159 *
160 * @param instance an instance data structure.
161 */
@@ -141,5 +190,25 @@ void simple_connector_init(struct instance *instance)
190 first_buffer->next = connector_specific_data->first_buffer;
191 connector_specific_data->last_buffer = connector_specific_data->first_buffer;
192
193 + if (*instance->config.username || *instance->config.password) {
194 + BUFFER *auth_string = buffer_create(0);
195 +
196 + buffer_sprintf(auth_string, "%s:%s", instance->config.username, instance->config.password);
197 +
198 + size_t encoded_size = (buffer_strlen(auth_string) / 3 + 1) * 4 + 1;
199 + char *encoded_credentials = callocz(1, encoded_size);
200 +
201 + base64_encode((unsigned char*)buffer_tostring(auth_string), buffer_strlen(auth_string), encoded_credentials, encoded_size);
202 +
203 + buffer_flush(auth_string);
204 + buffer_sprintf(auth_string, "Authorization: Basic %s\n", encoded_credentials);
205 +
206 + freez(encoded_credentials);
207 +
208 + connector_specific_data->auth_string = strdupz(buffer_tostring(auth_string));
209 +
210 + buffer_free(auth_string);
211 + }
212 +
213 return;
214 }
exporting/json/README.md
+6 -1
@@ -22,7 +22,12 @@ directory and set the following options:
22 ```
23
24 Add `:http` or `:https` modifiers to the connector type if you need to use other than a plaintext protocol. For example: `json:http:my_json_instance`,
25 -`json:https:my_json_instance`.
25 +`json:https:my_json_instance`. You can set basic HTTP authentication credentials using
26 +
27 +```conf
28 + username = my_username
29 + password = my_password
30 +```
31
32 The JSON connector is further configurable using additional settings. See the [exporting reference
33 doc](/exporting/README.md#options) for details.
exporting/json/json.c
+2
@@ -352,10 +352,12 @@ void json_http_prepare_header(struct instance *instance)
352 simple_connector_data->last_buffer->header,
353 "POST /api/put HTTP/1.1\r\n"
354 "Host: %s\r\n"
355 + "%s"
356 "Content-Type: application/json\r\n"
357 "Content-Length: %lu\r\n"
358 "\r\n",
359 instance->config.destination,
360 + simple_connector_data->auth_string ? simple_connector_data->auth_string : "",
361 buffer_strlen(simple_connector_data->last_buffer->buffer));
362
363 return;
exporting/opentsdb/README.md
+6 -1
@@ -22,7 +22,12 @@ directory and set the following options:
22 ```
23
24 Add `:http` or `:https` modifiers to the connector type if you need to use other than a plaintext protocol. For example: `opentsdb:http:my_opentsdb_instance`,
25 -`opentsdb:https:my_opentsdb_instance`.
25 +`opentsdb:https:my_opentsdb_instance`. You can set basic HTTP authentication credentials using
26 +
27 +```conf
28 + username = my_username
29 + password = my_password
30 +```
31
32 The OpenTSDB connector is further configurable using additional settings. See the [exporting reference
33 doc](/exporting/README.md#options) for details.
exporting/opentsdb/opentsdb.c
+2
@@ -269,10 +269,12 @@ void opentsdb_http_prepare_header(struct instance *instance)
269 simple_connector_data->last_buffer->header,
270 "POST /api/put HTTP/1.1\r\n"
271 "Host: %s\r\n"
272 + "%s"
273 "Content-Type: application/json\r\n"
274 "Content-Length: %lu\r\n"
275 "\r\n",
276 instance->config.destination,
277 + simple_connector_data->auth_string ? simple_connector_data->auth_string : "",
278 buffer_strlen(simple_connector_data->last_buffer->buffer));
279
280 return;
exporting/prometheus/remote_write/README.md
+7
@@ -41,6 +41,13 @@ For example, if your endpoint is `http://example.domain:example_port/storage/rea
41 remote write URL path = /storage/read
42 ```
43
44 +You can set basic HTTP authentication credentials using
45 +
46 +```conf
47 + username = my_username
48 + password = my_password
49 +```
50 +
51 `buffered` and `lost` dimensions in the Netdata Exporting Connector Data Size operation monitoring chart estimate uncompressed
52 buffer size on failures.
53
exporting/prometheus/remote_write/remote_write.c
+2
@@ -25,6 +25,7 @@ void prometheus_remote_write_prepare_header(struct instance *instance)
25 "POST %s HTTP/1.1\r\n"
26 "Host: %s\r\n"
27 "Accept: */*\r\n"
28 + "%s"
29 "Content-Encoding: snappy\r\n"
30 "Content-Type: application/x-protobuf\r\n"
31 "X-Prometheus-Remote-Write-Version: 0.1.0\r\n"
@@ -32,6 +33,7 @@ void prometheus_remote_write_prepare_header(struct instance *instance)
33 "\r\n",
34 connector_specific_config->remote_write_path,
35 simple_connector_data->connected_to,
36 + simple_connector_data->auth_string ? simple_connector_data->auth_string : "",
37 buffer_strlen(simple_connector_data->last_buffer->buffer));
38 }
39
exporting/read_config.c
+4
@@ -456,6 +456,10 @@ struct engine *read_exporting_config()
456
457 tmp_instance->config.destination = strdupz(exporter_get(instance_name, "destination", default_destination));
458
459 + tmp_instance->config.username = strdupz(exporter_get(instance_name, "username", ""));
460 +
461 + tmp_instance->config.password = strdupz(exporter_get(instance_name, "password", ""));
462 +
463 tmp_instance->config.prefix = strdupz(exporter_get(instance_name, "prefix", "netdata"));
464
465 tmp_instance->config.hostname = strdupz(exporter_get(instance_name, "hostname", engine->config.hostname));
exporting/tests/exporting_doubles.c
+2
@@ -22,6 +22,8 @@ struct engine *__mock_read_exporting_config()
22 instance->config.type = EXPORTING_CONNECTOR_TYPE_GRAPHITE;
23 instance->config.name = strdupz("instance_name");
24 instance->config.destination = strdupz("localhost");
25 + instance->config.username = strdupz("");
26 + instance->config.password = strdupz("");
27 instance->config.prefix = strdupz("netdata");
28 instance->config.hostname = strdupz("test-host");
29 instance->config.update_every = 1;
exporting/tests/exporting_fixtures.c
+2
@@ -18,6 +18,8 @@ int teardown_configured_engine(void **state)
18
19 struct instance *instance = engine->instance_root;
20 free((void *)instance->config.destination);
21 + free((void *)instance->config.username);
22 + free((void *)instance->config.password);
23 free((void *)instance->config.name);
24 free((void *)instance->config.prefix);
25 free((void *)instance->config.hostname);
exporting/tests/test_exporting_engine.c
+2 -2
@@ -1053,7 +1053,7 @@ static void test_format_host_labels_prometheus(void **state)
1053 instance->config.options |= EXPORTING_OPTION_SEND_AUTOMATIC_LABELS;
1054
1055 format_host_labels_prometheus(instance, localhost);
1056 - assert_string_equal(buffer_tostring(instance->labels), "key1=\"netdata\",key2=\"value2\"");
1056 + assert_string_equal(buffer_tostring(instance->labels), "key1=\"value1\",key2=\"value2\"");
1057 }
1058
1059 static void rrd_stats_api_v1_charts_allmetrics_prometheus(void **state)
@@ -1877,7 +1877,7 @@ int main(void)
1877 cmocka_unit_test_setup_teardown(test_prometheus_label_copy, setup_prometheus, teardown_prometheus),
1878 cmocka_unit_test_setup_teardown(test_prometheus_units_copy, setup_prometheus, teardown_prometheus),
1879 cmocka_unit_test_setup_teardown(
1880 - test_format_host_labels_prometheus, setup_configured_engine, teardown_configured_engine),
1880 + test_format_host_labels_prometheus, setup_initialized_engine, teardown_initialized_engine),
1881 cmocka_unit_test_setup_teardown(
1882 rrd_stats_api_v1_charts_allmetrics_prometheus, setup_prometheus, teardown_prometheus),
1883 };