views:

118

answers:

3

In my app users can upload files for other users. To make the uploaded files accesible only for the addresse I need some kind of static files authentication system.

My idea, is to create the apache hosted directory for each user and to limit access to this derectory using .htaccess.

This means that each time new django user is created, I need to create a directory and the appropriate .htaccess file in it. I know I should do it using post_save signals on User model but I don't know how to create the .htaccess in the user's directory from python level. Can you help me with that?

Or perhaps you have better solution to my problem?

A: 
  1. Use python to rewrite the .htaccess automatically?
  2. Use a database with users and use a Apache sessions to authenticate?
Delan Azabani
Uszy Wieloryba
Most authentication is done by validating the username + password from a database, e.g. MySQL, then creating a session through `session_start()`.
Delan Azabani
+1  A: 

Why not have an PrivateUploadedFile object that has a field for the file and a m2m relation for any Users who are allowed to read that file? Then you don't have to mess with Apache conf at all...

from django.contrib.auth.models import User
from django.db import models
import hashlib

def generate_obfuscated_filename(instance, filename):
   hashed_filename = hashlib.sha1(str(filename)) #you could salt this with something
   return u"your/upload/path/%s.%s" % (hashed_filename, filename.split(".")[-1]) #includes original file format extension



class PrivateUploadedFile(models.Model):
  file = models.FileField(upload_to=generate_obfuscated_filename)
  recipients = models.ManyToManyField('User')
  uploader = models.ForeignKey('User', related_name="files_uploaded")

  def available_to(self, user):
     #call this as my_uploaded_file_instance.available_to(request.user) or any other user object you want
     return user in self.recipients.all() #NB: not partic. efficient, but can be tuned
stevejalim
I have such thing, but I does not solve the problem. Notice that the file must be uploaded to public directory to be accessible from outside. I can verify if the user is the recipient in the view, but the file is still accessible for everyone.
Uszy Wieloryba
Ok, why don't you obfuscate the filename then with a hash - i'll edit the code above to reflect this
stevejalim
Though I appreciate that I'm giving you security through obscurity, rather than a proper authentication-based solution
stevejalim
A: 

Add a view that controls the authentication of the user, and serve the file via django's static files serving tools:

def get_file(request, some_id):
    # check that the user is allowed to see the file
    # obtain the file name:
    path = path_from_id(some_id)
    # serve the file:
    return django.views.static.serve(request, path, document_root=your_doc_root)

This is a perfectly secure solution, but perhaps not ideal if you serve an enormous of files in that way.

Edit: the disclaimer on the django page does not apply here. Obviously, it would be inefficient to serve all your files with static.serve. It is however secure in the sense that you only serve the files to the users that are allowed to.

Olivier
Logically it does the trick, but as you pointed out, there might be some efficiency issues
Uszy Wieloryba
Well that's only if you serve a massive amount of files in this way! If I were you I'd implement that and reconsider it only if you can measure a performance impact. You know, "premature optimization is the root of all evil". ;-)
Olivier
Why do you say this is "perfectly secure" when the page you link to has a huge disclaimer saying: "Using this method is inefficient and insecure. Do not use this in a production setting. Use this only for development."
Daniel Roseman
@Daniel sigh... I knew someone would react on that disclaimer
Olivier
+1 Not sure why you were voted down, as this seems to be the best solution for the OP and it avoids the ugliness of trying to generate Apache conf files with Django/Python.
Liam