]> git.parisson.com Git - django-social-auth.git/commitdiff
Merge remote branch 'upstream/master'
authorStas Kravets <skravets@applebough.(none)>
Fri, 20 May 2011 07:51:33 +0000 (11:51 +0400)
committerStas Kravets <skravets@applebough.(none)>
Fri, 20 May 2011 07:51:33 +0000 (11:51 +0400)
Conflicts:
example/templates/home.html

1  2 
example/templates/done.html
example/templates/home.html
social_auth/backends/contrib/vkontakte.py

index b0f9e70815e165e39dc7ddb7dc6350c459fbe235,2b67f3df5488dd58e2487f4071a523fdc2e5199a..7110ac81365c93253fc47f31f1c794c53e2d307d
      <li>
        <a rel="nofollow" href="{% url associate_begin "google-oauth2" %}">Google OAuth2</a>
        {% if google_oauth2 %}<span class="disconnect">(<a href="{% url disconnect "google-oauth2" %}">disconnect</a>)</span>{% endif %}
 +        <li><a rel="nofollow" href="{% url associate_begin "odnoklassniki" %}">Odnoklassniki OAuth 2.0</a></li>
 +        {% if odnoklassniki %}<span class="disconnect">(<a href="{% url disconnect "odnoklassniki" %}">disconnect</a>)</span>{% endif %}
 +        <li><a rel="nofollow" href="{% url associate_begin "vkontakte-oauth2" %}">VKontakte OAuth 2.0</a></li>
 +        {% if vkontakte_oauth2 %}<span class="disconnect">(<a href="{% url disconnect "vkontakte-oauth2" %}">disconnect</a>)</span>{% endif %}
 +        <li><a rel="nofollow" href="{% url associate_begin "mailru-oauth2" %}">Mail.ru OAuth 2.0</a></li>
 +        {% if mailru_oauth2 %}<span class="disconnect">(<a href="{% url disconnect "mailru-oauth2" %}">disconnect</a>)</span>{% endif %}
      </li>
+     <li>
+       <a rel="nofollow" href="{% url associate_begin "foursquare" %}">Foursquare</a>
+       {% if foursquare %}<span class="disconnect">(<a href="{% url disconnect "foursquare" %}">disconnect</a>)</span>{% endif %}
+     </li>
    </ul>
  
    <h3>Associate new OpenID credentials:</h3>
index b845eb0a5f6acf540ba00cca3e49c6c2c4ad9dcd,8555a50ac347f6f252e05d1b3c4d3a8fbbae35f7..36347560a68c4a697951af898065dadc101f660b
    <h3>Login using <a href="http://tools.ietf.org/html/draft-ietf-oauth-v2-10" title="OAuth2">OAuth2</a> from:</h3>
    <ul>
      <li><a rel="nofollow" href="{% url begin "google-oauth2" %}">Google OAuth2</a></li>
+     <li><a rel="nofollow" href="{% url begin "foursquare" %}">Foursquare</a></li>
 +      <li><a rel="nofollow" href="{% url begin "odnoklassniki" %}">Odnoklassniki OAuth 2.0</a></li>
 +      <li><a rel="nofollow" href="{% url begin "vkontakte-oauth2" %}">VKontakte OAuth 2.0</a></li>
 +      <li><a rel="nofollow" href="{% url begin "mailru-oauth2" %}">Mail.ru OAuth 2.0</a></li>
    </ul>
  </div>
  
index 0c547736df8d8ef46f0e832096f9bcb255dfe4b1,0000000000000000000000000000000000000000..3caa90dbae867afd680932407b4b8f3bc1e07cf9
mode 100644,000000..100644
--- /dev/null
@@@ -1,144 -1,0 +1,144 @@@
-         values = { USERNAME: response['user_id'], 'email': '', 'fullname': unquote(response['response']['user_name']),
 +"""
 +VKontakte OpenAPI and OAuth 2.0 support.
 +
 +This contribution adds support for VKontakte OpenAPI and OAuth 2.0 service in the form
 +www.vkontakte.ru. Username is retrieved from the identity returned by server.
 +"""
 +
 +from django.conf import settings
 +from django.contrib.auth import authenticate
 +from django.utils import simplejson
 +
 +from urllib import urlencode, unquote
 +from urllib2 import Request, urlopen
 +from hashlib import md5
 +from time import time
 +
 +from social_auth.backends import SocialAuthBackend, OAuthBackend, BaseAuth, BaseOAuth2, USERNAME
 +
 +VKONTAKTE_LOCAL_HTML  = 'vkontakte.html'
 +
 +VKONTAKTE_API_URL       = 'https://api.vkontakte.ru/method/'
 +VKONTAKTE_OAUTH2_SCOPE  = [''] # Enough for authentication
 +
 +EXPIRES_NAME = getattr(settings, 'SOCIAL_AUTH_EXPIRATION', 'expires')
 +
 +
 +class VKontakteBackend(SocialAuthBackend):
 +    """VKontakte authentication backend"""
 +    name = 'vkontakte'
 +
 +    def get_user_id(self, details, response):
 +        """Return user unique id provided by VKontakte"""
 +        return int(response.GET['id'])
 +    
 +    def get_user_details(self, response):
 +        """Return user details from VKontakte request"""
 +        nickname = unquote(response.GET['nickname'])
 +        values = { USERNAME: response.GET['id'] if len(nickname) == 0 else nickname, 'email': '', 'fullname': '',
 +                  'first_name': unquote(response.GET['first_name']), 'last_name': unquote(response.GET['last_name'])}
 +        return values
 +
 +
 +class VKontakteOAuth2Backend(OAuthBackend):
 +    """VKontakteOAuth2 authentication backend"""
 +    name = 'vkontakte-oauth2'
 +    EXTRA_DATA = [('expires_in', EXPIRES_NAME)]
 +
 +    def get_user_id(self, details, response):
 +        """Return user unique id provided by VKontakte"""
 +        return int(response['user_id'])
 +    
 +    def get_user_details(self, response):
 +        """Return user details from VKontakte request"""
++        values = { USERNAME: str(response['user_id']), 'email': '', 'fullname': unquote(response['response']['user_name']),
 +                  'first_name': '', 'last_name': ''}
 +        
 +        if ' ' in values['fullname']:
 +            values['first_name'], values['last_name'] = values['fullname'].split()
 +        else:
 +            values['first_name'] = values['fullname']
 +            
 +        return values
 +
 +
 +class VKontakteAuth(BaseAuth):
 +    """VKontakte OpenAPI authorization mechanism"""
 +    AUTH_BACKEND = VKontakteBackend
 +    APP_ID = settings.VKONTAKTE_APP_ID
 +    
 +    def auth_html(self):
 +        """Returns local VK authentication page, not necessary for VK to authenticate """
 +        from django.core.urlresolvers import reverse
 +        from django.template import RequestContext, loader
 +        
 +        dict = { 'VK_APP_ID'      : self.APP_ID,
 +                 'VK_COMPLETE_URL': reverse(settings.SOCIAL_AUTH_COMPLETE_URL_NAME, args=[VKontakteBackend.name]) }
 +        
 +        vk_template = loader.get_template(VKONTAKTE_LOCAL_HTML)
 +        context = RequestContext(self.request, dict)
 +    
 +        return vk_template.render(context)
 +        
 +    def auth_complete(self, *args, **kwargs):
 +        """Performs check of authentication in VKontakte, returns User if succeeded"""
 +        app_cookie = 'vk_app_' + self.APP_ID
 +        
 +        if not 'id' in self.request.GET or not app_cookie in self.request.COOKIES:
 +            raise ValueError('VKontakte authentication is not completed')
 +        
 +        cookie_dict = dict(item.split('=') for item in self.request.COOKIES[app_cookie].split('&'))
 +        check_str = ''.join([item + '=' + cookie_dict[item] for item in ['expire', 'mid', 'secret', 'sid']])
 +        
 +        hash = md5(check_str + settings.VKONTAKTE_APP_SECRET).hexdigest()
 +        
 +        if hash != cookie_dict['sig'] or int(cookie_dict['expire']) < time() :
 +            raise ValueError('VKontakte authentication failed: invalid hash')       
 +        else:
 +            kwargs.update({'response': self.request, self.AUTH_BACKEND.name: True})
 +            return authenticate(*args, **kwargs)
 +
 +    @property
 +    def uses_redirect(self):
 +        """VKontakte does not require visiting server url in order
 +        to do authentication, so auth_xxx methods are not needed to be called.
 +        Their current implementation is just an example"""
 +        return False
 +
 +    
 +class VKontakteOAuth2(BaseOAuth2):
 +    """VKontakte OAuth2 support"""
 +    AUTH_BACKEND = VKontakteOAuth2Backend
 +    AUTHORIZATION_URL = 'http://api.vkontakte.ru/oauth/authorize'
 +    ACCESS_TOKEN_URL = ' https://api.vkontakte.ru/oauth/access_token'
 +    SETTINGS_KEY_NAME = 'VKONTAKTE_APP_ID'
 +    SETTINGS_SECRET_NAME = 'VKONTAKTE_APP_SECRET'
 +
 +    def get_scope(self):
 +        return VKONTAKTE_OAUTH2_SCOPE + getattr(settings, 'VKONTAKTE_OAUTH2_EXTRA_SCOPE', [])
 +
 +    def user_data(self, access_token):
 +        """Return user data from VKontakte OpenAPI"""
 +        data = {'access_token': access_token }
 +        
 +        return vkontakte_api('getUserInfoEx', data)
 +
 +def vkontakte_api(method, data):
 +    """ Calls VKontakte OpenAPI method
 +        http://vkontakte.ru/apiclub, 
 +        http://vkontakte.ru/pages.php?o=-1&p=%C2%FB%EF%EE%EB%ED%E5%ED%E8%E5%20%E7%E0%EF%F0%EE%F1%EE%E2%20%EA%20API
 +    """
 +
 +    params = urlencode(data)
 +    request = Request(VKONTAKTE_API_URL + method + '?' + params)
 +    try:
 +        return simplejson.loads(urlopen(request).read())
 +    except (TypeError, KeyError, IOError, ValueError, IndexError):
 +        return None
 +        
 +# Backend definition
 +BACKENDS = {
 +    'vkontakte': VKontakteAuth,
 +    'vkontakte-oauth2': VKontakteOAuth2
 +}
 +