Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SNOW-1538117: Support privatelink environments #769

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
Open
5 changes: 5 additions & 0 deletions include/snowflake/client.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,11 @@ extern "C" {
*/
#define SF_JWT_CNXN_WAIT_TIME 10

/**
* Privatelink host suffix.
*/
#define PRIVATELINK_HOSTNAME_SUFFIX ".privatelink.snowflakecomputing."

/**
* Snowflake Data types
*
Expand Down
17 changes: 17 additions & 0 deletions lib/client.c
Original file line number Diff line number Diff line change
Expand Up @@ -475,15 +475,32 @@ _snowflake_check_connection_parameters(SF_CONNECT *sf) {
}

char* top_domain = strrchr(sf->host, '.');
char host_without_top_domain[1024];
if (top_domain)
{
top_domain++;
size_t length = top_domain - sf->host;
sf_strncpy(host_without_top_domain, sizeof(host_without_top_domain), sf->host,length);
}
else
{
// It's basically impossible not finding top domain in host.
// Log the entire host just in case.
top_domain = sf->host;
host_without_top_domain[0] = '\0';
}

//check privatelink
if (end_with(host_without_top_domain, PRIVATELINK_HOSTNAME_SUFFIX))
{
char url_buf[4096];
sf_sprintf(url_buf, sizeof(url_buf), "http://ocsp.%s/%s",
sfc-gh-jszczerbinski marked this conversation as resolved.
Show resolved Hide resolved
sf->host, "ocsp_response_cache.json");
log_trace(
sfc-gh-jszczerbinski marked this conversation as resolved.
Show resolved Hide resolved
"sf", "Connection", "connect",
"Setting SF_OCSP_RESPONSE_CACHE_SERVER_URL to %s",
url_buf);
sf_setenv("SF_OCSP_RESPONSE_CACHE_SERVER_URL", url_buf);
}

log_info("Connecting to %s Snowflake domain", (strcasecmp(top_domain, "cn") == 0) ? "CHINA" : "GLOBAL");
Expand Down
12 changes: 12 additions & 0 deletions lib/connection.c
Original file line number Diff line number Diff line change
Expand Up @@ -1344,4 +1344,16 @@ int64 get_retry_timeout(SF_CONNECT *sf)
int8 get_login_retry_count(SF_CONNECT *sf)
{
return (int8)get_less_one(sf->retry_on_connect_count, sf->retry_count);
}

sf_bool end_with(char* a, char* b)
sfc-gh-jszczerbinski marked this conversation as resolved.
Show resolved Hide resolved
sfc-gh-jszczerbinski marked this conversation as resolved.
Show resolved Hide resolved
sfc-gh-jszczerbinski marked this conversation as resolved.
Show resolved Hide resolved
{
if (strlen(b) > strlen(a))
{
return SF_BOOLEAN_FALSE;
}

char* as = a + (strlen(a) - strlen(b));

return sf_strncasecmp(as, b, strlen(b)) == 0 ? SF_BOOLEAN_TRUE : SF_BOOLEAN_FALSE;
sfc-gh-jszczerbinski marked this conversation as resolved.
Show resolved Hide resolved
}
5 changes: 5 additions & 0 deletions lib/connection.h
Original file line number Diff line number Diff line change
Expand Up @@ -624,6 +624,11 @@ int64 get_retry_timeout(SF_CONNECT *sf);
*/
uint64 sf_get_current_time_millis();

/**
* Validate that the value of a ends with the value of b
*/
sf_bool end_with(char* a, char* b);

#ifdef __cplusplus
}
#endif
Expand Down
1 change: 1 addition & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ SET(TESTS_C
test_unit_oauth
test_unit_mfa_auth
test_ocsp_fail_open
test_unit_privatelink
# FEATURE_INCREASED_MAX_LOB_SIZE_IN_MEMORY is internal switch
# will enable lob test when the change on server side will be published
# test_lob
Expand Down
59 changes: 59 additions & 0 deletions tests/test_unit_privatelink.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* Copyright (c) 2018-2024 Snowflake Computing, Inc. All rights reserved.
*/

#include <string.h>
#include "utils/test_setup.h"
#include "connection.h"
#include "memory.h"

/**
* Test json body is properly updated.
*/
void test_private_link_core(void** unused)
{
char* original_env = getenv("SF_OCSP_RESPONSE_CACHE_SERVER_URL");
SF_CONNECT* sf = (SF_CONNECT*)SF_CALLOC(1, sizeof(SF_CONNECT));
sf->account = "testaccount";
sf->user = "testuser";
sf->password = "testpassword";
sf->authenticator = SF_AUTHENTICATOR_DEFAULT;

_snowflake_check_connection_parameters(sf);
assert_int_equal(NULL, getenv("SF_OCSP_RESPONSE_CACHE_SERVER_URL"));
sf_unsetenv("SF_OCSP_RESPONSE_CACHE_SERVER_URL");

sf->host = "account.privateLINK.snowflakecomputING.com";
_snowflake_check_connection_parameters(sf);
assert_string_equal("http://ocsp.account.privateLINK.snowflakecomputING.com/ocsp_response_cache.json", getenv("SF_OCSP_RESPONSE_CACHE_SERVER_URL"));
sf_unsetenv("SF_OCSP_RESPONSE_CACHE_SERVER_URL");

sf->host = "account.snowflakecomputing.com";
_snowflake_check_connection_parameters(sf);
assert_int_equal(NULL, getenv("SF_OCSP_RESPONSE_CACHE_SERVER_URL"));
sf_unsetenv("SF_OCSP_RESPONSE_CACHE_SERVER_URL");

sf->host = "account.privatelink.snowflakecomputing.cn";
_snowflake_check_connection_parameters(sf);
assert_string_equal("http://ocsp.account.privatelink.snowflakecomputing.cn/ocsp_response_cache.json", getenv("SF_OCSP_RESPONSE_CACHE_SERVER_URL"));
sf_unsetenv("SF_OCSP_RESPONSE_CACHE_SERVER_URL");


if (original_env) {
sf_setenv("SF_OCSP_RESPONSE_CACHE_SERVER_URL", original_env);
}
else {
sf_unsetenv("SF_OCSP_RESPONSE_CACHE_SERVER_URL");
}
}

int main(void)
{
initialize_test(SF_BOOLEAN_FALSE);
const struct CMUnitTest tests[] = {
cmocka_unit_test(test_private_link_core),
};
int ret = cmocka_run_group_tests(tests, NULL, NULL);
snowflake_global_term();
return ret;
}
Loading