oidc-1.0.0-alpha2/src/Form/RealmsConfigForm.php

src/Form/RealmsConfigForm.php
<?php

namespace Drupal\oidc\Form;

use Drupal\Component\Datetime\TimeInterface;
use Drupal\Component\Utility\Html;
use Drupal\Component\Uuid\UuidInterface;
use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Ajax\ReplaceCommand;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Config\TypedConfigManagerInterface;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Core\Form\ConfigFormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Form\SubformState;
use Drupal\Core\KeyValueStore\KeyValueFactoryInterface;
use Drupal\Core\Link;
use Drupal\Core\Plugin\PluginBase;
use Drupal\Core\Url;
use Drupal\externalauth\AuthmapInterface;
use Drupal\oidc\JsonHttp\JsonHttpClientInterface;
use Drupal\oidc\OpenidConnectRealm\OpenidConnectRealmConfigurableInterface;
use Drupal\oidc\OpenidConnectRealm\OpenidConnectRealmManager;
use Drupal\oidc\Plugin\OpenidConnectRealm\GenericOpenidConnectRealm;
use Psr\Log\LoggerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * The realms configuration form.
 */
class RealmsConfigForm extends ConfigFormBase {

  /**
   * The OpenID Connect realm manager.
   *
   * @var \Drupal\oidc\OpenidConnectRealm\OpenidConnectRealmManager
   */
  protected $realmManager;

  /**
   * The authentication mapping service.
   *
   * @var \Drupal\externalauth\AuthmapInterface
   */
  protected $authmap;

  /**
   * The UUID service.
   *
   * @var \Drupal\Component\Uuid\UuidInterface
   */
  protected $uuid;

  /**
   * The key-value storage factory.
   *
   * @var \Drupal\Core\KeyValueStore\KeyValueFactoryInterface
   */
  protected $keyValueFactory;

  /**
   * The JSON HTTP client.
   *
   * @var \Drupal\oidc\JsonHttp\JsonHttpClientInterface
   */
  protected $jsonHttpClient;

  /**
   * The time service.
   *
   * @var \Drupal\Component\Datetime\TimeInterface
   */
  protected $time;

  /**
   * The logger.
   *
   * @var \Psr\Log\LoggerInterface
   */
  protected $logger;

  /**
   * The entity type manager.
   *
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   */
  protected $entityTypeManager;

  /**
   * Class constructor.
   *
   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
   *   The configuration factory service.
   * @param Drupal\Core\Config\TypedConfigManagerInterface $typed_config_manager
   *   The typed config manager.
   * @param \Drupal\oidc\OpenidConnectRealm\OpenidConnectRealmManager $realm_manager
   *   The OpenID Connect realm manager.
   * @param \Drupal\externalauth\AuthmapInterface $authmap
   *   The authentication mapping service.
   * @param \Drupal\Component\Uuid\UuidInterface $uuid
   *   The UUID service.
   * @param \Drupal\Core\KeyValueStore\KeyValueFactoryInterface $key_value_factory
   *   The key-value storage factory.
   * @param \Drupal\oidc\JsonHttp\JsonHttpClientInterface $json_http_client
   *   The JSON HTTP client.
   * @param \Drupal\Component\Datetime\TimeInterface $time
   *   The time service.
   * @param \Psr\Log\LoggerInterface $logger
   *   The logger.
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
   *   The entity type manager.
   */
  public function __construct(ConfigFactoryInterface $config_factory, TypedConfigManagerInterface $typed_config_manager, OpenidConnectRealmManager $realm_manager, AuthmapInterface $authmap, UuidInterface $uuid, KeyValueFactoryInterface $key_value_factory, JsonHttpClientInterface $json_http_client, TimeInterface $time, LoggerInterface $logger, EntityTypeManagerInterface $entity_type_manager) {
    parent::__construct($config_factory, $typed_config_manager);

    $this->realmManager = $realm_manager;
    $this->authmap = $authmap;
    $this->uuid = $uuid;
    $this->keyValueFactory = $key_value_factory;
    $this->jsonHttpClient = $json_http_client;
    $this->time = $time;
    $this->logger = $logger;
    $this->entityTypeManager = $entity_type_manager;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('config.factory'),
      $container->get('config.typed'),
      $container->get('plugin.manager.openid_connect_realm'),
      $container->get('externalauth.authmap'),
      $container->get('uuid'),
      $container->get('keyvalue'),
      $container->get('oidc.json_http_client'),
      $container->get('datetime.time'),
      $container->get('logger.channel.oidc'),
      $container->get('entity_type.manager')
    );
  }

  /**
   * {@inheritdoc}
   */
  protected function getEditableConfigNames() {
    return ['oidc.settings'];
  }

  /**
   * {@inheritdoc}
   */
  public function getFormId() {
    return 'oidc_realms_config_form';
  }

  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state) {
    $form['redirect_urls'] = [
      '#type' => 'details',
      '#title' => $this->t('Redirect URLs'),
      '#description' => $this->t('These redirect URLs should be accepted by the OpenID Connect authentication server.'),
      '#open' => TRUE,
    ];

    $url = Url::fromRoute('oidc.openid_connect.login_redirect')->setAbsolute();

    $form['redirect_urls']['login'] = [
      '#type' => 'item',
      '#title' => $this->t('Login redirect URL'),
      '#markup' => Link::fromTextAndUrl($url->toString(), $url)->toString(),
    ];

    $url = Url::fromRoute('oidc.openid_connect.logout_redirect')->setAbsolute();

    $form['redirect_urls']['logout'] = [
      '#type' => 'item',
      '#title' => $this->t('Logout redirect URL'),
      '#markup' => Link::fromTextAndUrl($url->toString(), $url)->toString(),
    ];

    // Realms.
    $form['realms'] = [
      '#type' => 'container',
      '#tree' => TRUE,
      '#id' => 'openid-connect-realms',
    ];

    if (!$form_state->has('generic_realms')) {
      // Store the generic realms.
      if ($generic_realms = $this->config('oidc.settings')->get('generic_realms')) {
        $generic_realms = array_combine($generic_realms, $generic_realms);
      }

      $form_state->set('generic_realms', $generic_realms ?? []);

      // Store all realms.
      if ($realms = $this->realmManager->getConfigurable()) {
        $realms = array_combine($realms, $realms);
      }

      $form_state->set('realms', $realms);
    }

    // Add the realm specific forms.
    foreach ($this->configurablePlugins($form_state) as $plugin_id => $plugin) {
      $form['realms'][$plugin_id] = [
        '#type' => 'details',
        '#title' => $plugin->getPluginDefinition()['name'],
        '#open' => TRUE,
      ];

      $url = Url::fromRoute('oidc.openid_connect.login', [
        'realm' => $plugin_id,
      ])->setAbsolute();

      $form['realms'][$plugin_id]['login_url'] = [
        '#type' => 'item',
        '#title' => $this->t('Login URL'),
        '#markup' => Link::fromTextAndUrl($url->toString(), $url)->toString(),
      ];

      $form['realms'][$plugin_id]['settings'] = [
        // Added for the convenience of plugins.
        '#parents' => ['realms', $plugin_id, 'settings'],
      ];

      $subform_state = SubformState::createForSubform($form['realms'][$plugin_id]['settings'], $form, $form_state);
      $form['realms'][$plugin_id]['settings'] = $plugin->buildConfigurationForm($form['realms'][$plugin_id]['settings'], $subform_state);

      // Allow deleting a generic realm.
      if ($plugin instanceof GenericOpenidConnectRealm) {
        $html_id = Html::getId('openid-connect-realms--' . $plugin_id);

        $form['realms'][$plugin_id] += [
          '#prefix' => '<div id="' . $html_id . '">',
          '#suffix' => '</div>',
        ];

        $form['realms'][$plugin_id]['actions'] = [
          '#type' => 'actions',
        ];

        $form['realms'][$plugin_id]['actions']['delete'] = [
          '#type' => 'submit',
          '#value' => $this->t('Delete'),
          '#name' => 'delete_' . $html_id,
          '#parents' => [],
          '#limit_validation_errors' => [],
          '#submit' => ['::deleteGenericRealmSubmit'],
          '#ajax' => [
            'wrapper' => $html_id,
            'callback' => '::deleteGenericRealmAjax',
          ],
          '#plugin_id' => $plugin_id,
        ];
      }
    }

    // Actions.
    $form['actions'] = [
      '#type' => 'actions',
    ];

    $form['actions']['add'] = [
      '#type' => 'submit',
      '#value' => $this->t('Add generic realm'),
      '#limit_validation_errors' => [],
      '#submit' => ['::addGenericRealmSubmit'],
      '#button_type' => 'secondary',
      '#ajax' => [
        'wrapper' => 'openid-connect-realms',
        'callback' => '::addGenericRealmAjax',
        'method' => 'append',
      ],
    ];

    return parent::buildForm($form, $form_state);
  }

  /**
   * {@inheritdoc}
   */
  public function validateForm(array &$form, FormStateInterface $form_state) {
    foreach ($this->configurablePlugins($form_state) as $plugin_id => $plugin) {
      $subform_state = SubformState::createForSubform($form['realms'][$plugin_id]['settings'], $form, $form_state);
      $plugin->validateConfigurationForm($form['realms'][$plugin_id]['settings'], $subform_state);
    }
  }

  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state) {
    $generic_realms = $this->config('oidc.settings')->get('generic_realms');

    // Clear the storage and delete the authmap entries of deleted generic realms.
    if ($generic_realms) {
      $deleted_generic_realms = array_diff(
        $generic_realms,
        $form_state->get('generic_realms')
      );

      foreach ($deleted_generic_realms as $derivative_id) {
        $plugin_id = 'generic' . PluginBase::DERIVATIVE_SEPARATOR;
        $plugin_id .= $derivative_id;

        $this->realmManager
          ->loadInstance($plugin_id)
          ->clearStorage();

        $this->realmManager->deleteInstance($plugin_id);
        $this->authmap->deleteProvider('oidc:' . $plugin_id);
      }
    }

    // Save the generic realms.
    if ($generic_realms = $form_state->get('generic_realms')) {
      $generic_realms = array_values($generic_realms);
    }

    $this->config('oidc.settings')
      ->set('generic_realms', $generic_realms)
      ->save();

    // Save the realm configurations.
    foreach ($this->configurablePlugins($form_state) as $plugin_id => $plugin) {
      $subform_state = SubformState::createForSubform($form['realms'][$plugin_id]['settings'], $form, $form_state);

      $plugin->submitConfigurationForm($form['realms'][$plugin_id]['settings'], $subform_state);
      $this->realmManager->saveInstance($plugin);
    }

    $this->realmManager->clearCachedDefinitions();

    parent::submitForm($form, $form_state);
  }

  /**
   * Form submit handler; Add a new generic realm.
   *
   * @param array $form
   *   An associative array containing the structure of the form.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The current state of the form.
   */
  public function addGenericRealmSubmit(array &$form, FormStateInterface $form_state) {
    // Add a generic realms entry.
    $derivative_id = str_replace('-', '_', $this->uuid->generate());
    $generic_realms = &$form_state->get('generic_realms');
    $generic_realms[$derivative_id] = $derivative_id;

    // Add a realms entry.
    $plugin_id = 'generic' . PluginBase::DERIVATIVE_SEPARATOR . $derivative_id;
    $realms = &$form_state->get('realms');
    $realms[$plugin_id] = $plugin_id;

    $form_state->setRebuild();
  }

  /**
   * Ajax callback; Returns the newly added realm element.
   *
   * @param array $form
   *   An associative array containing the structure of the form.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The current state of the form.
   *
   * @return array
   *   Form element for the newly added realm.
   */
  public function addGenericRealmAjax(array $form, FormStateInterface $form_state) {
    $plugin_id = $form_state->get('realms');
    $plugin_id = end($plugin_id);

    return $form['realms'][$plugin_id];
  }

  /**
   * Form submit handler; Delete a generic realm.
   *
   * @param array $form
   *   An associative array containing the structure of the form.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The current state of the form.
   */
  public function deleteGenericRealmSubmit(array &$form, FormStateInterface $form_state) {
    // Delete the realms entry.
    $plugin_id = $form_state->getTriggeringElement()['#plugin_id'];
    $realms = &$form_state->get('realms');
    unset($realms[$plugin_id]);

    // Delete the generic realms entry.
    $derivative_id = explode(PluginBase::DERIVATIVE_SEPARATOR, $plugin_id)[1];

    $generic_realms = &$form_state->get('generic_realms');
    unset($generic_realms[$derivative_id]);

    $form_state->setRebuild();
  }

  /**
   * Ajax callback; Returns the ajax response for when a generic realm was deleted.
   *
   * @param array $form
   *   An associative array containing the structure of the form.
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The current state of the form.
   *
   * @return \Drupal\Core\Ajax\AjaxResponse
   *   Ajax response for when a realm was deleted.
   */
  public function deleteGenericRealmAjax(array $form, FormStateInterface $form_state) {
    $response = new AjaxResponse();
    $response->addCommand(new ReplaceCommand(NULL, ''));

    return $response;
  }

  /**
   * Get the configurable realm plugins.
   *
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The current state of the form.
   *
   * @return \Drupal\oidc\OpenidConnectRealm\OpenidConnectRealmConfigurableInterface[]
   *   The configurable realm plugins keyed by plugin ID.
   *
   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
   */
  protected function configurablePlugins(FormStateInterface $form_state) {
    $plugins = [];

    foreach ($form_state->get('realms') as $plugin_id) {
      if ($this->realmManager->hasDefinition($plugin_id)) {
        // Existing plugin, load the instance.
        $plugin = $this->realmManager->loadInstance($plugin_id);

        if ($plugin instanceof OpenidConnectRealmConfigurableInterface) {
          $plugins[$plugin_id] = $plugin;
        }
      }
      else {
        // New (unsaved) generic realm.
        $plugins[$plugin_id] = new GenericOpenidConnectRealm(
          [],
          $plugin_id,
          [
            'id' => $plugin_id,
            'name' => $this->t('New realm'),
            'class' => GenericOpenidConnectRealm::class,
            'provider' => 'oidc',
          ],
          $this->keyValueFactory,
          $this->jsonHttpClient,
          $this->time,
          $this->logger,
          $this->entityTypeManager
        );
      }
    }

    return $plugins;
  }

}

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

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