You are here

class SamlUserService in SAML Authentication 8

Class SamlUserService.

@package Drupal\samlauth

Hierarchy

Expanded class hierarchy of SamlUserService

1 file declares its use of SamlUserService
SamlController.php in src/Controller/SamlController.php
Contains Drupal\samlauth\Controller\SamlController.
1 string reference to 'SamlUserService'
samlauth.services.yml in ./samlauth.services.yml
samlauth.services.yml
1 service uses SamlUserService
samlauth.saml_user in ./samlauth.services.yml
Drupal\samlauth\SamlUserService

File

src/SamlUserService.php, line 19
Contains Drupal\samlauth\SamlService.

Namespace

Drupal\samlauth
View source
class SamlUserService {

  /**
   * Instance of UserDataInterface.
   *
   * @var Drupal\user\UserDataInterface $user_data
   */
  protected $user_data;

  /**
   * Instance of ConfigFactoryInterface.
   *
   * @var Drupal\Core\Config\ConfigFactoryInterface $config
   */
  protected $config;

  /**
   * Constructor for SamlUserService.
   *
   * @param \Drupal\user\UserDataInterface $user_data
   */
  public function __construct(UserDataInterface $user_data) {
    $this->user_data = $user_data;

    // @TODO: How should this be injected?
    $this->config = \Drupal::config('samlauth.authentication');
  }

  /**
   * Find a user by a given SAML unique ID.
   *
   * @param string $id
   *   The unique ID to search for.
   * @return integer|null
   *   The uid of the matching user or NULL if we can't find one.
   */
  public function findUidByUniqueId($id) {
    $return = $this->user_data
      ->get('samlauth', NULL, 'saml_id', $id);
    if (empty($return)) {
      $return = NULL;
    }
    elseif (is_array($return)) {
      if (count($return) === 1) {
        $return = reset($return);
      }
      else {
        throw new Exception('There are duplicates of the unique ID.');
      }
    }
    return $return;
  }

  /**
   * Take appropriate action on provided SAML data.
   *
   * @param array $saml_data
   * @throws \Exception
   */
  public function handleSamlData(array $saml_data) {
    $unique_id_attribute = $this->config
      ->get('unique_id_attribute');

    // We depend on the unique ID being present, so make sure it's there.
    if (!isset($saml_data[$unique_id_attribute][0])) {
      throw new Exception('Configured unique ID is not present in SAML response!');
    }
    $unique_id = $saml_data[$unique_id_attribute][0];
    $uid = $this
      ->findUidByUniqueId($unique_id);
    if (!$uid) {
      $mail_attribute = $this->config
        ->get('map_users_email');
      if ($this->config
        ->get('map_users') && ($account = user_load_by_mail($saml_data[$mail_attribute]))) {
        $this
          ->associateSamlIdWithAccount($unique_id, $account);
      }
      else {
        if ($this->config
          ->get('create_users')) {
          $account = $this
            ->createUserFromSamlData($saml_data);
        }
        else {
          throw new Exception('No existing user account matches the SAML ID provided. This authentication service is not configured to create new accounts.');
        }
      }
    }
    else {
      $account = User::load($uid);
    }
    if ($account
      ->isBlocked()) {
      throw new Exception('Requested account is blocked.');
    }
    user_login_finalize($account);
  }

  /**
   * Ends the current session.
   */
  public function logout() {
    user_logout();
  }

  /**
   * Returns the route name that users will be redirected to after authenticating.
   *
   * @return string
   * @todo make this configurable
   */
  public function getPostLoginDestination() {
    return 'user.page';
  }

  /**
   * Returns the route name that users will be redirected to after logging out.
   *
   * @return string
   * @todo make this configurable
   */
  public function getPostLogoutDestination() {
    return '<front>';
  }

  /**
   * Create a new user from SAML response data.
   *
   * @param array $saml_data
   * @return static
   * @throws \Exception
   */
  protected function createUserFromSamlData(array $saml_data) {
    $user_unique_attribute = $this->config
      ->get('unique_id_attribute');
    $user_name_attribute = $this->config
      ->get('user_name_attribute');
    $user_mail_attribute = $this->config
      ->get('user_mail_attribute');
    if (!isset($saml_data[$user_name_attribute][0])) {
      throw new Exception('Missing name attribute.');
    }
    if (!isset($saml_data[$user_mail_attribute][0])) {
      throw new Exception('Missing mail attribute.');
    }
    $account = User::create();
    $account
      ->setUsername($saml_data[$user_name_attribute][0]);
    $account
      ->setPassword(user_password(50));
    $account
      ->setEmail($saml_data[$user_mail_attribute][0]);
    $account
      ->activate();

    // Allow other users to change/set user properties before saving.
    \Drupal::moduleHandler()
      ->alter('samlauth_new_user', $account, $saml_data);
    $account
      ->save();

    // Save the unique ID for later use.
    $this
      ->associateSamlIdWithAccount($saml_data[$user_unique_attribute][0], $account);
    return $account;
  }

  /**
   * Ensure that a SAML id is associated with a given user account.
   *
   * This function is idempotent.
   *
   * @param $saml_id
   * @param \Drupal\Core\Session\AccountInterface $account
   */
  protected function associateSamlIdWithAccount($saml_id, AccountInterface $account) {
    $this->user_data
      ->set('samlauth', $account
      ->id(), 'saml_id', $saml_id);
  }

}

Members

Namesort descending Modifiers Type Description Overrides
SamlUserService::$config protected property Instance of ConfigFactoryInterface.
SamlUserService::$user_data protected property Instance of UserDataInterface.
SamlUserService::associateSamlIdWithAccount protected function Ensure that a SAML id is associated with a given user account.
SamlUserService::createUserFromSamlData protected function Create a new user from SAML response data.
SamlUserService::findUidByUniqueId public function Find a user by a given SAML unique ID.
SamlUserService::getPostLoginDestination public function Returns the route name that users will be redirected to after authenticating.
SamlUserService::getPostLogoutDestination public function Returns the route name that users will be redirected to after logging out.
SamlUserService::handleSamlData public function Take appropriate action on provided SAML data.
SamlUserService::logout public function Ends the current session.
SamlUserService::__construct public function Constructor for SamlUserService.