2424#include <fluent-bit/flb_hmac.h>
2525#include <fluent-bit/flb_sds.h>
2626#include <fluent-bit/flb_kv.h>
27+ #include <fluent-bit/flb_oauth2.h>
2728
2829#include "azure_blob.h"
2930#include "azure_blob_uri.h"
@@ -38,6 +39,111 @@ static int hmac_sha256_sign(unsigned char out[32],
3839 out , 32 );
3940}
4041
42+ static int azb_get_oauth2_token (struct flb_azure_blob * ctx )
43+ {
44+ int ret ;
45+ char * token ;
46+
47+ flb_oauth2_payload_clear (ctx -> o );
48+
49+ ret = flb_oauth2_payload_append (ctx -> o ,
50+ "grant_type" , 10 ,
51+ "client_credentials" , 18 );
52+ if (ret == -1 ) {
53+ flb_plg_error (ctx -> ins , "failed to append OAuth2 grant type" );
54+ return -1 ;
55+ }
56+
57+ ret = flb_oauth2_payload_append (ctx -> o ,
58+ "scope" , 5 ,
59+ AZURE_BLOB_OAUTH_SCOPE , -1 );
60+ if (ret == -1 ) {
61+ flb_plg_error (ctx -> ins , "failed to append OAuth2 scope" );
62+ return -1 ;
63+ }
64+
65+ ret = flb_oauth2_payload_append (ctx -> o ,
66+ "client_id" , 9 ,
67+ ctx -> client_id , -1 );
68+ if (ret == -1 ) {
69+ flb_plg_error (ctx -> ins , "failed to append OAuth2 client ID" );
70+ return -1 ;
71+ }
72+
73+ ret = flb_oauth2_payload_append (ctx -> o ,
74+ "client_secret" , 13 ,
75+ ctx -> client_secret , -1 );
76+ if (ret == -1 ) {
77+ flb_plg_error (ctx -> ins , "failed to append OAuth2 client secret" );
78+ return -1 ;
79+ }
80+
81+ token = flb_oauth2_token_get (ctx -> o );
82+ if (!token ) {
83+ flb_plg_error (ctx -> ins , "failed to retrieve OAuth2 access token" );
84+ return -1 ;
85+ }
86+
87+ return 0 ;
88+ }
89+
90+ /*
91+ * Get the current Azure Blob bearer token as a formatted string.
92+ * Acquires the token mutex, refreshes the token if expired, and returns
93+ * a copy of the token string in the format "<token_type> <access_token>".
94+ * The caller must destroy the returned flb_sds_t.
95+ */
96+ static int azb_get_oauth2_authorization_header (struct flb_azure_blob * ctx ,
97+ flb_sds_t * out_auth_header )
98+ {
99+ int ret ;
100+ flb_sds_t auth_header = NULL ;
101+
102+ if (!out_auth_header ) {
103+ return -1 ;
104+ }
105+
106+ /* Acquire token mutex */
107+ ret = pthread_mutex_lock (& ctx -> token_mutex );
108+ if (ret != 0 ) {
109+ flb_plg_error (ctx -> ins , "failed to lock token mutex" );
110+ return -1 ;
111+ }
112+
113+ /* Check if token needs refresh */
114+ if (flb_oauth2_token_expired (ctx -> o ) == FLB_TRUE ) {
115+ ret = azb_get_oauth2_token (ctx );
116+ if (ret != 0 ) {
117+ pthread_mutex_unlock (& ctx -> token_mutex );
118+ flb_plg_error (ctx -> ins , "failed to refresh OAuth2 token" );
119+ return -1 ;
120+ }
121+ }
122+
123+ /* Build Authorization header while holding lock */
124+ auth_header = flb_sds_create_size (flb_sds_len (ctx -> o -> token_type ) +
125+ flb_sds_len (ctx -> o -> access_token ) + 2 );
126+ if (!auth_header ) {
127+ pthread_mutex_unlock (& ctx -> token_mutex );
128+ flb_plg_error (ctx -> ins , "failed to allocate authorization header" );
129+ return -1 ;
130+ }
131+
132+ ret = flb_sds_snprintf (& auth_header , flb_sds_alloc (auth_header ),
133+ "%s %s" , ctx -> o -> token_type , ctx -> o -> access_token );
134+ if (ret < 0 ) {
135+ flb_sds_destroy (auth_header );
136+ pthread_mutex_unlock (& ctx -> token_mutex );
137+ flb_plg_error (ctx -> ins , "failed to format authorization header" );
138+ return -1 ;
139+ }
140+
141+ pthread_mutex_unlock (& ctx -> token_mutex );
142+
143+ * out_auth_header = auth_header ;
144+ return 0 ;
145+ }
146+
41147static flb_sds_t canonical_headers (struct flb_http_client * c )
42148{
43149 flb_sds_t ch ;
@@ -300,6 +406,7 @@ int azb_http_client_setup(struct flb_azure_blob *ctx, struct flb_http_client *c,
300406 ssize_t content_length , int blob_type ,
301407 int content_type , int content_encoding )
302408{
409+ int ret ;
303410 int len ;
304411 time_t now ;
305412 struct tm tm ;
@@ -358,6 +465,7 @@ int azb_http_client_setup(struct flb_azure_blob *ctx, struct flb_http_client *c,
358465 /* Azure header: x-ms-version */
359466 flb_http_add_header (c , "x-ms-version" , 12 , "2019-12-12" , 10 );
360467
468+
361469 if (ctx -> atype == AZURE_BLOB_AUTH_KEY ) {
362470 can_req = azb_http_canonical_request (ctx , c , content_length , content_type ,
363471 content_encoding );
@@ -374,6 +482,20 @@ int azb_http_client_setup(struct flb_azure_blob *ctx, struct flb_http_client *c,
374482 flb_sds_destroy (can_req );
375483 flb_sds_destroy (auth );
376484 }
485+ else if (ctx -> atype == AZURE_BLOB_AUTH_SERVICE_PRINCIPAL ) {
486+ /* Get OAuth2 authorization header (thread-safe) */
487+ ret = azb_get_oauth2_authorization_header (ctx , & auth );
488+ if (ret != 0 ) {
489+ flb_plg_error (ctx -> ins , "failed to get OAuth2 authorization header" );
490+ return -1 ;
491+ }
492+
493+ /* Azure header: authorization */
494+ flb_http_add_header (c , "Authorization" , 13 , auth , flb_sds_len (auth ));
495+
496+ /* Release buffer */
497+ flb_sds_destroy (auth );
498+ }
377499
378500 /* Set callback context to the HTTP client context */
379501 flb_http_set_callback_context (c , ctx -> ins -> callback );
0 commit comments