Unverified Commit 8622072b authored by Alex Pott's avatar Alex Pott
Browse files

fix: #1452100 Private file download returns access denied, when file attached...

fix: #1452100 Private file download returns access denied, when file attached to revision other than current

By: jlongbottom
By: berdir
By: therainmakor
By: gapple
By: benjy
By: cilefen
By: eiriksm
By: cristiroma
By: leontin
By: amateescu
By: drenton
By: shubhangi1995
By: acbramley
By: catch
By: alexpott
By: fenstrat
By: larowlan
By: mxr576
By: rakshith.thotada
By: kim.pepper
By: richard.thomas
By: effulgentsia
By: lauriii
By: xjm
By: nicxvan
(cherry picked from commit c31dedaf)
parent c78fd35c
Loading
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -446,6 +446,13 @@ function drupal_static_reset($name = NULL): void {
    case 'filter_formats':
      @trigger_error("Using drupal_static_reset() with 'filter_formats' as argument is deprecated in drupal:11.4.0 and is removed from drupal:13.0.0. No replacement is provided. See https://www.drupal.org/node/3035368", E_USER_DEPRECATED);
      break;

    case 'file_get_file_references':
    case 'file_get_file_references:field_columns':
      @trigger_error("Calling drupal_static_reset() with \"$name\" as argument is deprecated in drupal:11.4.0 and is removed from drupal:13.0.0. Use \Drupal::service('cache.memory')->invalidateTags(['file_references']) instead. See https://www.drupal.org/node/3573884", E_USER_DEPRECATED);
      \Drupal::service('cache.memory')->invalidateTags(['file_references']);
      break;

  }
  drupal_static($name, NULL, TRUE);
}
+3 −3
Original line number Diff line number Diff line
@@ -272,8 +272,8 @@ public function entityRevisionDelete(EntityInterface $entity): void {
  /**
   * Implements hook_file_download().
   *
   * @see file_file_download()
   * @see file_get_file_references()
   * @see \Drupal\file\Hook\FileDownloadHook
   * @see \Drupal\file\FileReferenceResolver::getReferences()
   */
  #[Hook('file_download')]
  public function fileDownload($uri): array|int|null {
@@ -300,7 +300,7 @@ public function fileDownload($uri): array|int|null {
    // Editor.module MUST NOT call $file->access() here (like
    // file_file_download() does) as checking the 'download' access to a file
    // entity would end up in FileAccessControlHandler->checkAccess() and
    // ->getFileReferences(), which calls file_get_file_references(). This
    // \Drupal\file\FileReferenceResolver::getReferences(). This
    // latter one would allow downloading files only handled by the file.module,
    // which is exactly not the case right here. So instead we must check if the
    // current user is allowed to view any of the entities that reference the
+12 −0
Original line number Diff line number Diff line
@@ -453,8 +453,14 @@ function template_preprocess_file_upload_help(&$variables): void {
 *   entity_id and the value is an entity referencing this file.
 *
 * @ingroup file
 *
 * @deprecated in drupal:11.4.0 and is removed from drupal:13.0.0. Use
 *   \Drupal::service(\Drupal\file\FileReferenceResolver::class) instead.
 *
 * @see https://www.drupal.org/node/3573884
 */
function file_get_file_references(FileInterface $file, ?FieldDefinitionInterface $field = NULL, $age = EntityStorageInterface::FIELD_LOAD_REVISION, $field_type = 'file') {
  @trigger_error(__FUNCTION__ . ' is deprecated in drupal:11.4.0 and is removed from drupal:13.0.0. Use \Drupal::service(\Drupal\file\FileReferenceResolver::class)->getReferences($file) instead. See https://www.drupal.org/node/3573884', E_USER_DEPRECATED);
  $references = &drupal_static(__FUNCTION__, []);
  $field_columns = &drupal_static(__FUNCTION__ . ':field_columns', []);

@@ -530,8 +536,14 @@ function file_get_file_references(FileInterface $file, ?FieldDefinitionInterface
 * @return bool
 *   The field column if the field references {file_managed}.fid, typically
 *   fid, FALSE if it does not.
 *
 * @deprecated in drupal:11.4.0 and is removed from drupal:13.0.0. There is no
 *   replacement.
 *
 * @see https://www.drupal.org/node/3573884
 */
function file_field_find_file_reference_column(FieldDefinitionInterface $field) {
  @trigger_error(__FUNCTION__ . ' is deprecated in drupal:11.4.0 and is removed from drupal:13.0.0. There is no replacement. See https://www.drupal.org/node/3573884', E_USER_DEPRECATED);
  $schema = $field->getFieldStorageDefinition()->getSchema();
  foreach ($schema['foreign keys'] as $data) {
    if ($data['table'] == 'file_managed') {
+1 −0
Original line number Diff line number Diff line
@@ -37,3 +37,4 @@ services:
  Drupal\file\EventSubscriber\DefaultContentSubscriber:
    calls:
      - [setLogger, ['@logger.channel.file']]
  Drupal\file\FileReferenceResolver: ~
+28 −12
Original line number Diff line number Diff line
@@ -6,6 +6,7 @@
use Drupal\Core\Entity\EntityAccessControlHandler;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Entity\RevisionableInterface;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Session\AccountInterface;
@@ -29,20 +30,31 @@ protected function checkAccess(EntityInterface $entity, $operation, AccountInter
          return AccessResult::allowedIfHasPermission($account, 'access content');
        }
      }
      elseif ($references = $this->getFileReferences($entity)) {
        foreach ($references as $field_name => $entity_map) {
          foreach ($entity_map as $referencing_entities) {
            /** @var \Drupal\Core\Entity\EntityInterface $referencing_entity */
            foreach ($referencing_entities as $referencing_entity) {
              $entity_and_field_access = $referencing_entity->access('view', $account, TRUE)->andIf($referencing_entity->$field_name->access('view', $account, TRUE));
              if ($entity_and_field_access->isAllowed()) {
                return $entity_and_field_access;
      $has_references = FALSE;
      $resolver = \Drupal::service(FileReferenceResolver::class);
      foreach ($resolver->getReferences($entity) as $usage) {
        $has_references = TRUE;
        $referencing_entity = $resolver->loadEntityFromUsage($usage);

        // Either check view or revision access depending on this being a
        // default revision or not.
        if ($referencing_entity instanceof RevisionableInterface && !$referencing_entity->isDefaultRevision()) {
          $entity_and_field_access = $referencing_entity->access('view revision', $account, TRUE);
        }
        else {
          $entity_and_field_access = $referencing_entity->access('view', $account, TRUE);
        }

        // If access to that entity is allowed, check field access as well,
        // if access is still allowed, return this result.
        if ($entity_and_field_access->isAllowed()) {
          $entity_and_field_access = $entity_and_field_access->andIf($referencing_entity->get($usage->fieldName)->access('view', $account, TRUE));
          if ($entity_and_field_access->isAllowed()) {
            return $entity_and_field_access;
          }
        }
      }
      elseif ($entity->getOwnerId() == $account->id()) {
      if (!$has_references && $entity->getOwnerId() == $account->id()) {
        // This case handles new nodes, or detached files. The user who uploaded
        // the file can access it even if it's not yet used.
        if ($account->isAnonymous()) {
@@ -91,9 +103,13 @@ protected function checkAccess(EntityInterface $entity, $operation, AccountInter
   *   A multidimensional array. The keys are field_name, entity_type,
   *   entity_id and the value is an entity referencing this file.
   *
   * @see file_get_file_references()
   * @deprecated in drupal:11.4.0 and is removed from drupal:13.0.0. Use
   *   \Drupal::service(\Drupal\file\FileReferenceResolver::class) instead.
   *
   * @see https://www.drupal.org/node/3573884
   */
  protected function getFileReferences(FileInterface $file) {
    @trigger_error(__METHOD__ . ' is deprecated in drupal:11.4.0 and is removed from drupal:13.0.0. Use \Drupal::service(\Drupal\file\FileReferenceResolver::class) instead. See https://www.drupal.org/node/3573884', E_USER_DEPRECATED);
    return file_get_file_references($file, NULL, EntityStorageInterface::FIELD_LOAD_REVISION, NULL);
  }

Loading