3

I recently added a security check in my Routes.php file to ensure that only people who should be able to access images can access those images.

It works as expected for user interaction, but now when I generate PDFs it seems that the process which gets the image is not allowed access and therefore the image cannot load in the PDF.

Here is how the image is accessed in the Blade file for the PDF:

<img src="{{ URL::to('image/person/signature',$person->person_token) }} ">

I am accessing it through the Facade (URL), but for some reason the session cookie does not appear to be passed in this request, hence why it fails the security check.

Here is the security check:

Route::get('image/person/signature/{authToken}',function($authToken){
   // This permission checking should actually probably be in the filters file
   $loggedUser = Auth::user();

    $person = Person::getByAuthToken($authToken);
    if ($person instanceOf Person){
       // PDF is getting shut out here
       if($loggedUser->company_id == $person->company_id || $loggedUser->isAdmin()) {
           // Processing goes here 
       } else{
           die('You are not authorized to perform this function. Your IP address has been logged.');
       }
     } else {
         die('You are not authorized to perform this function. Your IP address has been logged.');
     }
});

I also tried adding the following conditions to the security check to allow the process access which did not work:

  • $loggedUser instanceOf PDF
  • $loggedUser instanceOf ServiceProvider
  • Auth::check()

The fact that Auth::check() didn't work is suspicious and would indicate that cookie/session information is not being passed..

I somehow doubt changing any of the settings in DOMPDF will help with this, since it's simply being blocked by the security check. Here is the actual tool I am using for DOMPDF / Laravel integration. DomPDF is registered as a Service Provider in my app under the Facade of PDF.

Remember, this is certainly not a path issue because it was working before I implemented this security check. All of the questions related to this on SO seem to stem from that.

How can I allow the PDF process to access the image, without wacky workarounds?

Marcel Gruber
  • 6,668
  • 6
  • 34
  • 60
  • 1
    quick fast solution, How about checking the Request IP, using Request::getClientIp(), if it is on a "whitelist" allow access. – Ezequiel Moreno May 20 '15 at 21:11
  • @EzequielMoreno that certainly is an interesting idea, and it does work because it is the external server IP which is making the request, but obviously it could be easy to break if someone spoofs their IP and there is no packet filtering done by the network. Thanks for the idea. – Marcel Gruber May 21 '15 at 22:39

1 Answers1

2

Probably the easiest method is to skip HTTP altogether and access your file via the filesystem.

<img src="{{ public_path() . '/image/person/signature }} ">

(I'm not too familiar with Laravel, so maybe someone can clean this up.)

This presumes that the image is accessible under the public path of the local filesystem. If it's a generated file, something not directly accessible, or maybe too much work (e.g. you're reusing the same template for web and PDF generation) then you'll have to consider something a bit more complex.


So something a bit more complex ... create a custom stream context from the user's request and pass it to dompdf. If you're using, for example, cookies for authentication you could try something like this:

$cookie_data = implode(
  "; ", array_map(
    function($k, $v) {
      return "$k=$v";
    },
    array_keys($_COOKIE),
    array_values($_COOKIE)
  )
);

$opts = array(
  'http'=>array(
    'method'=>'GET',
    'header'=>'Cookie: ' . $cookie_data
  )
);
$context = stream_context_create($opts);

$dompdf = new DOMPDF;
$dompdf->set_http_context($context);
...

I'm just taking a stab in the dark here (I don't have to test this do I?). This presumes that your user is the one triggering the PDF rendering (seems to be the case) and that the AuthN mechanism is one that can be accessed and added to the custom stream context. You may have to tweak the context to get the exact configuration you need to pass through the authentication.

Context code lifted modified from PHP file_get_contents() and headers and cookie munger from Sending cookies stored on $_COOKIE global using PHP curl.

Community
  • 1
  • 1
BrianS
  • 13,284
  • 15
  • 62
  • 125
  • The very first line of your answer might just be the actual right way to do it. This view is never exposed to the user and is used only by the server to generate PDFs. It makes absolute sense to just get it right from the source, then. I really appreciate your answer despite your lack of familiarity with Laravel. – Marcel Gruber May 22 '15 at 04:35
  • Feel free to edit that line so that it provides a more accurate code sample (for future visitors). – BrianS May 22 '15 at 16:33
  • (Maybe one day I'll actually test out authentication passthrough.) – BrianS May 22 '15 at 16:33
  • As a followup, I can now say that you're absolutely right about accessing it directly. For larger applications such as mine, determining the deeply nested filepaths is difficult, but we have built a custom storage manager class which is capable of spitting out filepaths based on certain parameters. I actually got it working and it seems to be the truest solution; it will just be time consuming to go back and change all of the different PDF views. Thank you, again! – Marcel Gruber May 24 '15 at 05:31