ppoidc-8.x-1.2/pixelpin_openid_connect.module

pixelpin_openid_connect.module
<?php

/**
 * @file
 * A pluggable client implementation for the OpenID Connect protocol.
 */

use Drupal\Core\Entity\EntityInterface;
use Drupal\user\Entity\User;
use Drupal\Core\Field\BaseFieldDefinition;
use Drupal\Core\Entity\EntityTypeInterface;

/**
 * Implements hook_entity_property_info_alter().
 */
function pixelpin_openid_connect_entity_property_info_alter(&$info) {
  $properties = &$info['user']['properties'];
  if (!isset($properties['timezone'])) {

    // Adds the missing timezone property.
    $properties['timezone'] = array(
      'label' => t('Time zone'),
      'description' => t("The user's time zone."),
      'options list' => 'system_time_zones',
      'getter callback' => 'entity_property_verbatim_get',
      'setter callback' => 'entity_property_verbatim_set',
      'schema field' => 'timezone',
    );

  }
}

/**
 * Implements hook_user_insert().
 */
function pixelpin_openid_connect_user_insert(EntityInterface $entity) {
  if (isset($edit['pixelpin_openid_connect_client'])) {
    pixelpin_openid_connect_connect_account($entity, $edit['pixelpin_openid_connect_client'], $edit['pixelpin_openid_connect_sub']);
  }
}

/**
 * Implements hook_user_cancel().
 */
function pixelpin_openid_connect_user_cancel($edit, $account, $method) {
  $authmap = \Drupal::service('pixelpin_openid_connect.authmap');
  $authmap->deleteAssociation($account->id());
}

/**
 * Implements hook_ENTITY_TYPE_delete().
 */
function pixelpin_openid_connect_user_delete(EntityInterface $entity) {
  $authmap = \Drupal::service('pixelpin_openid_connect.authmap');
  $authmap->deleteAssociation($entity->id());
}

/**
 * Implements hook_user_format_name_alter().
 */
function pixelpin_openid_connect_user_format_name_alter(&$name, $account) {
  // Ensure that usernames are not displayed if they are email addresses, or if
  // they are generated names starting with 'oidc_'.
  $oidc_name = \Drupal::service('user.data')->get('pixelpin_openid_connect', $account->id(), 'oidc_name');
  if (!empty($oidc_name) && (strpos($name, 'oidc_') === 0 || strpos($name, '@'))) {
    $name = $oidc_name;
  }
}

/**
 * Implements hook_form_FORM_ID_alter().
 */
function pixelpin_openid_connect_form_user_form_alter(&$form, &$form_state) {
  if (isset($form['account'])) {
    $account_form = &$form['account'];
  }
  else {
    $account_form = &$form;
  }

  $account = \Drupal::currentUser();
  $access = pixelpin_openid_connect_set_password_access($account);
  if (!$access) {
    $account_form['current_pass']['#access'] = FALSE;
    $account_form['current_pass_required_values']['#value'] = array();
    $account_form['pass']['#access'] = FALSE;
    $account_form['pass']['#required'] = FALSE;
  }
}

/**
 * Implements hook_form_FORM_ID_alter().
 */
function pixelpin_openid_connect_form_user_profile_form_alter(&$form, &$form_state) {
  if (isset($form['account'])) {
    $account_form = &$form['account'];
  }
  else {
    $account_form = &$form;
  }

  $account = \Drupal::currentUser();
  if (!empty($account_form['pass']['#access']) && !pixelpin_openid_connect_set_password_access($account)) {
    $account_form['current_pass']['#access'] = FALSE;
    $account_form['current_pass_required_values']['#value'] = array();
    $account_form['pass']['#access'] = FALSE;
  }
}

/**
 * Saves user profile information into a user account.
 *
 * @param \Drupal\user\UserInterface $account
 *   An user account object.
 * @param array $userinfo
 *   An array with information about the user.
 */
function pixelpin_openid_connect_save_userinfo($account, $userinfo) {
  $properties = \Drupal::entityManager()->getFieldDefinitions('user', 'user');
  $properties_skip = _pixelpin_openid_connect_user_properties_to_skip();
  foreach ($properties as $property_name => $property) {
    if (isset($properties_skip[$property_name])) {
      continue;
    }

    $userinfo_mappings = \Drupal::config('pixelpin_openid_connect.settings')
      ->get('userinfo_mappings');
    if (isset($userinfo_mappings[$property_name])) {
      $claim = $userinfo_mappings[$property_name];
      if ($claim && isset($userinfo[$claim])) {

        $property_type = $property->getType();
        // Set the user property, while ignoring exceptions from invalid values.
        try {
          if ($property_type === 'string') {
            $account->set($property_name, $userinfo[$claim]);
          }
          elseif ($property_type === 'image') {
            // Create file object from remote URL.
            $basename = explode('?', drupal_basename($userinfo[$claim]))[0];
            $data = file_get_contents($userinfo[$claim]);
            $file = file_save_data($data, 'public://user-picture-' . $account->id() . '-' . $basename, FILE_EXISTS_REPLACE);
            $account->set($property_name, ['target_id' => $file->id()]);
          }
        }
        catch (\InvalidArgumentException $e) {
          \Drupal::logger('pixelpin_openid_connect')->error($e->getMessage());
        }
      }
    }
  }

  // Save the display name additionally in the user account 'data', for use in
  // pixelpin_openid_connect_username_alter().
  if (isset($userinfo['name'])) {
    \Drupal::service('user.data')->set('pixelpin_openid_connect', $account->id(), 'oidc_name', $userinfo['name']);
  }

  $account->save();
}

/**
 * Logs in a user.
 *
 * @param \Drupal\user\UserInterface $account
 *   The user account.
 */
function pixelpin_openid_connect_login_user($account) {
  user_login_finalize($account);
}

/**
 * Save the current path in the session, for redirecting after authorization.
 */
function pixelpin_openid_connect_save_destination() {
  $destination = \Drupal::destination()->getAsArray();
  $destination = $destination['destination'] == 'user/login' ? 'user' : $destination['destination'];

  // The destination could contain query parameters. Ensure that they are
  // preserved.
  $parsed = parse_url($destination);
  $_SESSION['pixelpin_openid_connect_destination'] = array(
    $parsed['path'], array('query' => isset($parsed['query']) ? $parsed['query'] : ''),
  );
}

/**
 * Creates a user indicating sub-id and login provider.
 *
 * @param string $sub
 *   The subject identifier.
 * @param array $userinfo
 *   The user claims, containing at least 'email'.
 * @param string $client_name
 *   The machine name of the client.
 *
 * @return object|FALSE
 *   The user object or FALSE on failure.
 */
function pixelpin_openid_connect_create_user($sub, $userinfo, $client_name) {
  /** @var \Drupal\user\Entity\User $account */
  $address = $userinfo['address'];
  $decodeAddress = json_decode($address);

  $firstName = $userinfo['given_name'];
  $lastName = $userinfo['family_name'];


  $streetAddress2 = $decodeAddress->{"street_address"};
  $townCity2 = $decodeAddress->{"locality"};
  $region2 = $decodeAddress->{"region"};
  $postalCode2 = $decodeAddress->{"postal_code"};
  $country2 = $decodeAddress->{"country"};

  $streetAddress = (string)$streetAddress2;
  $townCity = (string)$townCity2;
  $region = (string)$region2;
  $postalCode = (string)$postalCode2;
  $country = (string)$country2;

  $account = User::create([
    'name' => $firstName.$lastName.$sub,
    'pass' => user_password(),
    'mail' => $userinfo['email'],
    'init' => $userinfo['email'],
    'family_name' => $userinfo['family_name'],
    'given_name' => $userinfo['given_name'],
    'nickname' => $userinfo['nickname'],
    'status' => 1,
    'pixelpin_openid_connect_client' => $client_name,
    'pixelpin_openid_connect_sub' => $sub,
  ]);

  $account->save();
  return $account;
}

/**
 * Generate a username for a new account.
 *
 * @param string $sub
 *    The subject identifier.
 * @param array $userinfo
 *   The user claims.
 * @param string $client_name
 *   The client identifier.
 *
 * @return string
 *   A unique username.
 */
function pixelpin_openid_connect_generate_username($sub, $userinfo, $client_name) {
  $name = 'oidc_' . $client_name . '_' . $sub;
  $candidates = array('preferred_username', 'name');
  foreach ($candidates as $candidate) {
    if (!empty($userinfo[$candidate])) {
      $name = trim($userinfo[$candidate]);
      break;
    }
  }

  // Ensure there are no duplicates.
  for ($original = $name, $i = 1; pixelpin_openid_connect_username_exists($name); $i++) {
    $name = $original . '_' . $i;
  }

  return $name;
}

/**
 * Check if a user name already exists.
 *
 * @param string $name
 *   A name to test.
 *
 * @return bool
 *   TRUE if a user exists with the given name, FALSE otherwise.
 */
function pixelpin_openid_connect_username_exists($name) {
  return db_query('SELECT COUNT(*) FROM {users_field_data} WHERE name = :name', array(
    ':name' => $name,
  ))->fetchField() > 0;
}

/**
 * Find whether the user is allowed to change their own password.
 *
 * @param object $account
 *   A user account object.
 *
 * @return bool
 *   TRUE if access is granted, FALSE otherwise.
 */
function pixelpin_openid_connect_set_password_access($account) {
  if ($account->hasPermission('openid connect set own password')) {
    return TRUE;
  }

  /* @var \Drupal\pixelpin_openid_connect\Authmap $authmap */
  $authmap = \Drupal::service('pixelpin_openid_connect.authmap');
  $connected_accounts = $authmap->getConnectedAccounts($account);

  return empty($connected_accounts);
}

/**
 * Returns user properties that can be skipped when mapping user profile info.
 */
function _pixelpin_openid_connect_user_properties_to_skip() {
  $properties_to_skip = array(
    'uid', 'uuid', 'langcode', 'preferred_langcode', 'preferred_admin_langcode',
    'name', 'pass', 'mail', 'status', 'created', 'changed', 'access', 'login',
    'init', 'roles', 'default_langcode',
  );
  \Drupal::moduleHandler()->alter(__FUNCTION__, $properties_to_skip);
  return array_combine($properties_to_skip, $properties_to_skip);
}

/**
 * Connect an external OpenID Connect account to a Drupal user account.
 *
 * @param object $account
 *   The Drupal user object.
 * @param string $client_name
 *   The client machine name.
 * @param string $sub
 *   The 'sub' property identifying the external account.
 */
function pixelpin_openid_connect_connect_account($account, $client_name, $sub) {
  /* @var \Drupal\pixelpin_openid_connect\Authmap $authmap */
  $authmap = \Drupal::service('pixelpin_openid_connect.authmap');
  $authmap->createAssociation($account, $client_name, $sub);
}

/**
 * Disconnect an external OpenID Connect account from a Drupal user account.
 *
 * @param object $account
 *   The Drupal user object.
 * @param string $client_name
 *   The client machine name.
 */
function pixelpin_openid_connect_disconnect_account($account, $client_name) {
  /* @var \Drupal\pixelpin_openid_connect\Authmap $authmap */
  $authmap = \Drupal::service('pixelpin_openid_connect.authmap');
  $authmap->deleteAssociation($account->id(), $client_name);
}

/**
 * Get the 'sub' property from the user data and/or user claims.
 *
 * The 'sub' (Subject Identifier) is a unique ID for the external provider to
 * identify the user.
 *
 * @param array $user_data
 *   The user data as returned from
 *   OpenIDConnectClientInterface::decodeIdToken().
 * @param array $userinfo
 *   The user claims as returned from
 *   OpenIDConnectClientInterface::retrieveUserInfo().
 *
 * @return string|FALSE
 *   The sub, or FALSE if there was an error.
 */
function pixelpin_openid_connect_extract_sub($user_data, $userinfo) {
  if (!isset($user_data['sub']) && !isset($userinfo['sub'])) {
    return FALSE;
  }
  elseif (!isset($user_data['sub'])) {
    return $userinfo['sub'];
  }
  elseif (isset($userinfo['sub']) && $user_data['sub'] != $userinfo['sub']) {
    return FALSE;
  }
  return $user_data['sub'];
}

/**
 * Complete the authorization after tokens have been retrieved.
 *
 * @param object $client
 *   The client.
 * @param array $tokens
 *   The tokens as returned from OpenIDConnectClientInterface::retrieveTokens().
 * @param string|array &$destination
 *   The path to redirect to after authorization.
 *
 * @return bool
 *   TRUE on success, FALSE on failure.
 */
function pixelpin_openid_connect_complete_authorization($client, $tokens, &$destination) {
  if (\Drupal::currentUser()->isAuthenticated()) {
    throw new \RuntimeException('User already logged in');
  }

  /* @var \Drupal\pixelpin_openid_connect\Authmap $authmap */
  $authmap = \Drupal::service('pixelpin_openid_connect.authmap');
  $user_data = $client->decodeIdToken($tokens['id_token']);
  $userinfo = $client->retrieveUserInfo($tokens['access_token']);
  $logger = \Drupal::logger('pixelpin_openid_connect');

  if ($userinfo && empty($userinfo['email'])) {
    $message = 'No e-mail address provided by PixelPin';
    $variables = array('@provider' => $client->getPluginId());
    $logger->error($message . ' (@code @error). Details: @details', $variables);
    return FALSE;
  }

  $sub = pixelpin_openid_connect_extract_sub($user_data, $userinfo);
  if (empty($sub)) {
    $message = 'No "sub" found from PixelPin';
    $variables = array('@provider' => $client->getPluginId());
    $logger->error($message . ' (@code @error). Details: @details', $variables);
    return FALSE;
  }

  /* @var \Drupal\user\UserInterface $account */
  $account = $authmap->userLoadBySub($sub, $client->getPluginId());
  if ($account) {
    // An existing account was found. Save user claims.
    if (\Drupal::config('pixelpin_openid_connect.settings')->get('always_save_userinfo')) {
      pixelpin_openid_connect_save_userinfo($account, $userinfo);
    }
  }
  else {
    // Check whether the e-mail address is valid.
    if (!\Drupal::service('email.validator')->isValid($userinfo['email'])) {
      drupal_set_message(
        t('The e-mail address is not valid: @email',
          array(
            '@email' => $userinfo['email'],
          )
        ),
        'error'
      );
      return FALSE;
    }
    // Check whether there is an e-mail address conflict.
    if (user_load_by_mail($userinfo['email'])) {
      drupal_set_message(
        t('The e-mail address is already taken: @email',
          array(
            '@email' => $userinfo['email'],
          )
        ),
        'error'
      );
      return FALSE;
    }

    // Create a new account.
    $account = pixelpin_openid_connect_create_user($sub, $userinfo, $client->getPluginId());
    pixelpin_openid_connect_save_userinfo($account, $userinfo);

    $authmap->createAssociation($account, $client->getPluginId(), $sub);
  }

  pixelpin_openid_connect_login_user($account);

  \Drupal::moduleHandler()->invokeAll('pixelpin_openid_connect_post_authorize', array(
    $tokens, $account, $userinfo, $client->getPluginId(),
  ));

  return TRUE;
}

/**
 * Connect the current user's account to an external provider.
 *
 * @param object $client
 *   The client.
 * @param array $tokens
 *   The tokens as returned from OpenIDConnectClientInterface::retrieveTokens().
 *
 * @return bool
 *   TRUE on success, FALSE on failure.
 */
function pixelpin_openid_connect_connect_current_user($client, $tokens) {
  /* @var \Drupal\Core\Session\AccountProxyInterface $user */
  $user = \Drupal::currentUser();
  if (!$user->isAuthenticated()) {
    throw new \RuntimeException('User not logged in');
  }

  /* @var \Drupal\pixelpin_openid_connect\Authmap $authmap */
  $authmap = \Drupal::service('pixelpin_openid_connect.authmap');
  $user_data = $client->decodeIdToken($tokens['id_token']);
  $userinfo = $client->retrieveUserInfo($tokens['access_token']);

  /* @var \Psr\Log\LoggerInterface $logger */
  $logger = \Drupal::logger('pixelpin_openid_connect');
  $provider_param = array('@provider' => $client->getPluginId());

  if ($userinfo && empty($userinfo['email'])) {
    $message = 'No e-mail address provided by PixelPin';
    $variables = $provider_param;
    $logger->error($message . ' (@code @error). Details: @details', $variables);
    return FALSE;
  }

  $sub = pixelpin_openid_connect_extract_sub($user_data, $userinfo);
  if (empty($sub)) {
    $message = 'No "sub" found from PixelPin';
    $variables = $provider_param;
    $logger->error($message . ' (@code @error). Details: @details', $variables);
    return FALSE;
  }

  /* @var \Drupal\user\UserInterface $account */
  $account = $authmap->userLoadBySub($sub, $client->getPluginId());
  if ($account && $account->id() !== $user->id()) {
    drupal_set_message(t('Another user is already connected to this PixelPin account.', $provider_param), 'error');
    return FALSE;
  }

  if (!$account) {
    $account = User::load($user->id());
    pixelpin_openid_connect_connect_account($account, $client->getPluginId(), $sub);
  }

  $always_save_userinfo = \Drupal::config('pixelpin_openid_connect.settings')->get('always_save_userinfo');
  if ($always_save_userinfo) {
    pixelpin_openid_connect_save_userinfo($account, $userinfo);
  }

  \Drupal::moduleHandler()->invokeAll('pixelpin_openid_connect_post_authorize', array(
    $tokens, $account, $userinfo, $client->getPluginId(),
  ));

  return TRUE;
}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc