diff --git a/plugins/out_azure_logs_ingestion/azure_logs_ingestion.c b/plugins/out_azure_logs_ingestion/azure_logs_ingestion.c index 3aee4ac182e..037a530402f 100644 --- a/plugins/out_azure_logs_ingestion/azure_logs_ingestion.c +++ b/plugins/out_azure_logs_ingestion/azure_logs_ingestion.c @@ -399,6 +399,11 @@ static struct flb_config_map config_map[] = { 0, FLB_TRUE, offsetof(struct flb_az_li, client_secret), "Set the client secret of the AAD application" }, + { + FLB_CONFIG_MAP_STR, "auth_url", (char *)NULL, + 0, FLB_TRUE, offsetof(struct flb_az_li, auth_url_override), + "[Optional] Override the OAuth2 token endpoint." + }, { FLB_CONFIG_MAP_STR, "dce_url", (char *)NULL, 0, FLB_TRUE, offsetof(struct flb_az_li, dce_url), diff --git a/plugins/out_azure_logs_ingestion/azure_logs_ingestion.h b/plugins/out_azure_logs_ingestion/azure_logs_ingestion.h index f3ed3f82b74..74516b81715 100644 --- a/plugins/out_azure_logs_ingestion/azure_logs_ingestion.h +++ b/plugins/out_azure_logs_ingestion/azure_logs_ingestion.h @@ -57,6 +57,7 @@ struct flb_az_li { int compress_enabled; /* mangement auth */ + flb_sds_t auth_url_override; flb_sds_t auth_url; struct flb_oauth2 *u_auth; /* mutex for acquiring tokens */ diff --git a/plugins/out_azure_logs_ingestion/azure_logs_ingestion_conf.c b/plugins/out_azure_logs_ingestion/azure_logs_ingestion_conf.c index 1450bd26799..69aa00f2053 100644 --- a/plugins/out_azure_logs_ingestion/azure_logs_ingestion_conf.c +++ b/plugins/out_azure_logs_ingestion/azure_logs_ingestion_conf.c @@ -26,6 +26,60 @@ #include "azure_logs_ingestion.h" #include "azure_logs_ingestion_conf.h" +static int validate_auth_url_override(struct flb_output_instance *ins, + flb_sds_t auth_url_override) +{ + int ret; + int result; + char *protocol = NULL; + char *host = NULL; + char *port = NULL; + char *uri = NULL; + + result = -1; + + ret = flb_utils_url_split(auth_url_override, &protocol, &host, &port, &uri); + if (ret == -1 || protocol == NULL || host == NULL) { + flb_plg_error(ins, "property 'auth_url' has an invalid URL"); + goto cleanup; + } + + if (strcasecmp(protocol, "https") == 0) { + result = 0; + goto cleanup; + } + + if (strcasecmp(protocol, "http") != 0) { + flb_plg_error(ins, "property 'auth_url' must use http or https"); + goto cleanup; + } + + if (strcmp(host, "localhost") == 0 || strcmp(host, "127.0.0.1") == 0) { + result = 0; + goto cleanup; + } + + flb_plg_error(ins, + "property 'auth_url' must use https or an explicit loopback " + "http endpoint"); + +cleanup: + if (protocol != NULL) { + flb_free(protocol); + } + if (host != NULL) { + flb_free(host); + } + if (port != NULL) { + flb_free(port); + } + if (uri != NULL) { + flb_free(uri); + } + + return result; +} + struct flb_az_li* flb_az_li_ctx_create(struct flb_output_instance *ins, struct flb_config *config) { @@ -61,7 +115,7 @@ struct flb_az_li* flb_az_li_ctx_create(struct flb_output_instance *ins, return NULL; } /* config: 'tenant_id' */ - if (!ctx->tenant_id) { + if (!ctx->tenant_id && !ctx->auth_url_override) { flb_plg_error(ins, "property 'tenant_id' is not defined"); flb_az_li_ctx_destroy(ctx); return NULL; @@ -91,16 +145,32 @@ struct flb_az_li* flb_az_li_ctx_create(struct flb_output_instance *ins, return NULL; } - /* Allocate and set auth url */ - ctx->auth_url = flb_sds_create_size(sizeof(FLB_AZ_LI_AUTH_URL_TMPLT) - 1 + - flb_sds_len(ctx->tenant_id)); - if (!ctx->auth_url) { - flb_errno(); - flb_az_li_ctx_destroy(ctx); - return NULL; + if (ctx->auth_url_override) { + ret = validate_auth_url_override(ins, ctx->auth_url_override); + if (ret == -1) { + flb_az_li_ctx_destroy(ctx); + return NULL; + } + + ctx->auth_url = flb_sds_create(ctx->auth_url_override); + if (!ctx->auth_url) { + flb_errno(); + flb_az_li_ctx_destroy(ctx); + return NULL; + } + } + else { + /* Allocate and set auth url */ + ctx->auth_url = flb_sds_create_size(sizeof(FLB_AZ_LI_AUTH_URL_TMPLT) - 1 + + flb_sds_len(ctx->tenant_id)); + if (!ctx->auth_url) { + flb_errno(); + flb_az_li_ctx_destroy(ctx); + return NULL; + } + flb_sds_snprintf(&ctx->auth_url, flb_sds_alloc(ctx->auth_url), + FLB_AZ_LI_AUTH_URL_TMPLT, ctx->tenant_id); } - flb_sds_snprintf(&ctx->auth_url, flb_sds_alloc(ctx->auth_url), - FLB_AZ_LI_AUTH_URL_TMPLT, ctx->tenant_id); /* Allocate and set dce full url */ ctx->dce_u_url = flb_sds_create_size(sizeof(FLB_AZ_LI_DCE_URL_TMPLT) - 1 + diff --git a/src/flb_oauth2.c b/src/flb_oauth2.c index e4fd405292c..7abe616448a 100644 --- a/src/flb_oauth2.c +++ b/src/flb_oauth2.c @@ -1201,6 +1201,7 @@ struct flb_oauth2 *flb_oauth2_create(struct flb_config *config, (void) expire_sec; oauth2_apply_defaults(&cfg); + cfg.enabled = FLB_TRUE; cfg.token_url = flb_sds_create(auth_url); cfg.refresh_skew = FLB_OAUTH2_DEFAULT_SKEW_SECS; diff --git a/tests/internal/oauth2.c b/tests/internal/oauth2.c index 95491968b3a..5206a324917 100644 --- a/tests/internal/oauth2.c +++ b/tests/internal/oauth2.c @@ -487,6 +487,26 @@ static struct flb_oauth2 *create_oauth_ctx(struct flb_config *config, return ctx; } +static struct flb_oauth2 *create_legacy_oauth_ctx(struct flb_config *config, + struct oauth2_mock_server *server) +{ + flb_sds_t token_url; + struct flb_oauth2 *ctx; + + token_url = flb_sds_create_size(64); + TEST_CHECK(token_url != NULL); + if (!token_url) { + return NULL; + } + + flb_sds_printf(&token_url, "http://127.0.0.1:%d/token", server->port); + + ctx = flb_oauth2_create(config, token_url, 300); + flb_sds_destroy(token_url); + + return ctx; +} + static int write_text_file(const char *path, const char *content) { FILE *fp; @@ -948,6 +968,57 @@ void test_caching_and_refresh(void) flb_config_exit(config); } +void test_legacy_create_manual_payload_flow(void) +{ + int ret; + char *token; + 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_legacy_oauth_ctx(config, &server); + TEST_CHECK(ctx != NULL); + +#ifdef FLB_SYSTEM_MACOS + ret = oauth2_mock_server_wait_ready(&server); + TEST_CHECK(ret == 0); +#endif + + flb_oauth2_payload_clear(ctx); + + ret = flb_oauth2_payload_append(ctx, "grant_type", -1, + "client_credentials", -1); + TEST_CHECK(ret == 0); + + ret = flb_oauth2_payload_append(ctx, "client_id", -1, "legacy-id", -1); + TEST_CHECK(ret == 0); + + ret = flb_oauth2_payload_append(ctx, "client_secret", -1, + "legacy-secret", -1); + TEST_CHECK(ret == 0); + + token = flb_oauth2_token_get(ctx); + TEST_CHECK(token != NULL); + TEST_CHECK(server.token_requests == 1); + TEST_CHECK(strcmp(token, "mock-token-1") == 0); + TEST_CHECK(strstr(server.latest_token_request, + "grant_type=client_credentials") != NULL); + TEST_CHECK(strstr(server.latest_token_request, + "client_id=legacy-id") != NULL); + TEST_CHECK(strstr(server.latest_token_request, + "client_secret=legacy-secret") != NULL); + + flb_oauth2_destroy(ctx); + oauth2_mock_server_stop(&server); + flb_config_exit(config); +} + void test_private_key_jwt_body(void) { int ret; @@ -1078,6 +1149,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}, + {"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}, {0}