Skip to content

Commit 09f0beb

Browse files
committed
merge in pconf mem handling of config
2 parents 8a4cacd + 635f3b6 commit 09f0beb

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

100 files changed

+1432
-1402
lines changed

ChangeLog

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,38 @@
1+
01/03/2026
2+
- test: fix long int test in test_util.c so that it fits within a 32bit long int size; see #1375; thanks @moschlar
3+
- update copyright year to 2026
4+
5+
12/13/2025
6+
- oauth: fix segfault when using OIDCOAuthVerifySharedKeys, regression since 2.4.16; closes #1373; thanks @contryboy
7+
8+
12/08/2025
9+
- jwk: fix parsi8ng RSA JWKs with only an "x5c" parameter (i.e. no "n" and "e")
10+
- bump to 2.4.19.1dev
11+
12+
12/01/2025
13+
- release 2.4.19
14+
15+
11/23/2025
16+
- init: refactor pconf pool memory allocation handling
17+
avoid increasing memory (pool) consumption over graceful restarts
18+
19+
11/19/2025
20+
- request: set the OIDC_ERROR variables when PAR is configured but not enabled by the Provider
21+
22+
11/18/2025
23+
- id_token: add "off" option to OIDCPassIDTokenAs so no claims from the ID token will be passed on
24+
- passphrase: generate a crypto key when OIDCCryptoPassphrase is not set
25+
26+
11/17/2025
27+
- metadata: avoid double-free when validation of provider metadata fails
28+
- perf: store id_token/userinfo claims as JSON objects and avoid parsing/serializing overhead
29+
which results in up to 7% performance increase, depending on the number of claims stored
30+
- session/cookie: save 20-40 bytes on the session and client-cookie size
31+
NB: the internal session format has changed and is backwards incompatible: existing sessions and cookies will be invalid
32+
- response: avoid proto state memory leaks upon errors in response processing
33+
- drop support for Apache 2.2
34+
- bump to 2.4.19dev
35+
136
11/14/2025
237
- test: add test/test_proto.c and migrate proto tests from test.c
338

@@ -9,7 +44,7 @@
944
- test: test/Makefile.am refactor check programs
1045

1146
11/07/2025
12-
- support individual SameSite cookie settings on the session cookie, state cookie and Discovery CSRF
47+
- cookie: support individual SameSite cookie settings on the session cookie, state cookie and Discovery CSRF
1348
cookie by adding 2 more arguments to OIDCCookieSameSite
1449
- code: avoid compiler warnings on `curl_easy_setopt` in http.c
1550
http.c:612:16: warning: call to '_curl_easy_setopt_err_long' declared with attribute warning: curl_easy_setopt expects a long argument [-Wattribute-warning]

Makefile.am

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ EXTRA_DIST = \
1111
auth_openidc.conf
1212

1313
clang-format:
14-
clang-format -style=file -i $$(find . -maxdepth 3 -name *.[ch])
14+
clang-format -style=file -i $$(find . -maxdepth 3 -name \*\.[ch])
1515

1616
valgrind check-code-coverage: check
1717
${MAKE} -C test $@

README.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ How to Use It
4141

4242
1. install and load `mod_auth_openidc.so` in your Apache server
4343
1. set `OIDCRedirectURI` to a "vanity" URL within a location that is protected by mod_auth_openidc
44-
1. configure a random password in `OIDCCryptoPassphrase` for session/state encryption purposes
44+
4545
1. configure `OIDCProviderMetadataURL` so it points to the Discovery metadata of your OpenID Connect Provider served on the `.well-known/openid-configuration` endpoint
4646
1. register/generate a Client identifier and a secret with the OpenID Connect Provider and configure those in `OIDCClientID` and `OIDCClientSecret` respectively
4747
1. register the `OIDCRedirectURI` configured above as the Redirect or Callback URI for your client at the Provider
@@ -53,7 +53,6 @@ LoadModule auth_openidc_module modules/mod_auth_openidc.so
5353
5454
# OIDCRedirectURI is a vanity URL that must point to a path protected by this module but must NOT point to any content
5555
OIDCRedirectURI https://<hostname>/secure/redirect_uri
56-
OIDCCryptoPassphrase <password>
5756
5857
OIDCProviderMetadataURL <issuer>/.well-known/openid-configuration
5958
OIDCClientID <client_id>

auth_openidc.conf

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
# support multiple vhosts that belong to the same security domain in a dynamic way
1313
#OIDCRedirectURI https://www.example.com/protected/redirect_uri
1414

15-
# (Mandatory)
15+
# (Optional, but required if sessions need to be preserved across server restarts or shared across a cluster)
1616
# Set a password for crypto purposes, this is used for:
1717
# - encryption of the (temporary) state cookie
1818
# - encryption of cache entries, that may include the session cookie, see: OIDCCacheEncrypt and OIDCSessionType
@@ -27,6 +27,7 @@
2727
# will be used for encryption of new values (including a "kid" in the JWEs during the time 2 values are defined),
2828
# both values will be used for verification (leveraging the "kid" if present); for seamless rollover one should
2929
# (at minimum) wait for OIDCSessionInActivityTimeout seconds before removing the 2nd (i.e. old) passprase again.
30+
# When not specified, a random passphrase will be generated at server start time.
3031
#OIDCCryptoPassphrase [ <passphrase> | "exec:/path/to/otherProgram arg1" ] [ <previous-passphrase> | "exec:/path/to/otherProgram arg2" ]
3132

3233
#
@@ -849,10 +850,11 @@
849850
# "claims" : the claims in the id_token are passed in individual headers/environment variables
850851
# "payload" : the payload of the id_token is passed as a JSON object in the "OIDC_id_token_payload" header/environment variable
851852
# "serialized" : the complete id_token is passed in compact serialized format in the "OIDC_id_token" header/environment variable
853+
# "off" : no id_token information is passed (overrides other options)
852854
# Note that when OIDCSessionType client-cookie is set, the id_token itself is not stored in the session/cookie (unless explicitly
853855
# configured to do so) and as such the header for the "serialized" option will not be set.
854856
# Can be configured on a per Directory/Location basis. When not defined the default "claims" is used..
855-
#OIDCPassIDTokenAs [claims|payload|serialized]+
857+
#OIDCPassIDTokenAs [claims|payload|serialized|off]+
856858

857859
# Define the way(s) in which the claims resolved from the userinfo endpoint are passed to the application according to OIDCPassClaimsAs.
858860
# Must be one or several of:
@@ -1032,8 +1034,13 @@
10321034
# The default is to use internal templates
10331035
#OIDCPreservePostTemplates <preserve-template-filepath> <restore-template-filepath>
10341036

1035-
# Indicates whether the access token and access token expiry will be passed to the application in a header/environment variable, according
1036-
# to the OIDCPassClaimsAs directive.
1037+
# Indicates whether the access token, the access token type, the access token expiry and
1038+
# the scope returned from the token endpoint will be passed to the application in header/environment
1039+
# variables, according to the OIDCPassClaimsAs directive, respectively:
1040+
# OIDC_access_token
1041+
# OIDC_access_token_type
1042+
# OIDC_access_token_expires
1043+
# OIDC_scope
10371044
# Can be configured on a per Directory/Location basis. The default is "On".
10381045
#OIDCPassAccessToken [On|Off]
10391046
#

configure.ac

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
AC_INIT([mod_auth_openidc],[2.4.18.2dev],[hans.zandbelt@openidc.com])
1+
AC_INIT([mod_auth_openidc],[2.4.19.1dev],[hans.zandbelt@openidc.com])
22

33
AC_SUBST(NAMEVER, AC_PACKAGE_TARNAME()-AC_PACKAGE_VERSION())
44

src/cache/cache.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
*/
1919

2020
/***************************************************************************
21-
* Copyright (C) 2017-2025 ZmartZone Holding BV
21+
* Copyright (C) 2017-2026 ZmartZone Holding BV
2222
* Copyright (C) 2013-2017 Ping Identity Corporation
2323
* All rights reserved.
2424
*
@@ -59,12 +59,12 @@
5959
#define OIDC_CACHE_KEY_SIZE_MAX 512
6060

6161
typedef void *(*oidc_cache_cfg_create)(apr_pool_t *pool);
62-
typedef int (*oidc_cache_post_config_function)(server_rec *s);
62+
typedef int (*oidc_cache_post_config_function)(apr_pool_t *pool, server_rec *s);
6363
typedef int (*oidc_cache_child_init_function)(apr_pool_t *p, server_rec *s);
6464
typedef apr_byte_t (*oidc_cache_get_function)(request_rec *r, const char *section, const char *key, char **value);
6565
typedef apr_byte_t (*oidc_cache_set_function)(request_rec *r, const char *section, const char *key, const char *value,
6666
apr_time_t expiry);
67-
typedef int (*oidc_cache_destroy_function)(server_rec *s);
67+
typedef int (*oidc_cache_destroy_function)(apr_pool_t *pool, server_rec *s);
6868

6969
typedef struct oidc_cache_t {
7070
const char *name;
@@ -86,7 +86,7 @@ typedef struct oidc_cache_mutex_t {
8686

8787
oidc_cache_mutex_t *oidc_cache_mutex_create(apr_pool_t *pool, apr_byte_t global);
8888
char *oidc_cache_status2str(apr_pool_t *p, apr_status_t statcode);
89-
apr_byte_t oidc_cache_mutex_post_config(server_rec *s, oidc_cache_mutex_t *m, const char *type);
89+
apr_byte_t oidc_cache_mutex_post_config(apr_pool_t *pool, server_rec *s, oidc_cache_mutex_t *m, const char *type);
9090
apr_status_t oidc_cache_mutex_child_init(apr_pool_t *p, server_rec *s, oidc_cache_mutex_t *m);
9191
apr_byte_t oidc_cache_mutex_lock(apr_pool_t *pool, server_rec *s, oidc_cache_mutex_t *m);
9292
apr_byte_t oidc_cache_mutex_unlock(apr_pool_t *pool, server_rec *s, oidc_cache_mutex_t *m);

src/cache/common.c

Lines changed: 73 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
*/
1919

2020
/***************************************************************************
21-
* Copyright (C) 2017-2025 ZmartZone Holding BV
21+
* Copyright (C) 2017-2026 ZmartZone Holding BV
2222
* Copyright (C) 2013-2017 Ping Identity Corporation
2323
* All rights reserved.
2424
*
@@ -80,21 +80,25 @@ char *oidc_cache_status2str(apr_pool_t *p, apr_status_t statcode) {
8080
return apr_pstrdup(p, buf);
8181
}
8282

83-
static apr_byte_t oidc_cache_mutex_global_create(server_rec *s, oidc_cache_mutex_t *m, const char *type) {
83+
/*
84+
* create a server-wide mutex
85+
*/
86+
static apr_byte_t oidc_cache_mutex_global_create(apr_pool_t *pool, server_rec *s, oidc_cache_mutex_t *m,
87+
const char *type) {
8488

8589
apr_status_t rv = APR_SUCCESS;
8690
const char *dir;
8791

8892
/* construct the mutex filename */
89-
rv = apr_temp_dir_get(&dir, s->process->pool);
93+
rv = apr_temp_dir_get(&dir, pool);
9094
if (rv != APR_SUCCESS) {
9195
oidc_serror(s, "apr_temp_dir_get failed: could not find a temp dir: %s",
92-
oidc_cache_status2str(s->process->pool, rv));
96+
oidc_cache_status2str(pool, rv));
9397
return FALSE;
9498
}
9599

96100
m->mutex_filename =
97-
apr_psprintf(s->process->pool, "%s/mod_auth_openidc_%s_mutex.%ld.%pp", dir, type, (long int)getpid(), s);
101+
apr_psprintf(pool, "%s/mod_auth_openidc_%s_mutex.%ld.%pp", dir, type, (long int)getpid(), s);
98102

99103
/* set the lock type */
100104
apr_lockmech_e mech =
@@ -107,25 +111,60 @@ static apr_byte_t oidc_cache_mutex_global_create(server_rec *s, oidc_cache_mutex
107111
#endif
108112
;
109113

114+
// TODO: need to allocate this on the server process pool to avoid crashes on
115+
// oidc_cache_mutex_unlock at shutdown time on graceful restarts
116+
// and test/helper.c shutdown; is it because libapr cleaned it up before us?
117+
118+
/*
119+
* ==54== Invalid read of size 4
120+
* ==54== at 0x4A1C1D0: sem_post@@GLIBC_2.34 (sem_post.c:35)
121+
* ==54== by 0x49626F7: ??? (in /usr/lib/x86_64-linux-gnu/libapr-1.so.0.7.5)
122+
* ==54== by 0x4962065: apr_global_mutex_unlock (in /usr/lib/x86_64-linux-gnu/libapr-1.so.0.7.5)
123+
* ==54== by 0x5A40F9B: oidc_cache_mutex_unlock (common.c:259)
124+
* ==54== by 0x5A3FF51: oidc_cache_shm_destroy (shm.c:334)
125+
* ==54== by 0x5A33F53: oidc_cfg_server_destroy (cfg.c:700)
126+
* ==54== by 0x4964A4D: apr_pool_destroy (in /usr/lib/x86_64-linux-gnu/libapr-1.so.0.7.5)
127+
* ==54== by 0x4964A2C: apr_pool_destroy (in /usr/lib/x86_64-linux-gnu/libapr-1.so.0.7.5)
128+
* ==54== by 0x142767: ??? (in /usr/sbin/apache2)
129+
* ==54== by 0x14223A: main (in /usr/sbin/apache2)
130+
* ==54== Address 0x5abb008 is not stack'd, malloc'd or (recently) free'd
131+
*/
132+
133+
// could it be related to the remaining valgrind report on possibly lost memory: ?
134+
135+
/*
136+
* ==73== 24 bytes in 1 blocks are possibly lost in loss record 39 of 176
137+
* ==73== at 0x4844818: malloc (vg_replace_malloc.c:446)
138+
* ==73== by 0x4A91765: __tsearch (tsearch.c:337)
139+
* ==73== by 0x4A91765: tsearch (tsearch.c:290)
140+
* ==73== by 0x4A1C4E5: __sem_check_add_mapping (sem_routines.c:121)
141+
* ==73== by 0x4A1C1A0: sem_open@@GLIBC_2.34 (sem_open.c:195)
142+
* ==73== by 0x49622BF: ??? (in /usr/lib/x86_64-linux-gnu/libapr-1.so.0.7.5)
143+
* ==73== by 0x49633D9: apr_proc_mutex_create (in /usr/lib/x86_64-linux-gnu/libapr-1.so.0.7.5)
144+
* ==73== by 0x4961E8C: apr_global_mutex_create (in /usr/lib/x86_64-linux-gnu/libapr-1.so.0.7.5)
145+
* ==73== by 0x5A27AD3: oidc_cache_mutex_global_create (common.c:116)
146+
* ==73== by 0x5A27AD3: oidc_cache_mutex_post_config (common.c:144)
147+
* ==73== by 0x5A2750D: oidc_cache_shm_post_config (shm.c:111)
148+
* ==73== by 0x5A1D66E: oidc_cfg_post_config (cfg.c:1009)
149+
* ==73== by 0x5A15F9C: oidc_post_config (mod_auth_openidc.c:1762)
150+
* ==73== by 0x16B2C3: ap_run_post_config (in /usr/sbin/apache2)
151+
*/
152+
110153
/* create the mutex lock */
111154
rv = apr_global_mutex_create(&m->gmutex, (const char *)m->mutex_filename, mech, s->process->pool);
112155

113156
if (rv != APR_SUCCESS) {
114157
oidc_serror(s, "apr_global_mutex_create failed to create mutex (%d) on file %s: %s (%d)", mech,
115-
m->mutex_filename, oidc_cache_status2str(s->process->pool, rv), rv);
158+
m->mutex_filename, oidc_cache_status2str(pool, rv), rv);
116159
return FALSE;
117160
}
118161

119162
/* need this on Linux */
120163
#ifdef AP_NEED_SET_MUTEX_PERMS
121-
#if MODULE_MAGIC_NUMBER_MAJOR >= 20081201
122164
rv = ap_unixd_set_global_mutex_perms(m->gmutex);
123-
#else
124-
rv = unixd_set_global_mutex_perms(m->gmutex);
125-
#endif
126165
if (rv != APR_SUCCESS) {
127166
oidc_serror(s, "unixd_set_global_mutex_perms failed; could not set permissions: %s (%d)",
128-
oidc_cache_status2str(s->process->pool, rv), rv);
167+
oidc_cache_status2str(pool, rv), rv);
129168
return FALSE;
130169
}
131170
#endif
@@ -135,21 +174,29 @@ static apr_byte_t oidc_cache_mutex_global_create(server_rec *s, oidc_cache_mutex
135174
return TRUE;
136175
}
137176

138-
apr_byte_t oidc_cache_mutex_post_config(server_rec *s, oidc_cache_mutex_t *m, const char *type) {
139-
177+
/*
178+
* initialize a server- or process-wide mutex
179+
*/
180+
apr_byte_t oidc_cache_mutex_post_config(apr_pool_t *pool, server_rec *s, oidc_cache_mutex_t *m, const char *type) {
181+
apr_byte_t rc = TRUE;
140182
apr_status_t rv = APR_SUCCESS;
141183

142-
if (m->is_global)
143-
return oidc_cache_mutex_global_create(s, m, type);
184+
if (m->is_global) {
185+
rc = oidc_cache_mutex_global_create(pool, s, m, type);
186+
goto end;
187+
}
144188

189+
// NB: see note above at apr_global_mutex_create on the use of s->process->pool
145190
rv = apr_thread_mutex_create(&m->tmutex, APR_THREAD_MUTEX_DEFAULT, s->process->pool);
146191
if (rv != APR_SUCCESS) {
147-
oidc_serror(s, "apr_thread_mutex_create failed: %s (%d)", oidc_cache_status2str(s->process->pool, rv),
148-
rv);
149-
return FALSE;
192+
oidc_serror(s, "apr_thread_mutex_create failed: %s (%d)", oidc_cache_status2str(pool, rv), rv);
193+
rc = FALSE;
194+
goto end;
150195
}
151196

152-
return TRUE;
197+
end:
198+
199+
return rc;
153200
}
154201

155202
/*
@@ -252,7 +299,7 @@ static inline apr_byte_t oidc_cache_crypto_encrypt(request_rec *r, const char *p
252299
/*
253300
* AES GCM decrypt using the crypto passphrase as symmetric key
254301
*/
255-
static inline apr_byte_t oidc_cache_crypto_decrypt(request_rec *r, const char *cache_value, char *secret,
302+
static inline apr_byte_t oidc_cache_crypto_decrypt(request_rec *r, const char *cache_value, const char *secret,
256303
char **plaintext) {
257304
oidc_crypto_passphrase_t passphrase;
258305
passphrase.secret1 = secret;
@@ -313,12 +360,12 @@ apr_byte_t oidc_cache_get(request_rec *r, const char *section, const char *key,
313360
char *msg = NULL;
314361
const char *s_key = NULL;
315362
char *cache_value = NULL;
316-
char *s_secret = NULL;
363+
const char *s_secret = NULL;
317364
const char *s_section = oidc_cache_section_get(r, section);
318365

319366
oidc_debug(r, "enter: %s (section=%s, decrypt=%d, type=%s)", key, s_section, encrypted, cfg->cache.impl->name);
320367

321-
s_secret = cfg->crypto_passphrase.secret1;
368+
s_secret = oidc_cfg_crypto_passphrase_secret1_get(cfg);
322369
if (oidc_cache_get_key(r, key, s_secret, encrypted, &s_key) == FALSE)
323370
goto end;
324371

@@ -329,9 +376,9 @@ apr_byte_t oidc_cache_get(request_rec *r, const char *section, const char *key,
329376
goto end;
330377

331378
/* see if it is any good */
332-
if ((cache_value == NULL) && (encrypted == 1) && (cfg->crypto_passphrase.secret2 != NULL)) {
379+
if ((cache_value == NULL) && (encrypted == 1) && (oidc_cfg_crypto_passphrase_secret2_get(cfg) != NULL)) {
333380
oidc_debug(r, "2nd try with previous passphrase");
334-
s_secret = cfg->crypto_passphrase.secret2;
381+
s_secret = oidc_cfg_crypto_passphrase_secret2_get(cfg);
335382
if (oidc_cache_get_key(r, key, s_secret, encrypted, &s_key) == FALSE)
336383
goto end;
337384
if (cfg->cache.impl->get(r, s_section, s_key, &cache_value) == FALSE)
@@ -389,12 +436,12 @@ apr_byte_t oidc_cache_set(request_rec *r, const char *section, const char *key,
389436
value ? (int)_oidc_strlen(value) : 0, encrypted, apr_time_sec(expiry - apr_time_now()),
390437
cfg->cache.impl->name);
391438

392-
if (oidc_cache_get_key(r, key, cfg->crypto_passphrase.secret1, encrypted, &s_key) == FALSE)
439+
if (oidc_cache_get_key(r, key, oidc_cfg_crypto_passphrase_secret1_get(cfg), encrypted, &s_key) == FALSE)
393440
goto end;
394441

395442
/* see if we need to encrypt */
396443
if ((encrypted == 1) && (value != NULL)) {
397-
if (oidc_cache_crypto_encrypt(r, value, &cfg->crypto_passphrase, &encoded) == FALSE)
444+
if (oidc_cache_crypto_encrypt(r, value, oidc_cfg_crypto_passphrase_get(cfg), &encoded) == FALSE)
398445
goto end;
399446
value = encoded;
400447
}

src/cache/file.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
*/
1919

2020
/***************************************************************************
21-
* Copyright (C) 2017-2025 ZmartZone Holding BV
21+
* Copyright (C) 2017-2026 ZmartZone Holding BV
2222
* Copyright (C) 2013-2017 Ping Identity Corporation
2323
* All rights reserved.
2424
*
@@ -63,15 +63,15 @@ typedef struct {
6363
#define OIDC_CACHE_FILE_PREFIX "mod-auth-openidc-"
6464

6565
/* post config routine */
66-
int oidc_cache_file_post_config(server_rec *s) {
66+
int oidc_cache_file_post_config(apr_pool_t *pool, server_rec *s) {
6767
apr_status_t rv = APR_SUCCESS;
6868
oidc_cfg_t *cfg = (oidc_cfg_t *)ap_get_module_config(s->module_config, &auth_openidc_module);
6969
if (cfg->cache.file_dir == NULL) {
7070
/* by default we'll use the OS specified /tmp dir for cache files */
71-
rv = apr_temp_dir_get((const char **)&cfg->cache.file_dir, s->process->pool);
71+
rv = apr_temp_dir_get((const char **)&cfg->cache.file_dir, pool);
7272
if (rv != APR_SUCCESS) {
7373
oidc_serror(s, "apr_temp_dir_get failed: could not find a temp dir: %s",
74-
oidc_cache_status2str(s->process->pool, rv));
74+
oidc_cache_status2str(pool, rv));
7575
return HTTP_INTERNAL_SERVER_ERROR;
7676
}
7777
}

0 commit comments

Comments
 (0)