Skip to content

Commit c11da6c

Browse files
committed
1.6.0: add support for the OAuth 2.0 Client Credentials grant type
re-format using clang-format-17 Signed-off-by: Hans Zandbelt <[email protected]>
1 parent 6851bb3 commit c11da6c

File tree

15 files changed

+308
-24
lines changed

15 files changed

+308
-24
lines changed

ChangeLog

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
12/06/2023
2+
- add support for the OAuth 2.0 Client Credentials grant type
3+
- release 1.6.0
4+
15
11/08/2023
26
- update DPoP support to RFC 9449
37
- release 1.5.2

configure.ac

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
AC_INIT([liboauth2],[1.5.2],[[email protected]])
1+
AC_INIT([liboauth2],[1.6.0],[[email protected]])
22

33
AM_INIT_AUTOMAKE([foreign no-define subdir-objects])
44
AC_CONFIG_MACRO_DIR([m4])

include/oauth2/cfg.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,4 +282,19 @@ const char *oauth2_cfg_ropc_get_password(oauth2_cfg_ropc_t *cfg);
282282
const oauth2_nv_list_t *
283283
oauth2_cfg_ropc_get_request_parameters(oauth2_cfg_ropc_t *cfg);
284284

285+
/*
286+
* client credentials
287+
*/
288+
289+
OAUTH2_CFG_TYPE_DECLARE(cfg, cc)
290+
291+
char *oauth2_cfg_set_cc(oauth2_log_t *log, oauth2_cfg_cc_t *cfg,
292+
const char *url, const char *options);
293+
294+
const oauth2_cfg_endpoint_t *
295+
oauth2_cfg_cc_get_token_endpoint(oauth2_cfg_cc_t *cfg);
296+
const char *oauth2_cfg_cc_get_client_id(oauth2_cfg_cc_t *cfg);
297+
const oauth2_nv_list_t *
298+
oauth2_cfg_cc_get_request_parameters(oauth2_cfg_cc_t *cfg);
299+
285300
#endif /* _OAUTH2_CFG_H_ */

include/oauth2/proto.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,7 @@ bool oauth2_ropc_exec(oauth2_log_t *log, oauth2_cfg_ropc_t *cfg,
3434
const char *username, const char *password, char **rtoken,
3535
oauth2_uint_t *status_code);
3636

37+
bool oauth2_cc_exec(oauth2_log_t *log, oauth2_cfg_cc_t *cfg, char **rtoken,
38+
oauth2_uint_t *status_code);
39+
3740
#endif /* _OAUTH2_PROTO_H_ */

src/cfg/auth.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -380,9 +380,10 @@ oauth2_cfg_endpoint_auth_basic_options_set(oauth2_log_t *log,
380380
return rv;
381381
}
382382

383-
typedef char *(oauth2_cfg_endpoint_auth_set_options_cb_t)(
384-
oauth2_log_t *log, oauth2_cfg_endpoint_auth_t *auth,
385-
const oauth2_nv_list_t *params);
383+
typedef char *(
384+
oauth2_cfg_endpoint_auth_set_options_cb_t)(oauth2_log_t *log,
385+
oauth2_cfg_endpoint_auth_t *auth,
386+
const oauth2_nv_list_t *params);
386387

387388
typedef struct oauth2_cfg_endpoint_auth_set_options_ctx_t {
388389
const char *type;

src/cfg/proto_cfg.c

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@
2424

2525
#include "cfg_int.h"
2626

27+
/*
28+
* endpoint
29+
*/
30+
2731
oauth2_cfg_endpoint_t *oauth2_cfg_endpoint_init(oauth2_log_t *log)
2832
{
2933
oauth2_cfg_endpoint_t *endpoint = NULL;
@@ -205,6 +209,10 @@ oauth2_cfg_endpoint_get_outgoing_proxy(const oauth2_cfg_endpoint_t *cfg)
205209
return cfg ? cfg->outgoing_proxy : NULL;
206210
}
207211

212+
/*
213+
* Resource Owner Password Credentials
214+
*/
215+
208216
#define OAUTH2_CFG_ROPC_CLIENT_ID_DEFAULT NULL
209217
#define OAUTH2_CFG_ROPC_USERNAME_DEFAULT NULL
210218
#define OAUTH2_CFG_ROPC_PASSWORD_DEFAULT NULL
@@ -401,3 +409,158 @@ const char *oauth2_cfg_ropc_get_password(oauth2_cfg_ropc_t *cfg)
401409
return OAUTH2_CFG_ROPC_PASSWORD_DEFAULT;
402410
return cfg->password;
403411
}
412+
413+
/*
414+
* Client Credentials
415+
*/
416+
417+
typedef struct oauth2_cfg_cc_t {
418+
oauth2_cfg_endpoint_t *token_endpoint;
419+
char *client_id;
420+
oauth2_nv_list_t *request_parameters;
421+
} oauth2_cfg_cc_t;
422+
423+
oauth2_cfg_cc_t *oauth2_cfg_cc_init(oauth2_log_t *log)
424+
{
425+
oauth2_cfg_cc_t *cc = NULL;
426+
427+
cc = (oauth2_cfg_cc_t *)oauth2_mem_alloc(sizeof(oauth2_cfg_cc_t));
428+
if (cc == NULL)
429+
goto end;
430+
431+
cc->token_endpoint = NULL;
432+
cc->client_id = NULL;
433+
cc->request_parameters = NULL;
434+
435+
end:
436+
437+
return cc;
438+
}
439+
440+
void oauth2_cfg_cc_free(oauth2_log_t *log, oauth2_cfg_cc_t *cc)
441+
{
442+
if (cc == NULL)
443+
goto end;
444+
445+
if (cc->token_endpoint)
446+
oauth2_cfg_endpoint_free(log, cc->token_endpoint);
447+
if (cc->client_id)
448+
oauth2_mem_free(cc->client_id);
449+
if (cc->request_parameters)
450+
oauth2_nv_list_free(log, cc->request_parameters);
451+
452+
oauth2_mem_free(cc);
453+
454+
end:
455+
456+
return;
457+
}
458+
459+
void oauth2_cfg_cc_merge(oauth2_log_t *log, oauth2_cfg_cc_t *dst,
460+
oauth2_cfg_cc_t *base, oauth2_cfg_cc_t *add)
461+
{
462+
463+
oauth2_cfg_cc_t *src = (add && add->token_endpoint != 0) ? add
464+
: base ? base
465+
: NULL;
466+
467+
if ((src == NULL) || (dst == NULL))
468+
goto end;
469+
470+
dst->token_endpoint =
471+
oauth2_cfg_endpoint_clone(log, src->token_endpoint);
472+
dst->client_id = oauth2_strdup(src->client_id);
473+
dst->request_parameters =
474+
oauth2_nv_list_clone(log, src->request_parameters);
475+
476+
end:
477+
478+
return;
479+
}
480+
481+
oauth2_cfg_cc_t *oauth2_cfg_cc_clone(oauth2_log_t *log,
482+
const oauth2_cfg_cc_t *src)
483+
{
484+
oauth2_cfg_cc_t *dst = NULL;
485+
486+
if (src == NULL)
487+
goto end;
488+
489+
dst = oauth2_cfg_cc_init(log);
490+
dst->token_endpoint =
491+
oauth2_cfg_endpoint_clone(log, src->token_endpoint);
492+
dst->client_id = oauth2_strdup(src->client_id);
493+
dst->request_parameters =
494+
oauth2_nv_list_clone(log, src->request_parameters);
495+
496+
end:
497+
498+
return dst;
499+
}
500+
501+
char *oauth2_cfg_set_cc(oauth2_log_t *log, oauth2_cfg_cc_t *cfg,
502+
const char *url, const char *options)
503+
{
504+
char *rv = NULL;
505+
oauth2_nv_list_t *params = NULL;
506+
const char *value = NULL;
507+
508+
if (cfg == NULL) {
509+
rv = oauth2_strdup("struct is null");
510+
goto end;
511+
}
512+
513+
if (oauth2_parse_form_encoded_params(log, options, &params) == false)
514+
goto end;
515+
516+
cfg->token_endpoint = oauth2_cfg_endpoint_init(log);
517+
rv = oauth2_cfg_set_endpoint(log, cfg->token_endpoint, url, params,
518+
NULL);
519+
if (rv)
520+
goto end;
521+
522+
value = oauth2_nv_list_get(log, params, "client_id");
523+
if (value) {
524+
rv = oauth2_strdup(oauth2_cfg_set_str_slot(
525+
cfg, offsetof(oauth2_cfg_cc_t, client_id), value));
526+
if (rv)
527+
goto end;
528+
}
529+
530+
value = oauth2_nv_list_get(log, params, "params");
531+
if (value) {
532+
if (oauth2_parse_form_encoded_params(
533+
log, value, &cfg->request_parameters) == false) {
534+
rv =
535+
oauth2_strdup("could not parse request parameters");
536+
goto end;
537+
}
538+
}
539+
end:
540+
541+
if (params)
542+
oauth2_nv_list_free(log, params);
543+
544+
oauth2_debug(log, "leave: %s", rv);
545+
546+
return rv;
547+
}
548+
549+
const oauth2_cfg_endpoint_t *
550+
oauth2_cfg_cc_get_token_endpoint(oauth2_cfg_cc_t *cfg)
551+
{
552+
return cfg ? cfg->token_endpoint : NULL;
553+
}
554+
555+
const char *oauth2_cfg_cc_get_client_id(oauth2_cfg_cc_t *cfg)
556+
{
557+
if ((cfg == NULL) || (cfg->client_id == NULL))
558+
return NULL;
559+
return cfg->client_id;
560+
}
561+
562+
const oauth2_nv_list_t *
563+
oauth2_cfg_cc_get_request_parameters(oauth2_cfg_cc_t *cfg)
564+
{
565+
return cfg->request_parameters;
566+
}

src/cfg/source.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -96,9 +96,12 @@ oauth2_cfg_accept_in_cookie_options_set(oauth2_log_t *log,
9696
return rv;
9797
}
9898

99-
typedef char *(oauth2_cfg_accept_token_in_set_options_cb_t)(
100-
oauth2_log_t *log, oauth2_cfg_token_in_t *accept_in,
101-
const oauth2_nv_list_t *params);
99+
typedef char *(
100+
oauth2_cfg_accept_token_in_set_options_cb_t)(oauth2_log_t *log,
101+
oauth2_cfg_token_in_t
102+
*accept_in,
103+
const oauth2_nv_list_t
104+
*params);
102105

103106
typedef struct oauth2_cfg_accept_token_in_set_options_ctx_t {
104107
const char *method;

src/http.c

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1007,11 +1007,9 @@ bool oauth2_http_call(oauth2_log_t *log, const char *url, const char *data,
10071007
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&buf);
10081008

10091009
#ifndef LIBCURL_NO_CURLPROTO
1010-
#if CURL_AT_LEAST_VERSION(7,85,0)
1011-
curl_easy_setopt(curl, CURLOPT_REDIR_PROTOCOLS_STR,
1012-
"http,https");
1013-
curl_easy_setopt(curl, CURLOPT_PROTOCOLS_STR,
1014-
"http,https");
1010+
#if CURL_AT_LEAST_VERSION(7, 85, 0)
1011+
curl_easy_setopt(curl, CURLOPT_REDIR_PROTOCOLS_STR, "http,https");
1012+
curl_easy_setopt(curl, CURLOPT_PROTOCOLS_STR, "http,https");
10151013
#else
10161014
curl_easy_setopt(curl, CURLOPT_REDIR_PROTOCOLS,
10171015
CURLPROTO_HTTP | CURLPROTO_HTTPS);

src/jose.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1850,8 +1850,9 @@ static oauth2_jose_jwk_list_t *oauth2_jose_jwks_list_resolve(
18501850
return oauth2_jose_jwk_list_clone(log, provider->jwks);
18511851
}
18521852

1853-
typedef oauth2_jose_jwk_list_t *(oauth2_jose_jwks_url_resolve_response_cb_t)(
1854-
oauth2_log_t *log, char *response);
1853+
typedef oauth2_jose_jwk_list_t *(
1854+
oauth2_jose_jwks_url_resolve_response_cb_t)(oauth2_log_t *log,
1855+
char *response);
18551856

18561857
// cater for the (Amazon ALB) use case that only a single EC(!) key is served
18571858
// from the URL

src/jose_int.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,9 @@ typedef enum oauth2_jose_jwks_provider_type_t {
5252

5353
typedef struct oauth2_jose_jwks_provider_t oauth2_jose_jwks_provider_t;
5454

55-
typedef oauth2_jose_jwk_list_t *(oauth2_jose_jwks_resolve_cb_t)(
56-
oauth2_log_t *, oauth2_jose_jwks_provider_t *, bool *);
55+
typedef oauth2_jose_jwk_list_t *(
56+
oauth2_jose_jwks_resolve_cb_t)(oauth2_log_t *,
57+
oauth2_jose_jwks_provider_t *, bool *);
5758

5859
typedef struct oauth2_jose_jwks_provider_t {
5960
oauth2_jose_jwks_provider_type_t type;

src/proto.c

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -492,3 +492,67 @@ bool oauth2_ropc_exec(oauth2_log_t *log, oauth2_cfg_ropc_t *cfg,
492492

493493
return rc;
494494
}
495+
496+
#define OAUTH2_PROTO_CC_GRANT_TYPE_VALUE "client_credentials"
497+
498+
bool oauth2_cc_exec(oauth2_log_t *log, oauth2_cfg_cc_t *cfg, char **rtoken,
499+
oauth2_uint_t *status_code)
500+
{
501+
502+
bool rc = false;
503+
oauth2_nv_list_t *params = NULL;
504+
oauth2_http_call_ctx_t *ctx = NULL;
505+
const char *client_id = oauth2_cfg_cc_get_client_id(cfg);
506+
const oauth2_cfg_endpoint_t *token_endpoint =
507+
oauth2_cfg_cc_get_token_endpoint(cfg);
508+
509+
oauth2_debug(log, "enter");
510+
511+
if (cfg == NULL) {
512+
oauth2_error(log, "token endpoint cfg is not set");
513+
goto end;
514+
}
515+
if (token_endpoint == NULL) {
516+
oauth2_warn(log, "token endpoint is not set");
517+
goto end;
518+
}
519+
params = oauth2_nv_list_init(log);
520+
oauth2_nv_list_add(log, params, OAUTH2_GRANT_TYPE,
521+
OAUTH2_PROTO_CC_GRANT_TYPE_VALUE);
522+
523+
if ((oauth2_cfg_endpoint_auth_type(oauth2_cfg_endpoint_get_auth(
524+
token_endpoint)) == OAUTH2_ENDPOINT_AUTH_NONE) &&
525+
(client_id != NULL))
526+
oauth2_nv_list_add(log, params, OAUTH2_CLIENT_ID, client_id);
527+
528+
oauth2_nv_list_merge_into(
529+
log, oauth2_cfg_cc_get_request_parameters(cfg), params);
530+
531+
ctx = oauth2_http_call_ctx_init(log);
532+
if (ctx == NULL)
533+
goto end;
534+
535+
oauth2_http_call_ctx_ssl_verify_set(
536+
log, ctx, oauth2_cfg_endpoint_get_ssl_verify(token_endpoint));
537+
oauth2_http_call_ctx_outgoing_proxy_set(
538+
log, ctx, oauth2_cfg_endpoint_get_outgoing_proxy(token_endpoint));
539+
540+
if (oauth2_http_ctx_auth_add(
541+
log, ctx, oauth2_cfg_endpoint_get_auth(token_endpoint),
542+
params) == false)
543+
goto end;
544+
545+
rc = oauth2_proto_request(log, oauth2_cfg_cc_get_token_endpoint(cfg),
546+
ctx, params, rtoken, status_code);
547+
548+
end:
549+
550+
if (params)
551+
oauth2_nv_list_free(log, params);
552+
if (ctx)
553+
oauth2_http_call_ctx_free(log, ctx);
554+
555+
oauth2_debug(log, "leave: %d", rc);
556+
557+
return rc;
558+
}

src/util.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -80,12 +80,12 @@ void oauth2_shutdown(oauth2_log_t *log)
8080
ERR_free_strings();
8181
CRYPTO_cleanup_all_ex_data();
8282

83-
//#if OPENSSL_API_COMPAT < 0x10100000L
84-
//#if OPENSSL_VERSION_NUMBER < 0x10000000L
83+
// #if OPENSSL_API_COMPAT < 0x10100000L
84+
// #if OPENSSL_VERSION_NUMBER < 0x10000000L
8585
// SSL_COMP_free_compression_methods();
86-
//#endif
86+
// #endif
8787
#if (OPENSSL_VERSION_NUMBER < 0x10100000) || defined(LIBRESSL_VERSION_NUMBER)
88-
//#if OPENSSL_API_COMPAT < 0x10100000L
88+
// #if OPENSSL_API_COMPAT < 0x10100000L
8989
ERR_remove_thread_state(NULL);
9090
#endif
9191
oauth2_log_free(log);

test/check_liboauth2.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838

3939
#include "util_int.h"
4040

41-
//#include <semaphore.h>
41+
// #include <semaphore.h>
4242

4343
static int http_server_port = 8888;
4444
static int http_server_signal_delivered = 0;

test/check_liboauth2.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,10 @@
2222
*
2323
**************************************************************************/
2424

25-
//#pragma GCC diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
26-
//#pragma GCC diagnostic ignored
25+
// #pragma GCC diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
26+
// #pragma GCC diagnostic ignored
2727
//"-Wincompatible-pointer-types-discards-qualifiers"
28-
//#pragma GCC diagnostic ignored "-Wpointer-sign"
28+
// #pragma GCC diagnostic ignored "-Wpointer-sign"
2929

3030
#include <check.h>
3131

0 commit comments

Comments
 (0)