| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830 |
- <?xml version="1.0" encoding="UTF-8"?>
- <!-- Reviewed: no -->
- <sect1 id="zend.openid.consumer">
- <title>Zend_OpenId_Consumer Basics</title>
- <para>
- <classname>Zend_OpenId_Consumer</classname> can be used to implement OpenID
- authentication for web sites.
- </para>
- <sect2 id="zend.openid.consumer.authentication">
- <title>OpenID Authentication</title>
- <para>
- From a web site developer's point of view, the OpenID authentication
- process consists of three steps:
- </para>
- <orderedlist>
- <listitem>
- <para>
- Show OpenID authentication form
- </para>
- </listitem>
- <listitem>
- <para>
- Accept OpenID identity and pass it to the OpenID provider
- </para>
- </listitem>
- <listitem>
- <para>
- Verify response from the OpenID provider
- </para>
- </listitem>
- </orderedlist>
- <para>
- The OpenID authentication protocol actually requires more
- steps, but many of them are encapsulated inside
- <classname>Zend_OpenId_Consumer</classname> and are therefore transparent to the
- developer.
- </para>
- <para>
- The end user initiates the OpenID authentication process by
- submitting his or her identification credentials with the appropriate form.
- The following example shows a simple form that accepts an OpenID
- identifier. Note that the example only demonstrates a login.
- </para>
- <example id="zend.openid.consumer.example-1">
- <title>The Simple OpenID Login form</title>
- <programlisting language="php"><![CDATA[
- <html><body>
- <form method="post" action="example-1_2.php"><fieldset>
- <legend>OpenID Login</legend>
- <input type="text" name="openid_identifier">
- <input type="submit" name="openid_action" value="login">
- </fieldset></form></body></html>
- ]]></programlisting>
- </example>
- <para>
- This form passes the OpenID identity on submission to the following
- <acronym>PHP</acronym> script that performs the second step of authentication. The
- <acronym>PHP</acronym> script need only call the
- <methodname>Zend_OpenId_Consumer::login()</methodname> method in this step. The first
- argument of this method is an accepted OpenID identity, and the second is the
- <acronym>URL</acronym> of a script that handles the third and last step of
- authentication.
- </para>
- <example id="zend.openid.consumer.example-1_2">
- <title>The Authentication Request Handler</title>
- <programlisting language="php"><![CDATA[
- $consumer = new Zend_OpenId_Consumer();
- if (!$consumer->login($_POST['openid_identifier'], 'example-1_3.php')) {
- die("OpenID login failed.");
- }
- ]]></programlisting>
- </example>
- <para>
- The <methodname>Zend_OpenId_Consumer::login()</methodname> method performs discovery on
- a given identifier, and, if successful, obtains the address of the identity
- provider and its local identifier. It then creates an association to the
- given provider so that both the site and provider share a secret
- that is used to sign the subsequent messages. Finally, it passes an
- authentication request to the provider. This request redirects the
- end user's web browser to an OpenID server site, where the user can
- continue the authentication process.
- </para>
- <para>
- An OpenID provider usually asks users for their password (if they
- weren't previously logged-in), whether the user trusts this site and what
- information may be returned to the site. These interactions are not
- visible to the OpenID consumer, so it can not obtain the
- user's password or other information that the user did not has not directed the
- OpenID provider to share with it.
- </para>
- <para>
- On success, <methodname>Zend_OpenId_Consumer::login()</methodname> does not
- return, instead performing an <acronym>HTTP</acronym> redirection. However, if there is
- an error it may return <constant>FALSE</constant>. Errors may occur due to an invalid
- identity, unresponsive provider, communication error, etc.
- </para>
- <para>
- The third step of authentication is initiated by the response from the
- OpenID provider, after it has authenticated the user's password.
- This response is passed indirectly, as an <acronym>HTTP</acronym> redirection using the
- end user's web browser. The consumer must now simply check
- that this response is valid.
- </para>
- <example id="zend.openid.consumer.example-1_3">
- <title>The Authentication Response Verifier</title>
- <programlisting language="php"><![CDATA[
- $consumer = new Zend_OpenId_Consumer();
- if ($consumer->verify($_GET, $id)) {
- echo "VALID " . htmlspecialchars($id);
- } else {
- echo "INVALID " . htmlspecialchars($id);
- }
- ]]></programlisting>
- </example>
- <para>
- This check is performed using the <classname>Zend_OpenId_Consumer::verify</classname>
- method, which takes an array of
- the <acronym>HTTP</acronym> request's arguments and checks that this response is
- properly signed by the OpenID provider. It may assign
- the claimed OpenID identity that was entered by end user in the
- first step using a second, optional argument.
- </para>
- </sect2>
- <sect2 id="zend.openid.consumer.combine">
- <title>Combining all Steps in One Page</title>
- <para>
- The following example combines all three steps in one script. It doesn't
- provide any new functionality. The advantage of using just one script is that
- the developer need not specify <acronym>URL</acronym>'s for a script to handle the next
- step. By default, all steps use the same <acronym>URL</acronym>. However, the script now
- includes some dispatch code to execute the appropriate code for each step of
- authentication.
- </para>
- <example id="zend.openid.consumer.example-2">
- <title>The Complete OpenID Login Script</title>
- <programlisting language="php"><![CDATA[
- <?php
- $status = "";
- if (isset($_POST['openid_action']) &&
- $_POST['openid_action'] == "login" &&
- !empty($_POST['openid_identifier'])) {
- $consumer = new Zend_OpenId_Consumer();
- if (!$consumer->login($_POST['openid_identifier'])) {
- $status = "OpenID login failed.";
- }
- } else if (isset($_GET['openid_mode'])) {
- if ($_GET['openid_mode'] == "id_res") {
- $consumer = new Zend_OpenId_Consumer();
- if ($consumer->verify($_GET, $id)) {
- $status = "VALID " . htmlspecialchars($id);
- } else {
- $status = "INVALID " . htmlspecialchars($id);
- }
- } else if ($_GET['openid_mode'] == "cancel") {
- $status = "CANCELLED";
- }
- }
- ?>
- <html><body>
- <?php echo "$status<br>" ?>
- <form method="post">
- <fieldset>
- <legend>OpenID Login</legend>
- <input type="text" name="openid_identifier" value=""/>
- <input type="submit" name="openid_action" value="login"/>
- </fieldset>
- </form>
- </body></html>
- ]]></programlisting>
- </example>
- <para>
- In addition, this code differentiates between cancelled and invalid
- authentication responses. The provider returns a cancelled response
- if the identity provider is not aware of the supplied identity, the user
- is not logged in, or the user doesn't trust the site. An invalid response indicates
- that the response is not conformant to the OpenID protocol or is incorrectly signed.
- </para>
- </sect2>
- <sect2 id="zend.openid.consumer.realm">
- <title>Consumer Realm</title>
- <para>
- When an OpenID-enabled site passes authentication requests to a
- provider, it identifies itself with a realm <acronym>URL</acronym>. This
- <acronym>URL</acronym> may be considered a root of a trusted site. If the user trusts
- the realm <acronym>URL</acronym>, he or she should also trust matched and subsequent
- <acronym>URL</acronym>s.
- </para>
- <para>
- By default, the realm <acronym>URL</acronym> is automatically set to the
- <acronym>URL</acronym> of the directory in which the login script resides. This default
- value is useful for most, but not all, cases. Sometimes an entire domain, and not a
- directory should be trusted. Or even a combination of several servers in one domain.
- </para>
- <para>
- To override the default value, developers may pass the realm <acronym>URL</acronym> as a
- third argument to the <classname>Zend_OpenId_Consumer::login</classname> method. In
- the following example, a single interaction asks for trusted access to
- all php.net sites.
- </para>
- <example id="zend.openid.consumer.example-3_2">
- <title>Authentication Request for Specified Realm</title>
- <programlisting language="php"><![CDATA[
- $consumer = new Zend_OpenId_Consumer();
- if (!$consumer->login($_POST['openid_identifier'],
- 'example-3_3.php',
- 'http://*.php.net/')) {
- die("OpenID login failed.");
- }
- ]]></programlisting>
- </example>
- <para>
- This example implements only the second step of authentication;
- the first and third steps are similar to the examples above.
- </para>
- </sect2>
- <sect2 id="zend.openid.consumer.check">
- <title>Immediate Check</title>
- <para>
- In some cases, an application need only check if a user is already
- logged in to a trusted OpenID server without any interaction with the
- user. The <classname>Zend_OpenId_Consumer::check</classname> method does precisely
- that. It is executed with the same arguments as
- <classname>Zend_OpenId_Consumer::login</classname>, but it doesn't display any
- OpenID server pages to the user. From the users point of view this process is
- transparent, and it appears as though they never left the site. The third step
- succeeds if the user is already logged in and trusted by the site, otherwise
- it will fail.
- </para>
- <example id="zend.openid.consumer.example-4">
- <title>Immediate Check without Interaction</title>
- <programlisting language="php"><![CDATA[
- $consumer = new Zend_OpenId_Consumer();
- if (!$consumer->check($_POST['openid_identifier'], 'example-4_3.php')) {
- die("OpenID login failed.");
- }
- ]]></programlisting>
- </example>
- <para>
- This example implements only the second step of authentication;
- the first and third steps are similar to the examples above.
- </para>
- </sect2>
- <sect2 id="zend.openid.consumer.storage">
- <title>Zend_OpenId_Consumer_Storage</title>
- <para>
- There are three steps in the OpenID authentication procedure, and each
- step is performed by a separate <acronym>HTTP</acronym> request. To store information
- between requests, <classname>Zend_OpenId_Consumer</classname> uses internal storage.
- </para>
- <para>
- Developers do not necessarily have to be aware of this storage because by default
- <classname>Zend_OpenId_Consumer</classname> uses file-based storage under the temporary
- directory- similar to <acronym>PHP</acronym> sessions. However, this storage may be not
- suitable in all cases. Some developers may want to store information in a database,
- while others may need to use common storage suitable for server farms. Fortunately,
- developers may easily replace the default storage with their own. To specify a custom
- storage mechanism, one need only extend the
- <classname>Zend_OpenId_Consumer_Storage</classname> class and pass this subclass to the
- <classname>Zend_OpenId_Consumer</classname> constructor in the first argument.
- </para>
- <para>
- The following example demonstrates a simple storage mechanism that uses
- <classname>Zend_Db</classname> as its backend and exposes three groups of functions.
- The first group contains functions for working with associations, while the second group
- caches discovery information, and the third group can be used to check whether a
- response is unique. This class can easily be used with existing or new databases; if the
- required tables don't exist, it will create them.
- </para>
- <example id="zend.openid.consumer.example-5">
- <title>Database Storage</title>
- <programlisting language="php"><![CDATA[
- class DbStorage extends Zend_OpenId_Consumer_Storage
- {
- private $_db;
- private $_association_table;
- private $_discovery_table;
- private $_nonce_table;
- // Pass in the Zend_Db_Adapter object and the names of the
- // required tables
- public function __construct($db,
- $association_table = "association",
- $discovery_table = "discovery",
- $nonce_table = "nonce")
- {
- $this->_db = $db;
- $this->_association_table = $association_table;
- $this->_discovery_table = $discovery_table;
- $this->_nonce_table = $nonce_table;
- $tables = $this->_db->listTables();
- // If the associations table doesn't exist, create it
- if (!in_array($association_table, $tables)) {
- $this->_db->getConnection()->exec(
- "create table $association_table (" .
- " url varchar(256) not null primary key," .
- " handle varchar(256) not null," .
- " macFunc char(16) not null," .
- " secret varchar(256) not null," .
- " expires timestamp" .
- ")");
- }
- // If the discovery table doesn't exist, create it
- if (!in_array($discovery_table, $tables)) {
- $this->_db->getConnection()->exec(
- "create table $discovery_table (" .
- " id varchar(256) not null primary key," .
- " realId varchar(256) not null," .
- " server varchar(256) not null," .
- " version float," .
- " expires timestamp" .
- ")");
- }
- // If the nonce table doesn't exist, create it
- if (!in_array($nonce_table, $tables)) {
- $this->_db->getConnection()->exec(
- "create table $nonce_table (" .
- " nonce varchar(256) not null primary key," .
- " created timestamp default current_timestamp" .
- ")");
- }
- }
- public function addAssociation($url,
- $handle,
- $macFunc,
- $secret,
- $expires)
- {
- $table = $this->_association_table;
- $secret = base64_encode($secret);
- $this->_db->insert($table, array(
- 'url' => $url,
- 'handle' => $handle,
- 'macFunc' => $macFunc,
- 'secret' => $secret,
- 'expires' => $expires,
- ));
- return true;
- }
- public function getAssociation($url,
- &$handle,
- &$macFunc,
- &$secret,
- &$expires)
- {
- $table = $this->_association_table;
- $this->_db->delete(
- $table, $this->_db->quoteInto('expires < ?', time())
- );
- $select = $this-_db->select()
- ->from($table, array('handle', 'macFunc', 'secret', 'expires'))
- ->where('url = ?', $url);
- $res = $this->_db->fetchRow($select);
- if (is_array($res)) {
- $handle = $res['handle'];
- $macFunc = $res['macFunc'];
- $secret = base64_decode($res['secret']);
- $expires = $res['expires'];
- return true;
- }
- return false;
- }
- public function getAssociationByHandle($handle,
- &$url,
- &$macFunc,
- &$secret,
- &$expires)
- {
- $table = $this->_association_table;
- $this->_db->delete(
- $table, $this->_db->quoteInto('expires < ', time())
- );
- $select = $this->_db->select()
- ->from($table, array('url', 'macFunc', 'secret', 'expires')
- ->where('handle = ?', $handle);
- $res = $select->fetchRow($select);
- if (is_array($res)) {
- $url = $res['url'];
- $macFunc = $res['macFunc'];
- $secret = base64_decode($res['secret']);
- $expires = $res['expires'];
- return true;
- }
- return false;
- }
- public function delAssociation($url)
- {
- $table = $this->_association_table;
- $this->_db->query("delete from $table where url = '$url'");
- return true;
- }
- public function addDiscoveryInfo($id,
- $realId,
- $server,
- $version,
- $expires)
- {
- $table = $this->_discovery_table;
- $this->_db->insert($table, array(
- 'id' => $id,
- 'realId' => $realId,
- 'server' => $server,
- 'version' => $version,
- 'expires' => $expires,
- ));
- return true;
- }
- public function getDiscoveryInfo($id,
- &$realId,
- &$server,
- &$version,
- &$expires)
- {
- $table = $this->_discovery_table;
- $this->_db->delete($table, $this->quoteInto('expires < ?', time()));
- $select = $this->_db->select()
- ->from($table, array('realId', 'server', 'version', 'expires'))
- ->where('id = ?', $id);
- $res = $this->_db->fetchRow($select);
- if (is_array($res)) {
- $realId = $res['realId'];
- $server = $res['server'];
- $version = $res['version'];
- $expires = $res['expires'];
- return true;
- }
- return false;
- }
- public function delDiscoveryInfo($id)
- {
- $table = $this->_discovery_table;
- $this->_db->delete($table, $this->_db->quoteInto('id = ?', $id));
- return true;
- }
- public function isUniqueNonce($nonce)
- {
- $table = $this->_nonce_table;
- try {
- $ret = $this->_db->insert($table, array(
- 'nonce' => $nonce,
- ));
- } catch (Zend_Db_Statement_Exception $e) {
- return false;
- }
- return true;
- }
- public function purgeNonces($date=null)
- {
- }
- }
- $db = Zend_Db::factory('Pdo_Sqlite',
- array('dbname'=>'/tmp/openid_consumer.db'));
- $storage = new DbStorage($db);
- $consumer = new Zend_OpenId_Consumer($storage);
- ]]></programlisting>
- </example>
- <para>
- This example doesn't list the OpenID authentication code itself, but this
- code would be the same as that for other examples in this chapter.
- examples.
- </para>
- </sect2>
- <sect2 id="zend.openid.consumer.sreg">
- <title>Simple Registration Extension</title>
- <para>
- In addition to authentication, the OpenID standard can be used for
- lightweight profile exchange to make information about a user portable across multiple
- sites. This feature is not covered by the OpenID authentication specification, but by
- the OpenID Simple Registration Extension protocol. This protocol allows OpenID-enabled
- sites to ask for information about end users from OpenID providers. Such information may
- include:
- </para>
- <itemizedlist>
- <listitem>
- <para>
- <emphasis>nickname</emphasis>
- - any UTF-8 string that the end user uses as a nickname
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis>email</emphasis>
- - the email address of the user as specified in section 3.4.1
- of RFC2822
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis>fullname</emphasis>
- - a UTF-8 string representation of the user's full name
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis>dob</emphasis>
- - the user's date of birth in the format 'YYYY-MM-DD'. Any values whose
- representation uses fewer than the specified number of digits in this format
- should be zero-padded. In other words, the length of this value must always be
- 10. If the end user does not want to reveal any particular
- part of this value (i.e., year, month or day), it must be set to zero. For
- example, if the user wants to specify that his date of birth falls in 1980,
- but not specify the month or day, the value returned should be '1980-00-00'.
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis>gender</emphasis>
- - the user's gender: "M" for male, "F" for female
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis>postcode</emphasis>
- - a UTF-8 string that conforms to the postal system of the user's country
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis>country</emphasis>
- - the user's country of residence as specified by ISO3166
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis>language</emphasis>
- - the user's preferred language as specified by ISO639
- </para>
- </listitem>
- <listitem>
- <para>
- <emphasis>timezone</emphasis>
- - an <acronym>ASCII</acronym> string from a TimeZone database. For example,
- "Europe/Paris" or "America/Los_Angeles".
- </para>
- </listitem>
- </itemizedlist>
- <para>
- An OpenID-enabled web site may ask for any combination of these
- fields. It may also strictly require some information and allow users
- to provide or hide additional information. The following example instantiates
- the <classname>Zend_OpenId_Extension_Sreg</classname> class, requiring
- a <emphasis>nickname</emphasis> and optionally requests
- an <emphasis>email</emphasis> and a <emphasis>fullname</emphasis>.
- </para>
- <example id="zend.openid.consumer.example-6_2">
- <title>Sending Requests with a Simple Registration Extension</title>
- <programlisting language="php"><![CDATA[
- $sreg = new Zend_OpenId_Extension_Sreg(array(
- 'nickname'=>true,
- 'email'=>false,
- 'fullname'=>false), null, 1.1);
- $consumer = new Zend_OpenId_Consumer();
- if (!$consumer->login($_POST['openid_identifier'],
- 'example-6_3.php',
- null,
- $sreg)) {
- die("OpenID login failed.");
- }
- ]]></programlisting>
- </example>
- <para>
- As you can see, the <classname>Zend_OpenId_Extension_Sreg</classname>
- constructor accepts an array of OpenID fields. This array has the names of
- fields as indexes to a flag indicating whether the field is required;
- <constant>TRUE</constant> means the field is required and
- <constant>FALSE</constant> means the field is optional. The
- <classname>Zend_OpenId_Consumer::login</classname> method accepts an extension or an
- array of extensions as its fourth argument.
- </para>
- <para>
- On the third step of authentication, the
- <classname>Zend_OpenId_Extension_Sreg</classname> object should be passed to
- <classname>Zend_OpenId_Consumer::verify</classname>. Then on successful authentication
- the <classname>Zend_OpenId_Extension_Sreg::getProperties</classname> method will return
- an associative array of requested fields.
- </para>
- <example id="zend.openid.consumer.example-6_3">
- <title>Verifying Responses with a Simple Registration Extension</title>
- <programlisting language="php"><![CDATA[
- $sreg = new Zend_OpenId_Extension_Sreg(array(
- 'nickname'=>true,
- 'email'=>false,
- 'fullname'=>false), null, 1.1);
- $consumer = new Zend_OpenId_Consumer();
- if ($consumer->verify($_GET, $id, $sreg)) {
- echo "VALID " . htmlspecialchars($id) ."<br>\n";
- $data = $sreg->getProperties();
- if (isset($data['nickname'])) {
- echo "nickname: " . htmlspecialchars($data['nickname']) . "<br>\n";
- }
- if (isset($data['email'])) {
- echo "email: " . htmlspecialchars($data['email']) . "<br>\n";
- }
- if (isset($data['fullname'])) {
- echo "fullname: " . htmlspecialchars($data['fullname']) . "<br>\n";
- }
- } else {
- echo "INVALID " . htmlspecialchars($id);
- }
- ]]></programlisting>
- </example>
- <para>
- If the <classname>Zend_OpenId_Extension_Sreg</classname> object was created without any
- arguments, the user code should check for the existence of the required
- data itself. However, if the object is created with the same list of
- required fields as on the second step, it will automatically check for the existence
- of required data. In this case, <classname>Zend_OpenId_Consumer::verify</classname>
- will return <constant>FALSE</constant> if any of the required fields are
- missing.
- </para>
- <para>
- <classname>Zend_OpenId_Extension_Sreg</classname> uses version
- 1.0 by default, because the specification for version 1.1 is not yet finalized.
- However, some libraries don't fully support version 1.0. For example,
- www.myopenid.com requires an SREG namespace in requests which is only
- available in 1.1. To work with such a server, you must explicitly set the version to
- 1.1 in the <classname>Zend_OpenId_Extension_Sreg</classname> constructor.
- </para>
- <para>
- The second argument of the <classname>Zend_OpenId_Extension_Sreg</classname>
- constructor is a policy <acronym>URL</acronym>, that should be provided to the user by
- the identity provider.
- </para>
- </sect2>
- <sect2 id="zend.openid.consumer.auth">
- <title>Integration with Zend_Auth</title>
- <para>
- Zend Framework provides a special class to support user
- authentication: <classname>Zend_Auth</classname>. This class can be used together
- with <classname>Zend_OpenId_Consumer</classname>. The following example shows how
- <classname>OpenIdAdapter</classname> implements
- the <classname>Zend_Auth_Adapter_Interface</classname> with the
- <methodname>authenticate()</methodname> method. This performs an authentication query
- and verification.
- </para>
- <para>
- The big difference between this adapter and existing ones, is that
- it works on two <acronym>HTTP</acronym> requests and includes a dispatch code to perform
- the second or third step of OpenID authentication.
- </para>
- <example id="zend.openid.consumer.example-7">
- <title>Zend_Auth Adapter for OpenID</title>
- <programlisting language="php"><![CDATA[
- <?php
- class OpenIdAdapter implements Zend_Auth_Adapter_Interface {
- private $_id = null;
- public function __construct($id = null) {
- $this->_id = $id;
- }
- public function authenticate() {
- $id = $this->_id;
- if (!empty($id)) {
- $consumer = new Zend_OpenId_Consumer();
- if (!$consumer->login($id)) {
- $ret = false;
- $msg = "Authentication failed.";
- }
- } else {
- $consumer = new Zend_OpenId_Consumer();
- if ($consumer->verify($_GET, $id)) {
- $ret = true;
- $msg = "Authentication successful";
- } else {
- $ret = false;
- $msg = "Authentication failed";
- }
- }
- return new Zend_Auth_Result($ret, $id, array($msg));
- }
- }
- $status = "";
- $auth = Zend_Auth::getInstance();
- if ((isset($_POST['openid_action']) &&
- $_POST['openid_action'] == "login" &&
- !empty($_POST['openid_identifier'])) ||
- isset($_GET['openid_mode'])) {
- $adapter = new OpenIdAdapter(@$_POST['openid_identifier']);
- $result = $auth->authenticate($adapter);
- if ($result->isValid()) {
- Zend_OpenId::redirect(Zend_OpenId::selfURL());
- } else {
- $auth->clearIdentity();
- foreach ($result->getMessages() as $message) {
- $status .= "$message<br>\n";
- }
- }
- } else if ($auth->hasIdentity()) {
- if (isset($_POST['openid_action']) &&
- $_POST['openid_action'] == "logout") {
- $auth->clearIdentity();
- } else {
- $status = "You are logged in as " . $auth->getIdentity() . "<br>\n";
- }
- }
- ?>
- <html><body>
- <?php echo htmlspecialchars($status);?>
- <form method="post"><fieldset>
- <legend>OpenID Login</legend>
- <input type="text" name="openid_identifier" value="">
- <input type="submit" name="openid_action" value="login">
- <input type="submit" name="openid_action" value="logout">
- </fieldset></form></body></html>
- ]]></programlisting>
- </example>
- <para>
- With <classname>Zend_Auth</classname> the end-user's identity is saved in the
- session's data. It may be checked with <classname>Zend_Auth::hasIdentity</classname>
- and <classname>Zend_Auth::getIdentity</classname>.
- </para>
- </sect2>
- <sect2 id="zend.openid.consumer.mvc">
- <title>Integration with Zend_Controller</title>
- <para>
- Finally a couple of words about integration into
- Model-View-Controller applications: such Zend Framework applications are
- implemented using the <classname>Zend_Controller</classname> class and they use
- objects of the <classname>Zend_Controller_Response_Http</classname> class to prepare
- <acronym>HTTP</acronym> responses and send them back to the user's web browser.
- </para>
- <para>
- <classname>Zend_OpenId_Consumer</classname> doesn't provide any GUI
- capabilities but it performs <acronym>HTTP</acronym> redirections on success of
- <classname>Zend_OpenId_Consumer::login</classname> and
- <classname>Zend_OpenId_Consumer::check</classname>. These redirections may work
- incorrectly or not at all if some data was already sent to the web browser. To
- properly perform <acronym>HTTP</acronym> redirection in <acronym>MVC</acronym> code the
- real <classname>Zend_Controller_Response_Http</classname> should be sent to
- <classname>Zend_OpenId_Consumer::login</classname> or
- <classname>Zend_OpenId_Consumer::check</classname> as the last argument.
- </para>
- </sect2>
- </sect1>
- <!--
- vim:se ts=4 sw=4 et:
- -->
|