wayf-1.0.x-dev/wayf.module

wayf.module
<?php

use Drupal\Core\Session\AccountInterface;
use Drupal\wayf\WAYF;
use Symfony\Component\HttpFoundation\RedirectResponse;

/**
 * Implements hook_cron().
 */
function wayf_cron() {
  // Execute every 24 hours.
  $interval = 24*60*60;
  $last_check = \Drupal::state()->get('wayf.last_fetch', 0);
  $time = \Drupal::time()->getRequestTime();
  if ($time - $last_check > $interval) {
    wayf__organizations_list();
    \Drupal::state()->set('wayf.last_fetch', $time);
  }
}

/**
 * Implements hook_theme().
 */
function wayf_theme($existing, $type, $theme, $path) {
  return [
    'wayf_login' => [
      'variables' => [
        'icon' => '',
        'login_url' => '/wayf/consume',
      ],
      'template' => 'wayf-login',
    ],
  ];
}

/**
 * @inheritdoc
 */
function wayf_user_cancel($edit, $account, $method) {
  if ('user_cancel_delete' === $method) {
    \Drupal::database()->delete('wayf')
      ->condition('uid', $account->id())
      ->execute();
  }
}


/**
 * Generate metadata based on configuration.
 *
 * @return string
 *   XML string with the metadata.
 */
function wayf_generate_metadata() {
  $config = \Drupal::config('wayf.settings');

  // Set library configuration.
  $config = [
    'cert' => $config->get('sp_cert') ? str_replace("\r\n", '', $config->get('sp_cert')) : '',
    'asc' => $config->get('sp_endpoint'),
    'logout_redirect' => $config->get('sp_logout_endpoint'),
    'entityid' => $config->get('sp_entityid'),
    'contact' => [
      'name' => $config->get('sp_contact_name'),
      'mail' => $config->get('sp_contact_mail'),
    ],
    'organization' => [
      'language' => $config->get('sp_organizations_name_language'),
      'name' => $config->get('sp_organizations_name'),
      'displayname' => $config->get('sp_organizations_displayname'),
      'url' => $config->get('sp_organizations_url'),
    ],
  ];

  return (new WAYF\SPorto($config))->getMetadata();
}

/**
 * Implements hook_wayf_create_user();
 */
function wayf_wayf_create_user($attributes) {
  // eduPersonTargetedID is a persistent, non-reassigned, privacy-preserving
  // identifier designed to provide a service provider with a unique
  // identifier for a logged in person while preserving the person's privacy.
  $edu_person_targeted_id = $attributes['eduPersonTargetedID'][0];

  // The following code is based on user_external_login_register that does
  // not allow the external identifier to be different from drupal username.
  $account = wayf_load_account($edu_person_targeted_id);

  if (!$account) {
    /** @var AccountInterface $account */
    $account = wayf_create_account($edu_person_targeted_id, $attributes);

    // Save eduPersonTargetedID -> uid mapping.
    $record = [
      'edu_person_targeted_id' => $edu_person_targeted_id,
      'uid' => $account->id(),
      'organization' => $attributes['schacHomeOrganization'][0],
    ];

    \Drupal::database()->insert('wayf')
      ->fields($record)
      ->execute();
  }

  if ($account) {
    user_login_finalize($account);
  } else {
    \Drupal::messenger()->addError(t('Login failed'));
    \Drupal::logger('wayf')->info("Login failed : %name.", ['%name' => $edu_person_targeted_id]);
  }
}

/**
 * Load user account.
 *
 * @param $edu_person_targeted_id
 */
function wayf_load_account($edu_person_targeted_id) {
  $uid = \Drupal::database()->query('SELECT uid FROM {wayf} WHERE edu_person_targeted_id = :eptid', [
    ':eptid' => $edu_person_targeted_id,
  ])->fetchField();

  if ($uid) {
    return Drupal\user\Entity\User::load($uid);
  }

  return FALSE;
}

/**
 * Implements hook_entity_delete().
 *
 * Removes the user entry in the WAYF table upon deletion.
 */
function wayf_entity_delete(\Drupal\Core\Entity\EntityInterface $entity) {
  if ('user' === $entity->getEntityType()->id()) {
    $conn = \Drupal::database();
    $conn->delete('wayf')
      ->condition('uid', $entity->id())
      ->execute();
  }
}

/**
 * Create new user account.
 *
 * @param $edu_person_targeted_id
 * @param $attributes
 *
 * @return RedirectResponse|AccountInterface
 */
function wayf_create_account($edu_person_targeted_id, $attributes) {
  // Create a user entity.
  $userinfo = [];
  $userinfo['name'] = $edu_person_targeted_id;
  $userinfo['mail'] = $attributes['mail'][0];
  $userinfo['pass'] = \Drupal::service('password_generator')->generate(32);
  $userinfo['status'] = 1;

  try {
    $account = Drupal\user\Entity\User::create($userinfo);
    wayf__map_fields($attributes, $account);
    $account->enforceIsNew();
    $account->save();
  } catch (\Exception $e) {
    \Drupal::messenger()->addError(t('Error saving user account.'));
    \Drupal::logger('wayf')->error('Error saving user account : %name.', [
        '%name' => $edu_person_targeted_id,
      ]
    );

    return new RedirectResponse('<front>');
  }

  \Drupal::logger('wayf')->info('New account created : %name.', [
    '%name' => $edu_person_targeted_id,
    ]
  );

  return $account;
}

/**
 * Implements hook_user_logout().
 *
 * Ensures that the WAYF logout function is called on user logout.
 */
function wayf_user_logout() {
  // Load configuration.
  $config = \Drupal::config('wayf.settings');

  // Set library configuration.
  $sportoConfig = [
    'idp_certificate' => $config->get('idp_certificate'),
    'sso' => $config->get('idp_sso'),
    'slo' => $config->get('idp_slo'),
    'private_key' => $config->get('sp_key'),
    'asc' => $config->get('sp_endpoint'),
    'entityid' => $config->get('sp_entityid'),
  ];

  // Check if the user maybe logged into WAYF.
  $sporto = new WAYF\SPorto($sportoConfig);
  if ($sporto->isLoggedIn()) {
    // Give other a change to clean up.
    \Drupal::moduleHandler()->invokeAll('wayf_pre_logout');

    // Send logout message.
    $sporto->logout();
  }
}

/**
 * Check if user is mapped in the WAYF table.
 *
 * @return bool
 */
function wayf_current_user_wayf_mapped(): bool {
  $account = \Drupal::currentUser();
  $status = \Drupal::database()->query('SELECT count(*) FROM {wayf} WHERE uid = :uid', [
    ':uid' => $account->id()
  ])->fetchField();

  return $status == 1;
}

/**
 * Map fields from released attributes to user fields.
 */
function wayf__map_fields($attributes, $account) {
  $mapping = \Drupal::config('wayf.settings')->get('mapping');

  foreach ($mapping as $field_name => $source) {
    if (!empty($source) && !empty($attributes[$source][0])) {
      $account->$field_name = $attributes[$source][0];
    }
  }
}

function wayf__icons() {
  return [
    'UK_01.png',
    'UK_02.png',
    'UK_03.png',
    'UK_04.png',
    'UK_05.png',
    'UK_01G.png',
    'UK_02G.png',
    'UK_03G.png',
    'UK_04G.png',
    'UK_05G.png',
    'wayf_logo.png',
  ];
}

/**
 * @param string $icon
 *   The filename of the icon to return size of.
 *
 * @return object|null
 */
function wayf__icon_size($icon): object|null {
  switch ($icon) {
    case 'UK_01G.png':
      return (object) ['width' => 83, 'height' => 34];

    case 'UK_01.png':
      return (object) ['width' => 79, 'height' => 34];

    case 'UK_02.png':
    case 'UK_02G.png':
      return (object) ['width' => 79, 'height' => 41];

    case 'UK_03G.png':
      return (object) ['width' => 93, 'height' => 25];

    case 'UK_03.png':
      return (object) ['width' => 94, 'height' => 26];

    case 'UK_04G.png':
      return (object) ['width' => 57, 'height' => 25];

    case 'UK_04.png':
      return (object) ['width' => 58, 'height' => 24];

    case 'UK_05.png':
    case 'UK_05G.png':
      return (object) ['width' => 71, 'height' => 31];

    case 'wayf_logo.png':
      return (object) ['width' => 125, 'height' => 65];

    default:
      return null;
  }
}

/**
 * {@inheritdoc}
 */
function wayf_form_user_login_form_alter(&$form, &$form_state) {
  $config = \Drupal::config('wayf.settings');

  if ($config->get('alter_login_form')) {
    $icon = \Drupal::service('extension.path.resolver')->getPath('module', 'wayf') . '/icons/' . $config->get('icon');
    $icon_size = wayf__icon_size($config->get('icon'));
    $uri = \Drupal::service('file_url_generator')->generateAbsoluteString($icon);

    $form['wayf_login'] = [
      '#weight' => 1000,
      '#theme' => 'wayf_login',
      '#icon' => [
        'uri'=> $uri,
        'size' => $icon_size
      ],
      '#login_url' => '/wayf/consume',
    ];
  }
}

/**
 * Implements hook_form_alter().
 *
 * Remove the current password field from the user_profile_form form (user/%/edit).
 */
function wayf_form_user_form_alter(&$form, &$form_state) {
  $config = \Drupal::config('wayf.settings');
  
  if (wayf_current_user_wayf_mapped()) {
    if ($config->get('validate_current_pass_disable')) {
      // searches the #validate array for the current_pass validation function, and removes it
      $key = array_search('user_validate_current_pass', $form['#validate']);
      if (FALSE !== $key) {
        unset($form['#validate'][$key]);
      }
      // hide the current password fields
      $form['account']['current_pass_required_value']['#access'] = FALSE;
      $form['account']['current_pass']['#access'] = FALSE;
    }
    if ($config->get('pass_disable')) {
      $form['account']['pass']['#access'] = FALSE;
    }
  }
}

/**
 * @return object
 *   Object with the service providers certificate og location.
 */
function wayf__get_ipd_metadata() {
  $metadata_url = 'https://metadata.wayf.dk/wayf-metadata.xml';

  // Set default information.
  $info = (object) [
    'cert' => '',
    'sso' => '',
    'slo' => '',
  ];

  $metadata = @file_get_contents($metadata_url);

  if (!$metadata) {
    /** @var \Drupal\Core\Messenger\Messenger $messenger */
    $messenger = \Drupal::service('messenger');
    $messenger->addError(t('An error occurred, WAYF metadata service not available'));
  }
  else {
    $xml = simplexml_load_string($metadata);
    $xml->registerXPathNamespace('md', 'urn:oasis:names:tc:SAML:2.0:metadata');
    $xml->registerXPathNamespace('ds', 'http://www.w3.org/2000/09/xmldsig#');

    $idpssodescriptor = '//md:EntityDescriptor/md:IDPSSODescriptor';
    $binding = 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect';

    // Get SignOn and logout urls.
    $sso = $xml->xpath("$idpssodescriptor/md:SingleSignOnService[@Binding='$binding']/@Location");
    $slo = $xml->xpath("$idpssodescriptor/md:SingleLogoutService[@Binding='$binding']/@Location");

    // Get certificate data.
    $cert = $xml->xpath("$idpssodescriptor/md:KeyDescriptor/ds:KeyInfo/ds:X509Data/ds:X509Certificate");

    // Set information form the meta-date.
    $info = (object) [
      'cert' => (string) $cert[0],
      'sso' => (string) $sso[0]['Location'],
      'slo' => (string) $slo[0]['Location'],
    ];
  }

  return $info;
}

/**
 * Import organizations from the WAYF service.
 */
function wayf__organizations_list() {
  // Set default values for config which require dynamic values.
  $config = \Drupal::configFactory()->getEditable('wayf.settings');

  // Get list from WAYF.
  $feed_url = $config->get('sp_organizations_list_url');
  $content = file_get_contents($feed_url);

  // De-code the data and the test end-point.
  $data = json_decode($content, TRUE);
  $data['https://testidp.wayf.dk/module.php/core/loginuserpass.php'] = [
    'da' => 'WAYF test-institution (IDP)',
    'en' => 'WAYF test-institution (IDP)',
    'schacHomeOrganization' => 'testidp.wayf.dk',
  ];

  // Re-encode to json as config don't allow dot's in any depth in keys.
  $config->set('sp_organizations_list', json_encode($data));
  $config->save();
}

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

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