/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 | } |