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