You are here

bakery.module in Bakery Single Sign-On System 8.2

For implementing different hooks for bakery SSO functionality.

File

bakery.module
View source
<?php

/**
 * @file
 * For implementing different hooks for bakery SSO functionality.
 */
use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Link;
use Drupal\Core\Routing\TrustedRedirectResponse;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Url;
use Drupal\user\UserInterface;

/**
 * Implements hook_user_login().
 */
function bakery_user_login(UserInterface $account) {
  \Drupal::service('bakery.user_service')
    ->login($account);
}

/**
 * Implements hook_user_logout().
 */
function bakery_user_logout(AccountInterface $account) {
  \Drupal::service('bakery.user_service')
    ->logout($account);
}

/**
 * Implements hook_ENTITY_TYPE_presave() for user entities.
 */
function bakery_user_presave(UserInterface $account) {
  \Drupal::service('bakery.user_service')
    ->presave($account);
}

/**
 * Implements hook_ENTITY_TYPE_update() for user entities.
 */
function bakery_user_update(UserInterface $account) {
  \Drupal::service('bakery.user_service')
    ->update($account);
}

/**
 * Implements hook_ENTITY_TYPE_view() for user entities.
 */
function bakery_user_view(array &$build, $account, EntityViewDisplayInterface $display) {
  \Drupal::service('bakery.user_service')
    ->view($account, $build);
}

/**
 * Implements hook_form_alter().
 */
function bakery_form_alter(&$form, FormStateInterface $form_state, $form_id) {
  switch ($form_id) {
    case 'user_profile_form':
    case 'user_form':
      $config = \Drupal::config('bakery.settings');

      /** @var \Drupal\bakery\BakeryService $bakery */
      $bakery = \Drupal::service('bakery.bakery_service');
      if (!\Drupal::currentUser()
        ->hasPermission('administer users') && $bakery
        ->isChild()) {
        $master_uri = $config
          ->get('bakery_master');

        // $init_url = _bakery_init_field_url($form['#user']->init);.
        if (isset($form['account'])) {
          \Drupal::messenger()
            ->addStatus(t('You can change the name, mail, and password <a href=":url">at the master site</a>.', [
            ':url' => $master_uri,
          ]), FALSE);
          $form['account']['#access'] = FALSE;
          $form['account']['name']['#access'] = FALSE;
          $form['account']['pass']['#access'] = FALSE;
          $form['account']['mail']['#access'] = FALSE;
        }
        foreach (\Drupal::config('bakery.settings')
          ->get('bakery_supported_fields') as $type => $value) {
          if ($value) {
            switch ($type) {
              case 'mail':
              case 'name':
                break;
              case 'picture':
                if (isset($form['picture'])) {
                  $form['picture']['picture_delete']['#access'] = FALSE;
                  $form['picture']['picture_upload']['#access'] = FALSE;
                  $form['picture']['#description'] = t('You can change the image <a href=":url">at the master site</a>.', [
                    ':url' => $master_uri,
                  ]);
                }
                break;
              case 'language':
                if (isset($form['locale'][$type])) {
                  $form['locale'][$type]['#disabled'] = TRUE;
                  $form['locale'][$type]['#description'] .= ' ' . t('You can change the language setting <a href=":url">at the master site</a>.', [
                    ':url' => $master_uri,
                  ]);
                }
                break;
              case 'signature':
                if (isset($form['signature_settings'][$type])) {
                  $form['signature_settings'][$type]['#disabled'] = TRUE;
                  $form['signature_settings'][$type]['#description'] .= ' ' . t('You can change the signature <a href=":url">at the master site</a>.', [
                    ':url' => $master_uri,
                  ]);
                }
                break;
              default:
                if (isset($form[$type])) {
                  $form[$type]['#disabled'] = TRUE;
                }
                if (isset($form[$type][$type])) {
                  $form[$type][$type]['#disabled'] = TRUE;
                  $form[$type][$type]['#description'] .= ' ' . t('You can change this setting <a href=":url">at the master site</a>.', [
                    ':url' => $master_uri,
                  ]);
                }
                break;
            }
          }
        }
      }
      break;
    case 'user_login_form':
      $config = \Drupal::config('bakery.settings');
      if ($config
        ->get('bakery_is_master')) {

        // Use both validate and submit, in case other modules like TFA are
        // also altering the login process.
        $form['#validate'][] = '_bakery_login_redirect';
        $form['#submit'][] = '_bakery_login_redirect';
      }
      else {
        if ($config
          ->get('subsite_login')) {

          // TODO allow login...
          // Replace two validators from user module because they log the user in
          // and test if account exists. We want to check if the account exists on
          // the master instead.
          // dpm($form['#validate']);.
          $form['#validate'] = array_diff($form['#validate'], [
            '::validateAuthentication',
            '::validateFinal',
          ]);

          // Also replace the submit handler with our own to
          // set a redirect cookie.
          $form['#submit'] = [
            '_bakery_login_submit',
          ];
        }
        else {

          // Remove all form elements and just link to main site for login.
          // We _could_ redirect but because this form is shared with the login
          // block in 8+ this would lead to some really weird behaviors.
          $link = Link::fromTextAndUrl('Log in on main site', Url::fromUri($config
            ->get('bakery_master') . 'user', [
            'query' => [
              'bd' => \Drupal::getContainer()
                ->get('bakery.redirect')
                ->get(),
            ],
          ])
            ->setAbsolute(TRUE))
            ->toRenderable();
          unset($form['name'], $form['pass'], $form['actions']);
          $link['#cache']['tags'] = [
            'config:bakery.settings',
          ];
          $form['login'] = $link;
        }
      }
      break;
  }
}
function _bakery_login_redirect($form, FormStateInterface $form_state) {
  $dest = \Drupal::service('bakery.redirect')
    ->get();
  if ($dest) {
    $response = new TrustedRedirectResponse($dest);

    // Ensure check_logged_in logic doesn't break our redirect.
    \Drupal::request()
      ->getSession()
      ->remove('check_logged_in');
    $form_state
      ->setResponse($response);
  }
}

/**
 * Implements hook_form_FORM_ID_alter() for 'user_register_form'.
 */
function bakery_form_user_register_form_alter(&$form, FormStateInterface $form_state) {

  /** @var \Drupal\bakery\BakeryService $bakery */
  $bakery = \Drupal::service('bakery.bakery_service');

  // Provide register ability on the slave sites.
  if ($bakery
    ->isChild()) {
    if (\Drupal::service('router.admin_context')
      ->isAdminRoute(\Drupal::routeMatch()
      ->getRouteObject())) {
      $config = \Drupal::config('bakery.settings');

      // Admin create user form. Add a note about account synchronization.
      $form['account']['bakery_help'] = [
        '#value' => t('<strong>Note:</strong> Only use this form to create accounts for users who exist on <a href="!url">@master</a> and not on this site. Be sure to use the exact same username and e-mail for the account here that they have on @master.', [
          '!url' => $config
            ->get('bakery_master'),
          '@master' => $config
            ->get('bakery_master'),
        ]),
        '#weight' => -100,
      ];
    }
    else {
      if (\Drupal::config('bakery.settings')
        ->get('subsite_login')) {

        // Anonymous user registration form.
        // Populate fields if set from previous attempt.
        if (isset($_SESSION['bakery']['register'])) {
          $form['account']['name']['#default_value'] = $_SESSION['bakery']['register']['name'];
          $form['account']['mail']['#default_value'] = $_SESSION['bakery']['register']['mail'];
          unset($_SESSION['bakery']['register']);
        }

        // Replace the submit handler with our own.
        // $form['#submit'] = array('_bakery_register_submit');.
      }
      else {

        // TODO replace route so this can't happen.
        exit;
      }
    }
  }
}

/**
 * Implements hook_form_FORM_ID_alter() for 'user_pass'.
 */
function bakery_form_user_pass_alter(&$form, FormStateInterface $form_state) {

  /** @var \Drupal\bakery\BakeryService $bakery */
  $bakery = \Drupal::service('bakery.bakery_service');

  // Child sites need to make sure the local account exists, if the master
  // account exists.
  if ($bakery
    ->isChild()) {
    array_unshift($form['#validate'], '_bakery_pass_validate');
  }
}

/**
 * Validate handler for the password reset login.
 */
function _bakery_pass_validate($form, FormStateInterface &$form_state) {

  // Attempt to copy account from master.
  \Drupal::service('bakery.bakery_service')
    ->requestAccount(trim($form_state
    ->getValue('name')), TRUE);
}

/**
 * Handle registration by redirecting to master.
 */
function _bakery_register_submit($form, &$form_state) {

  // Create an array of fields to send to the master.
  // Save values to cookie.
  $data = [
    "name" => $form_state
      ->getValue('name'),
    "pass" => $form_state
      ->getValue('pass'),
    "mail" => $form_state
      ->getValue('mail'),
  ];
  _bakery_save_destination_param($form, $data);
  unset($_GET['destination']);

  // Store name and email in case of error and return from master.
  $_SESSION['bakery']['register'] = [
    'name' => $data['name'],
    'mail' => $data['mail'],
  ];

  // Create cookie and redirect to master.
  \Drupal::service('bakery.bakery_service')
    ->bakeOatmealCookie($form_state
    ->getValue('name'), $data);

  // Remove unneeded values.
  $form_state
    ->cleanValues();
  $master_uri = \Drupal::config('bakery.settings')
    ->get('bakery_master') . 'bakery';
  $form_state
    ->setFormState([
    'redirect' => new TrustedRedirectResponse($master_uri),
  ]);
}

/**
 * Handle login by redirecting to master.
 */
function _bakery_login_submit($form, &$form_state) {
  return;

  // Get rid of all the values we don't explicitly know we want. While this may
  // break some modules it ensures we don't send sensitive data between sites.
  // login data to master site.
  $data = [
    "name" => $form_state
      ->getValue('name'),
    "pass" => $form_state
      ->getValue('pass'),
  ];
  _bakery_save_destination_param($form, $data);
  unset($_GET['destination']);

  // Create cookie and redirect to master.
  \Drupal::service('bakery.bakery_service')
    ->bakeOatmealCookie($form_state
    ->getValue('name'), $data);

  // Remove unneeded values.
  $form_state
    ->cleanValues();
  $master_uri = \Drupal::config('bakery.settings')
    ->get('bakery_master') . 'bakery/login';
  $form_state
    ->setFormState([
    'redirect' => new TrustedRedirectResponse($master_uri),
  ]);
}

/**
 * Check if a form destination is set and save it in $data array.
 *
 * Used to preserve destination in Bakery redirection to master and slave
 * during login and registration.
 *
 * @param array $form
 *   Form definition to check.
 * @param array $data
 *   Array to store the detected destination value, if any.
 */
function _bakery_save_destination_param($form, &$data) {

  // Hold on to destination if set.
  if (strpos($form['#action'], 'destination=') !== FALSE) {

    // If an absolute URL is in destination parse_url() will issue a warning
    // and not populate $url_args so no further protection is needed.
    parse_str(parse_url($form['#action'], PHP_URL_QUERY), $url_args);
    if (!empty($url_args['destination'])) {
      $data['destination'] = $url_args['destination'];
    }
  }
}

/**
 * Build full init url to master.
 */
function _bakery_init_field_url($init) {
  $scheme = parse_url(\Drupal::config('bakery.settings')
    ->get('bakery_master'), PHP_URL_SCHEME);
  return $scheme . '://' . $init;
}

Functions

Namesort descending Description
bakery_form_alter Implements hook_form_alter().
bakery_form_user_pass_alter Implements hook_form_FORM_ID_alter() for 'user_pass'.
bakery_form_user_register_form_alter Implements hook_form_FORM_ID_alter() for 'user_register_form'.
bakery_user_login Implements hook_user_login().
bakery_user_logout Implements hook_user_logout().
bakery_user_presave Implements hook_ENTITY_TYPE_presave() for user entities.
bakery_user_update Implements hook_ENTITY_TYPE_update() for user entities.
bakery_user_view Implements hook_ENTITY_TYPE_view() for user entities.
_bakery_init_field_url Build full init url to master.
_bakery_login_redirect
_bakery_login_submit Handle login by redirecting to master.
_bakery_pass_validate Validate handler for the password reset login.
_bakery_register_submit Handle registration by redirecting to master.
_bakery_save_destination_param Check if a form destination is set and save it in $data array.