From 7b215223d58df81e7ac966c0bcab7169bd88e3b9 Mon Sep 17 00:00:00 2001 From: rja5 Date: Sun, 24 May 2026 21:19:14 -0600 Subject: [PATCH 1/4] oauth2: Add user-agent member field Signed-off-by: rja5 --- include/fluent-bit/flb_oauth2.h | 1 + src/flb_oauth2.c | 27 ++++++++++++++++++++++++++- 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/include/fluent-bit/flb_oauth2.h b/include/fluent-bit/flb_oauth2.h index b6eb07d56d5..62777abcfe5 100644 --- a/include/fluent-bit/flb_oauth2.h +++ b/include/fluent-bit/flb_oauth2.h @@ -42,6 +42,7 @@ struct flb_oauth2_config { flb_sds_t token_url; flb_sds_t client_id; flb_sds_t client_secret; + flb_sds_t user_agent; flb_sds_t scope; flb_sds_t audience; flb_sds_t resource; diff --git a/src/flb_oauth2.c b/src/flb_oauth2.c index 7abe616448a..f1c9697f986 100644 --- a/src/flb_oauth2.c +++ b/src/flb_oauth2.c @@ -1,4 +1,4 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +And /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* Fluent Bit * ========== @@ -67,6 +67,11 @@ struct flb_config_map oauth2_config_map[] = { 0, FLB_TRUE, offsetof(struct flb_oauth2_config, client_secret), "OAuth2 client_secret" }, + { + FLB_CONFIG_MAP_STR, "oauth2.user_agent", NULL, + 0, FLB_TRUE, offsetof(struct flb_oauth2_config, user_agent), + "Optional User-Agent header for OAuth2 token requests" + }, { FLB_CONFIG_MAP_STR, "oauth2.scope", NULL, 0, FLB_TRUE, offsetof(struct flb_oauth2_config, scope), @@ -185,6 +190,7 @@ static void oauth2_apply_defaults(struct flb_oauth2_config *cfg) cfg->token_url = NULL; cfg->client_id = NULL; cfg->client_secret = NULL; + cfg->user_agent = NULL; cfg->scope = NULL; cfg->audience = NULL; cfg->resource = NULL; @@ -243,6 +249,15 @@ static int oauth2_clone_config(struct flb_oauth2_config *dst, } } + if (src->user_agent) { + dst->user_agent = flb_sds_create(src->user_agent); + if (!dst->user_agent) { + flb_errno(); + flb_oauth2_config_destroy(dst); + return -1; + } + } + if (src->scope) { dst->scope = flb_sds_create(src->scope); if (!dst->scope) { @@ -324,6 +339,8 @@ void flb_oauth2_config_destroy(struct flb_oauth2_config *cfg) cfg->client_id = NULL; flb_sds_destroy(cfg->client_secret); cfg->client_secret = NULL; + flb_sds_destroy(cfg->user_agent); + cfg->user_agent = NULL; flb_sds_destroy(cfg->scope); cfg->scope = NULL; flb_sds_destroy(cfg->audience); @@ -1114,6 +1131,14 @@ static int oauth2_http_request(struct flb_oauth2 *ctx, flb_sds_t body) FLB_OAUTH2_HTTP_ENCODING, sizeof(FLB_OAUTH2_HTTP_ENCODING) - 1); + if (ctx->cfg.user_agent) { + flb_http_add_header(c, + "User-Agent", + 10, + ctx->cfg.user_agent, + flb_sds_len(ctx->cfg.user_agent)); + } + if (ctx->cfg.auth_method == FLB_OAUTH2_AUTH_METHOD_BASIC && ctx->cfg.client_id && ctx->cfg.client_secret) { ret = flb_http_basic_auth(c, ctx->cfg.client_id, ctx->cfg.client_secret); From 5b70c00e8ba7dd715b7b0bc9b0a92c34369a588c Mon Sep 17 00:00:00 2001 From: rja5 Date: Sun, 24 May 2026 21:19:34 -0600 Subject: [PATCH 2/4] out_http: Add capability to handle user_agent option Signed-off-by: rja5 --- plugins/out_http/http.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/plugins/out_http/http.c b/plugins/out_http/http.c index 63e9552b6c9..79f7d9dfa1a 100644 --- a/plugins/out_http/http.c +++ b/plugins/out_http/http.c @@ -743,6 +743,11 @@ static struct flb_config_map config_map[] = { 0, FLB_TRUE, offsetof(struct flb_out_http, oauth2_config.client_secret), "OAuth2 client_secret" }, + { + FLB_CONFIG_MAP_STR, "oauth2.user_agent", NULL, + 0, FLB_TRUE, offsetof(struct flb_out_http, oauth2_config.user_agent), + "Optional User-Agent header for OAuth2 token requests" + }, { FLB_CONFIG_MAP_STR, "oauth2.scope", NULL, 0, FLB_TRUE, offsetof(struct flb_out_http, oauth2_config.scope), From 63c80b4bf5d5f5f92a71cd4b5aeb563b8d5d4dbd Mon Sep 17 00:00:00 2001 From: rja5 Date: Sun, 24 May 2026 21:19:49 -0600 Subject: [PATCH 3/4] tests: oauth2: add user-agent tests Signed-off-by: rja5 --- tests/internal/oauth2.c | 120 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 116 insertions(+), 4 deletions(-) diff --git a/tests/internal/oauth2.c b/tests/internal/oauth2.c index 5206a324917..9df0817d821 100644 --- a/tests/internal/oauth2.c +++ b/tests/internal/oauth2.c @@ -92,6 +92,8 @@ struct oauth2_mock_server { int expires_in; char latest_token[64]; char latest_token_request[MOCK_BODY_SIZE]; + int token_user_agent_seen; + char token_user_agent[256]; pthread_t thread; #ifdef _WIN32 int wsa_initialized; @@ -152,9 +154,45 @@ static int request_content_length(const char *request) return len; } +static int request_header_value(const char *request, const char *header_name, + char *out, size_t out_size) +{ + int header_len; + const char *end; + const char *start; + size_t value_len; + + start = strstr(request, header_name); + if (!start) { + return -1; + } + + header_len = strlen(header_name); + start += header_len; + while (*start == ' ') { + start++; + } + + end = strstr(start, "\r\n"); + if (!end) { + return -1; + } + + value_len = end - start; + if (value_len >= out_size) { + return -1; + } + + memcpy(out, start, value_len); + out[value_len] = '\0'; + + return 0; +} + static void handle_token_request(struct oauth2_mock_server *server, flb_sockfd_t fd, const char *request) { + int ret; char payload[MOCK_BODY_SIZE]; char *body; size_t body_len; @@ -163,6 +201,16 @@ static void handle_token_request(struct oauth2_mock_server *server, flb_sockfd_t snprintf(server->latest_token, sizeof(server->latest_token), "mock-token-%d", server->token_requests); + server->token_user_agent_seen = FLB_FALSE; + server->token_user_agent[0] = '\0'; + ret = request_header_value(request, + "User-Agent:", + server->token_user_agent, + sizeof(server->token_user_agent)); + if (ret == 0) { + server->token_user_agent_seen = FLB_TRUE; + } + body = strstr(request, "\r\n\r\n"); if (body) { body += 4; @@ -464,11 +512,13 @@ static void oauth2_mock_server_stop(struct oauth2_mock_server *server) #endif } -static struct flb_oauth2 *create_oauth_ctx(struct flb_config *config, - struct oauth2_mock_server *server, - int refresh_skew) +static struct flb_oauth2 *create_oauth_ctx_with_user_agent(struct flb_config *config, + struct oauth2_mock_server *server, + int refresh_skew, + const char *user_agent) { struct flb_oauth2_config cfg; + struct flb_oauth2 *ctx; memset(&cfg, 0, sizeof(cfg)); cfg.enabled = FLB_TRUE; @@ -477,16 +527,77 @@ static struct flb_oauth2 *create_oauth_ctx(struct flb_config *config, cfg.refresh_skew = refresh_skew; cfg.client_id = flb_sds_create("id"); cfg.client_secret = flb_sds_create("secret"); + if (user_agent) { + cfg.user_agent = flb_sds_create(user_agent); + } flb_sds_printf(&cfg.token_url, "http://127.0.0.1:%d/token", server->port); - struct flb_oauth2 *ctx = flb_oauth2_create_from_config(config, &cfg); + ctx = flb_oauth2_create_from_config(config, &cfg); flb_oauth2_config_destroy(&cfg); return ctx; } +static struct flb_oauth2 *create_oauth_ctx(struct flb_config *config, + struct oauth2_mock_server *server, + int refresh_skew) +{ + return create_oauth_ctx_with_user_agent(config, server, refresh_skew, NULL); +} + +void test_user_agent_header_optional(void) +{ + int ret; + flb_sds_t token = NULL; + struct flb_config *config; + struct flb_oauth2 *ctx; + struct oauth2_mock_server server; + + config = flb_config_init(); + TEST_CHECK(config != NULL); + + ret = oauth2_mock_server_start(&server, 3600, 0); + TEST_CHECK(ret == 0); + + ctx = create_oauth_ctx(config, &server, 58); + TEST_CHECK(ctx != NULL); + +#ifdef FLB_SYSTEM_MACOS + ret = oauth2_mock_server_wait_ready(&server); + TEST_CHECK(ret == 0); +#endif + + ret = flb_oauth2_get_access_token(ctx, &token, FLB_FALSE); + TEST_CHECK(ret == 0); + TEST_CHECK(server.token_user_agent_seen == FLB_FALSE); + + flb_oauth2_destroy(ctx); + oauth2_mock_server_stop(&server); + + ret = oauth2_mock_server_start(&server, 3600, 0); + TEST_CHECK(ret == 0); + + ctx = create_oauth_ctx_with_user_agent(config, &server, 58, + "oauth2-agent-test/1.0"); + TEST_CHECK(ctx != NULL); + +#ifdef FLB_SYSTEM_MACOS + ret = oauth2_mock_server_wait_ready(&server); + TEST_CHECK(ret == 0); +#endif + + ret = flb_oauth2_get_access_token(ctx, &token, FLB_FALSE); + TEST_CHECK(ret == 0); + TEST_CHECK(server.token_user_agent_seen == FLB_TRUE); + TEST_CHECK(strcmp(server.token_user_agent, "oauth2-agent-test/1.0") == 0); + + flb_oauth2_destroy(ctx); + oauth2_mock_server_stop(&server); + flb_config_exit(config); +} + static struct flb_oauth2 *create_legacy_oauth_ctx(struct flb_config *config, struct oauth2_mock_server *server) { @@ -1149,6 +1260,7 @@ TEST_LIST = { test_parse_rejects_missing_required_fields}, {"parse_rejects_invalid_expires_in", test_parse_rejects_invalid_expires_in}, {"caching_and_refresh", test_caching_and_refresh}, + {"user_agent_header_optional", test_user_agent_header_optional}, {"legacy_create_manual_payload_flow", test_legacy_create_manual_payload_flow}, {"private_key_jwt_body", test_private_key_jwt_body}, {"private_key_jwt_x5t_header", test_private_key_jwt_x5t_header}, From e51a51245286e48f10cb3375c769760a562ca4d1 Mon Sep 17 00:00:00 2001 From: rja5 Date: Mon, 25 May 2026 08:22:39 -0600 Subject: [PATCH 4/4] oauth2: Add user-agent member field Signed-off-by: rja5 --- src/flb_oauth2.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/flb_oauth2.c b/src/flb_oauth2.c index f1c9697f986..90e63ecae58 100644 --- a/src/flb_oauth2.c +++ b/src/flb_oauth2.c @@ -1,4 +1,4 @@ -And /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* Fluent Bit * ==========