Zend_InfoCard-Basics.xml 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392
  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 <acronym>HTML</acronym> block in your
  24. <acronym>HTML</acronym> 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 <property>requiredClaims</property>
  43. &lt;param&gt; tag is used to identify pieces of information known as claims (i.e.
  44. person's first name, last name) which the web site (a.k.a "relying party") needs in
  45. order a user to authenticate using an information card. For your reference, the full
  46. <acronym>URI</acronym> (for instance the <emphasis>givenname</emphasis> claim) is as
  47. follows:
  48. <filename>http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname</filename>
  49. </para>
  50. <para>
  51. When the above <acronym>HTML</acronym> 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 <acronym>XML</acronym>
  56. document to the specified POST <acronym>URL</acronym> 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 <acronym>HTTP</acronym> <acronym>POST</acronym>ed to
  61. <acronym>SSL</acronym>-encrypted <acronym>URL</acronym>s. Please consult your web
  62. server's documentation on how to set up <acronym>SSL</acronym> 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 <acronym>XML</acronym>
  125. data posted by the card selector into it. Once an instance has been created you
  126. must then provide at least one <acronym>SSL</acronym> certificate public/private key
  127. pair used by the web server that received the <acronym>HTTP</acronym>
  128. <acronym>POST</acronym>. These files are used to validate the destination of the
  129. information posted to the server and are a requirement when using Information Cards.
  130. </para>
  131. <para>
  132. Once the adapter has been configured, you can then use the standard
  133. <classname>Zend_Auth</classname> facilities to validate the provided
  134. information card token and authenticate the user by examining the
  135. identity provided by the <methodname>getIdentity()</methodname> method.
  136. </para>
  137. </sect2>
  138. <sect2 id="zend.infocard.basics.standalone">
  139. <title>Using the Zend_InfoCard component standalone</title>
  140. <para>
  141. It is also possible to use the <classname>Zend_InfoCard</classname> component as a
  142. standalone component by interacting with the
  143. <classname>Zend_InfoCard</classname> class directly. Using the
  144. <classname>Zend_InfoCard</classname> class is very similar to its use with the
  145. <classname>Zend_Auth</classname> component. An example of its use is shown below:
  146. </para>
  147. <programlisting language="php"><![CDATA[
  148. <?php
  149. if (isset($_POST['xmlToken'])) {
  150. $infocard = new Zend_InfoCard();
  151. $infocard->addCertificatePair('/usr/local/Zend/apache2/conf/server.key',
  152. '/usr/local/Zend/apache2/conf/server.crt');
  153. $claims = $infocard->process($_POST['xmlToken']);
  154. if($claims->isValid()) {
  155. print "Given Name: {$claims->givenname}<br />";
  156. print "Surname: {$claims->surname}<br />";
  157. print "Email Address: {$claims->emailaddress}<br />";
  158. print "PPI: {$claims->getCardID()}<br />";
  159. } else {
  160. print "Error Validating identity: {$claims->getErrorMsg()}";
  161. }
  162. }
  163. ?>
  164. <hr />
  165. <div id="login" style="font-family: arial; font-size: 2em;">
  166. <p>Simple Login Demo</p>
  167. <form method="post">
  168. <input type="submit" value="Login" />
  169. <object type="application/x-informationCard" name="xmlToken">
  170. <param name="tokenType"
  171. value="urn:oasis:names:tc:SAML:1.0:assertion" />
  172. <param name="requiredClaims"
  173. value="http://.../claims/givenname
  174. http://.../claims/surname
  175. http://.../claims/emailaddress
  176. http://.../claims/privatepersonalidentifier" />
  177. </object>
  178. </form>
  179. </div>
  180. ]]></programlisting>
  181. <para>
  182. In the example above, we use the <classname>Zend_InfoCard</classname> component
  183. independently to validate the token provided by the user. As was the
  184. case with the <classname>Zend_Auth_Adapter_InfoCard</classname>, we create an
  185. instance of <classname>Zend_InfoCard</classname> and then set one or more
  186. <acronym>SSL</acronym> certificate public/private key pairs used by the web server. Once
  187. configured, we can use the <methodname>process()</methodname> method to process
  188. the information card and return the results.
  189. </para>
  190. </sect2>
  191. <sect2 id="zend.infocard.basics.claims">
  192. <title>Working with a Claims object</title>
  193. <para>
  194. Regardless of whether the <classname>Zend_InfoCard</classname> component is used as
  195. a standalone component or as part of <classname>Zend_Auth</classname> via
  196. <classname>Zend_Auth_Adapter_InfoCard</classname>, the ultimate
  197. result of the processing of an information card is a
  198. <classname>Zend_InfoCard_Claims</classname> object. This object contains the
  199. assertions (a.k.a. claims) made by the submitting user based on the
  200. data requested by your web site when the user authenticated. As
  201. shown in the examples above, the validity of the information card
  202. can be ascertained by calling the
  203. <methodname>Zend_InfoCard_Claims::isValid()</methodname> method. Claims
  204. themselves can either be retrieved by simply accessing the
  205. identifier desired (i.e. <property>givenname</property>) as a property of
  206. the object or through the <methodname>getClaim()</methodname> method.
  207. </para>
  208. <para>
  209. In most cases you will never need to use the <methodname>getClaim()</methodname>
  210. method. However, if your <property>requiredClaims</property> mandate that
  211. you request claims from multiple different sources/namespaces then
  212. you will need to extract them explicitly using this method (simply
  213. pass it the full <acronym>URI</acronym> of the claim to retrieve its value from within
  214. the information card). Generally speaking however, the
  215. <classname>Zend_InfoCard</classname> component will set the default
  216. <acronym>URI</acronym> for claims to be the one used the most frequently within the
  217. information card itself and the simplified property-access method can be used.
  218. </para>
  219. <para>
  220. As part of the validation process, it is the developer's responsibility to
  221. examine the issuing source of the claims contained within the
  222. information card and to decide if that source is a trusted source of
  223. information. To do so, the <methodname>getIssuer()</methodname> method is
  224. provided within the <classname>Zend_InfoCard_Claims</classname> object which
  225. returns the <acronym>URI</acronym> of the issuer of the information card claims.
  226. </para>
  227. </sect2>
  228. <sect2 id="zend.infocard.basics.attaching">
  229. <title>Attaching Information Cards to existing accounts</title>
  230. <para>
  231. It is possible to add support for information cards to an existing
  232. authentication system by storing the private personal identifier
  233. (PPI) to a previously traditionally-authenticated account and
  234. including at least the
  235. <filename>http://schemas.xmlsoap.org/ws/2005/05/identity/claims/privatepersonalidentifier</filename>
  236. claim as part of the <property>requiredClaims</property> of the request. If
  237. this claim is requested then the <classname>Zend_InfoCard_Claims</classname>
  238. object will provide a unique identifier for the specific card that
  239. was submitted by calling the <methodname>getCardID()</methodname> method.
  240. </para>
  241. <para>
  242. An example of how to attach an information card to an existing
  243. traditional-authentication account is shown below:
  244. </para>
  245. <programlisting language="php"><![CDATA[
  246. // ...
  247. public function submitinfocardAction()
  248. {
  249. if (!isset($_REQUEST['xmlToken'])) {
  250. throw new ZBlog_Exception('Expected an encrypted token ' .
  251. 'but was not provided');
  252. }
  253. $infoCard = new Zend_InfoCard();
  254. $infoCard->addCertificatePair(SSL_CERTIFICATE_PRIVATE,
  255. SSL_CERTIFICATE_PUB);
  256. try {
  257. $claims = $infoCard->process($request['xmlToken']);
  258. } catch(Zend_InfoCard_Exception $e) {
  259. // TODO Error processing your request
  260. throw $e;
  261. }
  262. if ($claims->isValid()) {
  263. $db = ZBlog_Data::getAdapter();
  264. $ppi = $db->quote($claims->getCardID());
  265. $fullname = $db->quote("{$claims->givenname} {$claims->surname}");
  266. $query = "UPDATE blogusers
  267. SET ppi = $ppi,
  268. real_name = $fullname
  269. WHERE username='administrator'";
  270. try {
  271. $db->query($query);
  272. } catch(Exception $e) {
  273. // TODO Failed to store in DB
  274. }
  275. $this->view->render();
  276. return;
  277. } else {
  278. throw new
  279. ZBlog_Exception("Infomation card failed security checks");
  280. }
  281. }
  282. ]]></programlisting>
  283. </sect2>
  284. <sect2 id="zend.infocard.basics.adapters">
  285. <title>Creating Zend_InfoCard Adapters</title>
  286. <para>
  287. The <classname>Zend_InfoCard</classname> component was designed to allow for
  288. growth in the information card standard through the use of a modular
  289. architecture. At this time, many of these hooks are unused and can be
  290. ignored, but there is one class that should be written for
  291. any serious information card implementation: the
  292. <classname>Zend_InfoCard</classname> adapter.
  293. </para>
  294. <para>
  295. The <classname>Zend_InfoCard</classname> adapter is used as a callback
  296. mechanism within the component to perform various tasks, such as
  297. storing and retrieving Assertion IDs for information cards when they
  298. are processed by the component. While storing the assertion IDs of
  299. submitted information cards is not necessary, failing to do so opens
  300. up the possibility of the authentication scheme being compromised
  301. through a replay attack.
  302. </para>
  303. <para>
  304. To prevent this, one must implement the
  305. <classname>Zend_InfoCard_Adapter_Interface</classname> and set an
  306. instance of this interface prior to calling either the
  307. <methodname>process()</methodname> (standalone) or
  308. <methodname>authenticate()</methodname> method as a <classname>Zend_Auth</classname>
  309. adapter. To set this interface, the <methodname>setAdapter()</methodname> method should
  310. be used. In the example below, we set a <classname>Zend_InfoCard</classname> adapter and
  311. use it in our application:
  312. </para>
  313. <programlisting language="php"><![CDATA[
  314. class myAdapter implements Zend_InfoCard_Adapter_Interface
  315. {
  316. public function storeAssertion($assertionURI,
  317. $assertionID,
  318. $conditions)
  319. {
  320. /* Store the assertion and its conditions by ID and URI */
  321. }
  322. public function retrieveAssertion($assertionURI, $assertionID)
  323. {
  324. /* Retrieve the assertion by URI and ID */
  325. }
  326. public function removeAssertion($assertionURI, $assertionID)
  327. {
  328. /* Delete a given assertion by URI/ID */
  329. }
  330. }
  331. $adapter = new myAdapter();
  332. $infoCard = new Zend_InfoCard();
  333. $infoCard->addCertificatePair(SSL_PRIVATE, SSL_PUB);
  334. $infoCard->setAdapter($adapter);
  335. $claims = $infoCard->process($_POST['xmlToken']);
  336. ]]></programlisting>
  337. </sect2>
  338. </sect1>
  339. <!--
  340. vim:se ts=4 sw=4 et:
  341. -->