You are here

simplesamlphp_auth.module in simpleSAMLphp Authentication 7

simpleSAMLphp authentication module for Drupal.

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

ISSUES and TODOs: ISSUE: User is always dropped on user page after login, instead of where they were when they clicked "Federated Log In". Because of this, deep linking to access controlled content does not work. Usability would be considerably increased if this were resolved. FYI: Drupal now requires knowledge of the local user password in order to change e-mail address, etc. This could be an issue for users of accounts that are autoprovisioned by this module, though Drupal does give users the ability to reset their password to something they know via the Request new password feature. KLUDGE: Drupal does not kill the session on logout, even with drupal_session_destroy_uid(), so I had to use session_destroy(). @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.
 *
 * ISSUES and TODOs:
 *  ISSUE: User is always dropped on user page after login, instead of where
 *         they were when they clicked "Federated Log In". Because of this, deep
 *         linking to access controlled content does not work. Usability would
 *         be considerably increased if this were resolved.
 *  FYI: Drupal now requires knowledge of the local user password in order to
 *       change e-mail address, etc. This could be an issue for users of
 *       accounts that are autoprovisioned by this module, though Drupal does
 *       give users the ability to reset their password to something they know
 *       via the Request new password feature.
 *  KLUDGE: Drupal does not kill the session on logout, even with
 *          drupal_session_destroy_uid(), so I had to use session_destroy().
 *  @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.
 */

/**
 * Implements hook_menu().
 */
function simplesamlphp_auth_menu() {
  $items = array();
  $items['admin/config/people/simplesamlphp_auth'] = array(
    'title' => 'simpleSAMLphp authentication module settings',
    'description' => '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_LOCAL_TASK | MENU_NORMAL_ITEM,
  );
  $items['saml_login'] = array(
    'title' => 'Logon to the site',
    'description' => 'Provides a site login page',
    'page callback' => 'simplesamlphp_auth_loginpage',
    'access callback' => TRUE,
    'type' => MENU_CALLBACK,
  );
  return $items;
}

/**
 * Implements hook_admin_paths().
 */
function simplesamlphp_auth_admin_paths() {
  return array(
    'admin/config/people/simplesamlphp_auth' => TRUE,
  );
}

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

/**
 * Implements hook_permission().
 */
function simplesamlphp_auth_permission() {
  return array(
    'administer simpleSAMLphp authentication' => array(
      'title' => t('Administer simpleSAMLphp authentication'),
      'description' => t('Warning: Give to trusted roles only; this permission has security implications.'),
    ),
  );
}

/**
 * Represents the Drupal page (saml_login), which triggers user authentication against the SimpleSAMLphp service provider.
 */
function simplesamlphp_auth_loginpage() {
  global $user;
  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;
  }

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

  // Make sure phpsession is NOT being used.
  if ($configStoreType == 'phpsession') {
    watchdog('simplesamlphp_auth', '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', '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('/');
  }
  if ($user->uid == 0) {

    // Require the user to be authenticated.
    $_simplesamlphp_auth_as
      ->requireAuth();
  }
  else {
    drupal_goto('user/' . $user->uid);
  }
  return $output;
}

/**
 * Implements 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()) {

    // Exit without initializing.
    return;
  }

  // Get the simplesamlphp session.
  $basedir = variable_get('simplesamlphp_auth_installdir', '/var/simplesamlphp');
  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 to Drupal.
    if ($_simplesamlphp_auth_as
      ->isAuthenticated()) {

      // User is logged in - SimpleSAMLphp (but not 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.
        $ext_user = user_external_load($authname);
        if (!$ext_user) {

          // 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 ;)
            }
            drupal_set_message(t("Welcome. Since this is your first time logging in, we've automatically provisioned an account for you."), 'status');
          }
          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.
            // 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,
            );

            // Save the updated roles and populate the user object.
            $user = user_save($ext_user, $userinfo);
          }
          else {

            // No need to evaluate roles, populate the user object.
            $user = $ext_user;
          }
          $msg = t("Welcome back.");
          drupal_set_message($msg, 'status');
        }

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

      // End if !empty authname.
    }

    // End if isset saml_session.
  }
  else {

    // The user is already logged into Drupal.
    // If we forbid users from logging 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();
            }
          }
        }

        // Test for specified users.
      }

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

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

  // End if user->uid.
}

/**
 * Implements hook_user_insert().
 */
function simplesamlphp_auth_user_insert(&$edit, $account, $category = NULL) {
  global $_simplesamlphp_auth_as;
  global $_simplesamlphp_auth_saml_attributes;
  if ($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.' . $e
          ->getMessage());
        drupal_set_message($message, "error");
        watchdog('simplesamlphp', $message, WATCHDOG_CRITICAL);
      }
      db_update('users')
        ->fields(array(
        'name' => $account->name,
      ))
        ->condition('uid', $account->uid)
        ->execute();
      _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.' . $e
          ->getMessage());
        drupal_set_message($message, "error");
        watchdog('simplesamlphp', $message, WATCHDOG_CRITICAL);
      }
      if (!empty($mail_address)) {
        db_update('users')
          ->fields(array(
          'mail' => $mail_address,
        ))
          ->condition('uid', $account->uid)
          ->execute();
      }
      _simplesaml_auth_debug(t('Updating mail [%mailaddr]', array(
        '%mailaddr' => $mail_address,
      )));
    }
  }
}

/**
 * Implements hook_user_logout().
 */
function simplesamlphp_auth_user_logout($account) {
  global $user;
  global $_simplesamlphp_auth_as;
  global $_simplesamlphp_auth_saml_attributes;
  if (!empty($_simplesamlphp_auth_saml_attributes)) {
    $config = SimpleSAML_Configuration::getInstance();
    $msg = 'with_slo';
    try {
      $slo = $config
        ->getString('SingleLogoutService');
    } catch (Exception $e) {
      $msg = "no_slo";
    }

    // :KLUDGE: for some reason Drupal is not killing the session, even if I were to call drupal_session_destroy_uid() here.
    session_destroy();
    $_simplesamlphp_auth_as
      ->logout('/?msg=' . $msg);
  }
}

/**
 * Implements hook_user_delete().
 */
function simplesamlphp_auth_user_delete($account) {
  db_delete('authmap')
    ->condition('uid', $account->uid)
    ->condition('authname', $account->name)
    ->execute();
}

/**
 * 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)) {
      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);
}

/**
 * Implements hook_form_alter().
 */
function simplesamlphp_auth_form_alter(&$form, $form_state, $form_id) {
  if ($form_id == 'user_login_block') {
    $link = l('Federated Log In', 'saml_login');
    $links = $form['links']['#markup'];
    $links = str_replace('</ul>', '<li class="saml">' . $link . '</li></ul>', $links);
    $form['links']['#markup'] = $links;
  }
  if ($form_id == 'user_account_form') {
    $link = l('Federated Log In', 'saml_login');
    $links = $form['links']['#markup'];
    $links = str_replace('</ul>', '<li class="saml">' . $link . '</li></ul>', $links);
    $form['links']['#markup'] = $links;
  }
}

/**
 * Implements hook_block_view().
 */
function simplesamlphp_auth_block_view($delta = '') {
  switch ($delta) {
    case 0:
      $block = array(
        'subject' => t('simpleSAMLphp login'),
        'content' => _simplesamlphp_auth_generate_block_text(),
      );
      break;
  }
  return $block;
}

/**
 * Implements hook_block_info().
 */
function simplesamlphp_auth_block_info() {
  $block = array(
    array(
      'info' => t('simpleSAMLphp authentication'),
      'cache' => DRUPAL_NO_CACHE,
    ),
  );
  return $block;
}

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

/**
 * Checks to see if authentication via SimpleSAMLphp should be activated
 *
 * @return
 *   TRUE/FALSE
 */
function _simplesamlphp_auth_isEnabled() {
  global $user;
  $failure = NULL;
  $isActivated = variable_get('simplesamlphp_auth_activate');
  $basedir = variable_get('simplesamlphp_auth_installdir', '/var/simplesamlphp');
  if (!$isActivated) {
    $adminPath = array_keys(simplesamlphp_auth_admin_paths());
    $failure = t('SimpleSAMLphp authentication is NOT yet activated. It can be activated on the ' . l('configuration page', $adminPath[0]) . '.');
    watchdog('simplesamlphp_auth', $failure, NULL, WATCHDOG_WARNING);
    if ($user->uid != 0) {
      drupal_set_message($failure);
    }
  }
  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 ($user->uid != 0) {
        drupal_set_message($failure);
      }
    }
  }

  // If there were no failures, then it should be activated
  if (!$failure) {
    return TRUE;
  }
  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;

  // Check if valid local session exists..
  if ($_simplesamlphp_auth_as
    ->isAuthenticated()) {
    $block_content .= '<p>Logged in as: ' . $user->name . '<br />' . l('Log Out', 'user/logout') . '</a></p>';
  }
  else {
    $block_content .= '<p>' . l('Federated Log In', 'saml_login') . '</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', '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_admin_paths Implements hook_admin_paths().
simplesamlphp_auth_block_info Implements hook_block_info().
simplesamlphp_auth_block_view Implements hook_block_view().
simplesamlphp_auth_form_alter Implements hook_form_alter().
simplesamlphp_auth_help Implements hook_help().
simplesamlphp_auth_init Implements hook_init().
simplesamlphp_auth_loginpage Represents the Drupal page (saml_login), which triggers user authentication against the SimpleSAMLphp service provider.
simplesamlphp_auth_menu Implements hook_menu().
simplesamlphp_auth_permission Implements hook_permission().
simplesamlphp_auth_settings Implements settings for the module.
simplesamlphp_auth_user_delete Implements hook_user_delete().
simplesamlphp_auth_user_insert Implements hook_user_insert().
simplesamlphp_auth_user_logout Implements hook_user_logout().
_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.