1<<if: ZXIDBOOK>>
2<<else: >>ZXID Simple API
3###############
4<<author: Sampo Kellom�ki (sampo@iki.fi)>>
5<<cvsid: $Id: zxid-simple.pd,v 1.12 2010-01-08 02:10:09 sampo Exp $>>
6<<class: article!a4paper!!ZXID-SIMP 01>>
7<<define: ZXDOC=ZXID Simple API>>
8
9<<abstract:
10
11ZXID.org Identity Management toolkit implements standalone SAML 2.0 and
12Liberty ID-WSF 2.0 stacks and aims at implementing all popular
13federation and ID Web Services protocols. Other more general
14documents are available, here we document the "simple" API
15which is good for most Single Sign-On use cases. Other APIs
16described elsewhere may be more appropriate for other use cases.
17The ZXID Simple API is the most stable API available for the SSO
18functionality.
19
20>>
21
22<<maketoc: 1>>
23
241 Introduction
25==============
26
27The ZXID library provides two main APIs: the Simple and the Raw. The
28ZXID Simple API is meant to get you going with minimal understanding about
29SAML or SSO. It tries to encapsulate as much of the control flow as
30possible. You only need to learn this API, not the underlying protocol.
31
32If you do not want to program or learn any API at all, you should look
33at the Apache module <<link:../mod_auth_saml/mod_auth_saml.html: mod_auth_saml>>
34which will, in 80% of the cases, give all the benefits with the minimal
35effort of just configuring your web server.
36
371.1 Other documents
38-------------------
39
40<<doc-inc.pd>>
41<<htmlpreamble: <title>ZXID Simple API</title><link type="text/css" rel=stylesheet href="zx.css"><body><h1>ZXID Simple API</h1> >>
42
432 ZXID Simple API Tutorial
44==========================
45
46<<fi: >>
47
482.1 Hello World SSO
49-------------------
50
51Consider the following "Hello World" SSO CGI example in C<<footnote: zxidhlo.c
52in the source distribution is an actually usable example program. You should
53also look at its cousins zxidhlo.php and zxidhlo.pl>>
54(the zxid_simple() API is available in all language bindings):
55
56  01 #include <zx/zxid.h>
57  02 #define CONF "PATH=/var/zxid/&URL=https://sp1.zxidsp.org:8443/zxid"
58  03 void main() {
59  04   char* res = zxid_simple(CONF, 0, 255);
60  05   switch (res[0]) {
61  06   case 'd': /* Logged in case */
62  07     my_parse_ldif(res);
63  08     my_render_content();
64  09     exit(0);
65  10   default:
66  11     ERR("Unknown zxid_simple() response(%s)", res);
67  12   }
68  13 }
69
70What happens here:
71
721. The CGI script calls zxid_simple() to handle SAML protocol
73   according to the configuration
74
752. The last argument with value 255 tells zxid_simple()
76   to automatically handle redirections, login screen and
77   any other protocol interaction needed to make SSO happen.
78
793. If zxid_simple() returns, we have either succeeded in SSO
80   or we have failed (all other cases are handled internally
81   by zxid_simple() which calls exit(2) so it never returns).
82
834. In the success case, zxid_simple() returns an LDIF
84   entry (as a nul terminated C string) describing the SSO and
85   the attributes received. For example
86
87     dn: idpnid=Pa45XAs2332SDS2asFs,affid=https://idp.demo.com/idp.xml
88     objectclass: zxidsession
89     affid: https://idp.demo.com/idp.xml
90     idpnid: Pa45XAs2332SDS2asFs
91     authnctxlevel: password
92     sesid: S12aF3Xi4A
93     cn: Joe Doe
94
952.1.1 Attributes Returned in the SSO
96~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
97
98In the returned LDIF entry some attributes, such as ~cn~, are as they
99came from the IdP (you need to consult your IdP configuration and
100documentation to alter them). Other attributes are always created by
101zxid_simple(), albeit sometimes based on values received from the
102IdP. They have the following meaning:
103
104dn:: LDAP distinguished name (part of LDIF format). Always first.
105
106objectclass:: Part of LDIF format.
107
108eid:: The Entity ID of the SP
109
110issuer:: The Entity ID of the authority that issued SSO assertion.
111
112affid:: Specifies which IdP was used for SSO. More accurately, this describes the
113    affiliation namespace in which the ~idpnid~ and ~tgtnid~ attributes are meaningful.
114
115idpinfo:: Human readable description of which IdP was used.
116
117idpnid:: The federated ID, or pseudonym (IdP assigned NameID) of the user performing action
118
119nidfmt:: The format (category) of value returned in idpnid. P=persistent
120
121localpath:: Path to acting user's local account directory. The application can create its own
122    user specific files here. Please note that the directory may not be automatically
123    created.
124
125ssoa7npath:: Path to the raw data of the Single Sign-On assertion in the local audit trail
126
127tgtnid:: The federated ID, or pseudonym (IdP assigned NameID) of the
128    user targeted by the action. This indicates the resource owner.
129
130tgtfmt:: The format (category) of value returned in tgtnid. P=persistent
131
132tgta7npath:: Path to the raw data of the target identity assertion in the local audit trail
133
134tgtpath:: Path to targetted user's local account directory. The application can create its own
135    user specific files here. Please note that the directory may not be automatically
136    created.
137
138authnctxlevel:: Rough indication of how IdP authenticated user
139
140sesid:: Session ID, as may be stored in cookie or used for
141    file name in the session cache (/var/zxid/ses)
142
143sespath:: Directory corresponding to local ZXID session. This may
144    allow your application to access the raw data behind the ZXID session,
145    or it could allow you to add new data to the session. However, beware
146    that just altering the files in this directory may not be enough
147    to update values cached in memory. If session backend is not filesystem,
148    the contents of this attribute may be URI appropriate for accessing
149    the session, or this attribute may not be populated at all.
150
151sigres:: Signature validation error code, if any. 0=OK. For other
152    codes see ZXSIG_* definitions in the source.
153
154ssores:: Error code for most recent operation. 0=OK
155
156setcookie:: If this field is not empty and not equal to '-' (single dash),
157    then the controlling application should take the necessary actions
158    to set the cookie as specified. Namely, the controlling application
159    should create 'Set-Cookie' HTTP response header whose value is the value
160    of the +setcookie+ field. How this is done is environment dependent.
161
162cookie:: The ZXIDSES (or other, as configured) cookie value. For reference.
163
164tgt_*:: Any attribute starting by "tgt_" refers to the target identity
165    and was retrieved from local attribute authority (typically a user
166    specific directory inside /var/zxid/user, see ~tgtpath~).
167    They are prefixed so that their provenance is clear. SP administrator
168    can add these attributes by editing tgtpath/.bs/.at file, which is in LDIF format.
169
170    It is also possible to define SP site global attributes in /var/zxid/user/.all/.bs/.at
171    file, in LDIF format. Since these are common to all users of SP, there is
172    no prefix.
173
174local_*:: Any attribute starting by "local_" refers to the acting user's identity
175    and was retrieved from local attribute authority (typically a user
176    specific directory inside /var/zxid/user, see ~localpath~).
177    They are prefixed so that their provenance is clear. SP administrator
178    can add these attributes by editing localpath/.bs/.at file, which is in LDIF format.
179
180cn:: Common Name. This attribute just exemplifies how any
181    additional attributes the IdP may have set will appear.
182    Typically the LDAP attribute names are used.
183
184fedusername:: pseudonym@idpdomain, for example: FXyysxhM4F6d3DIwrtoiFdi0i@zxidp.org
185
186    The ~fedusername~ attribute is a helper for the SP web sites that
187    are fixated on the notion of needing a username and/or requiring
188    the username to look like an email. By packaging the psedonym this
189    way it is easy to get them to work with minimal modification.
190
191    N.B. Although it looks like an email address, it is not. Do not try
192    sending mail to it (unless you hack your mailserver to understand it).
193
194urn:oid:1.3.6.1.4.1.5923.1.1.1.6:: pseudonym@idpdomain (aka ~eduPersonPrincipalName~)
195
196    This is essentially the same as ~fedusername~, but it seems in some
197    shibboleth federations this is the right attribute name. At least
198    protectnetwork.org works this way.
199
200<<ignore:
201http://www.protectnetwork.org/support/policies/attribute-release-policy
202>>
203
204The ~dn~ line will always be the first. All other lines may appear
205in any order. String representation of LDIF was chosen
206as it is easy to parse in most programming languages.
207
208<<ignore: Some people have advocated JSON representation and it indeed seems
209reasonable. But there is no compelling argument why it would be better
210than LDIF. It clearly is better for JavaScript programs, but it is
211more complicated for most other scripting languages. Keep the feedback coming.>>
212
2132.1.2 Configuration Options
214~~~~~~~~~~~~~~~~~~~~~~~~~~~
215
216(*** This section also appears in zxid-conf.pd)
217
218The zxid_simple() can be configured in the following ways (later
219ways can override earlier ones).
220
2211. Built in default configuration
2222. Configuration file, usually /var/zxid/zxid.conf, if any
2233. Configuration string passed as first argument.
224   While configuration string can override all
225   other options (i.e. it is processed last), the
226   PATH specification is parsed before the configuration
227   file is looked up.
228
229Turns out that often the default configuration modified
230by the configurations string is all you need - you do not
231need to prepare configuration file.
232
233See section "Configuring and Running" for complete list of
234configuration options, but generally it is
235sufficient to specify only a handful:
236
237PATH:: Where files are kept and configuration file is found.
238URL:: The URL of the SP
239CDC_URL:: The Common Domain URL (optional, if omitted
240    the Common Domain Cookie processing is disabled)
241
2422.1.3 AUTO options (auto flags)
243~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
244
245(*** This section also appears in zxid-conf.pd)
246
247The ~auto_flags~ argument allows you to control which
248operations should be performed automatically and
249which should be passed to the calling application,
250see "Gaining More Control" section, below, for
251full description of this case.
252
253> N.B. ~auto_flags~ are specified in code rather than in configuration
254> file (/var/zxid/zxid.conf) because their correct values are highly
255> dependent on the surrounding program that calls zxid_simple(), i.e.
256> changing them wihtou changing the surroundiing program does not make
257> sense. Their correct seetting is a programmer decision, not a sysadmin
258> decision.
259
260The auto options can be added together.
261
262<<table: zxid_simple() AUTO options
263Dec   Hex    Symbol              Description
264===== ====== =================== ===========================================
265    1   0x01 ZXID_AUTO_EXIT      Call exit(), 0=return "n", even if auto CGI
266    2   0x02 ZXID_AUTO_REDIR     Automatic. handle redirects, assume CGI (calls exit(2))
267    4   0x04 ZXID_AUTO_SOAPC     SOAP response handling, content gen
268    8   0x08 ZXID_AUTO_SOAPH     SOAP response handling, header gen
269   16   0x10 ZXID_AUTO_METAC     Metadata response handling, content gen
270   32   0x20 ZXID_AUTO_METAH     Metadata response handling, header gen
271   64   0x40 ZXID_AUTO_LOGINC    IdP select / Login page handling, content gen
272  128   0x80 ZXID_AUTO_LOGINH    IdP select / Login page handling, header gen
273  256  0x100 ZXID_AUTO_MGMTC     Management page handling, content gen
274  512  0x200 ZXID_AUTO_MGMTH     Management page handling, header gen
275 1024  0x400 ZXID_AUTO_FORMF     In idp list and mgmt screen, generate form fields
276 2048  0x800 ZXID_AUTO_FORMT     In idp list & mgmt screen, wrap in <form> tag.
277 4095  0xfff ZXID_AUTO_ALL       Enable all automatic CGI behaviour.
278 4096 0x1000 ZXID_AUTO_DEBUG     Enable debugging output to stderr.
279 8192 0x2000 ZXID_AUTO_OFMTQ     Output Format Query String
28016384 0x4000 ZXID_AUTO_OFMTJ     Output Format JSON
281>>
282
283If the AUTO_REDIR flag is true, the LOCATION header is sent to stdout
284and exit(0) may be called, depending on the AUTO_NOEXIT flag.
285
286The SOAP, META, LOGIN, and MGMT flags follow convention:
287
288  HC
289  00  No automation. Only action letter is returned ("e"=login, "b"=meta, etc.)
290  01  Content, not wrapped in headers, is returned as a string
291  10  Headers and content is returned as a string
292  11  Headers and content are sent to stdout, CGI style and
293      exit(0) may be called, depending on AUTO_EXIT. Otherwise "n" is returned.
294
295Whether exit(0) is called in 11 case depends on ZXID_AUTO_NOEXIT flag.
296
297How much HTML is generated for Login page and Mgmt page in 01 (content only)
298mode depends on AUTO_PAGE and AUTO_FORM flags
299
300  TF
301  00  reserved / nothing is generated
302  01  Only form fields (but not form tag itself) are generated.
303  10  Complete form is generated
304  11  Whole page is generated (best support)
305
306The output format in the successful SSO case depends on Output
307Format (OFMT) bits as follows
308
309  JQ
310  00  LDIF (default)
311  01  Query String
312  10  JSON
313  11  No output (usually used if attributes are picked from session)
314
3152.1.4 Configuration options for customizing HTML
316~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
317
318(*** This section also appears in zxid-conf.pd)
319
320When whole page is generated, some templating information is taken
321from the configuration.
322
323IDP_SEL_TEMPL_FILE:: Path for Template for IdP Selecton Page. Default "idpsel.html".
324    This file, which you can edit for customization, is used as template to
325    render the IdP selection page on the SP side. If the file does not exist,
326    the value of IDP_SEL_TEMPL configuration option is used as template.
327    By default idpsel.html uses idpsel.css as stylesheet. You can make many
328    kinds of customization just by editing this stylesheet.
329
330IDP_SEL_TEMPL:: Template for IdP Authentication Page that is used if the
331    path does not work. This is really meant to be the last resort. The default
332    value of this page is the compiled in template "ZXID SP SSO: Choose IdP".
333
334IDP_LIST_METH:: Choose the method for rendeing IdP list.
335    0 = popup menu, 1 = buttons,
336    2 = branded image buttons (not implemented as of 20100922)
337
338IDP_SEL_PAGE::  IdP Selector Page URL
339   If the IDP_SEL_TEMPL_FILE or IDP_SEL_TEMPL, above, is not sufficient for
340   your customization needs, you can provide URL to page of your own design.
341   This page will receive as query string argument the relay state.
342   0 (zero) disables.
343
344You can set several rather technical configuration options by editing
345the IdP selection template and adding (hidden) form fields. You may
346want to hardwire these or allow user to set them
347
348fc:: Create federation (AllowCreate flag)
349fn:: Name ID format
350    prstnt:: Persistent (pseudonym)
351    trnsnt:: Transient, temporary pseudonym
352
353Technical parameters that the site administrator
354should decide and set. Usually hidden form fields in the template:
355
356fq:: Affiliation ID (usually empty)
357fy:: Consent obtained by SP for the federation or SSO
358    empty:: No statement about consent
359    urn:liberty:consent:obtained:: Has been obtained (unspecified way)
360    urn:liberty:consent:obtained:prior:: Obtained prior to present
361        transaction, e.g. user signed terms and conditions of service
362    urn:liberty:consent:obtained:current:implicit:: Consent
363        is implicit in the situation where user came to invoke service
364    urn:liberty:consent:obtained:current:explicit:: Obtained explicitly
365    urn:liberty:consent:unavailable:: Consent can not be obtained
366    urn:liberty:consent:inapplicable:: Obtaining consent is not
367        relevant for the SP or service.
368fa:: Authentication Context (strength of authentication) needed by the SP
369fm:: Matching rule for authentication strength (usually empty, IdP decides)
370fp:: Forbid IdP from interacting with the user (IsPassive flag)
371ff:: Request reauthentication of user (ForceAuthn flag)
372
3732.2 Gaining More Control
374------------------------
375
376The fully automated interface works well for CGI deployment
377but probably is not appropriate in more complex situations.
378You can use zxid_simple() without automation and prevent
379it from accessing the system layer too directly. Consider
380
381  01 #define CONF "PATH=/var/zxid/&URL=https://sp1.zxidsp.org:8443/zxid"
382  02 int main() {
383  03   char* res;
384  04   res = zxid_simple(CONF, getenv("QUERY_STRING"), 0);
385  05   switch (res[0]) {
386  06   case 'L': printf("%s", res); exit(0);  /* Redirect */
387  07   case 'C': printf("%s", res); exit(0);  /* Content-type + content */
388  08   case '<': printf("Content-Type: text/html\r\n\r\n%s", res); exit(0);
389  09   case 'n': exit(0);
390  10   case 'b': my_send_metadata();
391  11   case 'e': my_render_login_screen();
392  12   case 'd': /* Logged in case */
393  13     my_parse_ldif(res);
394  14     my_render_content();
395  15     exit(1);
396  16   default:
397  17     ERR("Unknown zxid_simple() response(%s)", res);
398  18   }
399  19 }
400
401Here we specify zero as ~auto_flags~, thus all automation is
402disabled. This means that the res can take more varied
403shape and the calling application has to be prepared
404to handle them. The different cases are distinguished by
405the first character of the res string:
406
407L:: Redirection request (L as in Location header). The
408    full contents of the res is the redirection request,
409    ready to be printed to stdout of a CGI. If you want
410    to handle the redirection some other way, you can
411    parse the string to extract the URL and do your thing.
412    This res is only returned if you did not
413    set ZXID_AUTO_REDIR.
414
415    Example:
416
417      Location: https://sp1.zxidsp.org:8443/zxid?o=C
418
419C:: Content with Content-type header. The res is ready
420    to be printed to the stdout of a CGI, but if you
421    want to handle it some other way, you can parse
422    the res to extract the header and the actual body.
423
424    Example:
425
426      CONTENT-TYPE: text/html
427
428      <title>Login page</title>
429      ...
430
431    Example (metadata):
432
433      CONTENT-TYPE: text/xml
434
435      <m:EntityDescriptor>
436      ...
437
438Less than ("<"):: Content without headers. This could
439    be HTML content for login page or metadata XML.
440    To know which (and set content type correctly),
441    you would have to parse the content. This res
442    format is only applicable if you did not specify
443    ZXID_AUTO_CTYPE (but did specify ZXID_AUTO_CONTENT).
444
445n:: Do nothing. The operation was somehow handled internally
446    but the exit(2) was not called (e.g. ZXID_AUTO_SOAP
447    was NOT specified). The application should NOT attempt
448    generating any output.
449
450b:: Indication that the application should send SP
451    metadata to the client. This res is only returned
452    if you did not set ZXID_AUTO_META.
453
454c:: Indication that the application should send SP
455    CARML declaration to the client. This res is only returned
456    if you did not set ZXID_AUTO_META.
457
458e:: Indication that the application should display the
459    IdP selection page. Application may use zxid_idp_list()
460    to render the IdP selection area. This res is only returned
461    if you did not set ZXID_AUTO_CONTENT.
462
463a:: Indication that the application should display the
464    authentication page (usually this happens on IdP).
465
466d:: Indication that SSO has been completed or that there
467    was an existing valid session in place. The res is an
468    LDIF entry containing attributes that describe the
469    SSO or session. See "Hello World" section for
470    description of the LDIF data.
471
472    Usually your application would parse the attributes
473    and then render its application specific content.
474    If you want to render the SSO management form (with
475    logout and defederate buttons), you can call
476    zxid_fed_mgmt().
477
478Open curly ("{"):: SSO completed, if JSON output was
479    chosen. Processing should be same as for "d".
480
481z:: Authorization failure. Application MUST NOT display
482    protected content. Instead, it should offer user
483    interface where the user can understand what happened
484    and possibly gain the extra credentials needed.
485
486Asterisk ("*"):: Although any unknown letter should be
487    interpreted as an error, we follow convention
488    of prefixing errors with an asterisk ("*").
489
4902.3 Some Generalization and Optimizations
491-----------------------------------------
492
493(*** also in zxid-php.pd)
494
495The simplest APIs are easy to use and suitable for CGIs where the
496program is restarted anew every time. However in situations where the
497script engine stays alive persistently, it is wasteful to reparse (and
498reallocate) the configuration every time. Consider following PHP
499snippet designed to be used with mod_php:
500
501  01 # Put this in the PHP initialization (it only needs to run once)
502  02 dl("php_zxid.so");
503  03 $conf = "PATH=/var/zxid/&URL=https://sp1.zxidsp.org:8443/zxiddemo.php";
504  04 $cf = zxid_new_conf_to_cf($conf);
505  05 <?   # For every page that is accessed
506  06 $qs = $_SERVER['REQUEST_METHOD'] == 'GET'
507  07       ? $_SERVER['QUERY_STRING']
508  08       : file_get_contents('php://input');
509  09 $res = zxid_simple_cf($cf, -1, $qs, null, 0x1800);
510  10 switch (substr($res, 0, 1)) {
511  11 case 'L': header($res); exit;  # Redirect
512  12 case 'n': exit;   # already handled
513  13 case 'b': my_send_metadata();
514  14 case 'e': my_render_login_screen();
515  15 case 'd': break;  # Logged in case -- fall through
516  16 default:  error_log("Unknown zxid_simple() res(%s)", res); exit;
517  17 }
518  18 # *** Parse the LDIF in $res into a hash of attributes (see zxidhlo.php)
519  19
520  20 ?>
521  21 <html><title>Protected content, logged in as <$=$attr['cn']$></title>
522  22 ...
523  23 </html>
524  24 <?
525  25 function my_render_login_screen()
526  26 {
527  27 ?>
528  28 <html><title>Please Login Using IdP</title>
529  29 ...
530  30 <?=zxid_idp_select_cf($cf, null, 0x1800)?>
531  31 ...</html>
532  32 <? exit; }?>
533
534Notes
535
5361. Line 4 creates a system-wide configuration object that is later
537   used by the other API calls
5382. On line 9 we call zxid_simple_cf() with the created object. The
539   second and third argument specify a buffer or string that contains
540   the CGI form data to parse. This may come from ~QUERY_STRING~ of a
541   GET request or from HTTP body of a POST request, as determined
542   on line 8. The -1 means the length of the data should be
543   determined using strlen(3), i.e. C string nul termination.
544   The ~auto_flags == 0x1800~ enables form tag wrapping and debug
545   prints, but otherwise automation is disabled.
5463. Since automation was disabled, we need to handle several
547   cases of possible outcomes from zxid_simple_cf(), on lines 10-17.
5484. From line 18 onwards we handle the login successful or already
549   logged in case. First we split the LDIF entry into a hash
550   so that we can access the attributes easily (e.g. ~cn~ on line 20).
5515. On line 30 we call zxid_idp_list_cf() to create the form
552   for choosing which IdP to use for login (remember that
553   ~auto_flags == 0xc0~ enabled the form wrapper). As can be
554   seen the same configuration object, ~$cf~, is used through out.
555
5562.4 Java Servlet Example Using Tomcat
557-------------------------------------
558
559(*** also in zxid-java.pd)
560
561Consider
562
563  01 import zxidjava.*;
564  02 import java.io.*;
565  03 import javax.servlet.*;
566  04 import javax.servlet.http.*;
567  05 public class zxidhlo extends HttpServlet {
568  06   static { System.loadLibrary("zxidjni"); }
569  07   static final String conf
570  08     = "PATH=/var/zxid/&URL=http://sp1.zxidsp.org:8080/zxidservlet/zxidHLO";
571  09   public void do_zxid(HttpServletRequest req, HttpServletResponse res, String qs)
572  10                       throws ServletException, IOException {
573  11     String ret = zxidjni.simple(conf, qs, 0xd54);
574  12     switch (ret.charAt(0)) {
575  13     case 'L':  /* Redirect: ret == "LOCATION: urlCRLF2" */
576  14       res.sendRedirect(ret.substring(10, ret.length() - 4));
577  15       return;
578  16     case '<':
579  17       switch (ret.charAt(1)) {
580  18       case 's':  /* <se:  SOAP envelope */
581  19       case 'm':  /* <m20: metadata */
582  20         res.setContentType("text/xml");
583  21         break;
584  22       default:
585  23         res.setContentType("text/html");
586  24       break;
587  25       }
588  26       res.setContentLength(ret.length());
589  27       res.getOutputStream().print(ret);
590  28       break;
591  29     case 'd': /* Logged in case */
592  30       //my_parse_ldif(ret);
593  31       res.setContentType("text/html");
594  32       res.getOutputStream().print(zxidjni.fed_mgmt(conf, sesid, 0xd54));
595  33       break;
596  34     default:
597  35       System.err.print("Unknown zxid_simple() response:");
598  36       System.err.print(ret);
599  37     }
600  38   }
601  39   public void doGet(HttpServletRequest req, HttpServletResponse res)
602  40                     throws ServletException, IOException {
603  41     // LECP/ECP PAOS header checks
604  42     do_zxid(req, res, req.getQueryString());
605  43   }
606  44   public void doPost(HttpServletRequest req, HttpServletResponse res)
607  45                      throws ServletException, IOException {
608  46     String qs;
609  47     int len = req.getContentLength();
610  48     byte[] b = new byte[len];
611  49     int got = req.getInputStream().read(b, 0, len);
612  50     qs = new String(b, 0, got);
613  51     do_zxid(req, res, qs);
614  52   }
615  53 }
616
6172.5 Samma p� Perl
618-----------------
619
620See also zxid-perl.pd
621
622<<logoutput:
62301 use Net::SAML;
62402 $| = 1; undef $/;  # Flush pipes, read all in at once
62503 $url = "http://sp.tas3.pt:8082/zxidhlo.pl";  # Edit to match your conf
62604 $conf = "PATH=/var/zxid/&URL=$url";
62705 $cf = Net::SAML::new_conf_to_cf($conf);
62806 $qs = $ENV{'QUERY_STRING'};
62907 $qs = <STDIN> if $qs =~ /o=P/;
63008 $res = Net::SAML::simple_cf($cf, -1, $qs, undef, 0x1828);
63109 $op = substr($res, 0, 1);
63210 if ($op eq 'L' || $op eq 'C') { print $res; exit; } # LOCATION (Redir) or CONTENT
63311 if ($op eq 'n') { exit; } # already handled
63412 if ($op eq 'e') { my_render_idpsel_screen(); exit; }
63513 if ($op ne 'd') { die "Unknown Net::SAML::simple() res($res)"; }
63614
63715 ($sid) = $res =~ /^sesid: (.*)$/m;  # Extract a useful attribute from SSO output
63816
63917 print <<HTML
64018 CONTENT-TYPE: text/html
64119
64220 <title>ZXID perl HLO SP Mgmt & Protected Content</title>
64321 <link rel="shortcut icon" href="/favicon.ico" type="image/x-icon">
64422 <link type="text/css" rel=stylesheet href="idpsel.css">
64523 <body bgcolor=white><font face=sans>
64624
64725 <h1>ZXID SP Perl HLO Management & Protected Content (user logged in, session active)</h1>
64826 sesid: $sid
64927 HTML
65028     ;
65129 print Net::SAML::fed_mgmt_cf($cf, undef, -1, $sid, 0x1900);
65230 exit;
65331
65432 sub my_render_idpsel_screen {  # Replaces traditional login screen
65533     print <<HTML;
65634 CONTENT-TYPE: text/html
65735
65836 <title>ZXID SP PERL HLO SSO IdP Selection</title>
65939 <body bgcolor=white><font face=sans>
66040 <h1>ZXID SP Perl HLO Federated SSO IdP Selection (user NOT logged in, no session.)</h1>
66141 <form method=get action="zxidhlo.pl">
66242
66343 <h3>Login Using New IdP</h3>
66444
66545 <i>A new IdP is one whose metadata we do not have yet. We need to know
66646 the Entity ID in order to fetch the metadata using the well known
66747 location method. You will need to ask the adminstrator of the IdP to
66848 tell you what the EntityID is.</i>
66949
67050 <p>IdP URL <input name=e size=60><input type=submit name=l2 value=" Login ">
67151 HTML
67252 ;
67353     print Net::SAML::idp_list_cf($cf, undef, 0x1c00);   # Get the IdP selection form
67454     print <<HTML;
67555 <h3>CoT configuration parameters your IdP may need to know</h3>
67656
67757 Entity ID of this SP: <a href="$url?o=B">$url?o=B</a> (Click on the link to fetch SP metadata.)
67858
67959 <input type=hidden name=fc value=1><input type=hidden name=fn value=prstnt>
68060 <input type=hidden name=fq value=""><input type=hidden name=fy value="">
68161 <input type=hidden name=fa value=""><input type=hidden name=fm value="">
68262 <input type=hidden name=fp value=0><input type=hidden name=ff value=0>
68363
68464 </form><hr><a href="http://zxid.org/">zxid.org</a>
68565 HTML
68666     ;
68767 }
688>>
689
690This example only demonstrates SSO.
691
692Lines 1-5 set up the configuration. See zxid-conf.pd for guidance.
693
694ll.6-7 reads in the CGI input the perl way.
695
696l.8 runs the SAML engine of ZXID. The engine will return result that
697is processed below. The magic constant 0x1828 sets some flags, see
698zxid-simple.pd for explanation. This explanation may be especially relevant
699if you plan to run as mod_perl process rather than as a CGI. With
700these flags you could eliminate the need to render the IdP selection
701screen.
702
703ll.9-13: interpret the return value. l.10 deals with parts of SAML
704protocol that need redirect or content. l.12 deals with rendering the
705IdP selection screen. This screen replaces the traditional login
706screen in most applications.
707
708l.15 demonstrates how to extract attributes from the return value. The ret
709is formatted as LDIF so it is very easy to parse with perl.
710
711ll.17-30 render the "protected content". Most protected content should
712contain also Single Logout button. This is accomplished on l.29.
713Protected content is where your normal application after SSO lives.
714You can rely in ZXID session mechanism and just show the content,
715or you could bootstrap your application's session mechanism here.
716
717ll.32-67 render the "idp selection" screen. This could have been
718automatically generated has the flags to Net::SAML::simple_cf()
719been different (see zxid-simple.pd for explanation).
720
721As can be seen, the most central logic for SSO is only about 10 lines. The
722rest is user interface.
723
7242.6 Shell Script API
725--------------------
726
727Any Bourne shell (Unix shell) shell script can be converted
728to a SAML SSO enabled CGI script using zxidsimple(1) helper
729utility executable. The program simply wraps the zxid_simple()
730API function so that the inputs can be provided as command line arguments,
731or in case of ~qs~ as stdin, and the output is returned on stdout.
732
733Synopsis
734
735   zxidsimple -o ldif CONF AUTO_FLAGS <cgi-input
736
737Typical usage (see also zxidhlo.sh):
738
739  01 CONF="PATH=/var/zxid/&URL=https://sp1.zxidsp.org:8443/zxidhlo.sh"
740  02 ./zxidsimple -o /tmp/zxidhlo.sh.$$ $CONF 4094 || exit;
741  03 IFS="
742  04 "
743  05 res=`cat /tmp/zxidhlo.sh.$$`
744  06 case "$res" in
745  07 dn*)                     # SSO successful case
746  08   for x in $res; do
747  09     case "$x" in
748  10     sesid:*)  SID=${x##*sesid: } ;;
749  11     idpnid:*) NID=${x##*idpnid: } ;;
750  12     cn:*)     CN=${x##*cn: } ;;
751  13     esac
752  14   done
753  15   ;;
754  16   *) echo "ERROR($res)" >>/tmp/hlo.err; exit ;;
755  17 esac
756  18
757  19 cat << EOF
758  20 Content-Type: text/html
759  21
760  22 <title>ZXID HELLO SP Mgmt (Logged In)</title>
761  23 <h1>ZXID HELLO SP Management (user $CN logged in, session active)</h1>
762  24 <form method=post action="zxidhlo.sh?o=P">
763  25 <input type=hidden name=s value="$SID">
764  26 <input type=submit name=gl value=" Local Logout ">
765  27 <input type=submit name=gr value=" Single Logout (Redir) ">
766  28 </form>
767  29 EOF
768
769The zxidsimple(1) utility will return exit value 1 if it
770handled a SAML protocol operation (by outputting to stdout
771whatever was appropriate). The shell script
772should not do any further processing and just exit.
773
774If the exit value is 0 (success) then SSO has been done. Since the
775attributes from the SAML assertion are usually interesting, you can
776capture them to a temporary file using the -o option.
777
778First we split the result of the backtick into a list on (literal)
779newline. Then we process the list with for loop and look with case
780for the interesting attributes and capture them into local variables.
781
782Finally the protected content page is output.
783
7843 ZXID Simple Form Fields
785=========================
786
787The ZXID cgi interface assumes certain hardwired form field
788names. These are not configurable (and there is no intent to make them
789configurable). The cgi fields may appear either in query string (GET
790method) or as POST content (though depending on your programming
791environment and language, you may need to read the POST data in
792yourself prior to calling zxid_simple()).
793
7943.1 Common Fields
795-----------------
796
797These fields appear often in requests and have universal meaning.
798
799o:: Operation. In particular o=P means that form uses POST method.
800s:: Session ID
801RelayState:: SAML 2.0 mandated field name for relay state
802SAMLart:: SAML 2.0 mandated field name for SAML artifact
803SAMLResponse:: SAML 2.0 mandated field name for SAML response,
804    especially in POST profile
805SAMLRequest:: SAML 2.0 mandated field name for SAML request
806SigAlg:: SAML 2.0 mandated field name for signature algorithm in
807    redirect binding
808Signature:: SAML 2.0 mandated field name for signature in redirect binding
809
8103.2 IdP Selection (Login) Screen
811--------------------------------
812
813These are typically embdedded (hidden) or visible fields of the IdP Selection
814screen.
815
816u:: User (local login)
817p:: Password (local login)
818c:: Common Domain Cookie
819e:: Entity ID (manual entry field)
820d:: Entity ID (from popup or radio box)
821i:: Protocol index
822l1:: Login using artifact profile (same as i=1)
823l2:: Login using POST profile (same as i=2)
824l1EID:: Login using specified IdP (artifact profile), same as e=EID&i=1
825l2EID:: Login using specified IdP (POST profile), same as e=EID&i=2
826fc:: Allow Create flag
827fp:: IsPassive flag
828ff:: Force Authentication flag
829fn:: NameID format
830fq:: Affiliation ID
831fy:: Consent field
832fm:: Matching rule
833fa:: Authentication Context Class
834fr:: Relay State (usually used to convey the page that originally initiated the SSO)
835
836Please understand that a significant part of any SSO configuration
837is realized via f* fields, which will typically be hidden
838fields in the IdP selection form. Some of these configuration
839options can not be set or overridden from the configuration file.
840You must provide them as (hidden) fields of the HTML form.
841
842The ~DEFAULTQS~ option often will emulate the IdP Selection
843form submission and set some f* options.
844
845The IdP selection form (aka Login) screen can be implemented, using
846the above documented form interface, in many ways as following
847examples illustrate.
848
849*Example IdP Selection Form: Popup menu method*
850
851***
852
853*Example IdP Selection Form: Separate IdP buttons method*
854
855  <form method=post
856    action="http://sp1.zxidsp.org:8080/zxidservlet/zxidHLO?o=P">
857  <h3>Login Using New IdP</h3>
858  <p>IdP URL <input name=e size=80>
859      <input type=submit name=l1 value=" Login (A2) ">
860      <input type=submit name=l2 value=" Login (P2) "><br>
861
862  <h3>Login Using Known IdP</h3>
863  <input type=submit name="l1https://a-idp.liberty-iop.org:8881/idp.xml"
864         value=" Login to https://a-idp.liberty-iop.org:8881/idp.xml (A2) ">
865  <input type=submit name="l2https://a-idp.liberty-iop.org:8881/idp.xml"
866         value=" Login to https://a-idp.liberty-iop.org:8881/idp.xml (P2) ">
867
868  <h3>Technical options</h3>
869  <input type=checkbox name=fc value=1 checked> Create federation,
870     NID Format: <select name=fn>
871                   <option value=prstnt>Persistent
872                   <option value=trnsnt>Transient
873                   <option value="">(none)
874                 </select><br>
875
876  <input type=hidden name=fq value="">
877  <input type=hidden name=fy value="">
878  <input type=hidden name=fa value="">
879  <input type=hidden name=fm value="">
880  <input type=hidden name=fp value=0>
881  <input type=hidden name=ff value=0>
882  </form>
883
884*Example IdP Selection Form: IdP links method*
885
886***
887
8883.3 Single Logout and Federation Management
889-------------------------------------------
890
891Following fields typically appear in form implementing
892logout button. You will usually need to embed them to
893your application's screens where logout button or link
894appears. Typically you would include one of them
895and teh <<tt: s>> argument in the query string.
896
897gl:: Local Logout
898gr:: Single Logout using redirection
899gs:: Single Logout using SOAP
900gt:: NameID Managment (redirect)
901gu:: NameID Management (SOAP)
902
903*Example Management Form*
904
905  <form method=post action="zxid?o=P">
906  <input type=hidden name=s  value="!!sid">
907  <input type=submit name=gl value=" Local Logout ">
908  <input type=submit name=gr value=" Single Logout (Redir) ">
909  <input type=submit name=gs value=" Single Logout (SOAP) ">
910  <input type=submit name=gt value=" Defederate (Redir) ">
911  <input type=submit name=gu value=" Defederate (SOAP) ">
912  </form>
913
9143.4 Login Button Abreviations
915-----------------------------
916
917Sometimes you will see in the IdP Selection screen a small
918abbreviation like "(A2)". This indicates the protocol binding that
919will be used (if supported in metadata). The button without such
920legend will automatically pick binding that is best among
921available. If both POST and artifact are available, it will pick
922artifact.
923
924  A2 = SAML 2.0 Artifact Profile
925  P2 = SAML 2.0 POST Profile
926  '' = SAML 2.0 POST Simple Sign
927  A12 = Liberty ID-FF 1.2 Artifact Profile
928  P12 = Liberty ID-FF 1.2 POST Profile
929  A1 = Bare SAML 1.x Artifact Profile
930  P1 = Base SAML 1.x POST Profile
931  A0 = WS-Federation Artifact Profile
932  P0 = WS-Federation POST Profile
933
9343.5 ZXID IdP Login Screen Form Fields
935-------------------------------------
936
937> N.B. The IdP functionality is not fully developed as of Nov 2008.
938
939  <form method=post action="zxididp?o=P">
940  <input type=hidden name=s  value="!!sid">
941  <input name=au>
942  <input type=password name=ap>
943  <input type=submit name=alp value=" Login ">
944  <input type=submit name=gl value=" Local Logout ">
945  <input type=submit name=gr value=" Single Logout (Redir) ">
946  <input type=submit name=gs value=" Single Logout (SOAP) ">
947  <input type=submit name=gt value=" Defederate (Redir) ">
948  <input type=submit name=gu value=" Defederate (SOAP) ">
949  </form>
950
951
952<<ignore:
95318 ZXID SP
954==========
955
956*** warning: not checked lately, may be wrong!
957
958< <table: ZXID SP URLs
959URL          Description
960============ =======================================================
961/zxid        Same as o=M. Main convenience entry point
962/zxid?o=M    SSO with CDC; or management if already logged in
963/zxid?o=C    Common Domain Cookie (CDC) reader, usually under common domain host name.
964/zxid?o=E    SSO after CDC read; or management if already logged in.
965/zxid?o=P    HTTP POST end point. Used for forms and last part of POST profile SSO.
966/zxid?o=Q    HTTP binding (POST or redirect) request end point (e.g. SLO, MNI).
967/zxid?o=S    SOAP end point (HTTP POST)
968/zxid?o=B    Get SP metadata (or combined SP and IdP metadata if proxying).
969> >
970>>
971
9724 ZXID Simple API Reference
973===========================
974
975See also <<link:ref/html/index.html:Function reference>>
976
9774.1 Creating Configuration Object
978---------------------------------
979
980<<logoutput:
981int zxid_conf_to_cf_len(struct zxid_conf* cf, int conf_len, char* conf);
982struct zxid_conf* zxid_new_conf_to_cf(char* conf);
983>>
984
9854.2 zxid_simple() main protocol dispatch
986----------------------------------------
987
988<<logoutput:
989/* Simple handler that assumes the configuration has already been read in.
990 * The memory for result is grabbed from ZX_ALLOC(), usually malloc(3)
991 * and is "given" away to the caller, i.e. caller must free it. The
992 * return value is LDIF of attributes in success case.
993 * res_len, if non-null, will receive the length of the response. */
994
995/* Process simple configuration and then call simple handler. Strings
996 * are length + pointer (no C string nul termination needed). */
997
998char* zxid_simple_cf(struct zxid_conf* cf, int qs_len, char* qs, int* res_len, int auto_flags);
999char* zxid_simple_len(int conf_len, char* conf, int qs_len, char* qs, int* res_len, int auto_flags);
1000char* zxid_simple(char* conf, char* qs, int auto_flags);
1001>>
1002
10034.3 Generating Login Screen
1004---------------------------
1005
1006<<logoutput:
1007/* ------------ zxid_idp_list() ------------ */
1008
1009char* zxid_idp_list_cf_cgi(struct zxid_conf* cf, struct zxid_cgi* cgi, int* res_len, int auto_flags)
1010char* zxid_idp_list_cf(struct zxid_conf* cf, int* res_len, int auto_flags)
1011char* zxid_idp_list_len(int conf_len, char* conf, int* res_len, int auto_flags)
1012char* zxid_idp_list(char* conf, int auto_flags)
1013
1014struct zx_str* zxid_idp_select_zxstr_cf_cgi(struct zxid_conf* cf, struct zxid_cgi* cgi, int auto_flags)
1015
1016struct zx_str* zxid_idp_select_zxstr_cf(struct zxid_conf* cf, int auto_flags)
1017char* zxid_idp_select_cf(struct zxid_conf* cf, int* res_len, int auto_flags)
1018char* zxid_idp_select_len(int conf_len, char* conf, int* res_len, int auto_flags)
1019char* zxid_idp_select(char* conf, int auto_flags)
1020
1021struct zx_str* zxid_ses_to_ldif(struct zxid_conf* cf, struct zxid_ses* ses)
1022
1023char* zxid_simple_render_ses(struct zxid_conf* cf, struct zxid_ses* ses, int* res_len, int auto_flags)
1024
1025static char* zxid_simple_show_meta(struct zxid_conf* cf, struct zxid_cgi* cgi, int* res_len, int auto_flags)
1026
1027/* NULL return means the not logged in processing is needed, see zxid_simple_no_ses_cf() */
1028
1029char* zxid_simple_ses_active_cf(struct zxid_conf* cf, struct zxid_cgi* cgi, struct zxid_ses* ses, int* res_len, int auto_flags)
1030
1031char* zxid_simple_no_ses_cf(struct zxid_conf* cf, struct zxid_cgi* cgi, struct zxid_ses* ses, int* res_len, int auto_flags)
1032>>
1033
10344.4 Generating HTML for Logout button or Management Screens
1035-----------------------------------------------------------
1036
1037<<logoutput:
1038char* zxid_fed_mgmt_cf(struct zxid_conf* cf, int* res_len, int sid_len, char* sid, int auto_flags)
1039char* zxid_fed_mgmt_len(int conf_len, char* conf, int* res_len, char* sid, int auto_flags)
1040char* zxid_fed_mgmt(char* conf, char* sid, int auto_flags)
1041>>
1042
10434.5 Explicitly Calling PEP (which makes SOAP/XACML call to PDP)
1044---------------------------------------------------------------
1045
1046Although a simple PEP functionality is built-in to zxid_simple() API
1047through configuration options like ~PEPMAP~, LOCALPDP_* family, and
1048~PDP_URL~, it is sometimes desirable to implement a Policy Enforcement
1049Point (PEP) at application layer where full particluars of the request or
1050response are available. To assist in this, the simple API provides
1051authorization client, which we term PEP because at protocol layer it
1052is a XACML PEP, which your application code can call to implement the
1053protocols specifics of calling a PDP. However, your own code still needs to
1054implement the actual enforcement or filtering logic.
1055
10564.5.1 zxid_az(conf, qs, sesid)
1057~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1058
1059conf:: the configuration will need to have ~PEPMAP~ and ~PDP_URL~ options
1060    set according to your situation.
1061
1062qs:: if supplied, any CGI variables are imported to session
1063    environment as attributes (according to ~INMAP~). Format is
1064    CGI Query String.
1065
1066sesid:: attributes are obtained from the session, if supplied (see also
1067    CGI). The session ID is supplied as a string. If none is
1068    supplied, then session will be entirely defined by the CGI
1069    attributes.
1070
1071returns:: 0 if deny (for any reason, e.g. indeterminate), or 1 if permit
1072
1073This function calls underlying zxid_pep_az_soap() with the difference
1074that it is possible to import attributes to the session via CGI string.
1075
1076The XACML request is constructed by applying ~PEPMAP~ configuration
1077to the attributes in the session. For this to work, the ~PEPMAP~ MUST
1078have ~subj~, ~rsrc~, and ~act~ stanzas and should have ~env~ stanza
1079if you have environment attributes to pass. See zxid-conf.pd for
1080further information and default values.
1081
1082*Variants*
1083
1084  zxid_az_cf(cf, qs, sesid)
1085
1086The configuration is received as binary object, usually obtained from
1087zxid_conf_to_cf_len(). This avoids reparsing configuration in case
1088multiple calls are made. Typically the same configuration object
1089might have been used with zxid_simple_cf().
1090
1091  zxid_az_cf_ses(cf, qs, ses)
1092
1093Both configuration and session are supplied as binary objects,
1094such as may have been received from zxid_conf_to_cf_len()
1095and zxid_alloc_ses() as used with zxid_simple_cf_ses().
1096
1097*Example Pseudocode*
1098
1099  cf = zxid_new_conf();
1100  ses = zxid_alloc_ses(cf);
1101  ret = zxid_simple_cf_ses(cf, 0, $QUERY_STRING, ses, 0, 0x1800);
1102  if (ret =~ /^d/) {
1103    perr "SSO ok, now checking authorization";
1104    if (zxid_az(cf, "", ses))
1105      perr "Permit, add code to deliver application content";
1106    else
1107      perr "Deny, send back an error";
1108  }
1109
11104.5.2 zxid_pep_az_soap() - Underlying PEP Function
1111~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1112
1113The simple PEP is based on this function:
1114
1115  int zxid_pep_az_soap(struct zxid_conf* cf, struct zxid_cgi* cgi, struct zxid_ses* ses)
1116
1117In particular
1118
1119cf:: the configuration will need to have ~PEPMAP~ and ~PDP_URL~ options
1120    set according to your situation.
1121
1122cgi:: if non-null, will resceive error and status codes
1123
1124ses:: all attributes are obtained from the session. You may wish
1125    to add additional attributes that are not known by SSO.
1126
1127returns:: 0 if deny (for any reason, e.g. indeterminate), or 1 if permit
1128
1129The XACML request is constructed by applying ~PEPMAP~ configuration
1130to the attributes in the session.
1131
11325 Miscellaneous Function Documentation
1133======================================
1134
1135<<img: meta-fetch: Relevant parts of the call graph for metadata fetching.>>
1136
1137<<ignore:
1138
1139Some OAuth APIs to look at
1140
1141http://wiki.oauth.net/w/page/OAuth-2
1142http://developer.cliqset.com/api#TOC-OAuth-2.0-Overview
1143http://www.dailymotion.com/doc/api
1144
1145>>
1146
1147<<if: ZXIDBOOK>>
1148<<else: >>
1149<<doc-end.pd>>
1150<<notapath: TCP/IP a.k.a xBSD/Unix n/a Perl/mod_perl PHP/mod_php Java/Tomcat>>
1151<<EOF: >>
1152<<fi: >>