Ejemplo n.º 1
0
 /**
  * Creates a new client record and exports the data to the configured client export directory
  *
  * @return mixed	The new client's ID or false on failure
  */
 public function createClient()
 {
     $s_NewID = ClientEntity::getNewID();
     $s_NewPath = $this->client_export_path . $s_NewID . DIRECTORY_SEPARATOR;
     $s_NewDBPath = $s_NewPath . $s_NewID . '.db';
     $s_NewConfigPath = $s_NewPath . 'config.xml';
     /* Create client directory */
     if (!file_exists($s_NewPath) && !mkdir($s_NewPath, (int) $this->dir_umask, true)) {
         return false;
     } elseif (!is_writeable($s_NewPath)) {
         return false;
     }
     /* Initialize client data */
     $s_NewDBKey = sha1(openssl_random_pseudo_bytes(4096));
     $a_NewData['id'] = $s_NewID;
     $a_NewData['server_public_key'] = (string) $this->public_key;
     // Randomizing the initial counter sequence makes brute force attacks harder
     $a_NewData['counter'] = hexdec(bin2hex(openssl_random_pseudo_bytes(1)));
     $a_NewData['key'] = sha1(openssl_random_pseudo_bytes(4096));
     $a_NewData['password_length'] = (int) $this->password_length;
     $a_NewData['status'] = ClientEntity::ACTIVE;
     $a_NewData['failed_auths'] = 0;
     /* Write the files to the client directory */
     $o_ClientConfig = new SimpleXMLElement('<otpclient></otpclient>');
     $o_ClientConfig->addChild('id', $a_NewData['id']);
     $o_ClientConfig->addChild('db_key', $s_NewDBKey);
     $o_ClientConfig->addChild('db_path', $s_NewDBPath);
     file_put_contents($s_NewConfigPath, $o_ClientConfig->asXML());
     chmod($s_NewConfigPath, (int) $this->file_umask);
     copy($this->client_export_path . 'OTPClient.php', $s_NewPath . 'OTPClient.php');
     chmod($s_NewPath . 'OTPClient.php', (int) $this->file_umask);
     copy($this->client_export_path . 'ClientEntity.php', $s_NewPath . 'ClientEntity.php');
     chmod($s_NewPath . 'ClientEntity.php', (int) $this->file_umask);
     // Create client's database file
     $o_ClientDB = new PDO('sqlite:' . $s_NewDBPath);
     $o_ClientDB->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
     chmod($s_NewDBPath, (int) $this->file_umask);
     /* Create the new client records */
     ClientEntity::save($a_NewData, $this->_o_DB, $this->db_key);
     $o_Result = $this->_o_DB->query("SELECT sql FROM sqlite_master WHERE tbl_name='clients'");
     $a_Result = $o_Result->fetch(PDO::FETCH_NUM);
     $s_CreateTableQuery = $a_Result[0];
     $o_ClientDB->exec($s_CreateTableQuery);
     ClientEntity::save($a_NewData, $o_ClientDB, $s_NewDBKey);
     /*
     The RFC specifies that the client should increment its counter before sending a password,
     but the server should only increment the counter AFTER a successful authentication attempt.
     This ensures that the server-side record is one count ahead of the client-side record to facilitate this requirement
     */
     $NewClient = new ClientEntity($this->_o_DB, $a_NewData['id'], $this->db_key);
     $NewClient->counter++;
     return $s_NewConfigPath;
 }
 /**
  * @test			getNewID
  */
 public function testGetNewID()
 {
     $s_NewID = ClientEntity::getNewID();
     $this->assertTrue(strlen($s_NewID) == 36);
     $a_IDParts = explode('-', $s_NewID);
     $this->assertTrue(count($a_IDParts) == 5);
     $this->assertTrue(strlen($a_IDParts[0]) == 8);
     $this->assertTrue(strlen($a_IDParts[1]) == 4);
     $this->assertTrue(strlen($a_IDParts[2]) == 4);
     $this->assertTrue(substr($a_IDParts[2], 0, 1) == 4);
     $this->assertTrue(strlen($a_IDParts[3]) == 4);
     $this->assertTrue(strlen($a_IDParts[4]) == 12);
 }