You are here

function saml_sp_drupal_login__saml_authenticate in SAML Service Provider 3.x

Same name and namespace in other branches
  1. 8.3 modules/saml_sp_drupal_login/saml_sp_drupal_login.module \saml_sp_drupal_login__saml_authenticate()
  2. 8.2 modules/saml_sp_drupal_login/saml_sp_drupal_login.module \saml_sp_drupal_login__saml_authenticate()
  3. 7.8 modules/saml_sp_drupal_login/saml_sp_drupal_login.module \saml_sp_drupal_login__saml_authenticate()
  4. 7 modules/saml_sp_drupal_login/saml_sp_drupal_login.module \saml_sp_drupal_login__saml_authenticate()
  5. 7.2 modules/saml_sp_drupal_login/saml_sp_drupal_login.module \saml_sp_drupal_login__saml_authenticate()
  6. 7.3 modules/saml_sp_drupal_login/saml_sp_drupal_login.module \saml_sp_drupal_login__saml_authenticate()
  7. 4.x modules/saml_sp_drupal_login/saml_sp_drupal_login.module \saml_sp_drupal_login__saml_authenticate()

SAML authentication callback.

1 string reference to 'saml_sp_drupal_login__saml_authenticate'
SamlSPDrupalLoginController::initiate in modules/saml_sp_drupal_login/src/Controller/SamlSPDrupalLoginController.php
Initiate a SAML login for the given IdP.

File

modules/saml_sp_drupal_login/saml_sp_drupal_login.module, line 99
SAML Drupal Login.

Code

function saml_sp_drupal_login__saml_authenticate($is_valid, Response $saml_response, Idp $idp) {
  $redirect_url = $_POST['RelayState'] ?: Url::fromRoute('<front>')
    ->toString();
  if (!$is_valid) {
    \Drupal::messenger()
      ->addError(t('Could not authenticate via %idp_label', [
      '%idp_label' => $idp
        ->label(),
    ]));
    \Drupal::logger('saml_sp')
      ->warning('Could not authenticate via %idp_label', [
      '%idp_label' => $idp
        ->label(),
    ]);
    return new RedirectResponse($redirect_url);
  }
  $attributes = $saml_response
    ->getAttributes();

  // Get the NameID value from response.
  $name_id = $saml_response
    ->getNameId();
  if (\Drupal::config('saml_sp.settings')
    ->get('debug')) {
    _saml_sp__debug('Response NameId', $name_id);
  }

  // If email address is not used to identify user,
  // it has to be in the attributes.
  if ($idp
    ->getNameIdField() != 'mail') {

    // Try to get email from SAML response attributes.
    try {
      $email = $attributes['mail'][0];
    } catch (Exception $e) {
      \Drupal::logger('saml_sp')
        ->error('No mail attribute available; please check IdP %idp_label configuration. Exception message: %exception', [
        '%idp_label' => $idp
          ->label(),
        '%exception' => $e->message,
      ]);

      // TODO: should we give up here and not allow authentication?
    }
  }
  else {
    $email = $name_id;
  }
  $site_register_access = \Drupal::config('user.settings')
    ->get('register');
  $config = \Drupal::config('saml_sp_drupal_login.config');
  $success = FALSE;
  if ($user = saml_sp_drupal_login_get_user($name_id, $idp
    ->getNameIdField(), $email)) {

    // Successful login to existing user account.
    $success = TRUE;
  }
  elseif ($site_register_access == UserInterface::REGISTER_VISITORS) {

    // Successful authentication, but no user account.
    // New users are allowed to register.
    $language = \Drupal::languageManager()
      ->getCurrentLanguage()
      ->getId();
    $user = User::create();

    // Mandatory:
    $user
      ->setPassword(random_bytes(64));
    $user
      ->enforceIsNew();
    $user
      ->setEmail($email);
    $user
      ->setUsername($email);

    // Optional:
    $user
      ->set('init', $email);
    $user
      ->set('langcode', $language);
    $user
      ->set('preferred_langcode', $language);
    $user
      ->set('preferred_admin_langcode', $language);

    /*
        $user->set('setting_name', 'setting_value');
        $user->addRole('rid');
        /**/

    // Activate and save user account.
    $user
      ->activate();
    $result = $user
      ->save();
    \Drupal::logger('saml_sp')
      ->notice('New SSO user account for %mail with UID %uid.', [
      '%mail' => $email,
      '%uid' => $user
        ->id(),
    ]);
    $success = TRUE;
  }
  elseif ($config
    ->get('no_account_authenticated_user_role') && $config
    ->get('no_account_authenticated_user_account')) {

    // Successful authentication, but no user account.
    // The setting allows for them to get an authenticated role.
    $user = User::load($config
      ->get('no_account_authenticated_user_account'));
    if (empty($user)) {
      \Drupal::messenger()
        ->addError(t('You have been authenticated but there is no account available for you to continue logging in. Please contact a site administrator.'));
      \Drupal::logger('saml_sp')
        ->notice('User authenticated via %idp_label with email %mail, cannot grant access to generic account as the generic account could not be loaded.', [
        '%idp_label' => $idp
          ->label(),
        '%mail' => $email,
      ]);
      $success = FALSE;
    }
    else {
      \Drupal::logger('saml_sp')
        ->notice('User authenticated via %idp_label with email %mail, granted access to %name account.', [
        '%idp_label' => $idp
          ->label(),
        '%mail' => $email,
        '%name' => $user
          ->getAccountName(),
      ]);
      $success = TRUE;
    }
  }
  else {

    // Successful authentication, but no user account.
    $_SESSION['authenticated_via_saml_sp'] = TRUE;
    $tokens = [
      '%mail' => $email,
      '%idp_label' => $idp
        ->label(),
    ];
    $rvaa = $site_register_access == UserInterface::REGISTER_VISITORS_ADMINISTRATIVE_APPROVAL;
    $arra = $config
      ->get('account_request_request_account');
    if (!$rvaa && !$arra) {

      // Only administrators can register new users.
      $no_account_message = t('No account matching %mail has been found. Please contact a site administrator.', $tokens);
      \Drupal::messenger()
        ->addWarning($no_account_message);
    }
    else {

      // The user is allowed to request an account from administrators.
      // Do not create an account, and redirect to the registration page.
      if ($rvaa) {

        // User is allowed to request by account settings.
        $registration_route = 'user.register';
      }
      else {

        // User is allowed to request by SAML SP Drupal Login settings.
        $registration_route = 'saml_sp_drupal_login.register';
      }
      \Drupal::messenger()
        ->addWarning(t('This site requires you to request an account.'));
      $redirect_url = Url::fromRoute($registration_route, [], [
        'query' => [
          'email' => $email,
        ],
      ])
        ->toString();
    }
    \Drupal::logger('saml_sp')
      ->warning("User attempting to login through %idp_label with %mail which doesn't match any accounts.", $tokens);
  }
  if ($success) {

    // @see user_login_name_validate().
    if ($user
      ->isBlocked() || !$user
      ->isActive()) {
      \Drupal::messenger()
        ->addError(t('The username %name has not been activated or is blocked.', [
        '%name' => $user
          ->getAccountName(),
      ]));
      if (\Drupal::config('saml_sp.settings')
        ->get('debug')) {
        _saml_sp__debug('Account', $this);
        _saml_sp__debug('Response NameId', $name_id);
      }
    }
    else {

      // TODO: this might not be the right place for this. It doesn't do
      // anything right now anyway.
      saml_sp_drupal_login_update_user_attributes($user, $email, $attributes);
      \Drupal::logger('saml_sp')
        ->notice('User %name logging in through SAML via %idp_name. with NameID %mail', [
        '%name' => $user
          ->getAccountName(),
        '%idp_name' => $idp
          ->label(),
        '%mail' => $email,
      ]);

      // Store the fact that the user logged in via the SAML SP module.
      $_SESSION['authenticated_via_saml_sp'] = TRUE;
      user_login_finalize($user);
    }
  }
  return new RedirectResponse($redirect_url);
}