[ZF-8969] Manual:
[zend.git] / documentation / manual / en / module_specs / Zend_Auth_Adapter_DbTable.xml
blobd93e5442c93e263bde65cfe38a676d6aa5e16573
1 <?xml version="1.0" encoding="UTF-8"?>
2 <!-- Reviewed: no -->
3 <sect1 id="zend.auth.adapter.dbtable">
4     <title>Database Table Authentication</title>
6     <sect2 id="zend.auth.adapter.dbtable.introduction">
7         <title>Introduction</title>
9         <para>
10             <classname>Zend_Auth_Adapter_DbTable</classname> provides the ability to
11             authenticate against credentials stored in a database table. Because
12             <classname>Zend_Auth_Adapter_DbTable</classname> requires an instance of
13             <classname>Zend_Db_Adapter_Abstract</classname> to be passed to its
14             constructor, each instance is bound to a particular database
15             connection. Other configuration options may be set through the
16             constructor and through instance methods, one for each option.
17         </para>
19         <para>
20             The available configuration options include:
21         </para>
23         <itemizedlist>
24             <listitem>
25                 <para>
26                     <emphasis><property>tableName</property></emphasis>: This is the name of the
27                     database table that contains the authentication credentials,
28                     and against which the database authentication query is
29                     performed.
30                 </para>
31             </listitem>
33             <listitem>
34                 <para>
35                     <emphasis><property>identityColumn</property></emphasis>: This is the name of
36                     the database table column used to represent the identity.
37                     The identity column must contain unique values, such as
38                     a username or e-mail address.
39                 </para>
40             </listitem>
42             <listitem>
43                 <para>
44                     <emphasis><property>credentialColumn</property></emphasis>: This is the name
45                     of the database table column used to represent the credential.
46                     Under a simple identity and password authentication
47                     scheme, the credential value corresponds to the
48                     password. See also the <property>credentialTreatment</property>
49                     option.
50                 </para>
51             </listitem>
53             <listitem>
54                 <para>
55                     <emphasis><property>credentialTreatment</property></emphasis>: In many cases,
56                     passwords and other sensitive data are encrypted,
57                     hashed, encoded, obscured, salted or otherwise treated
58                     through some function or algorithm. By specifying a
59                     parameterized treatment string with this method, such as
60                     '<methodname>MD5(?)</methodname>' or
61                     '<methodname>PASSWORD(?)</methodname>', a
62                     developer may apply such arbitrary <acronym>SQL</acronym> upon input
63                     credential data. Since these functions are specific to
64                     the underlying <acronym>RDBMS</acronym>, check the database manual for the
65                     availability of such functions for your database system.
66                 </para>
67             </listitem>
68         </itemizedlist>
70         <example id="zend.auth.adapter.dbtable.introduction.example.basic_usage">
71             <title>Basic Usage</title>
73             <para>
74                 As explained in the introduction, the
75                 <classname>Zend_Auth_Adapter_DbTable</classname> constructor requires an
76                 instance of <classname>Zend_Db_Adapter_Abstract</classname> that serves as
77                 the database connection to which the authentication adapter
78                 instance is bound. First, the database connection should be
79                 created.
80             </para>
82             <para>
83                 The following code creates an adapter for an in-memory database,
84                 creates a simple table schema, and inserts a row against
85                 which we can perform an authentication query later. This example
86                 requires the <acronym>PDO</acronym> SQLite extension to be available:
87             </para>
89             <programlisting language="php"><![CDATA[
90 // Create an in-memory SQLite database connection
91 $dbAdapter = new Zend_Db_Adapter_Pdo_Sqlite(array('dbname' =>
92                                                   ':memory:'));
94 // Build a simple table creation query
95 $sqlCreate = 'CREATE TABLE [users] ('
96            . '[id] INTEGER  NOT NULL PRIMARY KEY, '
97            . '[username] VARCHAR(50) UNIQUE NOT NULL, '
98            . '[password] VARCHAR(32) NULL, '
99            . '[real_name] VARCHAR(150) NULL)';
101 // Create the authentication credentials table
102 $dbAdapter->query($sqlCreate);
104 // Build a query to insert a row for which authentication may succeed
105 $sqlInsert = "INSERT INTO users (username, password, real_name) "
106            . "VALUES ('my_username', 'my_password', 'My Real Name')";
108 // Insert the data
109 $dbAdapter->query($sqlInsert);
110 ]]></programlisting>
112             <para>
113                 With the database connection and table data available, an
114                 instance of <classname>Zend_Auth_Adapter_DbTable</classname> may be
115                 created. Configuration option values may be passed to the
116                 constructor or deferred as parameters to setter methods after
117                 instantiation:
118             </para>
120             <programlisting language="php"><![CDATA[
121 // Configure the instance with constructor parameters...
122 $authAdapter = new Zend_Auth_Adapter_DbTable(
123     $dbAdapter,
124     'users',
125     'username',
126     'password'
129 // ...or configure the instance with setter methods
130 $authAdapter = new Zend_Auth_Adapter_DbTable($dbAdapter);
132 $authAdapter
133     ->setTableName('users')
134     ->setIdentityColumn('username')
135     ->setCredentialColumn('password')
137 ]]></programlisting>
139             <para>
140                 At this point, the authentication adapter instance is ready to
141                 accept authentication queries. In order to formulate an
142                 authentication query, the input credential values are passed to
143                 the adapter prior to calling the <methodname>authenticate()</methodname>
144                 method:
145             </para>
147             <programlisting language="php"><![CDATA[
148 // Set the input credential values (e.g., from a login form)
149 $authAdapter
150     ->setIdentity('my_username')
151     ->setCredential('my_password')
154 // Perform the authentication query, saving the result
155 ]]></programlisting>
157             <para>
158                 In addition to the availability of the
159                 <methodname>getIdentity()</methodname> method upon the authentication result
160                 object, <classname>Zend_Auth_Adapter_DbTable</classname> also supports
161                 retrieving the table row upon authentication success:
162             </para>
164             <programlisting language="php"><![CDATA[
165 // Print the identity
166 echo $result->getIdentity() . "\n\n";
168 // Print the result row
169 print_r($authAdapter->getResultRowObject());
171 /* Output:
172 my_username
174 Array
176     [id] => 1
177     [username] => my_username
178     [password] => my_password
179     [real_name] => My Real Name
181 ]]></programlisting>
183             <para>
184                 Since the table row contains the credential value, it is
185                 important to secure the values against unintended access.
186             </para>
187         </example>
188     </sect2>
190     <sect2 id="zend.auth.adapter.dbtable.advanced.storing_result_row">
191         <title>Advanced Usage: Persisting a DbTable Result Object</title>
193         <para>
194             By default, <classname>Zend_Auth_Adapter_DbTable</classname> returns the
195             identity supplied back to the auth object upon successful
196             authentication. Another use case scenario, where developers want to
197             store to the persistent storage mechanism of <classname>Zend_Auth</classname>
198             an identity object containing other useful information, is solved by
199              using the <methodname>getResultRowObject()</methodname> method to return a
200             <emphasis>stdClass</emphasis> object. The following code snippet illustrates
201             its use:
202         </para>
204         <programlisting language="php"><![CDATA[
205 // authenticate with Zend_Auth_Adapter_DbTable
206 $result = $this->_auth->authenticate($adapter);
208 if ($result->isValid()) {
209     // store the identity as an object where only the username and
210     // real_name have been returned
211     $storage = $this->_auth->getStorage();
212     $storage->write($adapter->getResultRowObject(array(
213         'username',
214         'real_name',
215     )));
217     // store the identity as an object where the password column has
218     // been omitted
219     $storage->write($adapter->getResultRowObject(
220         null,
221         'password'
222     ));
224     /* ... */
226 } else {
228     /* ... */
231 ]]></programlisting>
232     </sect2>
234     <sect2 id="zend.auth.adapter.dbtable.advanced.advanced_usage">
235         <title>Advanced Usage By Example</title>
237         <para>
238             While the primary purpose of <classname>Zend_Auth</classname> (and consequently
239             <classname>Zend_Auth_Adapter_DbTable</classname>) is primarily
240             <emphasis>authentication</emphasis> and not
241             <emphasis>authorization</emphasis>, there are a few
242             instances and problems that toe the line between which domain they fit
243             within. Depending on how you've decided to explain your problem, it
244              sometimes makes sense to solve what could look like an
245              authorization problem within the authentication adapter.
246         </para>
248         <para>
249             With that disclaimer out of the way, <classname>Zend_Auth_Adapter_DbTable</classname>
250             has some built in mechanisms that can be leveraged for additional checks at
251             authentication time to solve some common user problems.
252         </para>
254         <programlisting language="php"><![CDATA[
255 // The status field value of an account is not equal to "compromised"
256 $adapter = new Zend_Auth_Adapter_DbTable(
257     $db,
258     'users',
259     'username',
260     'password',
261     'MD5(?) AND status != "compromised"'
264 // The active field value of an account is equal to "TRUE"
265 $adapter = new Zend_Auth_Adapter_DbTable(
266     $db,
267     'users',
268     'username',
269     'password',
270     'MD5(?) AND active = "TRUE"'
271 ]]></programlisting>
273         <para>
274             Another scenario can be the implementation of a salting mechanism.
275             Salting is a term referring to a technique which can highly improve
276             your application's security. It's based on the idea that
277             concatenating a random string to every password makes it impossible
278             to accomplish a successful brute force attack on the database using
279             pre-computed hash values from a dictionary.
280         </para>
282         <para>
283             Therefore, we need to modify our table to store our salt string:
284         </para>
286         <programlisting language="php"><![CDATA[
287 $sqlAlter = "ALTER TABLE [users] "
288           . "ADD COLUMN [password_salt] "
289           . "AFTER [password]";
290 ]]></programlisting>
292         <para>
293             Here's a simple way to generate a salt string for every user at
294             registration:
295         </para>
297         <programlisting language="php"><![CDATA[
298 for ($i = 0; $i < 50; $i++) {
299     $dynamicSalt .= chr(rand(33, 126));
300 ]]></programlisting>
301         <para>
302             And now let's build the adapter:
303         </para>
304         <programlisting language="php"><![CDATA[
305 $adapter = new Zend_Auth_Adapter_DbTable(
306     $db,
307     'users',
308     'username',
309     'password',
310     "MD5(CONCAT('"
311     . Zend_Registry::get('staticSalt')
312     . "', ?, password_salt))"
314 ]]></programlisting>
316         <note>
317             <para>
318                 You can improve security even more by using a static salt value
319                 hard coded into your application. In the case that your database
320                 is compromised (e. g. by an <acronym>SQL</acronym> injection attack) but your web
321                 server is intact your data is still unusable for the attacker.
322             </para>
323         </note>
325         <para>
326             Another alternative is to use the <methodname>getDbSelect()</methodname> method
327             of the <classname>Zend_Auth_Adapter_DbTable</classname> after the adapter has been
328             constructed. This method will return the <classname>Zend_Db_Select</classname> object
329             instance it will use to complete the <methodname>authenticate()</methodname> routine.
330             It is important to note that this method will always return the same object regardless
331             if <methodname>authenticate()</methodname> has been called or not. This object
332             <emphasis>will not</emphasis> have any of the identity or credential information in it
333             as those values are placed into the select object at
334             <methodname>authenticate()</methodname> time.
335         </para>
337         <para>
338             An example of a situation where one might want to use the
339             <methodname>getDbSelect()</methodname> method would check the status of a user, in
340             other words to see if that user's account is enabled.
341         </para>
343         <programlisting language="php"><![CDATA[
344 // Continuing with the example from above
345 $adapter = new Zend_Auth_Adapter_DbTable(
346     $db,
347     'users',
348     'username',
349     'password',
350     'MD5(?)'
353 // get select object (by reference)
354 $select = $adapter->getDbSelect();
355 $select->where('active = "TRUE"');
357 // authenticate, this ensures that users.active = TRUE
358 $adapter->authenticate();
359 ]]></programlisting>
360     </sect2>
361 </sect1>