4

I have a contact form for job applications with a file field on it so users can upload their CV. Because of privacy / security, the uploaded CV's must be stored in the private filesystem.

Unfortunately, a problem occurs when an anonymous user tries to add a CV and submit the form. Since the anonymous user does not have access to the uploaded file, the file field's ReferenceAccess constraint (\Drupal\Core\Entity\Plugin\Validation\Constraint\ReferenceAccessConstraint) kicks in and throws a validation error: You do not have access to the referenced entity (file: 1). As a consequence, the user is not allowed to submit the form.

Is there a way to tell Drupal to skip the ReferenceAccess constraint when anonymous users reference a file that they just uploaded themselves?

Update: I came to realize that this does not happen when using the core file field, only with the File Entity module.

1 Answer 1

4

That constraint is validated by \Drupal\Core\Entity\Plugin\Validation\Constraint\ReferenceAccessConstraintValidator. ReferenceAccessConstraintValidator::validate uses the following code.

  /* @var \Drupal\Core\Entity\FieldableEntityInterface $referenced_entity */
  $referenced_entity = $value->entity;
  if ($referenced_entity) {
    $entity = $value->getEntity();
    $check_permission = TRUE;
    if (!$entity->isNew()) {
      $existing_entity = \Drupal::entityManager()->getStorage($entity->getEntityTypeId())->loadUnchanged($entity->id());
      $referenced_entities = $existing_entity->{$value->getFieldDefinition()->getName()}->referencedEntities();

      // Check permission if we are not already referencing the entity.
      foreach ($referenced_entities as $ref) {
        if (isset($referenced_entities[$ref->id()])) {
          $check_permission = FALSE;
          break;
        }
      }
    }

    // We check that the current user had access to view any newly added
    // referenced entity.
    if ($check_permission && !$referenced_entity->access('view')) {
      $type = $value->getFieldDefinition()->getSetting('target_type');
      $this->context->addViolation($constraint->message, [
        '%type' => $type,
        '%id' => $id,
      ]);
    }
  }

(In particular, see the line containing $referenced_entity->access('view').)

We can hook into the file's access control to alter the outcome, with hook_entity_access() or hook_ENTITY_TYPE_access().

Another solution could be to create a new field type which inherits everything from Drupal\file\Plugin\Field\FieldType\FileItem, except for the ReferenceAccess constraint in its plugin definition. You can do this in two ways:

  1. Create a new plugin class that extends the original class, and copy and modify its docblock, including the @FieldType annotation.

  2. Implement hook_field_info_alter(), copy the file plugin definition to your own, and make the necessary adjustments there.

4
  • Thank you. Extending the FieldItem class is a solution I was already considering, and it does indeed work. Implementing hook_ENTITY_TYPE_access works as well. However with either method I wonder if I am creating security holes. What are the possible risks and how could we prevent them? Sep 22, 2016 at 13:17
  • 1
    Yes, you are. At the moment the file is uploaded, even before submit. That the file is private does not protect it from getting downloaded by the owner. And this is any anonymous user with uid 0, if he can guess the filename.
    – 4uk4
    Sep 22, 2016 at 16:36
  • 1
    Since the private file can be viewed only by the owner, you just have to change the owner in the submit function.
    – ssibal
    Sep 22, 2016 at 16:41
  • 1
    That would help, but not for files that are not yet submitted. For this you can use hook_file_download: if (\Drupal::currentUser()->isAnonymous()) { return -1; }
    – 4uk4
    Sep 22, 2016 at 16:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.