Coverage Report

Created: 2026-09-04 06:43

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/mod_auth_openidc/src/cfg/cfg.c
Line
Count
Source
1
/*
2
 * Licensed to the Apache Software Foundation (ASF) under one
3
 * or more contributor license agreements.  See the NOTICE file
4
 * distributed with this work for additional information
5
 * regarding copyright ownership.  The ASF licenses this file
6
 * to you under the Apache License, Version 2.0 (the
7
 * "License"); you may not use this file except in compliance
8
 * with the License.  You may obtain a copy of the License at
9
 *
10
 *   http://www.apache.org/licenses/LICENSE-2.0
11
 *
12
 * Unless required by applicable law or agreed to in writing,
13
 * software distributed under the License is distributed on an
14
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15
 * KIND, either express or implied.  See the License for the
16
 * specific language governing permissions and limitations
17
 * under the License.
18
 */
19
20
/***************************************************************************
21
 * Copyright (C) 2017-2026 ZmartZone Holding BV
22
 * All rights reserved.
23
 *
24
 * DISCLAIMER OF WARRANTIES:
25
 *
26
 * THE SOFTWARE PROVIDED HEREUNDER IS PROVIDED ON AN "AS IS" BASIS, WITHOUT
27
 * ANY WARRANTIES OR REPRESENTATIONS EXPRESS, IMPLIED OR STATUTORY; INCLUDING,
28
 * WITHOUT LIMITATION, WARRANTIES OF QUALITY, PERFORMANCE, NONINFRINGEMENT,
29
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  NOR ARE THERE ANY
30
 * WARRANTIES CREATED BY A COURSE OR DEALING, COURSE OF PERFORMANCE OR TRADE
31
 * USAGE.  FURTHERMORE, THERE ARE NO WARRANTIES THAT THE SOFTWARE WILL MEET
32
 * YOUR NEEDS OR BE FREE FROM ERRORS, OR THAT THE OPERATION OF THE SOFTWARE
33
 * WILL BE UNINTERRUPTED.  IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
34
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
35
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES HOWEVER CAUSED AND ON ANY THEORY OF
36
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
37
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
38
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39
 *
40
 * @Author: Hans Zandbelt - hans.zandbelt@openidc.com
41
 */
42
43
#include "cfg/cache.h"
44
#include "cfg/cfg_int.h"
45
#include "cfg/dir.h"
46
#include "cfg/oauth.h"
47
#include "cfg/parse.h"
48
#include "cfg/provider.h"
49
#include "jose.h"
50
#include "metrics.h"
51
#include "proto/proto.h"
52
#include "session.h"
53
#include "util/util.h"
54
#include "util/util_cfg.h"
55
56
#if OPENSSL_API_COMPAT < 0x10100000L
57
#include <openssl/err.h>
58
#include <openssl/ssl.h>
59
#endif
60
61
2
const char *oidc_cfg_string_list_add(apr_pool_t *pool, apr_array_header_t **list, const char *arg) {
62
2
  if (*list == NULL)
63
2
    *list = apr_array_make(pool, 1, sizeof(const char *));
64
2
  APR_ARRAY_PUSH(*list, const char *) = arg;
65
2
  return NULL;
66
2
}
67
68
#define OIDC_DEFAULT_ACTION_ON_USERINFO_ERROR OIDC_ON_ERROR_502
69
OIDC_CFG_MEMBER_FUNC_TYPE_GET(action_on_userinfo_error, oidc_on_error_action_t, OIDC_DEFAULT_ACTION_ON_USERINFO_ERROR)
70
71
#define OIDC_CFG_MEMBER_FUNCS_HTTP_TIMEOUT(member, def_val)                                                            \
72
  const char *oidc_cmd_##member##_set(cmd_parms *cmd, void *ptr, const char *arg1, const char *arg2,             \
73
0
              const char *arg3) {                                                        \
74
0
    oidc_cfg_t *cfg =                                                                                      \
75
0
        (oidc_cfg_t *)ap_get_module_config(cmd->server->module_config, &auth_openidc_module);              \
76
0
    const char *rv = oidc_cfg_parse_http_timeout(cmd->pool, arg1, arg2, arg3, &cfg->member);               \
77
0
    return OIDC_CONFIG_DIR_RV(cmd, rv);                                                                    \
78
0
  }                                                                                                              \
79
                                                                                                                       \
80
252
  oidc_http_timeout_t *oidc_cfg_##member##_get(oidc_cfg_t *cfg) {                                                \
81
252
    if (cfg->member.request_timeout == OIDC_CONFIG_POS_INT_UNSET)                                          \
82
252
      /* NB: we are modifying in-config but post_config/merge has finished by now  */                \
83
252
      cfg->member.request_timeout = def_val;                                                         \
84
252
    return &cfg->member;                                                                                   \
85
252
  }
oidc_cfg_http_timeout_long_get
Line
Count
Source
80
252
  oidc_http_timeout_t *oidc_cfg_##member##_get(oidc_cfg_t *cfg) {                                                \
81
252
    if (cfg->member.request_timeout == OIDC_CONFIG_POS_INT_UNSET)                                          \
82
252
      /* NB: we are modifying in-config but post_config/merge has finished by now  */                \
83
252
      cfg->member.request_timeout = def_val;                                                         \
84
252
    return &cfg->member;                                                                                   \
85
252
  }
Unexecuted instantiation: oidc_cfg_http_timeout_short_get
86
87
/* request timeout in seconds for HTTP calls that may take a long time */
88
#define OIDC_DEFAULT_HTTP_REQUEST_TIMEOUT_LONG 30
89
/* connect timeout in seconds for HTTP calls that may take a long time */
90
40
#define OIDC_DEFAULT_HTTP_CONNECT_TIMEOUT_LONG 10
91
/* nr of retries for HTTP calls that may take a long time */
92
40
#define OIDC_DEFAULT_HTTP_RETRIES_LONG 1
93
/* retry interval in milliseconds for HTTP calls that may take a long time */
94
40
#define OIDC_DEFAULT_HTTP_RETRY_INTERVAL_LONG 500
95
/* timeouts in seconds for HTTP calls that should take a short time (registry/discovery related) */
96
#define OIDC_DEFAULT_HTTP_REQUEST_TIMEOUT_SHORT 5
97
/* connect timeout in seconds for HTTP calls that may take a long time */
98
40
#define OIDC_DEFAULT_HTTP_CONNECT_TIMEOUT_SHORT 2
99
/* nr of retries for HTTP calls that should take a short time */
100
40
#define OIDC_DEFAULT_HTTP_RETRIES_SHORT 1
101
/* retry interval in milliseconds for HTTP calls that should take a short time */
102
40
#define OIDC_DEFAULT_HTTP_RETRY_INTERVAL_SHORT 300
103
104
0
OIDC_CFG_MEMBER_FUNCS_HTTP_TIMEOUT(http_timeout_long, OIDC_DEFAULT_HTTP_REQUEST_TIMEOUT_LONG)
105
0
OIDC_CFG_MEMBER_FUNCS_HTTP_TIMEOUT(http_timeout_short, OIDC_DEFAULT_HTTP_REQUEST_TIMEOUT_SHORT)
106
107
0
const char *oidc_cmd_crypto_passphrase_set(cmd_parms *cmd, void *struct_ptr, const char *arg1, const char *arg2) {
108
0
  oidc_cfg_t *cfg = (oidc_cfg_t *)ap_get_module_config(cmd->server->module_config, &auth_openidc_module);
109
0
  const char *rv = NULL;
110
0
  char *v = NULL;
111
0
  if (arg1) {
112
0
    rv = oidc_cfg_parse_passphrase(cmd->pool, arg1, &v);
113
0
    if (rv == NULL)
114
0
      cfg->crypto_passphrase.secret1 = v;
115
0
  }
116
0
  if ((rv == NULL) && (arg2 != NULL)) {
117
0
    rv = oidc_cfg_parse_passphrase(cmd->pool, arg2, &v);
118
0
    if (rv == NULL)
119
0
      cfg->crypto_passphrase.secret2 = v;
120
0
  }
121
0
  return rv;
122
0
}
123
124
101k
const oidc_crypto_passphrase_t *oidc_cfg_crypto_passphrase_get(const oidc_cfg_t *cfg) {
125
101k
  return &cfg->crypto_passphrase;
126
101k
}
127
128
29.4k
const char *oidc_cfg_crypto_passphrase_secret1_get(const oidc_cfg_t *cfg) {
129
29.4k
  return cfg->crypto_passphrase.secret1;
130
29.4k
}
131
132
0
void oidc_cfg_crypto_passphrase_secret1_set(oidc_cfg_t *cfg, const char *secret) {
133
0
  cfg->crypto_passphrase.secret1 = secret;
134
0
}
135
136
23.2k
const char *oidc_cfg_crypto_passphrase_secret2_get(const oidc_cfg_t *cfg) {
137
23.2k
  return cfg->crypto_passphrase.secret2;
138
23.2k
}
139
140
/* Derive finalized passphrases once, before requests use them for JWE operations. */
141
0
apr_byte_t oidc_crypto_passphrase_derive_keys(oidc_crypto_passphrase_t *cp) {
142
  /* an empty (non-NULL) secret is treated as "not configured", matching
143
   * oidc_util_key_symmetric_create()'s existing behavior for a client_secret */
144
0
  if ((cp->secret1 != NULL) && (_oidc_strlen(cp->secret1) > 0) && (cp->derived_key1_set == FALSE)) {
145
0
    if (oidc_util_key_derive_passphrase_key(cp->secret1, cp->derived_key1,
146
0
              OIDC_CRYPTO_PASSPHRASE_DERIVED_KEY_LEN) == FALSE)
147
0
      return FALSE;
148
0
    cp->derived_key1_set = TRUE;
149
0
  }
150
151
0
  if ((cp->secret2 != NULL) && (_oidc_strlen(cp->secret2) > 0) && (cp->derived_key2_set == FALSE)) {
152
0
    if (oidc_util_key_derive_passphrase_key(cp->secret2, cp->derived_key2,
153
0
              OIDC_CRYPTO_PASSPHRASE_DERIVED_KEY_LEN) == FALSE)
154
0
      return FALSE;
155
0
    cp->derived_key2_set = TRUE;
156
0
  }
157
158
0
  return TRUE;
159
0
}
160
161
/*
162
 * thin wrapper around oidc_crypto_passphrase_derive_keys() for the passphrase embedded in a
163
 * server config; see that function for details
164
 */
165
0
apr_byte_t oidc_cfg_crypto_passphrase_derive_keys(oidc_cfg_t *cfg) {
166
0
  return oidc_crypto_passphrase_derive_keys(&cfg->crypto_passphrase);
167
0
}
168
169
/*
170
 * Memoize PBKDF2 output by secret across vhosts. The pool must outlive kdf_cache; a NULL cache
171
 * disables memoization.
172
 */
173
apr_byte_t oidc_crypto_passphrase_derive_keys_cached(apr_pool_t *pool, apr_hash_t *kdf_cache,
174
0
                 oidc_crypto_passphrase_t *cp) {
175
0
  const unsigned char *cached = NULL;
176
177
0
  if (kdf_cache == NULL)
178
0
    return oidc_crypto_passphrase_derive_keys(cp);
179
180
0
  if ((cp->secret1 != NULL) && (_oidc_strlen(cp->secret1) > 0) && (cp->derived_key1_set == FALSE)) {
181
0
    cached = apr_hash_get(kdf_cache, cp->secret1, APR_HASH_KEY_STRING);
182
0
    if (cached != NULL) {
183
0
      _oidc_memcpy(cp->derived_key1, cached, OIDC_CRYPTO_PASSPHRASE_DERIVED_KEY_LEN);
184
0
    } else {
185
0
      if (oidc_util_key_derive_passphrase_key(cp->secret1, cp->derived_key1,
186
0
                OIDC_CRYPTO_PASSPHRASE_DERIVED_KEY_LEN) == FALSE)
187
0
        return FALSE;
188
0
      apr_hash_set(kdf_cache, apr_pstrdup(pool, cp->secret1), APR_HASH_KEY_STRING,
189
0
             apr_pmemdup(pool, cp->derived_key1, OIDC_CRYPTO_PASSPHRASE_DERIVED_KEY_LEN));
190
0
    }
191
0
    cp->derived_key1_set = TRUE;
192
0
  }
193
194
0
  if ((cp->secret2 != NULL) && (_oidc_strlen(cp->secret2) > 0) && (cp->derived_key2_set == FALSE)) {
195
0
    cached = apr_hash_get(kdf_cache, cp->secret2, APR_HASH_KEY_STRING);
196
0
    if (cached != NULL) {
197
0
      _oidc_memcpy(cp->derived_key2, cached, OIDC_CRYPTO_PASSPHRASE_DERIVED_KEY_LEN);
198
0
    } else {
199
0
      if (oidc_util_key_derive_passphrase_key(cp->secret2, cp->derived_key2,
200
0
                OIDC_CRYPTO_PASSPHRASE_DERIVED_KEY_LEN) == FALSE)
201
0
        return FALSE;
202
0
      apr_hash_set(kdf_cache, apr_pstrdup(pool, cp->secret2), APR_HASH_KEY_STRING,
203
0
             apr_pmemdup(pool, cp->derived_key2, OIDC_CRYPTO_PASSPHRASE_DERIVED_KEY_LEN));
204
0
    }
205
0
    cp->derived_key2_set = TRUE;
206
0
  }
207
208
0
  return TRUE;
209
0
}
210
211
/*
212
 * thin wrapper around oidc_crypto_passphrase_derive_keys_cached() for the passphrase embedded
213
 * in a server config; see that function for details
214
 */
215
0
apr_byte_t oidc_cfg_crypto_passphrase_derive_keys_cached(apr_pool_t *pool, apr_hash_t *kdf_cache, oidc_cfg_t *cfg) {
216
0
  return oidc_crypto_passphrase_derive_keys_cached(pool, kdf_cache, &cfg->crypto_passphrase);
217
0
}
218
219
const char *oidc_cmd_outgoing_proxy_set(cmd_parms *cmd, void *ptr, const char *arg1, const char *arg2,
220
0
          const char *arg3) {
221
0
  oidc_cfg_t *cfg = (oidc_cfg_t *)ap_get_module_config(cmd->server->module_config, &auth_openidc_module);
222
0
  const char *rv = NULL;
223
0
  if (arg1)
224
0
    cfg->outgoing_proxy.host_port = apr_pstrdup(cmd->pool, arg1);
225
0
  if (arg2)
226
0
    cfg->outgoing_proxy.username_password = apr_pstrdup(cmd->pool, arg2);
227
0
  if (arg3) {
228
0
    rv = oidc_cfg_parse_is_valid_option(cmd->pool, arg3, oidc_http_proxy_auth_options());
229
0
    if (rv == NULL)
230
0
      cfg->outgoing_proxy.auth_type = oidc_http_proxy_s2auth(arg3);
231
0
  }
232
0
  return OIDC_CONFIG_DIR_RV(cmd, rv);
233
0
}
234
235
252
const oidc_http_outgoing_proxy_t *oidc_cfg_outgoing_proxy_get(const oidc_cfg_t *cfg) {
236
252
  return &cfg->outgoing_proxy;
237
252
}
238
239
0
static const char *oidc_cfg_valid_cookie_domain(apr_pool_t *pool, const char *arg) {
240
0
  size_t limit = _oidc_strlen(arg);
241
0
  char d;
242
0
  for (size_t sz = 0; sz < limit; sz++) {
243
0
    d = arg[sz];
244
0
    if ((d < '0' || d > '9') && (d < 'a' || d > 'z') && (d < 'A' || d > 'Z') && d != '.' && d != '-') {
245
0
      return (apr_psprintf(pool, "invalid character '%c' in cookie domain value: %s", d, arg));
246
0
    }
247
0
  }
248
0
  return NULL;
249
0
}
250
251
0
OIDC_CFG_MEMBER_FUNCS_TYPE(cookie_domain, const char *, oidc_cfg_valid_cookie_domain(cmd->pool, arg))
252
0
253
0
#define OIDC_SESSION_TYPE_SERVER_CACHE_STR "server-cache"
254
0
#define OIDC_SESSION_TYPE_CLIENT_COOKIE_STR "client-cookie"
255
0
#define OIDC_SESSION_TYPE_PERSISTENT "persistent"
256
0
#define OIDC_SESSION_TYPE_STORE_ID_TOKEN "store_id_token"
257
0
#define OIDC_SESSION_TYPE_SEPARATOR ":"
258
259
0
const char *oidc_cmd_session_type_set(cmd_parms *cmd, void *ptr, const char *arg) {
260
0
  oidc_cfg_t *cfg = (oidc_cfg_t *)ap_get_module_config(cmd->server->module_config, &auth_openidc_module);
261
262
0
  static const char *options[] = {
263
0
      OIDC_SESSION_TYPE_SERVER_CACHE_STR,
264
0
      OIDC_SESSION_TYPE_SERVER_CACHE_STR OIDC_SESSION_TYPE_SEPARATOR OIDC_SESSION_TYPE_PERSISTENT,
265
0
      OIDC_SESSION_TYPE_CLIENT_COOKIE_STR,
266
0
      OIDC_SESSION_TYPE_CLIENT_COOKIE_STR OIDC_SESSION_TYPE_SEPARATOR OIDC_SESSION_TYPE_PERSISTENT,
267
0
      OIDC_SESSION_TYPE_CLIENT_COOKIE_STR OIDC_SESSION_TYPE_SEPARATOR OIDC_SESSION_TYPE_STORE_ID_TOKEN,
268
0
      OIDC_SESSION_TYPE_CLIENT_COOKIE_STR OIDC_SESSION_TYPE_SEPARATOR OIDC_SESSION_TYPE_PERSISTENT
269
0
    OIDC_SESSION_TYPE_SEPARATOR OIDC_SESSION_TYPE_STORE_ID_TOKEN,
270
0
      NULL};
271
272
0
  const char *rv = oidc_cfg_parse_is_valid_option(cmd->pool, arg, options);
273
0
  if (rv != NULL)
274
0
    return OIDC_CONFIG_DIR_RV(cmd, rv);
275
276
0
  const char *s = apr_pstrdup(cmd->pool, arg);
277
0
  char *p = _oidc_strstr(s, OIDC_SESSION_TYPE_SEPARATOR);
278
279
0
  if (p) {
280
0
    *p = '\0';
281
0
    p++;
282
0
  }
283
284
0
  if (_oidc_strcmp(s, OIDC_SESSION_TYPE_SERVER_CACHE_STR) == 0) {
285
0
    cfg->session_type = OIDC_SESSION_TYPE_SERVER_CACHE;
286
0
  } else if (_oidc_strcmp(s, OIDC_SESSION_TYPE_CLIENT_COOKIE_STR) == 0) {
287
0
    cfg->session_type = OIDC_SESSION_TYPE_CLIENT_COOKIE;
288
0
    cfg->store_id_token = 0;
289
0
  }
290
291
  /* the combination was validated against options[] above, so each remaining
292
   * separator-delimited modifier can be applied on its own */
293
0
  while (p) {
294
0
    char *next = _oidc_strstr(p, OIDC_SESSION_TYPE_SEPARATOR);
295
0
    if (next) {
296
0
      *next = '\0';
297
0
      next++;
298
0
    }
299
0
    if (_oidc_strcmp(p, OIDC_SESSION_TYPE_PERSISTENT) == 0)
300
0
      cfg->persistent_session_cookie = 1;
301
0
    else if (_oidc_strcmp(p, OIDC_SESSION_TYPE_STORE_ID_TOKEN) == 0)
302
      // only for client-cookie
303
0
      cfg->store_id_token = 1;
304
0
    p = next;
305
0
  }
306
307
0
  return NULL;
308
0
}
309
310
#define OIDC_DEFAULT_SESSION_TYPE OIDC_SESSION_TYPE_SERVER_CACHE
311
OIDC_CFG_MEMBER_FUNC_TYPE_GET(session_type, int, OIDC_DEFAULT_SESSION_TYPE)
312
313
#define OIDC_DEFAULT_PERSISTENT_SESSION_COOKIE 0
314
OIDC_CFG_MEMBER_FUNC_TYPE_GET(persistent_session_cookie, int, OIDC_DEFAULT_PERSISTENT_SESSION_COOKIE)
315
316
#define OIDC_DEFAULT_STORE_ID_TOKEN 1
317
OIDC_CFG_MEMBER_FUNC_TYPE_GET(store_id_token, int, OIDC_DEFAULT_STORE_ID_TOKEN)
318
319
static const char *oidc_valid_endpoint_auth_method_impl(apr_pool_t *pool, const char *arg, apr_byte_t has_private_key,
320
12.4k
              apr_byte_t allow_mtls) {
321
  /* Build per call because private-key validation changes the candidate list. */
322
12.4k
  const char *options[9];
323
12.4k
  int i = 0;
324
12.4k
  options[i++] = OIDC_ENDPOINT_AUTH_CLIENT_SECRET_POST;
325
12.4k
  options[i++] = OIDC_ENDPOINT_AUTH_CLIENT_SECRET_BASIC;
326
12.4k
  options[i++] = OIDC_ENDPOINT_AUTH_CLIENT_SECRET_JWT;
327
12.4k
  options[i++] = OIDC_ENDPOINT_AUTH_NONE;
328
12.4k
  options[i++] = OIDC_ENDPOINT_AUTH_BEARER_ACCESS_TOKEN;
329
12.4k
  if (has_private_key)
330
12.4k
    options[i++] = OIDC_ENDPOINT_AUTH_PRIVATE_KEY_JWT;
331
12.4k
  if (allow_mtls) {
332
5.90k
    options[i++] = OIDC_ENDPOINT_AUTH_TLS_CLIENT_AUTH;
333
5.90k
    options[i++] = OIDC_ENDPOINT_AUTH_SELF_SIGNED_TLS_CLIENT_AUTH;
334
5.90k
  }
335
12.4k
  options[i] = NULL;
336
12.4k
  return oidc_cfg_parse_is_valid_option(pool, arg, options);
337
12.4k
}
338
339
401
static const char *oidc_valid_private_key_jwt_alg(apr_pool_t *pool, const char *arg) {
340
401
  static const char *options[] = {"RS256", "RS384", "RS512", "PS256", "PS384", "PS512",
341
401
#if (OIDC_JOSE_EC_SUPPORT)
342
401
          "ES256", "ES384", "ES512",
343
401
#endif
344
345
401
          NULL};
346
401
  return oidc_cfg_parse_is_valid_option(pool, arg, options);
347
401
}
348
349
12.6k
#define OIDC_ENDPOINT_AUTH_METHOD_SEPARATOR ":"
350
351
12.6k
static void oidc_cfg_endpoint_auth_parse(apr_pool_t *pool, const char *arg1, char **method, char **suffix) {
352
12.6k
  const char *arg = apr_pstrdup(pool, arg1);
353
12.6k
  char *sep = _oidc_strstr(arg, OIDC_ENDPOINT_AUTH_METHOD_SEPARATOR);
354
12.6k
  if (sep) {
355
629
    *sep = '\0';
356
629
    *suffix = apr_pstrdup(pool, ++sep);
357
629
  }
358
12.6k
  *method = apr_pstrdup(pool, arg);
359
12.6k
}
360
361
12.6k
static const char *oidc_cfg_valid_endpoint_auth_method_alg(apr_pool_t *pool, const char *arg1, apr_byte_t allow_mtls) {
362
12.6k
  const char *rv = NULL;
363
12.6k
  char *method = NULL;
364
12.6k
  char *alg = NULL;
365
12.6k
  oidc_cfg_endpoint_auth_parse(pool, arg1, &method, &alg);
366
12.6k
  if ((_oidc_strcmp(method, OIDC_ENDPOINT_AUTH_PRIVATE_KEY_JWT) == 0) && (alg != NULL)) {
367
401
    rv = oidc_valid_private_key_jwt_alg(pool, alg);
368
401
    if (rv != NULL)
369
204
      return rv;
370
401
  }
371
12.4k
  return oidc_valid_endpoint_auth_method_impl(pool, method, TRUE, allow_mtls);
372
12.6k
}
373
374
5.99k
static const char *oidc_cfg_valid_endpoint_auth_method_with_private_key(apr_pool_t *pool, const char *arg1) {
375
5.99k
  return oidc_cfg_valid_endpoint_auth_method_alg(pool, arg1, TRUE);
376
5.99k
}
377
378
0
static const char *oidc_cfg_valid_endpoint_auth_method_no_private_key(apr_pool_t *pool, const char *arg) {
379
0
  return oidc_valid_endpoint_auth_method_impl(pool, arg, FALSE, TRUE);
380
0
}
381
382
6.64k
static const char *oidc_cfg_valid_endpoint_auth_method_no_mtls_with_private_key(apr_pool_t *pool, const char *arg1) {
383
6.64k
  return oidc_cfg_valid_endpoint_auth_method_alg(pool, arg1, FALSE);
384
6.64k
}
385
386
0
static const char *oidc_cfg_valid_endpoint_auth_method_no_mtls_no_private_key(apr_pool_t *pool, const char *arg) {
387
0
  return oidc_valid_endpoint_auth_method_impl(pool, arg, FALSE, FALSE);
388
0
}
389
390
const char *oidc_cfg_endpoint_auth_set(apr_pool_t *pool, const oidc_cfg_t *cfg, const char *arg1, char **auth,
391
4.75k
               char **alg) {
392
4.75k
  const char *rv = oidc_cfg_get_valid_endpoint_auth_function(cfg, TRUE)(pool, arg1);
393
4.75k
  if (rv == NULL)
394
49
    oidc_cfg_endpoint_auth_parse(pool, arg1, auth, alg);
395
4.75k
  return rv;
396
4.75k
}
397
398
/*
399
 * check if the endpoint authentication method is one of the RFC 8705 mutual-TLS methods
400
 */
401
4.87k
apr_byte_t oidc_cfg_endpoint_auth_is_mtls(const char *method) {
402
4.87k
  return (_oidc_strcmp(method, OIDC_ENDPOINT_AUTH_TLS_CLIENT_AUTH) == 0) ||
403
4.87k
         (_oidc_strcmp(method, OIDC_ENDPOINT_AUTH_SELF_SIGNED_TLS_CLIENT_AUTH) == 0);
404
4.87k
}
405
406
/* Select endpoint-auth validation based on private-key availability and whether mTLS is allowed. */
407
9.48k
oidc_valid_function_t oidc_cfg_get_valid_endpoint_auth_function(const oidc_cfg_t *cfg, apr_byte_t allow_mtls) {
408
9.48k
  if (allow_mtls == FALSE)
409
4.69k
    return (cfg->private_keys != NULL) ? &oidc_cfg_valid_endpoint_auth_method_no_mtls_with_private_key
410
4.69k
               : &oidc_cfg_valid_endpoint_auth_method_no_mtls_no_private_key;
411
4.79k
  return (cfg->private_keys != NULL) ? &oidc_cfg_valid_endpoint_auth_method_with_private_key
412
4.79k
             : &oidc_cfg_valid_endpoint_auth_method_no_private_key;
413
9.48k
}
414
415
#define OIDC_SESSION_INACTIVITY_TIMEOUT_MIN 10
416
#define OIDC_SESSION_INACTIVITY_TIMEOUT_MAX (3600 * 24 * 365)
417
#define OIDC_DEFAULT_SESSION_INACTIVITY_TIMEOUT 300
418
419
0
OIDC_CFG_MEMBER_FUNCS_INT(session_inactivity_timeout, OIDC_SESSION_INACTIVITY_TIMEOUT_MIN,
420
0
        OIDC_SESSION_INACTIVITY_TIMEOUT_MAX, OIDC_DEFAULT_SESSION_INACTIVITY_TIMEOUT)
421
0
422
0
const char *oidc_cmd_public_keys_set(cmd_parms *cmd, void *ptr, const char *arg) {
423
0
  oidc_cfg_t *cfg = (oidc_cfg_t *)ap_get_module_config(cmd->server->module_config, &auth_openidc_module);
424
0
  const char *rv = oidc_cfg_parse_public_key_files(cmd->pool, arg, &cfg->public_keys);
425
0
  return OIDC_CONFIG_DIR_RV(cmd, rv);
426
0
}
427
428
OIDC_CFG_MEMBER_FUNC_GET(public_keys, const apr_array_header_t *)
429
430
/*
431
 * add a private key from an RSA/EC private key file to our list of JWKs with private keys
432
 */
433
0
const char *oidc_cmd_private_keys_set(cmd_parms *cmd, void *ptr, const char *arg) {
434
0
  oidc_cfg_t *cfg = (oidc_cfg_t *)ap_get_module_config(cmd->server->module_config, &auth_openidc_module);
435
0
  const char *rv = oidc_cfg_parse_private_key_files(cmd->pool, arg, &cfg->private_keys);
436
0
  return OIDC_CONFIG_DIR_RV(cmd, rv);
437
0
}
438
439
OIDC_CFG_MEMBER_FUNC_GET(private_keys, const apr_array_header_t *)
440
441
0
const char *oidc_cmd_remote_user_claim_set(cmd_parms *cmd, void *ptr, const char *v1, const char *v2, const char *v3) {
442
0
  oidc_cfg_t *cfg = (oidc_cfg_t *)ap_get_module_config(cmd->server->module_config, &auth_openidc_module);
443
0
  const char *rv = oidc_parse_remote_user_claim(cmd->pool, v1, v2, v3, &cfg->remote_user_claim);
444
0
  return OIDC_CONFIG_DIR_RV(cmd, rv);
445
0
}
446
447
1.98k
const oidc_remote_user_claim_t *oidc_cfg_remote_user_claim_get(const oidc_cfg_t *cfg) {
448
1.98k
  return &cfg->remote_user_claim;
449
1.98k
}
450
451
990
#define OIDC_DEFAULT_CLAIM_REMOTE_USER "sub@"
452
453
990
const char *oidc_cfg_remote_user_claim_name_get(const oidc_cfg_t *cfg) {
454
990
  return cfg->remote_user_claim.claim_name != NULL ? cfg->remote_user_claim.claim_name
455
990
               : OIDC_DEFAULT_CLAIM_REMOTE_USER;
456
990
}
457
458
#ifdef USE_LIBJQ
459
460
const char *oidc_cmd_filter_claims_expr_set(cmd_parms *cmd, void *m, const char *arg) {
461
  oidc_cfg_t *cfg = (oidc_cfg_t *)ap_get_module_config(cmd->server->module_config, &auth_openidc_module);
462
  const char *rv = oidc_util_apr_expr_parse(cmd, arg, &cfg->filter_claims_expr, OIDC_APR_EXPR_RESULT_STRING);
463
  return OIDC_CONFIG_DIR_RV(cmd, rv);
464
}
465
466
#endif
467
468
OIDC_CFG_MEMBER_FUNC_GET(filter_claims_expr, oidc_apr_expr_t *)
469
470
/*
471
 * define which data will be returned from the info hook
472
 */
473
0
const char *oidc_cmd_info_hook_data_set(cmd_parms *cmd, void *m, const char *arg) {
474
0
  oidc_cfg_t *cfg = (oidc_cfg_t *)ap_get_module_config(cmd->server->module_config, &auth_openidc_module);
475
0
  static const char *options[] = {
476
0
      OIDC_HOOK_INFO_TIMESTAMP,   OIDC_HOOK_INFO_ACCES_TOKEN, OIDC_HOOK_INFO_ACCES_TOKEN_EXP,
477
0
      OIDC_HOOK_INFO_ID_TOKEN_HINT, OIDC_HOOK_INFO_ID_TOKEN,    OIDC_HOOK_INFO_USER_INFO,
478
0
      OIDC_HOOK_INFO_REFRESH_TOKEN, OIDC_HOOK_INFO_SESSION_EXP, OIDC_HOOK_INFO_SESSION_TIMEOUT,
479
0
      OIDC_HOOK_INFO_SESSION_REMOTE_USER, OIDC_HOOK_INFO_SESSION,     NULL};
480
0
  const char *rv = oidc_cfg_parse_is_valid_option(cmd->pool, arg, options);
481
0
  if (rv != NULL)
482
0
    return OIDC_CONFIG_DIR_RV(cmd, rv);
483
0
  if (cfg->info_hook_data == NULL)
484
0
    cfg->info_hook_data = apr_hash_make(cmd->pool);
485
0
  apr_hash_set(cfg->info_hook_data, arg, APR_HASH_KEY_STRING, arg);
486
0
  return NULL;
487
0
}
488
489
OIDC_CFG_MEMBER_FUNC_GET(info_hook_data, apr_hash_t *)
490
491
0
const char *oidc_cmd_metrics_hook_data_set(cmd_parms *cmd, void *m, const char *arg) {
492
0
  oidc_cfg_t *cfg = (oidc_cfg_t *)ap_get_module_config(cmd->server->module_config, &auth_openidc_module);
493
0
  const char *rv = NULL;
494
0
  char *valid_names = NULL;
495
0
  if (oidc_metrics_is_valid_classname(cmd->pool, arg, &valid_names) == TRUE) {
496
0
    if (cfg->metrics_hook_data == NULL)
497
0
      cfg->metrics_hook_data = apr_hash_make(cmd->pool);
498
0
    apr_hash_set(cfg->metrics_hook_data, arg, APR_HASH_KEY_STRING, arg);
499
0
  } else {
500
0
    rv = apr_psprintf(cmd->pool, "undefined metric class name: \"%s\", must be one of [%s]", arg,
501
0
          valid_names);
502
0
  }
503
0
  return OIDC_CONFIG_DIR_RV(cmd, rv);
504
0
}
505
506
OIDC_CFG_MEMBER_FUNC_GET(metrics_hook_data, apr_hash_t *)
507
508
0
#define OIDC_TRACE_PARENT_OFF_STR "off"
509
0
#define OIDC_TRACE_PARENT_PROPAGATE_STR "propagate"
510
0
#define OIDC_TRACE_PARENT_GENERATE_STR "generate"
511
512
0
const char *oidc_cmd_trace_parent_set(cmd_parms *cmd, void *struct_ptr, const char *arg) {
513
0
  oidc_cfg_t *cfg = (oidc_cfg_t *)ap_get_module_config(cmd->server->module_config, &auth_openidc_module);
514
0
  static const oidc_cfg_option_t options[] = {{OIDC_TRACE_PARENT_OFF, OIDC_TRACE_PARENT_OFF_STR},
515
0
                {OIDC_TRACE_PARENT_PROPAGATE, OIDC_TRACE_PARENT_PROPAGATE_STR},
516
0
                {OIDC_TRACE_PARENT_GENERATE, OIDC_TRACE_PARENT_GENERATE_STR}};
517
0
  const char *rv =
518
0
      oidc_cfg_parse_option(cmd->pool, options, OIDC_CFG_OPTIONS_SIZE(options), arg, &cfg->trace_parent);
519
0
  return OIDC_CONFIG_DIR_RV(cmd, rv);
520
0
}
521
522
#define OIDC_DEFAULT_TRACE_PARENT OIDC_TRACE_PARENT_OFF
523
OIDC_CFG_MEMBER_FUNC_TYPE_GET(trace_parent, oidc_trace_parent_t, OIDC_DEFAULT_TRACE_PARENT)
524
525
#define OIDC_DEFAULT_DPOP_API_ENABLED 0
526
OIDC_CFG_MEMBER_FUNC_TYPE_GET(dpop_api_enabled, int, OIDC_DEFAULT_DPOP_API_ENABLED)
527
528
0
const char *oidc_cmd_claim_prefix_set(cmd_parms *cmd, void *struct_ptr, const char *args) {
529
0
  oidc_cfg_t *cfg = (oidc_cfg_t *)ap_get_module_config(cmd->server->module_config, &auth_openidc_module);
530
0
  char *w = ap_getword_conf(cmd->pool, &args);
531
0
  if (*w == '\0' || *args != 0)
532
0
    cfg->claim_prefix = "";
533
0
  else
534
0
    cfg->claim_prefix = w;
535
0
  return NULL;
536
0
}
537
538
5.51k
#define OIDC_DEFAULT_CLAIM_PREFIX "OIDC_CLAIM_"
539
540
2.75k
const char *oidc_cfg_claim_prefix_get(const oidc_cfg_t *cfg) {
541
2.75k
  return (cfg->claim_prefix != NULL) ? cfg->claim_prefix : OIDC_DEFAULT_CLAIM_PREFIX;
542
2.75k
}
543
544
0
#define OIDC_MAX_NUMBER_OF_STATE_COOKIES_MIN 0
545
0
#define OIDC_MAX_NUMBER_OF_STATE_COOKIES_MAX 255
546
547
const char *oidc_cmd_max_number_of_state_cookies_set(cmd_parms *cmd, void *struct_ptr, const char *arg1,
548
0
                 const char *arg2) {
549
0
  oidc_cfg_t *cfg = (oidc_cfg_t *)ap_get_module_config(cmd->server->module_config, &auth_openidc_module);
550
0
  const char *rv =
551
0
      oidc_cfg_parse_int_min_max(cmd->pool, arg1, &cfg->max_number_of_state_cookies,
552
0
               OIDC_MAX_NUMBER_OF_STATE_COOKIES_MIN, OIDC_MAX_NUMBER_OF_STATE_COOKIES_MAX);
553
0
  if ((rv == NULL) && (arg2 != NULL))
554
0
    rv = oidc_cfg_parse_boolean(cmd->pool, arg2, &cfg->delete_oldest_state_cookies);
555
0
  return OIDC_CONFIG_DIR_RV(cmd, rv);
556
0
}
557
558
#define OIDC_DEFAULT_MAX_NUMBER_OF_STATE_COOKIES 7
559
OIDC_CFG_MEMBER_FUNC_TYPE_GET(max_number_of_state_cookies, int, OIDC_DEFAULT_MAX_NUMBER_OF_STATE_COOKIES)
560
561
#define OIDC_DEFAULT_DELETE_OLDEST_STATE_COOKIES 0
562
OIDC_CFG_MEMBER_FUNC_TYPE_GET(delete_oldest_state_cookies, int, OIDC_DEFAULT_DELETE_OLDEST_STATE_COOKIES)
563
564
0
const char *oidc_cmd_x_forwarded_headers_set(cmd_parms *cmd, void *m, const char *arg) {
565
0
  oidc_cfg_t *cfg = (oidc_cfg_t *)ap_get_module_config(cmd->server->module_config, &auth_openidc_module);
566
0
  static const oidc_cfg_option_t options[] = {{OIDC_HDR_NONE, "none"},
567
0
                {OIDC_HDR_X_FORWARDED_HOST, OIDC_HTTP_HDR_X_FORWARDED_HOST},
568
0
                {OIDC_HDR_X_FORWARDED_PORT, OIDC_HTTP_HDR_X_FORWARDED_PORT},
569
0
                {OIDC_HDR_X_FORWARDED_PROTO, OIDC_HTTP_HDR_X_FORWARDED_PROTO},
570
0
                {OIDC_HDR_FORWARDED, OIDC_HTTP_HDR_FORWARDED}};
571
0
  int v = OIDC_CONFIG_POS_INT_UNSET;
572
0
  const char *rv = oidc_cfg_parse_option(cmd->pool, options, OIDC_CFG_OPTIONS_SIZE(options), arg, &v);
573
0
  if ((rv == NULL) && (v != OIDC_CONFIG_POS_INT_UNSET)) {
574
    // NB: cannot use |= with UNSET/-1 !
575
0
    if (cfg->x_forwarded_headers == OIDC_CONFIG_POS_INT_UNSET)
576
0
      cfg->x_forwarded_headers = OIDC_HDR_NONE;
577
0
    cfg->x_forwarded_headers |= v;
578
0
  }
579
0
  return OIDC_CONFIG_DIR_RV(cmd, rv);
580
0
}
581
582
#define OIDC_DEFAULT_X_FORWARDED_HEADERS OIDC_HDR_NONE
583
OIDC_CFG_MEMBER_FUNC_TYPE_GET(x_forwarded_headers, oidc_hdr_x_forwarded_t, OIDC_DEFAULT_X_FORWARDED_HEADERS)
584
585
12.1k
#define OIDC_CHECK_X_FORWARDED_HDR_LOG_DISABLE "OIDC_CHECK_X_FORWARDED_HDR_LOG_DISABLE"
586
587
static void oidc_check_x_forwarded_hdr(request_rec *r, const oidc_hdr_x_forwarded_t x_forwarded_headers,
588
               const oidc_hdr_x_forwarded_t hdr_type, const char *hdr_str,
589
12.1k
               const char *(hdr_func)(const request_rec *r)) {
590
12.1k
  apr_byte_t suppress = oidc_util_spaced_string_contains(
591
12.1k
      r->pool, apr_table_get(r->subprocess_env, OIDC_CHECK_X_FORWARDED_HDR_LOG_DISABLE), hdr_str);
592
12.1k
  if (hdr_func(r)) {
593
1.11k
    if (!(x_forwarded_headers & hdr_type) && !suppress)
594
1.11k
      oidc_warn(r, "header %s received but %s not configured for it", hdr_str, OIDCXForwardedHeaders);
595
11.0k
  } else {
596
11.0k
    if ((x_forwarded_headers & hdr_type) && !suppress)
597
11.0k
      oidc_warn(r, "%s configured for header %s but not found in request", OIDCXForwardedHeaders,
598
11.0k
          hdr_str);
599
11.0k
  }
600
12.1k
}
601
602
3.04k
void oidc_cfg_x_forwarded_headers_check(request_rec *r, oidc_hdr_x_forwarded_t x_forwarded_headers) {
603
3.04k
  oidc_check_x_forwarded_hdr(r, x_forwarded_headers, OIDC_HDR_X_FORWARDED_HOST, OIDC_HTTP_HDR_X_FORWARDED_HOST,
604
3.04k
           oidc_http_hdr_in_x_forwarded_host_get);
605
3.04k
  oidc_check_x_forwarded_hdr(r, x_forwarded_headers, OIDC_HDR_X_FORWARDED_PORT, OIDC_HTTP_HDR_X_FORWARDED_PORT,
606
3.04k
           oidc_http_hdr_in_x_forwarded_port_get);
607
3.04k
  oidc_check_x_forwarded_hdr(r, x_forwarded_headers, OIDC_HDR_X_FORWARDED_PROTO, OIDC_HTTP_HDR_X_FORWARDED_PROTO,
608
3.04k
           oidc_http_hdr_in_x_forwarded_proto_get);
609
3.04k
  oidc_check_x_forwarded_hdr(r, x_forwarded_headers, OIDC_HDR_FORWARDED, OIDC_HTTP_HDR_FORWARDED,
610
3.04k
           oidc_http_hdr_in_forwarded_get);
611
3.04k
}
612
613
0
#define OIDC_STATE_INPUT_HEADERS_AS_NONE "none"
614
0
#define OIDC_STATE_INPUT_HEADERS_AS_USER_AGENT "user-agent"
615
0
#define OIDC_STATE_INPUT_HEADERS_AS_X_FORWARDED_FOR "x-forwarded-for"
616
0
#define OIDC_STATE_INPUT_HEADERS_AS_BOTH "both"
617
618
/*
619
 * define which header we use for calculating the fingerprint of the state during authentication
620
 */
621
0
const char *oidc_cmd_state_input_headers_set(cmd_parms *cmd, void *m, const char *arg) {
622
0
  oidc_cfg_t *cfg = (oidc_cfg_t *)ap_get_module_config(cmd->server->module_config, &auth_openidc_module);
623
0
  static const oidc_cfg_option_t options[] = {
624
0
      {OIDC_STATE_INPUT_HEADERS_NONE, OIDC_STATE_INPUT_HEADERS_AS_NONE},
625
0
      {OIDC_STATE_INPUT_HEADERS_USER_AGENT, OIDC_STATE_INPUT_HEADERS_AS_USER_AGENT},
626
0
      {OIDC_STATE_INPUT_HEADERS_X_FORWARDED_FOR, OIDC_STATE_INPUT_HEADERS_AS_X_FORWARDED_FOR},
627
0
      {OIDC_STATE_INPUT_HEADERS_USER_AGENT | OIDC_STATE_INPUT_HEADERS_X_FORWARDED_FOR,
628
0
       OIDC_STATE_INPUT_HEADERS_AS_BOTH}};
629
0
  const char *rv =
630
0
      oidc_cfg_parse_option(cmd->pool, options, OIDC_CFG_OPTIONS_SIZE(options), arg, &cfg->state_input_headers);
631
0
  return OIDC_CONFIG_DIR_RV(cmd, rv);
632
0
}
633
634
#define OIDC_DEFAULT_STATE_INPUT_HEADERS OIDC_STATE_INPUT_HEADERS_USER_AGENT
635
OIDC_CFG_MEMBER_FUNC_TYPE_GET(state_input_headers, oidc_state_input_hdrs_t, OIDC_DEFAULT_STATE_INPUT_HEADERS)
636
637
0
const char *oidc_cmd_post_preserve_templates_set(cmd_parms *cmd, void *m, const char *arg1, const char *arg2) {
638
0
  oidc_cfg_t *cfg = (oidc_cfg_t *)ap_get_module_config(cmd->server->module_config, &auth_openidc_module);
639
0
  const char *rv = NULL;
640
0
  if (arg1 != NULL)
641
0
    rv = oidc_cfg_parse_filename(cmd->pool, arg1, &cfg->post_preserve_template);
642
0
  if ((rv == NULL) && (arg2 != NULL))
643
0
    rv = oidc_cfg_parse_filename(cmd->pool, arg2, &cfg->post_restore_template);
644
0
  return OIDC_CONFIG_DIR_RV(cmd, rv);
645
0
}
646
647
OIDC_CFG_MEMBER_FUNC_GET(post_preserve_template, const char *)
648
OIDC_CFG_MEMBER_FUNC_GET(post_restore_template, const char *)
649
650
0
const char *oidc_cmd_ca_bundle_path_set(cmd_parms *cmd, void *ptr, const char *arg) {
651
0
  oidc_cfg_t *cfg = (oidc_cfg_t *)ap_get_module_config(cmd->server->module_config, &auth_openidc_module);
652
0
  const char *rv = oidc_cfg_parse_filename(cmd->pool, arg, &cfg->ca_bundle_path);
653
0
  return OIDC_CONFIG_DIR_RV(cmd, rv);
654
0
}
655
656
OIDC_CFG_MEMBER_FUNC_GET(ca_bundle_path, const char *)
657
658
0
const char *oidc_cmd_metadata_dir_set(cmd_parms *cmd, void *ptr, const char *arg) {
659
0
  oidc_cfg_t *cfg = (oidc_cfg_t *)ap_get_module_config(cmd->server->module_config, &auth_openidc_module);
660
0
  const char *rv = oidc_cfg_parse_dirname(cmd->pool, arg, &cfg->metadata_dir);
661
0
  return OIDC_CONFIG_DIR_RV(cmd, rv);
662
0
}
663
664
OIDC_CFG_MEMBER_FUNC_GET(metadata_dir, const char *)
665
666
#define OIDC_DEFAULT_COOKIE_HTTPONLY 1
667
0
OIDC_CFG_MEMBER_FUNCS_BOOL(cookie_http_only, OIDC_DEFAULT_COOKIE_HTTPONLY)
668
0
669
0
#define OIDC_SAMESITE_COOKIE_OFF_STR "Off"
670
0
#define OIDC_SAMESITE_COOKIE_ON_STR "On"
671
0
#define OIDC_SAMESITE_COOKIE_DISABLED_STR "Disabled"
672
0
#define OIDC_SAMESITE_COOKIE_NONE_STR "None"
673
0
#define OIDC_SAMESITE_COOKIE_LAX_STR "Lax"
674
0
#define OIDC_SAMESITE_COOKIE_STRICT_STR "Strict"
675
676
/*
677
 * define which header we use for calculating the fingerprint of the state during authentication
678
 */
679
const char *oidc_cmd_cookie_same_site_session_set(cmd_parms *cmd, void *m, const char *arg1, const char *arg2,
680
0
              const char *arg3) {
681
0
  oidc_cfg_t *cfg = (oidc_cfg_t *)ap_get_module_config(cmd->server->module_config, &auth_openidc_module);
682
  // NB: On is made equal to Lax here and Off is equal to None (backwards compatibility)
683
0
  static const oidc_cfg_option_t options[] = {{OIDC_SAMESITE_COOKIE_NONE, OIDC_SAMESITE_COOKIE_OFF_STR},
684
0
                {OIDC_SAMESITE_COOKIE_LAX, OIDC_SAMESITE_COOKIE_ON_STR},
685
0
                {OIDC_SAMESITE_COOKIE_DISABLED, OIDC_SAMESITE_COOKIE_DISABLED_STR},
686
0
                {OIDC_SAMESITE_COOKIE_NONE, OIDC_SAMESITE_COOKIE_NONE_STR},
687
0
                {OIDC_SAMESITE_COOKIE_LAX, OIDC_SAMESITE_COOKIE_LAX_STR},
688
0
                {OIDC_SAMESITE_COOKIE_STRICT, OIDC_SAMESITE_COOKIE_STRICT_STR}};
689
0
  const char *rv = oidc_cfg_parse_option_ignore_case(cmd->pool, options, OIDC_CFG_OPTIONS_SIZE(options), arg1,
690
0
                 &cfg->cookie_same_site_session);
691
0
  if ((rv == NULL) && (arg2 != NULL)) {
692
0
    static const oidc_cfg_option_t state_options[] = {
693
0
        {OIDC_SAMESITE_COOKIE_DISABLED, OIDC_SAMESITE_COOKIE_DISABLED_STR},
694
0
        {OIDC_SAMESITE_COOKIE_NONE, OIDC_SAMESITE_COOKIE_NONE_STR},
695
0
        {OIDC_SAMESITE_COOKIE_LAX, OIDC_SAMESITE_COOKIE_LAX_STR}};
696
0
    rv = oidc_cfg_parse_option_ignore_case(cmd->pool, state_options, OIDC_CFG_OPTIONS_SIZE(state_options),
697
0
                   arg2, &cfg->cookie_same_site_state);
698
0
  }
699
0
  if ((rv == NULL) && (arg3 != NULL)) {
700
0
    static const oidc_cfg_option_t csrf_options[] = {
701
0
        {OIDC_SAMESITE_COOKIE_DISABLED, OIDC_SAMESITE_COOKIE_DISABLED_STR},
702
0
        {OIDC_SAMESITE_COOKIE_NONE, OIDC_SAMESITE_COOKIE_NONE_STR},
703
0
        {OIDC_SAMESITE_COOKIE_LAX, OIDC_SAMESITE_COOKIE_LAX_STR},
704
0
        {OIDC_SAMESITE_COOKIE_STRICT, OIDC_SAMESITE_COOKIE_STRICT_STR}};
705
0
    rv = oidc_cfg_parse_option_ignore_case(cmd->pool, csrf_options, OIDC_CFG_OPTIONS_SIZE(csrf_options),
706
0
                   arg3, &cfg->cookie_same_site_discovery_csrf);
707
0
  }
708
0
  return OIDC_CONFIG_DIR_RV(cmd, rv);
709
0
}
710
711
#define OIDC_DEFAULT_COOKIE_SAME_SITE OIDC_SAMESITE_COOKIE_LAX
712
OIDC_CFG_MEMBER_FUNC_TYPE_GET(cookie_same_site_session, oidc_samesite_cookie_t, OIDC_DEFAULT_COOKIE_SAME_SITE)
713
714
#define OIDC_DEFAULT_COOKIE_SAME_SITE_STATE oidc_cfg_cookie_same_site_session_get(cfg)
715
OIDC_CFG_MEMBER_FUNC_TYPE_GET(cookie_same_site_state, oidc_samesite_cookie_t, OIDC_DEFAULT_COOKIE_SAME_SITE_STATE)
716
717
#define OIDC_DEFAULT_COOKIE_SAME_SITE_CSRF_DISCOVERY oidc_cfg_cookie_same_site_session_get(cfg)
718
OIDC_CFG_MEMBER_FUNC_TYPE_GET(cookie_same_site_discovery_csrf, oidc_samesite_cookie_t,
719
            OIDC_DEFAULT_COOKIE_SAME_SITE_CSRF_DISCOVERY)
720
721
#define OIDC_DEFAULT_SESSION_FALLBACK_TO_COOKIE 0
722
0
OIDC_CFG_MEMBER_FUNCS_BOOL(session_cache_fallback_to_cookie, OIDC_DEFAULT_SESSION_FALLBACK_TO_COOKIE)
723
0
724
0
/* masking secrets in the debug log is the default; turning it off is a deliberate, logged choice */
725
0
#define OIDC_DEFAULT_DEBUG_MASK_SECRETS 1
726
0
OIDC_CFG_MEMBER_FUNCS_BOOL(debug_mask_secrets, OIDC_DEFAULT_DEBUG_MASK_SECRETS)
727
0
728
0
#define OIDC_DEFAULT_CLAIM_DELIMITER ","
729
1.13k
OIDC_CFG_MEMBER_FUNCS_STR_DEF(claim_delimiter, NULL, OIDC_DEFAULT_CLAIM_DELIMITER)
Unexecuted instantiation: oidc_cmd_claim_delimiter_set
oidc_cfg_claim_delimiter_get
Line
Count
Source
729
OIDC_CFG_MEMBER_FUNCS_STR_DEF(claim_delimiter, NULL, OIDC_DEFAULT_CLAIM_DELIMITER)
730
731
150
OIDC_CFG_MEMBER_FUNCS_STR_DEF(metrics_path, NULL, NULL)
Unexecuted instantiation: oidc_cmd_metrics_path_set
oidc_cfg_metrics_path_get
Line
Count
Source
731
OIDC_CFG_MEMBER_FUNCS_STR_DEF(metrics_path, NULL, NULL)
732
733
#define OIDC_DEFAULT_LOGOUT_X_FRAME_OPTIONS "DENY"
734
23
OIDC_CFG_MEMBER_FUNCS_STR_DEF(logout_x_frame_options, NULL, OIDC_DEFAULT_LOGOUT_X_FRAME_OPTIONS)
Unexecuted instantiation: oidc_cmd_logout_x_frame_options_set
oidc_cfg_logout_x_frame_options_get
Line
Count
Source
734
OIDC_CFG_MEMBER_FUNCS_STR_DEF(logout_x_frame_options, NULL, OIDC_DEFAULT_LOGOUT_X_FRAME_OPTIONS)
735
736
#define OIDC_STATE_TIMEOUT_MIN 1
737
#define OIDC_STATE_TIMEOUT_MAX (3600 * 24 * 30)
738
#define OIDC_DEFAULT_STATE_TIMEOUT 300
739
740
0
OIDC_CFG_MEMBER_FUNCS_INT(state_timeout, OIDC_STATE_TIMEOUT_MIN, OIDC_STATE_TIMEOUT_MAX, OIDC_DEFAULT_STATE_TIMEOUT)
741
0
742
0
#define OIDC_SESSION_CLIENT_COOKIE_CHUNK_SIZE_MIN 256
743
0
#define OIDC_SESSION_CLIENT_COOKIE_CHUNK_SIZE_MAX (1024 * 64)
744
0
#define OIDC_DEFAULT_SESSION_CLIENT_COOKIE_CHUNK_SIZE 4000
745
0
746
0
/* NB: 0 is accepted on top of the range and means "never chunk", which is what the
747
0
 * runtime already implements in oidc_http_set_chunked_cookie() */
748
0
OIDC_CFG_MEMBER_FUNCS_INT_EXT(session_cookie_chunk_size,
749
            oidc_cfg_parse_int_min_max_or_zero(cmd->pool, arg, &v,
750
                 OIDC_SESSION_CLIENT_COOKIE_CHUNK_SIZE_MIN,
751
                 OIDC_SESSION_CLIENT_COOKIE_CHUNK_SIZE_MAX),
752
            OIDC_DEFAULT_SESSION_CLIENT_COOKIE_CHUNK_SIZE)
753
754
#define OIDC_PROVIDER_METADATA_REFRESH_INTERVAL_MIN 30
755
#define OIDC_PROVIDER_METADATA_REFRESH_INTERVAL_MAX (3600 * 24 * 365)
756
#define OIDC_DEFAULT_PROVIDER_METADATA_REFRESH_INTERVAL 0
757
758
0
OIDC_CFG_MEMBER_FUNCS_INT(provider_metadata_refresh_interval, OIDC_PROVIDER_METADATA_REFRESH_INTERVAL_MIN,
759
0
        OIDC_PROVIDER_METADATA_REFRESH_INTERVAL_MAX, OIDC_DEFAULT_PROVIDER_METADATA_REFRESH_INTERVAL)
760
0
761
0
#define OIDC_CFG_MEMBER_FUNCS_HASHTABLE(member)                                                                        \
762
0
  const char *oidc_cmd_##member##_set(cmd_parms *cmd, void *ptr, const char *arg) {                              \
763
0
    oidc_cfg_t *cfg =                                                                                      \
764
0
        (oidc_cfg_t *)ap_get_module_config(cmd->server->module_config, &auth_openidc_module);              \
765
0
    if (cfg->member == NULL)                                                                               \
766
0
      cfg->member = apr_hash_make(cmd->pool);                                                        \
767
0
    apr_hash_set(cfg->member, arg, APR_HASH_KEY_STRING, arg);                                              \
768
0
    return NULL;                                                                                           \
769
0
  }                                                                                                              \
770
                                                                                                                       \
771
  OIDC_CFG_MEMBER_FUNC_GET(member, apr_hash_t *)
772
773
0
OIDC_CFG_MEMBER_FUNCS_HASHTABLE(white_listed_claims)
774
0
OIDC_CFG_MEMBER_FUNCS_HASHTABLE(black_listed_claims)
775
0
OIDC_CFG_MEMBER_FUNCS_HASHTABLE(redirect_urls_allowed)
776
0
OIDC_CFG_MEMBER_FUNCS_HASHTABLE(discover_issuers_allowed)
777
778
#define OIDC_CFG_MEMBER_FUNCS_ABS_OR_REL_URI(member)                                                                   \
779
0
  const char *oidc_cmd_##member##_set(cmd_parms *cmd, void *ptr, const char *arg) {                              \
780
0
    oidc_cfg_t *cfg =                                                                                      \
781
0
        (oidc_cfg_t *)ap_get_module_config(cmd->server->module_config, &auth_openidc_module);              \
782
0
    const char *rv = oidc_cfg_parse_relative_or_absolute_url(cmd->pool, arg, &cfg->member);                \
783
0
    return OIDC_CONFIG_DIR_RV(cmd, rv);                                                                    \
784
0
  }                                                                                                              \
785
                                                                                                                       \
786
  OIDC_CFG_MEMBER_FUNC_GET(member, const char *)
787
788
0
OIDC_CFG_MEMBER_FUNCS_ABS_OR_REL_URI(redirect_uri)
789
0
OIDC_CFG_MEMBER_FUNCS_ABS_OR_REL_URI(default_sso_url)
790
0
OIDC_CFG_MEMBER_FUNCS_ABS_OR_REL_URI(default_slo_url)
791
792
typedef struct oidc_cfg_cleanup_ctx_t {
793
  oidc_cfg_t *cfg;
794
  apr_pool_t *pool;
795
  server_rec *svr;
796
} oidc_cfg_cleanup_ctx_t;
797
798
/*
799
 * destroy a server config record and its members
800
 */
801
0
apr_byte_t oidc_cfg_server_destroy(apr_pool_t *pool, server_rec *s, oidc_cfg_t *cfg) {
802
0
  if ((cfg->cache.impl) && (cfg->cache.impl->destroy))
803
0
    cfg->cache.impl->destroy(pool, s);
804
0
  cfg->cache.impl = NULL;
805
0
  oidc_cfg_provider_destroy(cfg->provider);
806
0
  cfg->provider = NULL;
807
0
  oidc_cfg_oauth_destroy(cfg->oauth);
808
0
  cfg->oauth = NULL;
809
0
  oidc_jwk_list_destroy(cfg->public_keys);
810
0
  cfg->public_keys = NULL;
811
0
  oidc_jwk_list_destroy(cfg->private_keys);
812
0
  cfg->private_keys = NULL;
813
0
  return TRUE;
814
0
}
815
816
0
static apr_status_t oidc_cfg_server_cleanup(void *data) {
817
0
  oidc_cfg_cleanup_ctx_t *ctx = (oidc_cfg_cleanup_ctx_t *)data;
818
0
  oidc_cfg_t *cfg = ctx->cfg;
819
0
  return oidc_cfg_server_destroy(ctx->pool, ctx->svr, cfg) ? APR_SUCCESS : APR_EGENERAL;
820
0
}
821
822
40
static oidc_cfg_t *oidc_cfg_server_alloc(apr_pool_t *pool, server_rec *s) {
823
40
  oidc_cfg_t *c = apr_pcalloc(pool, sizeof(oidc_cfg_t));
824
40
  oidc_cfg_cleanup_ctx_t *ctx = apr_pcalloc(pool, sizeof(oidc_cfg_cleanup_ctx_t));
825
40
  ctx->cfg = c;
826
  // pconf pool used at destruction time
827
40
  ctx->pool = pool;
828
40
  ctx->svr = s;
829
  // register a cleanup handler on the config pool to handle graceful restarts without increasing
830
  // memory consumption; this MUST be a *pre*-cleanup: libapr registers its own regular cleanups
831
  // for the cache global mutex's POSIX semaphore and the shm segment on this same pool when they
832
  // are created at post_config time, and regular cleanups run in reverse order of registration,
833
  // so a regular registration here (which happens much earlier, at config-parse time) would run
834
  // only AFTER libapr has already closed/unmapped those objects, making the mutex unlock/destroy
835
  // in oidc_cache_shm_destroy() dereference an unmapped semaphore and segfault the parent process
836
  // on a graceful restart; pre-cleanups are guaranteed to run before all regular cleanups
837
40
  apr_pool_pre_cleanup_register(pool, ctx, oidc_cfg_server_cleanup);
838
40
  return c;
839
40
}
840
841
/*
842
 * create a new server config record with defaults
843
 */
844
480
#define OIDC_SVR_M_CREATE_PTR(type, name) c->name = NULL;
845
800
#define OIDC_SVR_M_CREATE_INT(name) c->name = OIDC_CONFIG_POS_INT_UNSET;
846
0
#define OIDC_SVR_M_MERGE_PTR(type, name) c->name = _oidc_cfg_merge_ptr(add->name, base->name);
847
0
#define OIDC_SVR_M_MERGE_INT(name) c->name = _oidc_cfg_merge_pos_int(add->name, base->name);
848
849
40
void *oidc_cfg_server_create(apr_pool_t *pool, server_rec *svr) {
850
40
  oidc_cfg_t *c = oidc_cfg_server_alloc(pool, svr);
851
40
  c->svr = svr;
852
853
40
  c->merged = FALSE;
854
  /* nothing to inherit from: whatever OIDCRedirectURI this config ends up with is its own */
855
40
  c->redirect_uri_inherited = FALSE;
856
857
800
  OIDC_SVR_CFG_SIMPLE_MEMBERS(OIDC_SVR_M_CREATE_PTR, OIDC_SVR_M_CREATE_INT)
858
40
  c->public_keys = NULL;
859
40
  c->private_keys = NULL;
860
861
40
  c->provider = oidc_cfg_provider_create(pool);
862
40
  c->oauth = oidc_cfg_oauth_create(pool);
863
40
  oidc_cfg_cache_create_server_config(c);
864
865
40
  c->http_timeout_long.request_timeout = OIDC_CONFIG_POS_INT_UNSET;
866
40
  c->http_timeout_long.connect_timeout = OIDC_DEFAULT_HTTP_CONNECT_TIMEOUT_LONG;
867
40
  c->http_timeout_long.retries = OIDC_DEFAULT_HTTP_RETRIES_LONG;
868
40
  c->http_timeout_long.retry_interval = OIDC_DEFAULT_HTTP_RETRY_INTERVAL_LONG;
869
40
  c->http_timeout_short.request_timeout = OIDC_CONFIG_POS_INT_UNSET;
870
40
  c->http_timeout_short.connect_timeout = OIDC_DEFAULT_HTTP_CONNECT_TIMEOUT_SHORT;
871
40
  c->http_timeout_short.retries = OIDC_DEFAULT_HTTP_RETRIES_SHORT;
872
40
  c->http_timeout_short.retry_interval = OIDC_DEFAULT_HTTP_RETRY_INTERVAL_SHORT;
873
874
40
  c->remote_user_claim.claim_name = NULL;
875
40
  c->remote_user_claim.reg_exp = NULL;
876
40
  c->remote_user_claim.replace = NULL;
877
878
40
  c->outgoing_proxy.host_port = NULL;
879
40
  c->outgoing_proxy.username_password = NULL;
880
40
  c->outgoing_proxy.auth_type = OIDC_CONFIG_POS_INT_UNSET;
881
882
40
  c->crypto_passphrase.secret1 = NULL;
883
40
  c->crypto_passphrase.secret2 = NULL;
884
40
  c->crypto_passphrase.derived_key1_set = FALSE;
885
40
  c->crypto_passphrase.derived_key2_set = FALSE;
886
887
40
  c->info_hook_data = NULL;
888
40
  c->metrics_hook_data = NULL;
889
890
40
  c->black_listed_claims = NULL;
891
40
  c->white_listed_claims = NULL;
892
40
  c->filter_claims_expr = NULL;
893
894
40
  c->redirect_urls_allowed = NULL;
895
40
  c->discover_issuers_allowed = NULL;
896
897
40
  return c;
898
40
}
899
900
/*
901
 * merge an http_timeout struct: "add" wins as a whole if it has been configured
902
 */
903
static void _oidc_cfg_merge_http_timeout(oidc_http_timeout_t *c, const oidc_http_timeout_t *add,
904
0
           const oidc_http_timeout_t *base) {
905
0
  const oidc_http_timeout_t *src = add->request_timeout != OIDC_CONFIG_POS_INT_UNSET ? add : base;
906
0
  c->request_timeout = src->request_timeout;
907
0
  c->connect_timeout = src->connect_timeout;
908
0
  c->retries = src->retries;
909
0
  c->retry_interval = src->retry_interval;
910
0
}
911
912
/*
913
 * merge the remote_user_claim struct: "add" wins as a whole if it has been configured
914
 */
915
static void _oidc_cfg_merge_remote_user_claim(oidc_remote_user_claim_t *c, const oidc_remote_user_claim_t *add,
916
0
                const oidc_remote_user_claim_t *base) {
917
0
  const oidc_remote_user_claim_t *src = add->claim_name != NULL ? add : base;
918
0
  c->claim_name = src->claim_name;
919
0
  c->reg_exp = src->reg_exp;
920
0
  c->replace = src->replace;
921
0
}
922
923
/*
924
 * merge the outgoing_proxy struct: "add" wins as a whole if it has been configured
925
 */
926
static void _oidc_cfg_merge_outgoing_proxy(oidc_http_outgoing_proxy_t *c, const oidc_http_outgoing_proxy_t *add,
927
0
             const oidc_http_outgoing_proxy_t *base) {
928
0
  const oidc_http_outgoing_proxy_t *src = add->host_port != NULL ? add : base;
929
0
  c->host_port = src->host_port;
930
0
  c->username_password = src->username_password;
931
0
  c->auth_type = src->auth_type;
932
0
}
933
934
/*
935
 * merge the crypto_passphrase struct: "add" wins as a whole if it has been configured
936
 */
937
static void _oidc_cfg_merge_crypto_passphrase(oidc_crypto_passphrase_t *c, const oidc_crypto_passphrase_t *add,
938
0
                const oidc_crypto_passphrase_t *base) {
939
0
  const oidc_crypto_passphrase_t *src = add->secret1 != NULL ? add : base;
940
0
  c->secret1 = src->secret1;
941
0
  c->secret2 = src->secret2;
942
  /* Keep derived keys paired with the selected secrets, regardless of merge/derivation order. */
943
0
  c->derived_key1_set = src->derived_key1_set;
944
0
  if (src->derived_key1_set)
945
0
    _oidc_memcpy(c->derived_key1, src->derived_key1, OIDC_CRYPTO_PASSPHRASE_DERIVED_KEY_LEN);
946
0
  c->derived_key2_set = src->derived_key2_set;
947
0
  if (src->derived_key2_set)
948
0
    _oidc_memcpy(c->derived_key2, src->derived_key2, OIDC_CRYPTO_PASSPHRASE_DERIVED_KEY_LEN);
949
0
}
950
951
/*
952
 * merge a new server config with a base one
953
 */
954
0
void *oidc_cfg_server_merge(apr_pool_t *pool, void *BASE, void *ADD) {
955
0
  const oidc_cfg_t *base = (const oidc_cfg_t *)BASE;
956
0
  const oidc_cfg_t *add = (const oidc_cfg_t *)ADD;
957
958
0
  oidc_cfg_t *c = oidc_cfg_server_alloc(pool, add->svr);
959
960
0
  c->provider = oidc_cfg_provider_create(pool);
961
0
  c->oauth = oidc_cfg_oauth_create(pool);
962
963
0
  c->merged = TRUE;
964
  /* record where the merged redirect_uri came from while "add" (this vhost's own config) and
965
   * "base" can still be told apart: the merge below collapses them into a single value */
966
0
  c->redirect_uri_inherited = (add->redirect_uri == NULL) && (base->redirect_uri != NULL);
967
968
0
  oidc_cfg_provider_merge(pool, c->provider, base->provider, add->provider);
969
0
  oidc_cfg_oauth_merge(pool, c->oauth, base->oauth, add->oauth);
970
0
  oidc_cfg_cache_merge_server_config(c, base, add);
971
972
0
  OIDC_SVR_CFG_SIMPLE_MEMBERS(OIDC_SVR_M_MERGE_PTR, OIDC_SVR_M_MERGE_INT)
973
0
  c->public_keys = oidc_jwk_list_copy(pool, _oidc_cfg_merge_ptr(add->public_keys, base->public_keys));
974
0
  c->private_keys = oidc_jwk_list_copy(pool, _oidc_cfg_merge_ptr(add->private_keys, base->private_keys));
975
976
0
  _oidc_cfg_merge_http_timeout(&c->http_timeout_long, &add->http_timeout_long, &base->http_timeout_long);
977
0
  _oidc_cfg_merge_http_timeout(&c->http_timeout_short, &add->http_timeout_short, &base->http_timeout_short);
978
979
0
  _oidc_cfg_merge_remote_user_claim(&c->remote_user_claim, &add->remote_user_claim, &base->remote_user_claim);
980
981
0
  _oidc_cfg_merge_outgoing_proxy(&c->outgoing_proxy, &add->outgoing_proxy, &base->outgoing_proxy);
982
0
  _oidc_cfg_merge_crypto_passphrase(&c->crypto_passphrase, &add->crypto_passphrase, &base->crypto_passphrase);
983
984
0
  c->info_hook_data = _oidc_cfg_merge_ptr(add->info_hook_data, base->info_hook_data);
985
0
  c->metrics_hook_data = _oidc_cfg_merge_ptr(add->metrics_hook_data, base->metrics_hook_data);
986
987
0
  c->black_listed_claims = _oidc_cfg_merge_ptr(add->black_listed_claims, base->black_listed_claims);
988
0
  c->white_listed_claims = _oidc_cfg_merge_ptr(add->white_listed_claims, base->white_listed_claims);
989
0
  c->filter_claims_expr = _oidc_cfg_merge_ptr(add->filter_claims_expr, base->filter_claims_expr);
990
991
0
  c->redirect_urls_allowed = _oidc_cfg_merge_ptr(add->redirect_urls_allowed, base->redirect_urls_allowed);
992
0
  c->discover_issuers_allowed =
993
0
      _oidc_cfg_merge_ptr(add->discover_issuers_allowed, base->discover_issuers_allowed);
994
995
0
  return c;
996
0
}
997
998
/*
999
 * Build a read-only request view with a private OAuth struct, allowing metadata endpoints to
1000
 * change without mutating shared server state. Other members remain shared.
1001
 */
1002
0
oidc_cfg_t *oidc_cfg_request_view(apr_pool_t *pool, const oidc_cfg_t *c) {
1003
0
  oidc_cfg_t *rc = apr_pmemdup(pool, c, sizeof(*c));
1004
0
  rc->oauth = oidc_cfg_oauth_shallow_copy(pool, c->oauth);
1005
0
  return rc;
1006
0
}
1007
1008
/*
1009
 * initialize before the post config handler runs
1010
 */
1011
38
void oidc_pre_config_init(void) {
1012
38
#if OPENSSL_API_COMPAT < 0x10100000L
1013
38
  ERR_load_crypto_strings();
1014
38
  OpenSSL_add_all_algorithms();
1015
38
  OpenSSL_add_all_digests();
1016
#else
1017
  OPENSSL_init_crypto(0, NULL);
1018
#endif
1019
38
}
1020
1021
232k
oidc_provider_t *oidc_cfg_provider_get(oidc_cfg_t *cfg) {
1022
232k
  return cfg->provider;
1023
232k
}
1024
1025
0
int oidc_cfg_merged_get(const oidc_cfg_t *cfg) {
1026
0
  return cfg->merged;
1027
0
}
1028
1029
0
int oidc_cfg_redirect_uri_inherited_get(const oidc_cfg_t *cfg) {
1030
0
  return cfg->redirect_uri_inherited;
1031
0
}
1032
1033
static oidc_cache_mutex_t *_oidc_refresh_mutex = NULL;
1034
1035
22
oidc_cache_mutex_t *oidc_cfg_refresh_mutex_get(const oidc_cfg_t *cfg) {
1036
22
  return _oidc_refresh_mutex;
1037
22
}
1038
1039
38
int oidc_cfg_post_config(apr_pool_t *pool, oidc_cfg_t *cfg, server_rec *s) {
1040
38
  if (cfg->cache.impl == NULL)
1041
0
    cfg->cache.impl = &oidc_cache_shm;
1042
38
  if ((cfg->cache.impl->post_config != NULL) && (cfg->cache.impl->post_config(pool, s) != OK))
1043
0
    return HTTP_INTERNAL_SERVER_ERROR;
1044
38
  if (_oidc_refresh_mutex == NULL) {
1045
    // NB: use the process pool here as the mutex is a process-wide singleton
1046
38
    _oidc_refresh_mutex = oidc_cache_mutex_create(s->process->pool, TRUE);
1047
38
    if (oidc_cache_mutex_post_config(s->process->pool, s, _oidc_refresh_mutex, "refresh") != TRUE)
1048
0
      return HTTP_INTERNAL_SERVER_ERROR;
1049
38
  }
1050
38
  if ((cfg->metrics_hook_data != NULL) && (oidc_metrics_post_config(pool, s) != TRUE))
1051
0
    return HTTP_INTERNAL_SERVER_ERROR;
1052
38
  return OK;
1053
38
}
1054
1055
0
void oidc_cfg_child_init(apr_pool_t *pool, const oidc_cfg_t *cfg, server_rec *s) {
1056
0
  if ((cfg->cache.impl->child_init != NULL) && (cfg->cache.impl->child_init(pool, s) != APR_SUCCESS))
1057
0
    oidc_serror(s, "cfg->cache->child_init failed");
1058
0
  if ((_oidc_refresh_mutex != NULL) && (oidc_cache_mutex_child_init(pool, s, _oidc_refresh_mutex) != APR_SUCCESS))
1059
0
    oidc_serror(s, "oidc_cache_mutex_child_init on refresh mutex failed");
1060
0
  if ((cfg->metrics_hook_data != NULL) && (oidc_metrics_child_init(pool, s) != APR_SUCCESS))
1061
0
    oidc_serror(s, "oidc_metrics_cache_child_init failed");
1062
0
}
1063
1064
0
void oidc_cfg_process_cleanup(oidc_cfg_t *cfg, server_rec *s) {
1065
0
  if (_oidc_refresh_mutex != NULL) {
1066
0
    if (oidc_cache_mutex_destroy(s, _oidc_refresh_mutex) != TRUE) {
1067
0
      oidc_serror(s, "oidc_cache_mutex_destroy on refresh mutex failed");
1068
0
    }
1069
    // this is a singleton, make sure we call destroy only once
1070
0
    _oidc_refresh_mutex = NULL;
1071
0
  }
1072
0
  if (cfg->metrics_hook_data != NULL) {
1073
0
    if (oidc_metrics_cleanup(s) != APR_SUCCESS) {
1074
0
      oidc_serror(s, "oidc_metrics_cleanup failed");
1075
0
    }
1076
    cfg->metrics_hook_data = NULL;
1077
0
  }
1078
0
}