/**
  * Builds a signed in user object for a given user ID and signs
  * the user into the session storage. This method should be used
  * by authentication strategies to build a signed in session once
  * a user is authenticated.
  *
  * NOTE: If 2FA is enabled, and a user requires it, then the returned
  * user will not be marked as signed in. It's up to the middleware
  * layer to detect when a user needs 2FA and act accordingly.
  *
  * @param UserInterface $user
  * @param string        $strategy
  * @param bool          $remember whether to enable remember me on this session
  *
  * @throws AuthException when the user could not be signed in.
  *
  * @return UserInterface authenticated user model
  */
 public function signInUser(UserInterface $user, $strategy = 'web', $remember = false)
 {
     // sign in the user with the session storage
     $storage = $this->getStorage();
     $result = $storage->signIn($user, $this->request, $this->response);
     if (!$result) {
         throw new AuthException('Could not sign in user');
     }
     // if a user needs 2FA verification then they cannot
     // be completely signed in until they verify using 2FA
     $twoFactor = $this->getTwoFactorStrategy();
     if ($twoFactor && !$user->isTwoFactorVerified() && $twoFactor->needsVerification($user)) {
         $this->app['user'] = $user;
         return $user->markSignedOut();
     }
     // use a remember me session (lasts longer)
     if ($remember) {
         $result = $storage->remember($user, $this->request, $this->response);
         if (!$result) {
             throw new AuthException('Could not enable remember me for user session');
         }
     }
     if ($user->id() > 0) {
         // mark the user model as signed in
         $user->markSignedIn();
         // record the login event
         $event = new AccountSecurityEvent();
         $event->user_id = $user->id();
         $event->type = AccountSecurityEvent::LOGIN;
         $event->ip = $this->request->ip();
         $event->user_agent = $this->request->agent();
         $event->auth_strategy = $strategy;
         $event->save();
     } else {
         // mark the user model as not signed in since this user
         // is a guest of some sort
         $user->markSignedOut();
     }
     $this->app['user'] = $user;
     return $user;
 }
 /**
  * Sends the user a notification and records a security event
  * if the password was changed.
  *
  * @param ModelEvent $event
  */
 public static function passwordChanged(ModelEvent $event)
 {
     $user = $event->getModel();
     if (!$user->_changedPassword) {
         return;
     }
     $app = $user->getApp();
     $auth = $app['auth'];
     $req = $auth->getRequest();
     $ip = $req->ip();
     $userAgent = $req->agent();
     // record the reset password request event
     $event = new AccountSecurityEvent();
     $event->user_id = $user->id();
     $event->type = AccountSecurityEvent::CHANGE_PASSWORD;
     $event->ip = $ip;
     $event->user_agent = $userAgent;
     $event->save();
     // changing the password signs the user out, everywhere
     $auth->signOutAllSessions($user);
     $user->markSignedOut();
     if ($app['user'] && $app['user']->id() == $user->id()) {
         $auth->logout();
     }
     // send the user an email about it
     $user->sendEmail('password-changed', ['ip' => $ip]);
 }
 /**
  * Builds a reset password link.
  *
  * @param int    $userId
  * @param string $ip
  * @param string $userAgent
  *
  * @return UserLink
  */
 public function buildLink($userId, $ip, $userAgent)
 {
     $link = new UserLink();
     $link->user_id = $userId;
     $link->type = UserLink::FORGOT_PASSWORD;
     try {
         $link->save();
     } catch (\Exception $e) {
         throw new \Exception("Could not create reset password link for user # {$userId}: " . $e->getMessage());
     }
     // record the reset password request event
     $event = new AccountSecurityEvent();
     $event->user_id = $userId;
     $event->type = AccountSecurityEvent::RESET_PASSWORD_REQUEST;
     $event->ip = $ip;
     $event->user_agent = $userAgent;
     $event->save();
     return $link;
 }