Skip to content
Snippets Groups Projects
Commit dbc577e6 authored by Ben Adida's avatar Ben Adida
Browse files

readded auth code as part of the core

parent 6b0803e1
Branches
No related tags found
No related merge requests found
Showing
with 2548 additions and 0 deletions
from django.conf import settings
TEMPLATE_BASE = settings.AUTH_TEMPLATE_BASE or "auth/templates/base.html"
# enabled auth systems
import auth_systems
ENABLED_AUTH_SYSTEMS = settings.AUTH_ENABLED_AUTH_SYSTEMS or auth_systems.AUTH_SYSTEMS.keys()
DEFAULT_AUTH_SYSTEM = settings.AUTH_DEFAULT_AUTH_SYSTEM or None
twitterconfig.py
facebookconfig.py
AUTH_SYSTEMS = {}
import twitter, password, cas, facebook, google, yahoo
AUTH_SYSTEMS['twitter'] = twitter
AUTH_SYSTEMS['password'] = password
AUTH_SYSTEMS['cas'] = cas
AUTH_SYSTEMS['facebook'] = facebook
AUTH_SYSTEMS['google'] = google
AUTH_SYSTEMS['yahoo'] = yahoo
# not ready
#import live
#AUTH_SYSTEMS['live'] = live
"""
CAS (Princeton) Authentication
Some code borrowed from
https://sp.princeton.edu/oit/sdp/CAS/Wiki%20Pages/Python.aspx
"""
from django.http import *
from django.core.mail import send_mail
from django.conf import settings
import sys, os, cgi, urllib, urllib2, re
from xml.etree import ElementTree
CAS_EMAIL_DOMAIN = "princeton.edu"
CAS_URL= 'https://fed.princeton.edu/cas/'
CAS_LOGOUT_URL = 'https://fed.princeton.edu/cas/logout?service=%s'
# eligibility checking
if hasattr(settings, 'CAS_USERNAME'):
CAS_USERNAME = settings.CAS_USERNAME
CAS_PASSWORD = settings.CAS_PASSWORD
CAS_ELIGIBILITY_URL = settings.CAS_ELIGIBILITY_URL
CAS_ELIGIBILITY_REALM = settings.CAS_ELIGIBILITY_REALM
# display tweaks
LOGIN_MESSAGE = "Log in with my NetID"
def _get_service_url():
# FIXME current URL
from auth.views import after
from django.conf import settings
from django.core.urlresolvers import reverse
return settings.URL_HOST + reverse(after)
def get_auth_url(request):
return CAS_URL + 'login?service=' + urllib.quote(_get_service_url())
def get_user_category(user_id):
theurl = CAS_ELIGIBILITY_URL % user_id
auth_handler = urllib2.HTTPBasicAuthHandler()
auth_handler.add_password(realm=CAS_ELIGIBILITY_REALM, uri= theurl, user= CAS_USERNAME, passwd = CAS_PASSWORD)
opener = urllib2.build_opener(auth_handler)
urllib2.install_opener(opener)
result = urllib2.urlopen(CAS_ELIGIBILITY_URL % user_id).read().strip()
parsed_result = ElementTree.fromstring(result)
return parsed_result.text
def get_user_info(user_id):
url = 'http://dsml.princeton.edu/'
headers = {'SOAPAction': "#searchRequest", 'Content-Type': 'text/xml'}
request_body = """<?xml version='1.0' encoding='UTF-8'?>
<soap-env:Envelope
xmlns:xsd='http://www.w3.org/2001/XMLSchema'
xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
xmlns:soap-env='http://schemas.xmlsoap.org/soap/envelope/'>
<soap-env:Body>
<batchRequest xmlns='urn:oasis:names:tc:DSML:2:0:core'
requestID='searching'>
<searchRequest
dn='o=Princeton University, c=US'
scope='wholeSubtree'
derefAliases='neverDerefAliases'
sizeLimit='200'>
<filter>
<equalityMatch name='uid'>
<value>%s</value>
</equalityMatch>
</filter>
<attributes>
<attribute name="displayName"/>
<attribute name="pustatus"/>
</attributes>
</searchRequest>
</batchRequest>
</soap-env:Body>
</soap-env:Envelope>
""" % user_id
req = urllib2.Request(url, request_body, headers)
response = urllib2.urlopen(req).read()
# parse the result
from xml.dom.minidom import parseString
response_doc = parseString(response)
# get the value elements (a bit of a hack but no big deal)
values = response_doc.getElementsByTagName('value')
return {'name' : values[0].firstChild.wholeText, 'category' : values[1].firstChild.wholeText}
def get_user_info_after_auth(request):
ticket = request.GET.get('ticket', None)
# if no ticket, this is a logout
if not ticket:
return None
# fetch the information from the CAS server
val_url = CAS_URL + "validate" + \
'?service=' + urllib.quote(_get_service_url()) + \
'&ticket=' + urllib.quote(ticket)
r = urllib.urlopen(val_url).readlines() # returns 2 lines
# success
if len(r) == 2 and re.match("yes", r[0]) != None:
netid = r[1].strip()
category = get_user_category(netid)
info = {'name': netid, 'category': category}
return {'type': 'cas', 'user_id': netid, 'name': netid, 'info': info, 'token': None}
else:
return None
def do_logout(user):
"""
Perform logout of CAS by redirecting to the CAS logout URL
"""
return HttpResponseRedirect(CAS_LOGOUT_URL % _get_service_url())
def update_status(token, message):
"""
simple update
"""
pass
def send_message(user_id, name, user_info, subject, body):
"""
send email, for now just to Princeton
"""
# if the user_id contains an @ sign already
if "@" in user_id:
email = user_id
else:
email = "%s@%s" % (user_id, CAS_EMAIL_DOMAIN)
if user_info.has_key('name'):
name = user_info["name"]
else:
name = email
send_mail(subject, body, settings.SERVER_EMAIL, ["%s <%s>" % (name, email)], fail_silently=False)
def check_constraint(constraint, user_info):
if not user_info.has_key('category'):
return False
return constraint['year'] == user_info['category']
"""
Facebook Authentication
"""
import logging
from django.conf import settings
from django.core.mail import send_mail
APP_ID = settings.FACEBOOK_APP_ID
API_KEY = settings.FACEBOOK_API_KEY
API_SECRET = settings.FACEBOOK_API_SECRET
#from facebookclient import Facebook
import urllib, urllib2, cgi
# some parameters to indicate that status updating is possible
STATUS_UPDATES = True
STATUS_UPDATE_WORDING_TEMPLATE = "Send %s to your facebook status"
from auth import utils
def facebook_url(url, params):
if params:
return "https://graph.facebook.com%s?%s" % (url, urllib.urlencode(params))
else:
return "https://graph.facebook.com%s" % url
def facebook_get(url, params):
full_url = facebook_url(url,params)
return urllib2.urlopen(full_url).read()
def facebook_post(url, params):
full_url = facebook_url(url, None)
return urllib2.urlopen(full_url, urllib.urlencode(params)).read()
def get_auth_url(request, redirect_url):
request.session['fb_redirect_uri'] = redirect_url
return facebook_url('/oauth/authorize', {
'client_id': APP_ID,
'redirect_uri': redirect_url,
'scope': 'publish_stream,email'})
def get_user_info_after_auth(request):
args = facebook_get('/oauth/access_token', {
'client_id' : APP_ID,
'redirect_uri' : request.session['fb_redirect_uri'],
'client_secret' : API_SECRET,
'code' : request.GET['code']
})
access_token = cgi.parse_qs(args)['access_token'][0]
info = utils.from_json(facebook_get('/me', {'access_token':access_token}))
return {'type': 'facebook', 'user_id' : info['id'], 'name': info['name'], 'email': info['email'], 'info': info, 'token': {'access_token': access_token}}
def update_status(user_id, user_info, token, message):
"""
post a message to the auth system's update stream, e.g. twitter stream
"""
result = facebook_post('/me/feed', {
'access_token': token['access_token'],
'message': message
})
def send_message(user_id, user_name, user_info, subject, body):
if user_info.has_key('email'):
send_mail(subject, body, settings.SERVER_EMAIL, ["%s <%s>" % (user_name, user_info['email'])], fail_silently=False)
This diff is collapsed.
import re
import datetime
import facebook
from django.http import HttpResponse, HttpResponseRedirect
from django.core.exceptions import ImproperlyConfigured
from django.conf import settings
from datetime import datetime
try:
from threading import local
except ImportError:
from django.utils._threading_local import local
__all__ = ['Facebook', 'FacebookMiddleware', 'get_facebook_client', 'require_login', 'require_add']
_thread_locals = local()
class Facebook(facebook.Facebook):
def redirect(self, url):
"""
Helper for Django which redirects to another page. If inside a
canvas page, writes a <fb:redirect> instead to achieve the same effect.
"""
if self.in_canvas:
return HttpResponse('<fb:redirect url="%s" />' % (url, ))
elif re.search("^https?:\/\/([^\/]*\.)?facebook\.com(:\d+)?", url.lower()):
return HttpResponse('<script type="text/javascript">\ntop.location.href = "%s";\n</script>' % url)
else:
return HttpResponseRedirect(url)
def get_facebook_client():
"""
Get the current Facebook object for the calling thread.
"""
try:
return _thread_locals.facebook
except AttributeError:
raise ImproperlyConfigured('Make sure you have the Facebook middleware installed.')
def require_login(next=None, internal=None):
"""
Decorator for Django views that requires the user to be logged in.
The FacebookMiddleware must be installed.
Standard usage:
@require_login()
def some_view(request):
...
Redirecting after login:
To use the 'next' parameter to redirect to a specific page after login, a callable should
return a path relative to the Post-add URL. 'next' can also be an integer specifying how many
parts of request.path to strip to find the relative URL of the canvas page. If 'next' is None,
settings.callback_path and settings.app_name are checked to redirect to the same page after logging
in. (This is the default behavior.)
@require_login(next=some_callable)
def some_view(request):
...
"""
def decorator(view):
def newview(request, *args, **kwargs):
next = newview.next
internal = newview.internal
try:
fb = request.facebook
except:
raise ImproperlyConfigured('Make sure you have the Facebook middleware installed.')
if internal is None:
internal = request.facebook.internal
if callable(next):
next = next(request.path)
elif isinstance(next, int):
next = '/'.join(request.path.split('/')[next + 1:])
elif next is None and fb.callback_path and request.path.startswith(fb.callback_path):
next = request.path[len(fb.callback_path):]
elif not isinstance(next, str):
next = ''
if not fb.check_session(request):
#If user has never logged in before, the get_login_url will redirect to the TOS page
return fb.redirect(fb.get_login_url(next=next))
if internal and request.method == 'GET' and fb.app_name:
return fb.redirect('%s%s' % (fb.get_app_url(), next))
return view(request, *args, **kwargs)
newview.next = next
newview.internal = internal
return newview
return decorator
def require_add(next=None, internal=None, on_install=None):
"""
Decorator for Django views that requires application installation.
The FacebookMiddleware must be installed.
Standard usage:
@require_add()
def some_view(request):
...
Redirecting after installation:
To use the 'next' parameter to redirect to a specific page after login, a callable should
return a path relative to the Post-add URL. 'next' can also be an integer specifying how many
parts of request.path to strip to find the relative URL of the canvas page. If 'next' is None,
settings.callback_path and settings.app_name are checked to redirect to the same page after logging
in. (This is the default behavior.)
@require_add(next=some_callable)
def some_view(request):
...
Post-install processing:
Set the on_install parameter to a callable in order to handle special post-install processing.
The callable should take a request object as the parameter.
@require_add(on_install=some_callable)
def some_view(request):
...
"""
def decorator(view):
def newview(request, *args, **kwargs):
next = newview.next
internal = newview.internal
try:
fb = request.facebook
except:
raise ImproperlyConfigured('Make sure you have the Facebook middleware installed.')
if internal is None:
internal = request.facebook.internal
if callable(next):
next = next(request.path)
elif isinstance(next, int):
next = '/'.join(request.path.split('/')[next + 1:])
elif next is None and fb.callback_path and request.path.startswith(fb.callback_path):
next = request.path[len(fb.callback_path):]
else:
next = ''
if not fb.check_session(request):
if fb.added:
if request.method == 'GET' and fb.app_name:
return fb.redirect('%s%s' % (fb.get_app_url(), next))
return fb.redirect(fb.get_login_url(next=next))
else:
return fb.redirect(fb.get_add_url(next=next))
if not fb.added:
return fb.redirect(fb.get_add_url(next=next))
if 'installed' in request.GET and callable(on_install):
on_install(request)
if internal and request.method == 'GET' and fb.app_name:
return fb.redirect('%s%s' % (fb.get_app_url(), next))
return view(request, *args, **kwargs)
newview.next = next
newview.internal = internal
return newview
return decorator
# try to preserve the argspecs
try:
import decorator
except ImportError:
pass
else:
def updater(f):
def updated(*args, **kwargs):
original = f(*args, **kwargs)
def newdecorator(view):
return decorator.new_wrapper(original(view), view)
return decorator.new_wrapper(newdecorator, original)
return decorator.new_wrapper(updated, f)
require_login = updater(require_login)
require_add = updater(require_add)
class FacebookMiddleware(object):
"""
Middleware that attaches a Facebook object to every incoming request.
The Facebook object created can also be accessed from models for the
current thread by using get_facebook_client().
"""
def __init__(self, api_key=None, secret_key=None, app_name=None, callback_path=None, internal=None):
self.api_key = api_key or settings.FACEBOOK_API_KEY
self.secret_key = secret_key or settings.FACEBOOK_SECRET_KEY
self.app_name = app_name or getattr(settings, 'FACEBOOK_APP_NAME', None)
self.callback_path = callback_path or getattr(settings, 'FACEBOOK_CALLBACK_PATH', None)
self.internal = internal or getattr(settings, 'FACEBOOK_INTERNAL', True)
self.proxy = None
if getattr(settings, 'USE_HTTP_PROXY', False):
self.proxy = settings.HTTP_PROXY
def process_request(self, request):
_thread_locals.facebook = request.facebook = Facebook(self.api_key, self.secret_key, app_name=self.app_name, callback_path=self.callback_path, internal=self.internal, proxy=self.proxy)
if not self.internal:
if 'fb_sig_session_key' in request.GET and 'fb_sig_user' in request.GET:
request.facebook.session_key = request.session['facebook_session_key'] = request.GET['fb_sig_session_key']
request.facebook.uid = request.session['fb_sig_user'] = request.GET['fb_sig_user']
elif request.session.get('facebook_session_key', None) and request.session.get('facebook_user_id', None):
request.facebook.session_key = request.session['facebook_session_key']
request.facebook.uid = request.session['facebook_user_id']
def process_response(self, request, response):
if not self.internal and request.facebook.session_key and request.facebook.uid:
request.session['facebook_session_key'] = request.facebook.session_key
request.session['facebook_user_id'] = request.facebook.uid
if request.facebook.session_key_expires:
expiry = datetime.datetime.fromtimestamp(request.facebook.session_key_expires)
request.session.set_expiry(expiry)
try:
fb = request.facebook
except:
return response
if not fb.is_session_from_cookie:
# Make sure the browser accepts our session cookies inside an Iframe
response['P3P'] = 'CP="NOI DSP COR NID ADMa OPTa OUR NOR"'
fb_cookies = {
'expires': fb.session_key_expires,
'session_key': fb.session_key,
'user': fb.uid,
}
expire_time = None
if fb.session_key_expires:
expire_time = datetime.utcfromtimestamp(fb.session_key_expires)
for k in fb_cookies:
response.set_cookie(self.api_key + '_' + k, fb_cookies[k], expires=expire_time)
response.set_cookie(self.api_key , fb._hash_args(fb_cookies), expires=expire_time)
return response
def messages(request):
"""Returns messages similar to ``django.core.context_processors.auth``."""
if hasattr(request, 'facebook') and request.facebook.uid is not None:
from models import Message
messages = Message.objects.get_and_delete_all(uid=request.facebook.uid)
return {'messages': messages}
\ No newline at end of file
from django.db import models
# get_facebook_client lets us get the current Facebook object
# from outside of a view, which lets us have cleaner code
from facebook.djangofb import get_facebook_client
class UserManager(models.Manager):
"""Custom manager for a Facebook User."""
def get_current(self):
"""Gets a User object for the logged-in Facebook user."""
facebook = get_facebook_client()
user, created = self.get_or_create(id=int(facebook.uid))
if created:
# we could do some custom actions for new users here...
pass
return user
class User(models.Model):
"""A simple User model for Facebook users."""
# We use the user's UID as the primary key in our database.
id = models.IntegerField(primary_key=True)
# TODO: The data that you want to store for each user would go here.
# For this sample, we let users let people know their favorite progamming
# language, in the spirit of Extended Info.
language = models.CharField(maxlength=64, default='Python')
# Add the custom manager
objects = UserManager()
<fb:header>
{% comment %}
We can use {{ fbuser }} to get at the current user.
{{ fbuser.id }} will be the user's UID, and {{ fbuser.language }}
is his/her favorite language (Python :-).
{% endcomment %}
Welcome, <fb:name uid="{{ fbuser.id }}" firstnameonly="true" useyou="false" />!
</fb:header>
<div class="clearfix" style="float: left; border: 1px #d8dfea solid; padding: 10px 10px 10px 10px; margin-left: 30px; margin-bottom: 30px; width: 500px;">
Your favorite language is {{ fbuser.language|escape }}.
<br /><br />
<div class="grayheader clearfix">
<br /><br />
<form action="." method="POST">
<input type="text" name="language" value="{{ fbuser.language|escape }}" />
<input type="submit" value="Change" />
</form>
</div>
</div>
from django.conf.urls.defaults import *
urlpatterns = patterns('{{ project }}.{{ app }}.views',
(r'^$', 'canvas'),
# Define other pages you want to create here
)
from django.http import HttpResponse
from django.views.generic.simple import direct_to_template
#uncomment the following two lines and the one below
#if you dont want to use a decorator instead of the middleware
#from django.utils.decorators import decorator_from_middleware
#from facebook.djangofb import FacebookMiddleware
# Import the Django helpers
import facebook.djangofb as facebook
# The User model defined in models.py
from models import User
# We'll require login for our canvas page. This
# isn't necessarily a good idea, as we might want
# to let users see the page without granting our app
# access to their info. See the wiki for details on how
# to do this.
#@decorator_from_middleware(FacebookMiddleware)
@facebook.require_login()
def canvas(request):
# Get the User object for the currently logged in user
user = User.objects.get_current()
# Check if we were POSTed the user's new language of choice
if 'language' in request.POST:
user.language = request.POST['language'][:64]
user.save()
# User is guaranteed to be logged in, so pass canvas.fbml
# an extra 'fbuser' parameter that is the User object for
# the currently logged in user.
return direct_to_template(request, 'canvas.fbml', extra_context={'fbuser': user})
@facebook.require_login()
def ajax(request):
return HttpResponse('hello world')
from django.db import models
from django.utils.html import escape
from django.utils.safestring import mark_safe
FB_MESSAGE_STATUS = (
(0, 'Explanation'),
(1, 'Error'),
(2, 'Success'),
)
class MessageManager(models.Manager):
def get_and_delete_all(self, uid):
messages = []
for m in self.filter(uid=uid):
messages.append(m)
m.delete()
return messages
class Message(models.Model):
"""Represents a message for a Facebook user."""
uid = models.CharField(max_length=25)
status = models.IntegerField(choices=FB_MESSAGE_STATUS)
message = models.CharField(max_length=300)
objects = MessageManager()
def __unicode__(self):
return self.message
def _fb_tag(self):
return self.get_status_display().lower()
def as_fbml(self):
return mark_safe(u'<fb:%s message="%s" />' % (
self._fb_tag(),
escape(self.message),
))
#
# webappfb - Facebook tools for Google's AppEngine "webapp" Framework
#
# Copyright (c) 2009, Max Battcher
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# * Neither the name of the author nor the names of its contributors may
# be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS``AS IS'' AND ANY
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from google.appengine.api import memcache
from google.appengine.ext.webapp import RequestHandler
from facebook import Facebook
import yaml
"""
Facebook tools for Google AppEngine's object-oriented "webapp" framework.
"""
# This global configuration dictionary is for configuration variables
# for Facebook requests such as the application's API key and secret
# key. Defaults to loading a 'facebook.yaml' YAML file. This should be
# useful and familiar for most AppEngine development.
FACEBOOK_CONFIG = yaml.load(file('facebook.yaml', 'r'))
class FacebookRequestHandler(RequestHandler):
"""
Base class for request handlers for Facebook apps, providing useful
Facebook-related tools: a local
"""
def _fbconfig_value(self, name, default=None):
"""
Checks the global config dictionary and then for a class/instance
variable, using a provided default if no value is found.
"""
if name in FACEBOOK_CONFIG:
default = FACEBOOK_CONFIG[name]
return getattr(self, name, default)
def initialize(self, request, response):
"""
Initialize's this request's Facebook client.
"""
super(FacebookRequestHandler, self).initialize(request, response)
app_name = self._fbconfig_value('app_name', '')
api_key = self._fbconfig_value('api_key', None)
secret_key = self._fbconfig_value('secret_key', None)
self.facebook = Facebook(api_key, secret_key,
app_name=app_name)
require_app = self._fbconfig_value('require_app', False)
require_login = self._fbconfig_value('require_login', False)
need_session = self._fbconfig_value('need_session', False)
check_session = self._fbconfig_value('check_session', True)
self._messages = None
self.redirecting = False
if require_app or require_login:
if not self.facebook.check_session(request):
self.redirect(self.facebook.get_login_url(next=request.path))
self.redirecting = True
return
elif check_session:
self.facebook.check_session(request) # ignore response
# NOTE: require_app is deprecated according to modern Facebook login
# policies. Included for completeness, but unnecessary.
if require_app and not self.facebook.added:
self.redirect(self.facebook.get_add_url(next=request.path))
self.redirecting = True
return
if not (require_app or require_login) and need_session:
self.facebook.auth.getSession()
def redirect(self, url, **kwargs):
"""
For Facebook canvas pages we should use <fb:redirect /> instead of
a normal redirect.
"""
if self.facebook.in_canvas:
self.response.clear()
self.response.out.write('<fb:redirect url="%s" />' % (url, ))
else:
super(FacebookRequestHandler, self).redirect(url, **kwargs)
def add_user_message(self, kind, msg, detail='', time=15 * 60):
"""
Add a message to the current user to memcache.
"""
if self.facebook.uid:
key = 'messages:%s' % self.facebook.uid
self._messages = memcache.get(key)
message = {
'kind': kind,
'message': msg,
'detail': detail,
}
if self._messages is not None:
self._messages.append(message)
else:
self._messages = [message]
memcache.set(key, self._messages, time=time)
def get_and_delete_user_messages(self):
"""
Get all of the messages for the current user; removing them.
"""
if self.facebook.uid:
key = 'messages:%s' % self.facebook.uid
if not hasattr(self, '_messages') or self._messages is None:
self._messages = memcache.get(key)
memcache.delete(key)
return self._messages
return None
class FacebookCanvasHandler(FacebookRequestHandler):
"""
Request handler for Facebook canvas (FBML application) requests.
"""
def canvas(self, *args, **kwargs):
"""
This will be your handler to deal with Canvas requests.
"""
raise NotImplementedError()
def get(self, *args):
"""
All valid canvas views are POSTS.
"""
# TODO: Attempt to auto-redirect to Facebook canvas?
self.error(404)
def post(self, *args, **kwargs):
"""
Check a couple of simple safety checks and then call the canvas
handler.
"""
if self.redirecting: return
if not self.facebook.in_canvas:
self.error(404)
return
self.canvas(*args, **kwargs)
# vim: ai et ts=4 sts=4 sw=4
"""This is some simple helper code to bridge the Pylons / PyFacebook gap.
There's some generic WSGI middleware, some Paste stuff, and some Pylons
stuff. Once you put FacebookWSGIMiddleware into your middleware stack,
you'll have access to ``environ["pyfacebook.facebook"]``, which is a
``facebook.Facebook`` object. If you're using Paste (which includes
Pylons users), you can also access this directly using the facebook
global in this module.
"""
# Be careful what you import. Don't expect everyone to have Pylons,
# Paste, etc. installed. Degrade gracefully.
from facebook import Facebook
__docformat__ = "restructuredtext"
# Setup Paste, if available. This needs to stay in the same module as
# FacebookWSGIMiddleware below.
try:
from paste.registry import StackedObjectProxy
from webob.exc import _HTTPMove
from paste.util.quoting import strip_html, html_quote, no_quote
except ImportError:
pass
else:
facebook = StackedObjectProxy(name="PyFacebook Facebook Connection")
class CanvasRedirect(_HTTPMove):
"""This is for canvas redirects."""
title = "See Other"
code = 200
template = '<fb:redirect url="%(location)s" />'
def html(self, environ):
""" text/html representation of the exception """
body = self.make_body(environ, self.template, html_quote, no_quote)
return body
class FacebookWSGIMiddleware(object):
"""This is WSGI middleware for Facebook."""
def __init__(self, app, config, facebook_class=Facebook):
"""Initialize the Facebook middleware.
``app``
This is the WSGI application being wrapped.
``config``
This is a dict containing the keys "pyfacebook.apikey" and
"pyfacebook.secret".
``facebook_class``
If you want to subclass the Facebook class, you can pass in
your replacement here. Pylons users will want to use
PylonsFacebook.
"""
self.app = app
self.config = config
self.facebook_class = facebook_class
def __call__(self, environ, start_response):
config = self.config
real_facebook = self.facebook_class(config["pyfacebook.apikey"],
config["pyfacebook.secret"])
registry = environ.get('paste.registry')
if registry:
registry.register(facebook, real_facebook)
environ['pyfacebook.facebook'] = real_facebook
return self.app(environ, start_response)
# The remainder is Pylons specific.
try:
import pylons
from pylons.controllers.util import redirect_to as pylons_redirect_to
from routes import url_for
except ImportError:
pass
else:
class PylonsFacebook(Facebook):
"""Subclass Facebook to add Pylons goodies."""
def check_session(self, request=None):
"""The request parameter is now optional."""
if request is None:
request = pylons.request
return Facebook.check_session(self, request)
# The Django request object is similar enough to the Paste
# request object that check_session and validate_signature
# should *just work*.
def redirect_to(self, url):
"""Wrap Pylons' redirect_to function so that it works in_canvas.
By the way, this won't work until after you call
check_session().
"""
if self.in_canvas:
raise CanvasRedirect(url)
pylons_redirect_to(url)
def apps_url_for(self, *args, **kargs):
"""Like url_for, but starts with "http://apps.facebook.com"."""
return "http://apps.facebook.com" + url_for(*args, **kargs)
def create_pylons_facebook_middleware(app, config):
"""This is a simple wrapper for FacebookWSGIMiddleware.
It passes the correct facebook_class.
"""
return FacebookWSGIMiddleware(app, config,
facebook_class=PylonsFacebook)
"""
Google Authentication
"""
from django.http import *
from django.core.mail import send_mail
from django.conf import settings
import sys, os, cgi, urllib, urllib2, re
from xml.etree import ElementTree
from openid import view_helpers
# some parameters to indicate that status updating is not possible
STATUS_UPDATES = False
# display tweaks
LOGIN_MESSAGE = "Log in with my Google Account"
OPENID_ENDPOINT = 'https://www.google.com/accounts/o8/id'
# FIXME!
# TRUST_ROOT = 'http://localhost:8000'
# RETURN_TO = 'http://localhost:8000/auth/after'
def get_auth_url(request, redirect_url):
# FIXME?? TRUST_ROOT should be diff than return_url?
request.session['google_redirect_url'] = redirect_url
url = view_helpers.start_openid(request.session, OPENID_ENDPOINT, redirect_url, redirect_url)
return url
def get_user_info_after_auth(request):
data = view_helpers.finish_openid(request.session, request.GET, request.session['google_redirect_url'])
return {'type' : 'google', 'user_id': data['ax']['email'][0], 'name': "%s %s" % (data['ax']['firstname'][0], data['ax']['lastname'][0]), 'info': {}, 'token':{}}
def do_logout(user):
"""
logout of Google
"""
return None
def update_status(token, message):
"""
simple update
"""
pass
def send_message(user_id, name, user_info, subject, body):
"""
send email to google users. user_id is the email for google.
"""
send_mail(subject, body, settings.SERVER_EMAIL, ["%s <%s>" % (name, user_id)], fail_silently=False)
def check_constraint(constraint, user_info):
"""
for eligibility
"""
pass
"""
Windows Live Authentication using oAuth WRAP,
so much like Facebook
# NOT WORKING YET because Windows Live documentation and status is unclear. Is it in beta? I think it is.
"""
import logging
from django.conf import settings
APP_ID = settings.LIVE_APP_ID
APP_SECRET = settings.LIVE_APP_SECRET
import urllib, urllib2, cgi
# some parameters to indicate that status updating is possible
STATUS_UPDATES = False
# STATUS_UPDATE_WORDING_TEMPLATE = "Send %s to your facebook status"
from auth import utils
def live_url(url, params):
if params:
return "https://graph.facebook.com%s?%s" % (url, urllib.urlencode(params))
else:
return "https://graph.facebook.com%s" % url
def live_get(url, params):
full_url = live_url(url,params)
return urllib2.urlopen(full_url).read()
def live_post(url, params):
full_url = live_url(url, None)
return urllib2.urlopen(full_url, urllib.urlencode(params)).read()
def get_auth_url(request, redirect_url):
request.session['live_redirect_uri'] = redirect_url
return live_url('/oauth/authorize', {
'client_id': APP_ID,
'redirect_uri': redirect_url,
'scope': 'publish_stream'})
def get_user_info_after_auth(request):
args = facebook_get('/oauth/access_token', {
'client_id' : APP_ID,
'redirect_uri' : request.session['fb_redirect_uri'],
'client_secret' : API_SECRET,
'code' : request.GET['code']
})
access_token = cgi.parse_qs(args)['access_token'][0]
info = utils.from_json(facebook_get('/me', {'access_token':access_token}))
return {'type': 'facebook', 'user_id' : info['id'], 'name': info['name'], 'info': info, 'token': {'access_token': access_token}}
def update_status(user_id, user_info, token, message):
"""
post a message to the auth system's update stream, e.g. twitter stream
"""
result = facebook_post('/me/feed', {
'access_token': token['access_token'],
'message': message
})
def send_message(user_id, user_name, user_info, subject, body):
pass
Python Oauth client for Twitter
---------
I built this so that i didn't have to keep looking for an oauth client for twitter to use in python.
It is based off of the PHP work from abrah.am (http://github.com/poseurtech/twitteroauth/tree/master).
It was very helpful.
I am using the OAuth lib that is from google gdata. I figure it is a working client and is in production use - so it should be solid. You can find it at:
http://gdata-python-client.googlecode.com/svn/trunk/src/gdata/oauth
With a bit of modification this client should work with other publishers.
btw, i am a python n00b. so feel free to help out.
Thanks,
harper - harper@nata2.org (email and xmpp)
-----------
Links:
Google Code Project: http://code.google.com/p/twitteroauth-python/
Issue Tracker: http://code.google.com/p/twitteroauth-python/issues/list
Wiki: http://wiki.github.com/harperreed/twitteroauth-python
-----------
The example client is included in the client.py. It is:
if __name__ == '__main__':
consumer_key = ''
consumer_secret = ''
while not consumer_key:
consumer_key = raw_input('Please enter consumer key: ')
while not consumer_secret:
consumer_secret = raw_input('Please enter consumer secret: ')
auth_client = TwitterOAuthClient(consumer_key,consumer_secret)
tok = auth_client.get_request_token()
token = tok['oauth_token']
token_secret = tok['oauth_token_secret']
url = auth_client.get_authorize_url(token)
webbrowser.open(url)
print "Visit this URL to authorize your app: " + url
response_token = raw_input('What is the oauth_token from twitter: ')
response_client = TwitterOAuthClient(consumer_key, consumer_secret,token, token_secret)
tok = response_client.get_access_token()
print "Making signed request"
#verify user access
content = response_client.oauth_request('https://twitter.com/account/verify_credentials.json', method='POST')
#make an update
#content = response_client.oauth_request('https://twitter.com/statuses/update.xml', {'status':'Updated from a python oauth client. awesome.'}, method='POST')
print content
print 'Done.'
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment