* @license BSD */ namespace Domframework; /** User authentication against SQL database */ class Authsql extends Auth { /** The DSN to use to connect to SQL database */ public $dsn = null; /** The username to connect to the database */ public $username = null; /** The password to use to connecto to the database */ public $password = null; /** The driver options for the PDO driver */ public $driver_options = null; /** The table name to use */ public $table = null; /** The tableprefix text to prepend to table name (Should finish by _) Just allow chars ! */ public $tableprefix = ""; /** The password field name */ public $fieldPassword = "password"; /** The identifier field name (maybe email) */ public $fieldIdentifier = "email"; /** The field name containing the lastname of the user */ public $fieldLastname = null; /** The field name containing the Firstname of the user */ public $fieldFirstname = null; /** The information fields (in an array) */ public $fieldsInfo = array(); /** The DBLayer pointer */ private $db = null; /** The details of the authenticated user */ private $details = null; /** Establish a connection to a SQL server */ public function connect() { if (! function_exists("openssl_random_pseudo_bytes")) { throw new \Exception( dgettext( "domframework", "No PHP support for openssl_random_pseudo_bytes" ), 500 ); } $this->db = new Dblayer( $this->dsn, $this->username, $this->password, $this->driver_options ); if ($this->table === null) { throw new \Exception( dgettext("domframework", "No SQL table defined"), 500 ); } if ($this->fieldIdentifier === null) { throw new \Exception(dgettext( "domframework", "No fieldIdentifier defined" ), 500); } if ($this->fieldPassword === null) { throw new \Exception(dgettext( "domframework", "No fieldPassword defined" ), 500); } if ($this->fieldLastname === null) { throw new \Exception(dgettext( "domframework", "No fieldLastname defined" ), 500); } if ($this->fieldFirstname === null) { throw new \Exception(dgettext( "domframework", "No fieldFirstname defined" ), 500); } $fields = array_merge( array($this->fieldIdentifier, $this->fieldPassword, $this->fieldLastname, $this->fieldFirstname), $this->fieldsInfo ); $fields = array_flip($fields); foreach ($fields as $key => $val) { $fields[$key] = array("varchar", "255"); } $this->db->table = $this->table; $this->db->fields = $fields; $this->db->primary = $this->fieldIdentifier; } /** Try to authenticate the email/password of the user @param string $email Email to authenticate @param string $password Password to authenticate */ public function authentication($email, $password) { if ($this->db === null) { throw new \Exception(dgettext( "domframework", "The SQL database is not connected" ), 500); } $data = $this->db->read( array(array($this->fieldIdentifier, $email)), array_merge( array($this->fieldIdentifier, $this->fieldFirstname, $this->fieldLastname, $this->fieldPassword), $this->fieldsInfo ) ); if (count($data) === 0) { throw new \Exception(sprintf( dgettext( "domframework", "Unable to find the user : '%s'" ), $email ), 401); } if (! isset($data[0][$this->fieldPassword])) { throw new \Exception( dgettext( "domframework", "Unable to get the user password from database" ), 500 ); } $cryptedPassword = $data[0][$this->fieldPassword]; if (crypt($password, $cryptedPassword) !== $cryptedPassword) { throw new \Exception( sprintf(dgettext( "domframework", "Bad password for '%s'" ), $email), 401 ); } // The password should never be stored by this function unset($data[0][$this->fieldPassword]); $content = $data[0]; $content["email"] = $data[0][$this->fieldIdentifier]; $content["lastname"] = $data[0][$this->fieldLastname]; $content["firstname"] = $data[0][$this->fieldFirstname]; $this->details = $content; } /** Return all the parameters recorded for the authenticate user */ public function getdetails() { return $this->details; } /** Method to change the password @param string $oldpassword The old password (to check if the user have the rights to change the password) @param string $newpassword The new password to be recorded */ public function changepassword($oldpassword, $newpassword) { if ($this->db === null) { throw new \Exception(dgettext( "domframework", "The SQL database is not connected" ), 500); } if ( $this->details === null || ! isset($this->details[$this->fieldIdentifier]) ) { throw new \Exception( dgettext( "domframework", "Can't change the password if the user is not authenticated" ), 500 ); } $data = $this->db->read( array(array($this->fieldIdentifier, $this->details[$this->fieldIdentifier])), array($this->fieldIdentifier, $this->fieldPassword) ); $cryptedPassword = $data[0][$this->fieldPassword]; if (crypt($oldpassword, $cryptedPassword) !== $cryptedPassword) { throw new \Exception(dgettext( "domframework", "Bad old password provided" ), 401); } $cost = 11; $salt = substr(base64_encode(openssl_random_pseudo_bytes(17)), 0, 22); $salt = str_replace("+", ".", $salt); $param = '$' . implode('$', array( "2y", //select the most secure version of blowfish (>=PHP 5.3.7) str_pad($cost, 2, "0", STR_PAD_LEFT), //add the cost in two digits $salt //add the salt )); //now do the actual hashing $cryptpassword = crypt($newpassword, $param); $rc = $this->db->update( $this->details[$this->fieldIdentifier], array($this->fieldPassword => $cryptpassword) ); if ($rc !== 1) { throw new \Exception(dgettext( "domframework", "Can't change the password" ), 500); } } /** Method to overwrite the password (without oldpassword check) Must be reserved to the administrators. For the users, use changepassword method @param string $email the user identifier to select @param string $newpassword The new password to be recorded */ public function overwritepassword($email, $newpassword) { if ($this->db === null) { throw new \Exception(dgettext( "domframework", "The SQL database is not connected" ), 500); } $data = $this->db->read( array(array($this->fieldIdentifier, $email)), array($this->fieldIdentifier, $this->fieldPassword) ); if (count($data) === 0) { throw new \Exception(sprintf( dgettext( "domframework", "Unable to find the user : '%s'" ), $email ), 401); } $cost = 11; $salt = substr(base64_encode(openssl_random_pseudo_bytes(17)), 0, 22); $salt = str_replace("+", ".", $salt); $param = '$' . implode('$', array( "2y", //select the most secure version of blowfish (>=PHP 5.3.7) str_pad($cost, 2, "0", STR_PAD_LEFT), //add the cost in two digits $salt //add the salt )); //now do the actual hashing $cryptpassword = crypt($newpassword, $param); $rc = $this->db->update( $email, array($this->fieldPassword => $cryptpassword) ); if ($rc !== 1) { throw new \Exception(dgettext( "domframework", "Can't change the password" ), 500); } } /** List all the users available in the database Return firstname, lastname, mail, with mail is an array */ public function listusers() { if ($this->db === null) { throw new \Exception(dgettext( "domframework", "The SQL database is not connected" ), 500); } $data = $this->db->read(null, array_merge( array($this->fieldIdentifier, $this->fieldFirstname, $this->fieldLastname), $this->fieldsInfo )); return $data; } }