Coverage Report

Created: 2026-10-17 07:02

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/mod_auth_openidc/src/proto/state.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 "proto/proto.h"
44
#include "util/util.h"
45
#include "util/util_cfg.h"
46
47
8.45k
#define OIDC_PROTO_STATE_ISSUER "i"
48
9.06k
#define OIDC_PROTO_STATE_ORIGINAL_URL "ou"
49
5.64k
#define OIDC_PROTO_STATE_ORIGINAL_METHOD "om"
50
6.31k
#define OIDC_PROTO_STATE_RESPONSE_MODE "rm"
51
9.45k
#define OIDC_PROTO_STATE_RESPONSE_TYPE "rt"
52
11.2k
#define OIDC_PROTO_STATE_NONCE "n"
53
9.89k
#define OIDC_PROTO_STATE_TIMESTAMP "t"
54
4.82k
#define OIDC_PROTO_STATE_PROMPT "pr"
55
5.46k
#define OIDC_PROTO_STATE_PKCE_STATE "ps"
56
6.82k
#define OIDC_PROTO_STATE_STATE "s"
57
4
#define OIDC_PROTO_STATE_AUTH_REQUEST_PARAMS "arp"
58
4
#define OIDC_PROTO_STATE_PATH_SCOPE "psc"
59
60
/*
61
 * retrieve a string from the state object
62
 */
63
25.9k
static const char *oidc_proto_state_get_string_value(const oidc_proto_state_t *proto_state, const char *name) {
64
25.9k
  const oidc_json_t *v = oidc_json_object_get(proto_state, name);
65
25.9k
  return v ? oidc_json_string_value(v) : NULL;
66
25.9k
}
67
68
/*
69
 * set a string value in the state object
70
 */
71
41.3k
static void oidc_proto_state_set_string_value(oidc_proto_state_t *proto_state, const char *name, const char *value) {
72
41.3k
  oidc_json_object_set_new(proto_state, name, oidc_json_string(value));
73
41.3k
}
74
75
/*
76
 * create a new state object
77
 */
78
5.26k
oidc_proto_state_t *oidc_proto_state_new(void) {
79
5.26k
  return oidc_json_object();
80
5.26k
}
81
82
/*
83
 * free up resources allocated for a state object
84
 */
85
9.95k
void oidc_proto_state_destroy(oidc_proto_state_t *proto_state) {
86
9.95k
  oidc_json_decref(proto_state);
87
9.95k
}
88
89
/*
90
 * serialize a state object to a string (for logging/debugging purposes); the nonce and
91
 * PKCE code_verifier are redacted since they are security-sensitive values that should
92
 * not end up in full in a log file
93
 */
94
4
char *oidc_proto_state_to_string(request_rec *r, const oidc_proto_state_t *proto_state) {
95
4
  oidc_proto_state_t *copy = oidc_json_deep_copy(proto_state);
96
4
  char *result = NULL;
97
98
4
  if (oidc_json_object_get(copy, OIDC_PROTO_STATE_NONCE) != NULL)
99
2
    oidc_proto_state_set_string_value(copy, OIDC_PROTO_STATE_NONCE, "***");
100
4
  if (oidc_json_object_get(copy, OIDC_PROTO_STATE_PKCE_STATE) != NULL)
101
2
    oidc_proto_state_set_string_value(copy, OIDC_PROTO_STATE_PKCE_STATE, "***");
102
103
4
  result = oidc_json_encode(r->pool, copy, OIDC_JSON_COMPACT);
104
4
  oidc_json_decref(copy);
105
106
4
  return result;
107
4
}
108
109
/*
110
 * retrieve the issuer value from the state object
111
 */
112
3.25k
const char *oidc_proto_state_get_issuer(const oidc_proto_state_t *proto_state) {
113
3.25k
  return oidc_proto_state_get_string_value(proto_state, OIDC_PROTO_STATE_ISSUER);
114
3.25k
}
115
116
/*
117
 * retrieve the nonce value from the state object
118
 */
119
6.07k
const char *oidc_proto_state_get_nonce(const oidc_proto_state_t *proto_state) {
120
6.07k
  return oidc_proto_state_get_string_value(proto_state, OIDC_PROTO_STATE_NONCE);
121
6.07k
}
122
123
/*
124
 * retrieve the timestamp value from the state object
125
 */
126
4.69k
apr_time_t oidc_proto_state_get_timestamp(const oidc_proto_state_t *proto_state) {
127
4.69k
  const oidc_json_t *v = oidc_json_object_get(proto_state, OIDC_PROTO_STATE_TIMESTAMP);
128
4.69k
  return v ? apr_time_from_sec(oidc_json_integer_value(v)) : -1;
129
4.69k
}
130
131
/*
132
 * retrieve the prompt value from the state object
133
 */
134
4.28k
const char *oidc_proto_state_get_prompt(const oidc_proto_state_t *proto_state) {
135
4.28k
  return oidc_proto_state_get_string_value(proto_state, OIDC_PROTO_STATE_PROMPT);
136
4.28k
}
137
138
/*
139
 * retrieve the response type value from the state object
140
 */
141
4.24k
const char *oidc_proto_state_get_response_type(const oidc_proto_state_t *proto_state) {
142
4.24k
  return oidc_proto_state_get_string_value(proto_state, OIDC_PROTO_STATE_RESPONSE_TYPE);
143
4.24k
}
144
145
/*
146
 * retrieve the response mode value from the state object
147
 */
148
3.37k
const char *oidc_proto_state_get_response_mode(const oidc_proto_state_t *proto_state) {
149
3.37k
  return oidc_proto_state_get_string_value(proto_state, OIDC_PROTO_STATE_RESPONSE_MODE);
150
3.37k
}
151
152
/*
153
 * retrieve the original URL value from the state object
154
 */
155
3.80k
const char *oidc_proto_state_get_original_url(const oidc_proto_state_t *proto_state) {
156
3.80k
  return oidc_proto_state_get_string_value(proto_state, OIDC_PROTO_STATE_ORIGINAL_URL);
157
3.80k
}
158
159
/*
160
 * retrieve the original HTTP method value from the state object
161
 */
162
438
const char *oidc_proto_state_get_original_method(const oidc_proto_state_t *proto_state) {
163
438
  return oidc_proto_state_get_string_value(proto_state, OIDC_PROTO_STATE_ORIGINAL_METHOD);
164
438
}
165
166
/*
167
 * retrieve the state (URL parameter) value from the state object
168
 */
169
252
const char *oidc_proto_state_get_state(const oidc_proto_state_t *proto_state) {
170
252
  return oidc_proto_state_get_string_value(proto_state, OIDC_PROTO_STATE_STATE);
171
252
}
172
173
/*
174
 * retrieve the PKCE state value from the state object
175
 */
176
252
const char *oidc_proto_state_get_pkce_state(const oidc_proto_state_t *proto_state) {
177
252
  return oidc_proto_state_get_string_value(proto_state, OIDC_PROTO_STATE_PKCE_STATE);
178
252
}
179
180
/*
181
 * retrieve the per-path authentication request parameters from the state object
182
 */
183
4
const char *oidc_proto_state_get_auth_request_params(const oidc_proto_state_t *proto_state) {
184
4
  return oidc_proto_state_get_string_value(proto_state, OIDC_PROTO_STATE_AUTH_REQUEST_PARAMS);
185
4
}
186
187
/*
188
 * retrieve the per-path scope from the state object
189
 */
190
4
const char *oidc_proto_state_get_path_scope(const oidc_proto_state_t *proto_state) {
191
4
  return oidc_proto_state_get_string_value(proto_state, OIDC_PROTO_STATE_PATH_SCOPE);
192
4
}
193
194
/*
195
 * set the state (URL parameter) value in the state object
196
 */
197
6.56k
void oidc_proto_state_set_state(oidc_proto_state_t *proto_state, const char *state) {
198
6.56k
  oidc_proto_state_set_string_value(proto_state, OIDC_PROTO_STATE_STATE, state);
199
6.56k
}
200
201
/*
202
 * set the issuer value in the state object
203
 */
204
5.20k
void oidc_proto_state_set_issuer(oidc_proto_state_t *proto_state, const char *issuer) {
205
5.20k
  oidc_proto_state_set_string_value(proto_state, OIDC_PROTO_STATE_ISSUER, issuer);
206
5.20k
}
207
208
/*
209
 * set the original URL value in the state object
210
 */
211
5.26k
void oidc_proto_state_set_original_url(oidc_proto_state_t *proto_state, const char *original_url) {
212
5.26k
  oidc_proto_state_set_string_value(proto_state, OIDC_PROTO_STATE_ORIGINAL_URL, original_url);
213
5.26k
}
214
215
/*
216
 * set the original HTTP method value in the state object
217
 */
218
5.20k
void oidc_proto_state_set_original_method(oidc_proto_state_t *proto_state, const char *original_method) {
219
5.20k
  oidc_proto_state_set_string_value(proto_state, OIDC_PROTO_STATE_ORIGINAL_METHOD, original_method);
220
5.20k
}
221
222
/*
223
 * set the response mode value in the state object
224
 */
225
2.94k
void oidc_proto_state_set_response_mode(oidc_proto_state_t *proto_state, const char *response_mode) {
226
2.94k
  oidc_proto_state_set_string_value(proto_state, OIDC_PROTO_STATE_RESPONSE_MODE, response_mode);
227
2.94k
}
228
229
/*
230
 * set the response type value in the state object
231
 */
232
5.20k
void oidc_proto_state_set_response_type(oidc_proto_state_t *proto_state, const char *response_type) {
233
5.20k
  oidc_proto_state_set_string_value(proto_state, OIDC_PROTO_STATE_RESPONSE_TYPE, response_type);
234
5.20k
}
235
236
/*
237
 * set the nonce value in the state object
238
 */
239
5.20k
void oidc_proto_state_set_nonce(oidc_proto_state_t *proto_state, const char *nonce) {
240
5.20k
  oidc_proto_state_set_string_value(proto_state, OIDC_PROTO_STATE_NONCE, nonce);
241
5.20k
}
242
243
/*
244
 * set the prompt value in the state object
245
 */
246
548
void oidc_proto_state_set_prompt(oidc_proto_state_t *proto_state, const char *prompt) {
247
548
  oidc_proto_state_set_string_value(proto_state, OIDC_PROTO_STATE_PROMPT, prompt);
248
548
}
249
250
/*
251
 * set the PKCE state value in the state object
252
 */
253
5.20k
void oidc_proto_state_set_pkce_state(oidc_proto_state_t *proto_state, const char *pkce_state) {
254
5.20k
  oidc_proto_state_set_string_value(proto_state, OIDC_PROTO_STATE_PKCE_STATE, pkce_state);
255
5.20k
}
256
257
/*
258
 * set the per-path authentication request parameters in the state object
259
 */
260
0
void oidc_proto_state_set_auth_request_params(oidc_proto_state_t *proto_state, const char *auth_request_params) {
261
0
  oidc_proto_state_set_string_value(proto_state, OIDC_PROTO_STATE_AUTH_REQUEST_PARAMS, auth_request_params);
262
0
}
263
264
/*
265
 * set the per-path scope in the state object
266
 */
267
0
void oidc_proto_state_set_path_scope(oidc_proto_state_t *proto_state, const char *path_scope) {
268
0
  oidc_proto_state_set_string_value(proto_state, OIDC_PROTO_STATE_PATH_SCOPE, path_scope);
269
0
}
270
271
/*
272
 * set the current time as timestamp value in the state object
273
 */
274
5.20k
void oidc_proto_state_set_timestamp_now(oidc_proto_state_t *proto_state) {
275
5.20k
  oidc_json_object_set_new(proto_state, OIDC_PROTO_STATE_TIMESTAMP,
276
5.20k
         oidc_json_integer(apr_time_sec(apr_time_now())));
277
5.20k
}
278
279
/*
280
 * parse a state object from the provided cookie value
281
 */
282
25.1k
oidc_proto_state_t *oidc_proto_state_from_cookie(request_rec *r, const oidc_cfg_t *c, const char *cookieValue) {
283
25.1k
  char *s_payload = NULL;
284
25.1k
  oidc_json_t *result = NULL;
285
25.1k
  oidc_util_jwt_verify(r, oidc_cfg_crypto_passphrase_get(c), cookieValue, &s_payload);
286
25.1k
  oidc_json_decode_object(r, s_payload, &result);
287
25.1k
  return result;
288
25.1k
}
289
290
/*
291
 * serialize a state object to a signed JWT cookie value
292
 */
293
5.20k
char *oidc_proto_state_to_cookie(request_rec *r, const oidc_cfg_t *c, const oidc_proto_state_t *proto_state) {
294
5.20k
  char *cookieValue = NULL;
295
5.20k
  oidc_util_jwt_create(r, oidc_cfg_crypto_passphrase_get(c),
296
5.20k
           oidc_json_encode(r->pool, proto_state, OIDC_JSON_COMPACT), &cookieValue);
297
5.20k
  return cookieValue;
298
5.20k
}