You are here

class WebformEntityAccessControlHandler in Webform 6.x

Same name and namespace in other branches
  1. 8.5 src/WebformEntityAccessControlHandler.php \Drupal\webform\WebformEntityAccessControlHandler

Defines the access control handler for the webform entity type.

Hierarchy

Expanded class hierarchy of WebformEntityAccessControlHandler

See also

\Drupal\webform\Entity\Webform.

1 file declares its use of WebformEntityAccessControlHandler
WebformEntityAccessControlHandlerTest.php in tests/src/Unit/WebformEntityAccessControlHandlerTest.php

File

src/WebformEntityAccessControlHandler.php, line 20

Namespace

Drupal\webform
View source
class WebformEntityAccessControlHandler extends EntityAccessControlHandler implements EntityHandlerInterface {
  use WebformEntityStorageTrait;

  /**
   * The request stack.
   *
   * @var \Symfony\Component\HttpFoundation\RequestStack
   */
  protected $requestStack;

  /**
   * The webform source entity plugin manager.
   *
   * @var \Drupal\webform\Plugin\WebformSourceEntityManagerInterface
   */
  protected $webformSourceEntityManager;

  /**
   * The webform access rules manager service.
   *
   * @var \Drupal\webform\WebformAccessRulesManagerInterface
   */
  protected $accessRulesManager;

  /**
   * {@inheritdoc}
   */
  public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) {
    $instance = new static($entity_type);
    $instance->requestStack = $container
      ->get('request_stack');
    $instance->entityTypeManager = $container
      ->get('entity_type.manager');
    $instance->webformSourceEntityManager = $container
      ->get('plugin.manager.webform.source_entity');
    $instance->accessRulesManager = $container
      ->get('webform.access_rules_manager');
    return $instance;
  }

  /**
   * {@inheritdoc}
   */
  protected function checkCreateAccess(AccountInterface $account, array $context, $entity_bundle = NULL) {

    // Check 'administer webform' and 'create webform' permissions.
    if ($account
      ->hasPermission('administer webform')) {
      return WebformAccessResult::allowed();
    }
    elseif ($account
      ->hasPermission('create webform')) {
      return WebformAccessResult::allowed();
    }
    else {
      return WebformAccessResult::neutral();
    }
  }

  /**
   * {@inheritdoc}
   */
  public function checkAccess(EntityInterface $entity, $operation, AccountInterface $account) {

    /** @var \Drupal\webform\WebformInterface $entity */

    // Check 'administer webform' permission.
    if ($account
      ->hasPermission('administer webform')) {
      return WebformAccessResult::allowed();
    }

    // Check 'administer' access rule.
    if ($account
      ->isAuthenticated()) {
      $administer_access_result = $this->accessRulesManager
        ->checkWebformAccess('administer', $account, $entity);
      if ($administer_access_result
        ->isAllowed()) {
        return $administer_access_result;
      }
    }
    $is_owner = (int) $account
      ->id() === (int) $entity
      ->getOwnerId();

    // Check 'view' operation use 'submission_create' when viewing rendered
    // HTML webform or use access 'configuration' when requesting a
    // webform's configuration via REST or JSON API.
    // @see https://www.drupal.org/project/webform/issues/2956771
    if ($operation === 'view') {

      // Check is current request if for HTML.
      $is_html = $this->requestStack
        ->getCurrentRequest()
        ->getRequestFormat() === 'html';

      // Make sure JSON API 1.x requests format which is 'html' is
      // detected properly.
      // @see https://www.drupal.org/project/jsonapi/issues/2877584
      $is_jsonapi = strpos($this->requestStack
        ->getCurrentRequest()
        ->getPathInfo(), '/jsonapi/') === 0 ? TRUE : FALSE;
      if ($is_html && !$is_jsonapi) {
        $access_result = $this->accessRulesManager
          ->checkWebformAccess('create', $account, $entity);
      }
      else {
        if ($account
          ->hasPermission('access any webform configuration') || $account
          ->hasPermission('access own webform configuration') && $is_owner) {
          $access_result = WebformAccessResult::allowed($entity, TRUE);
        }
        else {
          $access_result = $this->accessRulesManager
            ->checkWebformAccess('configuration', $account, $entity);
        }
      }
      if ($access_result instanceof AccessResultReasonInterface) {
        $access_result
          ->setReason('Access to webform configuration is required.');
      }
      return $access_result
        ->addCacheContexts([
        'url.path',
        'request_format',
      ]);
    }

    // Check if 'update', or 'delete' of 'own' or 'any' webform is allowed.
    if ($account
      ->isAuthenticated()) {
      switch ($operation) {
        case 'test':
        case 'update':
          if ($account
            ->hasPermission('edit any webform') || $account
            ->hasPermission('edit own webform') && $is_owner) {
            return WebformAccessResult::allowed($entity, TRUE);
          }
          break;
        case 'duplicate':
          if ($account
            ->hasPermission('create webform') && ($entity
            ->isTemplate() || ($account
            ->hasPermission('edit any webform') || $account
            ->hasPermission('edit own webform') && $is_owner))) {
            return WebformAccessResult::allowed($entity, TRUE);
          }
          break;
        case 'delete':
          if ($account
            ->hasPermission('delete any webform') || $account
            ->hasPermission('delete own webform') && $is_owner) {
            return WebformAccessResult::allowed($entity, TRUE);
          }
          break;
      }
    }

    // Check webform access rules.
    $rules_access_result = $this->accessRulesManager
      ->checkWebformAccess($operation, $account, $entity);
    if ($rules_access_result
      ->isAllowed()) {
      return $rules_access_result;
    }

    // Check submission_* operation.
    if (strpos($operation, 'submission_') === 0) {

      // Grant user with administer webform submission access to do whatever he
      // likes on the submission operations.
      if ($account
        ->hasPermission('administer webform submission')) {
        return WebformAccessResult::allowed();
      }

      // Allow users with 'view any webform submission' or
      // 'administer webform submission' to view all submissions.
      if ($operation === 'submission_view_any' && ($account
        ->hasPermission('view any webform submission') || $account
        ->hasPermission('administer webform submission'))) {
        return WebformAccessResult::allowed();
      }

      // Allow users with 'view own webform submission' to view own submissions.
      if ($operation === 'submission_view_own' && $account
        ->hasPermission('view own webform submission')) {
        return WebformAccessResult::allowed();
      }

      // Allow users with 'edit any webform submission' to update any submissions.
      if ($operation === 'submission_update_any' && $account
        ->hasPermission('edit any webform submission')) {
        return WebformAccessResult::allowed();
      }

      // Allow users with 'edit own webform submission' to update own submissions.
      if ($operation === 'submission_update_own' && $account
        ->hasPermission('edit own webform submission')) {
        return WebformAccessResult::allowed();
      }
      if (in_array($operation, [
        'submission_page',
        'submission_create',
      ])) {

        // Check limit total unique access.
        // @see \Drupal\webform\WebformSubmissionForm::setEntity
        if ($entity
          ->getSetting('limit_total_unique')) {
          $source_entity = $this->webformSourceEntityManager
            ->getSourceEntity('webform');
          $last_submission = $this
            ->getSubmissionStorage()
            ->getLastSubmission($entity, $source_entity, NULL, [
            'in_draft' => FALSE,
          ]);
          if ($last_submission && $last_submission
            ->access('update')) {
            return WebformAccessResult::allowed($last_submission);
          }
        }

        // Check limit user unique access.
        // @see \Drupal\webform\WebformSubmissionForm::setEntity
        if ($entity
          ->getSetting('limit_user_unique')) {

          // Require user to be authenticated to access a unique submission.
          if (!$account
            ->isAuthenticated()) {
            return WebformAccessResult::forbidden($entity);
          }
          $source_entity = $this->webformSourceEntityManager
            ->getSourceEntity('webform');
          $last_submission = $this
            ->getSubmissionStorage()
            ->getLastSubmission($entity, $source_entity, $account, [
            'in_draft' => FALSE,
          ]);
          if ($last_submission && $last_submission
            ->access('update')) {
            return WebformAccessResult::allowed($last_submission);
          }
        }

        // Allow (secure) token to bypass submission page and create access controls.
        $token = $this->requestStack
          ->getCurrentRequest()->query
          ->get('token');
        if ($token && $entity
          ->isOpen()) {
          $source_entity = $this->webformSourceEntityManager
            ->getSourceEntity('webform');
          if ($submission = $this
            ->getSubmissionStorage()
            ->loadFromToken($token, $entity, $source_entity)) {
            return WebformAccessResult::allowed($submission)
              ->addCacheContexts([
              'url',
            ]);
          }
        }
      }

      // The "page" operation is the same as "create" but requires that the
      // Webform is allowed to be displayed as dedicated page.
      // Used by the 'entity.webform.canonical' route.
      if ($operation === 'submission_page') {

        // Completely block access to a template if the user can't create new
        // Webforms.
        $create_access = $entity
          ->access('create', $account, TRUE);
        if ($entity
          ->isTemplate() && !$create_access
          ->isAllowed()) {
          return WebformAccessResult::forbidden($entity)
            ->addCacheableDependency($create_access);
        }

        // Block access if the webform does not have a page URL.
        if (!$entity
          ->getSetting('page')) {
          $source_entity = $this->webformSourceEntityManager
            ->getSourceEntity('webform');
          if (!$source_entity) {
            return WebformAccessResult::forbidden($entity);
          }
        }
      }

      // Convert submission 'page' to corresponding 'create' access rule.
      $submission_operation = str_replace('submission_page', 'submission_create', $operation);

      // Remove 'submission_*' prefix.
      $submission_operation = str_replace('submission_', '', $submission_operation);

      // Check webform submission access rules.
      $submission_access_result = $this->accessRulesManager
        ->checkWebformAccess($submission_operation, $account, $entity);
      if ($submission_access_result
        ->isAllowed()) {
        return $submission_access_result;
      }

      // Check webform 'update' access.
      $update_access_result = $this
        ->checkAccess($entity, 'update', $account);
      if ($update_access_result
        ->isAllowed()) {
        return $update_access_result;
      }
    }

    // NOTE: Not calling parent::checkAccess().
    // @see \Drupal\Core\Entity\EntityAccessControlHandler::checkAccess
    if ($operation === 'delete' && $entity
      ->isNew()) {
      return WebformAccessResult::forbidden($entity);
    }
    else {
      return WebformAccessResult::neutral($entity);
    }
  }

}

Members

Namesort descending Modifiers Type Description Overrides
DependencySerializationTrait::$_entityStorages protected property
DependencySerializationTrait::$_serviceIds protected property
DependencySerializationTrait::__sleep public function 2
DependencySerializationTrait::__wakeup public function 2
EntityAccessControlHandler::$accessCache protected property Stores calculated access check results.
EntityAccessControlHandler::$entityType protected property Information about the entity type.
EntityAccessControlHandler::$entityTypeId protected property The entity type ID of the access control handler instance.
EntityAccessControlHandler::$viewLabelOperation protected property Allows to grant access to just the labels. 5
EntityAccessControlHandler::access public function Checks access to an operation on a given entity or entity translation. Overrides EntityAccessControlHandlerInterface::access 1
EntityAccessControlHandler::checkFieldAccess protected function Default field access as determined by this access control handler. 4
EntityAccessControlHandler::createAccess public function Checks access to create an entity. Overrides EntityAccessControlHandlerInterface::createAccess 1
EntityAccessControlHandler::fieldAccess public function Checks access to an operation on a given entity field. Overrides EntityAccessControlHandlerInterface::fieldAccess
EntityAccessControlHandler::getCache protected function Tries to retrieve a previously cached access value from the static cache.
EntityAccessControlHandler::prepareUser protected function Loads the current account object, if it does not exist yet.
EntityAccessControlHandler::processAccessHookResults protected function We grant access to the entity if both of these conditions are met:
EntityAccessControlHandler::resetCache public function Clears all cached access checks. Overrides EntityAccessControlHandlerInterface::resetCache
EntityAccessControlHandler::setCache protected function Statically caches whether the given user has access.
EntityAccessControlHandler::__construct public function Constructs an access control handler instance. 6
EntityHandlerBase::$moduleHandler protected property The module handler to invoke hooks on. 5
EntityHandlerBase::moduleHandler protected function Gets the module handler. 5
EntityHandlerBase::setModuleHandler public function Sets the module handler for this handler.
StringTranslationTrait::$stringTranslation protected property The string translation service. 4
StringTranslationTrait::formatPlural protected function Formats a string containing a count of items.
StringTranslationTrait::getNumberOfPlurals protected function Returns the number of plurals supported by a given language.
StringTranslationTrait::getStringTranslation protected function Gets the string translation service.
StringTranslationTrait::setStringTranslation public function Sets the string translation service to use. 2
StringTranslationTrait::t protected function Translates a string to the current language or to a given language.
WebformEntityAccessControlHandler::$accessRulesManager protected property The webform access rules manager service.
WebformEntityAccessControlHandler::$requestStack protected property The request stack.
WebformEntityAccessControlHandler::$webformSourceEntityManager protected property The webform source entity plugin manager.
WebformEntityAccessControlHandler::checkAccess public function Performs access checks. Overrides EntityAccessControlHandler::checkAccess
WebformEntityAccessControlHandler::checkCreateAccess protected function Performs create access checks. Overrides EntityAccessControlHandler::checkCreateAccess
WebformEntityAccessControlHandler::createInstance public static function Instantiates a new instance of this entity handler. Overrides EntityHandlerInterface::createInstance
WebformEntityStorageTrait::$entityStorageToTypeMappings protected property An associate array of entity type storage aliases.
WebformEntityStorageTrait::$entityTypeManager protected property The entity type manager. 5
WebformEntityStorageTrait::getEntityStorage protected function Retrieves the entity storage.
WebformEntityStorageTrait::getSubmissionStorage protected function Retrieves the webform submission storage.
WebformEntityStorageTrait::getWebformStorage protected function Retrieves the webform storage.
WebformEntityStorageTrait::__get public function Implements the magic __get() method.