Authentication for direct file access

Hey!

I know this question has been asked regarding prior Kirby versions, but all the linked cookbook entries are offline and I’m not sure whether Bastian’s asset firewall (How to build an asset firewall) is still up to date.

The project I’m working on has a restricted member’s only section which I’ve used Kirby’s really convenient authentication features for. However, this only protects pages, while everyone can still directly access any files. I would like files located in a folder (page) with restricted access also to only be available to eligible authenticated users.

Is there a newer (or even built-in) way to achieve this, or is Bastian’s custom route still the way to go in Kirby 3? And if so, I’m assuming there are some minor changes like having to protect the new media folder?

Thanks a bunch! : )

1 Like

Update: Alright, using bits from Bastian’s asset firewall, I’m putting together a custom route to handle direct file access.
The problem is that there seems to be some code somewhere that is overruling my htaccess configuration for the media folder.

config:

'routes' => [
  'pattern' => ['content/portal/(:all)','media/pages/portal/(:all)'],
  'action' => function($path) {
    //Custom auth code is happening here
  }

htaccess:

# block all files in the portal folder from being accessed directly
RewriteRule ^content/portal/(.*)$ index.php [L]
RewriteRule ^media/pages/portal/(.*)$ index.php [L]

While calling a file within “content/portal” does trigger the custom route, this is not the case for anything within “media/pages/portal”. Is there some bit of code somewhere in Kirby that handles access to the media folder which is causing my rewrite rule to be ignored?

The thing is that you can’t override the media route.

What you could try is prevent that these files are copied to the media folder and only directly accessible from the content folder.

Oh, that’s a bummer. : /

So, how would I go about preventing Kirby from using the media folder? And what kind of adjustments would I need to make for all the media to be loaded from the content folders then?

Maybe these links are helpful:

Thank you - that definitely helped! I’ve now implemented an alternative to the url() file method that returns the url of the file in the content folder.

In case this is relevant to anyone else working on a similar issue: In his asset firewall, as far as I can tell, Bastian is using a file->show() function to display the file, which is no longer listed in the Guide in Kirby 3. I’m trying out the response::file in my route instead to call the file after authentication.

Yes, I need authentication for direct file access also for Kirby 3 like the Kirby 2 How to build an asset firewall.

But I cannot find a HowTo here in the forum or a Cookbook article for this, only a Remark:

We will deal with this in a separate recipe.

But may be your request is different from such a Kirby asset firewall if it would run in Kirby 3.

Hello everyone,
Im working on the same Problem as @Weltverloren. Following this thread and the threads linked further above by @texnixe. I managed to implement another file url method to direct to the image file in the /content folder and also was able to catch unauthorized requests to the image files. My problem right now is that I don’t know how to properly direct an authorized user to the requested file. This is what my code look like right now :

Kirby::plugin('your/plugin', [
          'routes' => [
            [
    	      'pattern' => 'content/intern/showroom/(:all)',
              'action'  => function ($name) {

    		if (!kirby()->user()){
	    	    return '<html><body>NEIN!</body></html>'; //works fine
	    	}
        	else {
		    $loc = kirby()->path();
                    return file($loc);
                  
		}
      }
    ]
  ]
]);

This gives me an JSON parse Error when trying to access the file as a logged in user for some reason. I also tried Response::file(loc) but that just gives me a blank page. I also tried using the $name variable passed to the function. I guess I am in general still confused to what arguments I should pass to Response::file .

Hey KatanaKarl, sorry for the late reply.
Maybe this helps?

//Split directories to array & get filename
$directories = str::split($path, '/');
$filename = array_pop($directories);

//Set the top level folder containing the files to be protected;
$parent = site()->find('myprotectedfolder');

//Cycle through directories until file parent is found
foreach ($directories as $directory) {
  if ($child = $parent->children()->findBy('dirname',$directory)) {
    $parent = $child;
  } else {
    header::notFound();
    die('Page not found');
  }
}

//Handle file
if ($file = $parent->file($filename)) {
  //Insert your user/authorization checks here
  //If checks are successfull, open file:
  echo Response::file($file->root());
} else {
  header::notFound();
  die('File not found');
}

Hey Weltverloren,
Thank you very much for your reply will try it out.