namespace Fierce; $db = $this->mock('DB'); Env::push('db', $db); $db->User = $this->Mock('DBEntity', 'User'); $db->LoginFailure = $this->Mock('DBEntity', 'LoginFailure'); $db->ApiToken = $this->Mock('DBEntity', 'ApiToken'); $api = new ApiController(); $api->rethrowExceptions = false; $api->db = $db; // create token with correct credentials $email = '*****@*****.**'; $password = '******'; $user = (object) ['id' => Auth::userIdByEmail($email), 'type' => 'test', 'email' => $email, 'password' => Auth::hashForPassword($email, $password)]; $user->signature = Auth::signatureForUser($user); $db->prepareForCall('id', null, function () { return sha1(rand()); }); $db->User->prepareForCall('byId', null, function () use($user) { return $user; }); $db->LoginFailure->prepareForCall('byId', null, function () { throw new \Exception("Invalid id"); }); $db->ApiToken->prepareForCall('write'); ob_start(); $api->apiParams = (object) ['email' => $email, 'password' => $password]; $api->runActionNamed('createApiToken'); $responseJson = ob_get_clean(); $response = json_decode($responseJson);
public function save($checkLogin = true) { $db = Env::get('db'); if ($checkLogin) { Auth::requireAdmin(); $user = Auth::loggedInUser(); $isCurrentUser = $user && $user->id == $this->id; } else { $user = null; $isCurrentUser = false; } // apply new id (email may have changed) $oldId = $this->id; $this->id = sha1(strtolower($this->row->email) . Env::get('auth_salt')); $this->row->id = $this->id; // misc fields $this->row->modified = new \DateTime(); if ($user) { $this->row->modifiedBy = $user->id; } else { $this->row->modifiedBy = 'none'; } // reset password if it changed $newPassword = false; if (@$this->row->newPassword) { $this->row->password = Auth::hashForPassword($this->email, $this->newPassword); $newPassword = $this->row->newPassword; unset($this->row->newPassword); } if (!isset($this->password)) { $this->password = ''; } // hash everything $this->row->signature = Auth::signatureForUser($this); $db->User->archive($oldId); $db->User->write($this->id, $this->row, true); if ($isCurrentUser && $newPassword) { Auth::attemptLogin($this->row->email, $newPassword); } }
// password hashing $email = 'justine'; $password = '******'; $type = 'admin'; $id = $id = Auth::userIdByEmail($email); $passwordHash = sha1(password_hash($password, PASSWORD_BCRYPT, ['cost' => 11, 'salt' => $id])); $passwordHash = sha1(password_hash($passwordHash, PASSWORD_BCRYPT, ['cost' => 11, 'salt' => $id])); // for historical reasons we have to double hash... would be good to remove this in future, but complicated without resetting passwords $start = microtime(true); $gotPasswordHash = Auth::hashForPassword('justine', 'sane'); $duration = abs($start - microtime(true)); $this->assertEqual($gotPasswordHash, $passwordHash, 'Verify password hashing'); $this->assert($duration > 0.3, 'Verify decent hash strength'); // user signatures $expectedSignature = sha1($id . $type . $email . $passwordHash . Env::get('auth_salt')); $signature = Auth::signatureForUser((object) ['id' => $id, 'type' => $type, 'email' => $email, 'password' => $passwordHash]); $this->assertEqual($expectedSignature, $signature, 'User signature generation'); // brute force $this->fail("Brute force detection"); // todo: test this // create session/api token $user = (object) ['id' => $id, 'password' => $passwordHash]; $tokenId = '419db9a8d05cf8657adc2e92b1fc98cd9c0054cf'; $date = new \DateTime(); $tokenHash = Auth::tokenHashForUser($user, $date, $tokenId); $this->assertEqual($tokenHash, sha1($user->id . $user->password . $date->getTimestamp() . Env::get('auth_salt')), 'Verify creating session/api tokens'); // test using an API token $user = (object) ['id' => $id, 'type' => $type, 'name' => 'Justine', 'email' => $email, 'password' => $passwordHash, 'signature' => $signature]; $apiToken = (object) ['id' => $tokenId, 'userId' => $user->id, 'created' => $date, 'hash' => $tokenHash]; $db->User->prepareForCall('byId', [$user->id], $user); $db->ApiToken->prepareForCall('byId', [$apiToken->id], $apiToken);