-
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
Changes from 16 commits
93312c9
a6b14df
c1b4da4
4ee3ef0
05de8a1
86bd7d0
2c3c33e
f50b55b
535c5f2
23ad9d2
0dd4599
69e2492
28141c0
4ba7062
1b889c1
5f36c0a
9a1b0c5
e7d5410
e82dfb0
61eab11
c9013e0
818c433
51adf05
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
/* | ||
* 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. | ||
const mongoc_oidc_callback_t * | ||
mongoc_oidc_cache_get_callback(const mongoc_oidc_cache_t *cache); | ||
|
||
// 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 *found_in_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 *found_in_cache, bson_error_t *error); | ||
|
||
// 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(const 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_token invalidates if the cached token (if any) matches `token`. Thread safe. | ||
void | ||
mongoc_oidc_cache_invalidate_token(mongoc_oidc_cache_t *cache, const char *token); | ||
|
||
void | ||
mongoc_oidc_cache_destroy(mongoc_oidc_cache_t *); | ||
|
||
#endif // MONGOC_OIDC_CACHE_PRIVATE_H |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,215 @@ | ||||||||||||||||||||||||||
/* | ||||||||||||||||||||||||||
* 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_shared_mutex_t lock; | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
// 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_shared_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); | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
BSON_ASSERT(!cache->ever_called); | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
if (cache->callback) { | ||||||||||||||||||||||||||
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(const 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); | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
BSON_ASSERT(!cache->ever_called); | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
cache->usleep_fn = usleep_fn ? usleep_fn : mongoc_usleep_default_impl; | ||||||||||||||||||||||||||
cache->usleep_data = usleep_data; | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
void | ||||||||||||||||||||||||||
mongoc_oidc_cache_destroy(mongoc_oidc_cache_t *cache) | ||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||
if (!cache) { | ||||||||||||||||||||||||||
return; | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
bson_free(cache->token); | ||||||||||||||||||||||||||
bson_shared_mutex_destroy(&cache->lock); | ||||||||||||||||||||||||||
mongoc_oidc_callback_destroy(cache->callback); | ||||||||||||||||||||||||||
bson_free(cache); | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
char * | ||||||||||||||||||||||||||
mongoc_oidc_cache_get_cached_token(const mongoc_oidc_cache_t *cache) | ||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||
BSON_ASSERT_PARAM(cache); | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
// Cast away const to lock. This function is logically const (read-only). | ||||||||||||||||||||||||||
bson_shared_mutex_lock_shared(&((mongoc_oidc_cache_t *)cache)->lock); | ||||||||||||||||||||||||||
char *token = bson_strdup(cache->token); | ||||||||||||||||||||||||||
bson_shared_mutex_unlock_shared(&((mongoc_oidc_cache_t *)cache)->lock); | ||||||||||||||||||||||||||
eramongodb marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||
return token; | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
void | ||||||||||||||||||||||||||
mongoc_oidc_cache_set_cached_token(mongoc_oidc_cache_t *cache, const char *token) | ||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||
BSON_ASSERT_PARAM(cache); | ||||||||||||||||||||||||||
BSON_OPTIONAL_PARAM(token); | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
bson_shared_mutex_lock(&cache->lock); | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
bson_free(cache->token); | ||||||||||||||||||||||||||
cache->token = NULL; | ||||||||||||||||||||||||||
cache->token = bson_strdup(token); | ||||||||||||||||||||||||||
bson_shared_mutex_unlock(&cache->lock); | ||||||||||||||||||||||||||
|
bson_shared_mutex_lock(&cache->lock); | |
bson_free(cache->token); | |
cache->token = NULL; | |
cache->token = bson_strdup(token); | |
bson_shared_mutex_unlock(&cache->lock); | |
bson_shared_mutex_lock(&cache->lock); | |
char *const old_token = cache->token; | |
cache->token = bson_strdup(token); | |
bson_shared_mutex_unlock(&cache->lock); | |
bson_free(old_token); |
Minor optimization: move deallocation out of critical zone + remove redundant assignment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated here and in mongoc_oidc_cache_invalidate_token
.
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor optimization: move callback param object initialization up and out of the critical section.
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor optimization: move callback param object deallocation down and out of the critical section.
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor suggestion: consider scoping critical sections with {}
:
{
// Obtain write-lock:
bson_shared_mutex_lock(&cache->lock);
...
unlock_and_return:
bson_shared_mutex_unlock(&cache->lock);
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wording tweak suggestion (a bit too many "if"s).