Authentication with Zend_Auth in Zend Framework 1.8

0
101
6 min read

Let’s get started.

Authentication versus Authorization

Before we go any further, we need to first look at what exactly authentication and authorization is, as they are often misunderstood.

Authorization is the process of allowing someone or something to actually do something. For example, if I go into a data centre, then the security guards control my authorization to the data centre and would, for instance, not allow me access to the server room if I was just a visitor but would if I worked there as a system admin.

Authentication is the process of confirming someone or something’s identity. For example, when I go to into the data centre the security guards will ask me for my identity, which most probably would be a card with my name and photo on. They use this to authenticate my identity.

These concepts are very important so make sure you understand the difference. This is how I remember them:

Authorization: Can they do this?
Authentication: Are they who they say they are?

Authentication with Zend_Auth

To provide our authentication layer, we are going to use Zend_Auth. It provides an easy way to authenticate a request, obtain a result, and then store the identity of that authentication request.

Zend_Auth

Zend_Auth has three main areas—authentication adapters, authentication results, and identity persistence.

Authentication adapters

Authentication adapters work in a similar way to database adapters. We configure the adapter and then pass it to the Zend_Auth instance, which then uses it to authenticate the request.

The following concrete adapters are provided by default:

  • HTTP Digest authentication
  • HTTP Basic authentication
  • Database Table authentication
  • LDAP authentication
  • OpenID authentication
  • InfoCard authentication

All of these adapters implement the Zend_Auth_Adapter_Interface, meaning we can create our own adapters by implementing this interface.

Authentication results

All authentication adapters return a Zend_Auth_Result instance, which stores the result of the authentication request. The stored data includes whether the authentication request was successful, an identity if the request was successful, and any failure messages, if unsuccessful.

Identity persistence

The default persistence used is the PHP session. It uses Zend_Session_Namespace to store the identity information in the Zend_Auth namespace. There is one other type of storage available named NonPersistent, which is used for HTTP authentication. We can also create our own storage by implementing the Zend_Auth_Storage_Interface.

Authentication Service

We are going to create an Authentication Service that will handle authentication requests. We are using a service to keep the authentication logic away from our User Model. Let’s create this class now:

application/modules/storefront/services/Authentication.php
class Storefront_Service_Authentication
{
protected $_authAdapter;
protected $_userModel;
protected $_auth;
public function __construct(Storefront_Model_User
$userModel = null)
{
$this->_userModel = null === $userModel ?
new Storefront_Model_User() : $userModel;
}
public function authenticate($credentials)
{
$adapter = $this->getAuthAdapter($credentials);
$auth = $this->getAuth();
$result = $auth->authenticate($adapter);
if (!$result->isValid()) {
return false;
}
$user = $this->_userModel
->getUserByEmail($credentials['email']);
$auth->getStorage()->write($user);
return true;
}
public function getAuth()
{
if (null === $this->_auth) {
$this->_auth = Zend_Auth::getInstance();
}
return $this->_auth;
}
public function getIdentity()
{
$auth = $this->getAuth();
if ($auth->hasIdentity()) {
return $auth->getIdentity();
}
return false;
}
public function clear()
{
$this->getAuth()->clearIdentity();
}
public function setAuthAdapter(Zend_Auth_Adapter_Interface
$adapter)
{
$this->_authAdapter = $adapter;
}
public function getAuthAdapter($values)
{
if (null === $this->_authAdapter) {
$authAdapter = new Zend_Auth_Adapter_DbTable(
Zend_Db_Table_Abstract::getDefaultAdapter(),
'user',
'email',
'passwd'
);
$this->setAuthAdapter($authAdapter);
$this->_authAdapter
->setIdentity($values['email']);
$this->_authAdapter
->setCredential($values['passwd']);
$this->_authAdapter
->setCredentialTreatment(
'SHA1(CONCAT(?,salt))'
);
}
return $this->_authAdapter;
}
}

The Authentication Service contains the following methods:

  • __constuct: Creates or sets the User Model instance
  • authenticate: Processes the authentication request
  • getAuth: Returns the Zend_Auth instance
  • getIdentity: Returns the stored identity
  • clear: Clears the identity (log out)
  • setAuthAdapter: Sets the authentication adapter to use
  • getAuthAdapter: Returns the authentication adapter

The Service is really separated into three areas. They are getting the Zend_Auth instance, configuring the adapter, and authenticating the request using Zend_Auth and the Adapter.

To get the Zend_Auth instance, we have the getAuth() method. This method retrieves the singleton Zend_Auth instance and sets it on the $_auth property. It is important to remember that Zend_Auth is a singleton class, meaning that there can only ever be one instance of it.

To configure the adapter, we have the getAuthAdapter() method. By default, we are going to use the Zend_Auth_Adapter_DbTable adapter to authenticate the request. However, we can also override this by setting another adapter using the setAuthAdapter() method. This is useful for adding authenticate strategies and testing. The configuration of the DbTable adapter is important here, so let’s have a look at that code:

$authAdapter = new Zend_Auth_Adapter_DbTable(
Zend_Db_Table_Abstract::getDefaultAdapter(),
'user',
'email',
'passwd',
'SHA1(CONCAT(?,salt))'
);
$this->setAuthAdapter($authAdapter);
$this->_authAdapter->setIdentity($values['email']);
$this->_authAdapter->setCredential($values['passwd']);

The Zend_Auth_Adapter_DbTable constructor accepts five parameters. They are database adapter, database table, table name, identity column, and credential treatment. For our adapter, we supply the default database adapter for our table classes using the getDefaultAdapter() method, the user table, the email column, the passwd column, and the encryption and salting SQL for the password. Once we have our configured adapter, we set the identity and credential properties. These will then be used during authentication.

To authenticate the request, we use the authenticate method.

$adapter = $this->getAuthAdapter($credentials);
$auth = $this->getAuth();
$result = $auth->authenticate($adapter);
if (!$result->isValid()) {
return false;
}
$user = $this->_userModel
->getUserByEmail($credentials[’email’]);
$auth->getStorage()->write($user);
return true;

Here we first get the configured adapter, get the Zend_Auth instance, and then fetch the result using Zend_Auth’s authenticate method, while passing in the configured adapter. We then check that the authentication request was successful using the isValid() method. At this point, we can also choose to handle different kinds of failures using the getCode() method. This will return one of the following constants:

Zend_Auth_Result::SUCCESS
Zend_Auth_Result::FAILURE
Zend_Auth_Result::FAILURE_IDENTITY_NOT_FOUND
Zend_Auth_Result::FAILURE_IDENTITY_AMBIGUOUS
Zend_Auth_Result::FAILURE_CREDENTIAL_INVALID
Zend_Auth_Result::FAILURE_UNCATEGORIZED

By using these, we could switch and handle each error in a different way. However, for our purposes, this is not necessary.

If the authentication request was successful, we then retrieve a Storefront_Resource_User_Item instance from the User Model and then write this object to Zend_Auth’s persistence layer by getting the storage instance using  getStorage() and writing to it using write(). This will then store the user in the session so that we can retrieve the user information throughout the session.

Our Authentication Service is now complete, and we can start using it to create a login system for the Storefront.



Subscribe to the weekly Packt Hub newsletter

* indicates required

LEAVE A REPLY

Please enter your comment!
Please enter your name here