1 /* zxid.c - CGI binary for SAML 2 SP
2 * Copyright (c) 2006 Symlabs (symlabs@symlabs.com), All Rights Reserved.
3 * Author: Sampo Kellomaki (sampo@iki.fi)
4 * This is confidential unpublished proprietary source code of the author.
5 * NO WARRANTY, not even implied warranties. Contains trade secrets.
6 * Distribution prohibited unless authorized in writing.
7 * Licensed under Apache License 2.0, see file COPYING.
8 * $Id: zxid.c,v 1.42 2009-11-24 23:53:40 sampo Exp $
9 *
10 * 15.4.2006, started work over Easter holiday --Sampo
11 * 22.4.2006, added more options over the weekend --Sampo
12 * 28.5.2006, adopted structure from s5066d --Sampo
13 * 30.9.2006, added signature verification --Sampo
14 *
15 * This file contains option processing, configuration, and main().
16 *
17 * See also: http://hoohoo.ncsa.uiuc.edu/cgi/interface.html (CGI specification)
18 *
19 * WARNING: This file is outdated. See zxidhlo.c instead.
20 */
21
22 #include "platform.h"
23 #include <string.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <errno.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 //#include <sys/wait.h>
30 //#include <pthread.h>
31 #include <signal.h>
32 #include <fcntl.h>
33 //#include <netdb.h>
34
35 #ifdef USE_CURL
36 #include <curl/curl.h>
37 #endif
38
39 #include <zx/errmac.h>
40 #include <zx/zx.h>
41 #include <zx/zxid.h>
42 #include <zx/zxidpriv.h>
43 #include <zx/zxidutil.h>
44 #include <zx/zxidconf.h>
45 #include <zx/c/zxidvers.h>
46 #include <zx/c/zx-ns.h>
47 #include <zx/c/zx-md-data.h>
48
49 char* help =
50 "zxid - SAML 2.0 SP CGI - R" ZXID_REL "\n\
51 SAML 2.0 is a standard for federated identity and Single Sign-On.\n\
52 Copyright (c) 2006 Symlabs (symlabs@symlabs.com), All Rights Reserved.\n\
53 Author: Sampo Kellomaki (sampo@iki.fi)\n\
54 NO WARRANTY, not even implied warranties. Licensed under Apache License v2.0\n\
55 See http://www.apache.org/licenses/LICENSE-2.0\n\
56 Send well researched bug reports to the author. Home: zxid.org\n\
57 \n\
58 Usage: zxid [options] (when used as CGI, no options can be supplied)\n\
59 -meta Dump our own metadata to stdout.\n\
60 -import URL Import metadata of others from URL, usually their Entity ID\n\
61 or Provider ID, aka well known location. The imported metadata\n\
62 is written to CoT cache directory.\n\
63 -fileimport FILE Import metadata of others from file.\n\
64 -C CONFPATH Path to (optional) config file, default " ZXID_CONF_PATH "\n\
65 -c OPT=VAL Override default or config file option. Only after -C, if any.\n\
66 -t SECONDS Timeout. Default: 0=no timeout.\n\
67 -k FDNUMBER File descriptor for reading symmetric key. Use 0 for stdin.\n\
68 -egd PATH Specify path of Entropy Gathering Daemon socket, default on\n\
69 Solaris: /tmp/entropy. On Linux /dev/urandom is used instead\n\
70 See http://www.lothar.com/tech/crypto/ or\n\
71 http://www.aet.tu-cottbus.de/personen/jaenicke/postfix_tls/prngd.html\n\
72 -rand PATH Location of random number seed file. On Solaris EGD is used.\n\
73 On Linux the default is /dev/urandom. See RFC1750.\n\
74 -uid UID:GID If run as root, drop privileges and assume specified uid and gid.\n\
75 -v Verbose messages.\n\
76 -q Be extra quiet.\n\
77 -d Turn on debugging.\n\
78 -license Show licensing details, including NATO C3 Agency disclaimer.\n\
79 -h This help message\n\
80 -- End of options\n";
81
82 int ak_buf_size = 0;
83 int verbose = 1;
84 int timeout = 0;
85 int gcthreshold = 0;
86 int leak_free = 0;
87 int drop_uid = 0;
88 int drop_gid = 0;
89 char* rand_path;
90 char* egd_path;
91 char symmetric_key[1024];
92 int symmetric_key_len;
93 char buf[32*1024];
94
95 /* N.B. This options processing is a skeleton. In reality CGI scripts do not have
96 * an opportunity to process any options. */
97
98 /* Called by: main x8, zxbusd_main, zxbuslist_main, zxbustailf_main, zxcall_main, zxcot_main, zxdecode_main */
opt(int * argc,char *** argv,char *** env,zxid_conf * cf,zxid_cgi * cgi)99 void opt(int* argc, char*** argv, char*** env, zxid_conf* cf, zxid_cgi* cgi)
100 {
101 char* conf_path = 0;
102 if (*argc <= 1) return;
103
104 while (1) {
105 ++(*argv); --(*argc);
106
107 if (!(*argc) || ((*argv)[0][0] != '-')) break; /* normal exit from options loop */
108
109 switch ((*argv)[0][1]) {
110 case '-': if ((*argv)[0][2]) break;
111 ++(*argv); --(*argc);
112 DD("End of options by --");
113 return; /* -- ends the options */
114
115 case 'C': if ((*argv)[0][2]) break;
116 ++(*argv); --(*argc);
117 if (!(*argc)) break;
118 conf_path = **argv;
119 continue;
120
121 case 'c': if ((*argv)[0][2]) break;
122 ++(*argv); --(*argc);
123 if (!(*argc)) break;
124 if (conf_path != (char*)1) {
125 if (conf_path)
126 read_all(sizeof(buf), buf, "new conf path in opt", 1, "%s", conf_path);
127 else
128 read_all(sizeof(buf), buf, "no conf path in opt", 1, "%s" ZXID_CONF_FILE, cf->cpath);
129 zxid_parse_conf(cf, buf);
130 conf_path = (char*)1;
131 }
132 zxid_parse_conf(cf, **argv);
133 continue;
134
135 case 'd':
136 switch ((*argv)[0][2]) {
137 case '\0':
138 ++errmac_debug;
139 continue;
140 case 'i': if ((*argv)[0][3]) break;
141 ++(*argv); --(*argc);
142 if (!(*argc)) break;
143 strcpy(errmac_instance, (*argv)[0]);
144 continue;
145 }
146 break;
147
148 case 'e':
149 switch ((*argv)[0][2]) {
150 case 'g': if ((*argv)[0][3] != 'd' || (*argv)[0][4]) break;
151 ++(*argv); --(*argc);
152 if (!(*argc)) break;
153 egd_path = (*argv)[0];
154 continue;
155 }
156 break;
157
158 case 'i':
159 switch ((*argv)[0][2]) {
160 case 'm':
161 if (!strcmp((*argv)[0],"-import")) {
162 zxid_entity* ent;
163 ++(*argv); --(*argc);
164 if (!(*argc)) break;
165 cf->ctx->ns_tab = zx_ns_tab;
166 ent = zxid_get_meta(cf, (*argv)[0]);
167 if (ent)
168 zxid_write_ent_to_cache(cf, ent);
169 exit(0);
170 }
171 break;
172 }
173 break;
174 #if 0
175 case 'f':
176 switch ((*argv)[0][2]) {
177 case 'i':
178 if (!strcmp((*argv)[0],"-fileimport")) {
179 zxid_entity* ent;
180 ++(*argv); --(*argc);
181 if (!(*argc)) break;
182 cf->ctx->ns_tab = zx_ns_tab;
183 ent = zxid_get_meta(cf, (*argv)[0]);
184 if (ent)
185 zxid_write_ent_to_cache(cf, ent);
186 exit(0);
187 }
188 break;
189 }
190 break;
191 #endif
192 #ifndef MINGW
193 case 'k':
194 switch ((*argv)[0][2]) {
195 case '\0':
196 ++(*argv); --(*argc);
197 if (!(*argc)) break;
198 read_all_fd((fdtype)atoi((*argv)[0]), symmetric_key, sizeof(symmetric_key), &symmetric_key_len);
199 D("Got %d characters of symmetric key", symmetric_key_len);
200 continue;
201 }
202 break;
203 #endif
204
205 case 'l':
206 switch ((*argv)[0][2]) {
207 case 'i':
208 if (!strcmp((*argv)[0],"-license")) {
209 extern char* license;
210 fprintf(stderr, "%s", license);
211 exit(0);
212 }
213 break;
214 }
215 break;
216
217 case 'm':
218 switch ((*argv)[0][2]) {
219 case 'e':
220 if (!strcmp((*argv)[0],"-meta")) {
221 cf->ctx->ns_tab = zx_ns_tab;
222 zxid_send_sp_meta(cf, cgi);
223 exit(0);
224 }
225 break;
226 }
227 break;
228
229 case 'q':
230 switch ((*argv)[0][2]) {
231 case '\0':
232 verbose = 0;
233 continue;
234 }
235 break;
236
237 case 'r':
238 switch ((*argv)[0][2]) {
239 case 'f':
240 /*AK_TS(LEAK, 0, "memory leaks enabled");*/
241 ERR("*** WARNING: You have turned memory frees to memory leaks. We will (eventually) run out of memory. Using -rf is not recommended. %d\n", 0);
242 ++leak_free;
243 continue;
244 #if 0
245 case 'e': /* -re */
246 if ((*argv)[0][3]) break;
247 ++(*argv); --(*argc);
248 if ((*argc) < 4) break;
249 sscanf((*argv)[0], "%i", &abort_funcno);
250 ++(*argv); --(*argc);
251 sscanf((*argv)[0], "%i", &abort_line);
252 ++(*argv); --(*argc);
253 sscanf((*argv)[0], "%i", &abort_error_code);
254 ++(*argv); --(*argc);
255 sscanf((*argv)[0], "%i", &abort_iter);
256 fprintf(stderr, "Will force core upon %x:%x err=%d iter=%d\n",
257 abort_funcno, abort_line, abort_error_code, abort_iter);
258 continue;
259 #endif
260 case 'g': /* -rg */
261 if ((*argv)[0][3]) break;
262 ++(*argv); --(*argc);
263 if (!(*argc)) break;
264 gcthreshold = atoi((*argv)[0]);
265 if (!gcthreshold)
266 ERR("*** WARNING: You have disabled garbage collection. This may lead to increased memory consumption for scripts that handle a lot of PDUs or run for long time. Using `-rg 0' is not recommended. %d\n", 0);
267 continue;
268 case 'a': /* -ra */
269 if ((*argv)[0][3] == 0) {
270 /*AK_TS(ASSERT_NONFATAL, 0, "assert nonfatal enabled");*/
271 #if 1
272 ERR("*** WARNING: YOU HAVE TURNED ASSERTS OFF USING -ra FLAG. THIS MEANS THAT YOU WILL NOT BE ABLE TO OBTAIN ANY SUPPORT. IF PROGRAM NOW TRIES TO ASSERT IT MAY MYSTERIOUSLY AND UNPREDICTABLY CRASH INSTEAD, AND NOBODY WILL BE ABLE TO FIGURE OUT WHAT WENT WRONG OR HOW MUCH DAMAGE MAY BE DONE. USING -ra IS NOT RECOMMENDED. %d\n", assert_nonfatal);
273 #endif
274 ++assert_nonfatal;
275 continue;
276 }
277 if (!strcmp((*argv)[0],"-rand")) {
278 ++(*argv); --(*argc);
279 if (!(*argc)) break;
280 rand_path = (*argv)[0];
281 continue;
282 }
283 break;
284 }
285 break;
286
287 case 't': if ((*argv)[0][2]) break;
288 ++(*argv); --(*argc);
289 if (!(*argc)) break;
290 timeout = atoi((*argv)[0]);
291 continue;
292
293 case 'u':
294 switch ((*argv)[0][2]) {
295 case 'i': if ((*argv)[0][3] != 'd' || (*argv)[0][4]) break;
296 ++(*argv); --(*argc);
297 if (!(*argc)) break;
298 sscanf((*argv)[0], "%i:%i", &drop_uid, &drop_gid);
299 continue;
300 }
301 break;
302
303 case 'v':
304 switch ((*argv)[0][2]) {
305 case '\0':
306 ++verbose;
307 continue;
308 }
309 break;
310
311 }
312 /* fall thru means unrecognized flag */
313 if (*argc)
314 fprintf(stderr, "Unrecognized flag `%s'\n", (*argv)[0]);
315 fprintf(stderr, "%s", help);
316 fprintf(stderr, "version=0x%06x rel(%s)\n", zxid_version(), zxid_version_str());
317 exit(3);
318 }
319 if (conf_path != (char*)1) {
320 if (conf_path)
321 read_all(sizeof(buf), buf, "conf_path in end of opt", 1, "%s", conf_path);
322 else
323 read_all(sizeof(buf), buf, "no conf_path in end of opt", 1, "%szxid.conf", cf->cpath);
324 zxid_parse_conf(cf, buf);
325 }
326 }
327
328 /* ============== Management Screen ============== */
329
330 /* This screen is only invoked if session is active. Zero return
331 * value causes the login screen to be rendered. */
332
333 /* Called by: main x7 */
zxid_mgmt(zxid_conf * cf,zxid_cgi * cgi,zxid_ses * ses)334 int zxid_mgmt(zxid_conf* cf, zxid_cgi* cgi, zxid_ses* ses)
335 {
336 struct zx_str* ss;
337 D("op(%c)", cgi->op);
338 switch (cgi->op) {
339 case 'l':
340 zxid_del_ses(cf, ses);
341 cgi->msg = "Local logout Ok. Session terminated.";
342 return 0; /* Simply abandon local session. Falls thru to login screen. */
343 case 'r':
344 ss = zxid_sp_slo_redir(cf, cgi, ses);
345 zxid_del_ses(cf, ses);
346 printf("%.*s", ss->len, ss->s);
347 zx_str_free(cf->ctx, ss);
348 fflush(stdout);
349 return 1; /* Redirect already happened. Do not show login screen. */
350 case 's':
351 zxid_sp_slo_soap(cf, cgi, ses);
352 zxid_del_ses(cf, ses);
353 cgi->msg = "SP Initiated logout (SOAP). Session terminated.";
354 return 0; /* Falls thru to login screen. */
355 case 't':
356 ss = zxid_sp_mni_redir(cf, cgi, ses, 0);
357 printf("%.*s", ss->len, ss->s);
358 zx_str_free(cf->ctx, ss);
359 fflush(stdout);
360 return 1; /* Redirect already happened. Do not show login screen. */
361 case 'u':
362 zxid_sp_mni_soap(cf, cgi, ses, 0);
363 cgi->msg = "SP Initiated defederation (SOAP).";
364 break; /* Defederation does not have to mean SLO */
365 case 'P':
366 case 'Q':
367 ss = zxid_sp_dispatch(cf, cgi, ses);
368 switch (ss->s[0]) {
369 case 'K': return 0;
370 case 'L':
371 printf("%.*s", ss->len, ss->s);
372 zx_str_free(cf->ctx, ss);
373 fflush(stdout);
374 return 1;
375 }
376 break;
377 }
378
379 //printf("COOKIE: foo\r\n");
380 printf("Content-Type: text/html\r\n\r\n");
381 printf("<title>ZXID SP Mgmt</title>" ZXID_BODY_TAG "<h1>ZXID SP Management (user logged in, session active)</h1><pre>\n");
382 //if (qs) printf("QS(%s)\n", qs);
383 //if (got>0) printf("GOT(%.*s)\n", got, buf);
384 printf("</pre><form method=post action=\"zxid?o=P\">");
385 if (cgi->err)
386 printf("<p><font color=red><i>%s</i></font></p>\n", cgi->err);
387 if (cgi->msg)
388 printf("<p><i>%s</i></p>\n", cgi->msg);
389 //printf("User:<input name=user> PW:<input name=pw type=password>");
390 //printf("<input name=login value=\" Login \" type=submit>");
391 printf("<input type=hidden name=s value=\"%s\">", ses->sid);
392 printf("<input type=submit name=gl value=\" Local Logout \">\n");
393 printf("<input type=submit name=gr value=\" Single Logout (Redir) \">\n");
394 printf("<input type=submit name=gs value=\" Single Logout (SOAP) \">\n");
395 printf("<input type=submit name=gt value=\" Defederate (Redir) \">\n");
396 printf("<input type=submit name=gu value=\" Defederate (SOAP) \">\n");
397
398 printf("<h3>Technical options (typically hidden fields on production site)</h3>\n");
399
400 printf("sid(%s) nid(%s) <a href=\"zxid?s=%s\">Reload</a>", ses->sid, ses->nid, ses->sid);
401
402 printf("</form><hr>");
403 printf("<a href=\"http://zxid.org/\">zxid.org</a>, %s", zxid_version_str());
404 if (cgi->dbg)
405 printf("<p><form><textarea cols=100 row=10>%s</textarea></form>\n", cgi->dbg);
406 return 1;
407 }
408
409 /* ============== M A I N ============== */
410
411 /* Called by: */
main(int argc,char ** argv,char ** env)412 int main(int argc, char** argv, char** env)
413 {
414 zxid_conf* cf = zxid_new_conf(ZXID_PATH);
415 zxid_ses ses;
416 zxid_cgi cgi;
417 int got;
418 char* qs;
419 char* cont_len;
420 struct zx_str* ss;
421 char* eid;
422 zxid_entity* idp;
423
424 #if 1
425 /* Helps debugging CGI scripts if you see stderr. */
426 close(2);
427 got = open("zxid.stderr", O_WRONLY | O_CREAT | O_APPEND, 0666);
428 if (got != 2)
429 exit(2);
430 fprintf(stderr, "=================== Running ===================\n");
431 ++errmac_debug;
432 zxid_set_opt(cf, 6, 0);
433 #endif
434 cf->nosig_fatal = 0; // *** For SimpleSign the signature is checked at other level
435
436 opt(&argc, &argv, &env, cf, &cgi);
437
438 /*if (stats_prefix) init_cmdline(argc, argv, env, stats_prefix);*/
439 CMDLINE("init");
440
441 #ifndef MINGW
442 /* *** all this cruft does not work on MINGW, but perhaps it should not even exist for Unix */
443 if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) { /* Ignore SIGPIPE */
444 perror("Init: signal ignore pipe");
445 exit(2);
446 }
447
448 /* Cause exit(3) to be called with the intent that any gcov profiling will get
449 * written to disk before we die. If not stopped with `kill -USR1' but you
450 * use plain kill instead, the profile will indicate many unexecuted (#####) lines. */
451 if (signal(SIGUSR1, exit) == SIG_ERR) {
452 perror("Init: signal USR1 exit");
453 exit(2);
454 }
455
456 /* Drop privileges, if requested. */
457
458 if (drop_gid) if (setgid(drop_gid)) { perror("Init: setgid"); exit(1); }
459 if (drop_uid) if (setuid(drop_uid)) { perror("Init: setuid"); exit(1); }
460 #endif
461
462 /* Pick up application variables from query string and post content (indicated by o=P in QS) */
463
464 ZERO(&cgi, sizeof(cgi));
465 qs = getenv("QUERY_STRING");
466 if (qs) {
467 D("QS(%s)", qs);
468 zxid_parse_cgi(cf, &cgi, qs);
469 if (cgi.op == 'P') {
470 cont_len = getenv("CONTENT_LENGTH");
471 if (cont_len) {
472 sscanf(cont_len, "%d", &got);
473 if (read_all_fd(fdstdin, buf, got, &got) == -1) {
474 perror("Trouble reading post content");
475 } else {
476 buf[got] = 0;
477 D("POST(%s) got=%d cont_len(%s)", buf, got, cont_len);
478 if (buf[0] == '<') { /* No BOM and looks XML */
479 return zxid_sp_soap_parse(cf, &cgi, &ses, got, buf);
480 }
481 if (buf[2] == '<') { /* UTF-16 BOM and looks XML */
482 return zxid_sp_soap_parse(cf, &cgi, &ses, got-2, buf+2);
483 }
484 if (buf[3] == '<') { /* UTF-8 BOM and looks XML */
485 return zxid_sp_soap_parse(cf, &cgi, &ses, got-3, buf+3);
486 }
487 zxid_parse_cgi(cf, &cgi, buf);
488 }
489 }
490 }
491 } else
492 cgi.op = 'M'; /* Bare `/zxid' as a URL means same as `/zxid?o=M' */
493
494 D("op(%c) sid(%s)", cgi.op, cgi.sid?cgi.sid:"-");
495
496 /* Check if user already has working session. */
497
498 if (cgi.sid) {
499 if (zxid_get_ses(cf, &ses, cgi.sid))
500 if (zxid_mgmt(cf, &cgi, &ses))
501 return 0;
502 }
503 ZERO(&ses, sizeof(ses));
504
505 switch (cgi.op) {
506 case 'M': /* Invoke LECP or redirect to CDC reader. */
507 if (zxid_lecp_check(cf, &cgi))
508 return 0;
509 printf("Location: %s?o=C\r\n\r\n", ZXID_CDC_URL);
510 return 0;
511 case 'C': /* CDC Read: Common Domain Cookie Reader */
512 if (zxid_cdc_read(cf, &cgi))
513 return 0;
514 return 1;
515 case 'E': /* Return from CDC read, or start here to by-pass CDC read. */
516 if (zxid_lecp_check(cf, &cgi))
517 return 0;
518 if (zxid_cdc_check(cf, &cgi))
519 return 0;
520 break;
521 case 'L':
522 if (ss = zxid_start_sso_location(cf, cgi)) {
523 printf("%.*s", ss->len, ss->s);
524 return 0;
525 }
526 break;
527 case 'A':
528 D("Process artifact(%s)", cgi.saml_art);
529 switch (zxid_sp_deref_art(cf, &cgi, &ses)) {
530 case ZXID_REDIR_OK: return 0;
531 case ZXID_SSO_OK:
532 if (zxid_mgmt(cf, &cgi, &ses))
533 return 0;
534 }
535 break;
536 case 'P':
537 case 'Q':
538 DD("Process response(%s)", cgi.saml_resp);
539 ss = zxid_sp_dispatch(cf, &cgi, &ses);
540 switch (ss->s[0]) {
541 case 'L':
542 printf("%.*s", ss->len, ss->s);
543 zx_str_free(cf->ctx, ss);
544 fflush(stdout);
545 return 0;
546 case 'O':
547 if (zxid_mgmt(cf, &cgi, &ses))
548 return 0;
549 }
550 break;
551 case 'B': /* Metadata */
552 write_all_fd(fdstdout, "Content-Type: text/xml\r\n\r\n", sizeof("Content-Type: text/xml\r\n\r\n")-1);
553 return zxid_send_sp_meta(cf, &cgi);
554 default: D("unknown op(%c)", cgi.op);
555 }
556
557 //printf("COOKIE: foo\r\n");
558 printf("Content-Type: text/html\r\n\r\n");
559 printf("<title>ZXID SP SSO</title>" ZXID_BODY_TAG "<h1>ZXID SP Federated SSO (user NOT logged in, no session)</h1><pre>\n");
560 //if (qs) printf("QS(%s)\n", qs);
561 //if (got>0) printf("GOT(%.*s)\n", got, buf);
562 printf("</pre><form method=post action=\"zxid?o=P\">");
563 if (cgi.err)
564 printf("<p><font color=red><i>%s</i></font></p>\n", cgi.err);
565 if (cgi.msg)
566 printf("<p><i>%s</i></p>\n", cgi.msg);
567 //printf("User:<input name=user> PW:<input name=pw type=password>");
568 //printf("<input name=login value=\" Login \" type=submit>");
569
570 printf("<h3>Login Using New IdP</h3>\n");
571 printf("<i>A new IdP is one whose metadata we do not have yet. We need to know the Entity ID in order to fetch the metadata using the well known location method. You will need to ask the adminstrator of the IdP to tell you what the EntityID is.</i>\n");
572 printf("<p>IdP EntityID URL <input name=e size=100>");
573 printf("<input type=submit name=l1 value=\" Login (SAML20:Artifact) \">\n");
574 printf("<input type=submit name=l2 value=\" Login (SAML20:POST) \"><br>\n");
575
576 idp = zxid_load_cot_cache(cf);
577
578 if (idp) {
579 printf("<h3>Login Using Known IdP</h3>\n");
580 for (; idp; idp = idp->n) {
581 if (!idp->ed->IDPSSODescriptor)
582 continue;
583 printf("<input type=submit name=\"l0%s\" value=\" Login to %s (SAML20:any) \">\n",
584 idp->eid, idp->eid);
585 printf("<input type=submit name=\"l1%s\" value=\" Login to %s (SAML20:Artifact) \">\n",
586 idp->eid, idp->eid);
587 printf("<input type=submit name=\"l2%s\" value=\" Login to %s (SAML20:POST) \">\n",
588 idp->eid, idp->eid);
589 printf("<input type=submit name=\"l5%s\" value=\" Login to %s (SAML20:SimpleSign) \">\n",
590 idp->eid, idp->eid);
591 }
592 }
593
594 #if 0
595 printf("<h3>Login Using IdP Discovered from Common Domain Cookie (CDC)</h3>\n");
596
597 printf("<input type=submit name=\"l1https://s-ps.liberty-iop.org:8881/idp.xml\" value=\" Login to test-idp3 (SAML20:Artifact) \">\n");
598 printf("<input type=submit name=\"l2https://s-ps.liberty-iop.org:8881/idp.xml\" value=\" Login to test-idp3 (SAML20:POST) \">\n");
599 #endif
600
601 printf("<h3>CoT configuration parameters your IdP may need to know</h3>\n");
602 eid = zxid_my_ent_id_cstr(cf);
603 printf("Entity ID of this SP: <a href=\"%s\">%s</a> (Click on the link to fetch SP metadata.)\n", eid, eid);
604
605 printf("<h3>Technical options (typically hidden fields on production site)</h3>\n");
606 printf("<input type=checkbox name=fc value=1 checked> Allow new federation to be created<br>\n");
607 printf("<input type=checkbox name=fp value=1> Do not allow IdP to interact (e.g. ask password) (IsPassive flag)<br>\n");
608 printf("<input type=checkbox name=ff value=1> IdP should reauthenticate user (ForceAuthn flag)<br>\n");
609
610 printf("NID Format: <select name=fn><option value=prstnt>Persistent<option value=trnsnt>Transient<option value=\"\">(none)</select><br>\n");
611 printf("Affiliation: <select name=fq><option value=\"\">(none)</select><br>\n");
612 printf("Consent: <select name=fy><option value=\"\">(empty)<option value=\"urn:liberty:consent:obtained\">obtained<option value=\"urn:liberty:consent:obtained:prior\">obtained:prior<option value=\"urn:liberty:consent:obtained:current:implicit\">obtained:current:implicit<option value=\"urn:liberty:consent:obtained:current:explicit\">obtained:current:explicit<option value=\"urn:liberty:consent:unavailable\">unavailable<option value=\"urn:liberty:consent:inapplicable\">inapplicable</select><br>\n");
613 printf("Authn Req Context: <select name=fa><option value=\"\">(none)<option value=pw>Password<option value=pwp>Password with Protected Transport<option value=clicert>TLS Client Certificate</select><br>\n");
614 printf("Matching Rule: <select name=fm><option value=exact>Exact<option value=minimum>Min<option value=maximum>Max<option value=better>Better<option value=\"\">(none)</select><br>\n");
615 printf("RelayState: <input name=fr value=\"rs123\"><br>\n");
616
617 printf("</form><hr>");
618 printf("<a href=\"http://zxid.org/\">zxid.org</a>, %s", zxid_version_str());
619 if (cgi.dbg)
620 printf("<p><form><textarea cols=100 row=10>%s</textarea></form>\n", cgi.dbg);
621 return 0;
622 }
623
624 /* EOF -- zxid.c */
625