Zend_OpenId-Provider.xml 16 KB

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