Commit e03d05fa authored by Christoph Martin's avatar Christoph Martin

New upstream version 2.3.2

parent 31d78a71
......@@ -36,3 +36,5 @@ reporting bugs, providing fixes, suggesting useful features or other:
Wouter Hund <https://github.com/wouterhund>
Hans Keeler <https://github.com/hkeeler>
Moritz Schlarb <https://github.com/moschlar>
remi-cc <https://github.com/remi-cc>
hihellobolke <https://github.com/hihellobolke>
09/18/2017
- release 2.3.2
09/11/2017
- fix "graceful" restart for shm/redis cache backends; see #296
- bump to 2.3.2rc8
09/05/2017
- optionally remove request object parameters from the authorization request URL with "copy_and_remove_from_request"; see #294
- bump to 2.3.2rc7
08/29/2017
- properly support JSON boolean values in metadata .conf files
- add regex substitution for *RemoteUserClaim; thanks @hihellobolke
- bump to 2.3.2rc6
08/27/2017
- add issuer specific redirect URI option ("issuer_specific_redirect_uri") for multi-provider setups to mitigate IDP mixup
- bump to 2.3.2rc5
08/20/2017
- fix public clients; add endpoint authentication method "none"
- bump to 2.3.2rc4
08/02/2017
- update experimental token binding support to https://tools.ietf.org/html/draft-ietf-tokbind-ttrp-01
and use header names prefixed with "Sec-"; depends on mod_token_binding >= 0.3.4 now
- bump to 2.3.2rc3
08/01/2017
- don't abort when mutex operations fail
- printout textual descriptions of errors returned by mutex operations
- bump to 2.3.2rc2
07/28/2017
- fix issue with the combination of shared memory (shm) cache and using encryption (OIDCCacheEncrypt On)
where the cache value would be corrupted after the first (successful) retrieval
- bump to 2.3.2rc1
07/27/2017
- support paths that are relative to the Apache root dir for:
OIDCHTMLErrorTemplate, OIDCPublicKeyFiles, OIDCPrivateKeyFiles,
OIDCOAuthVerifyCertFiles, OIDCClientTokenEndpointCert, OIDCClientTokenEndpointKey,
OIDCOAuthIntrospectionEndpointCert and OIDCOAuthIntrospectionEndpointKey
- bump to 2.3.2rc0
07/19/2017
- handle multiple values in X-Forwarded-* headers as to better support chains of reverse proxies in front of mod_auth_openidc
- log request headers in oidc_util_hdr_in_get
......
......@@ -32,6 +32,10 @@ make install
Note that, depending on your distribution, apxs2 may be named apxs.
FreeBSD users can use one of the following two options to install mod_auth_openidc:
- To install the port: cd /usr/ports/www/mod_auth_openidc/ && make install clean
- To add the package: pkg install ap24-mod_auth_openidc
Configuration
=============
......
......@@ -12,7 +12,8 @@ SRC=src/mod_auth_openidc.c \
src/session.c \
src/metadata.c \
src/jose.c \
src/parse.c
src/parse.c \
src/pcre_subst.c \
ifeq (@HAVE_LIBHIREDIS@, 1)
SRC += \
......@@ -31,7 +32,8 @@ HDRS = \
src/mod_auth_openidc.h \
src/jose.h \
src/parse.h \
src/cache/cache.h
src/cache/cache.h \
src/pcre_subst.h \
# Files to include when making a .tar.gz-file for distribution
DISTFILES=$(SRC) \
......
This diff is collapsed.
......@@ -365,6 +365,11 @@
# An optional regular expression can be added as a 2nd parameter that will be applied to the
# claim value from the 1st parameter and the first match returned from that expression will
# be set as the REMOTE_USER. E.g. to strip a domain from an e-mail style address you'd use ^(.*)@
#
# An optional 3rd parameter can be added that would contain string with number backrefrences.
# Backrefrences must be in the form $1, $2.. etc.
# E.g. to extract username in the form DOMAIN\userid from e-mail style address you may use
# ^(.*)@([^.]+)\..+$ $2\\$1
#OIDCOAuthRemoteUserClaim <claim-name> [<regular-expression>]
# Define the way(s) in which bearer OAuth 2.0 access tokens can be passed to this Resource Server.
......@@ -616,6 +621,11 @@
# An optional regular expression can be added as a 2nd parameter that will be applied to the
# resulting value from the 1st parameter and the first match returned from that expression will
# be set as the REMOTE_USER. E.g. to strip a domain from an e-mail style address you'd use ^(.*)@
#
# An optional 3rd parameter can be added that would contain string with number backrefrences.
# Backrefrences must be in the form $1, $2.. etc.
# E.g. to extract username in the form DOMAIN\userid from e-mail style address you may use
# ^(.*)@([^.]+)\..+$ $2\\$1
#OIDCRemoteUserClaim <claim-name>[@] [<regular-expression>]
# Define the way(s) in which the id_token contents are passed to the application according to OIDCPassClaimsAs.
......@@ -691,20 +701,21 @@
# Can be configured on a per Directory/Location basis. The default is "Off".
#OIDCPassRefreshToken [On|Off]
# Request Object/URI settings. For example:
# Request Object/URI settings expressed as a string that is a "double-quote-escaped" JSON object. For example:
# "{ \"copy_from_request\": [ \"claims\", \"response_type\", \"response_mode\", \"login_hint\", \"id_token_hint\", \"nonce\", \"state\", \"redirect_uri\", \"scope\", \"client_id\" ], \"static\": { \"some\": \"value\", \"some_nested\": { \"some_array\": [ 1,2,3] } }, \"crypto\": { \"sign_alg\": \"HS256\", \"crypt_alg\": \"A256KW\", \"crypt_enc\": \"A256CBC-HS512\" }, \"url\": \"https://www.pingidentity.nl/protected/\", \"request_object_type\" : \"request\" }"
# Parameters:
# copy_from_request (array) : array of parameters copied from request
# static (object) : parameter value is merged to the request object
# crypto (object) : defines cryptography used to create request object
# sign_alg (string) : algorithm used to sign request object (JWS alg parameter)
# crypt_alg (string) : algorithm used to encrypt CEK of request object (JWE alg parameter)
# crypt_enc (string) : algorithm used to encrypt request object (JWE enc parameter)
# url (string) : use this url instead of redirect_uri for request_uri
# request_object_type (string) : parameter used for sending authorization request object
# "request_uri" (default) or "request"
# copy_from_request (array) : array of query parameter names copied from request
# copy_and_remove_from_request (array) : array of parameter names copied from request and removed as query parameter
# static (object) : parameter value is merged to the request object
# crypto (object) : defines cryptography used to create request object
# sign_alg (string) : algorithm used to sign request object (JWS alg parameter)
# crypt_alg (string) : algorithm used to encrypt CEK of request object (JWE alg parameter)
# crypt_enc (string) : algorithm used to encrypt request object (JWE enc parameter)
# url (string) : use this url instead of redirect_uri for request_uri
# request_object_type (string) : parameter used for sending authorization request object
# "request_uri" (default) or "request"
# NB: this can be overridden on a per-OP basis in the .conf file using the key: request_object
#OIDCRequestObject <stringified-JSON-object>
#OIDCRequestObject <stringified-and-double-quote-escaped-JSON-object>
# Provider metadata refresh interval for the metadata in a multi-provider setup (with OIDCMetadataDir).
# When not defined the default is 0 seconds, i.e. it is never refreshed.
......
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.69 for mod_auth_openidc 2.3.1.
# Generated by GNU Autoconf 2.69 for mod_auth_openidc 2.3.2.
#
# Report bugs to <hans.zandbelt@zmartzone.eu>.
#
......@@ -580,8 +580,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='mod_auth_openidc'
PACKAGE_TARNAME='mod_auth_openidc'
PACKAGE_VERSION='2.3.1'
PACKAGE_STRING='mod_auth_openidc 2.3.1'
PACKAGE_VERSION='2.3.2'
PACKAGE_STRING='mod_auth_openidc 2.3.2'
PACKAGE_BUGREPORT='hans.zandbelt@zmartzone.eu'
PACKAGE_URL=''
......@@ -1269,7 +1269,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
\`configure' configures mod_auth_openidc 2.3.1 to adapt to many kinds of systems.
\`configure' configures mod_auth_openidc 2.3.2 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
......@@ -1331,7 +1331,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
short | recursive ) echo "Configuration of mod_auth_openidc 2.3.1:";;
short | recursive ) echo "Configuration of mod_auth_openidc 2.3.2:";;
esac
cat <<\_ACEOF
......@@ -1445,7 +1445,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
mod_auth_openidc configure 2.3.1
mod_auth_openidc configure 2.3.2
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
......@@ -1747,7 +1747,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
It was created by mod_auth_openidc $as_me 2.3.1, which was
It was created by mod_auth_openidc $as_me 2.3.2, which was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
......@@ -2096,7 +2096,7 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
NAMEVER=mod_auth_openidc-2.3.1
NAMEVER=mod_auth_openidc-2.3.2
# This section defines the --with-apxs2 option.
......@@ -4886,7 +4886,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
This file was extended by mod_auth_openidc $as_me 2.3.1, which was
This file was extended by mod_auth_openidc $as_me 2.3.2, which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
......@@ -4939,7 +4939,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
mod_auth_openidc config.status 2.3.1
mod_auth_openidc config.status 2.3.2
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"
......
AC_INIT([mod_auth_openidc],[2.3.1],[hans.zandbelt@zmartzone.eu])
AC_INIT([mod_auth_openidc],[2.3.2],[hans.zandbelt@zmartzone.eu])
AC_SUBST(NAMEVER, AC_PACKAGE_TARNAME()-AC_PACKAGE_VERSION())
......
......@@ -54,6 +54,7 @@
#define _MOD_AUTH_OPENIDC_CACHE_H_
#include "apr_global_mutex.h"
#include "apr_shm.h"
typedef void * (*oidc_cache_cfg_create)(apr_pool_t *pool);
typedef int (*oidc_cache_post_config_function)(server_rec *s);
......@@ -78,6 +79,8 @@ typedef struct oidc_cache_t {
typedef struct oidc_cache_mutex_t {
apr_global_mutex_t *mutex;
char *mutex_filename;
apr_shm_t *shm;
int *sema;
} oidc_cache_mutex_t;
oidc_cache_mutex_t *oidc_cache_mutex_create(apr_pool_t *pool);
......
......@@ -79,9 +79,21 @@ oidc_cache_mutex_t *oidc_cache_mutex_create(apr_pool_t *pool) {
oidc_cache_mutex_t *ctx = apr_pcalloc(pool, sizeof(oidc_cache_mutex_t));
ctx->mutex = NULL;
ctx->mutex_filename = NULL;
ctx->shm = NULL;
ctx->sema = NULL;
return ctx;
}
#define OIDC_CACHE_ERROR_STR_MAX 255
/*
* convert a apr status code to a string
*/
char *oidc_cache_status2str(apr_status_t statcode) {
char buf[OIDC_CACHE_ERROR_STR_MAX];
return apr_strerror(statcode, buf, OIDC_CACHE_ERROR_STR_MAX);
}
apr_byte_t oidc_cache_mutex_post_config(server_rec *s, oidc_cache_mutex_t *m,
const char *type) {
......@@ -99,8 +111,8 @@ apr_byte_t oidc_cache_mutex_post_config(server_rec *s, oidc_cache_mutex_t *m,
APR_LOCK_DEFAULT, s->process->pool);
if (rv != APR_SUCCESS) {
oidc_serror(s,
"apr_global_mutex_create failed to create mutex on file %s",
m->mutex_filename);
"apr_global_mutex_create failed to create mutex on file %s: %s (%d)",
m->mutex_filename, oidc_cache_status2str(rv), rv);
return FALSE;
}
......@@ -113,11 +125,21 @@ apr_byte_t oidc_cache_mutex_post_config(server_rec *s, oidc_cache_mutex_t *m,
#endif
if (rv != APR_SUCCESS) {
oidc_serror(s,
"unixd_set_global_mutex_perms failed; could not set permissions ");
"unixd_set_global_mutex_perms failed; could not set permissions: %s (%d)",
oidc_cache_status2str(rv), rv);
return FALSE;
}
#endif
rv = apr_shm_create(&m->shm, sizeof(int), NULL, s->process->pool);
if (rv != APR_SUCCESS) {
oidc_serror(s, "apr_shm_create failed to create shared memory segment");
return FALSE;
}
m->sema = apr_shm_baseaddr_get(m->shm);
*m->sema = 1;
return TRUE;
}
......@@ -133,10 +155,17 @@ apr_status_t oidc_cache_mutex_child_init(apr_pool_t *p, server_rec *s,
if (rv != APR_SUCCESS) {
oidc_serror(s,
"apr_global_mutex_child_init failed to reopen mutex on file %s",
m->mutex_filename);
"apr_global_mutex_child_init failed to reopen mutex on file %s: %s (%d)",
m->mutex_filename, oidc_cache_status2str(rv), rv);
} else {
apr_global_mutex_lock(m->mutex);
m->sema = apr_shm_baseaddr_get(m->shm);
(*m->sema)++;
apr_global_mutex_unlock(m->mutex);
}
//oidc_sdebug(s, "semaphore: %d (m=%pp,s=%pp)", *m->sema, m, s);
return rv;
}
......@@ -147,10 +176,9 @@ apr_byte_t oidc_cache_mutex_lock(request_rec *r, oidc_cache_mutex_t *m) {
apr_status_t rv = apr_global_mutex_lock(m->mutex);
if (rv != APR_SUCCESS) {
oidc_error(r, "apr_global_mutex_lock() failed [%d]", rv);
return FALSE;
}
if (rv != APR_SUCCESS)
oidc_error(r, "apr_global_mutex_lock() failed: %s (%d)",
oidc_cache_status2str(rv), rv);
return TRUE;
}
......@@ -162,10 +190,9 @@ apr_byte_t oidc_cache_mutex_unlock(request_rec *r, oidc_cache_mutex_t *m) {
apr_status_t rv = apr_global_mutex_unlock(m->mutex);
if (rv != APR_SUCCESS) {
oidc_error(r, "apr_global_mutex_unlock() failed [%d]", rv);
return FALSE;
}
if (rv != APR_SUCCESS)
oidc_error(r, "apr_global_mutex_unlock() failed: %s (%d)",
oidc_cache_status2str(rv), rv);
return TRUE;
}
......@@ -178,11 +205,24 @@ apr_byte_t oidc_cache_mutex_destroy(server_rec *s, oidc_cache_mutex_t *m) {
apr_status_t rv = APR_SUCCESS;
if (m->mutex != NULL) {
rv = apr_global_mutex_destroy(m->mutex);
if (rv != APR_SUCCESS) {
oidc_swarn(s, "apr_global_mutex_destroy failed: [%d]", rv);
apr_global_mutex_lock(m->mutex);
(*m->sema)--;
//oidc_sdebug(s, "semaphore: %d (m=%pp,s=%pp)", *m->sema, m->mutex, s);
apr_global_mutex_unlock(m->mutex);
if ((m->shm != NULL) && (*m->sema == 0)) {
rv = apr_global_mutex_destroy(m->mutex);
oidc_sdebug(s, "apr_global_mutex_destroy returned :%d", rv);
m->mutex = NULL;
rv = apr_shm_destroy(m->shm);
oidc_sdebug(s, "apr_shm_destroy for semaphore returned: %d", rv);
m->shm = NULL;
rv = APR_SUCCESS;
}
m->mutex = NULL;
}
return rv;
......@@ -429,9 +469,15 @@ static int oidc_cache_crypto_decrypt(request_rec *r, const char *cache_value,
/* grab the base64url-encoded tag after the "." */
char *encoded_tag = strstr(cache_value, ".");
if (encoded_tag == NULL)
if (encoded_tag == NULL) {
oidc_error(r,
"corrupted cache value: no tag separator found in encrypted value");
return FALSE;
*encoded_tag = '\0';
}
/* make sure we don't modify the original string since it may be just a pointer into the cache (shm) */
cache_value = apr_pstrmemdup(r->pool, cache_value,
strlen(cache_value) - strlen(encoded_tag));
encoded_tag++;
/* base64url decode the ciphertext */
......@@ -496,8 +542,8 @@ static char *oidc_cache_get_hashed_key(request_rec *r, const char *passphrase,
const char *key) {
char *input = apr_psprintf(r->pool, "%s:%s", passphrase, key);
char *output = NULL;
if (oidc_util_hash_string_and_base64url_encode(r, OIDC_JOSE_ALG_SHA256, input,
&output) == FALSE) {
if (oidc_util_hash_string_and_base64url_encode(r, OIDC_JOSE_ALG_SHA256,
input, &output) == FALSE) {
oidc_error(r,
"oidc_util_hash_string_and_base64url_encode returned an error");
return NULL;
......
......@@ -331,9 +331,13 @@ static int oidc_cache_shm_destroy(server_rec *s) {
apr_status_t rv = APR_SUCCESS;
if (context->shm) {
rv = apr_shm_destroy(context->shm);
oidc_sdebug(s, "apr_shm_destroy returned: %d", rv);
apr_global_mutex_lock(context->mutex->mutex);
if (*context->mutex->sema == 1) {
rv = apr_shm_destroy(context->shm);
oidc_sdebug(s, "apr_shm_destroy returned: %d", rv);
}
context->shm = NULL;
apr_global_mutex_unlock(context->mutex->mutex);
}
oidc_cache_mutex_destroy(s, context->mutex);
......
......@@ -159,6 +159,8 @@
#define OIDC_DEFAULT_PROVIDER_TOKEN_BINDING_POLICY OIDC_TOKEN_BINDING_POLICY_OPTIONAL
/* define the default HTTP method used to send the authentication request to the provider */
#define OIDC_DEFAULT_AUTH_REQUEST_METHOD OIDC_AUTH_REQUEST_METHOD_GET
/* define whether the issuer will be added to the redirect uri by default to mitigate the IDP mixup attack */
#define OIDC_DEFAULT_PROVIDER_ISSUER_SPECIFIC_REDIRECT_URI 0
#define OIDCProviderMetadataURL "OIDCProviderMetadataURL"
#define OIDCProviderIssuer "OIDCProviderIssuer"
......@@ -621,6 +623,8 @@ static const char *oidc_set_public_key_files(cmd_parms *cmd, void *struct_ptr,
if (rv != NULL)
return rv;
fname = oidc_util_get_full_path(cmd->pool, fname);
if (oidc_jwk_parse_rsa_public_key(cmd->pool, kid, fname, &jwk,
&err) == FALSE) {
return apr_psprintf(cmd->pool,
......@@ -688,6 +692,8 @@ static const char *oidc_set_private_key_files_enc(cmd_parms *cmd, void *dummy,
if (rv != NULL)
return rv;
fname = oidc_util_get_full_path(cmd->pool, fname);
if (oidc_jwk_parse_rsa_private_key(cmd->pool, kid, fname, &jwk,
&err) == FALSE) {
return apr_psprintf(cmd->pool,
......@@ -799,7 +805,7 @@ static const char *oidc_set_preserve_post(cmd_parms *cmd, void *m,
* set the remote user name claims, optionally plus the regular expression applied to it
*/
static const char *oidc_set_remote_user_claim(cmd_parms *cmd, void *struct_ptr,
const char *v1, const char *v2) {
const char *v1, const char *v2, const char *v3) {
oidc_cfg *cfg = (oidc_cfg *) ap_get_module_config(
cmd->server->module_config, &auth_openidc_module);
......@@ -810,6 +816,8 @@ static const char *oidc_set_remote_user_claim(cmd_parms *cmd, void *struct_ptr,
remote_user_claim->claim_name = v1;
if (v2)
remote_user_claim->reg_exp = v2;
if (v3)
remote_user_claim->replace = v3;
return NULL;
}
......@@ -1033,6 +1041,7 @@ void *oidc_create_server_config(apr_pool_t *pool, server_rec *svr) {
c->oauth.remote_user_claim.claim_name =
OIDC_DEFAULT_OAUTH_CLAIM_REMOTE_USER;
c->oauth.remote_user_claim.reg_exp = NULL;
c->oauth.remote_user_claim.replace = NULL;
c->oauth.verify_jwks_uri = NULL;
c->oauth.verify_public_keys = NULL;
......@@ -1069,6 +1078,7 @@ void *oidc_create_server_config(apr_pool_t *pool, server_rec *svr) {
c->claim_prefix = NULL;
c->remote_user_claim.claim_name = OIDC_DEFAULT_CLAIM_REMOTE_USER;
c->remote_user_claim.reg_exp = NULL;
c->remote_user_claim.replace = NULL;
c->pass_idtoken_as = OIDC_PASS_IDTOKEN_AS_CLAIMS;
c->cookie_http_only = OIDC_DEFAULT_COOKIE_HTTPONLY;
c->cookie_same_site = OIDC_DEFAULT_COOKIE_SAME_SITE;
......@@ -1093,6 +1103,9 @@ void *oidc_create_server_config(apr_pool_t *pool, server_rec *svr) {
c->black_listed_claims = NULL;
c->white_listed_claims = NULL;
c->provider.issuer_specific_redirect_uri =
OIDC_DEFAULT_PROVIDER_ISSUER_SPECIFIC_REDIRECT_URI;
return c;
}
......@@ -1338,6 +1351,10 @@ void *oidc_merge_server_config(apr_pool_t *pool, void *BASE, void *ADD) {
add->oauth.remote_user_claim.reg_exp != NULL ?
add->oauth.remote_user_claim.reg_exp :
base->oauth.remote_user_claim.reg_exp;
c->oauth.remote_user_claim.replace =
add->oauth.remote_user_claim.replace != NULL ?
add->oauth.remote_user_claim.replace :
base->oauth.remote_user_claim.replace;
c->oauth.verify_jwks_uri =
add->oauth.verify_jwks_uri != NULL ?
......@@ -1444,6 +1461,10 @@ void *oidc_merge_server_config(apr_pool_t *pool, void *BASE, void *ADD) {
add->remote_user_claim.reg_exp != NULL ?
add->remote_user_claim.reg_exp :
base->remote_user_claim.reg_exp;
c->remote_user_claim.replace =
add->remote_user_claim.replace != NULL ?
add->remote_user_claim.replace :
base->remote_user_claim.replace;
c->pass_idtoken_as =
add->pass_idtoken_as != OIDC_PASS_IDTOKEN_AS_CLAIMS ?
add->pass_idtoken_as : base->pass_idtoken_as;
......@@ -1502,6 +1523,12 @@ void *oidc_merge_server_config(apr_pool_t *pool, void *BASE, void *ADD) {
add->white_listed_claims != NULL ?
add->white_listed_claims : base->white_listed_claims;
c->provider.issuer_specific_redirect_uri =
add->provider.issuer_specific_redirect_uri
!= OIDC_DEFAULT_PROVIDER_ISSUER_SPECIFIC_REDIRECT_URI ?
add->provider.issuer_specific_redirect_uri :
base->provider.issuer_specific_redirect_uri;
return c;
}
......@@ -1945,8 +1972,7 @@ static void oidc_ssl_id_callback(CRYPTO_THREADID *id) {
#endif /* defined(OPENSSL_THREADS) && APR_HAS_THREADS */
static apr_status_t oidc_cleanup(void *data) {
static apr_status_t oidc_cleanup_child(void *data) {
server_rec *sp = (server_rec *) data;
while (sp != NULL) {
oidc_cfg *cfg = (oidc_cfg *) ap_get_module_config(sp->module_config,
......@@ -1967,6 +1993,13 @@ static apr_status_t oidc_cleanup(void *data) {
sp = sp->next;
}
return APR_SUCCESS;
}
static apr_status_t oidc_cleanup_parent(void *data) {
oidc_cleanup_child(data);
#if (defined (OPENSSL_THREADS) && APR_HAS_THREADS)
if (CRYPTO_get_locking_callback() == oidc_ssl_locking_callback)
CRYPTO_set_locking_callback(NULL);
......@@ -2054,7 +2087,7 @@ static int oidc_post_config(apr_pool_t *pool, apr_pool_t *p1, apr_pool_t *p2,
}
#endif /* OPENSSL_NO_THREADID */
#endif /* defined(OPENSSL_THREADS) && APR_HAS_THREADS */
apr_pool_cleanup_register(pool, s, oidc_cleanup, apr_pool_cleanup_null);
apr_pool_cleanup_register(pool, s, oidc_cleanup_parent, apr_pool_cleanup_null);
server_rec *sp = s;
while (sp != NULL) {
......@@ -2105,16 +2138,18 @@ static const authz_provider oidc_authz_claims_expr_provider = {
* initialize cache context in child process if required
*/
static void oidc_child_init(apr_pool_t *p, server_rec *s) {
while (s != NULL) {
oidc_cfg *cfg = (oidc_cfg *) ap_get_module_config(s->module_config,
server_rec *sp = s;
while (sp != NULL) {
oidc_cfg *cfg = (oidc_cfg *) ap_get_module_config(sp->module_config,
&auth_openidc_module);
if (cfg->cache->child_init != NULL) {
if (cfg->cache->child_init(p, s) != APR_SUCCESS) {
oidc_serror(s, "cfg->cache->child_init failed");
if (cfg->cache->child_init(p, sp) != APR_SUCCESS) {
oidc_serror(sp, "cfg->cache->child_init failed");
}
}
s = s->next;
sp = sp->next;
}
apr_pool_cleanup_register(p, s, oidc_cleanup_child, apr_pool_cleanup_null);
}
/*
......@@ -2416,7 +2451,7 @@ const command_rec oidc_config_cmds[] = {
(void*)APR_OFFSETOF(oidc_cfg, claim_prefix),
RSRC_CONF,
"The prefix to use when setting claims in the HTTP headers."),
AP_INIT_TAKE12(OIDCRemoteUserClaim,
AP_INIT_TAKE123(OIDCRemoteUserClaim,
oidc_set_remote_user_claim,
(void*)APR_OFFSETOF(oidc_cfg, remote_user_claim),
RSRC_CONF,
......@@ -2485,7 +2520,7 @@ const command_rec oidc_config_cmds[] = {
(void*)APR_OFFSETOF(oidc_cfg, oauth.ssl_validate_server),
RSRC_CONF,
"Require validation of the OAuth 2.0 AS Validation Endpoint SSL server certificate for successful authentication (On or Off)"),
AP_INIT_TAKE12(OIDCOAuthRemoteUserClaim,
AP_INIT_TAKE123(OIDCOAuthRemoteUserClaim,
oidc_set_remote_user_claim,
(void*)APR_OFFSETOF(oidc_cfg, oauth.remote_user_claim),
RSRC_CONF,
......
......@@ -142,7 +142,7 @@ char *oidc_jwt_serialize(apr_pool_t *pool, oidc_jwt_t *jwt,
if (cjose_base64url_encode((const uint8_t *) s_payload,
strlen(s_payload), &out, &out_len, &cjose_err) == FALSE)
return FALSE;
cser = apr_pstrndup(pool, out, out_len);
cser = apr_pstrmemdup(pool, out, out_len);
cjose_get_dealloc()(out);
free(s_payload);
......@@ -385,7 +385,7 @@ static apr_byte_t oidc_jose_hash_and_base64url_encode(apr_pool_t *pool,
if (cjose_base64url_encode(hashed, hashed_len, &out, &out_len,
&cjose_err) == FALSE)
return FALSE;
*output = apr_pstrndup(pool, out, out_len);
*output = apr_pstrmemdup(pool, out, out_len);
cjose_get_dealloc()(out);
return TRUE;
}
......@@ -1240,7 +1240,7 @@ static apr_byte_t oidc_jwk_parse_rsa_x5c(apr_pool_t *pool, json_t *json,
int i = 0;
char *s = apr_psprintf(pool, "%s\n", OIDC_JOSE_CERT_BEGIN);
while (i < strlen(s_x5c)) {
s = apr_psprintf(pool, "%s%s\n", s, apr_pstrndup(pool, s_x5c + i, len));
s = apr_psprintf(pool, "%s%s\n", s, apr_pstrmemdup(pool, s_x5c + i, len));
i += len;
}
s = apr_psprintf(pool, "%s%s\n", s, OIDC_JOSE_CERT_END);
......
......@@ -123,6 +123,7 @@ extern module AP_MODULE_DECLARE_DATA auth_openidc_module;
#define OIDC_METADATA_USERINFO_TOKEN_METHOD "userinfo_token_method"
#define OIDC_METADATA_TOKEN_BINDING_POLICY "token_binding_policy"
#define OIDC_METADATA_AUTH_REQUEST_METHOD "auth_request_method"
#define OIDC_METADATA_ISSUER_SPECIFIC_REDIRECT_URI "issuer_specific_redirect_uri"
/*
* get the metadata filename for a specified issuer (cq. urlencode it)
......@@ -487,7 +488,7 @@ static apr_byte_t oidc_metadata_client_register(request_rec *r, oidc_cfg *cfg,
json_object_set_new(data, OIDC_METADATA_CLIENT_NAME,
json_string(provider->client_name));
json_object_set_new(data, OIDC_METADATA_REDIRECT_URIS,
json_pack("[s]", oidc_get_redirect_uri(r, cfg)));
json_pack("[s]", oidc_get_redirect_uri_iss(r, cfg, provider)));
json_t *response_types = json_array();
apr_array_header_t *flows = oidc_proto_supported_flows(r->pool);
......@@ -907,16 +908,20 @@ static void oidc_metadata_parse_boolean(request_rec *r, json_t *json,
const char *key, int *value, int default_value) {
int int_value = 0;
char *s_value = NULL;
oidc_json_object_get_string(r->pool, json, key, &s_value,
NULL);
if (s_value != NULL) {
const char *rv = oidc_parse_boolean(r->pool, s_value, &int_value);
if (rv != NULL) {
oidc_warn(r, "%s: %s", key, rv);
int_value = default_value;
if (oidc_json_object_get_bool(r->pool, json, key, &int_value,
default_value) == FALSE) {
oidc_json_object_get_string(r->pool, json, key, &s_value,
NULL);
if (s_value != NULL) {
const char *rv = oidc_parse_boolean(r->pool, s_value, &int_value);
if (rv != NULL) {
oidc_warn(r, "%s: %s", key, rv);
int_value = default_value;
}
} else {
oidc_json_object_get_int(r->pool, json, key, &int_value,
default_value);
}
} else {
oidc_json_object_get_int(r->pool, json, key, &int_value, default_value);
}
*value = (int_value != 0) ? TRUE : FALSE;
}
......@@ -1234,6 +1239,12 @@ apr_byte_t oidc_metadata_conf_parse(request_rec *r, oidc_cfg *cfg,
else
provider->auth_request_method = cfg->provider.auth_request_method;
/* get the issuer specific redirect URI option */
oidc_metadata_parse_boolean(r, j_conf,
OIDC_METADATA_ISSUER_SPECIFIC_REDIRECT_URI,
&provider->issuer_specific_redirect_uri,
cfg->provider.issuer_specific_redirect_uri);
return TRUE;
}
......
......@@ -208,11 +208,9 @@ void oidc_strip_cookies(request_rec *r) {
}
if (i == strip->nelts) {
result =
result ?
apr_psprintf(r->pool, "%s%s%s", result,
OIDC_STR_SEMI_COLON, cookie) :
cookie;
result = result ? apr_psprintf(r->pool, "%s%s%s", result,
OIDC_STR_SEMI_COLON, cookie) :
cookie;
}
cookie = apr_strtok(NULL, OIDC_STR_SEMI_COLON, &ctx);
......@@ -284,7 +282,7 @@ static char *oidc_get_browser_state_hash(request_rec *r, const char *nonce) {
* return the name for the state cookie
*/
static char *oidc_get_state_cookie_name(request_rec *r, const char *state) {
return apr_psprintf(r->pool, "%s%s", OIDCStateCookiePrefix, state);
return apr_psprintf(r->pool, "%s%s", OIDC_STATE_COOKIE_PREFIX, state);
}
/*
......@@ -681,7 +679,7 @@ static void oidc_clean_expired_state_cookies(request_rec *r, oidc_cfg *c,
while (cookie != NULL) {
while (*cookie == OIDC_CHAR_SPACE)
cookie++;
if (strstr(cookie, OIDCStateCookiePrefix) == cookie) {
if (strstr(cookie, OIDC_STATE_COOKIE_PREFIX) == cookie) {
char *cookieName = cookie;
while (cookie != NULL && *cookie != OIDC_CHAR_EQUAL)
cookie++;
......@@ -1492,7 +1490,8 @@ static int oidc_authorization_response_error(request_rec *r, oidc_cfg *c,
* get the r->user for this request based on the configuration for OIDC/OAuth
*/
apr_byte_t oidc_get_remote_user(request_rec *r, const char *claim_name,
const char *reg_exp, json_t *json, char **request_user) {
const char *reg_exp, const char *replace, json_t *json,
char **request_user) {
/* get the claim value from the JSON object */
json_t *username = json_object_get(json, claim_name);
......@@ -1506,12 +1505,25 @@ apr_byte_t oidc_get_remote_user(request_rec *r, const char *claim_name,
if (reg_exp != NULL) {
char *error_str = NULL;
if (oidc_util_regexp_first_match(r->pool, *request_user, reg_exp,
request_user, &error_str) == FALSE) {
oidc_error(r, "oidc_util_regexp_first_match failed: %s", error_str);
if (replace == NULL) {
if (oidc_util_regexp_first_match(r->pool, *request_user, reg_exp,
request_user, &error_str) == FALSE) {
oidc_error(r, "oidc_util_regexp_first_match failed: %s",
error_str);
*request_user = NULL;
return FALSE;
}
} else if (oidc_util_regexp_substitute(r->pool, *request_user, reg_exp,
replace, request_user, &error_str) == FALSE) {
oidc_error(r, "oidc_util_regexp_substitute failed: %s", error_str);
*request_user = NULL;
return FALSE;
}
}