1 /*
2 * Test basic WebKDC login support without Kerberos.
3 *
4 * Perform the tests possible on the WebKDC login functionality without any
5 * Kerberos test configuration. This ensures we do some basic functionality
6 * tests even if no Kerberos configuration is provided.
7 *
8 * Written by Russ Allbery <eagle@eyrie.org>
9 * Copyright 2011, 2012, 2013, 2014
10 * The Board of Trustees of the Leland Stanford Junior University
11 *
12 * See LICENSE for licensing terms.
13 */
14
15 #include <config.h>
16 #include <portable/apr.h>
17 #include <portable/system.h>
18
19 #include <tests/tap/basic.h>
20 #include <tests/tap/webauth.h>
21 #include <webauth/basic.h>
22 #include <webauth/keys.h>
23 #include <webauth/webkdc.h>
24
25 /* Test cases to run without an identity file. */
26 static const struct wat_login_test tests_login[] = {
27
28 /* Attempt login with no authentication. */
29 {
30 "No authentication",
31 WA_PEC_PROXY_TOKEN_REQUIRED,
32 "webkdc-proxy token required",
33 {
34 { "krb5:webauth/example.com@EXAMPLE.COM", 0, 0 },
35 NO_TOKENS_LOGIN,
36 NO_TOKENS_WKPROXY,
37 NO_TOKENS_WKFACTOR,
38 NULL,
39 {
40 "id", "webkdc", NULL, NULL, 0, "https://example.com/", NULL,
41 NULL, NULL, 0, NULL, 0
42 }
43 },
44 {
45 NULL, NULL,
46 NO_FACTOR_DATA,
47 NO_TOKENS_WKPROXY,
48 EMPTY_TOKEN_WKFACTOR,
49 EMPTY_TOKEN_ID,
50 EMPTY_TOKEN_PROXY,
51 NO_LOGINS,
52 0,
53 NO_AUTHZ_IDS
54 },
55 },
56
57 /* The same, but with a login cancel token. */
58 {
59 "No authentication and login cancel",
60 WA_PEC_PROXY_TOKEN_REQUIRED,
61 "webkdc-proxy token required",
62 {
63 { "krb5:webauth/example.com@EXAMPLE.COM", 0, 0 },
64 NO_TOKENS_LOGIN,
65 NO_TOKENS_WKPROXY,
66 NO_TOKENS_WKFACTOR,
67 NULL,
68 {
69 "id", "webkdc", NULL, NULL, 0, "https://example.com/", "lc",
70 NULL, NULL, 0, NULL, 0
71 }
72 },
73 {
74 NULL, NULL,
75 NO_FACTOR_DATA,
76 NO_TOKENS_WKPROXY,
77 EMPTY_TOKEN_WKFACTOR,
78 EMPTY_TOKEN_ID,
79 EMPTY_TOKEN_PROXY,
80 NO_LOGINS,
81 0,
82 NO_AUTHZ_IDS
83 },
84 },
85
86 /* Attempt a login with a malformatted principal. */
87 {
88 "Login with malformatted principal",
89 WA_PEC_USER_REJECTED,
90 "Kerberos error",
91 {
92 { "krb5:webauth/example.com@EXAMPLE.COM", 0, 0 },
93 {
94 { "example\\", "testpassword", NULL, NULL, NULL, 0 },
95 EMPTY_TOKEN_LOGIN,
96 EMPTY_TOKEN_LOGIN
97 },
98 NO_TOKENS_WKPROXY,
99 NO_TOKENS_WKFACTOR,
100 NULL,
101 {
102 "id", "webkdc", NULL, "data", 4, "https://example.com/", NULL,
103 NULL, NULL, 0, NULL, 0
104 }
105 },
106 {
107 NULL, NULL,
108 NO_FACTOR_DATA,
109 NO_TOKENS_WKPROXY,
110 EMPTY_TOKEN_WKFACTOR,
111 EMPTY_TOKEN_ID,
112 EMPTY_TOKEN_PROXY,
113 NO_LOGINS,
114 0,
115 NO_AUTHZ_IDS
116 },
117 },
118
119 /* Pass in a webkdc-proxy token and obtain an id token. */
120 {
121 "webkdc-proxy authentication",
122 LOGIN_SUCCESS,
123 {
124 { "krb5:webauth/example.com@EXAMPLE.COM", 0, 0 },
125 NO_TOKENS_LOGIN,
126 {
127 {
128 "testuser", "remuser", "WEBKDC:remuser", "testuser", 8,
129 "x,x1", 3, 1365725079, 1938063600, NULL
130 },
131 EMPTY_TOKEN_WKPROXY,
132 EMPTY_TOKEN_WKPROXY
133 },
134 NO_TOKENS_WKFACTOR,
135 NULL,
136 {
137 "id", "webkdc", NULL, "data", 4, "https://example.com/", "lc",
138 NULL, NULL, 0, NULL, 0
139 }
140 },
141 {
142 NULL, NULL,
143 NO_FACTOR_DATA,
144 {
145 {
146 "testuser", "remuser", "WEBKDC:remuser", "testuser", 8,
147 "x,x1", 3, 1365725079, 1938063600, NULL
148 },
149 EMPTY_TOKEN_WKPROXY,
150 EMPTY_TOKEN_WKPROXY
151 },
152 EMPTY_TOKEN_WKFACTOR,
153 {
154 "testuser", NULL, "webkdc", NULL, 0, "x,x1", NULL, 3,
155 0, 1938063600
156 },
157 EMPTY_TOKEN_PROXY,
158 NO_LOGINS,
159 0,
160 NO_AUTHZ_IDS
161 },
162 },
163
164 /* The same, but also add a webkdc-factor token. */
165 {
166 "webkdc-proxy and webkdc-factor authentication",
167 LOGIN_SUCCESS,
168 {
169 { "krb5:webauth/example.com@EXAMPLE.COM", 0, 0 },
170 NO_TOKENS_LOGIN,
171 {
172 {
173 "testuser", "remuser", "WEBKDC:remuser", "testuser", 8,
174 "x,x1", 3, 1365725079, 1938063600, NULL
175 },
176 EMPTY_TOKEN_WKPROXY,
177 EMPTY_TOKEN_WKPROXY
178 },
179 {
180 { "testuser", "d", 0, 1906527600 },
181 EMPTY_TOKEN_WKFACTOR,
182 EMPTY_TOKEN_WKFACTOR
183 },
184 NULL,
185 {
186 "id", "webkdc", NULL, NULL, 0, "https://example.com/", "lc",
187 NULL, NULL, 0, NULL, 0
188 }
189 },
190 {
191 NULL, NULL,
192 NO_FACTOR_DATA,
193 {
194 {
195 "testuser", "remuser", "WEBKDC:remuser", "testuser", 8,
196 "x,x1,d", 3, 1365725079, 1938063600, NULL
197 },
198 EMPTY_TOKEN_WKPROXY,
199 EMPTY_TOKEN_WKPROXY
200 },
201 { "testuser", "d", 0, 1906527600 },
202 {
203 "testuser", NULL, "webkdc", NULL, 0, "x,x1,d", "d", 3,
204 0, 1938063600
205 },
206 EMPTY_TOKEN_PROXY,
207 NO_LOGINS,
208 0,
209 NO_AUTHZ_IDS
210 },
211 },
212
213 /* Forced login with a proxy token should fail. */
214 {
215 "Forced login with webkdc-proxy token",
216 WA_PEC_LOGIN_FORCED,
217 "forced authentication, must reauthenticate",
218 {
219 { "krb5:webauth/example.com@EXAMPLE.COM", 0, 0 },
220 NO_TOKENS_LOGIN,
221 {
222 {
223 "testuser", "remuser", "WEBKDC:remuser", "testuser", 8,
224 "x,x1", 3, 10, 60, NULL
225 },
226 EMPTY_TOKEN_WKPROXY,
227 EMPTY_TOKEN_WKPROXY
228 },
229 NO_TOKENS_WKFACTOR,
230 NULL,
231 {
232 "id", "webkdc", NULL, NULL, 0, "https://example.com/", "fa",
233 NULL, NULL, 0, NULL, 0
234 }
235 },
236 {
237 NULL, NULL,
238 NO_FACTOR_DATA,
239 {
240 {
241 "testuser", "remuser", "WEBKDC:remuser", "testuser", 8,
242 "x,x1", 3, 10, 60, NULL
243 },
244 EMPTY_TOKEN_WKPROXY,
245 EMPTY_TOKEN_WKPROXY
246 },
247 EMPTY_TOKEN_WKFACTOR,
248 EMPTY_TOKEN_ID,
249 EMPTY_TOKEN_PROXY,
250 NO_LOGINS,
251 0,
252 NO_AUTHZ_IDS
253 },
254 },
255
256 /*
257 * An initial factor requirement of p with a webkdc-proxy token for
258 * something other than p should result in a forced login error code, not
259 * multifactor required.
260 */
261 {
262 "Initial factor of p required with different webkdc-proxy factors",
263 WA_PEC_LOGIN_FORCED,
264 "forced authentication, must reauthenticate",
265 {
266 { "krb5:webauth/example.com@EXAMPLE.COM", 0, 0 },
267 NO_TOKENS_LOGIN,
268 {
269 {
270 "testuser", "remuser", "WEBKDC:remuser", "testuser", 8,
271 "x,x1", 3, 10, 60, NULL
272 },
273 EMPTY_TOKEN_WKPROXY,
274 EMPTY_TOKEN_WKPROXY
275 },
276 NO_TOKENS_WKFACTOR,
277 NULL,
278 {
279 "id", "webkdc", NULL, NULL, 0, "https://example.com/", NULL,
280 "p", NULL, 0, NULL, 0
281 }
282 },
283 {
284 NULL, NULL,
285 "p", "p",
286 {
287 {
288 "testuser", "remuser", "WEBKDC:remuser", "testuser", 8,
289 "x,x1", 3, 10, 60, NULL
290 },
291 EMPTY_TOKEN_WKPROXY,
292 EMPTY_TOKEN_WKPROXY
293 },
294 EMPTY_TOKEN_WKFACTOR,
295 EMPTY_TOKEN_ID,
296 EMPTY_TOKEN_PROXY,
297 NO_LOGINS,
298 0,
299 NO_AUTHZ_IDS
300 },
301 },
302
303 /*
304 * A proxy token request with a webkdc-proxy token without a Kerberos
305 * authenticator should fail.
306 */
307 {
308 "Proxy token request with webkdc-proxy token",
309 WA_PEC_PROXY_TOKEN_REQUIRED,
310 "webkdc-proxy token required",
311 {
312 { "krb5:webauth/example.com@EXAMPLE.COM", 0, 0 },
313 NO_TOKENS_LOGIN,
314 {
315 {
316 "testuser", "remuser", "WEBKDC:remuser", "testuser", 8,
317 "x,x1", 3, 1365725079, 1938063600, NULL
318 },
319 EMPTY_TOKEN_WKPROXY,
320 EMPTY_TOKEN_WKPROXY
321 },
322 NO_TOKENS_WKFACTOR,
323 NULL,
324 {
325 "proxy", NULL, "krb5", NULL, 0, "https://example.com/", NULL,
326 NULL, NULL, 0, NULL, 0
327 }
328 },
329 {
330 NULL, NULL,
331 NULL, "p",
332 {
333 {
334 "testuser", "remuser", "WEBKDC:remuser", "testuser", 8,
335 "x,x1", 3, 1365725079, 1938063600, NULL
336 },
337 EMPTY_TOKEN_WKPROXY,
338 EMPTY_TOKEN_WKPROXY
339 },
340 EMPTY_TOKEN_WKFACTOR,
341 EMPTY_TOKEN_ID,
342 EMPTY_TOKEN_PROXY,
343 NO_LOGINS,
344 0,
345 NO_AUTHZ_IDS
346 },
347 },
348
349 /*
350 * A Kerberos authenticator request with a webkdc-proxy token without
351 * Kerberos tickets should fail.
352 */
353 {
354 "Kerberos authenticator request with webkdc-proxy token",
355 WA_PEC_PROXY_TOKEN_REQUIRED,
356 "webkdc-proxy token required",
357 {
358 { "krb5:webauth/example.com@EXAMPLE.COM", 0, 0 },
359 NO_TOKENS_LOGIN,
360 {
361 {
362 "testuser", "remuser", "WEBKDC:remuser", "testuser", 8,
363 "x,x1", 3, 1365725079, 1938063600, NULL
364 },
365 EMPTY_TOKEN_WKPROXY,
366 EMPTY_TOKEN_WKPROXY
367 },
368 NO_TOKENS_WKFACTOR,
369 NULL,
370 {
371 "id", "krb5", NULL, NULL, 0, "https://example.com/", NULL,
372 NULL, NULL, 0, NULL, 0
373 }
374 },
375 {
376 NULL, NULL,
377 NULL, "p",
378 {
379 {
380 "testuser", "remuser", "WEBKDC:remuser", "testuser", 8,
381 "x,x1", 3, 1365725079, 1938063600, NULL
382 },
383 EMPTY_TOKEN_WKPROXY,
384 EMPTY_TOKEN_WKPROXY
385 },
386 EMPTY_TOKEN_WKFACTOR,
387 EMPTY_TOKEN_ID,
388 EMPTY_TOKEN_PROXY,
389 NO_LOGINS,
390 0,
391 NO_AUTHZ_IDS
392 },
393 }
394 };
395
396 /* Test cases to run with a login timeout of 15 minutes. */
397 static const struct wat_login_test tests_time_limit[] = {
398
399 /* Forced login should still fail with a fresh webkdc-proxy token. */
400 {
401 "Forced login within login timeout",
402 WA_PEC_LOGIN_FORCED,
403 "forced authentication, must reauthenticate",
404 {
405 { "krb5:webauth/example.com@EXAMPLE.COM", 0, 0 },
406 NO_TOKENS_LOGIN,
407 {
408 {
409 "testuser", "remuser", "WEBKDC:remuser", "testuser", 8,
410 "x,x1", 3, 10, 60, NULL
411 },
412 EMPTY_TOKEN_WKPROXY,
413 EMPTY_TOKEN_WKPROXY
414 },
415 NO_TOKENS_WKFACTOR,
416 NULL,
417 {
418 "id", "webkdc", NULL, NULL, 0, "https://example.com/", "fa",
419 NULL, NULL, 0, NULL, 0
420 }
421 },
422 {
423 NULL, NULL,
424 NO_FACTOR_DATA,
425 {
426 {
427 "testuser", "remuser", "WEBKDC:remuser", "testuser", 8,
428 "x,x1", 3, 10, 60, NULL
429 },
430 EMPTY_TOKEN_WKPROXY,
431 EMPTY_TOKEN_WKPROXY
432 },
433 EMPTY_TOKEN_WKFACTOR,
434 EMPTY_TOKEN_ID,
435 EMPTY_TOKEN_PROXY,
436 NO_LOGINS,
437 0,
438 NO_AUTHZ_IDS
439 },
440 },
441 };
442
443 /* Test cases to run with an identity file. */
444 static const struct wat_login_test tests_id_acl[] = {
445
446 /* Don't attempt to assert an identity. */
447 {
448 "Proxy authentication with identity ACL",
449 LOGIN_SUCCESS,
450 {
451 { "krb5:webauth/example.com@EXAMPLE.COM", 0, 0 },
452 NO_TOKENS_LOGIN,
453 {
454 {
455 "testuser", "remuser", "WEBKDC:remuser", "testuser", 8,
456 "x,x1", 3, 1365725079, 1938063600, NULL
457 },
458 EMPTY_TOKEN_WKPROXY,
459 EMPTY_TOKEN_WKPROXY
460 },
461 NO_TOKENS_WKFACTOR,
462 NULL,
463 {
464 "id", "webkdc", NULL, NULL, 0, "https://example.com/", NULL,
465 NULL, NULL, 0, NULL, 0
466 }
467 },
468 {
469 NULL, NULL,
470 NO_FACTOR_DATA,
471 {
472 {
473 "testuser", "remuser", "WEBKDC:remuser", "testuser", 8,
474 "x,x1", 3, 1365725079, 1938063600, NULL
475 },
476 EMPTY_TOKEN_WKPROXY,
477 EMPTY_TOKEN_WKPROXY
478 },
479 EMPTY_TOKEN_WKFACTOR,
480 {
481 "testuser", NULL, "webkdc", NULL, 0, "x,x1", NULL, 3,
482 0, 1938063600
483 },
484 EMPTY_TOKEN_PROXY,
485 NO_LOGINS,
486 0,
487 { "otheruser", "bar", NULL }
488 },
489 },
490
491 /* Now assert an authorization identity. */
492 {
493 "Proxy authentication with authorization identity",
494 LOGIN_SUCCESS,
495 {
496 { "krb5:webauth/example.com@EXAMPLE.COM", 0, 0 },
497 NO_TOKENS_LOGIN,
498 {
499 {
500 "testuser", "remuser", "WEBKDC:remuser", "testuser", 8,
501 "x,x1", 3, 1365725079, 1938063600, NULL
502 },
503 EMPTY_TOKEN_WKPROXY,
504 EMPTY_TOKEN_WKPROXY
505 },
506 NO_TOKENS_WKFACTOR,
507 "otheruser",
508 {
509 "id", "webkdc", NULL, NULL, 0, "https://example.com/", NULL,
510 NULL, NULL, 0, NULL, 0
511 }
512 },
513 {
514 NULL, NULL,
515 NO_FACTOR_DATA,
516 {
517 {
518 "testuser", "remuser", "WEBKDC:remuser", "testuser", 8,
519 "x,x1", 3, 1365725079, 1938063600, NULL
520 },
521 EMPTY_TOKEN_WKPROXY,
522 EMPTY_TOKEN_WKPROXY
523 },
524 EMPTY_TOKEN_WKFACTOR,
525 {
526 "testuser", "otheruser", "webkdc", NULL, 0, "x,x1", NULL, 3,
527 0, 1938063600
528 },
529 EMPTY_TOKEN_PROXY,
530 NO_LOGINS,
531 0,
532 { "otheruser", "bar", NULL }
533 },
534 },
535
536 /* Assert an identity we're not allowed to assert. */
537 {
538 "Unauthorized authorization identity",
539 WA_PEC_UNAUTHORIZED,
540 "authorization denied (may not assert that identity)",
541 {
542 { "krb5:webauth/example.com@EXAMPLE.COM", 0, 0 },
543 NO_TOKENS_LOGIN,
544 {
545 {
546 "testuser", "remuser", "WEBKDC:remuser", "testuser", 8,
547 "x,x1", 3, 1365725079, 1938063600, NULL
548 },
549 EMPTY_TOKEN_WKPROXY,
550 EMPTY_TOKEN_WKPROXY
551 },
552 NO_TOKENS_WKFACTOR,
553 "foo",
554 {
555 "id", "webkdc", NULL, NULL, 0, "https://example.com/", "lc",
556 NULL, NULL, 0, NULL, 0
557 }
558 },
559 {
560 NULL, NULL,
561 NO_FACTOR_DATA,
562 {
563 {
564 "testuser", "remuser", "WEBKDC:remuser", "testuser", 8,
565 "x,x1", 3, 1365725079, 1938063600, NULL
566 },
567 EMPTY_TOKEN_WKPROXY,
568 EMPTY_TOKEN_WKPROXY
569 },
570 EMPTY_TOKEN_WKFACTOR,
571 EMPTY_TOKEN_ID,
572 EMPTY_TOKEN_PROXY,
573 NO_LOGINS,
574 0,
575 { "otheruser", "bar", NULL }
576 },
577 },
578
579 /* Assert the same identity as the subject. */
580 {
581 "Authorization identity matching subject",
582 LOGIN_SUCCESS,
583 {
584 { "krb5:webauth/example.com@EXAMPLE.COM", 0, 0 },
585 NO_TOKENS_LOGIN,
586 {
587 {
588 "testuser", "remuser", "WEBKDC:remuser", "testuser", 8,
589 "x,x1", 3, 1365725079, 1938063600, NULL
590 },
591 EMPTY_TOKEN_WKPROXY,
592 EMPTY_TOKEN_WKPROXY
593 },
594 NO_TOKENS_WKFACTOR,
595 "testuser",
596 {
597 "id", "webkdc", NULL, NULL, 0, "https://example.com/", NULL,
598 NULL, NULL, 0, NULL, 0
599 }
600 },
601 {
602 NULL, NULL,
603 NO_FACTOR_DATA,
604 {
605 {
606 "testuser", "remuser", "WEBKDC:remuser", "testuser", 8,
607 "x,x1", 3, 1365725079, 1938063600, NULL
608 },
609 EMPTY_TOKEN_WKPROXY,
610 EMPTY_TOKEN_WKPROXY
611 },
612 EMPTY_TOKEN_WKFACTOR,
613 {
614 "testuser", NULL, "webkdc", NULL, 0, "x,x1", NULL, 3,
615 0, 1938063600
616 },
617 EMPTY_TOKEN_PROXY,
618 NO_LOGINS,
619 0,
620 { "otheruser", "bar", NULL }
621 },
622 }
623 };
624
625
626 int
main(void)627 main(void)
628 {
629 apr_pool_t *pool = NULL;
630 struct webauth_context *ctx;
631 struct webauth_keyring *ring;
632 struct webauth_webkdc_config config;
633 size_t i;
634 int s;
635 char *keyring;
636
637 /* Use lazy planning so that test counts can vary on some errors. */
638 plan_lazy();
639
640 /* Initialize APR and WebAuth. */
641 if (apr_initialize() != APR_SUCCESS)
642 bail("cannot initialize APR");
643 if (apr_pool_create(&pool, NULL) != APR_SUCCESS)
644 bail("cannot create memory pool");
645 if (webauth_context_init_apr(&ctx, pool) != WA_ERR_NONE)
646 bail("cannot initialize WebAuth context");
647
648 /* Load the precreated keyring that we'll use for token encryption. */
649 keyring = test_file_path("data/keyring");
650 s = webauth_keyring_read(ctx, keyring, &ring);
651 if (s != WA_ERR_NONE)
652 bail("cannot read %s: %s", keyring, webauth_error_message(ctx, s));
653 test_file_path_free(keyring);
654
655 /* Provide basic configuration to the WebKDC code. */
656 memset(&config, 0, sizeof(config));
657 config.local_realms = apr_array_make(pool, 0, sizeof(const char *));
658 config.permitted_realms = apr_array_make(pool, 0, sizeof(const char *));
659 s = webauth_webkdc_config(ctx, &config);
660 if (s != WA_ERR_NONE)
661 diag("configuration failed: %s", webauth_error_message(ctx, s));
662 is_int(WA_ERR_NONE, s, "WebKDC configuration succeeded");
663
664 /* Run the first set of tests. */
665 for (i = 0; i < ARRAY_SIZE(tests_login); i++)
666 run_login_test(ctx, &tests_login[i], ring, NULL);
667
668 /*
669 * Set a login time limit of 15 minutes. Since the webkdc-proxy tokens
670 * are dated 10 minutes ago, this will make them considered fresh.
671 */
672 config.login_time_limit = 15 * 60;
673 s = webauth_webkdc_config(ctx, &config);
674 if (s != WA_ERR_NONE)
675 diag("configuration failed: %s", webauth_error_message(ctx, s));
676 is_int(WA_ERR_NONE, s, "Setting login timeout succeeded");
677
678 /* Run the batch of tests requiring the login timeout setting. */
679 for (i = 0; i < ARRAY_SIZE(tests_time_limit); i++)
680 run_login_test(ctx, &tests_time_limit[i], ring, NULL);
681
682 /* Set up an identity ACL (and clear the login time limit). */
683 config.id_acl_path = test_file_path("data/id.acl");
684 config.login_time_limit = 0;
685 s = webauth_webkdc_config(ctx, &config);
686 if (s != WA_ERR_NONE)
687 diag("configuration failed: %s", webauth_error_message(ctx, s));
688 is_int(WA_ERR_NONE, s, "Identity ACL configuration succeeded");
689
690 /* Run the batch of tests requiring an identity ACL. */
691 for (i = 0; i < ARRAY_SIZE(tests_id_acl); i++)
692 run_login_test(ctx, &tests_id_acl[i], ring, NULL);
693
694 /* Clean up. */
695 apr_terminate();
696 test_file_path_free((char *) config.id_acl_path);
697 return 0;
698 }
699