Skip to content

Commit 49b0831

Browse files
authored
WIF auth support for C interface (#953)
1 parent 12acdf6 commit 49b0831

File tree

7 files changed

+498
-6
lines changed

7 files changed

+498
-6
lines changed

cpp/lib/Authenticator.cpp

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include <fstream>
3131

3232
#include "snowflake/SF_CRTFunctionSafe.h"
33+
#include "snowflake/WifAttestation.hpp"
3334

3435
#ifdef __APPLE__
3536
#include <CoreFoundation/CFBundle.h>
@@ -75,6 +76,10 @@ extern "C" {
7576
{
7677
return AUTH_PAT;
7778
}
79+
if (strcasecmp(authenticator, SF_AUTHENTICATOR_WORKLOAD_IDENTITY) == 0)
80+
{
81+
return AUTH_WIF;
82+
}
7883

7984
if (strcasecmp(authenticator, "test") == 0)
8085
{
@@ -190,6 +195,46 @@ extern "C" {
190195
snowflake_cJSON_AddStringToObject(data, "TOKEN", conn->oauth_token);
191196
}
192197
}
198+
if (AUTH_WIF == authenticator)
199+
{
200+
Snowflake::Client::AttestationConfig config;
201+
202+
// Populate config from SF_CONNECT fields
203+
if (conn->wif_provider) {
204+
auto typeOpt = Snowflake::Client::attestationTypeFromString(conn->wif_provider);
205+
if (typeOpt) {
206+
config.type = typeOpt;
207+
log_debug("Using explicit WIF provider: %s", conn->wif_provider);
208+
} else {
209+
log_warn("Invalid WIF provider specified: %s, falling back to auto-detection", conn->wif_provider);
210+
}
211+
}
212+
213+
if (conn->wif_token) {
214+
config.token = std::string(conn->wif_token);
215+
log_debug("Using explicit WIF token");
216+
}
217+
218+
if (conn->wif_azure_resource) {
219+
config.snowflakeEntraResource = std::string(conn->wif_azure_resource);
220+
log_debug("Using Azure resource: %s", conn->wif_azure_resource);
221+
}
222+
223+
if (auto attestationOpt = Snowflake::Client::createAttestation(config))
224+
{
225+
const Snowflake::Client::Attestation &attestation = attestationOpt.value();
226+
227+
snowflake_cJSON_DeleteItemFromObject(data, "AUTHENTICATOR");
228+
snowflake_cJSON_DeleteItemFromObject(data, "TOKEN");
229+
230+
snowflake_cJSON_AddStringToObject(data, "AUTHENTICATOR", SF_AUTHENTICATOR_WORKLOAD_IDENTITY);
231+
snowflake_cJSON_AddStringToObject(data, "TOKEN", attestation.credential.c_str());
232+
snowflake_cJSON_AddStringToObject(data, "PROVIDER",
233+
Snowflake::Client::stringFromAttestationType(attestation.type));
234+
} else {
235+
log_error("Failed to create WIF attestation - not running in a supported cloud environment?");
236+
}
237+
}
193238

194239
if (conn->sso_token)
195240
{
@@ -222,8 +267,6 @@ extern "C" {
222267
{
223268
; // Do nothing
224269
}
225-
226-
return;
227270
}
228271

229272
void auth_renew_json_body(SF_CONNECT * conn, cJSON* body)
@@ -246,8 +289,6 @@ extern "C" {
246289
{
247290
; // Do nothing
248291
}
249-
250-
return;
251292
}
252293

253294
void STDCALL auth_terminate(SF_CONNECT * conn)

include/snowflake/client.h

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,11 @@ extern "C" {
4545
*/
4646
#define SF_AUTHENTICATOR_PAT "programmatic_access_token"
4747

48+
/**
49+
* Workload Identity Federation authenticator
50+
*/
51+
#define SF_AUTHENTICATOR_WORKLOAD_IDENTITY "workload_identity"
52+
4853
/**
4954
* Authenticator, SSO token
5055
*/
@@ -321,7 +326,10 @@ typedef enum SF_ATTRIBUTE {
321326
SF_CON_CRL_ALLOW_NO_CRL,
322327
SF_CON_CRL_DISK_CACHING,
323328
SF_CON_CRL_MEMORY_CACHING,
324-
SF_CON_CRL_DOWNLOAD_TIMEOUT
329+
SF_CON_CRL_DOWNLOAD_TIMEOUT,
330+
SF_CON_WIF_PROVIDER,
331+
SF_CON_WIF_TOKEN,
332+
SF_CON_WIF_AZURE_RESOURCE
325333
} SF_ATTRIBUTE;
326334

327335
/**
@@ -500,6 +508,11 @@ typedef struct SF_CONNECT {
500508
//programmatic access token
501509
char *programmatic_access_token;
502510

511+
// WIF (Workload Identity Federation) configuration
512+
char *wif_provider;
513+
char *wif_token;
514+
char *wif_azure_resource;
515+
503516
// put get configurations
504517
sf_bool use_s3_regional_url;
505518
sf_bool put_use_urand_dev;

lib/authenticator.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ typedef enum authenticator_type
1818
AUTH_JWT,
1919
AUTH_USR_PWD_MFA,
2020
AUTH_PAT,
21+
AUTH_WIF,
2122
AUTH_TEST,
2223
AUTH_UNSUPPORTED
2324
} AuthenticatorType;

lib/client.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1083,6 +1083,10 @@ SF_CONNECT *STDCALL snowflake_init() {
10831083
sf->disable_saml_url_check = SF_BOOLEAN_FALSE;
10841084
sf->programmatic_access_token = NULL;
10851085

1086+
sf->wif_provider = NULL;
1087+
sf->wif_token = NULL;
1088+
sf->wif_azure_resource = NULL;
1089+
10861090
sf->use_s3_regional_url = SF_BOOLEAN_FALSE;
10871091
sf->put_use_urand_dev = SF_BOOLEAN_FALSE;
10881092
sf->put_compress_level = SF_DEFAULT_PUT_COMPRESS_LEVEL;
@@ -1170,6 +1174,9 @@ SF_STATUS STDCALL snowflake_term(SF_CONNECT *sf) {
11701174
SF_FREE(sf->proxy);
11711175
SF_FREE(sf->no_proxy);
11721176
SF_FREE(sf->oauth_token);
1177+
SF_FREE(sf->wif_provider);
1178+
SF_FREE(sf->wif_token);
1179+
SF_FREE(sf->wif_azure_resource);
11731180
SF_FREE(sf);
11741181

11751182
stopwatch_stop(&stopwatch);
@@ -1671,6 +1678,15 @@ SF_STATUS STDCALL snowflake_set_attribute(
16711678
case SF_CON_DISABLE_STAGE_BIND:
16721679
sf->stage_binding_disabled = value ? *((sf_bool*)value) : SF_BOOLEAN_FALSE;
16731680
break;
1681+
case SF_CON_WIF_PROVIDER:
1682+
alloc_buffer_and_copy(&sf->wif_provider, value);
1683+
break;
1684+
case SF_CON_WIF_TOKEN:
1685+
alloc_buffer_and_copy(&sf->wif_token, value);
1686+
break;
1687+
case SF_CON_WIF_AZURE_RESOURCE:
1688+
alloc_buffer_and_copy(&sf->wif_azure_resource, value);
1689+
break;
16741690
default:
16751691
SET_SNOWFLAKE_ERROR(&sf->error, SF_STATUS_ERROR_BAD_ATTRIBUTE_TYPE,
16761692
"Invalid attribute type",
@@ -1877,6 +1893,15 @@ SF_STATUS STDCALL snowflake_get_attribute(
18771893
case SF_CON_CLIENT_STORE_TEMPORARY_CREDENTIAL:
18781894
*value = &sf->client_store_temporary_credential;
18791895
break;
1896+
case SF_CON_WIF_PROVIDER:
1897+
*value = sf->wif_provider;
1898+
break;
1899+
case SF_CON_WIF_TOKEN:
1900+
*value = sf->wif_token;
1901+
break;
1902+
case SF_CON_WIF_AZURE_RESOURCE:
1903+
*value = sf->wif_azure_resource;
1904+
break;
18801905
default:
18811906
SET_SNOWFLAKE_ERROR(&sf->error, SF_STATUS_ERROR_BAD_ATTRIBUTE_TYPE,
18821907
"Invalid attribute type",

tests/test_auth/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ add_executable(
66
test_okta.c
77
test_external_browser.c
88
test_mfa.c
9+
test_wif.c
910
test_runner.c
1011
auth_utils.c
1112
../utils/test_setup.c

tests/test_auth/test_runner.c

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,16 @@ extern void test_external_browser_successful_connection(void **state);
1111
extern void test_external_browser_mismatched_username(void **state);
1212
extern void test_external_browser_wrong_credentials(void **state);
1313
extern void test_mfa_totp_authentication(void **state);
14+
extern void test_aws_wif_authentication(void **state);
15+
extern void test_gcp_wif_authentication(void **state);
16+
extern void test_azure_wif_authentication(void **state);
17+
extern void test_wif_no_cloud_credentials(void **state);
18+
extern void test_wif_invalid_authenticator(void **state);
19+
extern void test_wif_valid_authenticator(void **state);
20+
extern void test_wif_multiple_connections(void **state);
21+
extern void test_wif_explicit_provider_integration(void **state);
22+
extern void test_wif_invalid_provider_fallback(void **state);
23+
extern void test_wif_get_attributes(void **state);
1424

1525

1626
int main(void) {
@@ -27,7 +37,17 @@ int main(void) {
2737
cmocka_unit_test(test_external_browser_successful_connection),
2838
cmocka_unit_test(test_external_browser_mismatched_username),
2939
cmocka_unit_test(test_external_browser_wrong_credentials),
30-
cmocka_unit_test(test_mfa_totp_authentication)
40+
cmocka_unit_test(test_mfa_totp_authentication),
41+
cmocka_unit_test(test_aws_wif_authentication),
42+
cmocka_unit_test(test_gcp_wif_authentication),
43+
cmocka_unit_test(test_azure_wif_authentication),
44+
cmocka_unit_test(test_wif_no_cloud_credentials),
45+
cmocka_unit_test(test_wif_invalid_authenticator),
46+
cmocka_unit_test(test_wif_valid_authenticator),
47+
cmocka_unit_test(test_wif_multiple_connections),
48+
cmocka_unit_test(test_wif_explicit_provider_integration),
49+
cmocka_unit_test(test_wif_invalid_provider_fallback),
50+
cmocka_unit_test(test_wif_get_attributes)
3151
};
3252
int ret = cmocka_run_group_tests(tests, NULL, NULL);
3353
snowflake_global_term();

0 commit comments

Comments
 (0)