From: revolunet Date: Fri, 19 Aug 2011 13:46:31 +0000 (+0200) Subject: add github OAuth backend fix #122 X-Git-Url: https://git.parisson.com/?a=commitdiff_plain;h=72c1b0debef3ad5c2dc0e9df7b623586d70c41c3;p=django-social-auth.git add github OAuth backend fix #122 --- diff --git a/README.rst b/README.rst index e93016a..8159877 100644 --- a/README.rst +++ b/README.rst @@ -41,6 +41,7 @@ credentials, some features are: * `Orkut OAuth`_ * `Linkedin OAuth`_ * `Foursquare OAuth2`_ + * `GitHub OAuth`_ - Basic user data population and signaling, to allows custom fields values from providers response @@ -112,6 +113,7 @@ Configuration 'social_auth.backends.contrib.LiveJournalBackend', 'social_auth.backends.contrib.orkut.OrkutBackend', 'social_auth.backends.contrib.orkut.FoursquareBackend', + 'social_auth.backends.contrib.github.GithubBackend', 'social_auth.backends.OpenIDBackend', 'django.contrib.auth.backends.ModelBackend', ) @@ -150,6 +152,8 @@ Configuration GOOGLE_OAUTH2_CLIENT_SECRET = '' FOURSQUARE_CONSUMER_KEY = '' FOURSQUARE_CONSUMER_SECRET = '' + GITHUB_APP_ID = '' + GITHUB_API_SECRET = '' - Setup login URLs:: diff --git a/example/local_settings.py.template b/example/local_settings.py.template index 46ac466..8b52a3b 100644 --- a/example/local_settings.py.template +++ b/example/local_settings.py.template @@ -15,3 +15,5 @@ SOCIAL_AUTH_COMPLETE_URL_NAME = 'socialauth_complete' LOGIN_ERROR_URL = '/login/error/' #SOCIAL_AUTH_USER_MODEL = 'app.CustomUser' SOCIAL_AUTH_ERROR_KEY = 'socialauth_error' +GITHUB_APP_ID = '' +GITHUB_API_SECRET = '' \ No newline at end of file diff --git a/social_auth/backends/contrib/github.py b/social_auth/backends/contrib/github.py new file mode 100644 index 0000000..d53801e --- /dev/null +++ b/social_auth/backends/contrib/github.py @@ -0,0 +1,104 @@ +""" +GitHub OAuth support. + +This contribution adds support for GitHub OAuth service. The settings +GITHUB_APP_ID and GITHUB_API_SECRET must be defined with the values +given by Facebook application registration process. + +Extended permissions are supported by defining GITHUB_EXTENDED_PERMISSIONS +setting, it must be a list of values to request. + +By default account id and token expiration time are stored in extra_data +field, check OAuthBackend class for details on how to extend it. +""" +import cgi +import urllib + +from django.conf import settings +from django.utils import simplejson +from django.contrib.auth import authenticate + +from social_auth.backends import BaseOAuth, OAuthBackend, USERNAME + +# Facebook configuration +GITHUB_SERVER = 'github.com' +GITHUB_AUTHORIZATION_URL = 'https://%s/login/oauth/authorize' % GITHUB_SERVER +GITHUB_ACCESS_TOKEN_URL = 'https://%s/login/oauth/access_token' % GITHUB_SERVER +GITHUB_API_URL = 'https://api.%s' % GITHUB_SERVER +EXPIRES_NAME = getattr(settings, 'SOCIAL_AUTH_EXPIRATION', 'expires') + +class GithubBackend(OAuthBackend): + """Github OAuth authentication backend""" + name = 'github' + # Default extra data to store + EXTRA_DATA = [('id', 'id'), ('expires', EXPIRES_NAME)] + + def get_user_details(self, response): + """Return user details from Github account""" + return { + 'username':response.get('login'), + 'email':response.get('email'), + 'firstname':response.get('name') + } + +class GithubAuth(BaseOAuth): + """Github OAuth mechanism""" + AUTH_BACKEND = GithubBackend + + def auth_url(self): + """Returns redirect url""" + args = {'client_id': settings.GITHUB_APP_ID, + 'redirect_uri': self.redirect_uri} + if hasattr(settings, 'GITHUB_EXTENDED_PERMISSIONS'): + args['scope'] = ','.join(settings.GITHUB_EXTENDED_PERMISSIONS) + return GITHUB_AUTHORIZATION_URL + '?' + urllib.urlencode(args) + + def auth_complete(self, *args, **kwargs): + """Returns user, might be logged in""" + if 'code' in self.data: + + url = GITHUB_ACCESS_TOKEN_URL + '?' + \ + urllib.urlencode({'client_id': settings.GITHUB_APP_ID, + 'redirect_uri': self.redirect_uri, + 'client_secret': settings.GITHUB_API_SECRET, + 'code': self.data['code']}) + response = cgi.parse_qs(urllib.urlopen(url).read()) + if response.get('error'): + error = self.data.get('error') or 'unknown error' + raise ValueError('Authentication error: %s' % error) + access_token = response['access_token'][0] + data = self.user_data(access_token) + if data is not None: + if 'error' in data: + error = self.data.get('error') or 'unknown error' + raise ValueError('Authentication error: %s' % error) + data['access_token'] = access_token + kwargs.update({'response': data, GithubBackend.name: True}) + return authenticate(*args, **kwargs) + else: + error = self.data.get('error') or 'unknown error' + raise ValueError('Authentication error: %s' % error) + + def user_data(self, access_token): + """Loads user data from service""" + params = {'access_token': access_token,} + url = '%s/user' % GITHUB_API_URL + '?' + urllib.urlencode(params) + try: + data = simplejson.load(urllib.urlopen(url)) + return data + except ValueError: + return None + + + @classmethod + def enabled(cls): + """Return backend enabled status by checking basic settings""" + return all(hasattr(settings, name) for name in + ('GITHUB_APP_ID', + 'GITHUB_API_SECRET')) + + +# Backend definition +BACKENDS = { + 'github': GithubAuth, +}