From c5ef5fda60f1814e56ef1772b5277278cdca6a88 Mon Sep 17 00:00:00 2001 From: Hans Zandbelt Date: Wed, 12 Jun 2024 08:28:51 +0200 Subject: [PATCH] explicitly enable DPoP API through OIDCInfoHook; don't require a session Signed-off-by: Hans Zandbelt --- auth_openidc.conf | 5 +++-- src/cfg/cfg.c | 18 +++++++++++++----- src/cfg/cfg.h | 1 + src/handle/content.c | 14 ++------------ src/handle/dpop.c | 27 ++++++--------------------- src/handle/handle.h | 2 +- src/mod_auth_openidc.c | 9 +-------- 7 files changed, 27 insertions(+), 49 deletions(-) diff --git a/auth_openidc.conf b/auth_openidc.conf index b76f7337..ea753da5 100644 --- a/auth_openidc.conf +++ b/auth_openidc.conf @@ -309,7 +309,7 @@ # NB: this can be overridden on a per-OP basis in the .conf file using the key: pkce_method #OIDCPKCEMethod [ S256 | plain | |none ] -# The DPoP mode used (this serves as default value for multi-provider OPs too) +# The DPoP mode used (this serves as default value for multi-provider OPs too) # off: no DPoP token is requested from the OP # optional: a DPoP token is requested from the OP but we'll continue even if the returned token is Bearer # required: a DPoP token is requested from the OP and we'll fail if the returned token type is not DPoP @@ -1035,10 +1035,11 @@ # 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]+ +#OIDCInfoHook [iat|access_token|access_token_expires|id_token|id_token_hint|userinfo|refresh_token|exp|timeout|remote_user|session|dpop]+ # 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 eb761a43..0d4dcaca 100644 --- a/src/cfg/cfg.c +++ b/src/cfg/cfg.c @@ -325,11 +325,19 @@ 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, 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, + OIDC_HOOK_INFO_DPOP, + NULL}; const char *rv = oidc_cfg_parse_is_valid_option(cmd->pool, arg, options); if (rv != NULL) return OIDC_CONFIG_DIR_RV(cmd, rv); diff --git a/src/cfg/cfg.h b/src/cfg/cfg.h index 62ee334e..1de28c9e 100644 --- a/src/cfg/cfg.h +++ b/src/cfg/cfg.h @@ -129,6 +129,7 @@ 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" diff --git a/src/handle/content.c b/src/handle/content.c index fb0419b4..4a6ff013 100644 --- a/src/handle/content.c +++ b/src/handle/content.c @@ -96,18 +96,8 @@ int oidc_content_handler(request_rec *r) { OIDC_METRICS_COUNTER_INC(r, c, OM_CONTENT_REQUEST_DPOP); - /* see if a session was retained in the request state */ - apr_pool_userdata_get((void **)&session, OIDC_USERDATA_SESSION, r->pool); - - /* if no retained session was found, load it from the cache or create a new one*/ - if (session != NULL) - /* handle request to create a DPoP proof */ - rc = oidc_dpop_request(r, c, session); - else - rc = HTTP_UNAUTHORIZED; - - /* free resources allocated for the session */ - oidc_session_free(r, session); + /* handle request to create a DPoP proof */ + rc = oidc_dpop_request(r, c); } else if (oidc_util_request_has_parameter(r, OIDC_REDIRECT_URI_REQUEST_JWKS)) { diff --git a/src/handle/dpop.c b/src/handle/dpop.c index 1c8b2e27..e0d2b978 100644 --- a/src/handle/dpop.c +++ b/src/handle/dpop.c @@ -49,17 +49,21 @@ #define OIDC_DPOP_PARAM_NONCE "nonce" #define OIDC_DPOP_PARAM_METHOD "method" -int oidc_dpop_request(request_rec *r, oidc_cfg_t *c, oidc_session_t *session) { +int oidc_dpop_request(request_rec *r, oidc_cfg_t *c) { int rc = HTTP_BAD_REQUEST; char *s_url = NULL; char *s_access_token = NULL; char *s_nonce = NULL; - const char *session_access_token = NULL; char *s_method = NULL; char *s_dpop = NULL; char *s_response = NULL; json_t *json = NULL; + 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); + goto end; + } + /* try to make sure that the proof-of-possession semantics are preserved */ if ((_oidc_strnatcasecmp(r->useragent_ip, r->connection->local_ip) != 0) && (apr_table_get(r->subprocess_env, "OIDC_DPOP_API_INSECURE") == 0)) { @@ -99,25 +103,6 @@ int oidc_dpop_request(request_rec *r, oidc_cfg_t *c, oidc_session_t *session) { else if ((_oidc_strnatcasecmp(s_method, "get") == 0) || (s_method == NULL)) s_method = "GET"; - /* check that we actually have a user session and this is someone calling with a proper session cookie */ - if (session->remote_user == NULL) { - oidc_warn(r, "no user session found"); - rc = HTTP_UNAUTHORIZED; - goto end; - } - - session_access_token = oidc_session_get_access_token(r, session); - if (session_access_token == NULL) { - oidc_error(r, "no \"access_token\" was found in the session"); - goto end; - } - - if (_oidc_strcmp(s_access_token, session_access_token) != 0) { - oidc_error(r, "the provided \"access_token\" parameter is not matching the current access token stored " - "in the user session"); - goto end; - } - /* create the DPoP header value */ if ((oidc_proto_dpop_create(r, c, s_url, s_method, s_access_token, s_nonce, &s_dpop) == FALSE) || (s_dpop == NULL)) { diff --git a/src/handle/handle.h b/src/handle/handle.h index 90bcdfc9..f20c2002 100644 --- a/src/handle/handle.h +++ b/src/handle/handle.h @@ -80,7 +80,7 @@ apr_byte_t oidc_is_discovery_response(request_rec *r, oidc_cfg_t *cfg); int oidc_discovery_response(request_rec *r, oidc_cfg_t *c); // dpop.c -int oidc_dpop_request(request_rec *r, oidc_cfg_t *c, oidc_session_t *session); +int oidc_dpop_request(request_rec *r, oidc_cfg_t *c); // info.c int oidc_info_request(request_rec *r, oidc_cfg_t *c, oidc_session_t *session, apr_byte_t needs_save); diff --git a/src/mod_auth_openidc.c b/src/mod_auth_openidc.c index 7aec67ef..27336348 100644 --- a/src/mod_auth_openidc.c +++ b/src/mod_auth_openidc.c @@ -1441,16 +1441,9 @@ int oidc_handle_redirect_uri_request(request_rec *r, oidc_cfg_t *c, oidc_session } else if (oidc_util_request_has_parameter(r, OIDC_REDIRECT_URI_REQUEST_DPOP)) { - if (session->remote_user == NULL) - return HTTP_UNAUTHORIZED; - OIDC_METRICS_COUNTER_INC(r, c, OM_REDIRECT_URI_REQUEST_DPOP); - r->user = session->remote_user; - - // retain this session across the authentication and content handler phases - // by storing it in the request state - apr_pool_userdata_set(session, OIDC_USERDATA_SESSION, NULL, r->pool); + r->user = ""; return OK;