'social_auth.backends.google.GoogleOAuthBackend',
'social_auth.backends.google.GoogleBackend',
'social_auth.backends.yahoo.YahooBackend',
+ 'social_auth.backends.linkedin.LinkedinBackend',
'social_auth.backends.OpenIDBackend',
'social_auth.backends.contrib.livejournal.LiveJournalBackend',
'django.contrib.auth.backends.ModelBackend',
--- /dev/null
+"""
+Linkedin OAuth support
+
+No extra configurations are needed to make this work.
+"""
+import urlparse
+import xml
+from xml.etree import ElementTree
+
+from social_auth.backends import ConsumerBasedOAuth, OAuthBackend, USERNAME
+
+
+LINKEDIN_SERVER = 'linkedin.com'
+LINKEDIN_REQUEST_TOKEN_URL = 'https://api.%s/uas/oauth/requestToken' % LINKEDIN_SERVER
+LINKEDIN_ACCESS_TOKEN_URL = 'https://api.%s/uas/oauth/accessToken' % LINKEDIN_SERVER
+LINKEDIN_AUTHORIZATION_URL = 'https://www.%s/uas/oauth/authenticate' % LINKEDIN_SERVER
+LINKEDIN_CHECK_AUTH = 'https://api.%s/v1/people/~' % LINKEDIN_SERVER
+
+
+class LinkedinBackend(OAuthBackend):
+ """Linkedin OAuth authentication backend"""
+ name = 'linkedin'
+
+ def get_user_details(self, response):
+ """Return user details from Linkedin account"""
+ return {
+ 'first_name': response['first-name'],
+ 'last_name': response['last-name'],
+ 'email': '', # not supplied
+ }
+
+
+class LinkedinAuth(ConsumerBasedOAuth):
+ """Linkedin OAuth authentication mechanism"""
+ AUTHORIZATION_URL = LINKEDIN_AUTHORIZATION_URL
+ REQUEST_TOKEN_URL = LINKEDIN_REQUEST_TOKEN_URL
+ ACCESS_TOKEN_URL = LINKEDIN_ACCESS_TOKEN_URL
+ SERVER_URL = 'api.%s' % LINKEDIN_SERVER
+ AUTH_BACKEND = LinkedinBackend
+ SETTINGS_KEY_NAME = 'LINKEDIN_CONSUMER_KEY'
+ SETTINGS_SECRET_NAME = 'LINKEDIN_CONSUMER_SECRET'
+
+ def user_data(self, access_token):
+ """Return user data provided"""
+ request = self.oauth_request(access_token, LINKEDIN_CHECK_AUTH)
+ raw_xml = self.fetch_response(request)
+ try:
+ xml = ElementTree.fromstring(raw_xml)
+ data = _xml_to_dict(xml)
+ url = data['site-standard-profile-request']['url']
+ url = url.replace('&', '&')
+ data['id'] = urlparse.parse_qs(url)['key'][0]
+
+ return data
+ except (xml.parsers.expat.ExpatError, KeyError, IndexError):
+ return None
+
+ @classmethod
+ def enabled(cls):
+ return True
+
+
+# Backend definition
+BACKENDS = {
+ 'linkedin': LinkedinAuth,
+}
+
+
+def _xml_to_dict(xml):
+ data = {}
+ for child in xml.getchildren():
+ if child.getchildren():
+ data[child.tag] = _xml_to_dict(child)
+ else:
+ data[child.tag] = child.text
+
+ return data