Skip to content

Commit

Permalink
Merge pull request #53 from akshar-raaj/add_more_providers
Browse files Browse the repository at this point in the history
Add more providers
  • Loading branch information
shabda committed Sep 25, 2013
2 parents 59279dc + 6682962 commit b0b1acb
Show file tree
Hide file tree
Showing 9 changed files with 213 additions and 4 deletions.
15 changes: 13 additions & 2 deletions README.rst
Expand Up @@ -25,6 +25,8 @@ In particular it allows logging in via
#. Facebook
#. Yahoo(Essentially openid)
#. OpenId
#. Github
#. Foursquare

Libs you need to install
See requirements.txt
Expand All @@ -38,6 +40,8 @@ The API Keys are available from
* https://developer.yahoo.com/dashboard/createKey.html
* https://www.google.com/accounts/ManageDomains
* http://twitter.com/oauth_clients
* https://github.com/settings/applications/new
* https://developer.foursquare.com/overview/auth.html

How it works.
--------------
Expand All @@ -51,6 +55,9 @@ How it works.
used for authentication. (It is an autorisation framework, not an authentication one),
In practice it works pretty well. Once you have an access_token, and a name, essentially
authenticated.
* **Github**:We use Github Oauth for authentication. As like Twitter, it works
pretty well.
* **Foursquare**:We use Oauth2.0 for authenticating via foursquare.

References
----------
Expand All @@ -60,11 +67,13 @@ References
#. http://code.google.com/apis/accounts/docs/OpenID.html
#. http://apiwiki.twitter.com/OAuth-FAQ
#. http://developers.facebook.com/connect.php
#. http://develop.github.com/p/oauth.html
#. https://developer.foursquare.com/overview/auth.html

Limitations
------------

As with all APIs, we are limited by the amout of data which the API provider
As with all APIs, we are limited by the amount of data which the API provider
provides us. For example, both Yahoo and Google provide extremely limited data
about the autheticated subscriber. Twitter and Facebook provide a lot of details,
but not the email. Different Openid providers are free to provide [different
Expand Down Expand Up @@ -95,11 +104,13 @@ Urls
* /twitter_login/ AND /twitter_login/done/
* /facebook_login/done/ We dont have a start url here, as the starting tokens are
set in a popup.
* /github_login/ AND /github_login/done/
* /foursquare_login/ AND /foursquare_login/done/

Implementation
---------------

#. Install required libraries.
#. Get tokens and populate in localsettings.py
#. Set the token callback urls correctly at Twitter and Facebook.
#. Set the token callback urls correctly at Twitter, Facebook, Github and Foursquare.
#. Set the authentication_backends to the providers you are using.
9 changes: 9 additions & 0 deletions example_project/localsettings.example.py
Expand Up @@ -32,6 +32,13 @@
LINKEDIN_CONSUMER_KEY = ''
LINKEDIN_CONSUMER_SECRET = ''

GITHUB_CLIENT_ID = ''
GITHUB_CLIENT_SECRET = ''

FOURSQUARE_CONSUMER_KEY = ''
FOURSQUARE_CONSUMER_SECRET = ''
FOURSQUARE_REGISTERED_REDIRECT_URI = ''

## if any of this information is desired for your app
FACEBOOK_EXTENDED_PERMISSIONS = (
#'publish_stream',
Expand Down Expand Up @@ -92,4 +99,6 @@
'socialauth.auth_backends.TwitterBackend',
'socialauth.auth_backends.FacebookBackend',
'socialauth.auth_backends.LinkedInBackend',
'socialauth.auth_backends.GithubBackend',
'socialauth.auth_backends.FoursquareBackend',
)
4 changes: 3 additions & 1 deletion socialauth/admin.py
@@ -1,5 +1,5 @@
from socialauth.models import AuthMeta, OpenidProfile, TwitterUserProfile, \
FacebookUserProfile, LinkedInUserProfile
FacebookUserProfile, LinkedInUserProfile, GithubUserProfile, FoursquareUserProfile

from django.contrib import admin

Expand All @@ -8,3 +8,5 @@
admin.site.register(TwitterUserProfile)
admin.site.register(FacebookUserProfile)
admin.site.register(LinkedInUserProfile)
admin.site.register(GithubUserProfile)
admin.site.register(FoursquareUserProfile)
47 changes: 46 additions & 1 deletion socialauth/auth_backends.py
Expand Up @@ -7,10 +7,11 @@
import urllib
from socialauth.lib import oauthtwitter2 as oauthtwitter
from socialauth.models import OpenidProfile as UserAssociation, \
TwitterUserProfile, FacebookUserProfile, LinkedInUserProfile, AuthMeta
TwitterUserProfile, FacebookUserProfile, LinkedInUserProfile, AuthMeta, GithubUserProfile, FoursquareUserProfile
from socialauth.lib.linkedin import *

import random
from cgi import parse_qs

TWITTER_CONSUMER_KEY = getattr(settings, 'TWITTER_CONSUMER_KEY', '')
TWITTER_CONSUMER_SECRET = getattr(settings, 'TWITTER_CONSUMER_SECRET', '')
Expand Down Expand Up @@ -325,3 +326,47 @@ def get_user(self, user_id):
return User.objects.get(pk=user_id)
except:
return None

class GithubBackend:
def authenticate(self, github_access_token, user=None):
response_qs = parse_qs(github_access_token)
github_access_token = response_qs['access_token'][0]
try:
github_user = GithubUserProfile.objects.get(access_token=github_access_token)
return github_user.user
except GithubUserProfile.DoesNotExist:
github_user_count = GithubUserProfile.objects.all().count()
username = "GithubUser:" + str(github_user_count+1)
user = User(username=username)
user.save()
github_user = GithubUserProfile(user=user, access_token=github_access_token)
github_user.save()
AuthMeta(user=user, provider='Github').save()
return github_user.user

def get_user(self, user_id):
try:
return User.objects.get(pk=user_id)
except:
return None

class FoursquareBackend:
def authenticate(self, foursquare_access_token):
try:
foursquare_profile = FoursquareUserProfile.objects.get(access_token=foursquare_access_token)
return foursquare_profile.user
except FoursquareUserProfile.DoesNotExist:
foursquare_user_count = FoursquareUserProfile.objects.all().count()
username = "FoursquareUser:" + str(foursquare_user_count+1)
user = User(username=username)
user.save()
foursquare_user = FoursquareUserProfile(user=user, access_token=foursquare_access_token)
foursquare_user.save()
AuthMeta(user=user, provider='Foursquare').save()
return foursquare_user.user

def get_user(self, user_id):
try:
return User.objects.get(pk=user_id)
except:
return None
42 changes: 42 additions & 0 deletions socialauth/lib/foursquare.py
@@ -0,0 +1,42 @@
from oauth import oauth
from django.conf import settings
import httplib

FOURSQUARE_AUTHENTICATION_URL = 'https://foursquare.com/oauth2/authenticate'
FOURSQUARE_ACCESS_TOKEN_URL = 'https://foursquare.com/oauth2/access_token'
FOURSQUARE_CONSUMER_KEY = getattr(settings, 'FOURSQUARE_CONSUMER_KEY')
FOURSQUARE_CONSUMER_SECRET = getattr(settings, 'FOURSQUARE_CONSUMER_SECRET')
REGISTERED_REDIRECT_URI = getattr(settings, 'FOURSQUARE_REGISTERED_REDIRECT_URI')

def get_http_connection():
return httplib.HTTPSConnection('foursquare.com')

def get_response_body(oauth_request):
http_conn = get_http_connection()
http_conn.request('GET', oauth_request.to_url())
response = http_conn.getresponse().read()
return response


class FourSquareClient(object):
def __init__(self):
self.consumer = oauth.OAuthConsumer(FOURSQUARE_CONSUMER_KEY, FOURSQUARE_CONSUMER_SECRET)

def get_authentication_url(self):
parameters = {}
parameters['client_id'] = FOURSQUARE_CONSUMER_KEY
parameters['response_type'] = 'code'
parameters['redirect_uri'] = REGISTERED_REDIRECT_URI
oauth_request = oauth.OAuthRequest.from_consumer_and_token(self.consumer, http_url=FOURSQUARE_AUTHENTICATION_URL, parameters=parameters)
return oauth_request.to_url()

def get_access_token(self, foursquare_code):
parameters = {}
parameters['client_id'] = FOURSQUARE_CONSUMER_KEY
parameters['client_secret'] = FOURSQUARE_CONSUMER_SECRET
parameters['grant_type'] = 'authorization_code'
parameters['redirect_uri'] = REGISTERED_REDIRECT_URI
parameters['code'] = foursquare_code
oauth_request = oauth.OAuthRequest.from_consumer_and_token(self.consumer, http_url=FOURSQUARE_ACCESS_TOKEN_URL, parameters=parameters)
access_token_response = get_response_body(oauth_request)
return access_token_response
31 changes: 31 additions & 0 deletions socialauth/lib/github.py
@@ -0,0 +1,31 @@
from django.conf import settings
from oauth.oauth import OAuthConsumer, OAuthRequest
import httplib

GITHUB_CLIENT_ID = getattr(settings, 'GITHUB_CLIENT_ID')
GITHUB_CLIENT_SECRET = getattr(settings, 'GITHUB_CLIENT_SECRET')
GITHUB_AUTHORIZE_URL = 'https://github.com/login/oauth/authorize'
GITHUB_ACCESS_TOKEN_URL = 'https://github.com/login/oauth/access_token'

def get_response_from_url(to_url):
conn = httplib.HTTPSConnection('github.com')
conn.request('GET', to_url)
return conn.getresponse().read()

class GithubClient(object):
def __init__(self):
self.consumer = OAuthConsumer(GITHUB_CLIENT_ID, GITHUB_CLIENT_SECRET)

def get_authorize_url(self):
parameters = {'client_id':GITHUB_CLIENT_ID}
oauth_request = OAuthRequest.from_consumer_and_token(self.consumer, http_url=GITHUB_AUTHORIZE_URL, parameters=parameters)
return oauth_request.to_url()

def get_access_token(self, code):
parameters = {}
parameters['client_id'] = GITHUB_CLIENT_ID
parameters['client_secret'] = GITHUB_CLIENT_SECRET
parameters['code'] = code
oauth_request = OAuthRequest.from_consumer_and_token(self.consumer, http_url=GITHUB_ACCESS_TOKEN_URL, parameters=parameters)
access_token = get_response_from_url(oauth_request.to_url())
return access_token
14 changes: 14 additions & 0 deletions socialauth/models.py
Expand Up @@ -91,3 +91,17 @@ class FacebookUserProfile(models.Model):

def __unicode__(self):
return "%s's profile" % self.user

class GithubUserProfile(models.Model):
user = models.ForeignKey(User)
access_token = models.CharField(max_length=100, blank=True, null=True, editable=False)

def __unicode__(self):
return "%s's profile" % self.user

class FoursquareUserProfile(models.Model):
user = models.ForeignKey(User)
access_token = models.CharField(max_length=255, blank=True, null=True, editable=False)

def __unicode__(self):
return "%s's profile" % self.user
4 changes: 4 additions & 0 deletions socialauth/urls.py
Expand Up @@ -21,6 +21,10 @@
url(r'^openid/complete/$', complete, name='socialauth_openid_complete'),
url(r'^openid/signout/$', signout, name='openid_signout'),
url(r'^openid/done/$', 'openid_done', name='openid_openid_done'),
url(r'^github_login/$', 'github_login', name='github_login'),
url(r'github_login/done/$', 'github_login_done', name='github_login_done'),
url(r'^foursquare_login/$', 'foursquare_login', name='foursquare_login'),
url(r'^foursquare_login/done/$', 'foursquare_login_done', name='foursquare_login_done'),
)

#Other views.
Expand Down
51 changes: 51 additions & 0 deletions socialauth/views.py
Expand Up @@ -18,6 +18,8 @@
from socialauth.lib import oauthtwitter2 as oauthtwitter

from socialauth.lib.linkedin import *
from socialauth.lib.github import GithubClient
from socialauth.lib import foursquare

LINKEDIN_CONSUMER_KEY = getattr(settings, 'LINKEDIN_CONSUMER_KEY', '')
LINKEDIN_CONSUMER_SECRET = getattr(settings, 'LINKEDIN_CONSUMER_SECRET', '')
Expand All @@ -34,6 +36,7 @@
FACEBOOK_SECRET_KEY = getattr(settings, 'FACEBOOK_SECRET_KEY', '')



def del_dict_key(src_dict, key):
if key in src_dict:
del src_dict[key]
Expand Down Expand Up @@ -308,3 +311,51 @@ def social_logout(request):
response.delete_cookie("fbs_" + FACEBOOK_APP_ID)

return response

def github_login(request):
github_client = GithubClient()
authorize_url = github_client.get_authorize_url()
return HttpResponseRedirect(authorize_url)

def github_login_done(request):
try:
code = request.GET['code']
except:
"""Either github did not respond properly
or someone is playing with this url"""
return HttpResponseRedirect(LOGIN_URL)
github_client = GithubClient()
access_token = github_client.get_access_token(code)
try:
user = authenticate(github_access_token=access_token)
except:
user = None
if user:
login(request, user)
return HttpResponseRedirect(LOGIN_REDIRECT_URL)
return HttpResponseRedirect(LOGIN_URL)

def foursquare_login(request):
foursquare_client = foursquare.FourSquareClient()
return HttpResponseRedirect(foursquare_client.get_authentication_url())

def foursquare_login_done(request):
try:
code = request.GET.get('code')
except:
"""Some error ocurred.
Rediect to login page"""
return HttpResponseRedirect(LOGIN_URL)
request.session['foursquare_code'] = code
foursquare_client = foursquare.FourSquareClient()
access_token_response = foursquare_client.get_access_token(request.session['foursquare_code'])
import json
access_token = json.loads(access_token_response)['access_token']
try:
user = authenticate(foursquare_access_token=access_token)
except:
user=None
if user:
login(request, user)
return HttpResponseRedirect(LOGIN_REDIRECT_URL)
return HttpResponseRedirect(LOGIN_URL)

0 comments on commit b0b1acb

Please sign in to comment.