Coverage Report

Created: 2026-08-31 07:13

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
17.9k
#define OIDC_PROTO_STATE_ISSUER "i"
48
19.5k
#define OIDC_PROTO_STATE_ORIGINAL_URL "ou"
49
12.2k
#define OIDC_PROTO_STATE_ORIGINAL_METHOD "om"
50
13.2k
#define OIDC_PROTO_STATE_RESPONSE_MODE "rm"
51
19.5k
#define OIDC_PROTO_STATE_RESPONSE_TYPE "rt"
52
24.1k
#define OIDC_PROTO_STATE_NONCE "n"
53
20.4k
#define OIDC_PROTO_STATE_TIMESTAMP "t"
54
9.03k
#define OIDC_PROTO_STATE_PROMPT "pr"
55
11.4k
#define OIDC_PROTO_STATE_PKCE_STATE "ps"
56
13.8k
#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
52.8k
static const char *oidc_proto_state_get_string_value(const oidc_proto_state_t *proto_state, const char *name) {
64
52.8k
  const oidc_json_t *v = oidc_json_object_get(proto_state, name);
65
52.8k
  return v ? oidc_json_string_value(v) : NULL;
66
52.8k
}
67
68
/*
69
 * set a string value in the state object
70
 */
71
88.2k
static void oidc_proto_state_set_string_value(oidc_proto_state_t *proto_state, const char *name, const char *value) {
72
88.2k
  oidc_json_object_set_new(proto_state, name, oidc_json_string(value));
73
88.2k
}
74
75
/*
76
 * create a new state object
77
 */
78
11.4k
oidc_proto_state_t *oidc_proto_state_new(void) {
79
11.4k
  return oidc_json_object();
80
11.4k
}
81
82
/*
83
 * free up resources allocated for a state object
84
 */
85
20.6k
void oidc_proto_state_destroy(oidc_proto_state_t *proto_state) {
86
20.6k
  oidc_json_decref(proto_state);
87
20.6k
}
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
6.73k
const char *oidc_proto_state_get_issuer(const oidc_proto_state_t *proto_state) {
113
6.73k
  return oidc_proto_state_get_string_value(proto_state, OIDC_PROTO_STATE_ISSUER);
114
6.73k
}
115
116
/*
117
 * retrieve the nonce value from the state object
118
 */
119
12.9k
const char *oidc_proto_state_get_nonce(const oidc_proto_state_t *proto_state) {
120
12.9k
  return oidc_proto_state_get_string_value(proto_state, OIDC_PROTO_STATE_NONCE);
121
12.9k
}
122
123
/*
124
 * retrieve the timestamp value from the state object
125
 */
126
9.23k
apr_time_t oidc_proto_state_get_timestamp(const oidc_proto_state_t *proto_state) {
127
9.23k
  const oidc_json_t *v = oidc_json_object_get(proto_state, OIDC_PROTO_STATE_TIMESTAMP);
128
9.23k
  return v ? apr_time_from_sec(oidc_json_integer_value(v)) : -1;
129
9.23k
}
130
131
/*
132
 * retrieve the prompt value from the state object
133
 */
134
8.36k
const char *oidc_proto_state_get_prompt(const oidc_proto_state_t *proto_state) {
135
8.36k
  return oidc_proto_state_get_string_value(proto_state, OIDC_PROTO_STATE_PROMPT);
136
8.36k
}
137
138
/*
139
 * retrieve the response type value from the state object
140
 */
141
8.34k
const char *oidc_proto_state_get_response_type(const oidc_proto_state_t *proto_state) {
142
8.34k
  return oidc_proto_state_get_string_value(proto_state, OIDC_PROTO_STATE_RESPONSE_TYPE);
143
8.34k
}
144
145
/*
146
 * retrieve the response mode value from the state object
147
 */
148
6.77k
const char *oidc_proto_state_get_response_mode(const oidc_proto_state_t *proto_state) {
149
6.77k
  return oidc_proto_state_get_string_value(proto_state, OIDC_PROTO_STATE_RESPONSE_MODE);
150
6.77k
}
151
152
/*
153
 * retrieve the original URL value from the state object
154
 */
155
8.10k
const char *oidc_proto_state_get_original_url(const oidc_proto_state_t *proto_state) {
156
8.10k
  return oidc_proto_state_get_string_value(proto_state, OIDC_PROTO_STATE_ORIGINAL_URL);
157
8.10k
}
158
159
/*
160
 * retrieve the original HTTP method value from the state object
161
 */
162
1.08k
const char *oidc_proto_state_get_original_method(const oidc_proto_state_t *proto_state) {
163
1.08k
  return oidc_proto_state_get_string_value(proto_state, OIDC_PROTO_STATE_ORIGINAL_METHOD);
164
1.08k
}
165
166
/*
167
 * retrieve the state (URL parameter) value from the state object
168
 */
169
261
const char *oidc_proto_state_get_state(const oidc_proto_state_t *proto_state) {
170
261
  return oidc_proto_state_get_string_value(proto_state, OIDC_PROTO_STATE_STATE);
171
261
}
172
173
/*
174
 * retrieve the PKCE state value from the state object
175
 */
176
261
const char *oidc_proto_state_get_pkce_state(const oidc_proto_state_t *proto_state) {
177
261
  return oidc_proto_state_get_string_value(proto_state, OIDC_PROTO_STATE_PKCE_STATE);
178
261
}
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
13.5k
void oidc_proto_state_set_state(oidc_proto_state_t *proto_state, const char *state) {
198
13.5k
  oidc_proto_state_set_string_value(proto_state, OIDC_PROTO_STATE_STATE, state);
199
13.5k
}
200
201
/*
202
 * set the issuer value in the state object
203
 */
204
11.2k
void oidc_proto_state_set_issuer(oidc_proto_state_t *proto_state, const char *issuer) {
205
11.2k
  oidc_proto_state_set_string_value(proto_state, OIDC_PROTO_STATE_ISSUER, issuer);
206
11.2k
}
207
208
/*
209
 * set the original URL value in the state object
210
 */
211
11.4k
void oidc_proto_state_set_original_url(oidc_proto_state_t *proto_state, const char *original_url) {
212
11.4k
  oidc_proto_state_set_string_value(proto_state, OIDC_PROTO_STATE_ORIGINAL_URL, original_url);
213
11.4k
}
214
215
/*
216
 * set the original HTTP method value in the state object
217
 */
218
11.2k
void oidc_proto_state_set_original_method(oidc_proto_state_t *proto_state, const char *original_method) {
219
11.2k
  oidc_proto_state_set_string_value(proto_state, OIDC_PROTO_STATE_ORIGINAL_METHOD, original_method);
220
11.2k
}
221
222
/*
223
 * set the response mode value in the state object
224
 */
225
6.49k
void oidc_proto_state_set_response_mode(oidc_proto_state_t *proto_state, const char *response_mode) {
226
6.49k
  oidc_proto_state_set_string_value(proto_state, OIDC_PROTO_STATE_RESPONSE_MODE, response_mode);
227
6.49k
}
228
229
/*
230
 * set the response type value in the state object
231
 */
232
11.2k
void oidc_proto_state_set_response_type(oidc_proto_state_t *proto_state, const char *response_type) {
233
11.2k
  oidc_proto_state_set_string_value(proto_state, OIDC_PROTO_STATE_RESPONSE_TYPE, response_type);
234
11.2k
}
235
236
/*
237
 * set the nonce value in the state object
238
 */
239
11.2k
void oidc_proto_state_set_nonce(oidc_proto_state_t *proto_state, const char *nonce) {
240
11.2k
  oidc_proto_state_set_string_value(proto_state, OIDC_PROTO_STATE_NONCE, nonce);
241
11.2k
}
242
243
/*
244
 * set the prompt value in the state object
245
 */
246
670
void oidc_proto_state_set_prompt(oidc_proto_state_t *proto_state, const char *prompt) {
247
670
  oidc_proto_state_set_string_value(proto_state, OIDC_PROTO_STATE_PROMPT, prompt);
248
670
}
249
250
/*
251
 * set the PKCE state value in the state object
252
 */
253
11.2k
void oidc_proto_state_set_pkce_state(oidc_proto_state_t *proto_state, const char *pkce_state) {
254
11.2k
  oidc_proto_state_set_string_value(proto_state, OIDC_PROTO_STATE_PKCE_STATE, pkce_state);
255
11.2k
}
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
11.2k
void oidc_proto_state_set_timestamp_now(oidc_proto_state_t *proto_state) {
275
11.2k
  oidc_json_object_set_new(proto_state, OIDC_PROTO_STATE_TIMESTAMP,
276
11.2k
         oidc_json_integer(apr_time_sec(apr_time_now())));
277
11.2k
}
278
279
/*
280
 * parse a state object from the provided cookie value
281
 */
282
98.8k
oidc_proto_state_t *oidc_proto_state_from_cookie(request_rec *r, const oidc_cfg_t *c, const char *cookieValue) {
283
98.8k
  char *s_payload = NULL;
284
98.8k
  oidc_json_t *result = NULL;
285
98.8k
  oidc_util_jwt_verify(r, oidc_cfg_crypto_passphrase_get(c), cookieValue, &s_payload);
286
98.8k
  oidc_json_decode_object(r, s_payload, &result);
287
98.8k
  return result;
288
98.8k
}
289
290
/*
291
 * serialize a state object to a signed JWT cookie value
292
 */
293
11.2k
char *oidc_proto_state_to_cookie(request_rec *r, const oidc_cfg_t *c, const oidc_proto_state_t *proto_state) {
294
11.2k
  char *cookieValue = NULL;
295
11.2k
  oidc_util_jwt_create(r, oidc_cfg_crypto_passphrase_get(c),
296
11.2k
           oidc_json_encode(r->pool, proto_state, OIDC_JSON_COMPACT), &cookieValue);
297
11.2k
  return cookieValue;
298
11.2k
}