Skip to content

Commit

Permalink
add support for resolving provider metadata from a Discovery endpoint
Browse files Browse the repository at this point in the history
- see OpenIDC/ngx_openidc_module#18
- bump to 1.5.1dev

Signed-off-by: Hans Zandbelt <hans.zandbelt@openidc.com>
  • Loading branch information
zandbelt committed Apr 13, 2023
1 parent 41a600e commit 20fff96
Show file tree
Hide file tree
Showing 4 changed files with 175 additions and 1 deletion.
4 changes: 4 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
04/14/2023
- add support for resolving provider metadata from a Discovery endpoint URL; see https://github.com/OpenIDC/ngx_openidc_module/issues/18
- bump to 1.5.1dev

03/22/2023
- add error logs about missing or invalid "active" boolean claim in introspection response

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.0],[hans.zandbelt@openidc.com])
AC_INIT([liboauth2],[1.5.1dev],[hans.zandbelt@openidc.com])

AM_INIT_AUTOMAKE([foreign no-define subdir-objects])
AC_CONFIG_MACRO_DIR([m4])
Expand Down
131 changes: 131 additions & 0 deletions src/openidc/resolver.c
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,135 @@ static char *_oauth2_cfg_openidc_provider_resolver_file_set_options(
return NULL;
}

_OAUTH2_CFG_CTX_TYPE_START(oauth2_openidc_provider_resolver_url_ctx)
oauth2_cfg_endpoint_t *endpoint;
_OAUTH2_CFG_CTX_TYPE_END(oauth2_openidc_provider_resolver_url_ctx)

_OAUTH2_CFG_CTX_INIT_START(oauth2_openidc_provider_resolver_url_ctx)
ctx->endpoint = NULL;
_OAUTH2_CFG_CTX_INIT_END

_OAUTH2_CFG_CTX_CLONE_START(oauth2_openidc_provider_resolver_url_ctx)
dst->endpoint = oauth2_cfg_endpoint_clone(log, src->endpoint);
_OAUTH2_CFG_CTX_CLONE_END

_OAUTH2_CFG_CTX_FREE_START(oauth2_openidc_provider_resolver_url_ctx)
if (ctx->endpoint)
oauth2_cfg_endpoint_free(log, ctx->endpoint);
_OAUTH2_CFG_CTX_FREE_END

_OAUTH2_CFG_CTX_FUNCS(oauth2_openidc_provider_resolver_url_ctx)

static bool _oauth2_openidc_provider_resolve_url_exec(
oauth2_log_t *log, oauth2_openidc_provider_resolver_url_ctx_t *ctx,
char **s_json)
{
bool rc = false;
oauth2_http_call_ctx_t *http_ctx = NULL;
char *s_response = NULL;
oauth2_uint_t status_code = 0;

oauth2_debug(log, "enter");

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

if (oauth2_http_call_ctx_ssl_verify_set(
log, http_ctx,
oauth2_cfg_endpoint_get_ssl_verify(ctx->endpoint)) == false)
goto end;

if (oauth2_http_call_ctx_timeout_set(
log, http_ctx,
oauth2_cfg_endpoint_get_http_timeout(ctx->endpoint)) == false)
goto end;
oauth2_http_call_ctx_outgoing_proxy_set(
log, http_ctx,
oauth2_cfg_endpoint_get_outgoing_proxy(ctx->endpoint));

if (oauth2_http_get(log, oauth2_cfg_endpoint_get_url(ctx->endpoint),
NULL, http_ctx, s_json, &status_code) == false)
goto end;

if ((status_code < 200) || (status_code >= 300)) {
goto end;
}

rc = true;

end:

if (s_response)
oauth2_mem_free(s_response);
if (http_ctx)
oauth2_http_call_ctx_free(log, http_ctx);

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

return rc;
}

static bool _oauth2_openidc_provider_resolve_url(
oauth2_log_t *log, const oauth2_cfg_openidc_t *cfg,
const oauth2_http_request_t *request, char **s_json)
{
bool rc = false;
oauth2_openidc_provider_resolver_url_ctx_t *ctx = NULL;

oauth2_debug(log, "enter");

ctx = (oauth2_openidc_provider_resolver_url_ctx_t *)
cfg->provider_resolver->ctx->ptr;
if (ctx->endpoint == NULL)
goto end;

if (_oauth2_openidc_provider_resolve_url_exec(log, ctx, s_json) ==
false)
goto end;

rc = true;

end:

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

return rc;
}

static char *_oauth2_cfg_openidc_provider_resolver_url_set_options(
oauth2_log_t *log, const char *value, const oauth2_nv_list_t *params,
void *c)
{
oauth2_cfg_openidc_t *cfg = (oauth2_cfg_openidc_t *)c;
char *rv = NULL;

// TODO: macroize?
cfg->provider_resolver = oauth2_cfg_openidc_provider_resolver_init(log);
cfg->provider_resolver->callback = _oauth2_openidc_provider_resolve_url;
cfg->provider_resolver->ctx->callbacks =
&oauth2_openidc_provider_resolver_url_ctx_funcs;
cfg->provider_resolver->ctx->ptr =
cfg->provider_resolver->ctx->callbacks->init(log);

// TODO: factor out?
oauth2_openidc_provider_resolver_url_ctx_t *ctx =
(oauth2_openidc_provider_resolver_url_ctx_t *)
cfg->provider_resolver->ctx->ptr;

ctx->endpoint = oauth2_cfg_endpoint_init(log);
rv = oauth2_cfg_set_endpoint(log, ctx->endpoint, value, params, NULL);
if (rv)
goto end;

cfg->provider_resolver->cache =
oauth2_cache_obtain(log, oauth2_nv_list_get(log, params, "cache"));

end:

return rv;
}

// DIR

static char *_oauth2_cfg_openidc_provider_resolver_dir_set_options(
Expand Down Expand Up @@ -286,12 +415,14 @@ static char *_oauth2_cfg_openidc_provider_resolver_string_set_options(
#define OAUTH2_OPENIDC_PROVIDER_RESOLVER_STR_STR "string"
#define OAUTH2_OPENIDC_PROVIDER_RESOLVER_FILE_STR "file"
#define OAUTH2_OPENIDC_PROVIDER_RESOLVER_DIR_STR "dir"
#define OAUTH2_OPENIDC_PROVIDER_RESOLVER_URL_STR "url"

// clang-format off
static oauth2_cfg_set_options_ctx_t _oauth2_cfg_resolver_options_set[] = {
{ OAUTH2_OPENIDC_PROVIDER_RESOLVER_STR_STR, _oauth2_cfg_openidc_provider_resolver_string_set_options },
{ OAUTH2_OPENIDC_PROVIDER_RESOLVER_FILE_STR, _oauth2_cfg_openidc_provider_resolver_file_set_options },
{ OAUTH2_OPENIDC_PROVIDER_RESOLVER_DIR_STR, _oauth2_cfg_openidc_provider_resolver_dir_set_options },
{ OAUTH2_OPENIDC_PROVIDER_RESOLVER_URL_STR, _oauth2_cfg_openidc_provider_resolver_url_set_options },
{ NULL, NULL }
};
// clang-format on
Expand Down
39 changes: 39 additions & 0 deletions test/check_openidc.c
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ static cjose_jwk_t *jwk_rsa = NULL;
static char *jwks_uri_path = "/jwks_uri";
static char *token_endpoint_path = "/token";
static char *userinfo_endpoint_path = "/userinfo";
static char *discovery_endpoint_path = "/.well-known/openid-configuration";

static cjose_jwk_t *oauth2_jwk_rsa_get()
{
Expand Down Expand Up @@ -137,6 +138,10 @@ static char *oauth2_check_openidc_serve_get(const char *request)
strlen(userinfo_endpoint_path)) == 0) {
rv = oauth2_strdup("{ \"sub\": \"myclient\", "
"\"myuserinfoclaim\": \"somevalue\" }");
} else if (strncmp(request, discovery_endpoint_path,
strlen(discovery_endpoint_path)) == 0) {
rv =
oauth2_strdup("{ \"issuer\": \"https://op.example.org\" }");
} else {
rv = oauth2_strdup("problem");
}
Expand Down Expand Up @@ -527,6 +532,39 @@ static void _test_openidc_resolve_to_false(oauth2_cfg_openidc_t *c,
ck_assert_ptr_eq(NULL, provider);
}

START_TEST(test_openidc_resolver_url)
{
bool rc = false;
char *rv = NULL;
oauth2_cfg_openidc_t *c = NULL;
oauth2_http_request_t *r = NULL;
oauth2_openidc_provider_t *provider = NULL;
char *discovery_uri = oauth2_stradd(NULL, oauth2_check_http_base_url(),
discovery_endpoint_path, NULL);

c = oauth2_cfg_openidc_init(_log);
r = oauth2_http_request_init(_log);

rv = oauth2_cfg_openidc_provider_resolver_set_options(
_log, c, "url", discovery_uri, NULL);
ck_assert_ptr_eq(rv, NULL);

rc = _oauth2_openidc_provider_resolve(_log, c, r, NULL, &provider);
ck_assert_int_eq(rc, true);
ck_assert_ptr_ne(NULL, provider);
ck_assert_str_eq("https://op.example.org",
oauth2_openidc_provider_issuer_get(_log, provider));
oauth2_openidc_provider_free(_log, provider);
provider = NULL;

oauth2_openidc_provider_free(_log, provider);
provider = NULL;

oauth2_mem_free(discovery_uri);
oauth2_http_request_free(_log, r);
oauth2_cfg_openidc_free(_log, c);
}

START_TEST(test_openidc_resolver)
{
bool rc = false;
Expand Down Expand Up @@ -1103,6 +1141,7 @@ Suite *oauth2_check_openidc_suite()
tcase_add_test(c, test_openidc_handle_cookie);
tcase_add_test(c, test_openidc_handle_cache);
tcase_add_test(c, test_openidc_state_cookie);
tcase_add_test(c, test_openidc_resolver_url);

tcase_set_timeout(c, 8);

Expand Down

0 comments on commit 20fff96

Please sign in to comment.