Secure file access with contrib.auth

543 views
Skip to first unread message

Julien

unread,
May 15, 2008, 7:38:30 PM5/15/08
to Django users
Hi,

I'm building a website where users can create projects and upload
files for their projects. I already have a system in place so that
only members of a project can access the project related pages. Now,
I'd like it to be more secure by only giving access to the files of a
project to its members.

It appears to me that simply serving the files with Apache is not
enough. Does Django provide a way to achieve that? Does it mean I'll
have to serve the files with 'static.serve' with a layer of
authorization checking?

What do you think is the best approach?

Thank you very much,

Julien

John Hensley

unread,
May 17, 2008, 1:27:25 PM5/17/08
to django...@googlegroups.com
You can do this with Apache. You need to add mod_xsendfile (http://tn123.ath.cx/mod_xsendfile/
) to your Apache config, then control access to the files with a
Django view. A quick search of this group turns up references to
mod_xsendfile, but no example view, so here's what it might look like
for your project:

@login_required
def sendfile(request, id):
project_file = get_object_or_404(ProjectFile, id=id)

if not (request.user.is_staff or request.user in
project_file.project.members.all()):
return HttpResponseForbidden('No. Sorry.')

response = HttpResponse()
response['X-Sendfile'] = os.path.join(settings.MEDIA_ROOT,
project_file.file)
content_type, encoding =
mimetypes.guess_type(project_file.get_file_url())
if not content_type:
content_type = 'application/octet-stream'
response['Content-Type'] = content_type
response['Content-Length'] = project_file.get_file_size()
response['Content-Disposition'] = 'attachment; filename="%s"' %
os.path.basename(project_file.get_file_url())
return response

You get the idea.

The Apache config denies access to the upload subdirectory altogether;
mod_xsendfile overrides that when it sees the X-Sendfile header in the
response from the Django view. You get to use Django for the complex
authorization, then it lets Apache handle the grunt work of shipping
the file. Pretty nice; I thought this might have been the requirement
that finally pushed me over to nginx or lighty, but not yet....

John

Julien

unread,
May 19, 2008, 4:18:11 AM5/19/08
to Django users
Hi,

Thanks a lot for that info. This is really useful.

I installed mod_xsendfile and I tried your code, but the file that's
downloaded from the view is empty.
This might be because I've tested it using the development server on
port 8080. So I guess Apache is out of the loop :/

I also have Apache running in parallel. Is there any way to have
Apache send the file after the view (executed via dev server:8080)
returns the response? Or is there any way around that issue?

Thanks!

Julien

John Hensley

unread,
May 19, 2008, 9:25:01 AM5/19/08
to django...@googlegroups.com
On May 19, 2008, at 4:18 AM, Julien wrote:

> I installed mod_xsendfile and I tried your code, but the file that's
> downloaded from the view is empty.
> This might be because I've tested it using the development server on
> port 8080. So I guess Apache is out of the loop :/

Yes, this approach only works for requests that go through Apache. I
could have been clearer on how mod_xsendfile works, I guess. The
request is handled just like any Django request. The response from
Django is empty, as you saw; after authorization the view just sets
the X-Sendfile header, which is what tells mod_xsendfile to take over
the response handling and deliver the file. So without Apache and
mod_xsendfile in the loop, you just get that empty response.

You could have Apache add a request header or some other indicator
that the view could check, so it could handle the file itself in your
development environment. Or you could just run under Apache instead of
the dev server.

> I also have Apache running in parallel. Is there any way to have
> Apache send the file after the view (executed via dev server:8080)
> returns the response? Or is there any way around that issue?

No simple way springs to mind.

John

Julien

unread,
May 19, 2008, 9:41:36 AM5/19/08
to Django users
Thanks, this is all clear now.
Is there a method/function/attribute in Django that tells you what
server you're currently running on, that is, the dev server or others
like Apache?
Reply all
Reply to author
Forward
0 new messages