http://www.developer.com/

Back to article

Authenticating Users with OpenID and the Zend Framework


October 30, 2008

It goes without saying that the web is the single greatest communications medium ever devised. Bigger than the local newspaper. Bigger than TV. Bigger than radio. Heck, it's bigger than all three rolled into one, and one day each will be completely subsumed by this infinitely scalable and flexible new medium. Perhaps the primary reason we've seen such tremendous growth is the low barrier of entry. Armed with little more than a text editor, graphics software, and a hosting account, even novice developers can create impressive websites in a relatively short period of time.

This low barrier of entry has proved to be a bit of a double-edged sword. Because anyone, no matter their skill level, can build a website, many users have experienced a bit of the digital Wild West over the past 15 years, coming in the form of online robberies in the form of data theft, website hijackings, and even cyberbullying. There is, however, another significant side effect of the these heady growth stages, one which all of us experience on a daily basis, and one which I call the "passport effect."

The passport effect is the outgrowth of countless websites instituting their own authentication procedures, thereby requiring you to supply custom credentials to enter each website's territory. Some websites require you to supply an e-mail address; others would like you to come up with a contrived username. Some desire passwords consisting of a mix of uppercase and lowercase letters, while others do not allow special characters. Some allow you to recover your password simply by clicking on a link sent to your email address; others will do so only after you answer a host of questions about your first pet and favorite color. All of this contributes to a chaotic online environment in which users are constantly shuffling through their piles of "passports," regularly losing them, and generally becoming rather irritated over the whole process.

In this tutorial, I'll show you how to take advantage of a powerful open user identification service known as OpenID, and show you how to incorporate OpenID authentication and identification features into your Zend Framework-powered website. Even if you haven't started taking advantage of a web framework such as Zend's, this tutorial will serve two important purposes, demonstrating not only the allure of OpenID, but also how a framework such as the Zend Framework can greatly reduce development time.

Introducing OpenID

As mentioned, OpenID is a user identification service. More formally, it is an open source service that gives users control over their login information, rather than forcing them to repeatedly reenter and organize this information as they join new online services. Because the user manages his own login information (including data like the login password, name, and zip code), and uses that information to not only login to an OpenID-enabled website, but also to automatically populate profile fields that you've opted to share. What's more, is because OpenID accounts are identified by a URL, and subject to browser state, you don't have to be bothered with repeatedly entering a username and password as you move from one OpenID-enabled website to the next. Although not even four years old, OpenID is gaining quite a bit of traction among Internet heavyweights and startups alike, with Blogger, Plaxo, Yahoo! and SourceForge all offering OpenID-powered login options.

Creating an OpenID Account

Numerous online services have already started revamping their user authentication system to simultaneously act as an OpenID provider. Among them are AOL, Blogger, LiveJournal, Yahoo, and WordPress. For instance, if you blog on Blogger, your OpenID is blogname.blogspot.com, with blogname being whatever the corresponding name is for your blog. If you don't already happen to be using one of the aforementioned services, there are several options for creating your own OpenID. For instance, when making my initial investigations into OpenID, I created an identity at myOpenID (https://www.myopenid.com/), which is free and only takes a moment to do.

If you'd rather not leave third-party providers in charge of personal information, not to mention potentially allow them to track your online movements from one OpenID-enabled website to the next, you can even become your own provider with a bit of simple configuration. For instance, my OpenID URL is http://www.wjgilmore.com/, which also happens to serve the primary purpose of being my occasional blog. Noted open source and open standards developer Sam Ruby penned a great tutorial which explains how to do this, which you can read here.

Integrating OpenID Into Your Zend Framework-driven Website

If you've used the Zend Framework on even a simple project, chances are you took advantage of its Zend_Auth component, which greatly reduces the amount of coding you otherwise need to do to authenticate users and maintain authentication sessions. Among others, you can use it in conjunction with a variety of authentication solutions, such as LDAP, a database, or text files. But, unless you have particularly esoteric requirements, why force users to concoct yet another username and password when OpenID already serves that purpose? As you'll see, integrating OpenID into your Zend Framework-driven website is surprisingly easy, leaving you with little remaining reason not to do so.

Creating the Login Form

Let's begin with the simple task of creating the login form, shown in Figure 1. I incorporated the OpenID logo into the form, which they encourage you to do. Download the OpenID logo here.

Figure 1: The OpenID login form

Here's the code. For reasons of organization, I created a controller named LoginController.php, and within the /views/login/index.phtml I added the login form. This makes it possible for the user to log in by navigating to http://www.example.com/login/. Following the form, you'll check for the existence of a view variable ($this->success), and display an appropriate message based on the user's authentication success.

Listing 1: The login form

<form method="post" action="/login/">

   <img src="/images/openid-logo.gif" />&nbsp;
      <b>Login with OpenID!</b><br />
      <input type="text" name="openid_id" size="45" />

      <input type="submit" name="submit" value="Login" />
</form>

<?php if (! $this->success) { ?>

<p>
   Sorry, we could not authenticate you.
</p>
<?php } else { ?>
   Welcome to our website!
<?php } ?>

Creating the Login Code

Next up is the index method, found in the LoginController controller. This method is responsible for processing the authentication request, which takes place in two steps:

  1. Once the login form is posted, the Zend_OpenId_Consumer::login() method will seek out the address of the OpenID provider based on the address provided in the form. If found, an authentication request is prepared and sent to that provider.
  2. At this point, the authentication process is in the hands of the provider, which will prompt the user to provide his OpenID login and password if no session currently exists. Once complete, the request is routed back to the caller with the authentication status. The script can check this status, and determine what to do from there.

Listing 2: The Login controller's index method

/**
 *
 * Logs the user in to the website
 *
 */
public function indexAction()
{

   // If the login form has been posted, redirect the user to the
   // identified OpenID provider, allowing the user to complete
   // the authentication process
   if ($this->getRequest()->isPost()) {

      $consumer = new Zend_OpenId_Consumer();

      if (!$consumer->login($this->_request->
          getPost('openid_id'))) {
          die("OpenID login failed.");
      }

   // After the user authenticates, the OpenID server will redirect
   // the user back to the calling script, along with various
   // information confirming the user's identity (or lack thereof)
   } elseif ($this->_request->getParam('openid_mode') != "") {

      if ($this->_request->getParam('openid_mode') == "id_res") {

         $consumer = new Zend_OpenId_Consumer();
         if ($consumer->verify($_GET, $id)) {
            $this->view->success = TRUE;
         } else {
            $this->view->success = FALSE;
         }

      } elseif ($this->_request->getParam('openid_mode') ==
         "cancel") {
         $this->view->success = FALSE;
      }

   }

}

Retrieving the User's OpenID Profile

Once the user is successfully logged in, you can optionally retrieve profile information the user has identified as being shareable, for instance his zip code.

To retrieve data residing in the user's profile, you'll need to both declare your intent to do so within both steps of the authentication process (via both the Zend_OpenId_Consumer::login() and Zend_OpenId_Consumer::verify() methods). To begin, add this line to the script, above the isPost() method, because you'll need it for both steps:

$profile = new Zend_OpenId_Extension_Sreg(array(
   'postcode'=>true), null, 1.1);

Next, pass $profile into both the login() and verify() methods:

...
if (!$consumer->login($this->_request->getPost('openid_id'),
   null, null, $profile)) {
   die("OpenID login failed.");
}
...
if ($consumer->verify($_GET, $id, $profile)) {
...

Once the authentication request has been verified, you can call the getProperties() method to create an array containing the desired profile data:

$props = $profile->getProperties();
$this->view->zipcode = $props["postcode"];

Verifying Authentication and Logging the User Out

Of course, once authenticated you'll want to provide facilities for both transparently verifying authentication as the user moves from one part of the website to the next. This is done by creating an OpenID adapter that implements the Zend Framework's Auth adapter interface. It's surprisingly easy to do, and you'll find the code at the bottom of this page.

Where to From Here?

Integrating OpenID into your website removes a major hassle not only for users who have grown weary of keeping track of usernames and passwords, but also eliminates the need for you to write and maintain the code for dealing with tasks such as lost passwords. For further information, check out the following resources for more information about OpenID and the Zend Framework's implementation:

About the Author

Jason Gilmore is the founder of a Web development and consulting firm based out of Columbus, Ohio. Formerly Apress' open source editor, Jason fostered the development of more than 60 books, along the way helping to transform their open source line into one of the industry's most respected publishing programs. He's the author of several books, including the best-selling Beginning PHP and MySQL: From Novice to Professional (currently in its third edition), Beginning PHP and PostgreSQL: From Novice to Professional, and Beginning PHP and Oracle: From Novice to Professional.

Jason is cofounder of CodeMash, a nonprofit organization tasked with hosting an annual namesake developer's conference, and was a member of the 2008 MySQL Conference speaker selection board. Jason has over 100 articles to his credit within prominent publications such as Developer.com, Linux Magazine, and TechTarget.

Sitemap | Contact Us

Thanks for your registration, follow us on our social networks to keep up-to-date