2
0

Zend_InfoCard-Basics.xml 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!-- Reviewed: no -->
  3. <sect1 id="zend.infocard.basics">
  4. <title>Introduction</title>
  5. <para>
  6. The <classname>Zend_InfoCard</classname> component implements relying-party
  7. support for Information Cards. Information Cards are used for identity
  8. management on the internet and authentication of users to web sites. The web sites
  9. that the user ultimately authenticates to are called <emphasis>relying-parties</emphasis>.
  10. </para>
  11. <para>
  12. Detailed information about information cards and their importance to the
  13. internet identity metasystem can be found on the <ulink
  14. url="http://www.identityblog.com/">IdentityBlog</ulink>.
  15. </para>
  16. <sect2 id="zend.infocard.basics.theory">
  17. <title>Basic Theory of Usage</title>
  18. <para>
  19. Usage of <classname>Zend_InfoCard</classname> can be done one of two ways:
  20. either as part of the larger <classname>Zend_Auth</classname> component via
  21. the <classname>Zend_InfoCard</classname> authentication adapter or as a
  22. stand-alone component. In both cases an information card can be
  23. requested from a user by using the following HTML block in your HTML
  24. login form:
  25. </para>
  26. <programlisting language="html"><![CDATA[
  27. <form action="http://example.com/server" method="POST">
  28. <input type='image' src='/images/ic.png' align='center'
  29. width='120px' style='cursor:pointer' />
  30. <object type="application/x-informationCard"
  31. name="xmlToken">
  32. <param name="tokenType"
  33. value="urn:oasis:names:tc:SAML:1.0:assertion" />
  34. <param name="requiredClaims"
  35. value="http://.../claims/privatepersonalidentifier
  36. http://.../claims/givenname
  37. http://.../claims/surname" />
  38. </object>
  39. </form>
  40. ]]></programlisting>
  41. <para>
  42. In the example above, the <code>requiredClaims</code>
  43. <code>&lt;param&gt;</code> tag is used to identify pieces of
  44. information known as claims (i.e. person's first name, last name)
  45. which the web site (a.k.a "relying party") needs in order a user to
  46. authenticate using an information card. For your reference, the full
  47. URI (for instance the <code>givenname</code> claim) is as follows:
  48. <code>http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname</code>
  49. </para>
  50. <para>
  51. When the above HTML is activated by a user (clicks on it), the
  52. browser will bring up a card selection program which not only shows
  53. them which information cards meet the requirements of the site, but
  54. also allows them to select which information card to use if multiple
  55. meet the criteria. This information card is transmitted as an XML
  56. document to the specified <code>POST</code> URL and is ready to be
  57. processed by the <classname>Zend_InfoCard</classname> component.
  58. </para>
  59. <para>
  60. Note, Information cards can only be <code>HTTP POST</code>ed to
  61. SSL-encrypted URLs. Please consult your web server's documentation
  62. on how to set up SSL encryption.
  63. </para>
  64. </sect2>
  65. <sect2 id="zend.infocard.basics.auth">
  66. <title>Using as part of Zend_Auth</title>
  67. <para>
  68. In order to use the component as part of the <classname>Zend_Auth</classname>
  69. authentication system, you must use the provided
  70. <classname>Zend_Auth_Adapter_InfoCard</classname> to do so (not available in
  71. the standalone <classname>Zend_InfoCard</classname> distribution). An example
  72. of its usage is shown below:
  73. </para>
  74. <programlisting language="php"><![CDATA[
  75. <?php
  76. if (isset($_POST['xmlToken'])) {
  77. $adapter = new Zend_Auth_Adapter_InfoCard($_POST['xmlToken']);
  78. $adapter->addCertificatePair('/usr/local/Zend/apache2/conf/server.key',
  79. '/usr/local/Zend/apache2/conf/server.crt');
  80. $auth = Zend_Auth::getInstance();
  81. $result = $auth->authenticate($adapter);
  82. switch ($result->getCode()) {
  83. case Zend_Auth_Result::SUCCESS:
  84. $claims = $result->getIdentity();
  85. print "Given Name: {$claims->givenname}<br />";
  86. print "Surname: {$claims->surname}<br />";
  87. print "Email Address: {$claims->emailaddress}<br />";
  88. print "PPI: {$claims->getCardID()}<br />";
  89. break;
  90. case Zend_Auth_Result::FAILURE_CREDENTIAL_INVALID:
  91. print "The Credential you provided did not pass validation";
  92. break;
  93. default:
  94. case Zend_Auth_Result::FAILURE:
  95. print "There was an error processing your credentials.";
  96. break;
  97. }
  98. if (count($result->getMessages()) > 0) {
  99. print "<pre>";
  100. var_dump($result->getMessages());
  101. print "</pre>";
  102. }
  103. }
  104. ?>
  105. <hr />
  106. <div id="login" style="font-family: arial; font-size: 2em;">
  107. <p>Simple Login Demo</p>
  108. <form method="post">
  109. <input type="submit" value="Login" />
  110. <object type="application/x-informationCard" name="xmlToken">
  111. <param name="tokenType"
  112. value="urn:oasis:names:tc:SAML:1.0:assertion" />
  113. <param name="requiredClaims"
  114. value="http://.../claims/givenname
  115. http://.../claims/surname
  116. http://.../claims/emailaddress
  117. http://.../claims/privatepersonalidentifier" />
  118. </object>
  119. </form>
  120. </div>
  121. ]]></programlisting>
  122. <para>
  123. In the example above, we first create an instance of the
  124. <classname>Zend_Auth_Adapter_InfoCard</classname> and pass the XML data posted
  125. by the card selector into it. Once an instance has been created you
  126. must then provide at least one SSL certificate public/private key
  127. pair used by the web server that received the <code>HTTP
  128. POST</code>. These files are used to validate the destination
  129. of the information posted to the server and are a requirement when
  130. using Information Cards.
  131. </para>
  132. <para>
  133. Once the adapter has been configured, you can then use the standard
  134. <classname>Zend_Auth</classname> facilities to validate the provided
  135. information card token and authenticate the user by examining the
  136. identity provided by the <code>getIdentity()</code> method.
  137. </para>
  138. </sect2>
  139. <sect2 id="zend.infocard.basics.standalone">
  140. <title>Using the Zend_InfoCard component standalone</title>
  141. <para>
  142. It is also possible to use the Zend_InfoCard component as a
  143. standalone component by interacting with the
  144. <classname>Zend_InfoCard</classname> class directly. Using the Zend_InfoCard
  145. class is very similar to its use with the <classname>Zend_Auth</classname>
  146. component. An example of its use is shown below:
  147. </para>
  148. <programlisting language="php"><![CDATA[
  149. <?php
  150. if (isset($_POST['xmlToken'])) {
  151. $infocard = new Zend_InfoCard();
  152. $infocard->addCertificatePair('/usr/local/Zend/apache2/conf/server.key',
  153. '/usr/local/Zend/apache2/conf/server.crt');
  154. $claims = $infocard->process($_POST['xmlToken']);
  155. if($claims->isValid()) {
  156. print "Given Name: {$claims->givenname}<br />";
  157. print "Surname: {$claims->surname}<br />";
  158. print "Email Address: {$claims->emailaddress}<br />";
  159. print "PPI: {$claims->getCardID()}<br />";
  160. } else {
  161. print "Error Validating identity: {$claims->getErrorMsg()}";
  162. }
  163. }
  164. ?>
  165. <hr />
  166. <div id="login" style="font-family: arial; font-size: 2em;">
  167. <p>Simple Login Demo</p>
  168. <form method="post">
  169. <input type="submit" value="Login" />
  170. <object type="application/x-informationCard" name="xmlToken">
  171. <param name="tokenType"
  172. value="urn:oasis:names:tc:SAML:1.0:assertion" />
  173. <param name="requiredClaims"
  174. value="http://.../claims/givenname
  175. http://.../claims/surname
  176. http://.../claims/emailaddress
  177. http://.../claims/privatepersonalidentifier" />
  178. </object>
  179. </form>
  180. </div>
  181. ]]></programlisting>
  182. <para>
  183. In the example above, we use the <classname>Zend_InfoCard</classname> component
  184. independently to validate the token provided by the user. As was the
  185. case with the <classname>Zend_Auth_Adapter_InfoCard</classname>, we create an
  186. instance of <classname>Zend_InfoCard</classname> and then set one or more SSL
  187. certificate public/private key pairs used by the web server. Once
  188. configured, we can use the <code>process()</code> method to process
  189. the information card and return the results.
  190. </para>
  191. </sect2>
  192. <sect2 id="zend.infocard.basics.claims">
  193. <title>Working with a Claims object</title>
  194. <para>
  195. Regardless of whether the <classname>Zend_InfoCard</classname> component is used as
  196. a standalone component or as part of <classname>Zend_Auth</classname> via
  197. <classname>Zend_Auth_Adapter_InfoCard</classname>, the ultimate
  198. result of the processing of an information card is a
  199. <classname>Zend_InfoCard_Claims</classname> object. This object contains the
  200. assertions (a.k.a. claims) made by the submitting user based on the
  201. data requested by your web site when the user authenticated. As
  202. shown in the examples above, the validity of the information card
  203. can be ascertained by calling the
  204. <classname>Zend_InfoCard_Claims::isValid()</classname> method. Claims
  205. themselves can either be retrieved by simply accessing the
  206. identifier desired (i.e. <code>givenname</code>) as a property of
  207. the object or through the <code>getClaim()</code> method.
  208. </para>
  209. <para>
  210. In most cases you will never need to use the <code>getClaim()</code>
  211. method. However, if your <code>requiredClaims</code> mandate that
  212. you request claims from multiple different sources/namespaces then
  213. you will need to extract them explicitly using this method (simply
  214. pass it the full URI of the claim to retrieve its value from within
  215. the information card). Generally speaking however, the
  216. <classname>Zend_InfoCard</classname> component will set the default URI for
  217. claims to be the one used the most frequently within the information
  218. card itself and the simplified property-access method can be used.
  219. </para>
  220. <para>
  221. As part of the validation process, it is the developer's responsibility to
  222. examine the issuing source of the claims contained within the
  223. information card and to decide if that source is a trusted source of
  224. information. To do so, the <code>getIssuer()</code> method is
  225. provided within the <classname>Zend_InfoCard_Claims</classname> object which
  226. returns the URI of the issuer of the information card claims.
  227. </para>
  228. </sect2>
  229. <sect2 id="zend.infocard.basics.attaching">
  230. <title>Attaching Information Cards to existing accounts</title>
  231. <para>
  232. It is possible to add support for information cards to an existing
  233. authentication system by storing the private personal identifier
  234. (PPI) to a previously traditionally-authenticated account and
  235. including at least the
  236. <code>http://schemas.xmlsoap.org/ws/2005/05/identity/claims/privatepersonalidentifier</code>
  237. claim as part of the <code>requiredClaims</code> of the request. If
  238. this claim is requested then the <classname>Zend_InfoCard_Claims</classname>
  239. object will provide a unique identifier for the specific card that
  240. was submitted by calling the <code>getCardID()</code> method.
  241. </para>
  242. <para>
  243. An example of how to attach an information card to an existing
  244. traditional-authentication account is shown below:
  245. </para>
  246. <programlisting language="php"><![CDATA[
  247. // ...
  248. public function submitinfocardAction()
  249. {
  250. if (!isset($_REQUEST['xmlToken'])) {
  251. throw new ZBlog_Exception('Expected an encrypted token ' .
  252. 'but was not provided');
  253. }
  254. $infoCard = new Zend_InfoCard();
  255. $infoCard->addCertificatePair(SSL_CERTIFICATE_PRIVATE,
  256. SSL_CERTIFICATE_PUB);
  257. try {
  258. $claims = $infoCard->process($request['xmlToken']);
  259. } catch(Zend_InfoCard_Exception $e) {
  260. // TODO Error processing your request
  261. throw $e;
  262. }
  263. if ($claims->isValid()) {
  264. $db = ZBlog_Data::getAdapter();
  265. $ppi = $db->quote($claims->getCardID());
  266. $fullname = $db->quote("{$claims->givenname} {$claims->surname}");
  267. $query = "UPDATE blogusers
  268. SET ppi = $ppi,
  269. real_name = $fullname
  270. WHERE username='administrator'";
  271. try {
  272. $db->query($query);
  273. } catch(Exception $e) {
  274. // TODO Failed to store in DB
  275. }
  276. $this->view->render();
  277. return;
  278. } else {
  279. throw new
  280. ZBlog_Exception("Infomation card failed security checks");
  281. }
  282. }
  283. ]]></programlisting>
  284. </sect2>
  285. <sect2 id="zend.infocard.basics.adapters">
  286. <title>Creating Zend_InfoCard Adapters</title>
  287. <para>
  288. The <classname>Zend_InfoCard</classname> component was designed to allow for
  289. growth in the information card standard through the use of a modular
  290. architecture. At this time, many of these hooks are unused and can be
  291. ignored, but there is one class that should be written for
  292. any serious information card implementation: the
  293. <classname>Zend_InfoCard</classname> adapter.
  294. </para>
  295. <para>
  296. The <classname>Zend_InfoCard</classname> adapter is used as a callback
  297. mechanism within the component to perform various tasks, such as
  298. storing and retrieving Assertion IDs for information cards when they
  299. are processed by the component. While storing the assertion IDs of
  300. submitted information cards is not necessary, failing to do so opens
  301. up the possibility of the authentication scheme being compromised
  302. through a replay attack.
  303. </para>
  304. <para>
  305. To prevent this, one must implement the
  306. <classname>Zend_InfoCard_Adapter_Interface</classname> and set an
  307. instance of this interface prior to calling either the
  308. <code>process()</code> (standalone) or <code>authenticate()</code>
  309. method as a <classname>Zend_Auth</classname> adapter. To set this interface,
  310. the <code>setAdapter()</code> method should be used. In the example below,
  311. we set a <classname>Zend_InfoCard</classname> adapter and use it in our
  312. application:
  313. </para>
  314. <programlisting language="php"><![CDATA[
  315. class myAdapter implements Zend_InfoCard_Adapter_Interface
  316. {
  317. public function storeAssertion($assertionURI,
  318. $assertionID,
  319. $conditions)
  320. {
  321. /* Store the assertion and its conditions by ID and URI */
  322. }
  323. public function retrieveAssertion($assertionURI, $assertionID)
  324. {
  325. /* Retrieve the assertion by URI and ID */
  326. }
  327. public function removeAssertion($assertionURI, $assertionID)
  328. {
  329. /* Delete a given assertion by URI/ID */
  330. }
  331. }
  332. $adapter = new myAdapter();
  333. $infoCard = new Zend_InfoCard();
  334. $infoCard->addCertificatePair(SSL_PRIVATE, SSL_PUB);
  335. $infoCard->setAdapter($adapter);
  336. $claims = $infoCard->process($_POST['xmlToken']);
  337. ]]></programlisting>
  338. </sect2>
  339. </sect1>
  340. <!--
  341. vim:se ts=4 sw=4 et:
  342. -->