1<?
2# zxid/zxid.php  -  Implement SAML SP role in PHP using zxid extension
3#
4# Copyright (c) 2006-2008 Symlabs (symlabs@symlabs.com), All Rights Reserved.
5# Author: Sampo Kellomaki (sampo@iki.fi)
6# This is confidential unpublished proprietary source code of the author.
7# NO WARRANTY, not even implied warranties. Contains trade secrets.
8# Distribution prohibited unless authorized in writing.
9# Licensed under Apache License 2.0, see file COPYING.
10# $Id: zxid.php,v 1.8 2008-05-26 15:28:44 sampo Exp $
11# 31.8.2006, created --Sampo
12# 15.9.2006, enhanced to actually support SSO --Sampo
13# 5.3.2007, double checked and fixed to work against 0.16 --Sampo
14# 25.5.2008, fixed to work against 0.27, fixed port number to 5443 --Sampo
15
16dl("php_zxid.so");
17
18$cf = zxid_new_conf("/var/zxid/");
19$path = zxid_conf_path_get($cf);   # *** Weird: without "get" the cf->path is screwed?!?
20#$path_len = zxid_conf_path_len_get($cf);
21#error_log("path($path) len($len)", 0);
22
23$url = "https://sp1.zxidsp.org:5443/zxid.php";
24$cdc_url = "https://sp1.zxidcommon.org:5443/zxid.php";  # zxid_my_cdc_url()
25zxid_url_set($cf, $url);
26zxid_set_opt($cf, 1 ,1);  # Turn on libzxid level debugging
27$cgi = zxid_new_cgi($cf, $_SERVER['QUERY_STRING']);
28$op = zxid_cgi_op_get($cgi);
29error_log("op($op)", 0);
30if ($op == 'P') {
31    $qs = file_get_contents('php://input');  # better than $HTTP_RAW_POST_DATA
32    error_log("raw post($qs)", 0);
33    zxid_parse_cgi($cgi, $qs);
34    $op = zxid_cgi_op_get($cgi);
35}
36if (!$op) $op = 'M';
37
38function mgmt_screen($cf, $cgi, $ses, $op)
39{
40    error_log("mgmt op($op)", 0);
41    switch ($op) {
42    case 'l':
43	zxid_del_ses($cf, $ses);
44        $msg = "Local logout Ok. Session terminated.";
45	return 0;  # Simply abandon local session. Falls thru to login screen.
46    case 'r':
47	$loc = zxid_sp_slo_location($cf, $cgi, $ses);
48	zxid_del_ses($cf, $ses);
49        header($loc);
50	return 1;  # Redirect already happened. Do not show login screen.
51    case 's':
52	zxid_sp_slo_soap($cf, $cgi, $ses);
53	zxid_del_ses($cf, $ses);
54	$msg = "SP Initiated logout (SOAP). Session terminated.";
55	return 0;  # Falls thru to login screen.
56    case 't':
57	$loc = zxid_sp_nireg_location($cf, $cgi, $ses, 0);
58        header($loc);
59	return 1;  # Redirect already happened. Do not show login screen.
60    case 'u':
61	zxid_sp_nireg_soap($cf, $cgi, $ses, 0);
62	$msg = "SP Initiated defederation (SOAP).";
63        break;
64    case 'P':
65	$ret = zxid_sp_dispatch($cf, $cgi, $ses, zxid_cgi_saml_resp_get($cgi));
66        switch ($ret) {
67	case ZXID_OK:       return 0;
68	case ZXID_REDIR_OK: return 1;
69        }
70        break;
71    case 'Q':
72	$ret = zxid_sp_dispatch($cf, $cgi, $ses, zxid_cgi_saml_req_get($cgi));
73        switch ($ret) {
74	case ZXID_OK:       return 0;
75	case ZXID_REDIR_OK: return 1;
76        }
77        break;
78    }
79
80    $sid = zxid_ses_sid_get($ses);
81    $nid = zxid_ses_nid_get($ses);
82
83    # In gimp flatten the image and Save Copy as pnm
84    # giftopnm favicon.gif | ppmtowinicon >favicon.ico
85    #printf("COOKIE: foo\r\n");
86?>
87<title>ZXID SP Mgmt PHP</title>
88<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" />
89<body bgcolor="#330033" text="#ffaaff" link="#ffddff" vlink="#aa44aa" alink="#ffffff"><font face=sans>
90
91<h1>ZXID SP Management PHP (user logged in, session active)</h1><pre>
92</pre><form method=post action="zxid.php?o=P">
93<input type=hidden name=s value="<?=$sid?>">
94<input type=submit name=gl value=" Local Logout ">
95<input type=submit name=gr value=" Single Logout (Redir) ">
96<input type=submit name=gs value=" Single Logout (SOAP) ">
97<input type=submit name=gt value=" Defederate (Redir) ">
98<input type=submit name=gu value=" Defederate (SOAP) ">
99
100<h3>Technical options (typically hidden fields on production site)</h3>
101
102sid(<?=$sid?>) nid(<?=$nid?>) <a href="zxid.php?s=<?=$sid?>">Reload</a>
103
104</form><hr>
105<a href="http://zxid.org/">zxid.org</a>
106<?
107  return 1;
108}
109
110$sid = zxid_cgi_sid_get($cgi)
111    and $ses = zxid_fetch_ses($cf, $sid)
112    and mgmt_screen($cf, $cgi, $ses, $op)
113    and exit;
114$ses = zxid_fetch_ses($cf, "");  # Just allocate an empty one
115
116error_log("Not logged-in case: op($op) ses($ses)", 0);
117
118switch ($op) {
119case 'M':       # Invoke LECP or redirect to CDC reader.
120    #if (zxid_lecp_check($cf, $cgi)) exit;
121    header("Location: $cdc_url?o=C");
122    exit;
123case 'C':  # CDC Read: Common Domain Cookie Reader
124    zxid_cdc_read($cf, $cgi);
125    exit;
126case 'E':  # Return from CDC read, or start here to by-pass CDC read.
127    #if (zxid_lecp_check($cf, $cgi)) exit;
128    if (zxid_cdc_check($cf, $cgi)) exit;
129    break;
130case 'L':
131    error_log("Start login", 0);
132    $loc = zxid_start_sso_location($cf, $cgi);
133    if ($loc) {
134	error_log("login redir($loc)", 0);
135	header($loc);
136	exit;
137    }
138    error_log("Login trouble", 0);
139    break;
140case 'A':
141    $ret = zxid_sp_deref_art($cf, $cgi, $ses);
142    error_log("deref art ret($ret)", 0);
143    if ($ret == ZXID_REDIR_OK) exit;
144    if ($ret == ZXID_SSO_OK)
145      if (mgmt_screen($cf, $cgi, $ses, $op))
146        exit;
147    break;
148case 'P':
149    $ret = zxid_sp_dispatch($cf, $cgi, $ses, zxid_cgi_saml_resp_get($cgi));
150    error_log("saml_resp ret($ret)", 0);
151    if ($ret == ZXID_REDIR_OK) exit;
152    if ($ret == ZXID_SSO_OK)
153      if (mgmt_screen($cf, $cgi, $ses, $op))
154        exit;
155    break;
156case 'Q':
157    $ret = zxid_sp_dispatch($cf, $cgi, $ses, zxid_cgi_saml_req_get($cgi));
158    if ($ret == ZXID_REDIR_OK) exit;
159    if ($ret == ZXID_SSO_OK)
160      if (mgmt_screen($cf, $cgi, $ses, $op))
161        exit;
162    break;
163case 'B':
164    header("CONTENT-TYPE: text/xml");
165    $md = zxid_sp_meta($cf, $cgi);
166    echo $md;
167    exit;
168default:
169    error_log("Unknown op($op)", 0);
170}
171
172?>
173<title>ZXID SP SSO PHP</title>
174<link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" />
175<body bgcolor="#330033" text="#ffaaff" link="#ffddff" vlink="#aa44aa" alink="#ffffff"><font face=sans><h1>ZXID SP Federated SSO PHP (user NOT logged in, no session.)</h1><pre>
176</pre><form method=post action="zxid.php?o=P">
177
178<h3>Login Using New IdP</h3>
179
180<i>A new IdP is one whose metadata we do not have yet. We need to know
181the Entity ID in order to fetch the metadata using the well known
182location method. You will need to ask the adminstrator of the IdP to
183tell you what the EntityID is.</i>
184
185<p>IdP EntityID URL <input name=e size=60>
186<input type=submit name=l1 value=" Login (SAML20:Artifact) ">
187<input type=submit name=l2 value=" Login (SAML20:POST) ">
188<?
189
190$idp = zxid_load_cot_cache($cf);
191if ($idp) {
192    echo "<h3>Login Using Known IdP</h3>\n";
193    while ($idp) {
194	$eid = zxid_entity_eid_get($idp);
195	$eid_len = zxid_entity_eid_len_get($idp);
196	$eid = substr($eid, 0, $eid_len);
197	error_log("eid_len($eid_len) eid($eid)", 0);
198	echo <<< HTML
199<input type=submit name="l1$eid" value=" Login to $eid (SAML20:Artifact) ">
200<input type=submit name="l2$eid" value=" Login to $eid (SAML20:POST) ">
201HTML;
202	$idp = zxid_entity_n_get($idp);
203    }
204}
205
206$version_str = zxid_version_str();
207
208?>
209<h3>CoT configuration parameters your IdP may need to know</h3>
210
211Entity ID of this SP: <a href="<?=$url?>?o=B"><?=$url?>?o=B</a> (Click on the link to fetch SP metadata.)
212
213<h3>Technical options (typically hidden fields on production site)</h3>
214
215<input type=checkbox name=fc value=1 checked> Allow new federation to be created<br>
216<input type=checkbox name=fp value=1> Do not allow IdP to interact (e.g. ask password) (IsPassive flag)<br>
217<input type=checkbox name=ff value=1> IdP should reauthenticate user (ForceAuthn flag)<br>
218NID Format: <select name=fn><option value=prstnt>Persistent<option value=trnsnt>Transient<option value="">(none)</select><br>
219Affiliation: <select name=fq><option value="">(none)</select><br>
220
221Consent: <select name=fy><option value="">(empty)
222<option value="urn:liberty:consent:obtained">obtained
223<option value="urn:liberty:consent:obtained:prior">obtained:prior
224<option value="urn:liberty:consent:obtained:current:implicit">obtained:current:implicit
225<option value="urn:liberty:consent:obtained:current:explicit">obtained:current:explicit
226<option value="urn:liberty:consent:unavailable">unavailable
227<option value="urn:liberty:consent:inapplicable">inapplicable
228</select><br>
229Authn Req Context: <select name=fa><option value="">(none)
230<option value=pw>Password
231<option value=pwp>Password with Protected Transport
232<option value=clicert>TLS Client Certificate</select><br>
233Matching Rule: <select name=fm><option value=exact>Exact
234<option value=minimum>Min
235<option value=maximum>Max
236<option value=better>Better
237<option value="">(none)</select><br>
238
239</form><hr><a href="http://zxid.org/">zxid.org</a>, <?=$version_str?>
240