/** * Check if stored user object is enabled. * * @return boolean|null */ public function isEnabled() { if ($this->user !== null) { return $this->user->getEnabled(); } return null; }
/** * It should detect already hashed passwords. * * @dataProvider providePreSaveAlreadyHashed */ public function testOnPreSavePasswordAlreadyHashed($hash) { $this->storageEvent->getContent()->willReturn($this->user->reveal()); $this->user->getPassword()->willReturn($hash); $this->passwordFactory->createHash(Argument::cetera())->shouldNotBeCalled(); $this->user->setPassword($hash)->shouldBeCalled(); $this->listener->onUserEntityPreSave($this->storageEvent->reveal()); }
/** * @see \Symfony\Component\Console\Command\Command::execute() */ protected function execute(InputInterface $input, OutputInterface $output) { $username = $input->getArgument('username'); $password = $input->getArgument('password'); $email = $input->getArgument('email'); $displayname = $input->getArgument('displayname'); $role = $input->getArgument('role'); $data = ['username' => $username, 'password' => $password, 'email' => $email, 'displayname' => $displayname, 'roles' => [$role]]; $user = new Entity\Users($data); $valid = true; if (!$this->app['users']->checkAvailability('username', $user->getUsername())) { $valid = false; $output->writeln("<error>Error creating user: username {$user->getUsername()} already exists</error>"); } if (!$this->app['users']->checkAvailability('email', $user->getEmail())) { $valid = false; $output->writeln("<error>Error creating user: email {$user->getEmail()} exists</error>"); } if (!$this->app['users']->checkAvailability('displayname', $user->getDisplayname())) { $valid = false; $output->writeln("<error>Error creating user: display name {$user->getDisplayname()} already exists</error>"); } if ($valid) { $res = $this->app['users']->saveUser($user); if ($res) { $this->auditLog(__CLASS__, "User created: {$user['username']}"); $output->writeln("<info>Successfully created user: {$user['username']}</info>"); } else { $output->writeln("<error>Error creating user: {$user['username']}</error>"); } } }
/** * @see \Symfony\Component\Console\Command\Command::execute() */ protected function execute(InputInterface $input, OutputInterface $output) { /** @var \Bolt\Storage\Repository\UsersRepository $repo */ $repo = $this->app['storage']->getRepository('Bolt\\Storage\\Entity\\Users'); $user = new Entity\Users(['username' => $input->getArgument('username'), 'password' => $input->getArgument('password'), 'email' => $input->getArgument('email'), 'displayname' => $input->getArgument('displayname'), 'roles' => (array) $input->getArgument('role')]); $message = []; $valid = true; if ($repo->getUser($user->getEmail())) { $valid = false; $message[] = "<error> * Email address '{$user->getEmail()}' already exists</error>"; } if ($repo->getUser($user->getUsername())) { $valid = false; $message[] = "<error> * User name '{$user->getUsername()}' already exists</error>"; } if ($valid === false) { $message[] = "<error>Error creating user:</error>"; $output->write(array_reverse($message), true); return; } try { // Boot all service providers manually as, we're not handling a request $this->app->boot(); $this->app['storage']->getRepository('Bolt\\Storage\\Entity\\Users')->save($user); $this->auditLog(__CLASS__, "User created: {$user->getUsername()}"); $output->writeln("<info>Successfully created user: {$user->getUsername()}</info>"); } catch (\Exception $e) { $output->writeln("<error>Error creating user: {$user->getUsername()}</error>"); } }
/** * Hash user passwords on save. * * Hashstrength has a default of '10', don't allow less than '8'. * * @param Entity\Users $usersEntity */ protected function passwordHash(Entity\Users $usersEntity) { if ($usersEntity->getShadowSave()) { return; } elseif ($usersEntity->getPassword() && $usersEntity->getPassword() !== '**dontchange**') { $hasher = new PasswordHash($this->hashStrength, true); $usersEntity->setPassword($hasher->HashPassword($usersEntity->getPassword())); } else { unset($usersEntity->password); } }
/** * Hash user passwords on save. * * @param Entity\Users $usersEntity */ protected function passwordHash(Entity\Users $usersEntity) { if ($usersEntity->getShadowSave()) { return; } elseif ($usersEntity->getPassword() && $usersEntity->getPassword() !== '**dontchange**') { $crypt = new PasswordLib(); $usersEntity->setPassword($crypt->createPasswordHash($usersEntity->getPassword(), '$2a$', ['cost' => $this->hashStrength])); } else { unset($usersEntity->password); } }
/** * Handle a POST from user edit or first user creation. * * @param Request $request * @param Form $form A Symfony form * @param boolean $firstuser If this is a first user set up * * @return Entity\Users|false */ private function validateUserForm(Request $request, Form $form, $firstuser = false) { $form->submit($request->get($form->getName())); if (!$form->isValid()) { return false; } $userEntity = new Entity\Users($form->getData()); $userEntity->setUsername($this->app['slugify']->slugify($userEntity->getUsername())); if (!$firstuser) { $userEntity->setRoles($this->users()->filterManipulatableRoles($userEntity->getId(), $userEntity->getRoles())); } if ($this->getRepository('Bolt\\Storage\\Entity\\Users')->save($userEntity)) { $this->flashes()->success(Trans::__('page.edit-users.message.user-saved', ['%user%' => $userEntity->getDisplayname()])); $this->notifyUserSave($request, $userEntity->getDisplayname(), $userEntity->getEmail(), $firstuser); } else { $this->flashes()->error(Trans::__('page.edit-users.message.saving-user', ['%user%' => $userEntity->getDisplayname()])); } return $userEntity; }
/** * Send the password reset link notification to the user. * * @param Entity\Users $userEntity * @param string $shadowpassword * @param string $shadowtoken */ private function resetPasswordNotification(Entity\Users $userEntity, $shadowpassword, $shadowtoken) { $shadowlink = sprintf('%s%sresetpassword?token=%s', $this->app['resources']->getUrl('hosturl'), $this->app['resources']->getUrl('bolt'), urlencode($shadowtoken)); // Compile the email with the shadow password and reset link. $mailhtml = $this->app['render']->render('@bolt/mail/passwordreset.twig', ['user' => $userEntity, 'shadowpassword' => $shadowpassword, 'shadowtoken' => $shadowtoken, 'shadowvalidity' => date('Y-m-d H:i:s', strtotime('+2 hours')), 'shadowlink' => $shadowlink]); $subject = sprintf('[ Bolt / %s ] Password reset.', $this->app['config']->get('general/sitename')); $name = $this->app['config']->get('general/mailoptions/senderName', $this->app['config']->get('general/sitename')); $email = $this->app['config']->get('general/mailoptions/senderMail', $userEntity->getEmail()); $from = [$email => $name]; $message = $this->app['mailer']->createMessage('message')->setSubject($subject)->setFrom($from)->setReplyTo($from)->setTo([$userEntity->getEmail() => $userEntity->getDisplayname()])->setBody(strip_tags($mailhtml))->addPart($mailhtml, 'text/html'); $failed = true; $failedRecipients = []; try { $recipients = $this->app['mailer']->send($message, $failedRecipients); // Try and send immediately $this->app['swiftmailer.spooltransport']->getSpool()->flushQueue($this->app['swiftmailer.transport']); if ($recipients) { $this->app['logger.system']->info("Password request sent to '" . $userEntity->getDisplayname() . "'.", ['event' => 'authentication']); $failed = false; } } catch (\Exception $e) { // Notify below } if ($failed) { $this->app['logger.system']->error("Failed to send password request sent to '" . $userEntity['displayname'] . "'.", ['event' => 'authentication']); $this->app['logger.flash']->error(Trans::__('general.phrase.error-send-password-request')); } }
/** * Send the password reset link notification to the user. * * @param Entity\Users $userEntity * @param string $shadowPassword * @param string $shadowToken */ private function resetPasswordNotification(Entity\Users $userEntity, $shadowPassword, $shadowToken) { $config = $this->app['config']; $flash = $this->app['logger.flash']; $mailer = $this->app['mailer']; $logger = $this->app['logger.system']; $twig = $this->app['twig']; $urlGenerator = $this->app['url_generator']; $shadowLink = $urlGenerator->generate('resetpassword', ['token' => $shadowToken], UrlGeneratorInterface::ABSOLUTE_URL); // Compile the email with the shadow password and reset link. $mailHtml = $twig->render('@bolt/mail/passwordreset.twig', ['user' => $userEntity, 'shadowpassword' => $shadowPassword, 'shadowtoken' => $shadowToken, 'shadowvalidity' => Carbon::now()->addHours(2)->format('Y-m-d H:i:s'), 'shadowlink' => $shadowLink]); $subject = sprintf('[ Bolt / %s ] Password reset.', $config->get('general/sitename')); $name = $config->get('general/mailoptions/senderName', $config->get('general/sitename')); $email = $config->get('general/mailoptions/senderMail', $userEntity->getEmail()); $from = [$email => $name]; $message = $mailer->createMessage('message')->setSubject($subject)->setFrom($from)->setReplyTo($from)->setTo([$userEntity->getEmail() => $userEntity->getDisplayname()])->setBody(strip_tags($mailHtml))->addPart($mailHtml, 'text/html'); $failed = true; $failedRecipients = []; try { $recipients = $mailer->send($message, $failedRecipients); // Try and send immediately $this->app['swiftmailer.spooltransport']->getSpool()->flushQueue($this->app['swiftmailer.transport']); if ($recipients) { $logger->info("Password request sent to '" . $userEntity->getDisplayname() . "'.", ['event' => 'authentication']); $failed = false; } } catch (\Exception $e) { // Notify below } if ($failed) { $logger->error("Failed to send password request sent to '" . $userEntity['displayname'] . "'.", ['event' => 'authentication']); $flash->error(Trans::__('general.phrase.error-send-password-request')); } }
/** * Set the Authtoken cookie and DB-entry. If it's already present, update it. * * @param Entity\Users $userEntity * * @return Entity\Authtoken */ protected function updateAuthToken($userEntity) { $username = $userEntity->getUsername(); $cookieLifetime = (int) $this->cookieOptions['lifetime']; $tokenEntity = $this->getRepositoryAuthtoken()->getUserToken($userEntity->getUsername(), $this->getClientIp(), $this->getClientUserAgent()); if ($tokenEntity) { $token = $tokenEntity->getToken(); } else { $salt = $this->randomGenerator->generateString(32); $token = $this->getAuthToken($username, $salt); $tokenEntity = new Entity\Authtoken(); $tokenEntity->setUsername($userEntity->getUsername()); $tokenEntity->setToken($token); $tokenEntity->setSalt($salt); } $tokenEntity->setValidity(Carbon::create()->addSeconds($cookieLifetime)); $tokenEntity->setIp($this->getClientIp()); $tokenEntity->setLastseen(Carbon::now()); $tokenEntity->setUseragent($this->getClientUserAgent()); $this->getRepositoryAuthtoken()->save($tokenEntity); $this->systemLogger->debug("Saving new login token '{$token}' for user ID '{$username}'", ['event' => 'authentication']); return $tokenEntity; }
/** * Hash user passwords on save. * * @param Entity\Users $usersEntity */ protected function passwordHash(Entity\Users $usersEntity) { if ($usersEntity->getPassword() !== null) { $usersEntity->setPassword($this->getValidHash($usersEntity->getPassword())); } }
/** * Set user as enabled if user is new * * @param Entity\Users $usersEntity */ protected function enableUser(Entity\Users $usersEntity) { if ($usersEntity->getId() === null) { $usersEntity->setEnabled(true); } }
/** * Null sensitive data that doesn't need to be passed around. * * @param Entity\Users $entity */ protected function unsetSensitiveFields(Entity\Users $entity) { $entity->setPassword(null); $entity->setShadowpassword(null); $entity->setShadowtoken(null); $entity->setShadowvalidity(null); }
/** * Set user as enabled if user is new * * @param Entity\Users $usersEntity */ protected function enableUser(Entity\Users $usersEntity) { if ($usersEntity->getShadowSave()) { return; } elseif ($usersEntity->getId() === null) { $usersEntity->setEnabled(true); } }
/** * Check if stored user object is enabled. * * @return boolean|null */ public function isEnabled() { return $this->user->getEnabled(); }
public function testIsValidSessionValidWithDbTokenNoDbUser() { $this->markTestIncomplete('Requires upcoming refactor of Repository DI'); $app = $this->getApp(); $this->addDefaultUser($app); $userName = '******'; $salt = 'vinagre'; $ipAddress = '8.8.8.8'; // $hostName = 'bolt.dev'; $userAgent = 'Bolt PHPUnit tests'; // $cookieOptions = [ // 'remoteaddr' => true, // 'httphost' => true, // 'browseragent' => false, // ]; // $logger = $this->getMock('\Bolt\Logger\FlashLogger', ['info']); // $logger->expects($this->atLeastOnce()) // ->method('info') // ->with($this->equalTo('You have been logged out.')); // $app['logger.flash'] = $logger; // $app->boot(); $userEntity = new Entity\Users(); $userEntity->setUsername($userName); $tokenEntity = new Entity\Authtoken(); $tokenEntity->setUsername($userName); $tokenEntity->setToken('gum-leaves'); $tokenEntity->setSalt($salt); $tokenEntity->setIp($ipAddress); $tokenEntity->setUseragent('Bolt PHPUnit tests'); $repo = $app['storage']->getRepository('Bolt\\Storage\\Entity\\Authtoken'); $repo->save($tokenEntity); $token = new Token($userEntity, $tokenEntity); $request = Request::createFromGlobals(); $request->server->set('REMOTE_ADDR', $ipAddress); $request->server->set('HTTP_USER_AGENT', $userAgent); $request->cookies->set($app['token.authentication.name'], $token); $app['request_stack']->push($request); $app['session']->start(); $app['session']->set('authentication', $token); $accessControl = $this->getAccessControl(); $this->assertInstanceOf('Bolt\\AccessControl\\AccessChecker', $accessControl); $mockAuth = $this->getMock('Bolt\\Storage\\Entity\\Authtoken', ['getToken']); $mockAuth->expects($this->once())->method('getToken'); $app['storage']->setRepository('Bolt\\Storage\\Entity\\Authtoken', $mockAuth); $mockUser = $this->getMock('Bolt\\Storage\\Entity\\Users', ['getUser']); $mockUser->expects($this->never())->method('getUser'); $app['storage']->setRepository('Bolt\\Storage\\Entity\\Users', $mockUser); $response = $accessControl->isValidSession($token); $this->assertFalse($response); }
/** * Delete active session files for a user. * * @param Entity\Users $user */ private function deleteSessions(Entity\Users $user) { $savePath = $this->sessionStorage->getOptions()->get('save_path'); try { $sessionFiles = $this->filesystem->find()->files()->in($savePath); } catch (FileNotFoundException $e) { return; } /** @var \Bolt\Filesystem\Handler\File $sessionFile */ foreach ($sessionFiles as $sessionFile) { $data = unserialize($sessionFile->read()); if (!isset($data['_sf2_attributes']['authentication'])) { continue; } if (!$data['_sf2_attributes']['authentication'] instanceof \Bolt\AccessControl\Token\Token) { continue; } /** @var \Bolt\AccessControl\Token\Token $token */ $token = $data['_sf2_attributes']['authentication']; if ($token->getUser()->getId() === $user->getId()) { $sessionFile->delete(); } } }
/** * Create a stub for a new/empty user. * * @return array */ public function getEmptyUser() { $userEntity = new Entity\Users(); return $userEntity->toArray(); }
/** * Set the Authtoken cookie and DB-entry. If it's already present, update it. * * @param Entity\Users $userEntity * * @return Entity\Authtoken */ protected function updateAuthToken($userEntity) { $salt = $this->randomGenerator->generateString(32); if (!($tokenEntity = $this->repositoryAuthtoken->getUserToken($userEntity->getUsername(), $this->remoteIP, $this->userAgent))) { $tokenEntity = new Entity\Authtoken(); } $username = $userEntity->getUsername(); $token = $this->getAuthToken($username, $salt); $validityPeriod = $this->cookieOptions['lifetime']; $validityDate = new \DateTime(); $validityInterval = new \DateInterval("PT{$validityPeriod}S"); $tokenEntity->setUsername($userEntity->getUsername()); $tokenEntity->setToken($token); $tokenEntity->setSalt($salt); $tokenEntity->setValidity($validityDate->add($validityInterval)); $tokenEntity->setIp($this->remoteIP); $tokenEntity->setLastseen(new \DateTime()); $tokenEntity->setUseragent($this->userAgent); $this->repositoryAuthtoken->save($tokenEntity); $this->systemLogger->debug("Saving new login token '{$token}' for user ID '{$username}'", ['event' => 'authentication']); return $tokenEntity; }