Skip to content

Commit

Permalink
explicitly enable DPoP API through OIDCInfoHook; don't require a session
Browse files Browse the repository at this point in the history
Signed-off-by: Hans Zandbelt <[email protected]>
  • Loading branch information
zandbelt committed Jun 12, 2024
1 parent 5b618fb commit c5ef5fd
Show file tree
Hide file tree
Showing 7 changed files with 27 additions and 49 deletions.
5 changes: 3 additions & 2 deletions auth_openidc.conf
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 <redirect_uri>?dpop=<access_token>&url=<url>[&method=<method][&nonce=<nonce>]
# 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:
Expand Down
18 changes: 13 additions & 5 deletions src/cfg/cfg.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
1 change: 1 addition & 0 deletions src/cfg/cfg.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down
14 changes: 2 additions & 12 deletions src/handle/content.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)) {

Expand Down
27 changes: 6 additions & 21 deletions src/handle/dpop.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)) {
Expand Down Expand Up @@ -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)) {
Expand Down
2 changes: 1 addition & 1 deletion src/handle/handle.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
9 changes: 1 addition & 8 deletions src/mod_auth_openidc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down

0 comments on commit c5ef5fd

Please sign in to comment.