ZXID.org Identity Management toolkit implements standalone SAML 2.0 and Liberty ID-WSF 2.0 stacks. This document describes the Perl glue.
Perl access to ZXID is using Net::SAML module.
The perl glue for ZXID was generated using swig(1), however, the swig interface is not a retrofit: the whole ZXID API was designed to be easily swiggifiable.
The main aim of the glue is supporting the easy and simple API, see zxid_simple() for general reference. Only differences and language specifics are covered in this document.
mod_auth_saml Apache module documentation: SSO without programming.
zxid_simple() Easy API for SAML
ZXID Raw API: Program like the pros (and fix your own problems). See also Function Reference
ZXID ID-WSF API: Make Identity Web Services Calls using ID-WSF
ZXID Compilation and Installation: Compile and install from source or package. See also INSTALL.zxid for quick overview.
ZXID Configuration Reference: Nitty gritty on all options.
ZXID Circle of Trust Reference: How to set up the Circle of Trust, i.e. the partners your web site works with.
ZXID Logging Reference: ZXID digitally signed logging facility
javazxid: Using ZXID from Java
Net::SAML: Using ZXID from Perl
php_zxid: Using ZXID from PHP
zxididp: Using ZXID IdP and Discovery
README.smime: Crypto and Cert Tutorial
FAQ: Frequently Asked Questions
README.zxid: ZXID project overview
perl CGI example: zxid.pl
using with mod_perl
After building the main zxid tree, you can
cd Net perl Makefile.PL make make test # Tests are extremely sparse at the moment make install
This assumes you use the pregenerated Net/SAML_wrap.c and Net/SAML.pm files that we distribute. If you wish to generate these files from origin, you need to have SWIG installed and then say in main zxid directory
make perlmod ENA_GEN=1 # Makes all available perl modules (including heavy low level ones) make samlmod ENA_GEN=1 # Only makes Net::SAML (much faster) make wsfmod ENA_GEN=1 # Only makes Net::WSF (much faster)
WARNING: Low level interface is baroque, and consequently, it will take a lot of disk space, RAM and CPU to build it: 100 MB would not be exaggeration and over an hour (on 1GHz CPU). Build time memory consumption of single cc1 process will be over 256 MB of RAM. You have been warned.
01 use Net::SAML;
02 $| = 1; undef $/; # Flush pipes, read all in at once
03 $url = "http://sp.tas3.pt:8082/zxidhlo.pl"; # Edit to match your situation
04 $conf = "PATH=/var/zxid/&URL=$url";
05 $cf = Net::SAML::new_conf_to_cf($conf);
06 $qs = $ENV{'QUERY_STRING'};
07 $qs = if $qs =~ /o=P/;
08 $res = Net::SAML::simple_cf($cf, -1, $qs, undef, 0x1828);
09 $op = substr($res, 0, 1);
10 if ($op eq 'L' || $op eq 'C') { print $res; exit; } # LOCATION (Redir) or CONTENT
11 if ($op eq 'n') { exit; } # already handled
12 if ($op eq 'e') { my_render_idpsel_screen(); exit; }
13 if ($op ne 'd') { die "Unknown Net::SAML::simple() res($res)"; }
14
15 ($sid) = $res =~ /^sesid: (.*)$/m; # Extract a useful attribute from SSO output
16
17 print <ZXID perl HLO SP Mgmt & Protected Content
21
22
23
24 $az
25 ZXID SP Perl HLO Management & Protected Content (user logged in, session active)
26 sesid: $sid
27 HTML
28 ;
29 print Net::SAML::fed_mgmt_cf($cf, undef, -1, $sid, 0x1900);
30 exit;
31
32 sub my_render_idpsel_screen { # Replaces traditional login screen
33 print <ZXID SP PERL HLO SSO IdP Selection
37
38
39
40 ZXID SP Perl HLO Federated SSO IdP Selection (user NOT logged in, no session.)
41
zxid.org
65 HTML
66 ;
67 }
This example only demosntrates SSO.
Lines 1-5 set up the configuration. See zxid-conf.pd for guidance.
ll.6-7 reads in the CGI input the perl way.
l.8 runs the SAML engine of ZXID. The engine will return result that is processed below. The magic constant 0x1828 sets some flags, see zxid-simple.pd for explanation. This explanation may be especially relevant if you plan to run as mod_perl process rather than as a CGI. With these flags you could eliminate the need to render the IdP selection screen.
ll.9-13: interpret the return value. l.10 deals with parts of SAML protocol that need redirect or content. l.12 deals with rendering the IdP selection screen. This screen replaces the traditional login screen in most applications.
l.15 demonstrates how to extract attributes from the return value. The ret is formatted as LDIF so it is very easy to parse with perl.
ll.17-30 render the "protected content". Most protected content should contain also Single Logout button. This is accomplished on l.29. Protected content is where your normal application after SSO lives. You can rely in ZXID session mechanism and just show the content, or you could bootstrap your application's session mechanism here.
ll.32-67 render the "idp selection" screen. This could have been automatically generated has the flags to Net::SAML::simple_cf() been different (see zxid-simple.pd for explanation).
As can be seen, the most central logic for SSO is only about 10 lines. The rest is user interface.
Net::SAML - The high level interfaces for Single Sign-On (SSO)
Net::SAML::Raw - Low level assertion and protocol manipulation interfaces
Net::SAML::Metadata - Low level metadata manipulation interfaces
Net::WSF - The high level interfaces for Web Services Frameworks (WSF)
Net::WSF::Raw - The low level interfaces for WSF variants
Net::WSF::WSC - The high level interfaces for Web Services Clients
Net::WSF::WSC:Raw
The perl APIs were generated from the C .h files using SWIG. Generally any C functions and constants that start by zxid_, ZXID_, SAML2_, or SAML_ have that prefix changed to Net::SAML::. Note, however, that the zx_ prefix is not stripped.
Since ZXID wants to keep strings in many places in length + data representation, namely as struct zx_str, SWIG typemaps were used to make this happen automatically. Thus any C function that takes as an argument struct zx_str* can take a perl string directly. Similarly any C function that returns such a pointer, will return a perl string instead. As a final goodie, any C function, such as
struct zx_str* zx_ref_len_str(struct zx_ctx* c, int len, char* s);
that takes length and s as explicit arguments, takes only single argument that is a perl string (the one argument automatically satisfies two C arguments, thanks to a type map). The above could be called like
$a = Net::SAML::zx_ref_len_str(c, "foo");
First the "foo" satisfies both len and ~s~, and then the return value is converted back to perl string.
To test the perl module, you must restart the mini_httpd(8) so that it recognizes zxid.pl as CGI script:
mini_httpd -p 8443 -c zxid.pl -S -E zxid.pem
Then start browsing from
https://sp1.zxidsp.org:8443/zxid.pl
or if you want to avoid the common domain cookie check
https://sp1.zxidsp.org:8443/zxid.pl?o=E
You can run zxid.pl under mod_perl using the Apache::Registry module. See Apache recipe for how to compile Apache to support mod_perl. After configuration it should work the same as the CGI approach.
As bizarre as it may sound, it is actually quite feasible to debug libzxid and the SAML_wrap.c using GDB while in perl. For example
cd zxid gdb /usr/local/bin/perl set env QUERY_STRING=o=E r ./zxid.pl
If the script crashes inside the C code, GDB will perfectly reasonably take control, allowing you to see stack back-trace (bt) and examine variables. Of course it helps if openssl and perl were compiled with debug symbols (libzxid is compiled with debug symbols by default), but even if they weren't you can usually at least get some clue.
When preparing a perl module, generally Makefile.PL mechanism causes the same compilation flags to be used as were used to compile the perl itself. Generally this is good, but if libzxid was compiled with different flags, mysterious errors can crop up. For example, I compile my libzxid against openssl that I have also compiled myself. However, I once had a bug where the perl had been compiled such that the Linux distribution's incompatible openssl would be picked by perl compile flags, resulting in mystery crashes deep inside openssl ASN.1 decoder routines (c2i_ASN1_INTEGER() while in d2i_X509() to be exact). When I issued `info files' in GDB I finally realized that I was using the wrong openssl library.
Copyright (c) 2010 Sampo Kellomäki (sampo@iki.fi), All Rights Reserved.
Copyright (c) 2006-2009 Symlabs (symlabs@symlabs.com), All Rights Reserved. Author: Sampo Kellomäki (sampo@iki.fi)
See file COPYING for complete information.
See zxid-faq.pd for full story.
Perl modules generally want to be compiled with the same C compiler and options as were used to compile perl itself (see perl -V). If this happens to be different than the compiler you have defined in CC variable (gcc by default, near top of Makefile or in localconf.mk), you may get an error like:
cd Net; perl Makefile.PL && make Warning: -L.. changed to -L/home/sampo/zxid/Net/.. Writing Makefile for Net::SAML make[1]: Entering directory `/home/sampo/zxid/Net' cc -c -I.. -I/apps/openssl/std/include -I/apps/include -D_REENTRANT -D_GNU_SOURCE -DTHREADS_HAVE_PIDS -DDEBUGGING -fno-strict-aliasing -pipe -Wdeclaration-after-statement -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -O2 -march=i586 -mtune=i686 -fmessage-length=0 -Wall -D_FORTIFY_SOURCE=2 -g -Wall -pipe -DVERSION=\"\" -DXS_VERSION=\"\" -fPIC "-I/usr/lib/perl5/5.8.8/i586-linux-thread-multi/CORE" SAML_wrap.c /bin/sh: cc: command not found make[1]: *** [SAML_wrap.o] Error 127 make[1]: Leaving directory `/zxid/Net' make: *** [samlmod] Error 2
Solutions
Compile zxid with compiler that was used for perl, e.g.
make CC=the-compiler-that-perl-wants
Recompile perl using the compiler that you want to use for zxid
Tinker with PATH environment variable so that both C compilers are found. However, using two different compilers is not really supported.
In general these types of problems happen when you use perl installed by your distribution, but have later compiled a gcc of your own. It may even be that you never installed the distribution cc - in that case consider installing it and then trying approaches 1 or 3.
A similar situation can arise with incompatibility of the compiler and options used for dependency libraries, such as OpenSSL or libcurl, and those used for compiling zxid itself.
You need to symlink zx to zxid source directory, thus
ln -s . zx
If you do not have it, then you will get a lot of file inclusion errors for headers that are supposed to be in path starting by zx/
The symlink is there to keep all hand written source files on top level of directory for ease of development, yet allow inclusions to go through zx subdirectory. When zxid is installed, it goes to /usr/include/zx. Hence the symlink keeps the includes the same whether developing or using installed version.
If you compile zxid with compiler warnings turned on (CFLAGS += -Wall), you will see quite a number of warnings, most of which are unwarranted. Since the warnings are unwarranted, I ship zxid Makefile with warnings turned off. If this bothers you, feel free to investigate the warnings and report to me any issues you uncover.
Following warnings in partuclar are unwarranted:
Any unusued variable warnings, especially in generated code. Most common of these is se variable (see enc-templ.c).
"Suggest parenthesis around assignment when used as truth value." I rely on C language operator precedence. Also, in most cases the assignment is the only expression in the truth test - there simply is no opportunity for ambiguity -- and no justified case for gcc to warn about this.
"Suggest parenthesis around && when used in ||". I rely on C language operator precedence, hence the suggestion is redundant.
Some warnings you may want to worry about
"int format, long int arg". On 32 bit platforms int and long are both 32 bits so this warning is not an issue. On 64 bit platforms, however, there may be cause for worry.