/** * Logs in a user. * * @param \Symfony\Component\HttpFoundation\Request $request * The request. * * @return \Symfony\Component\HttpFoundation\Response * A response which contains the ID and CSRF token. */ public function login(Request $request) { $format = $this->getRequestFormat($request); $content = $request->getContent(); $credentials = $this->serializer->decode($content, $format); if (!isset($credentials['name']) && !isset($credentials['pass'])) { throw new BadRequestHttpException('Missing credentials.'); } if (!isset($credentials['name'])) { throw new BadRequestHttpException('Missing credentials.name.'); } if (!isset($credentials['pass'])) { throw new BadRequestHttpException('Missing credentials.pass.'); } $this->floodControl($request, $credentials['name']); if ($this->userIsBlocked($credentials['name'])) { throw new BadRequestHttpException('The user has not been activated or is blocked.'); } if ($uid = $this->userAuth->authenticate($credentials['name'], $credentials['pass'])) { $this->flood->clear('user.http_login', $this->getLoginFloodIdentifier($request, $credentials['name'])); /** @var \Drupal\user\UserInterface $user */ $user = $this->userStorage->load($uid); $this->userLoginFinalize($user); // Send basic metadata about the logged in user. $response_data = []; if ($user->get('uid')->access('view', $user)) { $response_data['current_user']['uid'] = $user->id(); } if ($user->get('roles')->access('view', $user)) { $response_data['current_user']['roles'] = $user->getRoles(); } if ($user->get('name')->access('view', $user)) { $response_data['current_user']['name'] = $user->getAccountName(); } $response_data['csrf_token'] = $this->csrfToken->get('rest'); $logout_route = $this->routeProvider->getRouteByName('user.logout.http'); // Trim '/' off path to match \Drupal\Core\Access\CsrfAccessCheck. $logout_path = ltrim($logout_route->getPath(), '/'); $response_data['logout_token'] = $this->csrfToken->get($logout_path); $encoded_response_data = $this->serializer->encode($response_data, $format); return new Response($encoded_response_data); } $flood_config = $this->config('user.flood'); if ($identifier = $this->getLoginFloodIdentifier($request, $credentials['name'])) { $this->flood->register('user.http_login', $flood_config->get('user_window'), $identifier); } // Always register an IP-based failed login event. $this->flood->register('user.failed_login_ip', $flood_config->get('ip_window')); throw new BadRequestHttpException('Sorry, unrecognized username or password.'); }
/** * {@inheritdoc} */ public function authenticate(Request $request) { $flood_config = $this->configFactory->get('user.flood'); $username = $request->headers->get('PHP_AUTH_USER'); $password = $request->headers->get('PHP_AUTH_PW'); // Flood protection: this is very similar to the user login form code. // @see \Drupal\user\Form\UserLoginForm::validateAuthentication() // Do not allow any login from the current user's IP if the limit has been // reached. Default is 50 failed attempts allowed in one hour. This is // independent of the per-user limit to catch attempts from one IP to log // in to many different user accounts. We have a reasonably high limit // since there may be only one apparent IP for all users at an institution. if ($this->flood->isAllowed('basic_auth.failed_login_ip', $flood_config->get('ip_limit'), $flood_config->get('ip_window'))) { $accounts = $this->entityManager->getStorage('user')->loadByProperties(array('name' => $username, 'status' => 1)); $account = reset($accounts); if ($account) { if ($flood_config->get('uid_only')) { // Register flood events based on the uid only, so they apply for any // IP address. This is the most secure option. $identifier = $account->id(); } else { // The default identifier is a combination of uid and IP address. This // is less secure but more resistant to denial-of-service attacks that // could lock out all users with public user names. $identifier = $account->id() . '-' . $request->getClientIP(); } // Don't allow login if the limit for this user has been reached. // Default is to allow 5 failed attempts every 6 hours. if ($this->flood->isAllowed('basic_auth.failed_login_user', $flood_config->get('user_limit'), $flood_config->get('user_window'), $identifier)) { $uid = $this->userAuth->authenticate($username, $password); if ($uid) { $this->flood->clear('basic_auth.failed_login_user', $identifier); return $this->entityManager->getStorage('user')->load($uid); } else { // Register a per-user failed login event. $this->flood->register('basic_auth.failed_login_user', $flood_config->get('user_window'), $identifier); } } } } // Always register an IP-based failed login event. $this->flood->register('basic_auth.failed_login_ip', $flood_config->get('ip_window')); return []; }
/** * Checks supplied username/password against local users table. * * If successful, $form_state->get('uid') is set to the matching user ID. */ public function validateAuthentication(array &$form, FormStateInterface $form_state) { $password = trim($form_state->getValue('pass')); $flood_config = $this->config('user.flood'); if (!$form_state->isValueEmpty('name') && !empty($password)) { // Do not allow any login from the current user's IP if the limit has been // reached. Default is 50 failed attempts allowed in one hour. This is // independent of the per-user limit to catch attempts from one IP to log // in to many different user accounts. We have a reasonably high limit // since there may be only one apparent IP for all users at an institution. if (!$this->flood->isAllowed('user.failed_login_ip', $flood_config->get('ip_limit'), $flood_config->get('ip_window'))) { $form_state->set('flood_control_triggered', 'ip'); return; } $accounts = $this->userStorage->loadByProperties(array('name' => $form_state->getValue('name'), 'status' => 1)); $account = reset($accounts); if ($account) { if ($flood_config->get('uid_only')) { // Register flood events based on the uid only, so they apply for any // IP address. This is the most secure option. $identifier = $account->id(); } else { // The default identifier is a combination of uid and IP address. This // is less secure but more resistant to denial-of-service attacks that // could lock out all users with public user names. $identifier = $account->id() . '-' . $this->getRequest()->getClientIP(); } $form_state->set('flood_control_user_identifier', $identifier); // Don't allow login if the limit for this user has been reached. // Default is to allow 5 failed attempts every 6 hours. if (!$this->flood->isAllowed('user.failed_login_user', $flood_config->get('user_limit'), $flood_config->get('user_window'), $identifier)) { $form_state->set('flood_control_triggered', 'user'); return; } } // We are not limited by flood control, so try to authenticate. // Store $uid in form state as a flag for self::validateFinal(). $uid = $this->userAuth->authenticate($form_state->getValue('name'), $password); $form_state->set('uid', $uid); } }
/** * Mostly copied from the basic_auth module * * @param $loginInfo * @param null $extra * @return array|\Drupal\Core\Entity\EntityInterface|null */ public function processAuthenticate($loginInfo, $extra = null) { if (is_string($loginInfo) && $loginInfo == strtolower("anonymous")) { return $this->processAnonymous(); } if (is_string($loginInfo)) { return $this->processToken($loginInfo); } if (isset($loginInfo['user']) && isset($loginInfo['pass'])) { $username = $loginInfo['user']; $password = $loginInfo['pass']; } else { return array("FAILURE"); } // $flood_config = $this->configFactory->get('user.flood'); // // // Flood protection: this is very similar to the user login form code. // // @see \Drupal\user\Form\UserLoginForm::validateAuthentication() // // Do not allow any login from the current user's IP if the limit has been // // reached. Default is 50 failed attempts allowed in one hour. This is // // independent of the per-user limit to catch attempts from one IP to log // // in to many different user accounts. We have a reasonably high limit // // since there may be only one apparent IP for all users at an institution. // if ($this->flood->isAllowed( // 'thruway_auth.failed_login_ip', // $flood_config->get('ip_limit'), // $flood_config->get('ip_window') // ) // ) { $accounts = $this->entityManager->getStorage('user')->loadByProperties(array('name' => $username, 'status' => 1)); $account = reset($accounts); if ($account) { // if ($flood_config->get('uid_only')) { // // Register flood events based on the uid only, so they apply for any // // IP address. This is the most secure option. // $identifier = $account->id(); // } else { // // The default identifier is a combination of uid and Session IP address. This // // is less secure but more resistant to denial-of-service attacks that // // could lock out all users with public user names. // $identifier = $account->id() . '-' . $this->getSession()->getSessionId(); // } // // Don't allow login if the limit for this user has been reached. // // Default is to allow 5 failed attempts every 6 hours. // if ($this->flood->isAllowed( // 'thruway_auth.failed_login_user', // $flood_config->get('user_limit'), // $flood_config->get('user_window'), // $identifier // ) // ) { $uid = $this->userAuth->authenticate($username, $password); if ($uid) { // $this->flood->clear('thruway_auth.failed_login_user', $identifier); return ["SUCCESS", ["authid" => $this->entityManager->getStorage('user')->load($uid)->getEmail()]]; } // else { // // Register a per-user failed login event. // $this->flood->register( // 'thruway_auth.failed_login_user', // $flood_config->get('user_window'), // $identifier // ); // } // } // } } // Always register an IP-based failed login event. // $this->flood->register('basic_auth.failed_login_ip', $flood_config->get('ip_window')); return array("FAILURE"); }