Zend_Auth_Adapter_DbTable
provides the ability to
authenticate against credentials stored in a database table. Because
Zend_Auth_Adapter_DbTable
requires an instance of
Zend_Db_Adapter_Abstract
to be passed to its
constructor, each instance is bound to a particular database
connection. Other configuration options may be set through the
constructor and through instance methods, one for each option.
The available configuration options include:
tableName
: This is the name of the database
table that contains the authentication credentials,
and against which the database authentication query is
performed.
identityColumn
: This is the name of the
database table column used to represent the identity.
The identity column must contain unique values, such as
a username or e-mail address.
credentialColumn
: This is the name of the
database table column used to represent the credential.
Under a simple identity and password authentication
scheme, the credential value corresponds to the
password. See also the credentialTreatment
option.
credentialTreatment
: In many cases,
passwords and other sensitive data are encrypted,
hashed, encoded, obscured, salted or otherwise treated
through some function or algorithm. By specifying a
parameterized treatment string with this method, such as
'MD5(?)'
or 'PASSWORD(?)'
, a
developer may apply such arbitrary SQL upon input
credential data. Since these functions are specific to
the underlying RDBMS, check the database manual for the
availability of such functions for your database system.
Example 4.3. Basic Usage
As explained in the introduction, the
Zend_Auth_Adapter_DbTable
constructor requires an
instance of Zend_Db_Adapter_Abstract
that serves as
the database connection to which the authentication adapter
instance is bound. First, the database connection should be
created.
The following code creates an adapter for an in-memory database, creates a simple table schema, and inserts a row against which we can perform an authentication query later. This example requires the PDO SQLite extension to be available:
// Create an in-memory SQLite database connection $dbAdapter = new Zend_Db_Adapter_Pdo_Sqlite(array('dbname' => ':memory:')); // Build a simple table creation query $sqlCreate = 'CREATE TABLE [users] (' . '[id] INTEGER NOT NULL PRIMARY KEY, ' . '[username] VARCHAR(50) UNIQUE NOT NULL, ' . '[password] VARCHAR(32) NULL, ' . '[real_name] VARCHAR(150) NULL)'; // Create the authentication credentials table $dbAdapter->query($sqlCreate); // Build a query to insert a row for which authentication may succeed $sqlInsert = "INSERT INTO users (username, password, real_name) " . "VALUES ('my_username', 'my_password', 'My Real Name')"; // Insert the data $dbAdapter->query($sqlInsert);
With the database connection and table data available, an
instance of Zend_Auth_Adapter_DbTable
may be
created. Configuration option values may be passed to the
constructor or deferred as parameters to setter methods after
instantiation:
// Configure the instance with constructor parameters... $authAdapter = new Zend_Auth_Adapter_DbTable( $dbAdapter, 'users', 'username', 'password' ); // ...or configure the instance with setter methods $authAdapter = new Zend_Auth_Adapter_DbTable($dbAdapter); $authAdapter ->setTableName('users') ->setIdentityColumn('username') ->setCredentialColumn('password') ;
At this point, the authentication adapter instance is ready to
accept authentication queries. In order to formulate an
authentication query, the input credential values are passed to
the adapter prior to calling the authenticate()
method:
// Set the input credential values (e.g., from a login form) $authAdapter ->setIdentity('my_username') ->setCredential('my_password') ; // Perform the authentication query, saving the result $result = $authAdapter->authenticate();
In addition to the availability of the
getIdentity()
method upon the authentication result
object, Zend_Auth_Adapter_DbTable
also supports
retrieving the table row upon authentication success:
// Print the identity echo $result->getIdentity() . "\n\n"; // Print the result row print_r($authAdapter->getResultRowObject()); /* Output: my_username Array ( [id] => 1 [username] => my_username [password] => my_password [real_name] => My Real Name ) */
Since the table row contains the credential value, it is important to secure the values against unintended access.
By default, Zend_Auth_Adapter_DbTable
returns the
identity supplied back to the auth object upon successful
authentication. Another use case scenario, where developers want to
store to the persistent storage mechanism of Zend_Auth
an identity object containing other useful information, is solved by
using the getResultRowObject()
method to return a
stdClass
object. The following code snippet illustrates
its use:
// authenticate with Zend_Auth_Adapter_DbTable $result = $this->_auth->authenticate($adapter); if ($result->isValid()) { // store the identity as an object where only the username and // real_name have been returned $storage = $this->_auth->getStorage(); $storage->write($adapter->getResultRowObject(array( 'username', 'real_name', ))); // store the identity as an object where the password column has // been omitted $storage->write($adapter->getResultRowObject( null, 'password' )); /* ... */ } else { /* ... */ }
While the primary purpose of Zend_Auth (and consequently Zend_Auth_Adapter_DbTable) is primarily authentication and not authorization, there are a few instances and problems that toe the line between which domain they fit within. Depending on how you’ve decided to explain your problem, it sometimes makes sense to solve what could look like an authorization problem within the authentication adapter.
With that disclaimer out of the way, Zend_Auth_Adapter_DbTable has some built in mechanisms that can be leveraged for additional checks at authentication time to solve some common user problems.
// The status field value of an account is not equal to "compromised" $adapter = new Zend_Auth_Adapter_DbTable( $db, 'users', 'username', 'password', 'MD5(?) AND status != "compromised"' ); // The active field value of an account is equal to "TRUE" $adapter = new Zend_Auth_Adapter_DbTable( $db, 'users', 'username', 'password', 'MD5(?) AND active = "TRUE"' );
Another scenario can be the implementation of a salting mechanism. Salting is a term referring to a technique which can highly improve your application’s security. It’s based on the idea that concatenating a random string to every password makes it impossible to accomplish a successful brute force attack on the database using pre-computed hash values from a dictionary.
Therefore, we need to modify our table to store our salt string:
$sqlAlter = "ALTER TABLE [users] " . "ADD COLUMN [password_salt] " . "AFTER [password]"; $dbAdapter->query($sqlAlter);
Here’s a simple way to generate a salt string for every user at registration:
for ($i = 0; $i < 50; $i++) { $dynamicSalt .= chr(rand(33, 126)); }
And now let’s build the adapter:
$adapter = new Zend_Auth_Adapter_DbTable( $db, 'users', 'username', 'password', "MD5(CONCAT('" . Zend_Registry::get('staticSalt') . "', ?, password_salt))" );
![]() |
Note |
---|---|
You can improve security even more by using a static salt value hard coded into your application. In the case that your database is compromised (e. g. by an SQL injection attack) but your web server is intact your data is still unusable for the attacker. |