-
Notifications
You must be signed in to change notification settings - Fork 456
CDRIVER-4489 add mongoc_oidc_cache_t
#2119
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
Merged
Merged
Changes from 1 commit
Commits
Show all changes
23 commits
Select commit
Hold shift + click to select a range
93312c9
CDRIVER-4489 add `mongoc_oidc_cache_t`
kevinAlbs a6b14df
remove unnecessary precondition
kevinAlbs c1b4da4
use `const` in `mongoc_oidc_cache_get_callback`
kevinAlbs 4ee3ef0
rename `is_cache` => `found_in_cache` for clarity
kevinAlbs 05de8a1
make `mongoc_oidc_cache_get_cached_token` logically const
kevinAlbs 86bd7d0
rename `mongoc_oidc_cache_invalidate_cached_token` to `mongoc_oidc_ca…
kevinAlbs 2c3c33e
clarify `mongoc_oidc_cache_invalidate_token` may be called when a tok…
kevinAlbs f50b55b
use `bson_shared_mutex_t`
kevinAlbs 535c5f2
add asserts in setters
kevinAlbs 23ad9d2
reduce redundant NULL checks
kevinAlbs 0dd4599
use `mlib_now()` for timeout arg
kevinAlbs 69e2492
assert time passed is less than 100ms before second call to callback
kevinAlbs 28141c0
assert contents of tokens
kevinAlbs 4ba7062
define `PLACEHOLDER_TOKEN` macro
kevinAlbs 1b889c1
move assert
kevinAlbs 5f36c0a
isolate test for delay between calls. Expect 90ms delay.
kevinAlbs 9a1b0c5
use less "if" in comment
kevinAlbs e7d5410
add `MC_DISABLE_CAST_QUAL_WARNING_*` macros and ignore warning
kevinAlbs e82dfb0
deallocate outside of lock
kevinAlbs 61eab11
prepare callback params and deallocate outside of lock
kevinAlbs c9013e0
use scope around locks
kevinAlbs 818c433
deallocate outside of lock
kevinAlbs 51adf05
use `(60, s)` to work around CDRIVER-6102
kevinAlbs File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,67 @@ | ||
| /* | ||
| * Copyright 2009-present MongoDB, Inc. | ||
| * | ||
| * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| * you may not use this file except in compliance with the License. | ||
| * You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| */ | ||
|
|
||
| #ifndef MONGOC_OIDC_CACHE_PRIVATE_H | ||
| #define MONGOC_OIDC_CACHE_PRIVATE_H | ||
|
|
||
| #include <mongoc/mongoc-oidc-callback.h> | ||
| #include <mongoc/mongoc-sleep.h> | ||
|
|
||
| // mongoc_oidc_cache_t implements the OIDC spec "Client Cache". | ||
| // Stores the OIDC callback, cache, and lock. | ||
| // Expected to be shared among all clients in a pool. | ||
| typedef struct mongoc_oidc_cache_t mongoc_oidc_cache_t; | ||
|
|
||
| mongoc_oidc_cache_t * | ||
| mongoc_oidc_cache_new(void); | ||
|
|
||
| // mongoc_oidc_cache_set_callback sets the token callback. | ||
| // Not thread safe. Call before any authentication can occur. | ||
| void | ||
| mongoc_oidc_cache_set_callback(mongoc_oidc_cache_t *cache, const mongoc_oidc_callback_t *cb); | ||
|
|
||
| // mongoc_oidc_cache_get_callback gets the token callback. | ||
| // Not thread safe. Call before any authentication can occur. | ||
| const mongoc_oidc_callback_t * | ||
| mongoc_oidc_cache_get_callback(mongoc_oidc_cache_t *cache); | ||
eramongodb marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| // mongoc_oidc_cache_set_usleep_fn sets a custom sleep function. | ||
| // Not thread safe. Call before any authentication can occur. | ||
| void | ||
| mongoc_oidc_cache_set_usleep_fn(mongoc_oidc_cache_t *cache, mongoc_usleep_func_t usleep_fn, void *usleep_data); | ||
|
|
||
| // mongoc_oidc_cache_get_token returns a token or NULL on error. Thread safe. | ||
| // Sets *is_cache to indicate if the returned token came from the cache or callback. | ||
| // Calls sleep if needed to enforce 100ms delay between calls to the callback. | ||
| char * | ||
| mongoc_oidc_cache_get_token(mongoc_oidc_cache_t *cache, bool *is_cache, bson_error_t *error); | ||
eramongodb marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| // mongoc_oidc_cache_get_cached_token returns a cached token or NULL if none is cached. Thread safe. | ||
| char * | ||
| mongoc_oidc_cache_get_cached_token(mongoc_oidc_cache_t *cache); | ||
|
|
||
| // mongoc_oidc_cache_set_cached_token overwrites the cached token. Useful for tests. Thread safe. | ||
| void | ||
| mongoc_oidc_cache_set_cached_token(mongoc_oidc_cache_t *cache, const char *token); | ||
|
|
||
| // mongoc_oidc_cache_invalidate_cached_token invalidates if the cached token matches `token`. Thread safe. | ||
| void | ||
| mongoc_oidc_cache_invalidate_cached_token(mongoc_oidc_cache_t *cache, const char *token); | ||
eramongodb marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| void | ||
| mongoc_oidc_cache_destroy(mongoc_oidc_cache_t *); | ||
|
|
||
| #endif // MONGOC_OIDC_CACHE_PRIVATE_H | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,205 @@ | ||
| /* | ||
| * Copyright 2009-present MongoDB, Inc. | ||
| * | ||
| * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| * you may not use this file except in compliance with the License. | ||
| * You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| */ | ||
|
|
||
| #include <common-thread-private.h> | ||
| #include <mongoc/mongoc-error-private.h> | ||
| #include <mongoc/mongoc-oidc-cache-private.h> | ||
| #include <mongoc/mongoc-oidc-callback-private.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 { | ||
| // callback is owned. NULL if unset. Not guarded by lock. Set before requesting tokens. | ||
| mongoc_oidc_callback_t *callback; | ||
|
|
||
| // usleep_fn is used to sleep between calls to the callback. Not guarded by lock. Set before requesting tokens. | ||
| mongoc_usleep_func_t usleep_fn; | ||
| void *usleep_data; | ||
|
|
||
| // lock is used to prevent concurrent calls to callback. Guards access to token, last_called, and ever_called. | ||
| bson_mutex_t lock; | ||
eramongodb marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| // token is a cached OIDC access token. | ||
| char *token; | ||
|
|
||
| // last_call tracks the time just after the last call to the callback. | ||
| mlib_time_point last_called; | ||
|
|
||
| // ever_called is set to true after the first call to the callback. | ||
| bool ever_called; | ||
| }; | ||
|
|
||
| mongoc_oidc_cache_t * | ||
| mongoc_oidc_cache_new(void) | ||
| { | ||
| mongoc_oidc_cache_t *oidc = bson_malloc0(sizeof(mongoc_oidc_cache_t)); | ||
| oidc->usleep_fn = mongoc_usleep_default_impl; | ||
| bson_mutex_init(&oidc->lock); | ||
| return oidc; | ||
| } | ||
|
|
||
| void | ||
| mongoc_oidc_cache_set_callback(mongoc_oidc_cache_t *cache, const mongoc_oidc_callback_t *cb) | ||
| { | ||
| BSON_ASSERT_PARAM(cache); | ||
| BSON_OPTIONAL_PARAM(cb); | ||
|
|
||
| if (cache->callback) { | ||
eramongodb marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| mongoc_oidc_callback_destroy(cache->callback); | ||
| } | ||
| cache->callback = cb ? mongoc_oidc_callback_copy(cb) : NULL; | ||
| } | ||
|
|
||
| const mongoc_oidc_callback_t * | ||
| mongoc_oidc_cache_get_callback(mongoc_oidc_cache_t *cache) | ||
| { | ||
| BSON_ASSERT_PARAM(cache); | ||
|
|
||
| return cache->callback; | ||
| } | ||
|
|
||
| void | ||
| mongoc_oidc_cache_set_usleep_fn(mongoc_oidc_cache_t *cache, mongoc_usleep_func_t usleep_fn, void *usleep_data) | ||
| { | ||
| BSON_ASSERT_PARAM(cache); | ||
| BSON_OPTIONAL_PARAM(usleep_fn); | ||
| BSON_OPTIONAL_PARAM(usleep_data); | ||
|
|
||
| cache->usleep_fn = usleep_fn ? usleep_fn : mongoc_usleep_default_impl; | ||
eramongodb marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| cache->usleep_data = usleep_data; | ||
| } | ||
|
|
||
| void | ||
| mongoc_oidc_cache_destroy(mongoc_oidc_cache_t *cache) | ||
| { | ||
| if (!cache) { | ||
| return; | ||
| } | ||
| bson_free(cache->token); | ||
| bson_mutex_destroy(&cache->lock); | ||
| mongoc_oidc_callback_destroy(cache->callback); | ||
| bson_free(cache); | ||
| } | ||
|
|
||
| char * | ||
| mongoc_oidc_cache_get_cached_token(mongoc_oidc_cache_t *cache) | ||
eramongodb marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| { | ||
| BSON_ASSERT_PARAM(cache); | ||
|
|
||
| bson_mutex_lock(&cache->lock); | ||
| const char *token = cache->token; | ||
| bson_mutex_unlock(&cache->lock); | ||
| return token ? bson_strdup(token) : NULL; | ||
eramongodb marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| void | ||
| mongoc_oidc_cache_set_cached_token(mongoc_oidc_cache_t *cache, const char *token) | ||
| { | ||
| BSON_ASSERT_PARAM(cache); | ||
| BSON_OPTIONAL_PARAM(token); | ||
|
|
||
| bson_mutex_lock(&cache->lock); | ||
|
|
||
| if (cache->token) { | ||
| bson_free(cache->token); | ||
| cache->token = NULL; | ||
| } | ||
|
|
||
| cache->token = token ? bson_strdup(token) : NULL; | ||
| bson_mutex_unlock(&cache->lock); | ||
eramongodb marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| char * | ||
| mongoc_oidc_cache_get_token(mongoc_oidc_cache_t *cache, bool *is_cache, bson_error_t *error) | ||
| { | ||
| BSON_ASSERT_PARAM(cache); | ||
| BSON_ASSERT_PARAM(is_cache); | ||
| BSON_OPTIONAL_PARAM(error); | ||
|
|
||
| char *token = NULL; | ||
| mongoc_oidc_credential_t *cred = NULL; | ||
|
|
||
| *is_cache = false; | ||
|
|
||
| if (!cache->callback) { | ||
| SET_ERROR("MONGODB-OIDC requested, but no callback set"); | ||
| return NULL; | ||
| } | ||
|
|
||
| bson_mutex_lock(&cache->lock); | ||
|
|
||
| if (NULL != cache->token) { | ||
| // Access token is cached. | ||
| token = bson_strdup(cache->token); | ||
| *is_cache = true; | ||
| goto unlock_and_return; | ||
| } | ||
|
|
||
| mongoc_oidc_callback_params_t *params = mongoc_oidc_callback_params_new(); | ||
| mongoc_oidc_callback_params_set_user_data(params, mongoc_oidc_callback_get_user_data(cache->callback)); | ||
| // From spec: "If CSOT is not applied, then the driver MUST use 1 minute as the timeout." | ||
| // The timeout parameter (when set) is meant to be directly compared against bson_get_monotonic_time(). It is a | ||
| // time point, not a duration. | ||
| mongoc_oidc_callback_params_set_timeout(params, bson_get_monotonic_time() + 60 * 1000 * 1000); | ||
eramongodb marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| // From spec: "Wait until it has been at least 100ms since the last callback invocation" | ||
| if (cache->ever_called) { | ||
| mlib_duration since_last_call = mlib_time_difference(mlib_now(), cache->last_called); | ||
| if (mlib_duration_cmp(since_last_call, <, (100, ms))) { | ||
| mlib_duration to_sleep = mlib_duration((100, ms), minus, since_last_call); | ||
| cache->usleep_fn(mlib_microseconds_count(to_sleep), cache->usleep_data); | ||
| } | ||
| } | ||
|
|
||
| // Call callback: | ||
| cred = mongoc_oidc_callback_get_fn(cache->callback)(params); | ||
|
|
||
| cache->last_called = mlib_now(); | ||
| cache->ever_called = true; | ||
| mongoc_oidc_callback_params_destroy(params); | ||
|
||
|
|
||
| if (!cred) { | ||
| SET_ERROR("MONGODB-OIDC callback failed"); | ||
| goto unlock_and_return; | ||
| } | ||
|
|
||
| token = bson_strdup(mongoc_oidc_credential_get_access_token(cred)); | ||
| cache->token = bson_strdup(token); // Cache a copy. | ||
|
|
||
| unlock_and_return: | ||
| bson_mutex_unlock(&cache->lock); | ||
| mongoc_oidc_credential_destroy(cred); | ||
| return token; | ||
| } | ||
|
|
||
| void | ||
| mongoc_oidc_cache_invalidate_cached_token(mongoc_oidc_cache_t *cache, const char *token) | ||
| { | ||
| BSON_ASSERT_PARAM(cache); | ||
| BSON_ASSERT_PARAM(token); | ||
|
|
||
| bson_mutex_lock(&cache->lock); | ||
|
|
||
| if (cache->token && 0 == strcmp(cache->token, token)) { | ||
| bson_free(cache->token); | ||
| cache->token = NULL; | ||
| } | ||
|
|
||
| bson_mutex_unlock(&cache->lock); | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.