Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion src/libmongoc/src/mongoc/mongoc-client-pool.c
Original file line number Diff line number Diff line change
Expand Up @@ -707,7 +707,8 @@ mongoc_client_pool_set_oidc_callback(mongoc_client_pool_t *pool, const mongoc_oi
return false;
}

mongoc_oidc_cache_set_user_callback(pool->topology->oidc_cache, callback);
mongoc_oidc_cache_set_user_callback(
pool->topology->oidc_cache, mongoc_uri_get_username(pool->topology->uri), callback);
return true;
}

Expand Down
3 changes: 2 additions & 1 deletion src/libmongoc/src/mongoc/mongoc-client.c
Original file line number Diff line number Diff line change
Expand Up @@ -2786,7 +2786,8 @@ mongoc_client_set_oidc_callback(mongoc_client_t *client, const mongoc_oidc_callb
return false;
}

mongoc_oidc_cache_set_user_callback(client->topology->oidc_cache, callback);
mongoc_oidc_cache_set_user_callback(
client->topology->oidc_cache, mongoc_uri_get_username(client->topology->uri), callback);
return true;
}

Expand Down
2 changes: 1 addition & 1 deletion src/libmongoc/src/mongoc/mongoc-oidc-cache-private.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ mongoc_oidc_cache_apply_env_from_uri(mongoc_oidc_cache_t *cache, const struct _m
// mongoc_oidc_cache_set_user_callback sets the token callback.
// Not thread safe. Call before any authentication can occur.
void
mongoc_oidc_cache_set_user_callback(mongoc_oidc_cache_t *cache, const mongoc_oidc_callback_t *cb);
mongoc_oidc_cache_set_user_callback(mongoc_oidc_cache_t *cache, const char *username, const mongoc_oidc_callback_t *cb);

// mongoc_oidc_cache_has_user_callback returns true if a custom callback was set.
bool
Expand Down
21 changes: 14 additions & 7 deletions src/libmongoc/src/mongoc/mongoc-oidc-cache.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,15 @@
#include <mongoc/mongoc-oidc-callback-private.h>
#include <mongoc/mongoc-oidc-env-private.h>

#include <mongoc/mcd-azure.h>

#include <mlib/duration.h>
#include <mlib/time_point.h>

#define SET_ERROR(...) _mongoc_set_error(error, MONGOC_ERROR_CLIENT, MONGOC_ERROR_CLIENT_AUTHENTICATE, __VA_ARGS__)

struct mongoc_oidc_cache_t {
// username is copied from the URI.
char *username;

// user_callback is owned. NULL if unset. Not guarded by lock. Set before requesting tokens.
// If both user_callback and env_callback are set, an error occurs when requesting a token.
mongoc_oidc_callback_t *user_callback;
Expand Down Expand Up @@ -103,21 +104,25 @@ mongoc_oidc_cache_apply_env_from_uri(mongoc_oidc_cache_t *cache, const mongoc_ur
mongoc_oidc_env_requires_token_resource(env)); // Checked in mongoc_uri_finalize_auth.

BSON_ASSERT(!cache->env_callback); // Not set yet.
cache->env_callback = mongoc_oidc_env_callback_new(env, token_resource, username);
cache->env_callback = mongoc_oidc_env_callback_new(env, token_resource);

BSON_ASSERT(!cache->username); // Not set yet.
cache->username = bson_strdup(username);
}

void
mongoc_oidc_cache_set_user_callback(mongoc_oidc_cache_t *cache, const mongoc_oidc_callback_t *cb)
mongoc_oidc_cache_set_user_callback(mongoc_oidc_cache_t *cache, const char *username, const mongoc_oidc_callback_t *cb)
{
BSON_ASSERT_PARAM(cache);
BSON_OPTIONAL_PARAM(username);
BSON_OPTIONAL_PARAM(cb);

BSON_ASSERT(!cache->ever_called);

if (cache->user_callback) {
mongoc_oidc_callback_destroy(cache->user_callback);
}
mongoc_oidc_callback_destroy(cache->user_callback);
cache->user_callback = cb ? mongoc_oidc_callback_copy(cb) : NULL;
bson_free(cache->username);
cache->username = bson_strdup(username);
}

bool
Expand Down Expand Up @@ -151,6 +156,7 @@ mongoc_oidc_cache_destroy(mongoc_oidc_cache_t *cache)
bson_shared_mutex_destroy(&cache->lock);
mongoc_oidc_callback_destroy(cache->user_callback);
mongoc_oidc_env_callback_destroy(cache->env_callback);
bson_free(cache->username);
bson_free(cache);
}

Expand Down Expand Up @@ -226,6 +232,7 @@ mongoc_oidc_cache_get_token(mongoc_oidc_cache_t *cache, bool *found_in_cache, bs
// time point, not a duration. bson_get_monotonic_time() calls mlib_now(). Use mlib_now() directly.
mongoc_oidc_callback_params_set_timeout(
params, mlib_microseconds_count(mlib_time_add(mlib_now(), mlib_duration(60, s)).time_since_monotonic_start));
mongoc_oidc_callback_params_set_username(params, cache->username);

// Obtain write-lock:
{
Expand Down
2 changes: 1 addition & 1 deletion src/libmongoc/src/mongoc/mongoc-oidc-env-private.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ bool
mongoc_oidc_env_requires_token_resource(const mongoc_oidc_env_t *env);

mongoc_oidc_env_callback_t *
mongoc_oidc_env_callback_new(const mongoc_oidc_env_t *env, const char *token_resource, const char *username);
mongoc_oidc_env_callback_new(const mongoc_oidc_env_t *env, const char *token_resource);

void
mongoc_oidc_env_callback_destroy(mongoc_oidc_env_callback_t *env_callback);
Expand Down
10 changes: 3 additions & 7 deletions src/libmongoc/src/mongoc/mongoc-oidc-env.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ struct _mongoc_oidc_env_t {
struct _mongoc_oidc_env_callback_t {
mongoc_oidc_callback_t *inner; // Contains non-owning user_data pointer back to this mongoc_oidc_env_callback_t
char *token_resource;
char *username;
};

static mongoc_oidc_credential_t *
Expand Down Expand Up @@ -74,7 +73,7 @@ mongoc_oidc_env_fn_azure(mongoc_oidc_callback_params_t *params)
0, // Default port as well
NULL, // No extra headers
timer,
callback->username, // Optional client id
mongoc_oidc_callback_params_get_username(params), // Optional client id
&error)) {
MONGOC_ERROR("Failed to obtain Azure OIDC access token: %s", error.message);
goto fail;
Expand Down Expand Up @@ -240,18 +239,16 @@ mongoc_oidc_env_requires_token_resource(const mongoc_oidc_env_t *env)
}

mongoc_oidc_env_callback_t *
mongoc_oidc_env_callback_new(const mongoc_oidc_env_t *env, const char *token_resource, const char *username)
mongoc_oidc_env_callback_new(const mongoc_oidc_env_t *env, const char *token_resource)
{
BSON_ASSERT_PARAM(env);
BSON_OPTIONAL_PARAM(token_resource);
BSON_OPTIONAL_PARAM(username);
mongoc_oidc_env_callback_t *env_callback = bson_malloc(sizeof *env_callback);
// Note that the callback's user_data points back to this containing mongoc_oidc_env_callback_t.
// We expect that the inner callback can only be destroyed via mongoc_oidc_env_callback_destroy.
*env_callback =
(mongoc_oidc_env_callback_t){.inner = mongoc_oidc_callback_new_with_user_data(env->callback_fn, env_callback),
.token_resource = bson_strdup(token_resource),
.username = bson_strdup(username)};
.token_resource = bson_strdup(token_resource)};
return env_callback;
}

Expand All @@ -262,7 +259,6 @@ mongoc_oidc_env_callback_destroy(mongoc_oidc_env_callback_t *env_callback)
BSON_ASSERT(mongoc_oidc_callback_get_user_data(env_callback->inner) == (void *)env_callback);
mongoc_oidc_callback_destroy(env_callback->inner);
bson_free(env_callback->token_resource);
bson_free(env_callback->username);
bson_free(env_callback);
}
}
Expand Down
44 changes: 38 additions & 6 deletions src/libmongoc/tests/test-mongoc-oidc-cache.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
typedef struct {
int call_count;
bool returns_null;
const char *expect_username;
} callback_ctx_t;

#define PLACEHOLDER_TOKEN "PLACEHOLDER_TOKEN"
Expand All @@ -36,6 +37,7 @@ oidc_callback_fn(mongoc_oidc_callback_params_t *params)
if (ctx->returns_null) {
return NULL;
}
ASSERT_CMPSTR(mongoc_oidc_callback_params_get_username(params), ctx->expect_username);
return mongoc_oidc_credential_new(PLACEHOLDER_TOKEN);
}

Expand All @@ -59,7 +61,7 @@ test_oidc_cache_works(void)
{
mongoc_oidc_callback_t *cb = mongoc_oidc_callback_new(oidc_callback_fn);
mongoc_oidc_callback_set_user_data(cb, &ctx);
mongoc_oidc_cache_set_user_callback(cache, cb);
mongoc_oidc_cache_set_user_callback(cache, NULL, cb);
mongoc_oidc_callback_destroy(cb);
}

Expand Down Expand Up @@ -122,7 +124,7 @@ test_oidc_cache_waits_between_calls(void)
{
mongoc_oidc_callback_t *cb = mongoc_oidc_callback_new(oidc_callback_fn);
mongoc_oidc_callback_set_user_data(cb, &ctx);
mongoc_oidc_cache_set_user_callback(cache, cb);
mongoc_oidc_cache_set_user_callback(cache, NULL, cb);
mongoc_oidc_callback_destroy(cb);
}

Expand Down Expand Up @@ -183,20 +185,49 @@ test_oidc_cache_set_callback(void)
// Can set a callback:
{
mongoc_oidc_callback_t *cb = mongoc_oidc_callback_new(oidc_callback_fn);
mongoc_oidc_cache_set_user_callback(cache, cb);
mongoc_oidc_cache_set_user_callback(cache, NULL, cb);
ASSERT(mongoc_oidc_cache_has_user_callback(cache));
mongoc_oidc_callback_destroy(cb);
}

// Can clear a callback:
{
mongoc_oidc_cache_set_user_callback(cache, NULL);
mongoc_oidc_cache_set_user_callback(cache, NULL, NULL);
ASSERT(!mongoc_oidc_cache_has_user_callback(cache));
}

mongoc_oidc_cache_destroy(cache);
}

static void
test_oidc_cache_passes_username(void)
{
bool found_in_cache = false;
bson_error_t error;
mongoc_oidc_cache_t *cache = mongoc_oidc_cache_new();
callback_ctx_t ctx = {.expect_username = "test_user"};

// Set a callback:
{
mongoc_oidc_callback_t *cb = mongoc_oidc_callback_new(oidc_callback_fn);
mongoc_oidc_callback_set_user_data(cb, &ctx);
mongoc_oidc_cache_set_user_callback(cache, "test_user", cb);
mongoc_oidc_callback_destroy(cb);
}

// Expect callback is called to fetch token:
{
char *token = mongoc_oidc_cache_get_token(cache, &found_in_cache, &error);
ASSERT_OR_PRINT(token, error);
ASSERT_CMPSTR(token, PLACEHOLDER_TOKEN);
ASSERT_CMPINT(ctx.call_count, ==, 1);
ASSERT(!found_in_cache);
bson_free(token);
}

mongoc_oidc_cache_destroy(cache);
}

typedef struct {
int call_count;
int64_t last_arg;
Expand All @@ -222,7 +253,7 @@ test_oidc_cache_set_sleep(void)
{
mongoc_oidc_callback_t *cb = mongoc_oidc_callback_new(oidc_callback_fn);
mongoc_oidc_callback_set_user_data(cb, &ctx);
mongoc_oidc_cache_set_user_callback(cache, cb);
mongoc_oidc_cache_set_user_callback(cache, NULL, cb);
mongoc_oidc_callback_destroy(cb);
}

Expand Down Expand Up @@ -300,7 +331,7 @@ test_oidc_cache_propagates_error(void)
{
mongoc_oidc_callback_t *cb = mongoc_oidc_callback_new(oidc_callback_fn);
mongoc_oidc_callback_set_user_data(cb, &ctx);
mongoc_oidc_cache_set_user_callback(cache, cb);
mongoc_oidc_cache_set_user_callback(cache, NULL, cb);
mongoc_oidc_callback_destroy(cb);
}

Expand Down Expand Up @@ -388,5 +419,6 @@ test_mongoc_oidc_install(TestSuite *suite)
TestSuite_Add(suite, "/oidc/cache/propagates_error", test_oidc_cache_propagates_error);
TestSuite_Add(suite, "/oidc/cache/invalidate", test_oidc_cache_invalidate);
TestSuite_Add(suite, "/oidc/cache/waits_between_calls", test_oidc_cache_waits_between_calls);
TestSuite_Add(suite, "/oidc/cache/passes_username", test_oidc_cache_passes_username);
TestSuite_Add(suite, "/oidc/connection_cache", test_oidc_connection_cache);
}
11 changes: 9 additions & 2 deletions src/libmongoc/tests/test-mongoc-oidc.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ read_test_token(void)
}

typedef struct {
const char *expect_username;
bool validate_params;
bool return_null;
bool return_bad_token;
Expand Down Expand Up @@ -83,7 +84,7 @@ oidc_callback_fn(mongoc_oidc_callback_params_t *params)
ASSERT_CMPINT(version, ==, 1);

const char *username = mongoc_oidc_callback_params_get_username(params);
ASSERT(!username);
ASSERT_CMPSTR(username, ctx->config.expect_username);
}

char *token = read_test_token();
Expand All @@ -103,6 +104,7 @@ typedef struct {
typedef struct {
bool use_pool;
bool use_error_api_v1;
const char *with_username;
callback_config_t callback_config;
} test_config_t;

Expand Down Expand Up @@ -167,6 +169,9 @@ test_fixture_new(test_config_t cfg)
test_fixture_t *tf = bson_malloc0(sizeof(*tf));

mongoc_uri_t *uri = get_test_uri();
if (cfg.with_username) {
mongoc_uri_set_username(uri, cfg.with_username);
}
mongoc_uri_set_appname(uri, "mongoc-oidc");
mongoc_uri_set_auth_mechanism(uri, "MONGODB-OIDC");
mongoc_uri_set_option_as_bool(uri, MONGOC_URI_RETRYREADS, false); // Disable retryable reads per spec.
Expand Down Expand Up @@ -577,7 +582,9 @@ PROSE_TEST(2, 1, "Valid Callback Inputs")
{
bool use_pool = *(bool *)use_pool_void;
test_fixture_t *tf =
test_fixture_new((test_config_t){.use_pool = use_pool, .callback_config = {.validate_params = true}});
test_fixture_new((test_config_t){.use_pool = use_pool,
.with_username = "foo",
.callback_config = {.validate_params = true, .expect_username = "foo"}});

// Expect auth to succeed:
bson_error_t error;
Expand Down