/** * 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; }