You are here

function samlauth_check_saml_user in SAML Authentication 4.x

Same name and namespace in other branches
  1. 8.3 samlauth.module \samlauth_check_saml_user()
  2. 8 samlauth.module \samlauth_check_saml_user()
  3. 8.2 samlauth.module \samlauth_check_saml_user()
  4. 7 samlauth.module \samlauth_check_saml_user()

Validation callback for SAML users logging in through the normal methods.

2 string references to 'samlauth_check_saml_user'
samlauth_form_user_login_form_alter in ./samlauth.module
Implements hook_form_FORM_ID_alter() for the login form.
samlauth_form_user_pass_alter in ./samlauth.module
Implements hook_form_FORM_ID_alter() for the password reset form.

File

./samlauth.module, line 93
Allows users to authenticate against an external SAML identity provider.

Code

function samlauth_check_saml_user(&$form, FormStateInterface $form_state) {

  // If previous validation has already failed (name/pw incorrect or blocked),
  // bail out so we don't disclose any details about a user that otherwise
  // wouldn't be authenticated. Also skip unworkable form state.
  if (!$form_state
    ->hasAnyErrors() && $form_state
    ->hasValue('name')) {

    // If the user has logged into the site using samlauth before, block them
    // if they don't have a role that is allowed to log in locally. The 'name'
    // element may contain a user name or e-mail address; the latter happens
    // for the password reset form, and for the login form if certain contrib
    // modules are installed.

    /** @var \Drupal\user\Entity\User $account */
    $account = user_load_by_name($form_state
      ->getValue('name'));
    if (!$account) {
      $account = user_load_by_mail($form_state
        ->getValue('name'));
    }
    if (!$account) {
      $form_state
        ->setErrorByName('name', t('Could not load user to do a validation check.'));
    }
    elseif (!array_intersect($account
      ->getRoles(), \Drupal::config(SamlController::CONFIG_OBJECT_NAME)
      ->get('drupal_login_roles') ?? [])) {

      /** @var \Drupal\externalauth\AuthmapInterface $authmap */
      $authmap = \Drupal::service('externalauth.authmap');
      if ($authmap
        ->get($account
        ->id(), 'samlauth')) {

        // Are we allowed to tell the user why they cannot use this form, or
        // should we use the exact same messages as when a user does not exist
        // (to prevent disclosing info about which accounts exist)?
        if (\Drupal::config(SamlController::CONFIG_OBJECT_NAME)
          ->get('local_login_saml_error')) {
          $form_state
            ->setErrorByName('name', t('This user is only allowed to log in through an external authentication provider.'));
        }
        elseif (!isset($form['#form_id']) || $form['#form_id'] !== 'user_pass') {
          $query = $form_state
            ->hasValue('name') ? [
            'name' => $form_state
              ->getValue('name'),
          ] : [];
          $form_state
            ->setErrorByName('name', t('Unrecognized username or password. <a href=":password">Forgot your password?</a>', [
            ':password' => Url::fromRoute('user.pass', [], [
              'query' => $query,
            ])
              ->toString(),
          ]));
          \Drupal::logger('user')
            ->notice('Local login attempt denied to SAML-only account %user.', [
            '%user' => $form_state
              ->getValue('name'),
          ]);
        }
        else {
          if (version_compare(\Drupal::VERSION, '9.2.0-dev') >= 0) {
            \Drupal::messenger()
              ->addStatus(t('If %identifier is a valid account, an email will be sent with instructions to reset your password.', [
              '%identifier' => $form_state
                ->getValue('name'),
            ]));
          }
          else {
            \Drupal::messenger()
              ->addStatus(t('Further instructions have been sent to your email address.'));
          }
          \Drupal::logger('user')
            ->notice('Prevented sending password reset instructions mailed to %name at %email.', [
            '%name' => $account
              ->getAccountName(),
            '%email' => $account
              ->getEmail(),
          ]);

          // Prevent executing the submit callback that sends the mail and
          // prints the same message.
          $form['#submit'] = [];
        }
      }
    }
  }
}