[MANUAL] English:
[zend.git] / documentation / manual / en / module_specs / Zend_OpenId-Provider.xml
blob64b9f067c1c212b019e9f166fb7d432d80fc6bca
1 <?xml version="1.0" encoding="UTF-8"?>
2 <!-- Reviewed: no -->
3 <sect1 id="zend.openid.provider">
4     <title>Zend_OpenId_Provider</title>
6     <para>
7         <classname>Zend_OpenId_Provider</classname> can be used to implement OpenID
8         servers. This chapter provides examples that demonstrate how to
9         build a very basic server. However, for implementation of a production OpenID
10         server (such as <ulink url="http://www.myopenid.com">www.myopenid.com</ulink>) you
11         may have to deal with more complex issues.
12     </para>
14     <sect2 id="zend.openid.provider.start">
15         <title>Quick start</title>
17         <para>
18             The following example includes code for creating a user account
19             using <classname>Zend_OpenId_Provider::register</classname>. The link element with
20             <code>rel="openid.server"</code> points to our own server script. If you
21             submit this identity to an OpenID-enabled site, it will perform
22             authentication on this server.
23         </para>
25         <para>
26             The code before the &lt;html&gt; tag is just a trick that automatically
27             creates a user account. You won't need such code when using real
28             identities.
29         </para>
31         <example id="zend.openid.provider.example-1">
32             <title>The Identity</title>
34             <programlisting language="php"><![CDATA[
35 <?php
36 // Set up test identity
37 define("TEST_SERVER", Zend_OpenId::absoluteURL("example-8.php"));
38 define("TEST_ID", Zend_OpenId::selfURL());
39 define("TEST_PASSWORD", "123");
40 $server = new Zend_OpenId_Provider();
41 if (!$server->hasUser(TEST_ID)) {
42     $server->register(TEST_ID, TEST_PASSWORD);
45 <html><head>
46 <link rel="openid.server" href="<?php echo TEST_SERVER;?>" />
47 </head><body>
48 <?php echo TEST_ID;?>
49 </body></html>
50 ]]></programlisting>
51         </example>
53         <para>
54             The following identity server script handles two kinds of requests
55             from OpenID-enabled sites (for association and authentication). Both of
56             them are handled by the same method:
57             <classname>Zend_OpenId_Provider::handle</classname>. The two arguments to the
58             <classname>Zend_OpenId_Provider</classname> constructor are <acronym>URL</acronym>s of
59             login and trust pages, which ask for input from the end user.
60         </para>
62         <para>
63             On success, the method <classname>Zend_OpenId_Provider::handle</classname>
64             returns a string that should be passed back to the OpenID-enabled site. On
65             failure, it returns <constant>FALSE</constant>. This example will return an
66             <acronym>HTTP</acronym> 403 response if
67             <classname>Zend_OpenId_Provider::handle</classname> fails. You will get this response if
68             you open this script with a web browser, because it sends a non-OpenID conforming
69             request.
70         </para>
72         <example id="zend.openid.provider.example-2">
73             <title>Simple Identity Provider</title>
75             <programlisting language="php"><![CDATA[
76 $server = new Zend_OpenId_Provider("example-8-login.php",
77                                    "example-8-trust.php");
78 $ret = $server->handle();
79 if (is_string($ret)) {
80     echo $ret;
81 } else if ($ret !== true) {
82     header('HTTP/1.0 403 Forbidden');
83     echo 'Forbidden';
85 ]]></programlisting>
86         </example>
88         <note>
89             <para>
90                 It is a good idea to use a secure connection (HTTPS) for these scripts-
91                 especially for the following interactive scripts- to prevent password
92                 disclosure.
93             </para>
94         </note>
96         <para>
97             The following script implements a login screen for an identity
98             server using <classname>Zend_OpenId_Provider</classname> and redirects to this page when
99             a required user has not yet logged in. On this page, a user will enter his password
100             to login.
101         </para>
103         <para>
104             You should use the password "123" that was used in the identity script above.
105         </para>
107         <para>
108             On submit, the script calls <classname>Zend_OpenId_Provider::login</classname>
109             with the accepted user's identity and password, then redirects back
110             to the main identity provider's script. On success, the
111             <classname>Zend_OpenId_Provider::login</classname> establishes a session between the
112             user and the identity provider and stores the information about
113             the user, who is now logged in. All following requests from the same user won't
114             require a login procedure- even if they come from another OpenID enabled
115             web site.
116         </para>
118         <note>
119             <para>
120                 Note that this session is between end-user and identity provider
121                 only. OpenID enabled sites know nothing about it.
122             </para>
123         </note>
125         <example id="zend.openid.provider.example-3">
126             <title>Simple Login Screen</title>
128             <programlisting language="php"><![CDATA[
129 <?php
130 $server = new Zend_OpenId_Provider();
132 if ($_SERVER['REQUEST_METHOD'] == 'POST' &&
133     isset($_POST['openid_action']) &&
134     $_POST['openid_action'] === 'login' &&
135     isset($_POST['openid_identifier']) &&
136     isset($_POST['openid_password'])) {
137     $server->login($_POST['openid_identifier'],
138                    $_POST['openid_password']);
139     Zend_OpenId::redirect("example-8.php", $_GET);
142 <html>
143 <body>
144 <form method="post">
145 <fieldset>
146 <legend>OpenID Login</legend>
147 <table border=0>
148 <tr>
149 <td>Name:</td>
150 <td>
151 <input type="text"
152        name="openid_identifier"
153        value="<?php echo htmlspecialchars($_GET['openid_identity']);?>">
154 </td>
155 </tr>
156 <tr>
157 <td>Password:</td>
158 <td>
159 <input type="text"
160        name="openid_password"
161        value="">
162 </td>
163 </tr>
164 <tr>
165 <td>&nbsp;</td>
166 <td>
167 <input type="submit"
168        name="openid_action"
169        value="login">
170 </td>
171 </tr>
172 </table>
173 </fieldset>
174 </form>
175 </body>
176 </html>
177 ]]></programlisting>
178         </example>
180         <para>
181             The fact that the user is now logged in doesn't mean that the
182             authentication must necessarily succeed. The user may decide not to trust
183             particular OpenID enabled sites. The following trust screen allows the
184             end user to make that choice. This choice may either be made only for current
185             requests or forever. In the second case, information about
186             trusted/untrusted sites is stored in an internal database, and all
187             following authentication requests from this site will be handled
188             automatically without user interaction.
189         </para>
191         <example id="zend.openid.provider.example-4">
192             <title>Simple Trust Screen</title>
194             <programlisting language="php"><![CDATA[
195 <?php
196 $server = new Zend_OpenId_Provider();
198 if ($_SERVER['REQUEST_METHOD'] == 'POST' &&
199     isset($_POST['openid_action']) &&
200     $_POST['openid_action'] === 'trust') {
202     if (isset($_POST['allow'])) {
203         if (isset($_POST['forever'])) {
204             $server->allowSite($server->getSiteRoot($_GET));
205         }
206         $server->respondToConsumer($_GET);
207     } else if (isset($_POST['deny'])) {
208         if (isset($_POST['forever'])) {
209             $server->denySite($server->getSiteRoot($_GET));
210         }
211         Zend_OpenId::redirect($_GET['openid_return_to'],
212                               array('openid.mode'=>'cancel'));
213     }
216 <html>
217 <body>
218 <p>A site identifying as
219 <a href="<?php echo htmlspecialchars($server->getSiteRoot($_GET));?>">
220 <?php echo htmlspecialchars($server->getSiteRoot($_GET));?>
221 </a>
222 has asked us for confirmation that
223 <a href="<?php echo htmlspecialchars($server->getLoggedInUser());?>">
224 <?php echo htmlspecialchars($server->getLoggedInUser());?>
225 </a>
226 is your identity URL.
227 </p>
228 <form method="post">
229 <input type="checkbox" name="forever">
230 <label for="forever">forever</label><br>
231 <input type="hidden" name="openid_action" value="trust">
232 <input type="submit" name="allow" value="Allow">
233 <input type="submit" name="deny" value="Deny">
234 </form>
235 </body>
236 </html>
237 ]]></programlisting>
238         </example>
240         <para>
241             Production OpenID servers usually support the Simple Registration
242             Extension that allows consumers to request some information about the user from
243             the provider. In this case, the trust page can be extended to allow
244             entering requested fields or selecting a specific user profile.
245         </para>
246     </sect2>
248     <sect2 id="zend.openid.provider.all">
249         <title>Combined Provide Scripts</title>
251         <para>
252             It is possible to combine all provider functionality in one script. In
253             this case login and trust <acronym>URL</acronym>s are omitted, and
254             <classname>Zend_OpenId_Provider</classname> assumes that they point to the same page
255             with the additional "openid.action" GET argument.
256         </para>
258         <note>
259             <para>
260                 The following example is not complete. It doesn't provide GUI code for
261                 the user, instead performing an automatic login and trust relationship instead.
262                 This is done just to simplify the example; a production server should include some
263                 code from previous examples.
264             </para>
265         </note>
267         <example id="zend.openid.provider.example-5">
268             <title>Everything Together</title>
270             <programlisting language="php"><![CDATA[
271 $server = new Zend_OpenId_Provider();
273 define("TEST_ID", Zend_OpenId::absoluteURL("example-9-id.php"));
274 define("TEST_PASSWORD", "123");
276 if ($_SERVER['REQUEST_METHOD'] == 'GET' &&
277     isset($_GET['openid_action']) &&
278     $_GET['openid_action'] === 'login') {
279     $server->login(TEST_ID, TEST_PASSWORD);
280     unset($_GET['openid_action']);
281     Zend_OpenId::redirect(Zend_OpenId::selfUrl(), $_GET);
282 } else if ($_SERVER['REQUEST_METHOD'] == 'GET' &&
283     isset($_GET['openid_action']) &&
284     $_GET['openid_action'] === 'trust') {
285     unset($_GET['openid_action']);
286     $server->respondToConsumer($_GET);
287 } else {
288     $ret = $server->handle();
289     if (is_string($ret)) {
290         echo $ret;
291     } else if ($ret !== true) {
292         header('HTTP/1.0 403 Forbidden');
293         echo 'Forbidden';
294     }
296 ]]></programlisting>
297         </example>
299         <para>
300             If you compare this example with previous examples split in to
301             separate pages, you will see only the one
302             difference besides the dispatch code:
303             <methodname>unset($_GET['openid_action'])</methodname>. This call to <code>unset</code>
304             is necessary to route the next request to main handler.
305         </para>
306     </sect2>
308     <sect2 id="zend.openid.provider.sreg">
309         <title>Simple Registration Extension</title>
311         <para>
312             Again, the code before the &lt;html&gt; tag is just a trick to demonstrate
313             functionality. It creates a new user account and associates it with a profile (nickname
314             and password). Such tricks aren't needed in deployed providers where end users register
315             on OpenID servers and fill in their profiles. Implementing this GUI is out of scope for
316             this manual.
317         </para>
319         <example id="zend.openid.provider.example-6">
320             <title>Identity with Profile</title>
322             <programlisting language="php"><![CDATA[
323 <?php
324 define("TEST_SERVER", Zend_OpenId::absoluteURL("example-10.php"));
325 define("TEST_ID", Zend_OpenId::selfURL());
326 define("TEST_PASSWORD", "123");
327 $server = new Zend_OpenId_Provider();
328 if (!$server->hasUser(TEST_ID)) {
329     $server->register(TEST_ID, TEST_PASSWORD);
330     $server->login(TEST_ID, TEST_PASSWORD);
331     $sreg = new Zend_OpenId_Extension_Sreg(array(
332         'nickname' =>'test',
333         'email' => 'test@test.com'
334     ));
335     $root = Zend_OpenId::absoluteURL(".");
336     Zend_OpenId::normalizeUrl($root);
337     $server->allowSite($root, $sreg);
338     $server->logout();
341 <html>
342 <head>
343 <link rel="openid.server" href="<?php echo TEST_SERVER;?>" />
344 </head>
345 <body>
346 <?php echo TEST_ID;?>
347 </body>
348 </html>
349 ]]></programlisting>
350         </example>
352         <para>
353             You should now pass this identity to the OpenID-enabled web site (use the Simple
354             Registration Extension example from the previous section), and it should use the
355             following OpenID server script.
356         </para>
358         <para>
359             This script is a variation of the script in the "Everything Together" example. It uses
360             the same automatic login mechanism, but doesn't contain any code for a trust
361             page. The user already trusts the example scripts forever. This trust was
362             established by calling the <methodname>Zend_OpenId_Provider::allowSite()</methodname>
363             method in the identity script. The same method associates the profile with the trusted
364             <acronym>URL</acronym>. This profile will be returned automatically for a request from
365             the trusted <acronym>URL</acronym>.
366         </para>
368         <para>
369             To make Simple Registration Extension work, you must simply
370             pass an instance of <classname>Zend_OpenId_Extension_Sreg</classname> as the second
371             argument to the <methodname>Zend_OpenId_Provider::handle()</methodname> method.
372         </para>
374         <example id="zend.openid.provider.example-7">
375             <title>Provider with SREG</title>
377             <programlisting language="php"><![CDATA[
378 $server = new Zend_OpenId_Provider();
379 $sreg = new Zend_OpenId_Extension_Sreg();
381 define("TEST_ID", Zend_OpenId::absoluteURL("example-10-id.php"));
382 define("TEST_PASSWORD", "123");
384 if ($_SERVER['REQUEST_METHOD'] == 'GET' &&
385     isset($_GET['openid_action']) &&
386     $_GET['openid_action'] === 'login') {
387     $server->login(TEST_ID, TEST_PASSWORD);
388     unset($_GET['openid_action']);
389     Zend_OpenId::redirect(Zend_OpenId::selfUrl(), $_GET);
390 } else if ($_SERVER['REQUEST_METHOD'] == 'GET' &&
391     isset($_GET['openid_action']) &&
392     $_GET['openid_action'] === 'trust') {
393    echo "UNTRUSTED DATA" ;
394 } else {
395     $ret = $server->handle(null, $sreg);
396     if (is_string($ret)) {
397         echo $ret;
398     } else if ($ret !== true) {
399         header('HTTP/1.0 403 Forbidden');
400         echo 'Forbidden';
401     }
403 ]]></programlisting>
404         </example>
405     </sect2>
407     <sect2 id="zend.openid.provider.else">
408         <title>Anything Else?</title>
410         <para>
411             Building OpenID providers is much less common than building
412             OpenID-enabled sites, so this manual doesn't cover all
413             <classname>Zend_OpenId_Provider</classname> features exhaustively, as was done for
414             <classname>Zend_OpenId_Consumer</classname>.
415         </para>
417         <para>
418             To summamize, <classname>Zend_OpenId_Provider</classname> contains:
419         </para>
421         <itemizedlist>
422             <listitem>
423                 <para>
424                     A set of methods to build an end-user GUI that allows
425                     users to register and manage their trusted sites and profiles
426                 </para>
427             </listitem>
429             <listitem>
430                 <para>
431                     An abstract storage layer to store information about users,
432                     their sites and their profiles. It also stores associations between
433                     the provider and OpenID-enabled sites. This layer is very similar
434                     to that of the <classname>Zend_OpenId_Consumer</classname> class. It also uses
435                     file storage by default, but may used with another backend.
436                 </para>
437             </listitem>
439             <listitem>
440                 <para>
441                     An abstract user-association layer that may associate
442                     a user's web browser with a logged-in identity
443                 </para>
444             </listitem>
445         </itemizedlist>
447         <para>
448             The <classname>Zend_OpenId_Provider</classname> class doesn't attempt to cover all
449             possible features that can be implemented by OpenID servers, e.g. digital
450             certificates, but it can be extended easily using
451             <classname>Zend_OpenId_Extension</classname>s or by standard object-oriented extension.
452         </para>
453     </sect2>
454 </sect1>
455 <!--
456 vim:se ts=4 sw=4 et: