1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354
|
<?xml version="1.0" encoding="utf-8"?>
<!-- EN-Revision: 24249 -->
<!-- Reviewed: no -->
<sect1 id="zend.auth.adapter.dbtable">
<title>Authentification avec une table de base de données</title>
<sect2 id="zend.auth.adapter.dbtable.introduction">
<title>Introduction</title>
<para>
<classname>Zend_Auth_Adapter_DbTable</classname> fournit la possibilité d'authentifier
sur la base de crédits stockés dans une table de base de données. Comme
<classname>Zend_Auth_Adapter_DbTable</classname> requiert qu'une instance de
<classname>Zend_Db_Adapter_Abstract</classname> soit fournie à son constructeur, chaque
instance est liée à une connexion de base de données particulière. Les autres options
de configuration peuvent être réglées grâce au constructeur ou au travers de
différentes méthodes, une pour chaque option.
</para>
<para>
Les options de configuration disponibles incluent :
</para>
<itemizedlist>
<listitem>
<para>
<emphasis><property>tableName</property></emphasis> : il s'agit du nom de
la table dans la base de données qui contient les crédits d'authentification,
et envers laquelle la requête d'authentification sera réalisée.
</para>
</listitem>
<listitem>
<para>
<emphasis><property>identityColumn</property></emphasis> : il s'agit du
nom de la colonne dans la table utilisée pour représenter l'identité. La
colonne d'identité doit contenir une valeur unique, comme un "username" ou
une adresse mail.
</para>
</listitem>
<listitem>
<para>
<emphasis><property>credentialColumn</property></emphasis> : il s'agit
du nom de la colonne dans la table utilisée pour représenter le crédit. Dans
le cas d'une simple authentification par identité / mot de passe, la valeur
de crédit correspond au mot de passe. Voir aussi l'option
<property>credentialTreatment</property>.
</para>
</listitem>
<listitem>
<para>
<emphasis><property>credentialTreatment</property></emphasis> : dans la
plupart des cas, les mots de passe et autres données sensibles sont cryptés,
hachés, encodés, masqués, ou sinon traités à travers une fonction ou un
algorithme. En spécifiant un traitement paramétrable de chaîne avec cette
méthode, comme <methodname>MD5(?)</methodname> ou
<methodname>PASSWORD(?)</methodname>, un
développeur peut appliquer un code <acronym>SQL</acronym> arbitraire sur les
données de crédit fournies. Comme ces fonctions sont spécifiques à chaque
gestionnaire de base de données (<acronym>SGBD</acronym>), vérifiez le manuel
de la base de données pour vérifier la disponibilité de ces fonctions dans
votre système.
</para>
</listitem>
</itemizedlist>
<example id="zend.auth.adapter.dbtable.introduction.example.basic_usage">
<title>Utilisation basique</title>
<para>
Comme expliqué dans l'introduction, le constructeur de
<classname>Zend_Auth_Adapter_DbTable</classname> requiert une instance de
<classname>Zend_Db_Adapter_Abstract</classname> qui est utilisée comme connexion à
la base de données à laquelle l'instance d'adaptateur d'authentification est liée.
Avant tout, la connexion à la base de donnée devrait être crée.
</para>
<para>
Le code suivant crée un adaptateur pour une base de données en mémoire, crée
un schéma avec une table unique, et insère une ligne sur laquelle nous pouvons
réaliser une requête d'authentification plus tard. Cet exemple requiert que
l'extension <acronym>PDO</acronym> SQLite soit disponible :
</para>
<programlisting language="php"><![CDATA[
// Crée une connexion de base de données SQLite en mémoire
$dbAdapter = new Zend_Db_Adapter_Pdo_Sqlite(array('dbname' =>
':memory:'));
// Construit une requête de création de table
$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)';
// Crée la table de crédits d'authentification
$dbAdapter->query($sqlCreate);
// Construit la requête pour insérer une ligne pour laquelle
// l'authentification pourra réussir
$sqlInsert = "INSERT INTO users (username, password, real_name) "
. "VALUES ('my_username', 'my_password', 'My Real Name')";
// Insertion des données
$dbAdapter->query($sqlInsert);
]]></programlisting>
<para>
Avec une connexion de base de données et des données disponibles dans la
table, une instance de <classname>Zend_Auth_Adapter_DbTable</classname> peut être
créée. Les valeurs d'options de configuration peuvent être fournies au
constructeur ou en tant que paramètres aux méthodes de réglage après
l'instanciation :
</para>
<programlisting language="php"><![CDATA[
// Configure une instance avec des paramètres de constructeur ...
$authAdapter = new Zend_Auth_Adapter_DbTable($dbAdapter,
'users',
'username',
'password');
// ... ou configure l'instance avec des méthodes de réglage
$authAdapter = new Zend_Auth_Adapter_DbTable($dbAdapter);
$authAdapter->setTableName('users')
->setIdentityColumn('username')
->setCredentialColumn('password');
]]></programlisting>
<para>
A cet instant, l'instance de l'adaptateur d'authentification est prête à
recevoir des requêtes d'authentification. Dans le but de réaliser une requête
d'authentification, les valeurs des crédits requêtés sont fournies à l'adaptateur
avant d'appeler la méthode <methodname>authenticate()</methodname> :
</para>
<programlisting language="php"><![CDATA[
// Règle les valeurs d'entrées des crédits
// (en général, à partir d'un formulaire d'enregistrement)
$authAdapter->setIdentity('my_username')
->setCredential('my_password');
// Réalise la requête d'authentification, et sauvegarde le résultat
$result = $authAdapter->authenticate();
]]></programlisting>
<para>
En plus de la disponibilité de la méthode <methodname>getIdentity()</methodname>
pour récupérer l'objet du résultat d'authentification,
<classname>Zend_Auth_Adapter_DbTable</classname> supporte aussi la récupération de
la ligne de la table qui a réussi l'authentification :
</para>
<programlisting language="php"><![CDATA[
// Affiche l'identité
echo $result->getIdentity() . "\n\n";
// Affiche la ligne de résultat
print_r($authAdapter->getResultRowObject());
/* Affiche:
my_username
Array
(
[id] => 1
[username] => my_username
[password] => my_password
[real_name] => My Real Name
)
*/
]]></programlisting>
<para>
Puisque la ligne de la table contient la valeur de crédit, il est important de
garantir ces valeurs contre l'accès fortuit.
</para>
</example>
</sect2>
<sect2 id="zend.auth.adapter.dbtable.advanced.storing_result_row">
<title>Utilisation avancée : maintenir persistant l'objet de résultat DbTable</title>
<para>
Par défaut, <classname>Zend_Auth_Adapter_DbTable</classname> retourne l'identité
fournie à l'objet Auth en cas d'authentification couronnée de succès. Un autre scénario
d'utilisation, où les développeurs veulent stocker dans le mécanisme de stockage
persistant du <classname>Zend_Auth</classname> un objet d'identité contenant d'autres
informations utiles, est résolu en utilisant la méthode
<methodname>getResultRowObject()</methodname> retournant un objet
<emphasis>stdClass</emphasis>. Le petit bout de code suivant illustre cette
utilisation :
</para>
<programlisting language="php"><![CDATA[
// authentifie avec Zend_Auth_Adapter_DbTable
$result = $this->_auth->authenticate($adapter);
if ($result->isValid()) {
// stocke l'identité comme objet dans lequel seulement username et
// real_name sont retournés
$storage = $this->_auth->getStorage();
$storage->write($adapter->getResultRowObject(array('username',
'real_name')));
// stocke l'identité comme objet dans lequel la colonne password
// a été omis
$storage->write($adapter->getResultRowObject(null, 'password'));
/* ... */
} else {
/* ... */
}
]]></programlisting>
</sect2>
<sect2 id="zend.auth.adapter.dbtable.advanced.advanced_usage">
<title>Utilisation avancée par l'exemple</title>
<para>
Bien que le but initial de <classname>Zend_Auth</classname> (et par extension celui de
<classname>Zend_Auth_Adapter_DbTable</classname>) est principalement
l'<emphasis>authentification</emphasis> et non
l'<emphasis>autorisation</emphasis> (ou contrôle d'accès), il existe quelques
exemples et problèmes qui franchissent la limite des domaines auxquels ils
appartiennent. Selon la façon dont vous avez décidé d'expliquer votre problème, il
semble parfois raisonnable de résoudre ce qui pourrait ressembler à un problème
d'autorisation dans l'adaptateur d'authentification.
</para>
<para>
Ceci étant dit, <classname>Zend_Auth_Adapter_DbTable</classname> possède des mécanismes
qui sont construits de telle sorte qu'ils peuvent être démultipliés pour ajouter des
contrôles supplémentaires au moment de l'authentification pour résoudre quelques
problèmes communs d'utilisateur.
</para>
<programlisting language="php"><![CDATA[
// La valeur du champs "etat" d'un compte
// ne doit pas être égal à "compromis"
$adapter = new Zend_Auth_Adapter_DbTable($db,
'utilisateurs',
'login',
'password',
'MD5(?) AND etat != "compromis"');
// La valeur du champs "actif" d'un compte
// doit être égal à "TRUE"
$adapter = new Zend_Auth_Adapter_DbTable($db,
'utilisateurs',
'login',
'password',
'MD5(?) AND actif = "TRUE"');
]]></programlisting>
<para>
Un autre scénario possible est l'implantation d'un mécanisme de "salting".
"Salting" est un terme se référant une technique qui peut fortement améliorer la
sécurité de votre application. C'est basé sur l'idée que concaténer une chaîne
aléatoire à tout mot de passe rend impossible la réussite d'une attaque de type "brute
force" sur la base de données en utilisant des valeurs préalablement hashées issues
d'un dictionnaire.
</para>
<para>
Par conséquent nous devons modifier notre table pour stocker notre chaîne de
"salt" aléatoire :
</para>
<programlisting language="php"><![CDATA[
$sqlAlter = "ALTER TABLE [users] "
. "ADD COLUMN [password_salt] "
. "AFTER [password]";
$dbAdapter->query($sqlAlter);
]]></programlisting>
<para>
Voici une méthode simple pour générer une chaîne aléatoire pour chaque
utilisateur à leur enregistrement :
</para>
<programlisting language="php"><![CDATA[
for ($i = 0; $i < 50; $i++)
{
$dynamicSalt .= chr(rand(33, 126));
}
]]></programlisting>
<para>Et maintenant, construisons l'adaptateur :</para>
<programlisting language="php"><![CDATA[
$adapter = new Zend_Auth_Adapter_DbTable(
$db,
'users',
'username',
'password',
"MD5(CONCAT('"
. Zend_Registry::get('staticSalt')
. "', ?, password_salt))"
);
]]></programlisting>
<note>
<para>
Vous pouvez encore améliorer la sécurité en utilisant une chaîne de "salt"
statique codée en dur dans votre application. Dans le cas ou la base de données est
compromise (par exemple par une attaque de type injection <acronym>SQL</acronym>)
mais que votre serveur Web est intact, les données sont inutilisables par
l'attaquant.
</para>
</note>
<para>
Une autre alternative est d'utiliser la méthode <methodname>getDbSelect()</methodname>
de la classe <classname>Zend_Auth_Adapter_DbTable</classname> après la construction de
l'adaptateur. Cette méthode retournera une instance d'objet
<classname>Zend_Db_Select</classname> utilisée pour réaliser la routine
<methodname>authenticate()</methodname>. Il est important de noter que cette méthode
retournera toujours le même objet, que la méthode
<methodname>authenticate()</methodname> a été appelée ou non. Cet objet
<emphasis>ne comportera aucune</emphasis> information d'identité ou de crédit puisque
celles-ci sont placées dans l'objet select au moment de
<methodname>authenticate()</methodname>.
</para>
<para>
Un exemple de situation nécessitant l'utilisation de la méthode
<methodname>getDbSelect()</methodname> serait de vérifier le statut d'un utilisateur,
en d'autres termes pour voir si le compte d'un utilisateur est activé.
</para>
<programlisting language="php"><![CDATA[
// En continuant avec l'exemple ci-dessus
$adapter = new Zend_Auth_Adapter_DbTable(
$db,
'users',
'username',
'password',
'MD5(?)'
);
// Récupérer l'objet select (par référence)
$select = $adapter->getDbSelect();
$select->where('active = "TRUE"');
// Authentification, ceci s'assure que users.active = TRUE
$adapter->authenticate();
]]></programlisting>
</sect2>
</sect1>
|