Support for private files system, or similar access restriction

Created on 23 June 2023, almost 2 years ago
Updated 5 July 2023, almost 2 years ago

Problem/Motivation

We have an intranet site that uses Acquia DAM to serve assets like images and documents. Currently, the site uses the media_acquiadam module. The file fields on our media types are implemented using the private filesystem. Since that module downloads the file to the server, the proper permissions are maintained. Even if a user were to right click on an image on the site and copy the URL, it would be inaccessible to unauthenticated users.

Does this module support the private filesystem or a similar means for restriction access? While trying to migrate our existing site and assets to acquia_dam, I'm struggling to find a way to set up similar access restrictions. Since there is not a traditional file field, what would be the best way to go about this?

Steps to reproduce

  1. Set up a site with a connection to Acquia DAM using this module
  2. Embed an image into your site via the WYSIWYG editor or an entity reference field
  3. View the media entity
  4. Right click the image file
  5. Observe the URL is of the pattern https://<subdomain>.widen.net/content/gxzcvxtogx/web/test-image-scenario.jpg
  6. Paste this URL into an incognito window
  7. Observe you are able to see the image without being logged into Drupal

Proposed resolution

  • For previous projects, I've implemented an EventSubscriber that returns a BinaryFileResponse when viewing the media entity's canonical path. This obscures the file path on the server and allows a path alias to be used for direct access of the file. I'm able to use a TrustedRedirectResponse with `acquia_dam` but the user is redirected to a Widen CDN link. I could temporarily fetch and save the file to use a BinaryFileResponse, but there could be performance implications.
  • I've not developed or implemented a custom stream wrapper, but there may be a possibility of extending it.

Remaining tasks

n/a

User interface changes

n/a

API changes

n/a

Data model changes

n/a

✨ Feature request
Status

Active

Version

1.0

Component

Code

Created by

πŸ‡ΊπŸ‡ΈUnited States patrickfweston Columbus, Ohio

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

  • Issue created by @patrickfweston
  • πŸ‡ΊπŸ‡ΈUnited States patrickfweston Columbus, Ohio
  • πŸ‡ΊπŸ‡ΈUnited States patrickfweston Columbus, Ohio

    I was actually able to get a proof of concept working where the path alias of the media entity is used, but the image content is displayed inline in the browser.

    Here's what my EventSubscriber looks like:

      public function onRequest(RequestEvent $event) {
        // Get values from the request.
        $attributes = $event->getRequest()->attributes;
        $media = $attributes->get('media');
        $route_name = $attributes->get('_route');
    
        // Redirect to the file directly if we are accessing a media entity's full
        // view mode route.
        $view_mode = $attributes->get("view_mode");
        if ($media && !str_contains($route_name, 'media_entity_download') && $route_name && $view_mode === 'full') {
          // Get the source for this media entity.
          $source = $media->getSource();
    
          // Grab the ID values from the source information to be fetched from the
          // Acquia DAM.
          $id_values = $source->getSourceFieldValue($media);
    
          // Get the client for the Acquia DAM and get the asset object.
          $client = \Drupal::service('acquia_dam.client.factory')->getSiteClient();
          $asset = $client->getAsset($id_values['asset_id'], $id_values['version_id'] ?? '');
    
          // Get the embed URL for the asset.
          $url = $asset["embeds"]["original"]["url"];
    
          // Create a response with the URL's content.
          $response = new Response(file_get_contents($url));
    
          // Create the disposition of the file to display it inline.
          $disposition = $response->headers->makeDisposition(
            ResponseHeaderBag::DISPOSITION_INLINE,
            $asset['filename']
          );
    
          // Create the MIME type from the Asset's properties.
          $mime_type = $asset["file_properties"]["format_type"] . "/" . $asset["file_properties"]["format"];
    
          // Initialize headers for the response.
          $headers = [
            'Content-Type' => $mime_type,
            'Content-Disposition' => $disposition . '"',
            'Content-Description' => ' File Transfer',
          ];
    
          // Return the response object.
          $response->headers->add($headers);
          $response->setStatusCode(Response::HTTP_OK);
    
          // Dispatch request
          $event->setResponse($response);
        }
      }
    
  • πŸ‡ΊπŸ‡ΈUnited States mglaman WI, USA

    Tagging as a feature request, we'll raise internally.

Production build 0.71.5 2024