diff --git a/src/libmongoc/CMakeLists.txt b/src/libmongoc/CMakeLists.txt index fa303f235a..0f801a7f0d 100644 --- a/src/libmongoc/CMakeLists.txt +++ b/src/libmongoc/CMakeLists.txt @@ -597,6 +597,7 @@ set (MONGOC_SOURCES ${PROJECT_SOURCE_DIR}/src/mongoc/mongoc-log-and-monitor-private.c ${PROJECT_SOURCE_DIR}/src/mongoc/mongoc-memcmp.c ${PROJECT_SOURCE_DIR}/src/mongoc/mongoc-cmd.c + ${PROJECT_SOURCE_DIR}/src/mongoc/mongoc-oidc-callback.c ${PROJECT_SOURCE_DIR}/src/mongoc/mongoc-opcode.c ${PROJECT_SOURCE_DIR}/src/mongoc/mongoc-optional.c ${PROJECT_SOURCE_DIR}/src/mongoc/mongoc-opts-helpers.c @@ -717,6 +718,7 @@ set (HEADERS ${PROJECT_SOURCE_DIR}/src/mongoc/mongoc-iovec.h ${PROJECT_SOURCE_DIR}/src/mongoc/mongoc-log.h ${PROJECT_SOURCE_DIR}/src/mongoc/mongoc-macros.h + ${PROJECT_SOURCE_DIR}/src/mongoc/mongoc-oidc-callback.h ${PROJECT_SOURCE_DIR}/src/mongoc/mongoc-opcode.h ${PROJECT_SOURCE_DIR}/src/mongoc/mongoc-optional.h ${PROJECT_SOURCE_DIR}/src/mongoc/mongoc-prelude.h @@ -1057,6 +1059,7 @@ set (test-libmongoc-sources ${PROJECT_SOURCE_DIR}/tests/test-mongoc-max-staleness.c ${PROJECT_SOURCE_DIR}/tests/test-mongoc-mongohouse.c ${PROJECT_SOURCE_DIR}/tests/test-mongoc-mongos-pinning.c + ${PROJECT_SOURCE_DIR}/tests/test-mongoc-oidc-callback.c ${PROJECT_SOURCE_DIR}/tests/test-mongoc-opts.c ${PROJECT_SOURCE_DIR}/tests/test-mongoc-primary-stepdown.c ${PROJECT_SOURCE_DIR}/tests/test-mongoc-queue.c diff --git a/src/libmongoc/doc/api.rst b/src/libmongoc/doc/api.rst index c47650d03c..0387b3b15e 100644 --- a/src/libmongoc/doc/api.rst +++ b/src/libmongoc/doc/api.rst @@ -39,6 +39,10 @@ API Reference mongoc_host_list_t mongoc_insert_flags_t mongoc_iovec_t + mongoc_oidc_callback_fn_t + mongoc_oidc_callback_params_t + mongoc_oidc_callback_t + mongoc_oidc_credential_t mongoc_optional_t mongoc_query_flags_t mongoc_rand diff --git a/src/libmongoc/doc/mongoc_oidc_callback_destroy.rst b/src/libmongoc/doc/mongoc_oidc_callback_destroy.rst new file mode 100644 index 0000000000..ff6db70e3b --- /dev/null +++ b/src/libmongoc/doc/mongoc_oidc_callback_destroy.rst @@ -0,0 +1,27 @@ +:man_page: mongoc_oidc_callback_destroy + +mongoc_oidc_callback_destroy() +============================== + +Synopsis +-------- + +.. code-block:: c + + void + mongoc_oidc_callback_destroy (mongoc_oidc_callback_t *callback) + +Release all resources associated with the given :symbol:`mongoc_oidc_callback_t` object. + +.. warning:: + + The lifetime of the object pointed to by ``user_data`` is managed the user, not by :symbol:`mongoc_oidc_callback_t`! + +Parameters +---------- + +* ``callback``: a :symbol:`mongoc_oidc_callback_t` or ``NULL``. + +.. seealso:: + + - :symbol:`mongoc_oidc_callback_t` diff --git a/src/libmongoc/doc/mongoc_oidc_callback_fn_t.rst b/src/libmongoc/doc/mongoc_oidc_callback_fn_t.rst new file mode 100644 index 0000000000..5fd62a369e --- /dev/null +++ b/src/libmongoc/doc/mongoc_oidc_callback_fn_t.rst @@ -0,0 +1,35 @@ +:man_page: mongoc_oidc_callback_fn_t + +mongoc_oidc_callback_fn_t +========================= + +Synopsis +-------- + +.. code-block:: c + + typedef mongoc_oidc_credential_t *(*mongoc_oidc_callback_fn_t) (mongoc_oidc_callback_params_t *params); + +The type of the function pointer stored by :symbol:`mongoc_oidc_callback_t`. + +Parameters +---------- + +* ``params``: A :symbol:`mongoc_oidc_callback_params_t` object representing in/out parameters of a :symbol:`mongoc_oidc_callback_t`. + +Returns +------- + +A :symbol:`mongoc_oidc_credential_t` object created with :symbol:`mongoc_oidc_credential_new()`, or ``NULL`` to indicate an error or timeout. + +* The function MUST return a :symbol:`mongoc_oidc_credential_t` object to indicate success. +* The function MUST return ``NULL`` to indicate an error. +* The function MUST call :symbol:`mongoc_oidc_callback_params_cancel_with_timeout()` before returning ``NULL`` to indicate a timeout instead of an error. + +The ``cancel_with_timeout`` out parameter is ignored if the return value is not ``NULL``. + +.. seealso:: + + - :symbol:`mongoc_oidc_callback_t` + - :symbol:`mongoc_oidc_callback_params_t` + - :symbol:`mongoc_oidc_credential_t` diff --git a/src/libmongoc/doc/mongoc_oidc_callback_get_fn.rst b/src/libmongoc/doc/mongoc_oidc_callback_get_fn.rst new file mode 100644 index 0000000000..bf1bcc04a4 --- /dev/null +++ b/src/libmongoc/doc/mongoc_oidc_callback_get_fn.rst @@ -0,0 +1,29 @@ +:man_page: mongoc_oidc_callback_get_fn + +mongoc_oidc_callback_get_fn() +============================= + +Synopsis +-------- + +.. code-block:: c + + mongoc_oidc_callback_fn_t + mongoc_oidc_callback_get_fn (const mongoc_oidc_callback_t *callback); + +Return the stored pointer to the callback function. + +Parameters +---------- + +* ``callback``: a :symbol:`mongoc_oidc_callback_t`. + +Returns +------- + +A :symbol:`mongoc_oidc_callback_fn_t`. + +.. seealso:: + + - :symbol:`mongoc_oidc_callback_t` + - :symbol:`mongoc_oidc_callback_fn_t` diff --git a/src/libmongoc/doc/mongoc_oidc_callback_get_user_data.rst b/src/libmongoc/doc/mongoc_oidc_callback_get_user_data.rst new file mode 100644 index 0000000000..0edabb3935 --- /dev/null +++ b/src/libmongoc/doc/mongoc_oidc_callback_get_user_data.rst @@ -0,0 +1,29 @@ +:man_page: mongoc_oidc_callback_get_user_data + +mongoc_oidc_callback_get_user_data() +==================================== + +Synopsis +-------- + +.. code-block:: c + + void * + mongoc_oidc_callback_get_user_data (const mongoc_oidc_callback_t *callback); + +Return the stored pointer to user data. + +Parameters +---------- + +* ``callback``: a :symbol:`mongoc_oidc_callback_t`. + +Returns +------- + +A pointer to user data or ``NULL``. + +.. seealso:: + + - :symbol:`mongoc_oidc_callback_t` + - :symbol:`mongoc_oidc_callback_set_user_data()` diff --git a/src/libmongoc/doc/mongoc_oidc_callback_new.rst b/src/libmongoc/doc/mongoc_oidc_callback_new.rst new file mode 100644 index 0000000000..2f7f93f6d9 --- /dev/null +++ b/src/libmongoc/doc/mongoc_oidc_callback_new.rst @@ -0,0 +1,31 @@ +:man_page: mongoc_oidc_callback_new + +mongoc_oidc_callback_new() +========================== + +Synopsis +-------- + +.. code-block:: c + + mongoc_oidc_callback_t * + mongoc_oidc_callback_new (mongoc_oidc_callback_fn_t fn) + +Create a new :symbol:`mongoc_oidc_callback_t` object which stores the provided OIDC callback function. + +Equivalent to calling :symbol:`mongoc_oidc_callback_new_with_user_data()` with ``user_data`` set to ``NULL``. + +Parameters +---------- + +* ``fn``: a :symbol:`mongoc_oidc_callback_fn_t`. Must not be ``NULL``. + +Returns +------- + +A new :symbol:`mongoc_oidc_callback_t` that must be freed with :symbol:`mongoc_oidc_callback_destroy()`, or ``NULL`` when an invalid argument was given. + +.. seealso:: + + - :symbol:`mongoc_oidc_callback_t` + - :symbol:`mongoc_oidc_callback_new_with_user_data` diff --git a/src/libmongoc/doc/mongoc_oidc_callback_new_with_user_data.rst b/src/libmongoc/doc/mongoc_oidc_callback_new_with_user_data.rst new file mode 100644 index 0000000000..7cfc1ba4bd --- /dev/null +++ b/src/libmongoc/doc/mongoc_oidc_callback_new_with_user_data.rst @@ -0,0 +1,34 @@ +:man_page: mongoc_oidc_callback_new_with_user_data + +mongoc_oidc_callback_new_with_user_data() +========================================= + +Synopsis +-------- + +.. code-block:: c + + mongoc_oidc_callback_t * + mongoc_oidc_callback_new_with_user_data (mongoc_oidc_callback_fn_t fn, void *user_data) + +Create a new :symbol:`mongoc_oidc_callback_t` object which stores the provided OIDC callback function and pointer to user data. + +.. warning:: + + The lifetime of the object pointed to by ``user_data`` is managed the user, not by :symbol:`mongoc_oidc_callback_t`! + +Parameters +---------- + +* ``fn``: a :symbol:`mongoc_oidc_callback_fn_t`. Must not be ``NULL``. +* ``user_data``: a pointer to user data or ``NULL``. + +Returns +------- + +A new :symbol:`mongoc_oidc_callback_t` that must be freed with :symbol:`mongoc_oidc_callback_destroy()`, or ``NULL`` when an invalid argument was given. + +.. seealso:: + + - :symbol:`mongoc_oidc_callback_t` + - :symbol:`mongoc_oidc_callback_new` diff --git a/src/libmongoc/doc/mongoc_oidc_callback_params_cancel_with_timeout.rst b/src/libmongoc/doc/mongoc_oidc_callback_params_cancel_with_timeout.rst new file mode 100644 index 0000000000..62373eff27 --- /dev/null +++ b/src/libmongoc/doc/mongoc_oidc_callback_params_cancel_with_timeout.rst @@ -0,0 +1,33 @@ +:man_page: mongoc_oidc_callback_params_cancel_with_timeout + +mongoc_oidc_callback_params_cancel_with_timeout() +================================================= + +Synopsis +-------- + +.. code-block:: c + + mongoc_oidc_credential_t * + mongoc_oidc_callback_params_cancel_with_timeout (mongoc_oidc_callback_params_t *params); + +Set the out parameter indicating cancellation of the callback function due to a timeout instead of an error. + +.. note:: + + If the callback function returns a not-null value, the value of this out parameter is ignored. + +Parameters +---------- + +* ``params``: a :symbol:`mongoc_oidc_callback_params_t`. + +Returns +------- + +``NULL``. + +.. seealso:: + + - :symbol:`mongoc_oidc_callback_params_t` + - :symbol:`mongoc_oidc_callback_t` diff --git a/src/libmongoc/doc/mongoc_oidc_callback_params_get_timeout.rst b/src/libmongoc/doc/mongoc_oidc_callback_params_get_timeout.rst new file mode 100644 index 0000000000..36919ee0fb --- /dev/null +++ b/src/libmongoc/doc/mongoc_oidc_callback_params_get_timeout.rst @@ -0,0 +1,36 @@ +:man_page: mongoc_oidc_callback_params_get_timeout + +mongoc_oidc_callback_params_get_timeout() +========================================= + +Synopsis +-------- + +.. code-block:: c + + const int64_t * + mongoc_oidc_callback_params_get_timeout (const mongoc_oidc_callback_params_t *params); + +Return a value comparable with :symbol:`bson_get_monotonic_time()` to determine when a timeout must occur. + +A ``NULL`` (unset) return value means "infinite" timeout. + +Parameters +---------- + +* ``params``: a :symbol:`mongoc_oidc_callback_params_t`. + +Returns +------- + +A value comparable with :symbol:`bson_get_monotonic_time()`, or ``NULL``. + +Lifecycle +--------- + +The pointed-to ``int64_t`` is only valid for the duration of the invocation of the OIDC callback function. + +.. seealso:: + + - :symbol:`mongoc_oidc_callback_params_t` + - :symbol:`mongoc_oidc_callback_t` diff --git a/src/libmongoc/doc/mongoc_oidc_callback_params_get_user_data.rst b/src/libmongoc/doc/mongoc_oidc_callback_params_get_user_data.rst new file mode 100644 index 0000000000..e6e7db3f18 --- /dev/null +++ b/src/libmongoc/doc/mongoc_oidc_callback_params_get_user_data.rst @@ -0,0 +1,35 @@ +:man_page: mongoc_oidc_callback_params_get_user_data + +mongoc_oidc_callback_params_get_user_data() +=========================================== + +Synopsis +-------- + +.. code-block:: c + + void * + mongoc_oidc_callback_params_get_user_data (const mongoc_oidc_callback_params_t *params); + +Return the pointer to user data which was stored by an associated :symbol:`mongoc_oidc_callback_t` object. + +Parameters +---------- + +* ``params``: a :symbol:`mongoc_oidc_callback_params_t`. + +Returns +------- + +A pointer to user data or ``NULL``. + +Lifecycle +--------- + +The lifetime of the object pointed to by ``user_data`` is managed the user. + +.. seealso:: + + - :symbol:`mongoc_oidc_callback_params_t` + - :symbol:`mongoc_oidc_callback_t` + - :symbol:`mongoc_oidc_callback_set_user_data()` diff --git a/src/libmongoc/doc/mongoc_oidc_callback_params_get_username.rst b/src/libmongoc/doc/mongoc_oidc_callback_params_get_username.rst new file mode 100644 index 0000000000..2de4c3408f --- /dev/null +++ b/src/libmongoc/doc/mongoc_oidc_callback_params_get_username.rst @@ -0,0 +1,35 @@ +:man_page: mongoc_oidc_callback_params_get_username + +mongoc_oidc_callback_params_get_username() +========================================== + +Synopsis +-------- + +.. code-block:: c + + const char * + mongoc_oidc_callback_params_get_username (const mongoc_oidc_callback_params_t *params); + +Return the username component of the URI of an associated :symbol:`mongoc_client_t` or :symbol:`mongoc_client_pool_t` object. + +Parameters +---------- + +* ``params``: a :symbol:`mongoc_oidc_callback_params_t`. + +Returns +------- + +A string which must not be modified or freed, or ``NULL``. + +Lifecycle +--------- + +The string is only valid for the duration of the invocation of the OIDC callback function. + +.. seealso:: + + - :symbol:`mongoc_oidc_callback_params_t` + - :symbol:`mongoc_oidc_callback_t` + - :symbol:`mongoc_uri_t` diff --git a/src/libmongoc/doc/mongoc_oidc_callback_params_get_version.rst b/src/libmongoc/doc/mongoc_oidc_callback_params_get_version.rst new file mode 100644 index 0000000000..2117162377 --- /dev/null +++ b/src/libmongoc/doc/mongoc_oidc_callback_params_get_version.rst @@ -0,0 +1,29 @@ +:man_page: mongoc_oidc_callback_params_get_version + +mongoc_oidc_callback_params_get_version() +========================================= + +Synopsis +-------- + +.. code-block:: c + + int32_t + mongoc_oidc_callback_params_get_version (const mongoc_oidc_callback_params_t *params); + +Return the OIDC callback API version number. + +Parameters +---------- + +* ``params``: a :symbol:`mongoc_oidc_callback_params_t`. + +Returns +------- + +A positive integer. + +.. seealso:: + + - :symbol:`mongoc_oidc_callback_params_t` + - :symbol:`mongoc_oidc_callback_t` diff --git a/src/libmongoc/doc/mongoc_oidc_callback_params_t.rst b/src/libmongoc/doc/mongoc_oidc_callback_params_t.rst new file mode 100644 index 0000000000..d76c5c9500 --- /dev/null +++ b/src/libmongoc/doc/mongoc_oidc_callback_params_t.rst @@ -0,0 +1,215 @@ +:man_page: mongoc_oidc_callback_params_t + +mongoc_oidc_callback_params_t +============================= + +Synopsis +-------- + +.. code-block:: c + + typedef struct _mongoc_oidc_callback_params_t mongoc_oidc_callback_params_t; + +Represents the in/out parameters of a :symbol:`mongoc_oidc_callback_t`. + +The parameters will be passed to the :symbol:`mongoc_oidc_callback_fn_t` stored in an :symbol:`mongoc_oidc_callback_t` object when it is invoked by an :symbol:`mongoc_client_t` or :symbol:`mongoc_client_pool_t` object. + +.. only:: html + + Functions + --------- + + .. toctree:: + :titlesonly: + :maxdepth: 1 + + mongoc_oidc_callback_params_get_version + mongoc_oidc_callback_params_get_user_data + mongoc_oidc_callback_params_get_timeout + mongoc_oidc_callback_params_get_username + mongoc_oidc_callback_params_cancel_with_timeout + +Parameters +---------- + +The list of currently supported parameters are: + +.. list-table:: + :widths: auto + + * - Parameter + - Versions + - Description + * - ``version`` + - 1 + - The current OIDC callback API version number. + * - ``user_data`` + - 1 + - A pointer to data provided by the user. + * - ``timeout`` + - 1 + - The timestamp after which the callback function must report a timeout. + * - ``username`` + - 1 + - The username specified by the URI of the associated client object. + * - ``cancel_with_timeout`` + - 1 + - An out parameter indicating cancellation of the callback function due to a timeout instead of an error. + +The "Version" column indicates the OIDC callback API versions for which the parameter is applicable. + +Version +``````` + +The ``version`` parameter is used to communicate backward compatible changes to the OIDC callback API (i.e. the addition of a new parameter). + +This parameter may be used to detect when existing usage of :symbol:`mongoc_oidc_callback_t` or a relevant callback function may need to be reviewed. + +For example, users may add the following check to their callback function: + +.. code-block:: c + + mongoc_oidc_credential_t * + example_callback_fn (mongoc_oidc_callback_params_t *params) + { + // A runtime message that new features are available in the OIDC Callback API. + if (mongoc_oidc_callback_params_get_version (params) > 1) { + printf ("OIDC Callback API has been updated to a new version!"); + } + + // ... + } + +User Data +````````` + +The ``user_data`` parameter may be used to pass additional arguments to the callback function or to return additional values out of the callback function. + +This parameter must be set in advance via :symbol:`mongoc_oidc_callback_set_user_data()` before the :symbol:`mongoc_oidc_callback_t` object is associated with a :symbol:`mongoc_client_t` or :symbol:`mongoc_client_pool_t` object. + +.. warning:: + + The lifetime of the object pointed to by ``user_data`` is managed the user, not by :symbol:`mongoc_oidc_callback_t`! + +.. code-block:: c + + typedef struct { + int counter; + const char *error_message; + } user_data_t; + + mongoc_oidc_credential_t * + example_callback_fn (mongoc_oidc_callback_params_t *params) + { + user_data_t *user_data = (user_data_t *) mongoc_oidc_callback_params_get_user_data (params); + + user_data->counter += 1; + + // ... + + if (/* ... */) { + user_data->error_message = "OIDC callback failed due to ..."; + return NULL; + } + + // ... + } + + void + example (void) + { + mongoc_client_t *client = /* ... */; + bson_error_t error; + + { + user_data_t *user_data = malloc (sizeof (*user_data)); + *user_data = (user_data_t){.counter = 0, .error_message = NULL}; + mongoc_oidc_callback_t *callback = mongoc_oidc_callback_new_with_user_data (&example_callback_fn, (void *) user_data); + mongoc_client_set_oidc_callback (client, callback); + mongoc_oidc_callback_destroy (callback); + } + + // ... client operations ... + + { + const mongoc_oidc_callback_t *callback = mongoc_client_get_oidc_callback (client); + user_data_t *user_data = (user_data_t *) mongoc_oidc_callback_get_user_data (callback); + + if (error.code != 0) { + printf ("client error message: %s\n", error.message); + } + + if (user_data->error_message) { + printf ("custom error message: %s\n", user_data->error_message); + } + + printf ("The callback function was invoked %d times!", user_data->counter); + + free (user_data); + } + + mongoc_client_destroy (client); + } + +Timeout +``````` + +The ``timeout`` parameter is used to determine when the callback function should report cancellation due to a timeout. + +When :symbol:`bson_get_monotonic_time()` is greater than ``timeout``, the callback function must invoke :symbol:`mongoc_oidc_callback_params_cancel_with_timeout()` and return ``NULL``. + +Username +```````` + +The ``username`` parameter is the value of the username component of the URI of the associated :symbol:`mongoc_client_t` or :symbol:`mongoc_client_pool_t` object from which the callback function is invoked. + +Cancel With Timeout +``````````````````` + +The ``cancel_with_timeout`` out parameter indicates cancellation of the callback function due to a timeout instead of an error. + +.. important:: + + The callback function MUST return ``NULL``, otherwise the invocation will be interpreted as a success even when ``cancel_with_timeout`` is set. + +.. code-block:: c + + mongoc_oidc_credential_t * + example_callback_fn (mongoc_oidc_callback_params_t *params) { + const int64_t *timeout = mongoc_oidc_callback_params_get_timeout (params); + + // NULL means "infinite" timeout. + if (timeout && bson_get_monotonic_time () > *timeout) { + return mongoc_oidc_callback_params_cancel_with_timeout (params); + } + + // ... + } + +Error Handling +`````````````` + +A ``NULL`` return value (without setting ``cancel_with_timeout``) indicates failure to provide an access token due to an error. + +.. important:: + + The callback function MUST return ``NULL``, otherwise the invocation will be interpreted as a success. + +.. code-block:: c + + mongoc_oidc_credential_t * + example_callback_fn (mongoc_oidc_callback_params_t *params) { + // ... + + if (/* ... */) { + // The OIDC callback function could not provide an access token due to an error. + return NULL; + } + + // ... + } + +.. seealso:: + + - :symbol:`mongoc_oidc_callback_t` + - :symbol:`mongoc_oidc_callback_fn_t` diff --git a/src/libmongoc/doc/mongoc_oidc_callback_set_user_data.rst b/src/libmongoc/doc/mongoc_oidc_callback_set_user_data.rst new file mode 100644 index 0000000000..d3c78fbb98 --- /dev/null +++ b/src/libmongoc/doc/mongoc_oidc_callback_set_user_data.rst @@ -0,0 +1,29 @@ +:man_page: mongoc_oidc_callback_set_user_data + +mongoc_oidc_callback_set_user_data() +==================================== + +Synopsis +-------- + +.. code-block:: c + + void + mongoc_oidc_callback_set_user_data (mongoc_oidc_callback_t *callback, void *user_data); + +Store the provided pointer to user data. + +.. warning:: + + The lifetime of the object pointed to by ``user_data`` is managed the user, not by :symbol:`mongoc_oidc_callback_t`! + +Parameters +---------- + +* ``callback``: a :symbol:`mongoc_oidc_callback_t`. +* ``user_data``: a pointer to user data or ``NULL``. + +.. seealso:: + + - :symbol:`mongoc_oidc_callback_t` + - :symbol:`mongoc_oidc_callback_get_user_data()` diff --git a/src/libmongoc/doc/mongoc_oidc_callback_t.rst b/src/libmongoc/doc/mongoc_oidc_callback_t.rst new file mode 100644 index 0000000000..c3c4baf54b --- /dev/null +++ b/src/libmongoc/doc/mongoc_oidc_callback_t.rst @@ -0,0 +1,150 @@ +:man_page: mongoc_oidc_callback_t + +mongoc_oidc_callback_t +====================== + +Synopsis +-------- + +.. code-block:: c + + typedef struct _mongoc_oidc_callback_t mongoc_oidc_callback_t; + +:symbol:`mongoc_oidc_callback_t` represents a user-defined callback function :symbol:`mongoc_oidc_callback_fn_t` that returns an OIDC access token. + +The callback may be used to integrate with OIDC providers that are not supported by the built-in provider integrations (:ref:`Authentication Mechanism Properties `). + +.. only:: html + + Functions + --------- + + .. toctree:: + :titlesonly: + :maxdepth: 1 + + mongoc_oidc_callback_new + mongoc_oidc_callback_new_with_user_data + mongoc_oidc_callback_destroy + mongoc_oidc_callback_get_fn + mongoc_oidc_callback_get_user_data + mongoc_oidc_callback_set_user_data + +Lifecycle +--------- + +The function and optional user data stored by :symbol:`mongoc_oidc_callback_t` must outlive any associated client or client pool object which may invoke the stored callback function. + +Thread Safety +------------- + +The callback function stored by a :symbol:`mongoc_oidc_callback_t` object will be invoked by at most one thread at a time for an associated :symbol:`mongoc_client_t` or :symbol:`mongoc_client_pool_t` object: + +.. code-block:: c + + static mongoc_oidc_credential_t * + single_thread_only (mongoc_oidc_callback_params_t *params) + { + // This function does not need to support invocation by more than thread at a time. + + // ... + } + + void + with_single_client (void) + { + mongoc_client_t *client = /* ... */; + + { + mongoc_oidc_callback_t *callback = mongoc_oidc_callback_new (&single_thread_only); + mongoc_client_set_oidc_callback (client, callback); + mongoc_oidc_callback_destroy (callback); + } + + // ... client operations ... + + mongoc_client_destroy (client); + } + + void + with_single_pool (void) + { + mongoc_client_pool_t *pool = /* ... */; + + { + mongoc_oidc_callback_t *callback = mongoc_oidc_callback_new (&single_thread_only); + mongoc_client_pool_set_oidc_callback (pool, callback); + mongoc_oidc_callback_destroy (callback); + } + + // ... client pool operations ... + + mongoc_client_pool_destroy (pool); + } + +If the callback is associated with more than one :symbol:`mongoc_client_t` object (in multiple threads), or with more than one :symbol:`mongoc_client_pool_t` object (even in a single thread), the callback function MUST support invocation by more than one thread at a time: + +.. code-block:: c + + static mongoc_oidc_credential_t * + many_threads_possible (mongoc_oidc_callback_params_t *params) + { + // This function MUST support invocation by more than one thread at a time. + + // ... + } + + void + with_many_clients (void) + { + mongoc_client_t *client_a = /* ... */; + mongoc_client_t *client_b = /* ... */; + + { + mongoc_oidc_callback_t *callback = mongoc_oidc_callback_new (&many_threads_possible); + mongoc_client_set_oidc_callback (client_a, callback); + mongoc_client_set_oidc_callback (client_b, callback); + mongoc_oidc_callback_destroy (callback); + } + + pthread_t thread_a; + pthread_t thread_b; + + if (pthread_create (&thread_a, NULL, /* thread_a_fn */, client_a) != 0) { /* ... */ } + if (pthread_create (&thread_b, NULL, /* thread_b_fn */, client_b) != 0) { /* ... */ } + + // ... client operations using multiple threads ... + + if (pthread_join (&thread_a, NULL) != 0) { /* ... */ } + if (pthread_join (&thread_b, NULL) != 0) { /* ... */ } + + mongoc_client_destroy (client_a); + mongoc_client_destroy (client_b); + } + + void + with_many_pools (void) + { + mongoc_client_pool_t *pool_a = /* ... */; + mongoc_client_pool_t *pool_b = /* ... */; + + { + mongoc_oidc_callback_t *callback = mongoc_oidc_callback_new (&many_threads_possible); + mongoc_client_pool_set_oidc_callback (pool_a, callback); + mongoc_client_pool_set_oidc_callback (pool_b, callback); + mongoc_oidc_callback_destroy (callback); + } + + // ... client operations using multiple client pools ... + + mongoc_client_pool_destroy (pool_a); + mongoc_client_pool_destroy (pool_b); + } + +.. seealso:: + + - :symbol:`mongoc_client_t` + - :symbol:`mongoc_client_pool_t` + - :symbol:`mongoc_oidc_callback_fn_t` + - :symbol:`mongoc_oidc_callback_params_t` + - :symbol:`mongoc_oidc_credential_t` diff --git a/src/libmongoc/doc/mongoc_oidc_credential_destroy.rst b/src/libmongoc/doc/mongoc_oidc_credential_destroy.rst new file mode 100644 index 0000000000..b9f121c84a --- /dev/null +++ b/src/libmongoc/doc/mongoc_oidc_credential_destroy.rst @@ -0,0 +1,23 @@ +:man_page: mongoc_oidc_credential_destroy + +mongoc_oidc_credential_destroy() +================================ + +Synopsis +-------- + +.. code-block:: c + + void + mongoc_oidc_credential_destroy (mongoc_oidc_credential_t *credential) + +Release all resources associated with the given :symbol:`mongoc_oidc_credential_t` object. + +Parameters +---------- + +* ``credential``: a :symbol:`mongoc_oidc_credential_t` or ``NULL``. + +.. seealso:: + + - :symbol:`mongoc_oidc_credential_t` diff --git a/src/libmongoc/doc/mongoc_oidc_credential_get_access_token.rst b/src/libmongoc/doc/mongoc_oidc_credential_get_access_token.rst new file mode 100644 index 0000000000..ac567b6bea --- /dev/null +++ b/src/libmongoc/doc/mongoc_oidc_credential_get_access_token.rst @@ -0,0 +1,36 @@ +:man_page: mongoc_oidc_credential_get_access_token + +mongoc_oidc_credential_get_access_token() +========================================= + +Synopsis +-------- + +.. code-block:: c + + const char * + mongoc_oidc_credential_get_access_token (const mongoc_oidc_credential_t *cred); + +Return the access token stored in the :symbol:`mongoc_oidc_credential_t` object. + +Parameters +---------- + +* ``cred``: a :symbol:`mongoc_oidc_credential_t`. + +Returns +------- + +A string which must not be modified or freed. + +Lifecycle +--------- + +The string is only valid for the lifetime of the :symbol:`mongoc_oidc_credential_t` object. + +.. seealso:: + + - :symbol:`mongoc_oidc_credential_t` + - :symbol:`mongoc_oidc_callback_fn_t` + - :symbol:`mongoc_oidc_credential_new` + - :symbol:`mongoc_oidc_credential_new_with_expires_in` diff --git a/src/libmongoc/doc/mongoc_oidc_credential_get_expires_in.rst b/src/libmongoc/doc/mongoc_oidc_credential_get_expires_in.rst new file mode 100644 index 0000000000..1c1bda261a --- /dev/null +++ b/src/libmongoc/doc/mongoc_oidc_credential_get_expires_in.rst @@ -0,0 +1,39 @@ +:man_page: mongoc_oidc_credential_get_expires_in + +mongoc_oidc_credential_get_expires_in() +======================================= + +Synopsis +-------- + +.. code-block:: c + + const int64_t * + mongoc_oidc_credential_get_expires_in (const mongoc_oidc_credential_t *cred); + +Return the optional expiry duration (in milliseconds) for the access token stored in :symbol:`mongoc_oidc_credential_t`. + +.. important:: + + An unset value is interpreted as an infinite expiry duration. + +Parameters +---------- + +* ``cred``: a :symbol:`mongoc_oidc_credential_t`. + +Returns +------- + +The expiry duration (in milliseconds), or ``NULL`` when unset. + +Lifecycle +--------- + +The pointed-to ``int64_t`` is only valid for the lifetime of the :symbol:`mongoc_oidc_credential_t` object. + +.. seealso:: + + - :symbol:`mongoc_oidc_credential_t` + - :symbol:`mongoc_oidc_credential_new_with_expires_in` + - :symbol:`mongoc_oidc_callback_fn_t` diff --git a/src/libmongoc/doc/mongoc_oidc_credential_new.rst b/src/libmongoc/doc/mongoc_oidc_credential_new.rst new file mode 100644 index 0000000000..b052c50db7 --- /dev/null +++ b/src/libmongoc/doc/mongoc_oidc_credential_new.rst @@ -0,0 +1,34 @@ +:man_page: mongoc_oidc_credential_new + +mongoc_oidc_credential_new() +============================ + +Synopsis +-------- + +.. code-block:: c + + mongoc_oidc_credential_t * + mongoc_oidc_credential_new (const char *access_token) + +Create a new :symbol:`mongoc_oidc_credential_t` object which stores a copy of the provided OIDC access token with an infinite expiry duration. + +To set a finite expiry duration, use :symbol:`mongoc_oidc_credential_new_with_expires_in()`. + +.. warning:: + + ``access_token`` is NOT directly validated by the driver. + +Parameters +---------- + +* ``access_token``: an OIDC access token. Must not be ``NULL``. + +Returns +------- + +A new :symbol:`mongoc_oidc_credential_t` that must be freed with :symbol:`mongoc_oidc_credential_destroy()`, or ``NULL`` when an invalid argument was given. + +.. seealso:: + + - :symbol:`mongoc_oidc_credential_t` diff --git a/src/libmongoc/doc/mongoc_oidc_credential_new_with_expires_in.rst b/src/libmongoc/doc/mongoc_oidc_credential_new_with_expires_in.rst new file mode 100644 index 0000000000..0d35d2f257 --- /dev/null +++ b/src/libmongoc/doc/mongoc_oidc_credential_new_with_expires_in.rst @@ -0,0 +1,37 @@ +:man_page: mongoc_oidc_credential_new_with_expires_in + +mongoc_oidc_credential_new_with_expires_in() +============================================ + +Synopsis +-------- + +.. code-block:: c + + mongoc_oidc_credential_t * + mongoc_oidc_credential_new_with_expires_in (const char *access_token, int64_t expires_in) + +Create a new :symbol:`mongoc_oidc_credential_t` object which stores a copy of the provided OIDC access token and its expiry duration (in milliseconds). + +The expiry duration will be evaluated relative to the value returned by :symbol:`bson_get_monotonic_time()` immediately after the callback function has returned. + +To set an infinite expiry duration, use :symbol:`mongoc_oidc_credential_new()`. + +.. warning:: + + ``access_token`` is NOT directly validated by the driver. + +Parameters +---------- + +* ``access_token``: an OIDC access token. Must not be ``NULL``. +* ``expires_in``: a non-negative integer. + +Returns +------- + +A new :symbol:`mongoc_oidc_credential_t` that must be freed with :symbol:`mongoc_oidc_credential_destroy()`, or ``NULL`` when an invalid argument was given. + +.. seealso:: + + - :symbol:`mongoc_oidc_credential_t` diff --git a/src/libmongoc/doc/mongoc_oidc_credential_t.rst b/src/libmongoc/doc/mongoc_oidc_credential_t.rst new file mode 100644 index 0000000000..3e7f93ad01 --- /dev/null +++ b/src/libmongoc/doc/mongoc_oidc_credential_t.rst @@ -0,0 +1,73 @@ +:man_page: mongoc_oidc_credential_t + +mongoc_oidc_credential_t +======================== + +Synopsis +-------- + +.. code-block:: c + + typedef struct _mongoc_oidc_credential_t mongoc_oidc_credential_t; + +Represents the return value of a :symbol:`mongoc_oidc_callback_fn_t`. + +The value will be returned by the :symbol:`mongoc_oidc_callback_fn_t` stored in an :symbol:`mongoc_oidc_callback_t` object when it is invoked by an associated :symbol:`mongoc_client_t` or :symbol:`mongoc_client_pool_t` object. + +.. only:: html + + Functions + --------- + + .. toctree:: + :titlesonly: + :maxdepth: 1 + + mongoc_oidc_credential_new + mongoc_oidc_credential_new_with_expires_in + mongoc_oidc_credential_destroy + mongoc_oidc_credential_get_access_token + mongoc_oidc_credential_get_expires_in + +Return Values +------------- + +The list of currently supported return values are: + +.. list-table:: + :widths: auto + + * - Value + - Versions + - Description + * - ``access_token`` + - 1 + - The OIDC access token. + * - ``expires_in`` + - 1 + - An optional expiration duration (in milliseconds). + +The "Version" column indicates the OIDC callback API versions for which the parameter is applicable. + +Access Token +```````````` + +An OIDC access token (a signed JWT token). + +.. warning:: + + ``access_token`` is NOT directly validated by the driver. + +Expiry Duration +``````````````` + +An optional expiry duration (in milliseconds) for the access token. + +.. important:: + + An unset value is interpreted as an infinite expiry duration. + +.. seealso:: + + - :symbol:`mongoc_oidc_callback_t` + - :symbol:`mongoc_oidc_callback_fn_t` diff --git a/src/libmongoc/src/mongoc/mongoc-oidc-callback-private.h b/src/libmongoc/src/mongoc/mongoc-oidc-callback-private.h new file mode 100644 index 0000000000..636fbd1e27 --- /dev/null +++ b/src/libmongoc/src/mongoc/mongoc-oidc-callback-private.h @@ -0,0 +1,60 @@ +/* + * 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 + +#ifndef MONGOC_OIDC_CALLBACK_PRIVATE_H +#define MONGOC_OIDC_CALLBACK_PRIVATE_H + +#include + +// + +#include + +// Authentication spec: the version number is used to communicate callback API changes that are not breaking but that +// users may want to know about and review their implementation. Drivers MUST pass 1 for the initial callback API +// version number and increment the version number anytime the API changes. +#define MONGOC_PRIVATE_OIDC_CALLBACK_API_VERSION 1 + +mongoc_oidc_callback_params_t * +mongoc_oidc_callback_params_new (void); + +void +mongoc_oidc_callback_params_destroy (mongoc_oidc_callback_params_t *params); + +void +mongoc_oidc_callback_params_set_version (mongoc_oidc_callback_params_t *params, int32_t version); + +void +mongoc_oidc_callback_params_set_user_data (mongoc_oidc_callback_params_t *params, void *user_data); + +void +mongoc_oidc_callback_params_set_timeout (mongoc_oidc_callback_params_t *params, int64_t timeout); + +void +mongoc_oidc_callback_params_unset_timeout (mongoc_oidc_callback_params_t *params); + +void +mongoc_oidc_callback_params_set_username (mongoc_oidc_callback_params_t *params, const char *username); + +bool +mongoc_oidc_callback_params_get_cancelled_with_timeout (const mongoc_oidc_callback_params_t *params); + +void +mongoc_oidc_callback_params_set_cancelled_with_timeout (mongoc_oidc_callback_params_t *params, bool value); + +#endif // MONGOC_OIDC_CALLBACK_PRIVATE_H diff --git a/src/libmongoc/src/mongoc/mongoc-oidc-callback.c b/src/libmongoc/src/mongoc/mongoc-oidc-callback.c new file mode 100644 index 0000000000..cdeea8d147 --- /dev/null +++ b/src/libmongoc/src/mongoc/mongoc-oidc-callback.c @@ -0,0 +1,258 @@ +/* + * 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 + +// + +#include + +struct _mongoc_oidc_callback_t { + mongoc_oidc_callback_fn_t fn; + void *user_data; +}; + +struct _mongoc_oidc_callback_params_t { + void *user_data; + char *username; + int64_t timeout; // Guarded by timeout_is_set. + int32_t version; + bool cancelled_with_timeout; + bool timeout_is_set; +}; + +struct _mongoc_oidc_credential_t { + char *access_token; + int64_t expires_in; // Guarded by expires_in_set. + bool expires_in_set; +}; + +mongoc_oidc_callback_t * +mongoc_oidc_callback_new (mongoc_oidc_callback_fn_t fn) +{ + if (!fn) { + return NULL; + } + + mongoc_oidc_callback_t *const ret = bson_malloc (sizeof (*ret)); + *ret = (mongoc_oidc_callback_t){.fn = fn}; + return ret; +} + +mongoc_oidc_callback_t * +mongoc_oidc_callback_new_with_user_data (mongoc_oidc_callback_fn_t fn, void *user_data) +{ + if (!fn) { + return NULL; + } + + mongoc_oidc_callback_t *const ret = bson_malloc (sizeof (*ret)); + *ret = (mongoc_oidc_callback_t){.fn = fn, .user_data = user_data}; + return ret; +} + +void +mongoc_oidc_callback_destroy (mongoc_oidc_callback_t *callback) +{ + if (callback) { + bson_free (callback); + } +} + +mongoc_oidc_callback_fn_t +mongoc_oidc_callback_get_fn (const mongoc_oidc_callback_t *callback) +{ + BSON_ASSERT_PARAM (callback); + return callback->fn; +} + +void * +mongoc_oidc_callback_get_user_data (const mongoc_oidc_callback_t *callback) +{ + BSON_ASSERT_PARAM (callback); + return callback->user_data; +} + +void +mongoc_oidc_callback_set_user_data (mongoc_oidc_callback_t *callback, void *user_data) +{ + BSON_ASSERT_PARAM (callback); + callback->user_data = user_data; +} + +mongoc_oidc_callback_params_t * +mongoc_oidc_callback_params_new (void) +{ + mongoc_oidc_callback_params_t *const ret = bson_malloc (sizeof (*ret)); + *ret = (mongoc_oidc_callback_params_t){ + .version = MONGOC_PRIVATE_OIDC_CALLBACK_API_VERSION, + }; + return ret; +} + +void +mongoc_oidc_callback_params_destroy (mongoc_oidc_callback_params_t *params) +{ + if (params) { + bson_free (params->username); + bson_free (params); + } +} + +int32_t +mongoc_oidc_callback_params_get_version (const mongoc_oidc_callback_params_t *params) +{ + BSON_ASSERT_PARAM (params); + return params->version; +} + +void +mongoc_oidc_callback_params_set_version (mongoc_oidc_callback_params_t *params, int32_t version) +{ + BSON_ASSERT_PARAM (params); + params->version = version; +} + +void * +mongoc_oidc_callback_params_get_user_data (const mongoc_oidc_callback_params_t *params) +{ + BSON_ASSERT_PARAM (params); + return params->user_data; +} + +void +mongoc_oidc_callback_params_set_user_data (mongoc_oidc_callback_params_t *params, void *user_data) +{ + BSON_ASSERT_PARAM (params); + params->user_data = user_data; +} + +const int64_t * +mongoc_oidc_callback_params_get_timeout (const mongoc_oidc_callback_params_t *params) +{ + BSON_ASSERT_PARAM (params); + return params->timeout_is_set ? ¶ms->timeout : NULL; +} + +void +mongoc_oidc_callback_params_set_timeout (mongoc_oidc_callback_params_t *params, int64_t timeout) +{ + BSON_ASSERT_PARAM (params); + params->timeout = timeout; + params->timeout_is_set = true; +} + +void +mongoc_oidc_callback_params_unset_timeout (mongoc_oidc_callback_params_t *params) +{ + BSON_ASSERT_PARAM (params); + params->timeout_is_set = false; +} + +const char * +mongoc_oidc_callback_params_get_username (const mongoc_oidc_callback_params_t *params) +{ + BSON_ASSERT_PARAM (params); + return params->username; +} + +void +mongoc_oidc_callback_params_set_username (mongoc_oidc_callback_params_t *params, const char *username) +{ + BSON_ASSERT_PARAM (params); + bson_free (params->username); + params->username = bson_strdup (username); +} + +mongoc_oidc_credential_t * +mongoc_oidc_callback_params_cancel_with_timeout (mongoc_oidc_callback_params_t *params) +{ + BSON_ASSERT_PARAM (params); + params->cancelled_with_timeout = true; + return NULL; +} + +bool +mongoc_oidc_callback_params_get_cancelled_with_timeout (const mongoc_oidc_callback_params_t *params) +{ + BSON_ASSERT_PARAM (params); + return params->cancelled_with_timeout; +} + +void +mongoc_oidc_callback_params_set_cancelled_with_timeout (mongoc_oidc_callback_params_t *params, bool value) +{ + BSON_ASSERT_PARAM (params); + params->cancelled_with_timeout = value; +} + +mongoc_oidc_credential_t * +mongoc_oidc_credential_new (const char *access_token) +{ + if (!access_token) { + return NULL; + } + + mongoc_oidc_credential_t *const ret = bson_malloc (sizeof (*ret)); + *ret = (mongoc_oidc_credential_t){ + .access_token = bson_strdup (access_token), + .expires_in_set = false, // Infinite. + }; + return ret; +} + +mongoc_oidc_credential_t * +mongoc_oidc_credential_new_with_expires_in (const char *access_token, int64_t expires_in) +{ + if (!access_token) { + return NULL; + } + + if (expires_in < 0) { + return NULL; + } + + mongoc_oidc_credential_t *const ret = bson_malloc (sizeof (*ret)); + *ret = (mongoc_oidc_credential_t){ + .access_token = bson_strdup (access_token), + .expires_in_set = true, + .expires_in = expires_in, + }; + return ret; +} + +void +mongoc_oidc_credential_destroy (mongoc_oidc_credential_t *cred) +{ + if (cred) { + bson_free (cred->access_token); + bson_free (cred); + } +} + +const char * +mongoc_oidc_credential_get_access_token (const mongoc_oidc_credential_t *cred) +{ + BSON_ASSERT_PARAM (cred); + return cred->access_token; +} + +const int64_t * +mongoc_oidc_credential_get_expires_in (const mongoc_oidc_credential_t *cred) +{ + BSON_ASSERT_PARAM (cred); + return cred->expires_in_set ? &cred->expires_in : NULL; +} diff --git a/src/libmongoc/src/mongoc/mongoc-oidc-callback.h b/src/libmongoc/src/mongoc/mongoc-oidc-callback.h new file mode 100644 index 0000000000..486ea1abdb --- /dev/null +++ b/src/libmongoc/src/mongoc/mongoc-oidc-callback.h @@ -0,0 +1,86 @@ +/* + * 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 + +#ifndef MONGOC_OIDC_CALLBACK_H +#define MONGOC_OIDC_CALLBACK_H + +#include + +#include + +#include + +BSON_BEGIN_DECLS + +typedef struct _mongoc_oidc_callback_t mongoc_oidc_callback_t; +typedef struct _mongoc_oidc_callback_params_t mongoc_oidc_callback_params_t; +typedef struct _mongoc_oidc_credential_t mongoc_oidc_credential_t; + +typedef mongoc_oidc_credential_t *(MONGOC_CALL *mongoc_oidc_callback_fn_t) (mongoc_oidc_callback_params_t *params); + +MONGOC_EXPORT (mongoc_oidc_callback_t *) +mongoc_oidc_callback_new (mongoc_oidc_callback_fn_t fn); + +MONGOC_EXPORT (mongoc_oidc_callback_t *) +mongoc_oidc_callback_new_with_user_data (mongoc_oidc_callback_fn_t fn, void *user_data); + +MONGOC_EXPORT (void) +mongoc_oidc_callback_destroy (mongoc_oidc_callback_t *callback); + +MONGOC_EXPORT (mongoc_oidc_callback_fn_t) +mongoc_oidc_callback_get_fn (const mongoc_oidc_callback_t *callback); + +MONGOC_EXPORT (void *) +mongoc_oidc_callback_get_user_data (const mongoc_oidc_callback_t *callback); + +MONGOC_EXPORT (void) +mongoc_oidc_callback_set_user_data (mongoc_oidc_callback_t *callback, void *user_data); + +MONGOC_EXPORT (int32_t) +mongoc_oidc_callback_params_get_version (const mongoc_oidc_callback_params_t *params); + +MONGOC_EXPORT (void *) +mongoc_oidc_callback_params_get_user_data (const mongoc_oidc_callback_params_t *params); + +MONGOC_EXPORT (const int64_t *) +mongoc_oidc_callback_params_get_timeout (const mongoc_oidc_callback_params_t *params); + +MONGOC_EXPORT (const char *) +mongoc_oidc_callback_params_get_username (const mongoc_oidc_callback_params_t *params); + +MONGOC_EXPORT (mongoc_oidc_credential_t *) +mongoc_oidc_callback_params_cancel_with_timeout (mongoc_oidc_callback_params_t *params); + +MONGOC_EXPORT (mongoc_oidc_credential_t *) +mongoc_oidc_credential_new (const char *access_token); + +MONGOC_EXPORT (mongoc_oidc_credential_t *) +mongoc_oidc_credential_new_with_expires_in (const char *access_token, int64_t expires_in); + +MONGOC_EXPORT (void) +mongoc_oidc_credential_destroy (mongoc_oidc_credential_t *cred); + +MONGOC_EXPORT (const char *) +mongoc_oidc_credential_get_access_token (const mongoc_oidc_credential_t *cred); + +MONGOC_EXPORT (const int64_t *) +mongoc_oidc_credential_get_expires_in (const mongoc_oidc_credential_t *cred); + +BSON_END_DECLS + +#endif // MONGOC_OIDC_CALLBACK_H diff --git a/src/libmongoc/tests/test-libmongoc-main.c b/src/libmongoc/tests/test-libmongoc-main.c index af0947283d..18fb70722b 100644 --- a/src/libmongoc/tests/test-libmongoc-main.c +++ b/src/libmongoc/tests/test-libmongoc-main.c @@ -157,6 +157,7 @@ main (int argc, char *argv[]) TEST_INSTALL (test_service_gcp_install); TEST_INSTALL (test_mcd_nsinfo_install); TEST_INSTALL (test_bulkwrite_install); + TEST_INSTALL (test_mongoc_oidc_callback_install); ret = TestSuite_Run (&suite); diff --git a/src/libmongoc/tests/test-mongoc-oidc-callback.c b/src/libmongoc/tests/test-mongoc-oidc-callback.c new file mode 100644 index 0000000000..d32ef677e2 --- /dev/null +++ b/src/libmongoc/tests/test-mongoc-oidc-callback.c @@ -0,0 +1,185 @@ +/* + * 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 + +// + +#include "test-conveniences.h" +#include "TestSuite.h" + +static mongoc_oidc_credential_t * +_test_oidc_callback_fn_cb (mongoc_oidc_callback_params_t *params) +{ + BSON_UNUSED (params); + test_error ("should not be invoked"); +} + +static void +test_oidc_callback_new (void) +{ + // Invalid arguments. + { + ASSERT (!mongoc_oidc_callback_new (NULL)); + } + + mongoc_oidc_callback_t *const callback = mongoc_oidc_callback_new (&_test_oidc_callback_fn_cb); + ASSERT (mongoc_oidc_callback_get_fn (callback) == &_test_oidc_callback_fn_cb); + + // Initial values. + { + ASSERT (!mongoc_oidc_callback_get_user_data (callback)); + } + + // Normal values. + { + int user_data = 0; + + mongoc_oidc_callback_set_user_data (callback, &user_data); + + ASSERT (mongoc_oidc_callback_get_user_data (callback) == &user_data); + } + + // "Reset" values. + { + mongoc_oidc_callback_set_user_data (callback, NULL); + + ASSERT (!mongoc_oidc_callback_get_user_data (callback)); + } + + mongoc_oidc_callback_destroy (callback); +} + +static void +test_oidc_callback_params (void) +{ + mongoc_oidc_callback_params_t *const params = mongoc_oidc_callback_params_new (); + + // Initial values. + ASSERT (!mongoc_oidc_callback_params_get_timeout (params)); + ASSERT_CMPSTR (mongoc_oidc_callback_params_get_username (params), NULL); + ASSERT_CMPINT32 (mongoc_oidc_callback_params_get_version (params), ==, MONGOC_PRIVATE_OIDC_CALLBACK_API_VERSION); + ASSERT (!mongoc_oidc_callback_params_get_cancelled_with_timeout (params)); + + // Input parameters. + { + // Normal values. + { + mongoc_oidc_callback_params_set_timeout (params, 123); + { + char username[] = "username"; + mongoc_oidc_callback_params_set_username (params, username); + username[0] = '\0'; // Ensure a copy was made. + } + mongoc_oidc_callback_params_set_version (params, 123); + + const int64_t *timeout = mongoc_oidc_callback_params_get_timeout (params); + ASSERT (timeout); + ASSERT_CMPINT64 (*timeout, ==, 123); + ASSERT_CMPSTR (mongoc_oidc_callback_params_get_username (params), "username"); + ASSERT_CMPINT32 (mongoc_oidc_callback_params_get_version (params), ==, 123); + } + + // "Reset" values. + { + mongoc_oidc_callback_params_set_username (params, NULL); + mongoc_oidc_callback_params_unset_timeout (params); + mongoc_oidc_callback_params_set_version (params, MONGOC_PRIVATE_OIDC_CALLBACK_API_VERSION); + + ASSERT_CMPSTR (mongoc_oidc_callback_params_get_username (params), NULL); + ASSERT (!mongoc_oidc_callback_params_get_timeout (params)); + ASSERT_CMPINT32 ( + mongoc_oidc_callback_params_get_version (params), ==, MONGOC_PRIVATE_OIDC_CALLBACK_API_VERSION); + } + } + + // Out parameters. + { + // Normal values. + { + mongoc_oidc_callback_params_cancel_with_timeout (params); + + ASSERT (mongoc_oidc_callback_params_get_cancelled_with_timeout (params)); + } + + // "Reset" values. + { + mongoc_oidc_callback_params_set_cancelled_with_timeout (params, false); + + ASSERT (!mongoc_oidc_callback_params_get_cancelled_with_timeout (params)); + } + } + + // Owning resources. + { + mongoc_oidc_callback_params_set_username (params, "must be freed"); + } + + mongoc_oidc_callback_params_destroy (params); +} + +static void +test_oidc_credential (void) +{ + // Normal. + { + char token[] = "token"; + mongoc_oidc_credential_t *const cred = mongoc_oidc_credential_new (token); + token[0] = '\0'; // Ensure a copy was made. + + ASSERT_CMPSTR (mongoc_oidc_credential_get_access_token (cred), "token"); + ASSERT (!mongoc_oidc_credential_get_expires_in (cred)); + mongoc_oidc_credential_destroy (cred); + } + + // Normal with expires_in. + { + char token[] = "token"; + mongoc_oidc_credential_t *const cred = mongoc_oidc_credential_new_with_expires_in (token, 123); + token[0] = '\0'; // Ensure a copy was made. + + ASSERT_CMPSTR (mongoc_oidc_credential_get_access_token (cred), "token"); + const int64_t *const expires_in = mongoc_oidc_credential_get_expires_in (cred); + ASSERT (expires_in); + ASSERT_CMPINT64 (*expires_in, ==, 123); + mongoc_oidc_credential_destroy (cred); + } + + // expires_in == 0 is a valid argument. + { + mongoc_oidc_credential_t *const cred = mongoc_oidc_credential_new_with_expires_in ("token", 0); + ASSERT_CMPSTR (mongoc_oidc_credential_get_access_token (cred), "token"); + const int64_t *const expires_in = mongoc_oidc_credential_get_expires_in (cred); + ASSERT (expires_in); + ASSERT_CMPINT64 (*expires_in, ==, 0); + mongoc_oidc_credential_destroy (cred); + } + + // Invalid arguments. + { + ASSERT (!mongoc_oidc_credential_new (NULL)); + ASSERT (!mongoc_oidc_credential_new_with_expires_in (NULL, 123)); + ASSERT (!mongoc_oidc_credential_new_with_expires_in ("token", -1)); + } +} + +void +test_mongoc_oidc_callback_install (TestSuite *suite) +{ + TestSuite_Add (suite, "/oidc/callback/new", test_oidc_callback_new); + TestSuite_Add (suite, "/oidc/callback/params", test_oidc_callback_params); + TestSuite_Add (suite, "/oidc/callback/credential", test_oidc_credential); +}