You are here

function _bakery_taste_chocolatechip_cookie in Bakery Single Sign-On System 7.4

Same name and namespace in other branches
  1. 6.2 bakery.module \_bakery_taste_chocolatechip_cookie()
  2. 6 bakery.module \_bakery_taste_chocolatechip_cookie()
  3. 7.2 bakery.module \_bakery_taste_chocolatechip_cookie()

Test identification cookie

1 call to _bakery_taste_chocolatechip_cookie()
bakery_boot in ./bakery.module
Implements hook_boot().

File

./bakery.module, line 516

Code

function _bakery_taste_chocolatechip_cookie() {
  $destroy_cookie = NULL;
  $token = NULL;
  try {
    $token = _bakery_validate_cookie();
  } catch (\Exception $e) {
    $destroy_cookie = TRUE;
    $GLOBALS['bakery_exception'] = $e;
  }

  // Continue if this is a valid cookie. That only happens for users who have
  // a current valid session on the master site.
  if ($token) {
    $destroy_cookie = FALSE;
    global $user;

    // Detect SSO cookie mismatch if there is already a valid session for user.
    if ($user->uid && $token
      ->getClaim('jti') !== $user->name) {

      // The SSO cookie doesn't match the existing session so force a logout.
      drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
      _bakery_user_logout();
    }

    // Bake a fresh cookie. Yum.
    _bakery_bake_chocolatechip_cookie($token
      ->getClaim('jti'), $token
      ->getClaim('mail'), $token
      ->getClaim('init'));
    if (!$user->uid) {

      // Since this might happen in hook_boot we need to bootstrap first.
      // Note that this only runs if they have a valid session on the master
      // and do not have one on the slave so it only creates the extra load of
      // a bootstrap on one pageview per session on the site which is not much.
      drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);

      // User is anonymous. If they do not have an account we'll create one by
      // requesting their information from the master site. If they do have an
      // account we may need to correct some disparant information.
      $account = user_load_multiple(array(), array(
        'name' => $token
          ->getClaim('jti'),
        'mail' => $token
          ->getClaim('mail'),
      ));
      $account = reset($account);

      // Fix out of sync users with valid init.
      if (!$account && !variable_get('bakery_is_master', 0) && $token
        ->getClaim('master')) {
        $count = db_select('users', 'u')
          ->fields('u', array(
          'uid',
        ))
          ->condition('init', $token
          ->getClaim('init'))
          ->countQuery()
          ->execute()
          ->fetchField();
        if ($count > 1) {

          // Uh oh.
          watchdog('bakery', 'Account uniqueness problem: Multiple users found with init %init.', array(
            '%init' => $token['init'],
          ), WATCHDOG_ERROR);
          drupal_set_message(t('Account uniqueness problem detected. <a href="@contact">Please contact the site administrator.</a>', array(
            '@contact' => variable_get('bakery_master', 'https://drupal.org/') . 'contact',
          )), 'error');
        }
        if ($count == 1) {
          $account = user_load_multiple(array(), array(
            'init' => $token
              ->getClaim('init'),
          ));
          if (is_array($account)) {
            $account = reset($account);
          }
          if ($account) {
            watchdog('bakery', 'Fixing out of sync uid %uid. Changed name %name_old to %name_new, mail %mail_old to %mail_new.', array(
              '%uid' => $account->uid,
              '%name_old' => $account->name,
              '%name_new' => $token
                ->getClaim('jti'),
              '%mail_old' => $account->mail,
              '%mail_new' => $token
                ->getClaim('mail'),
            ));
            user_save($account, array(
              'name' => $token
                ->getClaim('jti'),
              'mail' => $token
                ->getClaim('mail'),
            ));
            $account = user_load_multiple(array(), array(
              'name' => $token
                ->getClaim('jti'),
              'mail' => $token
                ->getClaim('mail'),
            ));
            $account = reset($account);
          }
        }
      }

      // Create the account if it doesn't exist.
      if (!$account && !variable_get('bakery_is_master', 0) && $token
        ->getClaim('master')) {
        $checks = TRUE;
        $mail_count = db_select('users', 'u')
          ->fields('u', array(
          'uid',
        ))
          ->condition('uid', $user->uid, '!=')
          ->condition('mail', '', '!=')
          ->where('LOWER(mail) = LOWER(:mail)', array(
          ':mail' => $token
            ->getClaim('mail'),
        ))
          ->countQuery()
          ->execute()
          ->fetchField();
        if ($mail_count > 0) {
          $checks = FALSE;
        }
        $name_count = db_select('users', 'u')
          ->fields('u', array(
          'uid',
        ))
          ->condition('uid', $user->uid, '!=')
          ->where('LOWER(name) = LOWER(:name)', array(
          ':name' => $token
            ->getClaim('jti'),
        ))
          ->countQuery()
          ->execute()
          ->fetchField();
        if ($name_count > 0) {
          $checks = FALSE;
        }
        $init_count = db_select('users', 'u')
          ->fields('u', array(
          'uid',
        ))
          ->condition('uid', $user->uid, '!=')
          ->condition('init', $token
          ->getClaim('init'), '=')
          ->where('LOWER(name) = LOWER(:name)', array(
          ':name' => $token
            ->getClaim('jti'),
        ))
          ->countQuery()
          ->execute()
          ->fetchField();
        if ($init_count > 0) {
          $checks = FALSE;
        }
        if ($checks) {

          // Request information from master to keep data in sync.
          $uid = bakery_request_account($token
            ->getClaim('jti'));

          // In case the account creation failed we want to make sure the user
          // gets their bad cookie destroyed by not returning too early.
          if ($uid) {
            $account = user_load($uid);
          }
          else {
            $destroy_cookie = TRUE;
          }
        }
        else {
          drupal_set_message(t('Your user account on %site appears to have problems.', array(
            '%site' => variable_get('site_name', 'Drupal'),
          )));
          drupal_set_message(filter_xss_admin(variable_get('bakery_help_text', 'Please contact the site administrators.')));
        }
      }
      if ($account && $token
        ->getClaim('master') && $account->uid && !variable_get('bakery_is_master', 0) && $account->init != $token
        ->getClaim('init')) {

        // User existed previously but init is wrong. Fix it to ensure account
        // remains in sync.
        // Make sure that there aren't any OTHER accounts with this init already.
        $count = db_select('users', 'u')
          ->fields('u', array(
          'uid',
        ))
          ->condition('init', $token
          ->getClaim('init'), '=')
          ->countQuery()
          ->execute()
          ->fetchField();
        if ($count == 0) {
          db_update('users')
            ->fields(array(
            'init' => $token['init'],
          ))
            ->condition('uid', $account->uid)
            ->execute();
          watchdog('bakery', 'uid %uid out of sync. Changed init field from %oldinit to %newinit', array(
            '%oldinit' => $account->init,
            '%newinit' => $token
              ->getClaim('init'),
            '%uid' => $account->uid,
          ));
        }
        else {

          // Username and email matched, but init belonged to a DIFFERENT account.
          // Something got seriously tangled up.
          watchdog('bakery', 'Accounts mixed up! Username %user and init %init disagree with each other!', array(
            '%user' => $account->name,
            '%init' => $token
              ->getClaim('init'),
          ), WATCHDOG_CRITICAL);
        }
      }
      if ($account && $user->uid == 0) {

        // If the login attempt fails we need to destroy the cookie to prevent
        // infinite redirects (with infinite failed login messages).
        $login = bakery_user_external_login($account);
        if ($login) {

          // If an anonymous user has just been logged in, trigger a 'refresh'
          // of the current page, ensuring that drupal_goto() does not override
          // the current page with the destination query.
          $query = drupal_get_query_parameters();
          unset($_GET['destination']);
          drupal_goto(current_path(), array(
            'query' => $query,
          ));
        }
        else {
          $destroy_cookie = TRUE;
        }
      }
    }
    if ($destroy_cookie !== TRUE) {
      return TRUE;
    }
  }
  if ($destroy_cookie === TRUE) {

    // Destroy the bad cookie. Burp.
    _bakery_destroy_cookie();
  }
  global $user;

  // Log out users that have lost their SSO cookie, with the exception of
  // roles with permission to bypass.
  if ($user->uid > 1) {

    // This runs for logged in users. Those folks are going to get a full bootstrap anyway so this isn't a problem.
    drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
    if (!user_access('bypass bakery')) {
      watchdog('bakery', 'Logging out the user with the bad cookie.');
      _bakery_user_logout();
    }
  }
  return FALSE;
}