Skip to content

Instantly share code, notes, and snippets.

@ksamuel
Created April 5, 2011 21:36
Show Gist options
  • Save ksamuel/904623 to your computer and use it in GitHub Desktop.
Save ksamuel/904623 to your computer and use it in GitHub Desktop.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# vim: ai ts=4 sts=4 et sw=4
"""
Decorators to facilitate authentifications and redirections in Facebook
apps
"""
import uuid
import urllib2
import json
import urlparse
from functools import update_wrapper
from urlparse import urljoin
from django.conf import settings
from django.shortcuts import redirect
from django.contrib.auth.models import User
from django.contrib.sites.models import Site
from django.http import HttpResponse
from utils import parse_signed_request, ParsingError
def require_auth():
"""
Put it on a view. It will check if the 'signed_request' POST param is
available, and if not, will redirect to the facebook url for this app.
If 'signed_request' is available and the user is anonymous, log him
in using the Dynoo backend authentification system.
"""
def decorator(func):
def wrapper(request, *args, **kwargs):
app_settings = settings.FACEBOOK_APPS['dynoo']
signed_request = request.POST.get('signed_request', None)
if getattr(settings, 'SKIP_AUTH', False):
uid = request.session['uuid'] = app_settings['test_uuid']
device_id = request.session['device_id'] = app_settings['device_id']
request.session['name'] = app_settings['test_name']
else:
uid = request.session.get('uuid', None)
device_id = request.session.get('device_id', None)
# if the signed request is passed, check its content
# agains the one in session to ensure we are still
# dealing with the same user
if all((signed_request, uid, device_id)):
print "Checking against signed request"
print uid, device_id
# extract the FB user data from the signed request
# if there is any error, redirect to an error screen
try:
data = parse_signed_request(signed_request,
app_settings['secret_key'])
except ParsingError, e:
# todo: log on error
print "Parsing error"
return redirect('fb_dynoo:unknowned_error')
except Exception, e:
return redirect('fb_dynoo:unknowned_error')
try:
fuid = data['user_id']
except KeyError, TypeError:
fuid = None
# if fuid does not match the one in session
# the user probably switched account
saved_fuid = request.session.get('fuid', None)
if not fuid or fuid != saved_fuid:
uid = None
device_id = None
print "Signed request doesn't match"
if not (uid and device_id):
print "Needs authentification"
request.session.clear()
device_id = device_id or str(uuid.uuid4())
request.session['device_id'] = device_id
# calls the API once to check if this device_id is
# knowned. if yes, get the uid from it and log in
# the user
auth_url = app_settings['dynoo_auth_url'].rstrip()
app_url = app_settings['app_url']
current_url = urllib2.quote(request.get_full_path())
callback = "%s?redirect_path=%s" % (app_url, current_url)
url = '%s?device_id=%s&callback=%s' % (
auth_url, device_id, urllib2.quote(callback))
data = urllib2.urlopen(url).read(10000)
result = json.loads(data)
uid = result.get('uuid', None)
name = result.get('name', None)
fuid = result.get('fuid', None)
if not uid:
print "Unknowned user. Needs auth redirection"
print "Redirect to %s" % result['url']
# return a response containing a javascript code
# that redirect the parent of the iframe to
# the permission page
# if we do a normal redirection, it will open
# facebook in the iframe and Facebook don't like
# recursion
redirect_page = """
<head>
<script type="text/javascript">
parent.location.href='%s';
</script>
</head>
""" % result['url']
return HttpResponse(redirect_page)
request.session['uuid'] = uid
request.session['name'] = name
request.session['fuid'] = fuid
return func(request, *args, **kwargs)
return update_wrapper(wrapper, func)
return decorator
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment