1<<if: ZXIDBOOK>>
2<<else: >>PHP Interface to ZXID
3#####################
4<<author: Sampo Kellom�ki (sampo@iki.fi)>>
5<<cvsid: $Id: zxid-php.pd,v 1.7 2010-01-08 02:10:09 sampo Exp $>>
6<<class: article!a4paper!!ZXID-PHP 01>>
7<<define: ZXDOC=ZXID PHP Interface>>
8
9<<abstract:
10
11ZXID.org Identity Management toolkit implements standalone SAML 2.0 and
12Liberty ID-WSF 2.0 stacks. This document describes the PHP glue.
13
14>>
15
16<<maketoc: 1>>
17
181 Introduction
19==============
20
21The PHP glue for ZXID was generated using swig(1), however, the swig
22interface is not a retrofit: the whole ZXID API was designed to
23be easily swiggifiable.
24
25The main aim of the glue is supporting the easy and simple API, see
26<<link:zxid-simple.html: zxid_simple()>> for general
27reference. Only differences and language specifics are covered in this
28document.
29
301.1 Other documents
31-------------------
32
33<<doc-inc.pd>>
34
357 PHP extension php_zxid.so
36===========================
37
38<<fi: >>
39
40The PHP integration is incomplete due to incomplete support in SWIG
41for php5. However, enough interface exists to get most high level API
42working and thus successfully run an SP.
43
447.1 Installing Binaries or from Package
45---------------------------------------
46
47TBD (*** WIP)
48
497.2 Building and Installing ZXID PHP extension
50----------------------------------------------
51
52After building main zxid distribution, say
53
54  make phpzxid
55
56You MUST have php-config(1) in path. If not, try
57
58  make phpzxid PHP_CONFIG=/path/to/php-config
59
60If the extension built successfully, you can use it by copying
61it to a suitable place, e.g.
62
63  make phpzxid_install
64
65The install again uses the php-config(1) to figure out where
66php(1) can find the module.
67
68Next you need to decide whether to run under Apache mod_php
69setup (apache), or as CGI (any web server).
70
71We have tested ZXID with php-5.1.6 and php-5.3.6 (current development
72target as of 20110707). For mod_php operation, the Apache httpd 2.2.3
73and 2.2.19 (current development target as of 20110707) have been
74tested.
75
767.2.1 Running PHP as Apache mod_php
77~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
78
79See <<link:apache.html: Apache recipe>> for how
80to compile Apache to support mod_php.
81
827.2.2 Running PHP as CGI (any web server)
83~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
84
85In the CGI case you generally make sure your CGI script starts like
86
87  #!/usr/bin/php
88  <?
89  dl("php_zxid.so");  # These three lines can go to initialization: they only need to run once
90  $conf = "PATH=/var/zxid/&URL=https://sp1.zxidsp.org:8443/zxidhlo.php";
91  $cf = zxid_new_conf_to_cf($conf);
92  ?>
93
94The first line makes sure the file is executed with php interpreter. You should
95change it to match the path where your php is installed. You also need to
96make your CGI script executable, e.g:
97
98  chmod a+x mycgi.php
99
100Then you place the CGI script in a directory in the document tree
101of the web site and make sure your http server is configured (permitted)
102to execute CGI scripts in that directory.
103
104One tricky thing that can go wrong is dynamic linking. When you compiled
105the php_zxid.so module, some linking dependencies are usually created.
106Problem arises if some of the dependencies are not in the paths
107allowed for dynamic linking by your web server. The paths allowed
108by web server can easily be different than in your shell and some
109web servers even ignore ~LD_LIBRARY_PATH~ environment variable. Sometimes
110you just have to copy the dependency libraries to one of the allowed
111directories. This is "dirty", but works. See ldconfig(8) and
112section <<see: ZXID-Installing-CannedTutorialRunningZXIDasCGIundermini_httpd-AccessingZXID>> for further information.
113
114You can easily see the dependencies using ldd(1)
115
116  ldd /apps/php/5.1.6/lib/php/extensions/no-debug-non-zts-20050922/php_zxid.so
117        linux-gate.so.1 =>  (0xffffe000)
118        libpthread.so.0 => /lib/libpthread.so.0 (0xb7796000)
119        libdl.so.2 => /lib/libdl.so.2 (0xb7792000)
120        libcurl.so.3 => /apps/lib/libcurl.so.3 (0xb7611000)
121        libz.so.1 => /apps/lib/libz.so.1 (0xb75fe000)
122        libc.so.6 => /lib/libc.so.6 (0xb74dd000)
123        /lib/ld-linux.so.2 (0x80000000)
124
125In this example the suspect library dependencies are
126/apps/lib/libcurl.so.3 and /apps/lib/libz.so.1 because they are
127outside normal places, i.e. /lib and /usr/lib.
128
129Another thing to remember is that CGI specification requires that the
130~Content-Type~ header and an empty line (to separate headers from
131content) is emitted before the actual page. If this fails to happen, the
132page will mysteriously not appear although your script ran successfully.
133
134Sometimes the debug output can end up in stdout (e.g. somewhere stderr
135was redirected to stdout) and this will garble the returned web page.
136Easy fix is to disable debug output by not supplying ~ZXID_AUTO_DEBUG~.
137See section <<see: ZXID-ZXID_simpleAPI-HelloWorld-AUTOoptions>>.
138
1397.3 Programming with ZXID PHP Extension
140---------------------------------------
141
142To use the ZXID PHP extension you must add near beginning of your script
143
144  dl("php_zxid.so");   // Load the module
145
146You may need to tweak the paths, or ~LD_LIBRARY_PATH~, to get this to work.
147
148After this, you can use the PHP interface much the same way as you
149would use the C interface. See the distributed zxid.php and
150zxidhlo.php for further usage examples.
151
1527.4 Simple API Using PHP
153------------------------
154
155(*** also in zxid-php.pd)
156
157The simplest APIs are easy to use and suitable for CGIs where the
158program is restarted anew every time. However in situations where the
159script engine stays alive persistently, it is wasteful to reparse (and
160reallocate) the configuration every time. Consider following PHP
161snippet designed to be used with mod_php:
162
163  01 # Put this in the PHP initialization (it only needs to run once)
164  02 dl("php_zxid.so");
165  03 $conf = "PATH=/var/zxid/&URL=https://sp1.zxidsp.org:8443/zxiddemo.php";
166  04 $cf = zxid_new_conf_to_cf($conf);
167  05 <?   # For every page that is accessed
168  06 $qs = $_SERVER['REQUEST_METHOD'] == 'GET'
169  07       ? $_SERVER['QUERY_STRING']
170  08       : file_get_contents('php://input');
171  09 $res = zxid_simple_cf($cf, -1, $qs, null, 0x1800);
172  10 switch (substr($res, 0, 1)) {
173  11 case 'L': header($res); exit;  # Redirect
174  12 case 'n': exit;   # already handled
175  13 case 'b': my_send_metadata();
176  14 case 'e': my_render_login_screen();
177  15 case 'd': break;  # Logged in case -- fall through
178  16 default:  error_log("Unknown zxid_simple() res(%s)", res); exit;
179  17 }
180  18 # *** Parse the LDIF in $res into a hash of attributes (see zxidhlo.php)
181  19
182  20 ?>
183  21 <html><title>Protected content, logged in as <$=$attr['cn']$></title>
184  22 ...
185  23 </html>
186  24 <?
187  25 function my_render_login_screen()
188  26 {
189  27 ?>
190  28 <html><title>Please Login Using IdP</title>
191  29 ...
192  30 <?=zxid_idp_select_cf($cf, 0, 0x1800)?>
193  31 ...</html>
194  32 <? exit; }?>
195
196Notes
197
1981. Line 4 creates a system-wide configuration object that is later
199   used by the other API calls
2002. On line 9 we call zxid_simple_cf() with the created object. The
201   second and third argument specify a buffer or string that contains
202   the CGI form data to parse. This may come from ~QUERY_STRING~ of a
203   GET request or from HTTP body of a POST request, as determined
204   on line 8. The -1 means the length of the data should be
205   determined using strlen(3), i.e. C string nul termination.
206   The ~auto_flags == 0x1800~ enables form tag wrapping and debug
207   prints, but otherwise automation is disabled.
2083. Since automation was disabled, we need to handle several
209   cases of possible outcomes from zxid_simple_cf(), on lines 10-17.
2104. From line 18 onwards we handle the login successful or already
211   logged in case. First we split the LDIF entry into a hash
212   so that we can access the attributes easily (e.g. ~cn~ on line 20).
2135. On line 30 we call zxid_idp_list_cf() to create the form
214   for choosing which IdP to use for login (remember that
215   ~auto_flags == 0xc0~ enabled the form wrapper). As can be
216   seen the same configuration object, ~$cf~, is used through out.
217
21814 Integration of Other Libraries with ZXID PHP
219===============================================
220
22114.2 Pat Patterson's php module
222-------------------------------
223
224(*** this section appears in README.zxid)
225
226Pat Patterson of Sun distributes a pure PHP module (not to be confused
227with Sun's OpenSSO open source effort, with which Pat has some
228contact) that implements some aspects of SAML 2.0. As of May 2007, his
229library provides functionality that, by and large, parallels that of the
230php_zxid module. A major advatage of his module is that it does not have
231C shared library dependency, but beware that he still depends on XML
232parsing and popular crypto libraries (openssl) to be available. These
233assumptions are not onerous, but you should be aware of them in case
234your system differs from main stream deployments.
235
236Overall, Pat's PHP implementation, as of May 2007, is still lacking
237in metadata generation and loading (it does not implement Auto-CoT
238or Well Known Location) and has some rough edges around less frequently
239used parts of the SAML specification. No doubt matters will improve
240over the time.
241
242Pat's library handles only SSO and not ID Web Services. It would be
243possible to extract the discovery bootstrap from SSO using his library
244after which you can use ZXID WSC API to actually call the services.
245
24614.3 Sun OpenSSO
247----------------
248
249Sun Microsystems distributes an open source implementation of SAML 2.0.
250Their implementation is of primary interest as it provides a freely available
251IdP implementation (as of May 2007 IMNSHO the ZXID SP interface is
252superior to the OpenSSO SP - and since both implement an open standard,
253you can mix ZXID SP with OpenSSO IdP).
254
255Thus, the ZXID to OpenSSO integration reduces to each one acting in its
256role using standard wire protocol - SAML 2.0.
257
25895 FAQ
259======
260
26195.1 Build and Linking Problems
262-------------------------------
263
26495.1.1 Dry run test
265~~~~~~~~~~~~~~~~~~~
266
267A good way to test whether php is able to run at all is to simulate
268running of a CGI script by setting few environment variables and
269then invoking the script from command line:
270
271 QUERY_STRING=o=E REQUEST_METHOD=GET php ./zxidhlo.php
272
273The result should be the IdP selection page as HTML. Another test is
274to run o=B to obtain the metadata.
275
27695.1.1 Duplicate symbols
277~~~~~~~~~~~~~~~~~~~~~~~~
278
279Following types of error messages
280
281 Warning: Function registration failed - duplicate name - hexdec in /a/d/sampo/zxid/zxidhlo.php on line 16
282
283 Warning: zxid:  Unable to register functions, unable to load in Unknown on line 0
284
285 Fatal error: Call to undefined function zxid_new_conf_to_cf() in /a/d/sampo/zxid/zxidhlo.php on line 22
286
287Theory: the zxid library has already been loaded in some other way, such as part
288of mod_auth_saml or Net::SAML loading.
289
290<<if: ZXIDBOOK>>
291<<else: >>
292
29396 License
294==========
295
296Copyright (c) 2006-2009 Symlabs (symlabs@symlabs.com), All Rights Reserved.
297Author: Sampo Kellom�ki (sampo@iki.fi)
298
299See file COPYING for complete information.
300
301<<references:
302
303[SAML2core] "Assertions and Protocols for the OASIS Security Assertion Markup Language (SAML) V2.0", Oasis Standard, 15.3.2005, saml-core-2.0-os
304
305>>
306
307<<doc-end.pd>>
308<<notapath: TCP/IP a.k.a xBSD/Unix n/a Perl/mod_perl PHP/mod_php Java/Tomcat>>
309<<EOF: >>
310<<fi: >>