Using Pear Auth As Zend Auth Adapter

Using Pear Auth As Zend Auth Adapter

July 15, 2009

If you use both Pear and Zend framework you may want to extend the Zend_Auth adapters to use all the containers shipped with the Pear::Auth package.

Let’s go to create the class implements the Zend_Auth_Adapter_Interface starting from the Zend_Auth_Adapter_Ldap class.

My_Zend_Auth_Adapter_PearAuth

<?php

class My_Zend_Auth_Adapter_PearAuth implements Zend_Auth_Adapter_Interface
{

    /**
     * The array of arrays of Pear::Auth options passed to the constructor.
     *
     * @var array
     */
    protected $_options = null;

    /**
     * The username of the account being authenticated.
     *
     * @var string
     */
    protected $_username = null;

    /**
     * The password of the account being authenticated.
     *
     * @var string
     */
    protected $_password = null;

    /**
     * The Pear::Auth container.
     *
     * @var string
     */
    protected $_container = null;

    protected $_logger = null;

    /**
     * Constructor
     *
     * @param  string $container The Pear::Auth container to use
     * @param  array $options An array of arrays of Pear::Auth options
     * @param  string $username The username of the account being authenticated
     * @param  string $password The password of the account being authenticated
     * @return void
     */
    public function __construct($container, array $options = array(), $username = null, $password = null)
    {
        $this->setOptions($options);
        if ($username !== null) {
            $this->setUsername($username);
        }
        if ($password !== null) {
            $this->setPassword($password);
        }
        $this->_container = $container;
    }

    public function setLogger($logger)
    {
        $this->_logger = $logger;
    }

    /**
     * Returns the array of arrays of Pear::Auth options.
     *
     * @return array|null
     */
    public function getOptions()
    {
        return $this->_options;
    }

    /**
     * Sets the array of arrays of Pear::Auth options to be used by
     * this adapter.
     *
     * @param  array $options The array of arrays of of Pear::Auth options
     * @return My_Zend_Auth_Adapter_PearAuth Provides a fluent interface
     */
    public function setOptions($options)
    {
        $this->_options = is_array($options) ? $options : array();
        return $this;
    }

    /**
     * Returns the username of the account being authenticated, or
     * NULL if none is set.
     *
     * @return string|null
     */
    public function getUsername()
    {
        return $this->_username;
    }

    /**
     * Sets the username for binding
     *
     * @param  string $username The username for binding
     * @return My_Zend_Auth_Adapter_PearAuth Provides a fluent interface
     */
    public function setUsername($username)
    {
        $this->_username = (string)$username;
        return $this;
    }

    /**
     * Returns the password of the account being authenticated, or
     * NULL if none is set.
     *
     * @return string|null
     */
    public function getPassword()
    {
        return $this->_password;
    }

    /**
     * Sets the password for the account
     *
     * @param  string $password The password of the account being authenticated
     * @return My_Zend_Auth_Adapter_PearAuth Provides a fluent interface
     */
    public function setPassword($password)
    {
        $this->_password = (string)$password;
        return $this;
    }

    /**
     * Authenticate the user
     *
     * @throws Zend_Auth_Adapter_Exception
     * @return Zend_Auth_Result
     */
    public function authenticate()
    {
        require_once 'Pear/Auth.php';

        $messages = array();
        $messages[0] = ''; // reserved
        $messages[1] = ''; // reserved

        $username = $this->_username;
        $password = $this->_password;

        if (!$username) {
            $code = Zend_Auth_Result::FAILURE_IDENTITY_NOT_FOUND;
            $messages[0] = 'A username is required';
            return new Zend_Auth_Result($code, '', $messages);
        }
        if (!$password) {
            /* A password is required because some servers will
            * treat an empty password as an anonymous bind.
            */
            $code = Zend_Auth_Result::FAILURE_CREDENTIAL_INVALID;
            $messages[0] = 'A password is required';
            return new Zend_Auth_Result($code, '', $messages);
        }

        //Override $_POST variables required by Auth pear package.
        $_POST['username'] = $username;
        $_POST['password'] = $password;

        $_auth = new Auth($this->_container, $this->_options, '', false);

        //Enable logging
        if (isset ($this->_options['enableLogging']) && $this->_options['enableLogging'] && !is_null($this->_logger)) {
            $_auth->logger = $this->_logger;
        }

        $_auth->start();

        if ($_auth->getAuth()) {
            //Destroy Pear::Auth session to avoid unespected behaviour
            $_auth->logout();
            $messages[] = "$username authentication successful";
            return new Zend_Auth_Result(Zend_Auth_Result::SUCCESS, $username, $messages);
        }

        $messages[] = "$username authentication failed.";
        return new Zend_Auth_Result(Zend_Auth_Result::FAILURE, $username, $messages);
    }
}

and now let’s go to use it, for example in our controller

<?php
    ...
    $auth = Zend_Auth::getInstance();
    $config = new Zend_Config_Xml('APPLICATION_HOME/configs/auth_ldap.xml', 'production');
    $options = $config->ldap->toArray();
    $authAdapter = new Zend_Auth_Adapter_PearAuth('LDAP', $options, $username, $password);
    $result = $auth->authenticate($authAdapter);
    if (!is_null($result) && $result->isValid()) {
        $authorized = true;
    }
    ...

In the example above I’ve used the LDAP container but this should be valid for all supported containers by Pear::Auth.