1 /* openid20.c --- Test the OPENID20 mechanism.
2 * Copyright (C) 2010-2021 Simon Josefsson
3 *
4 * This file is part of GNU SASL.
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 *
19 */
20
21 #include <config.h>
22
23 #include <stdio.h>
24 #include <stdarg.h>
25 #include <stdlib.h>
26 #include <string.h>
27
28 #include "utils.h"
29
30 const char *authzid = NULL;
31 const char *sreg = NULL;
32 int validation_res = GSASL_OK;
33 int expect_server_res = GSASL_OK;
34 int expect_client_res = GSASL_OK;
35 int expect_server2_res = GSASL_MECHANISM_CALLED_TOO_MANY_TIMES;
36
37 static int
client_callback(Gsasl * ctx,Gsasl_session * sctx,Gsasl_property prop)38 client_callback (Gsasl * ctx, Gsasl_session * sctx, Gsasl_property prop)
39 {
40 int rc = GSASL_NO_CALLBACK;
41
42 switch (prop)
43 {
44 case GSASL_AUTHZID:
45 if (authzid)
46 gsasl_property_set (sctx, prop, authzid);
47 rc = GSASL_OK;
48 break;
49
50 case GSASL_AUTHID:
51 gsasl_property_set (sctx, prop, "http://user.example.org/");
52 rc = GSASL_OK;
53 break;
54
55 case GSASL_OPENID20_AUTHENTICATE_IN_BROWSER:
56 rc = GSASL_OK;
57 break;
58
59 default:
60 fail ("Unknown client callback property %u\n", prop);
61 break;
62 }
63
64 return rc;
65 }
66
67 static int
server_callback(Gsasl * ctx,Gsasl_session * sctx,Gsasl_property prop)68 server_callback (Gsasl * ctx, Gsasl_session * sctx, Gsasl_property prop)
69 {
70 int rc = GSASL_NO_CALLBACK;
71
72 switch (prop)
73 {
74 case GSASL_OPENID20_REDIRECT_URL:
75 gsasl_property_set (sctx, prop,
76 "http://idp.example/NONCE/?openid.foo=bar");
77 rc = GSASL_OK;
78 break;
79
80 case GSASL_VALIDATE_OPENID20:
81 rc = validation_res;
82 break;
83
84 case GSASL_OPENID20_OUTCOME_DATA:
85 if (sreg)
86 gsasl_property_set (sctx, prop, sreg);
87 rc = GSASL_OK;
88 break;
89
90 default:
91 fail ("Unknown server callback property %u\n", prop);
92 break;
93 }
94
95 return rc;
96 }
97
98 static void
openid20(Gsasl * c,Gsasl * s)99 openid20 (Gsasl * c, Gsasl * s)
100 {
101 Gsasl_session *client, *server;
102 char *s1, *s2;
103 int res;
104
105 /* Simple client */
106
107 res = gsasl_client_start (c, "OPENID20", &client);
108 if (res != GSASL_OK)
109 {
110 fail ("gsasl_client_start (%d):\n%s\n", res, gsasl_strerror (res));
111 return;
112 }
113
114 res = gsasl_server_start (s, "OPENID20", &server);
115 if (res != GSASL_OK)
116 {
117 fail ("gsasl_server_start (%d):\n%s\n", res, gsasl_strerror (res));
118 return;
119 }
120
121 /* OPENID20 is client-first. Check that server just waits. */
122
123 res = gsasl_step64 (server, NULL, &s2);
124 if (res != GSASL_NEEDS_MORE)
125 {
126 fail ("gsasl_step server0 (%d):\n%s\n", res, gsasl_strerror (res));
127 return;
128 }
129
130 if (debug)
131 printf ("S: `%s' (%d) %s\n", s2 ? s2 : "", (int) strlen (s2),
132 gsasl_strerror_name (res));
133
134 /* The client should send the OpenID URL. */
135
136 res = gsasl_step64 (client, s2, &s1);
137 gsasl_free (s2);
138 if (res != GSASL_NEEDS_MORE)
139 {
140 fail ("gsasl_step client1 (%d):\n%s\n", res, gsasl_strerror (res));
141 return;
142 }
143
144 if (debug)
145 printf ("C: `%s' (%d) %s\n", s1 ? s1 : "", (int) strlen (s1),
146 gsasl_strerror_name (res));
147
148 /* The server should send the redirect URL. */
149
150 res = gsasl_step64 (server, s1, &s2);
151 gsasl_free (s1);
152 if (res != GSASL_NEEDS_MORE)
153 {
154 fail ("gsasl_step server1 (%d):\n%s\n", res, gsasl_strerror (res));
155 return;
156 }
157
158 if (debug)
159 printf ("S: `%s' (%d) %s\n", s2 ? s2 : "", (int) strlen (s2),
160 gsasl_strerror_name (res));
161
162 /* The client sends '='. */
163
164 res = gsasl_step64 (client, s2, &s1);
165 gsasl_free (s2);
166 if (res != GSASL_OK)
167 {
168 fail ("gsasl_step client2 (%d):\n%s\n", res, gsasl_strerror (res));
169 return;
170 }
171
172 if (debug)
173 printf ("C: `%s' (%d) %s\n", s1 ? s1 : "", (int) strlen (s1),
174 gsasl_strerror_name (res));
175
176 /* Now the server sends the outcome_data */
177
178 res = gsasl_step64 (server, s1, &s2);
179 gsasl_free (s1);
180 if (res != expect_server_res)
181 {
182 fail ("gsasl_step server2 (%d):\n%s\n", res, gsasl_strerror (res));
183 return;
184 }
185
186 if (res == GSASL_OK || res == GSASL_NEEDS_MORE)
187 {
188 if (debug)
189 printf ("S: `%s' (%d) %s\n", s2 ? s2 : "", (int) strlen (s2),
190 gsasl_strerror_name (res));
191 }
192
193 /* The client receives the outcome data and sends a empty packet. */
194
195 res = gsasl_step64 (client, s2, &s1);
196 gsasl_free (s2);
197 if (res != expect_client_res)
198 {
199 fail ("gsasl_step client3 (%d):\n%s\n", res, gsasl_strerror (res));
200 return;
201 }
202
203 if (res == GSASL_OK || res == GSASL_NEEDS_MORE)
204 {
205 if (debug)
206 printf ("C: `%s' (%d) %s\n", s1 ? s1 : "", (int) strlen (s1),
207 gsasl_strerror_name (res));
208 }
209 else if (debug)
210 {
211 printf ("C: %s\n", gsasl_strerror_name (res));
212 s1 = NULL;
213 }
214
215 /* The server should reject authentication at this point */
216
217 res = gsasl_step64 (server, s1, &s2);
218 gsasl_free (s1);
219 if (res != expect_server2_res)
220 {
221 fail ("gsasl_step server3 (%d):\n%s\n", res, gsasl_strerror (res));
222 return;
223 }
224
225 if (res == GSASL_OK || res == GSASL_NEEDS_MORE)
226 {
227 if (debug)
228 printf ("S: `%s' (%d) %s\n", s2 ? s2 : "", (int) strlen (s2),
229 gsasl_strerror_name (res));
230 }
231 else if (debug)
232 {
233 printf ("S: %s\n", gsasl_strerror_name (res));
234 s2 = NULL;
235 }
236
237 /* The client should be called too many times now */
238
239 res = gsasl_step64 (client, s2, &s1);
240 gsasl_free (s2);
241 if (res != GSASL_MECHANISM_CALLED_TOO_MANY_TIMES)
242 {
243 fail ("gsasl_step client4 (%d):\n%s\n", res, gsasl_strerror (res));
244 return;
245 }
246
247 if (debug)
248 printf ("C: %s\n", gsasl_strerror_name (res));
249
250 if (authzid == NULL && gsasl_property_fast (server, GSASL_AUTHZID) == NULL)
251 success ("expected and got no authzid\n");
252 else if (!authzid && gsasl_property_fast (server, GSASL_AUTHZID))
253 fail ("got unexpected authzid? %s\n",
254 gsasl_property_fast (server, GSASL_AUTHZID));
255 else if (authzid && !gsasl_property_fast (server, GSASL_AUTHZID))
256 fail ("did not get authzid? %s\n", authzid);
257 else if (strcmp (authzid, gsasl_property_fast (server, GSASL_AUTHZID)) != 0)
258 fail ("authzid comparison failed: got %s expected %s\n",
259 gsasl_property_fast (server, GSASL_AUTHZID), authzid);
260
261 gsasl_finish (client);
262 gsasl_finish (server);
263 }
264
265 void
doit(void)266 doit (void)
267 {
268 Gsasl *c = NULL, *s = NULL;
269 int res;
270
271 res = gsasl_init (&c);
272 if (res != GSASL_OK)
273 {
274 fail ("gsasl_init() failed (%d):\n%s\n", res, gsasl_strerror (res));
275 return;
276 }
277
278 res = gsasl_init (&s);
279 if (res != GSASL_OK)
280 {
281 fail ("gsasl_init() failed (%d):\n%s\n", res, gsasl_strerror (res));
282 return;
283 }
284
285 if (!gsasl_client_support_p (c, "OPENID20"))
286 {
287 gsasl_done (c);
288 fail ("No support for OPENID20 clients.\n");
289 exit (77);
290 }
291
292 if (!gsasl_server_support_p (s, "OPENID20"))
293 {
294 gsasl_done (s);
295 fail ("No support for OPENID20 servers.\n");
296 exit (77);
297 }
298
299 gsasl_callback_set (c, client_callback);
300 gsasl_callback_set (s, server_callback);
301
302 printf ("Running successful authentication without SREG.\n");
303 openid20 (c, s);
304
305 printf ("Running successful authentication with SREG.\n");
306 sreg = "nickname=jas";
307 openid20 (c, s);
308
309 authzid = "user";
310 printf ("Running successful authentication without SREG with authzid.\n");
311 openid20 (c, s);
312
313 printf ("Running successful authentication with SREG with authzid.\n");
314 sreg = "nickname=jas";
315 openid20 (c, s);
316
317 printf ("Running failed authentication.\n");
318 validation_res = GSASL_AUTHENTICATION_ERROR;
319 expect_server_res = GSASL_NEEDS_MORE;
320 expect_client_res = GSASL_NEEDS_MORE;
321 expect_server2_res = GSASL_AUTHENTICATION_ERROR;
322 openid20 (c, s);
323
324 gsasl_done (c);
325 gsasl_done (s);
326 }
327