Coverage Report

Created: 2026-11-12 07:05

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
246
  oidc_http_timeout_t *oidc_cfg_##member##_get(oidc_cfg_t *cfg) {                                                \
81
246
    if (cfg->member.request_timeout == OIDC_CONFIG_POS_INT_UNSET)                                          \
82
246
      /* NB: we are modifying in-config but post_config/merge has finished by now  */                \
83
246
      cfg->member.request_timeout = def_val;                                                         \
84
246
    return &cfg->member;                                                                                   \
85
246
  }
oidc_cfg_http_timeout_long_get
Line
Count
Source
80
246
  oidc_http_timeout_t *oidc_cfg_##member##_get(oidc_cfg_t *cfg) {                                                \
81
246
    if (cfg->member.request_timeout == OIDC_CONFIG_POS_INT_UNSET)                                          \
82
246
      /* NB: we are modifying in-config but post_config/merge has finished by now  */                \
83
246
      cfg->member.request_timeout = def_val;                                                         \
84
246
    return &cfg->member;                                                                                   \
85
246
  }
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
31.7k
const oidc_crypto_passphrase_t *oidc_cfg_crypto_passphrase_get(const oidc_cfg_t *cfg) {
125
31.7k
  return &cfg->crypto_passphrase;
126
31.7k
}
127
128
13.5k
const char *oidc_cfg_crypto_passphrase_secret1_get(const oidc_cfg_t *cfg) {
129
13.5k
  return cfg->crypto_passphrase.secret1;
130
13.5k
}
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
10.4k
const char *oidc_cfg_crypto_passphrase_secret2_get(const oidc_cfg_t *cfg) {
137
10.4k
  return cfg->crypto_passphrase.secret2;
138
10.4k
}
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
246
const oidc_http_outgoing_proxy_t *oidc_cfg_outgoing_proxy_get(const oidc_cfg_t *cfg) {
236
246
  return &cfg->outgoing_proxy;
237
246
}
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
6.42k
              apr_byte_t allow_mtls) {
321
  /* Build per call because private-key validation changes the candidate list. */
322
6.42k
  const char *options[9];
323
6.42k
  int i = 0;
324
6.42k
  options[i++] = OIDC_ENDPOINT_AUTH_CLIENT_SECRET_POST;
325
6.42k
  options[i++] = OIDC_ENDPOINT_AUTH_CLIENT_SECRET_BASIC;
326
6.42k
  options[i++] = OIDC_ENDPOINT_AUTH_CLIENT_SECRET_JWT;
327
6.42k
  options[i++] = OIDC_ENDPOINT_AUTH_NONE;
328
6.42k
  options[i++] = OIDC_ENDPOINT_AUTH_BEARER_ACCESS_TOKEN;
329
6.42k
  if (has_private_key)
330
6.42k
    options[i++] = OIDC_ENDPOINT_AUTH_PRIVATE_KEY_JWT;
331
6.42k
  if (allow_mtls) {
332
3.40k
    options[i++] = OIDC_ENDPOINT_AUTH_TLS_CLIENT_AUTH;
333
3.40k
    options[i++] = OIDC_ENDPOINT_AUTH_SELF_SIGNED_TLS_CLIENT_AUTH;
334
3.40k
  }
335
6.42k
  options[i] = NULL;
336
6.42k
  return oidc_cfg_parse_is_valid_option(pool, arg, options);
337
6.42k
}
338
339
398
static const char *oidc_valid_private_key_jwt_alg(apr_pool_t *pool, const char *arg) {
340
398
  static const char *options[] = {"RS256", "RS384", "RS512", "PS256", "PS384", "PS512",
341
398
#if (OIDC_JOSE_EC_SUPPORT)
342
398
          "ES256", "ES384", "ES512",
343
398
#endif
344
345
398
          NULL};
346
398
  return oidc_cfg_parse_is_valid_option(pool, arg, options);
347
398
}
348
349
6.67k
#define OIDC_ENDPOINT_AUTH_METHOD_SEPARATOR ":"
350
351
6.67k
static void oidc_cfg_endpoint_auth_parse(apr_pool_t *pool, const char *arg1, char **method, char **suffix) {
352
6.67k
  const char *arg = apr_pstrdup(pool, arg1);
353
6.67k
  char *sep = _oidc_strstr(arg, OIDC_ENDPOINT_AUTH_METHOD_SEPARATOR);
354
6.67k
  if (sep) {
355
618
    *sep = '\0';
356
618
    *suffix = apr_pstrdup(pool, ++sep);
357
618
  }
358
6.67k
  *method = apr_pstrdup(pool, arg);
359
6.67k
}
360
361
6.62k
static const char *oidc_cfg_valid_endpoint_auth_method_alg(apr_pool_t *pool, const char *arg1, apr_byte_t allow_mtls) {
362
6.62k
  const char *rv = NULL;
363
6.62k
  char *method = NULL;
364
6.62k
  char *alg = NULL;
365
6.62k
  oidc_cfg_endpoint_auth_parse(pool, arg1, &method, &alg);
366
6.62k
  if ((_oidc_strcmp(method, OIDC_ENDPOINT_AUTH_PRIVATE_KEY_JWT) == 0) && (alg != NULL)) {
367
398
    rv = oidc_valid_private_key_jwt_alg(pool, alg);
368
398
    if (rv != NULL)
369
198
      return rv;
370
398
  }
371
6.42k
  return oidc_valid_endpoint_auth_method_impl(pool, method, TRUE, allow_mtls);
372
6.62k
}
373
374
3.50k
static const char *oidc_cfg_valid_endpoint_auth_method_with_private_key(apr_pool_t *pool, const char *arg1) {
375
3.50k
  return oidc_cfg_valid_endpoint_auth_method_alg(pool, arg1, TRUE);
376
3.50k
}
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
3.11k
static const char *oidc_cfg_valid_endpoint_auth_method_no_mtls_with_private_key(apr_pool_t *pool, const char *arg1) {
383
3.11k
  return oidc_cfg_valid_endpoint_auth_method_alg(pool, arg1, FALSE);
384
3.11k
}
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
2.74k
               char **alg) {
392
2.74k
  const char *rv = oidc_cfg_get_valid_endpoint_auth_function(cfg, TRUE)(pool, arg1);
393
2.74k
  if (rv == NULL)
394
58
    oidc_cfg_endpoint_auth_parse(pool, arg1, auth, alg);
395
2.74k
  return rv;
396
2.74k
}
397
398
/*
399
 * check if the endpoint authentication method is one of the RFC 8705 mutual-TLS methods
400
 */
401
2.83k
apr_byte_t oidc_cfg_endpoint_auth_is_mtls(const char *method) {
402
2.83k
  return (_oidc_strcmp(method, OIDC_ENDPOINT_AUTH_TLS_CLIENT_AUTH) == 0) ||
403
2.83k
         (_oidc_strcmp(method, OIDC_ENDPOINT_AUTH_SELF_SIGNED_TLS_CLIENT_AUTH) == 0);
404
2.83k
}
405
406
/* Select endpoint-auth validation based on private-key availability and whether mTLS is allowed. */
407
5.43k
oidc_valid_function_t oidc_cfg_get_valid_endpoint_auth_function(const oidc_cfg_t *cfg, apr_byte_t allow_mtls) {
408
5.43k
  if (allow_mtls == FALSE)
409
2.65k
    return (cfg->private_keys != NULL) ? &oidc_cfg_valid_endpoint_auth_method_no_mtls_with_private_key
410
2.65k
               : &oidc_cfg_valid_endpoint_auth_method_no_mtls_no_private_key;
411
2.78k
  return (cfg->private_keys != NULL) ? &oidc_cfg_valid_endpoint_auth_method_with_private_key
412
2.78k
             : &oidc_cfg_valid_endpoint_auth_method_no_private_key;
413
5.43k
}
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
694
const oidc_remote_user_claim_t *oidc_cfg_remote_user_claim_get(const oidc_cfg_t *cfg) {
448
694
  return &cfg->remote_user_claim;
449
694
}
450
451
347
#define OIDC_DEFAULT_CLAIM_REMOTE_USER "sub@"
452
453
347
const char *oidc_cfg_remote_user_claim_name_get(const oidc_cfg_t *cfg) {
454
347
  return cfg->remote_user_claim.claim_name != NULL ? cfg->remote_user_claim.claim_name
455
347
               : OIDC_DEFAULT_CLAIM_REMOTE_USER;
456
347
}
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
4.14k
#define OIDC_DEFAULT_CLAIM_PREFIX "OIDC_CLAIM_"
539
540
2.07k
const char *oidc_cfg_claim_prefix_get(const oidc_cfg_t *cfg) {
541
2.07k
  return (cfg->claim_prefix != NULL) ? cfg->claim_prefix : OIDC_DEFAULT_CLAIM_PREFIX;
542
2.07k
}
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
11.9k
#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
11.9k
               const char *(hdr_func)(const request_rec *r)) {
590
11.9k
  apr_byte_t suppress = oidc_util_spaced_string_contains(
591
11.9k
      r->pool, apr_table_get(r->subprocess_env, OIDC_CHECK_X_FORWARDED_HDR_LOG_DISABLE), hdr_str);
592
11.9k
  if (hdr_func(r)) {
593
1.09k
    if (!(x_forwarded_headers & hdr_type) && !suppress)
594
1.09k
      oidc_warn(r, "header %s received but %s not configured for it", hdr_str, OIDCXForwardedHeaders);
595
10.8k
  } else {
596
10.8k
    if ((x_forwarded_headers & hdr_type) && !suppress)
597
10.8k
      oidc_warn(r, "%s configured for header %s but not found in request", OIDCXForwardedHeaders,
598
10.8k
          hdr_str);
599
10.8k
  }
600
11.9k
}
601
602
2.98k
void oidc_cfg_x_forwarded_headers_check(request_rec *r, oidc_hdr_x_forwarded_t x_forwarded_headers) {
603
2.98k
  oidc_check_x_forwarded_hdr(r, x_forwarded_headers, OIDC_HDR_X_FORWARDED_HOST, OIDC_HTTP_HDR_X_FORWARDED_HOST,
604
2.98k
           oidc_http_hdr_in_x_forwarded_host_get);
605
2.98k
  oidc_check_x_forwarded_hdr(r, x_forwarded_headers, OIDC_HDR_X_FORWARDED_PORT, OIDC_HTTP_HDR_X_FORWARDED_PORT,
606
2.98k
           oidc_http_hdr_in_x_forwarded_port_get);
607
2.98k
  oidc_check_x_forwarded_hdr(r, x_forwarded_headers, OIDC_HDR_X_FORWARDED_PROTO, OIDC_HTTP_HDR_X_FORWARDED_PROTO,
608
2.98k
           oidc_http_hdr_in_x_forwarded_proto_get);
609
2.98k
  oidc_check_x_forwarded_hdr(r, x_forwarded_headers, OIDC_HDR_FORWARDED, OIDC_HTTP_HDR_FORWARDED,
610
2.98k
           oidc_http_hdr_in_forwarded_get);
611
2.98k
}
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
871
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
116
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
/* metrics flush interval (ms) and shm JSON size (bytes): the getters return
734
 * OIDC_CONFIG_POS_INT_UNSET when the directive is absent so metrics.c can fall
735
 * back to the legacy environment variables and built-in defaults */
736
#define OIDC_METRICS_CACHE_STORAGE_INTERVAL_DIR_MIN 100
737
#define OIDC_METRICS_CACHE_STORAGE_INTERVAL_DIR_MAX 3600000
738
0
OIDC_CFG_MEMBER_FUNCS_INT(metrics_cache_storage_interval, OIDC_METRICS_CACHE_STORAGE_INTERVAL_DIR_MIN,
739
0
        OIDC_METRICS_CACHE_STORAGE_INTERVAL_DIR_MAX, OIDC_CONFIG_POS_INT_UNSET)
740
0
741
0
#define OIDC_METRICS_CACHE_JSON_MAX_DIR_MIN 1024
742
0
#define OIDC_METRICS_CACHE_JSON_MAX_DIR_MAX (1024 * 256 * 4 * 100)
743
0
OIDC_CFG_MEMBER_FUNCS_INT(metrics_cache_json_max, OIDC_METRICS_CACHE_JSON_MAX_DIR_MIN,
744
0
        OIDC_METRICS_CACHE_JSON_MAX_DIR_MAX, OIDC_CONFIG_POS_INT_UNSET)
745
0
746
0
#define OIDC_DEFAULT_LOGOUT_X_FRAME_OPTIONS "DENY"
747
19
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
747
OIDC_CFG_MEMBER_FUNCS_STR_DEF(logout_x_frame_options, NULL, OIDC_DEFAULT_LOGOUT_X_FRAME_OPTIONS)
748
749
#define OIDC_STATE_TIMEOUT_MIN 1
750
#define OIDC_STATE_TIMEOUT_MAX (3600 * 24 * 30)
751
#define OIDC_DEFAULT_STATE_TIMEOUT 300
752
753
0
OIDC_CFG_MEMBER_FUNCS_INT(state_timeout, OIDC_STATE_TIMEOUT_MIN, OIDC_STATE_TIMEOUT_MAX, OIDC_DEFAULT_STATE_TIMEOUT)
754
0
755
0
#define OIDC_SESSION_CLIENT_COOKIE_CHUNK_SIZE_MIN 256
756
0
#define OIDC_SESSION_CLIENT_COOKIE_CHUNK_SIZE_MAX (1024 * 64)
757
0
#define OIDC_DEFAULT_SESSION_CLIENT_COOKIE_CHUNK_SIZE 4000
758
0
759
0
/* NB: 0 is accepted on top of the range and means "never chunk", which is what the
760
0
 * runtime already implements in oidc_http_set_chunked_cookie() */
761
0
OIDC_CFG_MEMBER_FUNCS_INT_EXT(session_cookie_chunk_size,
762
            oidc_cfg_parse_int_min_max_or_zero(cmd->pool, arg, &v,
763
                 OIDC_SESSION_CLIENT_COOKIE_CHUNK_SIZE_MIN,
764
                 OIDC_SESSION_CLIENT_COOKIE_CHUNK_SIZE_MAX),
765
            OIDC_DEFAULT_SESSION_CLIENT_COOKIE_CHUNK_SIZE)
766
767
#define OIDC_PROVIDER_METADATA_REFRESH_INTERVAL_MIN 30
768
#define OIDC_PROVIDER_METADATA_REFRESH_INTERVAL_MAX (3600 * 24 * 365)
769
#define OIDC_DEFAULT_PROVIDER_METADATA_REFRESH_INTERVAL 0
770
771
0
OIDC_CFG_MEMBER_FUNCS_INT(provider_metadata_refresh_interval, OIDC_PROVIDER_METADATA_REFRESH_INTERVAL_MIN,
772
0
        OIDC_PROVIDER_METADATA_REFRESH_INTERVAL_MAX, OIDC_DEFAULT_PROVIDER_METADATA_REFRESH_INTERVAL)
773
0
774
0
#define OIDC_CFG_MEMBER_FUNCS_HASHTABLE(member)                                                                        \
775
0
  const char *oidc_cmd_##member##_set(cmd_parms *cmd, void *ptr, const char *arg) {                              \
776
0
    oidc_cfg_t *cfg =                                                                                      \
777
0
        (oidc_cfg_t *)ap_get_module_config(cmd->server->module_config, &auth_openidc_module);              \
778
0
    if (cfg->member == NULL)                                                                               \
779
0
      cfg->member = apr_hash_make(cmd->pool);                                                        \
780
0
    apr_hash_set(cfg->member, arg, APR_HASH_KEY_STRING, arg);                                              \
781
0
    return NULL;                                                                                           \
782
0
  }                                                                                                              \
783
                                                                                                                       \
784
  OIDC_CFG_MEMBER_FUNC_GET(member, apr_hash_t *)
785
786
0
OIDC_CFG_MEMBER_FUNCS_HASHTABLE(white_listed_claims)
787
0
OIDC_CFG_MEMBER_FUNCS_HASHTABLE(black_listed_claims)
788
0
OIDC_CFG_MEMBER_FUNCS_HASHTABLE(redirect_urls_allowed)
789
0
OIDC_CFG_MEMBER_FUNCS_HASHTABLE(discover_issuers_allowed)
790
791
#define OIDC_CFG_MEMBER_FUNCS_ABS_OR_REL_URI(member)                                                                   \
792
0
  const char *oidc_cmd_##member##_set(cmd_parms *cmd, void *ptr, const char *arg) {                              \
793
0
    oidc_cfg_t *cfg =                                                                                      \
794
0
        (oidc_cfg_t *)ap_get_module_config(cmd->server->module_config, &auth_openidc_module);              \
795
0
    const char *rv = oidc_cfg_parse_relative_or_absolute_url(cmd->pool, arg, &cfg->member);                \
796
0
    return OIDC_CONFIG_DIR_RV(cmd, rv);                                                                    \
797
0
  }                                                                                                              \
798
                                                                                                                       \
799
  OIDC_CFG_MEMBER_FUNC_GET(member, const char *)
800
801
0
OIDC_CFG_MEMBER_FUNCS_ABS_OR_REL_URI(redirect_uri)
802
0
OIDC_CFG_MEMBER_FUNCS_ABS_OR_REL_URI(default_sso_url)
803
0
OIDC_CFG_MEMBER_FUNCS_ABS_OR_REL_URI(default_slo_url)
804
805
typedef struct oidc_cfg_cleanup_ctx_t {
806
  oidc_cfg_t *cfg;
807
  apr_pool_t *pool;
808
  server_rec *svr;
809
} oidc_cfg_cleanup_ctx_t;
810
811
/*
812
 * destroy a server config record and its members
813
 */
814
0
apr_byte_t oidc_cfg_server_destroy(apr_pool_t *pool, server_rec *s, oidc_cfg_t *cfg) {
815
0
  if ((cfg->cache.impl) && (cfg->cache.impl->destroy))
816
0
    cfg->cache.impl->destroy(pool, s);
817
0
  cfg->cache.impl = NULL;
818
0
  oidc_cfg_provider_destroy(cfg->provider);
819
0
  cfg->provider = NULL;
820
0
  oidc_cfg_oauth_destroy(cfg->oauth);
821
0
  cfg->oauth = NULL;
822
0
  oidc_jwk_list_destroy(cfg->public_keys);
823
0
  cfg->public_keys = NULL;
824
0
  oidc_jwk_list_destroy(cfg->private_keys);
825
0
  cfg->private_keys = NULL;
826
0
  return TRUE;
827
0
}
828
829
0
static apr_status_t oidc_cfg_server_cleanup(void *data) {
830
0
  oidc_cfg_cleanup_ctx_t *ctx = (oidc_cfg_cleanup_ctx_t *)data;
831
0
  oidc_cfg_t *cfg = ctx->cfg;
832
0
  return oidc_cfg_server_destroy(ctx->pool, ctx->svr, cfg) ? APR_SUCCESS : APR_EGENERAL;
833
0
}
834
835
40
static oidc_cfg_t *oidc_cfg_server_alloc(apr_pool_t *pool, server_rec *s) {
836
40
  oidc_cfg_t *c = apr_pcalloc(pool, sizeof(oidc_cfg_t));
837
40
  oidc_cfg_cleanup_ctx_t *ctx = apr_pcalloc(pool, sizeof(oidc_cfg_cleanup_ctx_t));
838
40
  ctx->cfg = c;
839
  // pconf pool used at destruction time
840
40
  ctx->pool = pool;
841
40
  ctx->svr = s;
842
  // register a cleanup handler on the config pool to handle graceful restarts without increasing
843
  // memory consumption; this MUST be a *pre*-cleanup: libapr registers its own regular cleanups
844
  // for the cache global mutex's POSIX semaphore and the shm segment on this same pool when they
845
  // are created at post_config time, and regular cleanups run in reverse order of registration,
846
  // so a regular registration here (which happens much earlier, at config-parse time) would run
847
  // only AFTER libapr has already closed/unmapped those objects, making the mutex unlock/destroy
848
  // in oidc_cache_shm_destroy() dereference an unmapped semaphore and segfault the parent process
849
  // on a graceful restart; pre-cleanups are guaranteed to run before all regular cleanups
850
40
  apr_pool_pre_cleanup_register(pool, ctx, oidc_cfg_server_cleanup);
851
40
  return c;
852
40
}
853
854
/*
855
 * create a new server config record with defaults
856
 */
857
480
#define OIDC_SVR_M_CREATE_PTR(type, name) c->name = NULL;
858
880
#define OIDC_SVR_M_CREATE_INT(name) c->name = OIDC_CONFIG_POS_INT_UNSET;
859
0
#define OIDC_SVR_M_MERGE_PTR(type, name) c->name = _oidc_cfg_merge_ptr(add->name, base->name);
860
0
#define OIDC_SVR_M_MERGE_INT(name) c->name = _oidc_cfg_merge_pos_int(add->name, base->name);
861
862
40
void *oidc_cfg_server_create(apr_pool_t *pool, server_rec *svr) {
863
40
  oidc_cfg_t *c = oidc_cfg_server_alloc(pool, svr);
864
40
  c->svr = svr;
865
866
40
  c->merged = FALSE;
867
  /* nothing to inherit from: whatever OIDCRedirectURI this config ends up with is its own */
868
40
  c->redirect_uri_inherited = FALSE;
869
870
880
  OIDC_SVR_CFG_SIMPLE_MEMBERS(OIDC_SVR_M_CREATE_PTR, OIDC_SVR_M_CREATE_INT)
871
40
  c->public_keys = NULL;
872
40
  c->private_keys = NULL;
873
874
40
  c->provider = oidc_cfg_provider_create(pool);
875
40
  c->oauth = oidc_cfg_oauth_create(pool);
876
40
  oidc_cfg_cache_create_server_config(c);
877
878
40
  c->http_timeout_long.request_timeout = OIDC_CONFIG_POS_INT_UNSET;
879
40
  c->http_timeout_long.connect_timeout = OIDC_DEFAULT_HTTP_CONNECT_TIMEOUT_LONG;
880
40
  c->http_timeout_long.retries = OIDC_DEFAULT_HTTP_RETRIES_LONG;
881
40
  c->http_timeout_long.retry_interval = OIDC_DEFAULT_HTTP_RETRY_INTERVAL_LONG;
882
40
  c->http_timeout_short.request_timeout = OIDC_CONFIG_POS_INT_UNSET;
883
40
  c->http_timeout_short.connect_timeout = OIDC_DEFAULT_HTTP_CONNECT_TIMEOUT_SHORT;
884
40
  c->http_timeout_short.retries = OIDC_DEFAULT_HTTP_RETRIES_SHORT;
885
40
  c->http_timeout_short.retry_interval = OIDC_DEFAULT_HTTP_RETRY_INTERVAL_SHORT;
886
887
40
  c->remote_user_claim.claim_name = NULL;
888
40
  c->remote_user_claim.reg_exp = NULL;
889
40
  c->remote_user_claim.replace = NULL;
890
891
40
  c->outgoing_proxy.host_port = NULL;
892
40
  c->outgoing_proxy.username_password = NULL;
893
40
  c->outgoing_proxy.auth_type = OIDC_CONFIG_POS_INT_UNSET;
894
895
40
  c->crypto_passphrase.secret1 = NULL;
896
40
  c->crypto_passphrase.secret2 = NULL;
897
40
  c->crypto_passphrase.derived_key1_set = FALSE;
898
40
  c->crypto_passphrase.derived_key2_set = FALSE;
899
900
40
  c->info_hook_data = NULL;
901
40
  c->metrics_hook_data = NULL;
902
903
40
  c->black_listed_claims = NULL;
904
40
  c->white_listed_claims = NULL;
905
40
  c->filter_claims_expr = NULL;
906
907
40
  c->redirect_urls_allowed = NULL;
908
40
  c->discover_issuers_allowed = NULL;
909
910
40
  return c;
911
40
}
912
913
/*
914
 * merge an http_timeout struct: "add" wins as a whole if it has been configured
915
 */
916
static void _oidc_cfg_merge_http_timeout(oidc_http_timeout_t *c, const oidc_http_timeout_t *add,
917
0
           const oidc_http_timeout_t *base) {
918
0
  const oidc_http_timeout_t *src = add->request_timeout != OIDC_CONFIG_POS_INT_UNSET ? add : base;
919
0
  c->request_timeout = src->request_timeout;
920
0
  c->connect_timeout = src->connect_timeout;
921
0
  c->retries = src->retries;
922
0
  c->retry_interval = src->retry_interval;
923
0
}
924
925
/*
926
 * merge the remote_user_claim struct: "add" wins as a whole if it has been configured
927
 */
928
static void _oidc_cfg_merge_remote_user_claim(oidc_remote_user_claim_t *c, const oidc_remote_user_claim_t *add,
929
0
                const oidc_remote_user_claim_t *base) {
930
0
  const oidc_remote_user_claim_t *src = add->claim_name != NULL ? add : base;
931
0
  c->claim_name = src->claim_name;
932
0
  c->reg_exp = src->reg_exp;
933
0
  c->replace = src->replace;
934
0
}
935
936
/*
937
 * merge the outgoing_proxy struct: "add" wins as a whole if it has been configured
938
 */
939
static void _oidc_cfg_merge_outgoing_proxy(oidc_http_outgoing_proxy_t *c, const oidc_http_outgoing_proxy_t *add,
940
0
             const oidc_http_outgoing_proxy_t *base) {
941
0
  const oidc_http_outgoing_proxy_t *src = add->host_port != NULL ? add : base;
942
0
  c->host_port = src->host_port;
943
0
  c->username_password = src->username_password;
944
0
  c->auth_type = src->auth_type;
945
0
}
946
947
/*
948
 * merge the crypto_passphrase struct: "add" wins as a whole if it has been configured
949
 */
950
static void _oidc_cfg_merge_crypto_passphrase(oidc_crypto_passphrase_t *c, const oidc_crypto_passphrase_t *add,
951
0
                const oidc_crypto_passphrase_t *base) {
952
0
  const oidc_crypto_passphrase_t *src = add->secret1 != NULL ? add : base;
953
0
  c->secret1 = src->secret1;
954
0
  c->secret2 = src->secret2;
955
  /* Keep derived keys paired with the selected secrets, regardless of merge/derivation order. */
956
0
  c->derived_key1_set = src->derived_key1_set;
957
0
  if (src->derived_key1_set)
958
0
    _oidc_memcpy(c->derived_key1, src->derived_key1, OIDC_CRYPTO_PASSPHRASE_DERIVED_KEY_LEN);
959
0
  c->derived_key2_set = src->derived_key2_set;
960
0
  if (src->derived_key2_set)
961
0
    _oidc_memcpy(c->derived_key2, src->derived_key2, OIDC_CRYPTO_PASSPHRASE_DERIVED_KEY_LEN);
962
0
}
963
964
/*
965
 * merge a new server config with a base one
966
 */
967
0
void *oidc_cfg_server_merge(apr_pool_t *pool, void *BASE, void *ADD) {
968
0
  const oidc_cfg_t *base = (const oidc_cfg_t *)BASE;
969
0
  const oidc_cfg_t *add = (const oidc_cfg_t *)ADD;
970
971
0
  oidc_cfg_t *c = oidc_cfg_server_alloc(pool, add->svr);
972
973
0
  c->provider = oidc_cfg_provider_create(pool);
974
0
  c->oauth = oidc_cfg_oauth_create(pool);
975
976
0
  c->merged = TRUE;
977
  /* record where the merged redirect_uri came from while "add" (this vhost's own config) and
978
   * "base" can still be told apart: the merge below collapses them into a single value */
979
0
  c->redirect_uri_inherited = (add->redirect_uri == NULL) && (base->redirect_uri != NULL);
980
981
0
  oidc_cfg_provider_merge(pool, c->provider, base->provider, add->provider);
982
0
  oidc_cfg_oauth_merge(pool, c->oauth, base->oauth, add->oauth);
983
0
  oidc_cfg_cache_merge_server_config(c, base, add);
984
985
0
  OIDC_SVR_CFG_SIMPLE_MEMBERS(OIDC_SVR_M_MERGE_PTR, OIDC_SVR_M_MERGE_INT)
986
0
  c->public_keys = oidc_jwk_list_copy(pool, _oidc_cfg_merge_ptr(add->public_keys, base->public_keys));
987
0
  c->private_keys = oidc_jwk_list_copy(pool, _oidc_cfg_merge_ptr(add->private_keys, base->private_keys));
988
989
0
  _oidc_cfg_merge_http_timeout(&c->http_timeout_long, &add->http_timeout_long, &base->http_timeout_long);
990
0
  _oidc_cfg_merge_http_timeout(&c->http_timeout_short, &add->http_timeout_short, &base->http_timeout_short);
991
992
0
  _oidc_cfg_merge_remote_user_claim(&c->remote_user_claim, &add->remote_user_claim, &base->remote_user_claim);
993
994
0
  _oidc_cfg_merge_outgoing_proxy(&c->outgoing_proxy, &add->outgoing_proxy, &base->outgoing_proxy);
995
0
  _oidc_cfg_merge_crypto_passphrase(&c->crypto_passphrase, &add->crypto_passphrase, &base->crypto_passphrase);
996
997
0
  c->info_hook_data = _oidc_cfg_merge_ptr(add->info_hook_data, base->info_hook_data);
998
0
  c->metrics_hook_data = _oidc_cfg_merge_ptr(add->metrics_hook_data, base->metrics_hook_data);
999
1000
0
  c->black_listed_claims = _oidc_cfg_merge_ptr(add->black_listed_claims, base->black_listed_claims);
1001
0
  c->white_listed_claims = _oidc_cfg_merge_ptr(add->white_listed_claims, base->white_listed_claims);
1002
0
  c->filter_claims_expr = _oidc_cfg_merge_ptr(add->filter_claims_expr, base->filter_claims_expr);
1003
1004
0
  c->redirect_urls_allowed = _oidc_cfg_merge_ptr(add->redirect_urls_allowed, base->redirect_urls_allowed);
1005
0
  c->discover_issuers_allowed =
1006
0
      _oidc_cfg_merge_ptr(add->discover_issuers_allowed, base->discover_issuers_allowed);
1007
1008
0
  return c;
1009
0
}
1010
1011
/*
1012
 * Build a read-only request view with a private OAuth struct, allowing metadata endpoints to
1013
 * change without mutating shared server state. Other members remain shared.
1014
 */
1015
0
oidc_cfg_t *oidc_cfg_request_view(apr_pool_t *pool, const oidc_cfg_t *c) {
1016
0
  oidc_cfg_t *rc = apr_pmemdup(pool, c, sizeof(*c));
1017
0
  rc->oauth = oidc_cfg_oauth_shallow_copy(pool, c->oauth);
1018
0
  return rc;
1019
0
}
1020
1021
/*
1022
 * initialize before the post config handler runs
1023
 */
1024
38
void oidc_pre_config_init(void) {
1025
38
#if OPENSSL_API_COMPAT < 0x10100000L
1026
38
  ERR_load_crypto_strings();
1027
38
  OpenSSL_add_all_algorithms();
1028
38
  OpenSSL_add_all_digests();
1029
#else
1030
  OPENSSL_init_crypto(0, NULL);
1031
#endif
1032
38
}
1033
1034
123k
oidc_provider_t *oidc_cfg_provider_get(oidc_cfg_t *cfg) {
1035
123k
  return cfg->provider;
1036
123k
}
1037
1038
0
int oidc_cfg_merged_get(const oidc_cfg_t *cfg) {
1039
0
  return cfg->merged;
1040
0
}
1041
1042
0
int oidc_cfg_redirect_uri_inherited_get(const oidc_cfg_t *cfg) {
1043
0
  return cfg->redirect_uri_inherited;
1044
0
}
1045
1046
static oidc_cache_mutex_t *_oidc_refresh_mutex = NULL;
1047
1048
14
oidc_cache_mutex_t *oidc_cfg_refresh_mutex_get(const oidc_cfg_t *cfg) {
1049
14
  return _oidc_refresh_mutex;
1050
14
}
1051
1052
38
int oidc_cfg_post_config(apr_pool_t *pool, oidc_cfg_t *cfg, server_rec *s) {
1053
38
  if (cfg->cache.impl == NULL)
1054
0
    cfg->cache.impl = &oidc_cache_shm;
1055
38
  if ((cfg->cache.impl->post_config != NULL) && (cfg->cache.impl->post_config(pool, s) != OK))
1056
0
    return HTTP_INTERNAL_SERVER_ERROR;
1057
38
  if (_oidc_refresh_mutex == NULL) {
1058
    // NB: use the process pool here as the mutex is a process-wide singleton
1059
38
    _oidc_refresh_mutex = oidc_cache_mutex_create(s->process->pool, TRUE);
1060
38
    if (oidc_cache_mutex_post_config(s->process->pool, s, _oidc_refresh_mutex, "refresh") != TRUE)
1061
0
      return HTTP_INTERNAL_SERVER_ERROR;
1062
38
  }
1063
38
  if ((cfg->metrics_hook_data != NULL) && (oidc_metrics_post_config(pool, s) != TRUE))
1064
0
    return HTTP_INTERNAL_SERVER_ERROR;
1065
38
  return OK;
1066
38
}
1067
1068
0
void oidc_cfg_child_init(apr_pool_t *pool, const oidc_cfg_t *cfg, server_rec *s) {
1069
0
  if ((cfg->cache.impl->child_init != NULL) && (cfg->cache.impl->child_init(pool, s) != APR_SUCCESS))
1070
0
    oidc_serror(s, "cfg->cache->child_init failed");
1071
0
  if ((_oidc_refresh_mutex != NULL) && (oidc_cache_mutex_child_init(pool, s, _oidc_refresh_mutex) != APR_SUCCESS))
1072
0
    oidc_serror(s, "oidc_cache_mutex_child_init on refresh mutex failed");
1073
0
  if ((cfg->metrics_hook_data != NULL) && (oidc_metrics_child_init(pool, s) != APR_SUCCESS))
1074
0
    oidc_serror(s, "oidc_metrics_cache_child_init failed");
1075
0
}
1076
1077
0
void oidc_cfg_process_cleanup(oidc_cfg_t *cfg, server_rec *s) {
1078
0
  if (_oidc_refresh_mutex != NULL) {
1079
0
    if (oidc_cache_mutex_destroy(s, _oidc_refresh_mutex) != TRUE) {
1080
0
      oidc_serror(s, "oidc_cache_mutex_destroy on refresh mutex failed");
1081
0
    }
1082
    // this is a singleton, make sure we call destroy only once
1083
0
    _oidc_refresh_mutex = NULL;
1084
0
  }
1085
0
  if (cfg->metrics_hook_data != NULL) {
1086
0
    if (oidc_metrics_cleanup(s) != APR_SUCCESS) {
1087
0
      oidc_serror(s, "oidc_metrics_cleanup failed");
1088
0
    }
1089
    cfg->metrics_hook_data = NULL;
1090
0
  }
1091
0
}