You are here

simplesamlphp_auth.module in simpleSAMLphp Authentication 6.2

simpleSAMLphp authentication module for Drupal.

This authentication module is based on the shibboleth authentication module, with changes to adopt to use simpleSAMLphp.

@todo Rework the default login limitation logic to use a drupal permission rather than a list of UIDs. @todo When denying access because the administrator has chosen not to allow the module to register/create accounts, the user is told to contact the administrator; the message should provide the contact information. :ISSUE: Until Drupal issue #754560 is resolved users will not see logout notices.

File

simplesamlphp_auth.module
View source
<?php

/**
 * @file
 * simpleSAMLphp authentication module for Drupal.
 *
 * This authentication module is based on the shibboleth authentication module, with changes
 * to adopt to use simpleSAMLphp.
 *
 * @todo Rework the default login limitation logic to use a drupal permission rather
 *       than a list of UIDs.
 * @todo When denying access because the administrator has chosen not to allow the module
 *       to register/create accounts, the user is told to contact the administrator; the
 *       message should provide the contact information.
 * :ISSUE: Until Drupal issue #754560 is resolved users will not see logout notices.
 */

/**
 * Implementation of hook_menu().
 */
function simplesamlphp_auth_menu() {
  $items = array();
  $items['admin/user/simplesamlphp_auth'] = array(
    'title' => t('simpleSAMLphp authentication module settings'),
    'description' => t('Control the various settings of the simpleSAMLphp authentication module'),
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'simplesamlphp_auth_settings',
    ),
    'access arguments' => array(
      'administer simpleSAMLphp authentication',
    ),
    'type' => MENU_NORMAL_ITEM,
  );
  $items['saml_login'] = array(
    'title' => t('Logon to the site'),
    'description' => t('Provides a site login page'),
    'page callback' => 'simplesamlphp_auth_loginpage',
    'access callback' => TRUE,
    'type' => MENU_CALLBACK,
  );
  return $items;
}

/**
 * Implementation of hook_help().
 */
function simplesamlphp_auth_help($path, $arg) {
  switch ($path) {
    case 'admin/user/simplesamlphp_auth':
      $output = t('<p>This module integrates Drupal with a SimpleSAMLphp Service Point, effectively federating Drupal.</p>');
      $output .= t('<p></p>');
      return $output;
  }
}

/**
 * Implementation of hook_perm().
 */
function simplesamlphp_auth_perm() {
  return array(
    'administer simpleSAMLphp authentication',
  );
}

/**
 * Represents the Drupal page (saml_login), which triggers user authentication against the SimpleSAMLphp service provider.
 */
function simplesamlphp_auth_loginpage() {
  global $user, $base_root;
  global $_simplesamlphp_auth_as;
  global $_simplesamlphp_auth_saml_attributes;
  $fail = NULL;
  $output = NULL;
  if (!_simplesamlphp_auth_isEnabled()) {

    // Exit without initializing.
    drupal_set_message(t('We\'re sorry this feature is not yet enabled.'));
    return;
  }

  // Are we forcing https?
  if (variable_get('simplesamlphp_auth_forcehttps', NULL) && 'on' != $_SERVER['HTTPS']) {
    drupal_goto(_simplesamlphp_auth_forcehttps_rewrite($base_root . request_uri()));
  }

  // Do some sanity checking before attempting anything.
  $_simplesamlphp_auth_saml_config = SimpleSAML_Configuration::getInstance();
  $configStoreType = $_simplesamlphp_auth_saml_config
    ->getValue('store.type');

  // Make sure phpsession is NOT being used.
  if ($configStoreType == 'phpsession') {
    watchdog('simplesamlphp_auth', t('A user attempted to login using simplesamlphp but the store.type is phpsession, use memcache or sql for simplesamlphp session storage. See: simplesamlphp/config/config.php.'), NULL, WATCHDOG_WARNING);
    $fail = TRUE;
  }

  // Make sure there is an instance of SimpleSAML_Auth_Simple.
  if (!$_simplesamlphp_auth_as) {
    watchdog('simplesamlphp_auth', t('A user attempted to login using this module but there was a problem'), NULL, WATCHDOG_WARNING);
    $fail = TRUE;
  }

  // There was a problem, we can't go on, but we don't want to tell the user any specifics either.
  if ($fail) {
    drupal_set_message(t('We\'re sorry. There was a problem. The issue has been logged for the administrator.'));
    drupal_goto('/');
  }
  $_simplesamlphp_auth_authparms = NULL;

  // Support for deep linking.
  // See if a URL has been provided in ReturnTo.
  if (isset($_REQUEST['ReturnTo']) && $_REQUEST['ReturnTo'] && valid_url($_REQUEST['ReturnTo'])) {

    // we'll only use the REFERER if it points to this Drupal site.
    if (preg_match(base_path(), $_REQUEST['ReturnTo'])) {
      $_simplesamlphp_auth_authparms = array(
        'ReturnTo' => $_REQUEST['ReturnTo'],
      );
    }
  }
  elseif (isset($_SERVER['HTTP_REFERER']) && $_SERVER['HTTP_REFERER'] && valid_url($_SERVER['HTTP_REFERER'])) {

    // we'll only use the REFERER if it points to this Drupal site.
    if (preg_match(base_path(), $_SERVER['HTTP_REFERER'])) {
      $_simplesamlphp_auth_authparms = array(
        'ReturnTo' => $_SERVER['HTTP_REFERER'],
      );
    }
  }
  if ($user->uid == 0) {

    // Require the user to be authentcated.
    if (is_array($_simplesamlphp_auth_authparms)) {
      $_simplesamlphp_auth_as
        ->requireAuth($_simplesamlphp_auth_authparms);
    }
    else {
      $_simplesamlphp_auth_as
        ->requireAuth();
    }
  }
  else {

    // See if a ReturnTo has been set.
    if (isset($_simplesamlphp_auth_authparms['ReturnTo']) && $_simplesamlphp_auth_authparms['ReturnTo']) {

      // Using header() here feels like a kuldge. Drupal might have a more appropriate way to do this, but there is the possibility that the ReturnTo URL might be outside of the Drupal site.
      header('Location: ' . $_simplesamlphp_auth_authparms['ReturnTo']);
    }
    else {
      drupal_goto('user/' . $user->uid);
    }
  }
  return $output;
}

/**
 * Implementation of hook_init().
 */
function simplesamlphp_auth_init() {
  global $user;
  global $_simplesamlphp_auth_as;
  global $_simplesamlphp_auth_saml_attributes;
  global $_simplesamlphp_auth_saml_config;
  global $_simplesamlphp_auth_saml_version;
  if (!_simplesamlphp_auth_isEnabled(TRUE)) {

    // Exit without initializing.
    return;
  }

  // Get the simplesamlphp session.
  $basedir = variable_get('simplesamlphp_auth_installdir', '/var/simplesamlphp');

  // Make sure we know where SimpleSAMLphp is.
  if (!file_exists($basedir)) {
    $failure = t('SimpleSAMLphp could not be found at %basedir . The simplesamlphp_auth module cannot function until the path to the local SimpleSAMLphp instance is configured.', array(
      '%basedir' => $basedir,
    ));
    watchdog('simplesamlphp_auth', $failure, NULL, WATCHDOG_WARNING);
    if ($user->uid != 0) {
      drupal_set_message($failure);
    }

    // Exit without initializing.
    return;
  }
  require_once $basedir . '/lib/_autoload.php';
  $_simplesamlphp_auth_saml_config = SimpleSAML_Configuration::getInstance();
  $_simplesamlphp_auth_saml_version = $_simplesamlphp_auth_saml_config
    ->getVersion();

  // Load simpleSAMLphp, configuration and metadata.
  $_simplesamlphp_auth_as = new SimpleSAML_Auth_Simple(variable_get('simplesamlphp_auth_authsource', 'default-sp'));
  $_simplesamlphp_auth_saml_attributes = $_simplesamlphp_auth_as
    ->getAttributes();
  if ($user->uid == 0) {

    // User is not logged in - Drupal.
    if ($_simplesamlphp_auth_as
      ->isAuthenticated()) {

      // User is logged in - SimpleSAMLphp, user is not logged in - Drupal.
      // Get unique identifier from saml attributes.
      $authname = _simplesamlphp_auth_get_authname();
      _simplesaml_auth_debug(t('Authname is [%authname] userid is [%uid]', array(
        '%authname' => $authname,
        '%uid' => $user->uid,
      )));
      if (!empty($authname)) {

        // User is logged in with SAML authentication and we got the unique identifier.
        // Try to log into Drupal.
        _simplesaml_auth_debug(t('Load user [%authname]', array(
          '%authname' => $authname,
        )));

        // Retrieve user mapping and attempt to log the user in.
        $user = user_external_load($authname);
        if (!$user) {

          // If unsuccessful, register the user. This will trigger simplesamlphp_auth_user() and any other _user() hooks.
          // First we check the admin settings for simpleSAMLphp and find out if we are allowed to register users.
          if (variable_get('simplesamlphp_auth_registerusers', TRUE)) {

            // We are allowed to register new users.
            _simplesaml_auth_debug(t('Register [%authname]', array(
              '%authname' => $authname,
            )));
            user_external_login_register($authname, 'simplesamlphp_auth');
            if ($user) {

              // Populate roles based on configuration setting.
              $roles = _simplesamlphp_auth_rolepopulation(variable_get('simplesamlphp_auth_rolepopulation', ''));
              $userinfo = array(
                'roles' => $roles,
              );
              $user = user_save($user, $userinfo);

              // @todo - Fjernet rolle-delen her da den gav en bra feilmelding når roller ikke finnes ;)
            }
          }
          else {

            // We are not allowed to register new users on the site through simpleSAML.
            // We let the user know about this and redirect to the user/login page.
            $msg = t('We are sorry. While you have successfully authenticated, you are not yet entitled to access this site.
              Please ask the site administrator to provision access for you.');
            drupal_set_message($msg);
            $_simplesamlphp_auth_as
              ->logout('/?msg=' . $msg);
          }
        }
        else {

          // If successfully logged into Drupal.
          // See if we're supposed to re-evaluate role assignments.
          if (variable_get('simplesamlphp_auth_roleevaleverytime', 0)) {

            // If the user is already registered, update the roles and populate roles based on configuration setting.
            _simplesaml_auth_debug(t('User already registered [%authname] updating roles.', array(
              '%authname' => $authname,
            )));
            $roles = _simplesamlphp_auth_rolepopulation(variable_get('simplesamlphp_auth_rolepopulation', ''));
            $userinfo = array(
              'roles' => $roles,
            );
            $user = user_save($user, $userinfo);
          }
        }

        // Finalizing the login, calls hook_user op login.
        $edit = array();
        user_authenticate_finalize($edit);
      }

      // End if !empty authname.
    }

    // End if isset saml_session.
  }
  else {

    // The user is already logged into Drupal.
    // If we forbid users from loggin in using local accounts.
    if (FALSE == variable_get('simplesamlphp_auth_allowdefaultlogin', TRUE)) {

      // If the user has NOT been authenticated via simpleSAML.
      if (!$_simplesamlphp_auth_as
        ->isAuthenticated()) {

        // FYI: Until Drupal issue #754560 is corrected this message will never be seen by the user.
        drupal_set_message(t("We are sorry, users are not permitted to log in using local accounts."));

        // Destroy the user's session (log them out).
        _simplesamlphp_auth_destroy_drupal_session();
      }
    }
    else {

      // If we are allowing users to log in with local accounts.
      // If the user has NOT been authenticated via simpleSAML.
      if (!$_simplesamlphp_auth_as
        ->isAuthenticated()) {

        // See if we limit this privilege to specified users.
        $strAllwDefLogUsers = variable_get('simplesamlphp_auth_allowdefaultloginusers', '');
        $arrAllwDefLogUsers = array();

        // If user IDs are specified, we let them in, but everyone else gets logged out.
        if (drupal_strlen($strAllwDefLogUsers)) {

          // @todo perform a test to make sure that only numbers, spaces, or commas are in the string.
          // Convert the string into an array.
          $arrAllwDefLogUsers = explode(',', $strAllwDefLogUsers);

          // If we still have something to work with.
          if (0 < count($arrAllwDefLogUsers)) {

            // Log the user out of Drupal if the current user's uid is NOT in the list of allowed uids.
            if (!in_array($user->uid, $arrAllwDefLogUsers)) {

              // User is logged into Drupal, but may not be logged into simpleSAML.
              // If this is the case we're supposed to log the user out of Drupal.
              // FYI: Until Drupal issue #754560 is corrected this message will never be seen by the user.
              drupal_set_message(t("We are sorry, you are not permitted to log in using a local account."));
              _simplesamlphp_auth_destroy_drupal_session();
            }
          }
        }

        // End test for specified users.
      }

      // End if $_simplesamlphp_auth_as->isAuthenticated().
    }

    // End test to see if we allow default logins.
  }

  // End if user->uid.
}

/**
 * Implementation of hook_user().
 */
function simplesamlphp_auth_user($op, &$edit, &$account, $category = NULL) {
  global $_simplesamlphp_auth_as;
  global $_simplesamlphp_auth_saml_attributes;
  if ($op == 'insert' && ($category = 'account')) {

    // If user registration has a valid session.
    if ($_simplesamlphp_auth_as
      ->isAuthenticated()) {

      // Get name from default attributes.
      try {
        _simplesaml_auth_debug(t('Registering user [%acctname]', array(
          '%acctname' => $account->name,
        )));
        $account->name = _simplesamlphp_auth_get_default_name($account->uid);
      } catch (Exception $e) {
        $message = t('Username is missing.' . check_plain($e
          ->getMessage()));
        drupal_set_message(t($message), "error");
        watchdog('simplesamlphp', $message, WATCHDOG_CRITICAL);
      }
      db_query("UPDATE {users} SET name = '%s' WHERE uid = %d", $account->name, $account->uid);
      _simplesaml_auth_debug(t('Updating username [%acctname]', array(
        '%acctname' => $account->name,
      )));

      // Get mail from default attribute.
      try {
        $mail_address = _simplesamlphp_auth_get_mail();
      } catch (Exception $e) {
        $message = t('Email is missing.' . check_plain($e
          ->getMessage()));
        drupal_set_message(t($message), "error");
        watchdog('simplesamlphp', $message, WATCHDOG_CRITICAL);
      }
      if (!empty($mail_address)) {
        db_query("UPDATE {users} SET mail = '%s' WHERE uid = %d", $mail_address, $account->uid);
      }
      _simplesaml_auth_debug(t('Updating mail [%mailaddr]', array(
        '%mailaddr' => $mail_address,
      )));
    }
  }
  elseif ($op == 'logout') {
    if (!empty($_simplesamlphp_auth_saml_attributes)) {
      $config = SimpleSAML_Configuration::getInstance();
      $_simplesamlphp_auth_as
        ->logout(base_path());
    }
  }
  elseif ($op == "delete") {
    db_query("DELETE FROM {authmap} WHERE uid = %d AND authname = '%s' AND module = 'simplesamlphp_auth'", $account->uid, $account->name);
  }
}

/**
 * Implements settings for the module.
 */
function simplesamlphp_auth_settings() {
  global $_simplesamlphp_auth_saml_version;
  if (!empty($_simplesamlphp_auth_saml_version)) {
    $ver = explode('.', $_simplesamlphp_auth_saml_version);
    if ($ver[0] >= 1 && $ver[1] >= 5) {

      // Say nothing.
    }
    else {
      drupal_set_message(t('Please upgrade SimpleSAMLphp. You are using %ssp_version', array(
        '%ssp_version' => $_simplesamlphp_auth_saml_version,
      )), 'warning');
    }
  }
  $form = array(
    'simplesamlphp_auth_activate' => array(
      '#type' => 'checkbox',
      '#title' => t('Activate authentication via SimpleSAMLphp'),
      '#default_value' => variable_get('simplesamlphp_auth_activate', FALSE),
      '#description' => t('Checking this box before configuring the module could lock you out of Drupal.'),
    ),
    'simplesamlphp_auth_installdir' => array(
      '#type' => 'textfield',
      '#title' => t('Installation directory (default: /var/simplesamlphp)'),
      '#default_value' => variable_get('simplesamlphp_auth_installdir', '/var/simplesamlphp'),
      '#description' => t('The base directory of simpleSAMLphp. Absolute path with no trailing slash.'),
    ),
    'simplesamlphp_auth_authsource' => array(
      '#type' => 'textfield',
      '#title' => t('Autenticaton source for this SP (default: default-sp)'),
      '#default_value' => variable_get('simplesamlphp_auth_authsource', 'default-sp'),
      '#description' => t('The name of the source to use from /var/simplesamlphp/config/authsources.php'),
    ),
    'simplesamlphp_auth_user_name' => array(
      '#type' => 'textfield',
      '#title' => t('Which attribute from simpleSAMLphp should be used as user\'s name'),
      '#default_value' => variable_get('simplesamlphp_auth_user_name', 'eduPersonPrincipalName'),
      '#description' => t('Example: <i>eduPersonPrincipalName</i> or <i>displayName</i><br />If the attribute is multivalued, the first value will be used.'),
      '#required' => TRUE,
    ),
    'simplesamlphp_auth_unique_id' => array(
      '#type' => 'textfield',
      '#title' => t('Which attribute from simpleSAMLphp should be used as unique identifier for the user'),
      '#default_value' => variable_get('simplesamlphp_auth_unique_id', 'eduPersonPrincipalName'),
      '#description' => t('Example: <i>eduPersonPrincipalName</i> or <i>eduPersonTargetedID</i><br />If the attribute is multivalued, the first value will be used.'),
      '#required' => TRUE,
    ),
    'simplesamlphp_auth_mailattr' => array(
      '#type' => 'textfield',
      '#title' => t('Which attribute from simpleSAMLphp should be used as user mail address'),
      '#default_value' => variable_get('simplesamlphp_auth_mailattr', 'mail'),
      '#description' => t('Example: <i>mail</i><br />If the user attribute is multivalued, the first value will be used.'),
    ),
    'simplesamlphp_auth_rolepopulation' => array(
      '#type' => 'textarea',
      '#title' => t('Automatic role population from simpleSAMLphp attributes'),
      '#default_value' => variable_get('simplesamlphp_auth_rolepopulation', ''),
      '#description' => t('A pipe separated list of rules.<br />Example: <i>roleid1:condition1|roleid2:contition2...</i> <br />For instance: <i>1:eduPersonPrincipalName,@=,uninett.no;affiliation,=,employee|2:mail,=,andreas@uninett.no</i>'),
    ),
    'simplesamlphp_auth_roleevaleverytime' => array(
      '#type' => 'checkbox',
      '#title' => t('Reevaluate roles every time the user logs in.'),
      '#default_value' => variable_get('simplesamlphp_auth_roleevaleverytime', 0),
      '#description' => t('NOTE: This means users could loose any roles that have been assigned manually in Drupal.'),
    ),
    'simplesamlphp_auth_forcehttps' => array(
      '#type' => 'checkbox',
      '#title' => t('Force https for login links'),
      '#default_value' => variable_get('simplesamlphp_auth_forcehttps', TRUE),
      '#description' => t('Should be enabled on production sites.'),
    ),
    'simplesamlphp_auth_registerusers' => array(
      '#type' => 'checkbox',
      '#title' => t('Register users'),
      '#default_value' => variable_get('simplesamlphp_auth_registerusers', TRUE),
      '#description' => t('Decides wether or not the module should create/register new users upon authentication.<br />NOTE: If unchecked each user must already have been provisioned a Drupal account before logging in. Otherwise they will receive a notice and be denied access.'),
    ),
    'simplesamlphp_auth_allowdefaultlogin' => array(
      '#type' => 'checkbox',
      '#title' => t('Allow authentication with local Drupal accounts'),
      '#default_value' => variable_get('simplesamlphp_auth_allowdefaultlogin', TRUE),
      '#description' => t('Check this box if you want to let people log in with local Drupal accounts (without using simpleSAMLphp). If you want to restrict this privilege to certain users you can enter the Drupal user IDs in the next field.'),
    ),
    'simplesamlphp_auth_allowdefaultloginusers' => array(
      '#type' => 'textfield',
      '#title' => t('Which users should be allowed to login with local accounts?'),
      '#default_value' => variable_get('simplesamlphp_auth_allowdefaultloginusers', ''),
      '#description' => t('Example: <i>1,2,3</i><br />A comma-separated list of user IDs that should be allowed to login without simpleSAMLphp.'),
    ),
  );
  return system_settings_form($form);
}

/**
 * Implementation of hook_form_alter().
 */
function simplesamlphp_auth_form_alter(&$form, $form_state, $form_id) {
  if (!_simplesamlphp_auth_isEnabled()) {

    // Exit without executing.
    return;
  }
  if ($form_id == 'user_login_block') {
    $link = l('Federated Login', 'saml_login');
    $links = $form['links']['#value'];
    $links = str_replace('</ul>', '<li class="saml">' . $link . '</li></ul>', $links);
    $form['links']['#value'] = $links;
  }
}

/**
 * Implementation of hook_block().
 */
function simplesamlphp_auth_block($op = 'list', $delta = 0, $edit = array()) {
  if (!_simplesamlphp_auth_isEnabled()) {

    // Exit without executing.
    return;
  }
  if ($op == 'list') {
    $blocks = array(
      array(
        'info' => t('simpleSAMLphp authentication'),
        'weight' => 0,
        'status' => 1,
        'region' => 'left',
        'cache' => BLOCK_NO_CACHE,
      ),
    );
    return $blocks;
  }
  elseif ($op == 'view') {
    switch ($delta) {
      case 0:
        $block = array(
          'subject' => t('simpleSAMLphp login'),
          'content' => _simplesamlphp_auth_generate_block_text(),
        );
        break;
    }
    return $block;
  }
}

// Helper functions --------------------------------------

/**
 * Checks to see if authentication via SimpleSAMLphp should be activated
 *
 * @param bShowInactiveMsg
 *   Whether to display the "module not activated" message
 *
 * @return
 *   TRUE/FALSE
 */
function _simplesamlphp_auth_isEnabled($bShowInactiveMsg = FALSE) {
  global $user;
  $failure = NULL;
  $isActivated = variable_get('simplesamlphp_auth_activate', FALSE);
  $basedir = variable_get('simplesamlphp_auth_installdir', '/var/simplesamlphp');
  if (!$isActivated) {
    $menuPaths = array_keys(simplesamlphp_auth_menu());
    $failure = t('SimpleSAMLphp authentication is NOT yet activated. It can be activated on the ' . l(t('configuration page'), $menuPaths[0]) . '.');
    watchdog('simplesamlphp_auth', $failure, NULL, WATCHDOG_WARNING);
  }
  else {

    // Make sure we know where SimpleSAMLphp is.
    if (!file_exists($basedir)) {
      $failure = t('SimpleSAMLphp could not be found at %basedir . The simplesamlphp_auth module cannot function until the path to the local SimpleSAMLphp instance is configured.', array(
        '%basedir' => $basedir,
      ));
      watchdog('simplesamlphp_auth', $failure, NULL, WATCHDOG_WARNING);
    }
  }

  // If there were no failures, then it should be activated
  if (!$failure) {
    return TRUE;
  }
  else {

    // communicate but don't be too annoying
    if ($bShowInactiveMsg && user_access('access administration pages') && (preg_match('/\\/admin\\/user/', request_uri()) || preg_match('/\\/admin\\/build\\/modules/', request_uri()))) {
      drupal_set_message($failure);
    }
  }
  return FALSE;
}

/**
 * Gets the authname attribute from the SAML assertion.
 *
 * @return
 *   The authname attribute.
 */
function _simplesamlphp_auth_get_authname() {
  global $_simplesamlphp_auth_saml_attributes;
  $authname = '';

  // Check if valid local session exists..
  if (isset($_simplesamlphp_auth_saml_attributes)) {
    _simplesaml_auth_debug(t('_simplesamlphp_auth_get_authname: Valid local session exist'));
    if (isset($_simplesamlphp_auth_saml_attributes[variable_get('simplesamlphp_auth_unique_id', 'eduPersonPrincipalName')])) {
      $authname = $_simplesamlphp_auth_saml_attributes[variable_get('simplesamlphp_auth_unique_id', 'eduPersonPrincipalName')][0];
    }
    else {
      throw new Exception(t('error in simplesamlphp_auth.module: no valid unique id attribute set'));
    }
  }
  return $authname;
}

/**
 * Gets the default name attribute from the SAML assertion.
 *
 * @return
 *   The name attribute.
 */
function _simplesamlphp_auth_get_default_name($account) {
  global $_simplesamlphp_auth_as;
  global $_simplesamlphp_auth_saml_attributes;
  $default_name = '';

  // Check if valid local session exists.
  if ($_simplesamlphp_auth_as
    ->isAuthenticated()) {
    $auth_user_name_attr = variable_get('simplesamlphp_auth_user_name', 'eduPersonPrincipalName');
    if (!isset($_simplesamlphp_auth_saml_attributes[$auth_user_name_attr]) || !isset($_simplesamlphp_auth_saml_attributes[$auth_user_name_attr][0])) {
      throw new Exception(t('There was no attribute named %auth_user_name_attr set for your user.', array(
        '%auth_user_name_attr' => $auth_user_name_attr,
      )));
    }
    $default_name = $_simplesamlphp_auth_saml_attributes[$auth_user_name_attr][0];
  }
  return $default_name;
}

/**
 * Gets the mail attribute.
 *
 * @return
 *   The mail attribute.
 */
function _simplesamlphp_auth_get_mail() {
  global $_simplesamlphp_auth_as;
  global $_simplesamlphp_auth_saml_attributes;
  $mail_address = '';

  // Check if valid local session exists.
  if ($_simplesamlphp_auth_as
    ->isAuthenticated()) {
    if (isset($_simplesamlphp_auth_saml_attributes[variable_get('simplesamlphp_auth_mailattr', 'mail')])) {
      $mail_address = $_simplesamlphp_auth_saml_attributes[variable_get('simplesamlphp_auth_mailattr', 'mail')][0];
    }
    else {
      throw new Exception(t('error in simplesamlphp_auth.module: no valid mail attribute set'));
    }
  }
  return $mail_address;
}

/**
 * Forces HTTPS connections.
 */
function _simplesamlphp_auth_forcehttps_rewrite($url) {
  if (variable_get('simplesamlphp_auth_forcehttps', TRUE)) {
    $url = str_replace('http://', 'https://', $url);
    _simplesaml_auth_debug('forcehttps rewrite: ' . $url);
  }
  return $url;
}

/**
 * Generates the text for the log in block.
 */
function _simplesamlphp_auth_generate_block_text() {
  global $_simplesamlphp_auth_as;
  $block_content = '';
  global $user;
  if (!_simplesamlphp_auth_isEnabled()) {

    // Exit without executing.
    return;
  }

  // Check if valid local session exists.
  if ($_simplesamlphp_auth_as
    ->isAuthenticated()) {
    $block_content .= '<p>Logged in as: ' . $user->name . '<br /><a href="/logout">' . t('Federated logout') . '</a></p>';
  }
  else {
    $block_content .= '<p><a href="saml_login">' . t('Federated login') . '</a></p>';
  }
  return $block_content;
}

/**
 * Evaluates a role rule.
 *
 * @param $roleruleevaluation
 *   An array containing the role rule to evaluate.
 *
 * @param $attributes
 *   An array containing the identity attributes.
 *
 * @return
 *   An array containing role value and the attribute, or FALSE.
 */
function _simplesamlphp_auth_evaulaterolerule($roleruleevaluation, $attributes) {
  _simplesaml_auth_debug(t('Evaluate rule (key=%key,operator=%op,value=%val)', array(
    '%key' => $roleruleevaluation[0],
    '%op' => $roleruleevaluation[1],
    '%val' => $roleruleevaluation[2],
  )));
  if (!array_key_exists($roleruleevaluation[0], $attributes)) {
    return FALSE;
  }
  $attribute = $attributes[$roleruleevaluation[0]];
  switch ($roleruleevaluation[1]) {
    case '=':
      return in_array($roleruleevaluation[2], $attribute);
    case '@=':
      $dc = explode('@', $attribute[0]);
      if (count($dc) != 2) {
        return FALSE;
      }
      return $dc[1] == $roleruleevaluation[2];
  }
  return FALSE;
}

/**
 * Performs role population.
 *
 * @param $rolemap
 *   A string containing the role map.
 *
 * @return
 *   An array containing user's roles.
 */
function _simplesamlphp_auth_rolepopulation($rolemap) {
  global $_simplesamlphp_auth_as;
  global $_simplesamlphp_auth_saml_attributes;
  $roles = array();
  _simplesaml_auth_debug(t('Rolemap: %rolemap', array(
    '%rolemap' => $rolemap,
  )));

  // Check if valid local session exists..
  if ($_simplesamlphp_auth_as
    ->isAuthenticated()) {
    $attributes = $_simplesamlphp_auth_saml_attributes;
    if (empty($rolemap)) {
      return $roles;
    }
    _simplesaml_auth_debug(t('Evaluate rolemap: %rolemap', array(
      '%rolemap' => $rolemap,
    )));
    $rolerules = explode('|', $rolemap);
    foreach ($rolerules as $rolerule) {
      _simplesaml_auth_debug(t('Evaluate role rule: %rolerule', array(
        '%rolerule' => $rolerule,
      )));
      $roleruledecompose = explode(':', $rolerule);
      $roleid = $roleruledecompose[0];
      $roleruleevaluations = explode(';', $roleruledecompose[1]);
      $addnew = TRUE;
      foreach ($roleruleevaluations as $roleruleevaluation) {
        _simplesaml_auth_debug(t('Evaluate role evaulation: %roleruleeval', array(
          '%roleruleeval' => $roleruleevaluation,
        )));
        $roleruleevaluationdc = explode(',', $roleruleevaluation);
        if (!_simplesamlphp_auth_evaulaterolerule($roleruleevaluationdc, $attributes)) {
          $addnew = FALSE;
        }
      }
      if ($addnew) {
        $roles[$roleid] = $roleid;
        _simplesaml_auth_debug(t('Add new role: %roleid', array(
          '%roleid' => $roleid,
        )));
      }
    }
  }
  return $roles;
}

/**
 * This helper function is used by developers to debug the form API workflow in this module.
 */
function _simplesaml_auth_debug($message) {
  watchdog('simplesamlphp', $message, NULL, WATCHDOG_DEBUG);
}

/**
 * Helper function for logging out a user that is has a active session in Drupal but not with simpleSAML.
 */
function _simplesamlphp_auth_destroy_drupal_session() {
  global $user;
  watchdog('user', t('Session closed for %name.'), array(
    '%name' => $user->name,
  ));

  // Destroy the current session.
  session_destroy();

  // Only variables can be passed by reference workaround.
  $NULL = NULL;
  user_module_invoke('logout', $NULL, $user);

  // Load the anonymous user.
  $user = drupal_anonymous_user();
  drupal_goto();
}

Functions

Namesort descending Description
simplesamlphp_auth_block Implementation of hook_block().
simplesamlphp_auth_form_alter Implementation of hook_form_alter().
simplesamlphp_auth_help Implementation of hook_help().
simplesamlphp_auth_init Implementation of hook_init().
simplesamlphp_auth_loginpage Represents the Drupal page (saml_login), which triggers user authentication against the SimpleSAMLphp service provider.
simplesamlphp_auth_menu Implementation of hook_menu().
simplesamlphp_auth_perm Implementation of hook_perm().
simplesamlphp_auth_settings Implements settings for the module.
simplesamlphp_auth_user Implementation of hook_user().
_simplesamlphp_auth_destroy_drupal_session Helper function for logging out a user that is has a active session in Drupal but not with simpleSAML.
_simplesamlphp_auth_evaulaterolerule Evaluates a role rule.
_simplesamlphp_auth_forcehttps_rewrite Forces HTTPS connections.
_simplesamlphp_auth_generate_block_text Generates the text for the log in block.
_simplesamlphp_auth_get_authname Gets the authname attribute from the SAML assertion.
_simplesamlphp_auth_get_default_name Gets the default name attribute from the SAML assertion.
_simplesamlphp_auth_get_mail Gets the mail attribute.
_simplesamlphp_auth_isEnabled Checks to see if authentication via SimpleSAMLphp should be activated
_simplesamlphp_auth_rolepopulation Performs role population.
_simplesaml_auth_debug This helper function is used by developers to debug the form API workflow in this module.