16

I'm building a site where registered users can upload files. Those files are then served via Apache. Only users who are logged in should be able to access those files.

I have read this page but it seems that people would have to log in twice to access both the site and the media, each time using a different type of login box.

Is there a way around this or is there some other way to limit access to static media served by Apache using the Django authentication database?

I'm using mod_python.

EDIT: How I ended up solving this after reading Van Gale's answer and this:

  1. Switched to WSGI.
  2. Installed mod_xsendfile
  3. Moved all public media files into a subfolder in /media/public
  4. Added access to the public folder using an Alias /media/public /var/www.../media/public
  5. Added WSGIScriptAlias /media/protected/ /var/www.../apache/django.wsgi (same handler as for the rest of the site)
  6. Added XSendFile On and XSendFileAllowAbove On
  7. To the Django app I added an urlconf for /media/protected which does basically what's here, only modified for my authentication system. It handles urls such as /media/protected/GROUP_ID/file so that only members of the GROUP can download the files.
Tomas Andrle
  • 13,132
  • 15
  • 75
  • 92
  • The other possible problem with the approach described in the Django docs is that it appears to be using basic authentication - this sends passwords in base64-encoded cleartext, so is not secure unless you also use SSL for all requests. – Vinay Sajip Aug 27 '09 at 12:53

2 Answers2

11

The usual way to do this is to pass back a special header to the web server.

You can do it with nginx using x-accel-redirect as in this Django snippet.

For Apache, it should be pretty similar using the mod_xsendfile module (discussion and examples on Django users mailing list).

Van Gale
  • 43,536
  • 9
  • 71
  • 81
  • I'm going to give mod_xsendfile a try. – Tomas Andrle Aug 27 '09 at 18:06
  • It worked! Had to switch to WSGI but that wasn't as hard as I thought it would be. – Tomas Andrle Aug 27 '09 at 22:07
  • In mod_wsgi 3.0, you can pass back a Location with 200 status. The directories need to be mapped via a URL though, which is then referenced in Location. Since URL mapping required, to ensure remote clients can't get to them, you need to use a mod_rewrite rule to make them forbidden if not an Apache sub request. The other option is to make use of wsgi.file_wrapper extension to optimally return file direct from Django. Right now can't do this with Django, but will be allowed in future version. – Graham Dumpleton Aug 28 '09 at 11:03
  • An example implementation of the X-Sendfile approach is shown here: http://stackoverflow.com/questions/1156246/having-django-serve-downloadable-files – Isaac Sutherland Jul 16 '12 at 15:43
2

If you have freedom to switch from Apache to lighttpd, then the most straightforward solution would be to use mod_secdownload which would do exactly what you want, that is, provide application authentication while serving the actual files via web server.

However if you are stuck with Apache, then I suggest mod_auth_token, here they mention PHP but you can generate the token in Python or any other language. Using mod_auth_token you will be able to generate the token in your application, and then have web server serve the static file utilizing that token.

Sergey Golovchenko
  • 18,203
  • 15
  • 55
  • 72