]> git.parisson.com Git - django-social-auth.git/commitdiff
Yandex OAuth2 support for Ya.ru and Moi Krug added
authorStas Kravets <krvss@mail.ru>
Wed, 4 Jan 2012 16:03:26 +0000 (20:03 +0400)
committerStas Kravets <krvss@mail.ru>
Wed, 4 Jan 2012 16:03:26 +0000 (20:03 +0400)
example/local_settings.py.template
example/settings.py
social_auth/backends/contrib/yandex.py

index 26aeaaea5bdff80a6c36258fe22c42b9d11628aa..7e928f14880523421d9af34958424cf6016d2d01 100644 (file)
@@ -31,3 +31,6 @@ GITHUB_APP_ID                     = ''
 GITHUB_API_SECRET                 = ''
 FOURSQUARE_CONSUMER_KEY           = ''
 FOURSQUARE_CONSUMER_SECRET        = ''
+YANDEX_OAUTH2_CLIENT_KEY          = ''
+YANDEX_OAUTH2_CLIENT_SECRET       = ''
+YANDEX_OAUTH2_API_URL             = 'https://api-yaru.yandex.ru/me/' # http://api.moikrug.ru/v1/my/ for Moi Krug
\ No newline at end of file
index 537d8218e86003ed0359c5b7b90c575c98ea0ef5..797e7df000271e6dfca70d80eb413285766109af 100644 (file)
@@ -80,6 +80,7 @@ AUTHENTICATION_BACKENDS = (
     'social_auth.backends.contrib.livejournal.LiveJournalBackend',
     'social_auth.backends.contrib.vkontakte.VKontakteBackend',
     'social_auth.backends.contrib.yandex.YandexBackend',
+    'social_auth.backends.contrib.yandex.YandexOAuth2Backend',
     'social_auth.backends.contrib.odnoklassniki.OdnoklassnikiBackend',
     'social_auth.backends.contrib.vkontakte.VKontakteOAuth2Backend',
     'social_auth.backends.contrib.mailru.MailruBackend',
index fee08b8fe7c5ad8e0baae6c9ae352f27ed64f537..8030e5b35d6e4ea7b5907dd28b5bd6254e086ec3 100644 (file)
@@ -11,7 +11,13 @@ logger = logging.getLogger(__name__)
 
 import urlparse
 
-from social_auth.backends import OpenIDBackend, OpenIdAuth, USERNAME
+from urllib import urlencode, unquote
+from urllib2 import Request, urlopen, HTTPError
+
+from django.conf import settings
+import xml.dom.minidom
+
+from social_auth.backends import OpenIDBackend, OpenIdAuth, USERNAME, OAuthBackend, BaseOAuth2
 
 
 # Yandex conf
@@ -19,6 +25,7 @@ YANDEX_URL = 'http://openid.yandex.ru/%s'
 YANDEX_USER_FIELD = 'openid_ya_user'
 YANDEX_OID_2_URL = 'http://yandex.ru'
 
+EXPIRES_NAME = getattr(settings, 'SOCIAL_AUTH_EXPIRATION', 'expires')
 
 class YandexBackend(OpenIDBackend):
     """Yandex OpenID authentication backend"""
@@ -36,6 +43,33 @@ class YandexBackend(OpenIDBackend):
         return values
 
 
+class YandexOAuth2Backend(OAuthBackend):
+    """Yandex OAuth2 authentication backend"""
+    name = 'yandex-oauth2'
+
+    def get_user_id(self, details, response):
+        """Return user unique id provided by Yandex"""
+        return int(response['id'])
+
+    def get_user_details(self, response):
+        """Return user details from Yandex request"""
+
+        name = unquote(response['name'])
+        first_name = ''
+        last_name = ''
+
+        if ' ' in name:
+            last_name, first_name = name.split(' ')
+            name = first_name
+        else:
+            first_name = name
+
+        values = { USERNAME: name, 'email': '',
+                   'first_name': first_name, 'last_name': last_name}
+
+        return values
+
+
 class YandexAuth(OpenIdAuth):
     """Yandex OpenID authentication"""
     AUTH_BACKEND = YandexBackend
@@ -46,8 +80,73 @@ class YandexAuth(OpenIdAuth):
             return YANDEX_OID_2_URL
         else:
             return YANDEX_URL % self.data[YANDEX_USER_FIELD]
-    
+
+
+class YandexOAuth2(BaseOAuth2):
+    """Yandex OAuth2 support
+       See http://api.yandex.ru/oauth/doc/dg/concepts/About.xml for details"""
+    AUTH_BACKEND = YandexOAuth2Backend
+    AUTHORIZATION_URL = 'https://oauth.yandex.ru/authorize'
+    ACCESS_TOKEN_URL = 'https://oauth.yandex.ru/token'
+    SETTINGS_KEY_NAME = 'YANDEX_OAUTH2_CLIENT_KEY'
+    SETTINGS_SECRET_NAME = 'YANDEX_OAUTH2_CLIENT_SECRET'
+
+    def get_scope(self):
+        return [] # Yandex does not allow custom scope
+
+    def auth_complete(self, *args, **kwargs):
+        try:
+            auth_result = super(YandexOAuth2, self).auth_complete(*args, **kwargs)
+        except HTTPError: # Returns HTTPError 400 if cancelled
+            raise ValueError('Authentication cancelled')
+
+        return auth_result
+
+    def user_data(self, access_token):
+        """Return user data from Yandex REST API specified in settings"""
+        params = urlencode({'oauth_token': access_token, 'text': 1, 'format': 'xml'})
+        request = Request(settings.YANDEX_OAUTH2_API_URL + '?' + params)
+
+        try:
+            dom = xml.dom.minidom.parseString(urlopen(request).read())
+
+            id = getNodeText(dom, "id")
+            if "/" in id:
+                id = id.split("/")[-1]
+
+            name = getNodeText(dom, "name")
+
+            links = getNodesWithAttribute(dom, "link", {"rel": "userpic"})
+            userpic = links[0].getAttribute("href") if links else ""
+
+            return {"id": id, "name": name, "userpic": userpic, "access_token": access_token}
+        except (TypeError, KeyError, IOError, ValueError, IndexError):
+            logger.error('Could not load data from Yandex.', exc_info=True, extra=dict(data=params))
+            return None
+
+
+def getNodeText(dom, nodeName):
+    nodelist = dom.getElementsByTagName(nodeName)[0].childNodes
+
+    rc = []
+    for node in nodelist:
+        if node.nodeType == node.TEXT_NODE:
+            rc.append(node.data)
+    return ''.join(rc)
+
+def getNodesWithAttribute(dom, nodeName, attrDict):
+    nodelist = dom.getElementsByTagName(nodeName)
+    found = []
+
+    for node in nodelist:
+        for key, value in attrDict.items():
+            if node.hasAttribute(key) and node.getAttribute(key) == value:
+                found.append(node)
+
+    return found
+
 # Backend definition
 BACKENDS = {
     'yandex': YandexAuth,
+    'yandex-oauth2': YandexOAuth2
 }