Skip to content

Commit

Permalink
1.6.0: add support for the OAuth 2.0 Client Credentials grant type
Browse files Browse the repository at this point in the history
re-format using clang-format-17

Signed-off-by: Hans Zandbelt <hans.zandbelt@openidc.com>
  • Loading branch information
zandbelt committed Dec 6, 2023
1 parent 6851bb3 commit c11da6c
Show file tree
Hide file tree
Showing 15 changed files with 308 additions and 24 deletions.
4 changes: 4 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
12/06/2023
- add support for the OAuth 2.0 Client Credentials grant type
- release 1.6.0

11/08/2023
- update DPoP support to RFC 9449
- release 1.5.2
Expand Down
2 changes: 1 addition & 1 deletion configure.ac
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
AC_INIT([liboauth2],[1.5.2],[hans.zandbelt@openidc.com])
AC_INIT([liboauth2],[1.6.0],[hans.zandbelt@openidc.com])

AM_INIT_AUTOMAKE([foreign no-define subdir-objects])
AC_CONFIG_MACRO_DIR([m4])
Expand Down
15 changes: 15 additions & 0 deletions include/oauth2/cfg.h
Original file line number Diff line number Diff line change
Expand Up @@ -282,4 +282,19 @@ const char *oauth2_cfg_ropc_get_password(oauth2_cfg_ropc_t *cfg);
const oauth2_nv_list_t *
oauth2_cfg_ropc_get_request_parameters(oauth2_cfg_ropc_t *cfg);

/*
* client credentials
*/

OAUTH2_CFG_TYPE_DECLARE(cfg, cc)

char *oauth2_cfg_set_cc(oauth2_log_t *log, oauth2_cfg_cc_t *cfg,
const char *url, const char *options);

const oauth2_cfg_endpoint_t *
oauth2_cfg_cc_get_token_endpoint(oauth2_cfg_cc_t *cfg);
const char *oauth2_cfg_cc_get_client_id(oauth2_cfg_cc_t *cfg);
const oauth2_nv_list_t *
oauth2_cfg_cc_get_request_parameters(oauth2_cfg_cc_t *cfg);

#endif /* _OAUTH2_CFG_H_ */
3 changes: 3 additions & 0 deletions include/oauth2/proto.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,7 @@ bool oauth2_ropc_exec(oauth2_log_t *log, oauth2_cfg_ropc_t *cfg,
const char *username, const char *password, char **rtoken,
oauth2_uint_t *status_code);

bool oauth2_cc_exec(oauth2_log_t *log, oauth2_cfg_cc_t *cfg, char **rtoken,
oauth2_uint_t *status_code);

#endif /* _OAUTH2_PROTO_H_ */
7 changes: 4 additions & 3 deletions src/cfg/auth.c
Original file line number Diff line number Diff line change
Expand Up @@ -380,9 +380,10 @@ oauth2_cfg_endpoint_auth_basic_options_set(oauth2_log_t *log,
return rv;
}

typedef char *(oauth2_cfg_endpoint_auth_set_options_cb_t)(
oauth2_log_t *log, oauth2_cfg_endpoint_auth_t *auth,
const oauth2_nv_list_t *params);
typedef char *(
oauth2_cfg_endpoint_auth_set_options_cb_t)(oauth2_log_t *log,
oauth2_cfg_endpoint_auth_t *auth,
const oauth2_nv_list_t *params);

typedef struct oauth2_cfg_endpoint_auth_set_options_ctx_t {
const char *type;
Expand Down
163 changes: 163 additions & 0 deletions src/cfg/proto_cfg.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@

#include "cfg_int.h"

/*
* endpoint
*/

oauth2_cfg_endpoint_t *oauth2_cfg_endpoint_init(oauth2_log_t *log)
{
oauth2_cfg_endpoint_t *endpoint = NULL;
Expand Down Expand Up @@ -205,6 +209,10 @@ oauth2_cfg_endpoint_get_outgoing_proxy(const oauth2_cfg_endpoint_t *cfg)
return cfg ? cfg->outgoing_proxy : NULL;
}

/*
* Resource Owner Password Credentials
*/

#define OAUTH2_CFG_ROPC_CLIENT_ID_DEFAULT NULL
#define OAUTH2_CFG_ROPC_USERNAME_DEFAULT NULL
#define OAUTH2_CFG_ROPC_PASSWORD_DEFAULT NULL
Expand Down Expand Up @@ -401,3 +409,158 @@ const char *oauth2_cfg_ropc_get_password(oauth2_cfg_ropc_t *cfg)
return OAUTH2_CFG_ROPC_PASSWORD_DEFAULT;
return cfg->password;
}

/*
* Client Credentials
*/

typedef struct oauth2_cfg_cc_t {
oauth2_cfg_endpoint_t *token_endpoint;
char *client_id;
oauth2_nv_list_t *request_parameters;
} oauth2_cfg_cc_t;

oauth2_cfg_cc_t *oauth2_cfg_cc_init(oauth2_log_t *log)
{
oauth2_cfg_cc_t *cc = NULL;

cc = (oauth2_cfg_cc_t *)oauth2_mem_alloc(sizeof(oauth2_cfg_cc_t));
if (cc == NULL)
goto end;

cc->token_endpoint = NULL;
cc->client_id = NULL;
cc->request_parameters = NULL;

end:

return cc;
}

void oauth2_cfg_cc_free(oauth2_log_t *log, oauth2_cfg_cc_t *cc)
{
if (cc == NULL)
goto end;

if (cc->token_endpoint)
oauth2_cfg_endpoint_free(log, cc->token_endpoint);
if (cc->client_id)
oauth2_mem_free(cc->client_id);
if (cc->request_parameters)
oauth2_nv_list_free(log, cc->request_parameters);

oauth2_mem_free(cc);

end:

return;
}

void oauth2_cfg_cc_merge(oauth2_log_t *log, oauth2_cfg_cc_t *dst,
oauth2_cfg_cc_t *base, oauth2_cfg_cc_t *add)
{

oauth2_cfg_cc_t *src = (add && add->token_endpoint != 0) ? add
: base ? base
: NULL;

if ((src == NULL) || (dst == NULL))
goto end;

dst->token_endpoint =
oauth2_cfg_endpoint_clone(log, src->token_endpoint);
dst->client_id = oauth2_strdup(src->client_id);
dst->request_parameters =
oauth2_nv_list_clone(log, src->request_parameters);

end:

return;
}

oauth2_cfg_cc_t *oauth2_cfg_cc_clone(oauth2_log_t *log,
const oauth2_cfg_cc_t *src)
{
oauth2_cfg_cc_t *dst = NULL;

if (src == NULL)
goto end;

dst = oauth2_cfg_cc_init(log);
dst->token_endpoint =
oauth2_cfg_endpoint_clone(log, src->token_endpoint);
dst->client_id = oauth2_strdup(src->client_id);
dst->request_parameters =
oauth2_nv_list_clone(log, src->request_parameters);

end:

return dst;
}

char *oauth2_cfg_set_cc(oauth2_log_t *log, oauth2_cfg_cc_t *cfg,
const char *url, const char *options)
{
char *rv = NULL;
oauth2_nv_list_t *params = NULL;
const char *value = NULL;

if (cfg == NULL) {
rv = oauth2_strdup("struct is null");
goto end;
}

if (oauth2_parse_form_encoded_params(log, options, &params) == false)
goto end;

cfg->token_endpoint = oauth2_cfg_endpoint_init(log);
rv = oauth2_cfg_set_endpoint(log, cfg->token_endpoint, url, params,
NULL);
if (rv)
goto end;

value = oauth2_nv_list_get(log, params, "client_id");
if (value) {
rv = oauth2_strdup(oauth2_cfg_set_str_slot(
cfg, offsetof(oauth2_cfg_cc_t, client_id), value));
if (rv)
goto end;
}

value = oauth2_nv_list_get(log, params, "params");
if (value) {
if (oauth2_parse_form_encoded_params(
log, value, &cfg->request_parameters) == false) {
rv =
oauth2_strdup("could not parse request parameters");
goto end;
}
}
end:

if (params)
oauth2_nv_list_free(log, params);

oauth2_debug(log, "leave: %s", rv);

return rv;
}

const oauth2_cfg_endpoint_t *
oauth2_cfg_cc_get_token_endpoint(oauth2_cfg_cc_t *cfg)
{
return cfg ? cfg->token_endpoint : NULL;
}

const char *oauth2_cfg_cc_get_client_id(oauth2_cfg_cc_t *cfg)
{
if ((cfg == NULL) || (cfg->client_id == NULL))
return NULL;
return cfg->client_id;
}

const oauth2_nv_list_t *
oauth2_cfg_cc_get_request_parameters(oauth2_cfg_cc_t *cfg)
{
return cfg->request_parameters;
}
9 changes: 6 additions & 3 deletions src/cfg/source.c
Original file line number Diff line number Diff line change
Expand Up @@ -96,9 +96,12 @@ oauth2_cfg_accept_in_cookie_options_set(oauth2_log_t *log,
return rv;
}

typedef char *(oauth2_cfg_accept_token_in_set_options_cb_t)(
oauth2_log_t *log, oauth2_cfg_token_in_t *accept_in,
const oauth2_nv_list_t *params);
typedef char *(
oauth2_cfg_accept_token_in_set_options_cb_t)(oauth2_log_t *log,
oauth2_cfg_token_in_t
*accept_in,
const oauth2_nv_list_t
*params);

typedef struct oauth2_cfg_accept_token_in_set_options_ctx_t {
const char *method;
Expand Down
8 changes: 3 additions & 5 deletions src/http.c
Original file line number Diff line number Diff line change
Expand Up @@ -1007,11 +1007,9 @@ bool oauth2_http_call(oauth2_log_t *log, const char *url, const char *data,
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&buf);

#ifndef LIBCURL_NO_CURLPROTO
#if CURL_AT_LEAST_VERSION(7,85,0)
curl_easy_setopt(curl, CURLOPT_REDIR_PROTOCOLS_STR,
"http,https");
curl_easy_setopt(curl, CURLOPT_PROTOCOLS_STR,
"http,https");
#if CURL_AT_LEAST_VERSION(7, 85, 0)
curl_easy_setopt(curl, CURLOPT_REDIR_PROTOCOLS_STR, "http,https");
curl_easy_setopt(curl, CURLOPT_PROTOCOLS_STR, "http,https");
#else
curl_easy_setopt(curl, CURLOPT_REDIR_PROTOCOLS,
CURLPROTO_HTTP | CURLPROTO_HTTPS);
Expand Down
5 changes: 3 additions & 2 deletions src/jose.c
Original file line number Diff line number Diff line change
Expand Up @@ -1850,8 +1850,9 @@ static oauth2_jose_jwk_list_t *oauth2_jose_jwks_list_resolve(
return oauth2_jose_jwk_list_clone(log, provider->jwks);
}

typedef oauth2_jose_jwk_list_t *(oauth2_jose_jwks_url_resolve_response_cb_t)(
oauth2_log_t *log, char *response);
typedef oauth2_jose_jwk_list_t *(
oauth2_jose_jwks_url_resolve_response_cb_t)(oauth2_log_t *log,
char *response);

// cater for the (Amazon ALB) use case that only a single EC(!) key is served
// from the URL
Expand Down
5 changes: 3 additions & 2 deletions src/jose_int.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,9 @@ typedef enum oauth2_jose_jwks_provider_type_t {

typedef struct oauth2_jose_jwks_provider_t oauth2_jose_jwks_provider_t;

typedef oauth2_jose_jwk_list_t *(oauth2_jose_jwks_resolve_cb_t)(
oauth2_log_t *, oauth2_jose_jwks_provider_t *, bool *);
typedef oauth2_jose_jwk_list_t *(
oauth2_jose_jwks_resolve_cb_t)(oauth2_log_t *,
oauth2_jose_jwks_provider_t *, bool *);

typedef struct oauth2_jose_jwks_provider_t {
oauth2_jose_jwks_provider_type_t type;
Expand Down
64 changes: 64 additions & 0 deletions src/proto.c
Original file line number Diff line number Diff line change
Expand Up @@ -492,3 +492,67 @@ bool oauth2_ropc_exec(oauth2_log_t *log, oauth2_cfg_ropc_t *cfg,

return rc;
}

#define OAUTH2_PROTO_CC_GRANT_TYPE_VALUE "client_credentials"

bool oauth2_cc_exec(oauth2_log_t *log, oauth2_cfg_cc_t *cfg, char **rtoken,
oauth2_uint_t *status_code)
{

bool rc = false;
oauth2_nv_list_t *params = NULL;
oauth2_http_call_ctx_t *ctx = NULL;
const char *client_id = oauth2_cfg_cc_get_client_id(cfg);
const oauth2_cfg_endpoint_t *token_endpoint =
oauth2_cfg_cc_get_token_endpoint(cfg);

oauth2_debug(log, "enter");

if (cfg == NULL) {
oauth2_error(log, "token endpoint cfg is not set");
goto end;
}
if (token_endpoint == NULL) {
oauth2_warn(log, "token endpoint is not set");
goto end;
}
params = oauth2_nv_list_init(log);
oauth2_nv_list_add(log, params, OAUTH2_GRANT_TYPE,
OAUTH2_PROTO_CC_GRANT_TYPE_VALUE);

if ((oauth2_cfg_endpoint_auth_type(oauth2_cfg_endpoint_get_auth(
token_endpoint)) == OAUTH2_ENDPOINT_AUTH_NONE) &&
(client_id != NULL))
oauth2_nv_list_add(log, params, OAUTH2_CLIENT_ID, client_id);

oauth2_nv_list_merge_into(
log, oauth2_cfg_cc_get_request_parameters(cfg), params);

ctx = oauth2_http_call_ctx_init(log);
if (ctx == NULL)
goto end;

oauth2_http_call_ctx_ssl_verify_set(
log, ctx, oauth2_cfg_endpoint_get_ssl_verify(token_endpoint));
oauth2_http_call_ctx_outgoing_proxy_set(
log, ctx, oauth2_cfg_endpoint_get_outgoing_proxy(token_endpoint));

if (oauth2_http_ctx_auth_add(
log, ctx, oauth2_cfg_endpoint_get_auth(token_endpoint),
params) == false)
goto end;

rc = oauth2_proto_request(log, oauth2_cfg_cc_get_token_endpoint(cfg),
ctx, params, rtoken, status_code);

end:

if (params)
oauth2_nv_list_free(log, params);
if (ctx)
oauth2_http_call_ctx_free(log, ctx);

oauth2_debug(log, "leave: %d", rc);

return rc;
}
8 changes: 4 additions & 4 deletions src/util.c
Original file line number Diff line number Diff line change
Expand Up @@ -80,12 +80,12 @@ void oauth2_shutdown(oauth2_log_t *log)
ERR_free_strings();
CRYPTO_cleanup_all_ex_data();

//#if OPENSSL_API_COMPAT < 0x10100000L
//#if OPENSSL_VERSION_NUMBER < 0x10000000L
// #if OPENSSL_API_COMPAT < 0x10100000L
// #if OPENSSL_VERSION_NUMBER < 0x10000000L
// SSL_COMP_free_compression_methods();
//#endif
// #endif
#if (OPENSSL_VERSION_NUMBER < 0x10100000) || defined(LIBRESSL_VERSION_NUMBER)
//#if OPENSSL_API_COMPAT < 0x10100000L
// #if OPENSSL_API_COMPAT < 0x10100000L
ERR_remove_thread_state(NULL);
#endif
oauth2_log_free(log);
Expand Down
2 changes: 1 addition & 1 deletion test/check_liboauth2.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@

#include "util_int.h"

//#include <semaphore.h>
// #include <semaphore.h>

static int http_server_port = 8888;
static int http_server_signal_delivered = 0;
Expand Down
6 changes: 3 additions & 3 deletions test/check_liboauth2.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@
*
**************************************************************************/

//#pragma GCC diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
//#pragma GCC diagnostic ignored
// #pragma GCC diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
// #pragma GCC diagnostic ignored
//"-Wincompatible-pointer-types-discards-qualifiers"
//#pragma GCC diagnostic ignored "-Wpointer-sign"
// #pragma GCC diagnostic ignored "-Wpointer-sign"

#include <check.h>

Expand Down
Loading

0 comments on commit c11da6c

Please sign in to comment.