From 28557c1b84bac245730058328430fea354a97d25 Mon Sep 17 00:00:00 2001 From: Hans Zandbelt Date: Mon, 17 Jun 2024 20:34:52 +0200 Subject: [PATCH] configure the DPoP API with OIDCDPoPMode instead of OIDCInfoHook Signed-off-by: Hans Zandbelt --- ChangeLog | 2 +- auth_openidc.conf | 8 +++++--- src/cfg/cfg.c | 26 ++++++++++++-------------- src/cfg/cfg.h | 2 +- src/cfg/cfg_int.h | 1 + src/cfg/cmds.c | 2 +- src/cfg/provider.c | 27 +++++++++++++++++++++++++-- src/cfg/provider.h | 3 ++- src/handle/dpop.c | 4 ++-- 9 files changed, 50 insertions(+), 25 deletions(-) diff --git a/ChangeLog b/ChangeLog index 0a2bea4b..4d00d6a8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,4 @@ -08/08/2024 +06/08/2024 - support DPoP nonces to the userinfo endpoint 06/07/2024 diff --git a/auth_openidc.conf b/auth_openidc.conf index ea753da5..714405de 100644 --- a/auth_openidc.conf +++ b/auth_openidc.conf @@ -315,7 +315,10 @@ # required: a DPoP token is requested from the OP and we'll fail if the returned token type is not DPoP # When not defined "off" is used. # NB: this can be overridden on a per-OP basis in the .conf file using the key: dpop_mode -#OIDCDPoPMode [ off | optional | required] +# The 2nd parameter is used to optionally enable an API for creating DPoP proofs on: +# ?dpop=&url=[&method=] +# When not defined "off" is used. +#OIDCDPoPMode [off|optional|required] [on|off] # (used only in dynamic client registration) # Define the Client JWKs URL (e.g. https://localhost/protected/?jwks=rsa)") that will be @@ -1035,11 +1038,10 @@ # timeout (int) : the session inactivity timeout (Unix timestamp in seconds) # remote_user (string) : the remote user name # session (object) : (for debugging) mod_auth_openidc specific session data such as "remote user", "session expiry", "session id" and a "state" object -# dpop : enable API for creating DPoP proofs ?dpop=&url=[&method=] # Note that when using ProxyPass / you may have to add a proxy exception for the Redirect URI # for this to work, e.g. ProxyPass /redirect_uri ! # When not defined the session hook will not return any data but a HTTP 404 -#OIDCInfoHook [iat|access_token|access_token_expires|id_token|id_token_hint|userinfo|refresh_token|exp|timeout|remote_user|session|dpop]+ +#OIDCInfoHook [iat|access_token|access_token_expires|id_token|id_token_hint|userinfo|refresh_token|exp|timeout|remote_user|session]+ # Specify metrics that you wish to collect and keep in shared memory for retrieval. # Supported metrics classes are: diff --git a/src/cfg/cfg.c b/src/cfg/cfg.c index 0d4dcaca..b562876c 100644 --- a/src/cfg/cfg.c +++ b/src/cfg/cfg.c @@ -325,19 +325,11 @@ OIDC_CFG_MEMBER_FUNC_GET(filter_claims_expr, oidc_apr_expr_t *) */ const char *oidc_cmd_info_hook_data_set(cmd_parms *cmd, void *m, const char *arg) { oidc_cfg_t *cfg = (oidc_cfg_t *)ap_get_module_config(cmd->server->module_config, &auth_openidc_module); - static const char *options[] = {OIDC_HOOK_INFO_TIMESTAMP, - OIDC_HOOK_INFO_ACCES_TOKEN, - OIDC_HOOK_INFO_ACCES_TOKEN_EXP, - OIDC_HOOK_INFO_ID_TOKEN_HINT, - OIDC_HOOK_INFO_ID_TOKEN, - OIDC_HOOK_INFO_USER_INFO, - OIDC_HOOK_INFO_REFRESH_TOKEN, - OIDC_HOOK_INFO_SESSION_EXP, - OIDC_HOOK_INFO_SESSION_TIMEOUT, - OIDC_HOOK_INFO_SESSION_REMOTE_USER, - OIDC_HOOK_INFO_SESSION, - OIDC_HOOK_INFO_DPOP, - NULL}; + static const char *options[] = { + OIDC_HOOK_INFO_TIMESTAMP, OIDC_HOOK_INFO_ACCES_TOKEN, OIDC_HOOK_INFO_ACCES_TOKEN_EXP, + OIDC_HOOK_INFO_ID_TOKEN_HINT, OIDC_HOOK_INFO_ID_TOKEN, OIDC_HOOK_INFO_USER_INFO, + OIDC_HOOK_INFO_REFRESH_TOKEN, OIDC_HOOK_INFO_SESSION_EXP, OIDC_HOOK_INFO_SESSION_TIMEOUT, + OIDC_HOOK_INFO_SESSION_REMOTE_USER, OIDC_HOOK_INFO_SESSION, NULL}; const char *rv = oidc_cfg_parse_is_valid_option(cmd->pool, arg, options); if (rv != NULL) return OIDC_CONFIG_DIR_RV(cmd, rv); @@ -381,7 +373,10 @@ const char *oidc_cmd_trace_parent_set(cmd_parms *cmd, void *struct_ptr, const ch } #define OIDC_DEFAULT_TRACE_PARENT OIDC_TRACE_PARENT_OFF -OIDC_CFG_MEMBER_FUNC_TYPE_GET(trace_parent, oidc_trace_parent_t, OIDC_TRACE_PARENT_OFF) +OIDC_CFG_MEMBER_FUNC_TYPE_GET(trace_parent, oidc_trace_parent_t, OIDC_DEFAULT_TRACE_PARENT) + +#define OIDC_DEFAULT_DPOP_API_ENABLED 0 +OIDC_CFG_MEMBER_FUNC_TYPE_GET(dpop_api_enabled, int, OIDC_DEFAULT_DPOP_API_ENABLED) const char *oidc_cmd_claim_prefix_set(cmd_parms *cmd, void *struct_ptr, const char *args) { oidc_cfg_t *cfg = (oidc_cfg_t *)ap_get_module_config(cmd->server->module_config, &auth_openidc_module); @@ -676,6 +671,7 @@ void *oidc_cfg_server_create(apr_pool_t *pool, server_rec *svr) { c->metrics_hook_data = NULL; c->metrics_path = NULL; c->trace_parent = OIDC_CONFIG_POS_INT_UNSET; + c->dpop_api_enabled = OIDC_CONFIG_POS_INT_UNSET; c->black_listed_claims = NULL; c->white_listed_claims = NULL; @@ -816,6 +812,8 @@ void *oidc_cfg_server_merge(apr_pool_t *pool, void *BASE, void *ADD) { c->metrics_hook_data = add->metrics_hook_data != NULL ? add->metrics_hook_data : base->metrics_hook_data; c->metrics_path = add->metrics_path != NULL ? add->metrics_path : base->metrics_path; c->trace_parent = add->trace_parent != OIDC_CONFIG_POS_INT_UNSET ? add->trace_parent : base->trace_parent; + c->dpop_api_enabled = + add->dpop_api_enabled != OIDC_CONFIG_POS_INT_UNSET ? add->dpop_api_enabled : base->dpop_api_enabled; c->black_listed_claims = add->black_listed_claims != NULL ? add->black_listed_claims : base->black_listed_claims; diff --git a/src/cfg/cfg.h b/src/cfg/cfg.h index 1de28c9e..245cfd69 100644 --- a/src/cfg/cfg.h +++ b/src/cfg/cfg.h @@ -129,7 +129,6 @@ typedef enum { #define OIDC_HOOK_INFO_SESSION_TIMEOUT "timeout" #define OIDC_HOOK_INFO_SESSION_REMOTE_USER "remote_user" #define OIDC_HOOK_INFO_REFRESH_TOKEN "refresh_token" -#define OIDC_HOOK_INFO_DPOP "dpop" #define OIDC_HTML_ERROR_TEMPLATE_DEPRECATED "deprecated" @@ -237,6 +236,7 @@ OIDC_CFG_MEMBER_FUNCS_DECL(redirect_urls_allowed, apr_hash_t *) OIDC_CFG_MEMBER_FUNCS_DECL(ca_bundle_path, const char *) OIDC_CFG_MEMBER_FUNCS_DECL(logout_x_frame_options, const char *) OIDC_CFG_MEMBER_FUNCS_DECL(x_forwarded_headers, oidc_hdr_x_forwarded_t) +OIDC_CFG_MEMBER_FUNCS_DECL(dpop_api_enabled, int) // 2 args OIDC_CFG_MEMBER_FUNCS_DECL(post_preserve_templates, const char *, const char *) diff --git a/src/cfg/cfg_int.h b/src/cfg/cfg_int.h index c3acf778..fa5f0810 100644 --- a/src/cfg/cfg_int.h +++ b/src/cfg/cfg_int.h @@ -189,6 +189,7 @@ struct oidc_cfg_t { apr_hash_t *metrics_hook_data; char *metrics_path; + int dpop_api_enabled; /* directory that holds the provider & client metadata files */ char *metadata_dir; diff --git a/src/cfg/cmds.c b/src/cfg/cmds.c index 42005592..d505c8fd 100644 --- a/src/cfg/cmds.c +++ b/src/cfg/cmds.c @@ -546,7 +546,7 @@ const command_rec oidc_cfg_cmds[] = { pkce, "The RFC 7636 PCKE mode used; must be one of \"plain\" or \"S256\""), OIDC_CFG_CMD_PROVIDER( - AP_INIT_TAKE1, + AP_INIT_TAKE12, OIDCDPoPMode, dpop_mode, "The RFC 9449 DPoP mode used; must be one of \"off\", \"optional\" or \"required\""), diff --git a/src/cfg/provider.c b/src/cfg/provider.c index f45e452d..85dfbe74 100644 --- a/src/cfg/provider.c +++ b/src/cfg/provider.c @@ -279,8 +279,31 @@ static const char *oidc_cfg_provider_parse_dop_method(apr_pool_t *pool, const ch } #define OIDC_DEFAULT_DPOP_MODE OIDC_DPOP_MODE_OFF -OIDC_PROVIDER_MEMBER_FUNCS_STR_INT(dpop_mode, oidc_cfg_provider_parse_dop_method, oidc_dpop_mode_t, - OIDC_DEFAULT_DPOP_MODE) + +OIDC_PROVIDER_MEMBER_GET_INT_DEF(dpop_mode, oidc_dpop_mode_t, OIDC_DEFAULT_DPOP_MODE) + +void oidc_cfg_provider_dpop_mode_int_set(oidc_provider_t *provider, oidc_dpop_mode_t arg) { + provider->dpop_mode = arg; +} + +const char *oidc_cfg_provider_dpop_mode_set(apr_pool_t *pool, oidc_provider_t *provider, const char *arg) { + const char *rv = NULL; + oidc_dpop_mode_t v; + rv = oidc_cfg_provider_parse_dop_method(pool, arg, &v); + if (rv == NULL) + provider->dpop_mode = v; + else + provider->dpop_mode = OIDC_DEFAULT_DPOP_MODE; + return rv; +} + +const char *oidc_cmd_provider_dpop_mode_set(cmd_parms *cmd, void *ptr, const char *arg1, const char *arg2) { + oidc_cfg_t *cfg = (oidc_cfg_t *)ap_get_module_config(cmd->server->module_config, &auth_openidc_module); + const char *rv = oidc_cfg_provider_dpop_mode_set(cmd->pool, cfg->provider, arg1); + if ((rv == NULL) && (arg2)) + rv = oidc_cfg_parse_boolean(cmd->pool, arg2, &cfg->dpop_api_enabled); + return OIDC_CONFIG_DIR_RV(cmd, rv); +} OIDC_PROVIDER_MEMBER_FUNCS_STR(issuer, NULL) OIDC_PROVIDER_MEMBER_FUNCS_URL(authorization_endpoint_url) diff --git a/src/cfg/provider.h b/src/cfg/provider.h index 1b0f624f..fe5653ba 100644 --- a/src/cfg/provider.h +++ b/src/cfg/provider.h @@ -226,11 +226,12 @@ OIDC_CFG_PROVIDER_MEMBER_FUNCS_INT_DECL(session_max_duration) OIDC_CFG_PROVIDER_MEMBER_FUNCS_INT_DECL(response_require_iss) // ints with 2 args OIDC_CFG_PROVIDER_MEMBER_FUNCS_INT_DECL(userinfo_refresh_interval, const char *) +OIDC_CFG_PROVIDER_MEMBER_FUNCS_TYPE_DECL(dpop_mode, oidc_dpop_mode_t, const char *) +void OIDC_CFG_MEMBER_FUNC_NAME(dpop_mode, cfg_provider, int_set)(oidc_provider_t *provider, oidc_dpop_mode_t arg); // for metadata.c OIDC_CFG_PROVIDER_MEMBER_FUNCS_INT_INT_DECL(userinfo_token_method, oidc_userinfo_token_method_t) OIDC_CFG_PROVIDER_MEMBER_FUNCS_INT_INT_DECL(auth_request_method, oidc_auth_request_method_t) -OIDC_CFG_PROVIDER_MEMBER_FUNCS_INT_INT_DECL(dpop_mode, oidc_dpop_mode_t) // types OIDC_CFG_PROVIDER_MEMBER_FUNCS_TYPE_DECL(pkce, const oidc_proto_pkce_t *) diff --git a/src/handle/dpop.c b/src/handle/dpop.c index 3953a87d..9f63bf60 100644 --- a/src/handle/dpop.c +++ b/src/handle/dpop.c @@ -68,8 +68,8 @@ int oidc_dpop_request(request_rec *r, oidc_cfg_t *c) { remote_ip = r->connection->remote_ip; #endif - if (apr_hash_get(oidc_cfg_info_hook_data_get(c), OIDC_HOOK_INFO_DPOP, APR_HASH_KEY_STRING) == NULL) { - oidc_error(r, "DPoP hook called but \"dpop\" is not enabled in %s", OIDCInfoHook); + if (!oidc_cfg_dpop_api_enabled_get(c)) { + oidc_error(r, "DPoP hook called but the DPoP API is not enabled in %s", OIDCDPoPMode); goto end; }