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: >>