django-social-auth-0.7.23/ 0000755 0001750 0001750 00000000000 12135257233 015135 5 ustar omab omab 0000000 0000000 django-social-auth-0.7.23/PKG-INFO 0000644 0001750 0001750 00000020707 12135257233 016240 0 ustar omab omab 0000000 0000000 Metadata-Version: 1.1
Name: django-social-auth
Version: 0.7.23
Summary: Django social authentication made simple.
Home-page: https://github.com/omab/django-social-auth
Author: Matías Aguirre
Author-email: matiasaguirre@gmail.com
License: BSD
Description: Django Social Auth
==================
Django Social Auth is an easy way to setup social authentication/authorization
mechanism for Django projects.
Crafted using base code from django-twitter-oauth_ and django-openid-auth_,
it implements a common interface to define new authentication providers from
third parties.
You can view this app's documentation on `Read the Docs`_ too.
.. contents:: Table of Contents
Features
--------
This application provides user registration and login using social site
credentials. Some features are:
- Registration and login with social sites using the following providers
at the moment:
* `Google OpenID`_
* `Google OAuth`_
* `Google OAuth2`_
* `Yahoo OpenID`_
* OpenId_ like myOpenID_
* `Twitter OAuth`_
* `Facebook OAuth`_
Some contributions added support for:
* `DISQUS OAuth`_
* `LiveJournal OpenID`_
* `Orkut OAuth`_
* `Linkedin OAuth`_
* `Foursquare OAuth2`_
* `GitHub OAuth`_
* `Dropbox OAuth`_
* `Flickr OAuth`_
* `Vkontakte OAuth`_
* `MSN Live Connect OAuth2`_
* `Skyrock OAuth`_
* `Yahoo OAuth`_
* `Evernote OAuth`_
* `Mail.ru OAuth`_
* `Odnoklassniki OAuth`_
* `Mixcloud OAuth2`_
* `BitBucket OAuth`_
* `Douban OAuth`_
* `Fitbit OAuth`_
* `Instagram OAuth2`_
* `Twilio`_
* `Weibo OAuth2`_
* `Yandex OpenId`_
* `Shopify OAuth2`_
* `StockTwits OAuth2`_
* `Stackoverflow OAuth2`_
- Basic user data population and signaling to allows custom fields values
from providers' responses
- Multiple social account associations to a single user
- Custom User model override if needed (`auth.User`_ by default)
- Extensible pipeline to handle authentication/association mechanism
Demo
----
There's a demo at http://social.matiasaguirre.net/.
Note: It lacks some backends' support at the moment.
Contact
-------
Join the `django-social-auth discussion list`_ and bring any questions or suggestions
that would improve this application.
Also join the IRC channel ``#django-social-auth`` on Freenode server.
Documentation
-------------
Extensive documentation at `Read the Docs`_.
Dependencies
------------
Dependencies that **must** be met to use the application:
- OpenId_ support depends on python-openid_
- OAuth_ support depends on python-oauth2_
- Several backends demands application registration on their corresponding
sites
Installation
------------
From pypi_::
$ pip install django-social-auth
or::
$ easy_install django-social-auth
or clone from github_::
$ git clone git://github.com/omab/django-social-auth.git
and add social_auth to PYTHONPATH::
$ export PYTHONPATH=$PYTHONPATH:$(pwd)/django-social-auth/
or::
$ cd django-social-auth
$ sudo python setup.py install
Copyrights and Licence
----------------------
``django-social-auth`` is protected by BSD licence.
Some bits were derived from others' work and copyrighted by:
- django-twitter-oauth::
Original Copyright goes to Henrik Lied (henriklied)
Code borrowed from https://github.com/henriklied/django-twitter-oauth
- django-openid-auth::
django-openid-auth - OpenID integration for django.contrib.auth
Copyright (C) 2007 Simon Willison
Copyright (C) 2008-2010 Canonical Ltd.
.. _django-twitter-oauth: https://github.com/henriklied/django-twitter-oauth
.. _django-openid-auth: https://launchpad.net/django-openid-auth
.. _Read the Docs: http://django-social-auth.readthedocs.org/
.. _Google OpenID: https://developers.google.com/accounts/docs/OpenID
.. _Google OAuth: https://developers.google.com/accounts/docs/OAuth
.. _Google OAuth2: https://developers.google.com/accounts/docs/OAuth2
.. _Yahoo OpenID: http://openid.yahoo.com/
.. _OpenId: http://openid.net/
.. _myOpenID: https://www.myopenid.com/
.. _Twitter OAuth: http://dev.twitter.com/pages/oauth_faq
.. _Facebook OAuth: http://developers.facebook.com/docs/authentication/
.. _DISQUS OAuth: http://disqus.com/api/docs/auth/
.. _LiveJournal OpenID: http://www.livejournal.com/support/faqbrowse.bml?faqid=283
.. _Orkut OAuth: http://code.google.com/apis/orkut/docs/rest/developers_guide_protocol.html#Authenticating
.. _Linkedin OAuth: https://www.linkedin.com/secure/developer
.. _Foursquare OAuth2: https://developer.foursquare.com/docs/oauth.html
.. _GitHub OAuth: http://developer.github.com/v3/oauth/
.. _Dropbox OAuth: https://www.dropbox.com/developers_beta/reference/api
.. _Flickr OAuth: http://www.flickr.com/services/api/
.. _Vkontakte OAuth: http://vk.com/developers.php?oid=-1&p=%D0%90%D0%B2%D1%82%D0%BE%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F_%D1%81%D0%B0%D0%B9%D1%82%D0%BE%D0%B2
.. _MSN Live Connect OAuth2: http://msdn.microsoft.com/en-us/library/live/hh243647.aspx
.. _Skyrock OAuth: http://www.skyrock.com/developer/
.. _Yahoo OAuth: http://developer.yahoo.com/oauth/guide/oauth-auth-flow.html
.. _Evernote OAuth: http://dev.evernote.com/documentation/cloud/chapters/Authentication.php
.. _Mail.ru OAuth: http://api.mail.ru/docs/guides/oauth/
.. _Odnoklassniki OAuth: http://dev.odnoklassniki.ru/wiki/display/ok/The+OAuth+2.0+Protocol
.. _Mixcloud OAuth2: http://www.mixcloud.com/developers/documentation/#authorization
.. _BitBucket OAuth: https://confluence.atlassian.com/display/BITBUCKET/OAuth+Consumers
.. _Douban OAuth: http://www.douban.com/service/apidoc/auth
.. _Fitbit OAuth: https://wiki.fitbit.com/display/API/OAuth+Authentication+in+the+Fitbit+API
.. _Instagram OAuth2: http://instagram.com/developer/authentication/
.. _Twilio: https://www.twilio.com/user/account/connect/apps
.. _Weibo OAuth2: http://open.weibo.com/wiki/Oauth2
.. _Yandex OpenId: http://openid.yandex.ru/
.. _Shopify OAuth2: http://api.shopify.com/authentication.html
.. _StockTwits OAuth2: http://stocktwits.com/developers/docs/authentication
.. _auth.User: http://code.djangoproject.com/browser/django/trunk/django/contrib/auth/models.py#L186
.. _python-openid: http://pypi.python.org/pypi/python-openid/
.. _python-oauth2: https://github.com/simplegeo/python-oauth2
.. _OAuth: http://oauth.net/
.. _pypi: http://pypi.python.org/pypi/django-social-auth/
.. _github: https://github.com/omab/django-social-auth
.. _django-social-auth discussion list: https://groups.google.com/forum/?fromgroups#!forum/django-social-auth
.. _Stackoverflow OAuth2: http://api.stackexchange.com/
Keywords: django,openid,oauth,social auth,application
Platform: UNKNOWN
Classifier: Framework :: Django
Classifier: Development Status :: 4 - Beta
Classifier: Topic :: Internet
Classifier: License :: OSI Approved :: BSD License
Classifier: Intended Audience :: Developers
Classifier: Environment :: Web Environment
Classifier: Programming Language :: Python :: 2.5
Classifier: Programming Language :: Python :: 2.6
Classifier: Programming Language :: Python :: 2.7
django-social-auth-0.7.23/django_social_auth.egg-info/ 0000755 0001750 0001750 00000000000 12135257233 022444 5 ustar omab omab 0000000 0000000 django-social-auth-0.7.23/django_social_auth.egg-info/not-zip-safe 0000644 0001750 0001750 00000000001 12135257226 024674 0 ustar omab omab 0000000 0000000
django-social-auth-0.7.23/django_social_auth.egg-info/requires.txt 0000644 0001750 0001750 00000000060 12135257226 025042 0 ustar omab omab 0000000 0000000 Django>=1.2.5
oauth2>=1.5.167
python-openid>=2.2 django-social-auth-0.7.23/django_social_auth.egg-info/PKG-INFO 0000644 0001750 0001750 00000020707 12135257226 023551 0 ustar omab omab 0000000 0000000 Metadata-Version: 1.1
Name: django-social-auth
Version: 0.7.23
Summary: Django social authentication made simple.
Home-page: https://github.com/omab/django-social-auth
Author: Matías Aguirre
Author-email: matiasaguirre@gmail.com
License: BSD
Description: Django Social Auth
==================
Django Social Auth is an easy way to setup social authentication/authorization
mechanism for Django projects.
Crafted using base code from django-twitter-oauth_ and django-openid-auth_,
it implements a common interface to define new authentication providers from
third parties.
You can view this app's documentation on `Read the Docs`_ too.
.. contents:: Table of Contents
Features
--------
This application provides user registration and login using social site
credentials. Some features are:
- Registration and login with social sites using the following providers
at the moment:
* `Google OpenID`_
* `Google OAuth`_
* `Google OAuth2`_
* `Yahoo OpenID`_
* OpenId_ like myOpenID_
* `Twitter OAuth`_
* `Facebook OAuth`_
Some contributions added support for:
* `DISQUS OAuth`_
* `LiveJournal OpenID`_
* `Orkut OAuth`_
* `Linkedin OAuth`_
* `Foursquare OAuth2`_
* `GitHub OAuth`_
* `Dropbox OAuth`_
* `Flickr OAuth`_
* `Vkontakte OAuth`_
* `MSN Live Connect OAuth2`_
* `Skyrock OAuth`_
* `Yahoo OAuth`_
* `Evernote OAuth`_
* `Mail.ru OAuth`_
* `Odnoklassniki OAuth`_
* `Mixcloud OAuth2`_
* `BitBucket OAuth`_
* `Douban OAuth`_
* `Fitbit OAuth`_
* `Instagram OAuth2`_
* `Twilio`_
* `Weibo OAuth2`_
* `Yandex OpenId`_
* `Shopify OAuth2`_
* `StockTwits OAuth2`_
* `Stackoverflow OAuth2`_
- Basic user data population and signaling to allows custom fields values
from providers' responses
- Multiple social account associations to a single user
- Custom User model override if needed (`auth.User`_ by default)
- Extensible pipeline to handle authentication/association mechanism
Demo
----
There's a demo at http://social.matiasaguirre.net/.
Note: It lacks some backends' support at the moment.
Contact
-------
Join the `django-social-auth discussion list`_ and bring any questions or suggestions
that would improve this application.
Also join the IRC channel ``#django-social-auth`` on Freenode server.
Documentation
-------------
Extensive documentation at `Read the Docs`_.
Dependencies
------------
Dependencies that **must** be met to use the application:
- OpenId_ support depends on python-openid_
- OAuth_ support depends on python-oauth2_
- Several backends demands application registration on their corresponding
sites
Installation
------------
From pypi_::
$ pip install django-social-auth
or::
$ easy_install django-social-auth
or clone from github_::
$ git clone git://github.com/omab/django-social-auth.git
and add social_auth to PYTHONPATH::
$ export PYTHONPATH=$PYTHONPATH:$(pwd)/django-social-auth/
or::
$ cd django-social-auth
$ sudo python setup.py install
Copyrights and Licence
----------------------
``django-social-auth`` is protected by BSD licence.
Some bits were derived from others' work and copyrighted by:
- django-twitter-oauth::
Original Copyright goes to Henrik Lied (henriklied)
Code borrowed from https://github.com/henriklied/django-twitter-oauth
- django-openid-auth::
django-openid-auth - OpenID integration for django.contrib.auth
Copyright (C) 2007 Simon Willison
Copyright (C) 2008-2010 Canonical Ltd.
.. _django-twitter-oauth: https://github.com/henriklied/django-twitter-oauth
.. _django-openid-auth: https://launchpad.net/django-openid-auth
.. _Read the Docs: http://django-social-auth.readthedocs.org/
.. _Google OpenID: https://developers.google.com/accounts/docs/OpenID
.. _Google OAuth: https://developers.google.com/accounts/docs/OAuth
.. _Google OAuth2: https://developers.google.com/accounts/docs/OAuth2
.. _Yahoo OpenID: http://openid.yahoo.com/
.. _OpenId: http://openid.net/
.. _myOpenID: https://www.myopenid.com/
.. _Twitter OAuth: http://dev.twitter.com/pages/oauth_faq
.. _Facebook OAuth: http://developers.facebook.com/docs/authentication/
.. _DISQUS OAuth: http://disqus.com/api/docs/auth/
.. _LiveJournal OpenID: http://www.livejournal.com/support/faqbrowse.bml?faqid=283
.. _Orkut OAuth: http://code.google.com/apis/orkut/docs/rest/developers_guide_protocol.html#Authenticating
.. _Linkedin OAuth: https://www.linkedin.com/secure/developer
.. _Foursquare OAuth2: https://developer.foursquare.com/docs/oauth.html
.. _GitHub OAuth: http://developer.github.com/v3/oauth/
.. _Dropbox OAuth: https://www.dropbox.com/developers_beta/reference/api
.. _Flickr OAuth: http://www.flickr.com/services/api/
.. _Vkontakte OAuth: http://vk.com/developers.php?oid=-1&p=%D0%90%D0%B2%D1%82%D0%BE%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F_%D1%81%D0%B0%D0%B9%D1%82%D0%BE%D0%B2
.. _MSN Live Connect OAuth2: http://msdn.microsoft.com/en-us/library/live/hh243647.aspx
.. _Skyrock OAuth: http://www.skyrock.com/developer/
.. _Yahoo OAuth: http://developer.yahoo.com/oauth/guide/oauth-auth-flow.html
.. _Evernote OAuth: http://dev.evernote.com/documentation/cloud/chapters/Authentication.php
.. _Mail.ru OAuth: http://api.mail.ru/docs/guides/oauth/
.. _Odnoklassniki OAuth: http://dev.odnoklassniki.ru/wiki/display/ok/The+OAuth+2.0+Protocol
.. _Mixcloud OAuth2: http://www.mixcloud.com/developers/documentation/#authorization
.. _BitBucket OAuth: https://confluence.atlassian.com/display/BITBUCKET/OAuth+Consumers
.. _Douban OAuth: http://www.douban.com/service/apidoc/auth
.. _Fitbit OAuth: https://wiki.fitbit.com/display/API/OAuth+Authentication+in+the+Fitbit+API
.. _Instagram OAuth2: http://instagram.com/developer/authentication/
.. _Twilio: https://www.twilio.com/user/account/connect/apps
.. _Weibo OAuth2: http://open.weibo.com/wiki/Oauth2
.. _Yandex OpenId: http://openid.yandex.ru/
.. _Shopify OAuth2: http://api.shopify.com/authentication.html
.. _StockTwits OAuth2: http://stocktwits.com/developers/docs/authentication
.. _auth.User: http://code.djangoproject.com/browser/django/trunk/django/contrib/auth/models.py#L186
.. _python-openid: http://pypi.python.org/pypi/python-openid/
.. _python-oauth2: https://github.com/simplegeo/python-oauth2
.. _OAuth: http://oauth.net/
.. _pypi: http://pypi.python.org/pypi/django-social-auth/
.. _github: https://github.com/omab/django-social-auth
.. _django-social-auth discussion list: https://groups.google.com/forum/?fromgroups#!forum/django-social-auth
.. _Stackoverflow OAuth2: http://api.stackexchange.com/
Keywords: django,openid,oauth,social auth,application
Platform: UNKNOWN
Classifier: Framework :: Django
Classifier: Development Status :: 4 - Beta
Classifier: Topic :: Internet
Classifier: License :: OSI Approved :: BSD License
Classifier: Intended Audience :: Developers
Classifier: Environment :: Web Environment
Classifier: Programming Language :: Python :: 2.5
Classifier: Programming Language :: Python :: 2.6
Classifier: Programming Language :: Python :: 2.7
django-social-auth-0.7.23/django_social_auth.egg-info/top_level.txt 0000644 0001750 0001750 00000000014 12135257226 025173 0 ustar omab omab 0000000 0000000 social_auth
django-social-auth-0.7.23/django_social_auth.egg-info/dependency_links.txt 0000644 0001750 0001750 00000000001 12135257226 026514 0 ustar omab omab 0000000 0000000
django-social-auth-0.7.23/django_social_auth.egg-info/SOURCES.txt 0000644 0001750 0001750 00000006761 12135257226 024344 0 ustar omab omab 0000000 0000000 README.rst
setup.py
django_social_auth.egg-info/PKG-INFO
django_social_auth.egg-info/SOURCES.txt
django_social_auth.egg-info/dependency_links.txt
django_social_auth.egg-info/not-zip-safe
django_social_auth.egg-info/requires.txt
django_social_auth.egg-info/top_level.txt
social_auth/__init__.py
social_auth/admin.py
social_auth/context_processors.py
social_auth/decorators.py
social_auth/exceptions.py
social_auth/fields.py
social_auth/middleware.py
social_auth/models.py
social_auth/signals.py
social_auth/store.py
social_auth/urls.py
social_auth/utils.py
social_auth/views.py
social_auth/backends/__init__.py
social_auth/backends/browserid.py
social_auth/backends/facebook.py
social_auth/backends/google.py
social_auth/backends/reddit.py
social_auth/backends/steam.py
social_auth/backends/stripe.py
social_auth/backends/twitter.py
social_auth/backends/utils.py
social_auth/backends/yahoo.py
social_auth/backends/contrib/__init__.py
social_auth/backends/contrib/angel.py
social_auth/backends/contrib/behance.py
social_auth/backends/contrib/bitbucket.py
social_auth/backends/contrib/dailymotion.py
social_auth/backends/contrib/disqus.py
social_auth/backends/contrib/douban.py
social_auth/backends/contrib/dropbox.py
social_auth/backends/contrib/evernote.py
social_auth/backends/contrib/fitbit.py
social_auth/backends/contrib/flickr.py
social_auth/backends/contrib/foursquare.py
social_auth/backends/contrib/gae.py
social_auth/backends/contrib/github.py
social_auth/backends/contrib/instagram.py
social_auth/backends/contrib/linkedin.py
social_auth/backends/contrib/live.py
social_auth/backends/contrib/livejournal.py
social_auth/backends/contrib/mailru.py
social_auth/backends/contrib/mendeley.py
social_auth/backends/contrib/mixcloud.py
social_auth/backends/contrib/odnoklassniki.py
social_auth/backends/contrib/orkut.py
social_auth/backends/contrib/rdio.py
social_auth/backends/contrib/readability.py
social_auth/backends/contrib/shopify.py
social_auth/backends/contrib/skyrock.py
social_auth/backends/contrib/soundcloud.py
social_auth/backends/contrib/stackoverflow.py
social_auth/backends/contrib/stocktwits.py
social_auth/backends/contrib/tripit.py
social_auth/backends/contrib/tumblr.py
social_auth/backends/contrib/twilio.py
social_auth/backends/contrib/vkontakte.py
social_auth/backends/contrib/weibo.py
social_auth/backends/contrib/xing.py
social_auth/backends/contrib/yahoo.py
social_auth/backends/contrib/yammer.py
social_auth/backends/contrib/yammer_staging.py
social_auth/backends/contrib/yandex.py
social_auth/backends/pipeline/__init__.py
social_auth/backends/pipeline/associate.py
social_auth/backends/pipeline/misc.py
social_auth/backends/pipeline/social.py
social_auth/backends/pipeline/user.py
social_auth/db/__init__.py
social_auth/db/base.py
social_auth/db/django_models.py
social_auth/db/mongoengine_models.py
social_auth/locale/ru/LC_MESSAGES/django.mo
social_auth/locale/ru/LC_MESSAGES/django.po
social_auth/locale/tr/LC_MESSAGES/django.mo
social_auth/locale/tr/LC_MESSAGES/django.po
social_auth/management/__init__.py
social_auth/management/commands/__init__.py
social_auth/management/commands/clean_associations.py
social_auth/management/commands/clean_nonces.py
social_auth/migrations/0001_initial.py
social_auth/migrations/0002_auto__add_unique_nonce_timestamp_salt_server_url__add_unique_associati.py
social_auth/migrations/__init__.py
social_auth/tests/__init__.py
social_auth/tests/base.py
social_auth/tests/client.py
social_auth/tests/facebook.py
social_auth/tests/google.py
social_auth/tests/odnoklassniki.py
social_auth/tests/twitter.py django-social-auth-0.7.23/social_auth/ 0000755 0001750 0001750 00000000000 12135257233 017430 5 ustar omab omab 0000000 0000000 django-social-auth-0.7.23/social_auth/signals.py 0000644 0001750 0001750 00000000505 12127316474 021446 0 ustar omab omab 0000000 0000000 from django.dispatch import Signal
# This module is deprecated, this signals aren't used by the code anymore
# and it's functionality should be replaced by pipeline methods.
pre_update = Signal(providing_args=['user', 'response', 'details'])
socialauth_registered = Signal(providing_args=['user', 'response', 'details'])
django-social-auth-0.7.23/social_auth/tests/ 0000755 0001750 0001750 00000000000 12135257233 020572 5 ustar omab omab 0000000 0000000 django-social-auth-0.7.23/social_auth/tests/twitter.py 0000644 0001750 0001750 00000006112 12127316474 022652 0 ustar omab omab 0000000 0000000 from social_auth.utils import setting
from social_auth.tests.base import SocialAuthTestsCase, FormParserByID, \
RefreshParser
from django.test.utils import override_settings
class TwitterTestCase(SocialAuthTestsCase):
name = 'twitter'
def setUp(self, *args, **kwargs):
super(TwitterTestCase, self).setUp(*args, **kwargs)
self.user = setting('TEST_TWITTER_USER')
self.passwd = setting('TEST_TWITTER_PASSWORD')
# check that user and password are setup properly
self.assertTrue(self.user)
self.assertTrue(self.passwd)
class TwitterTestLogin(TwitterTestCase):
@override_settings(SOCIAL_AUTH_PIPELINE = (
'social_auth.backends.pipeline.social.social_auth_user',
'social_auth.backends.pipeline.associate.associate_by_email',
'social_auth.backends.pipeline.user.get_username',
'social_auth.backends.pipeline.misc.save_status_to_session',
'social_auth.backends.pipeline.social.associate_user',
'social_auth.backends.pipeline.social.load_extra_data',
'social_auth.backends.pipeline.user.update_user_details',
))
def test_login_succeful(self):
response = self.client.get(self.reverse('socialauth_begin', 'twitter'))
# social_auth must redirect to service page
self.assertEqual(response.status_code, 302)
# Open first redirect page, it contains user login form because
# we don't have cookie to send to twitter
login_content = self.get_content(response['Location'])
parser = FormParserByID('oauth_form')
parser.feed(login_content)
auth = {'session[username_or_email]': self.user,
'session[password]': self.passwd}
# Check that action and values were loaded properly
self.assertTrue(parser.action)
self.assertTrue(parser.values)
# Post login form, will return authorization or redirect page
parser.values.update(auth)
content = self.get_content(parser.action, data=parser.values)
# If page contains a form#login_form, then we are in the app
# authorization page because the app is not authorized yet,
# otherwise the app already gained permission and twitter sends
# a page that redirects to redirect_url
if 'login_form' in content:
# authorization form post, returns redirect_page
parser = FormParserByID('login_form').feed(content)
self.assertTrue(parser.action)
self.assertTrue(parser.values)
parser.values.update(auth)
redirect_page = self.get_content(parser.action, data=parser.values)
else:
redirect_page = content
parser = RefreshParser()
parser.feed(redirect_page)
self.assertTrue(parser.value)
response = self.client.get(self.make_relative(parser.value))
self.assertEqual(response.status_code, 302)
location = self.make_relative(response['Location'])
login_redirect = setting('LOGIN_REDIRECT_URL')
self.assertTrue(location == login_redirect)
django-social-auth-0.7.23/social_auth/tests/client.py 0000644 0001750 0001750 00000011314 12131430347 022415 0 ustar omab omab 0000000 0000000 import urllib
from django.conf import settings
from django.contrib.auth.models import AnonymousUser
from django.test.client import Client, RequestFactory
from django.utils import simplejson
from django.utils.importlib import import_module
from mock import patch
from social_auth.views import complete
class DumbResponse(object):
"""
Response from a call to, urllib2.urlopen()
"""
def __init__(self, data_str, url=None):
self.data_str = data_str
self.url = url
def read(self):
return self.data_str
class NoBackendError(Exception):
"""
Used when a client attempts to login with a invalid backend.
"""
pass
class SocialClient(Client):
"""
Test client to login/register a user
Does so by mocking api posts/responses.
Only supports facebook.
"""
@patch('social_auth.utils.urlopen')
def login(self, user, mock_urlopen, backend='facebook'):
"""
Login or Register a facebook user.
If the user has never logged in then they get registered and logged in.
If the user has already registered, then they are logged in.
user: dict
backend: 'facebook'
example user:
{
'first_name': 'Django',
'last_name': 'Reinhardt',
'verified': True,
'name': 'Django Reinhardt',
'locale': 'en_US',
'hometown': {
'id': '12345678',
'name': 'Any Town, Any State'
},
'expires': '4812',
'updated_time': '2012-01-29T19:27:32+0000',
'access_token': 'dummyToken',
'link': 'http://www.facebook.com/profile.php?id=1234',
'location': {
'id': '108659242498155',
'name': 'Chicago, Illinois'
},
'gender': 'male',
'timezone': -6,
'id': '1234',
'email': 'user@domain.com'
}
"""
token = 'dummyToken'
backends = {
'facebook': (
urllib.urlencode({
'access_token': token,
'expires': 3600,
}),
simplejson.dumps(user),
),
'google': (
simplejson.dumps({
"access_token": token,
"token_type": "Bearer",
"expires_in": 3600,
}),
simplejson.dumps(user),
),
'linkedin': (
urllib.urlencode({
'oauth_token': token,
'oauth_token_secret': token,
'oauth_callback_confirmed': 'true',
'xoauth_request_auth_url': (
'https://api.linkedin.com/uas/oauth/authorize'),
'oauth_expires_in': 3600,
}),
urllib.urlencode({
'oauth_token': token,
'oauth_token_secret': token,
'oauth_expires_in': 3600,
'oauth_authorization_expires_in': 3600,
}),
(('\n'
'\n'
' {id}\n'
' {email}\n'
' {first_name}\n'
' {last_name}\n'
'\n').format(**user)),
),
}
if backend not in backends:
raise NoBackendError("%s is not supported" % backend)
"""
mock out urlopen
"""
mock_urlopen.side_effect = [
DumbResponse(r) for r in backends[backend]
]
factory = RequestFactory()
request = factory.post('', {'code': 'dummy',
'redirect_state': 'dummy'})
engine = import_module(settings.SESSION_ENGINE)
if self.session:
request.session = self.session
else:
request.session = engine.SessionStore()
request.user = AnonymousUser()
request.session['facebook_state'] = 'dummy'
# make it happen.
redirect = complete(request, backend)
request.session.save()
# Set the cookie for this session.
session_cookie = settings.SESSION_COOKIE_NAME
self.cookies[session_cookie] = request.session.session_key
cookie_data = {
'max-age': None,
'path': '/',
'domain': settings.SESSION_COOKIE_DOMAIN,
'secure': settings.SESSION_COOKIE_SECURE or None,
'expires': None,
}
self.cookies[session_cookie].update(cookie_data)
return True
django-social-auth-0.7.23/social_auth/tests/odnoklassniki.py 0000644 0001750 0001750 00000020572 12127316474 024026 0 ustar omab omab 0000000 0000000 # -*- coding:utf-8 -*-
from __future__ import unicode_literals
from django.conf import settings
from django.core.urlresolvers import reverse
from django.test.testcases import LiveServerTestCase, SimpleTestCase
from django.test.utils import override_settings
from selenium.webdriver.firefox.webdriver import WebDriver
from selenium.webdriver.support.ui import WebDriverWait
from social_auth.backends.contrib.odnoklassniki import odnoklassniki_oauth_sig
from social_auth.models import UserSocialAuth
import time
class SignatureTest(SimpleTestCase):
def test_oauth_signature(self):
data = {'access_token': 'cq240efje3pd0gdXUmrvvMaHyb-74XQi8',
'application_key': 'CBAJLNABABABABABA',
'method': 'users.getCurrentUser',
'format': 'JSON'}
secret = '31D6095131175A7C9656EC2C'
signature = '755fe7af274abbe545916039eb428c98'
self.assertEqual(odnoklassniki_oauth_sig(data, secret), signature)
class OdnoklassnikiLiveTest(LiveServerTestCase):
@classmethod
def setUpClass(cls):
cls.selenium = WebDriver()
super(OdnoklassnikiLiveTest, cls).setUpClass()
@classmethod
def tearDownClass(cls):
super(OdnoklassnikiLiveTest, cls).tearDownClass()
cls.selenium.quit()
def get_odnoklassniki_name(self):
raise NotImplementedError('This method is part of interface, but should be implemented in subclass')
class BaseOdnoklassnikiAppTest(OdnoklassnikiLiveTest):
def setUp(self):
self.assertTrue(hasattr(settings, 'ODNOKLASSNIKI_APP_ID'),
"You need to have ODNOKLASSNIKI_APP_ID in settings to test iframe app")
self.assertTrue(hasattr(settings, 'ODNOKLASSNIKI_SANDBOX_DEV_USERNAME'),
"You need to have ODNOKLASSNIKI_SANDBOX_DEV_USERNAME in settings to test iframe app")
self.assertTrue(hasattr(settings, 'ODNOKLASSNIKI_SANDBOX_DEV_PASSWORD'),
"You need to have ODNOKLASSNIKI_SANDBOX_DEV_PASSWORD in settings to test iframe app")
self.app_id = settings.ODNOKLASSNIKI_APP_ID
self.dev_username = settings.ODNOKLASSNIKI_SANDBOX_DEV_USERNAME
self.dev_password = settings.ODNOKLASSNIKI_SANDBOX_DEV_PASSWORD
self.get_odnoklassniki_name()
def sandbox_login(self):
WebDriverWait(self.selenium, 3).until(lambda ff: ff.find_element_by_name('j_username'))
dev_username_input = self.selenium.find_element_by_name('j_username')
dev_username_input.send_keys(self.dev_username)
dev_password_input = self.selenium.find_element_by_name('j_password')
dev_password_input.send_keys(self.dev_password)
self.selenium.find_element_by_name('actionId').click()
def sandbox_logout(self):
self.selenium.get('http://api-sandbox.odnoklassniki.ru:8088/sandbox/logout.do')
WebDriverWait(self.selenium, 3).until(lambda ff: ff.find_element_by_name('j_username'))
def get_odnoklassniki_name(self):
self.selenium.get('http://api-sandbox.odnoklassniki.ru:8088/sandbox/protected/main.do')
self.sandbox_login()
WebDriverWait(self.selenium, 3).until(lambda ff: ff.find_element_by_tag_name('fieldset'))
self.odnoklassniki_name = self.selenium.find_element_by_xpath('//*[@id="command"]/fieldset/table/tbody/tr[2]/td[2]').text
self.sandbox_logout()
def login_into_sandbox(self):
self.selenium.get('http://api-sandbox.odnoklassniki.ru:8088/sandbox/protected/application/launch.do?appId={0:s}&userId=0'.format(self.app_id))
self.sandbox_login()
WebDriverWait(self.selenium, 3).until(lambda ff: ff.find_element_by_tag_name('iframe'))
time.sleep(1)
class OdnoklassnikiAppTest(BaseOdnoklassnikiAppTest):
def test_auth(self):
self.login_into_sandbox()
self.assertEquals(UserSocialAuth.objects.count(), 1)
social_auth = UserSocialAuth.objects.get()
user = social_auth.user
full_name = '{0} {1}'.format(user.first_name, user.last_name)
self.assertEquals(full_name, self.odnoklassniki_name)
self.assertTrue('apiconnection' in social_auth.extra_data)
self.assertTrue('api_server' in social_auth.extra_data)
class OdnoklassnikiAppTestExtraData(BaseOdnoklassnikiAppTest):
@override_settings(ODNOKLASSNIKI_APP_EXTRA_USER_DATA_LIST = ('gender', 'birthday', 'age'))
def test_extra_data(self):
self.login_into_sandbox()
self.assertEquals(UserSocialAuth.objects.count(), 1)
social_user = UserSocialAuth.objects.get()
user = social_user.user
full_name = '{0} {1}'.format(user.first_name, user.last_name)
self.assertEquals(full_name, self.odnoklassniki_name)
self.assertTrue(all([field in social_user.extra_data for field in ('gender', 'birthday', 'age')]))
class OdnoklassnikiOAuthTest(OdnoklassnikiLiveTest):
def setUp(self):
self.assertTrue(hasattr(settings, 'ODNOKLASSNIKI_OAUTH2_CLIENT_KEY'),
"You need to have ODNOKLASSNIKI_OAUTH2_CLIENT_KEY in settings to test odnoklassniki OAuth")
self.assertTrue(hasattr(settings, 'ODNOKLASSNIKI_TEST_USERNAME'),
"You need to have ODNOKLASSNIKI_TEST_USERNAME in settings to test odnoklassniki OAuth")
self.assertTrue(hasattr(settings, 'ODNOKLASSNIKI_TEST_PASSWORD'),
"You need to have ODNOKLASSNIKI_TEST_PASSWORD in settings to test odnoklassniki OAuth")
self.username = settings.ODNOKLASSNIKI_TEST_USERNAME
self.password = settings.ODNOKLASSNIKI_TEST_PASSWORD
self.get_odnoklassniki_name()
def get_odnoklassniki_name(self):
#Load login page
self.selenium.get('http://www.odnoklassniki.ru/')
WebDriverWait(self.selenium, 3).until(lambda ff: ff.find_element_by_id('field_email'))
email_input = self.selenium.find_element_by_id('field_email')
email_input.send_keys(self.username)
pw_input = self.selenium.find_element_by_id('field_password')
pw_input.send_keys(self.password)
self.selenium.find_element_by_id('hook_FormButton_button_go').click()
#Submit form, wait for successful login
name_css_sel = '#hook_Block_MiddleColumnTopCardUser .mctc_name>a.mctc_nameLink'
WebDriverWait(self.selenium, 2).until(lambda ff: ff.find_element_by_css_selector(name_css_sel))
self.odnoklassniki_name = self.selenium.find_element_by_css_selector(name_css_sel).text
#Remember the name of logged user
link = [el for el in self.selenium.find_elements_by_css_selector('.portal-headline__login__link') if el.text == 'выход']
self.assertTrue(len(link) == 1)
link[0].click()
#Click on logout link to show logout popup
WebDriverWait(self.selenium, 2).until(lambda ff: ff.find_element_by_id('hook_Form_PopLayerLogoffUserForm') and ff.find_element_by_id('hook_Form_PopLayerLogoffUserForm').is_displayed())
self.selenium.find_element_by_css_selector('#hook_FormButton_button_logoff').click()
#Click logout popup and wait for the login form be shown
WebDriverWait(self.selenium, 2).until(lambda ff: ff.find_element_by_id('field_email'))
def login_into_odnoklassniki(self):
url = reverse('socialauth_begin', args=('odnoklassniki',))
self.selenium.get('{0:s}{1:s}'.format(self.live_server_url, url))
WebDriverWait(self.selenium, 2).until(lambda ff: ff.find_element_by_id('field_email'))
email_input = self.selenium.find_element_by_id('field_email')
pw_input = self.selenium.find_element_by_id('field_password')
email_input.send_keys(self.username)
pw_input.send_keys(self.password)
self.selenium.find_element_by_name('button_continue').click()
WebDriverWait(self.selenium, 2).until(lambda ff: ff.find_element_by_name('button_accept_request'))
self.selenium.find_element_by_name('button_accept_request').click()
self.selenium.implicitly_wait(2)
time.sleep(1)#We need this for the server to close database connection
#If this line is removed, following line will fail
def test_auth(self):
self.login_into_odnoklassniki()
self.assertEquals(UserSocialAuth.objects.count(), 1)
user = UserSocialAuth.objects.get().user
full_name = '{0} {1}'.format(user.first_name, user.last_name)
self.assertEquals(full_name, self.odnoklassniki_name)
django-social-auth-0.7.23/social_auth/tests/facebook.py 0000644 0001750 0001750 00000006400 12127316474 022721 0 ustar omab omab 0000000 0000000 import re
from social_auth.utils import setting
from social_auth.tests.base import SocialAuthTestsCase, FormParserByID
from django.contrib.sites.models import Site
class FacebookTestCase(SocialAuthTestsCase):
SERVER_NAME = 'myapp.com'
SERVER_PORT = '8000'
def __init__(self, methodName='runTest'):
self.SERVER_NAME = Site.objects.get_current()
super(FacebookTestCase, self).__init__(methodName)
name = 'facebook'
def setUp(self, *args, **kwargs):
super(FacebookTestCase, self).setUp(*args, **kwargs)
self.user = setting('TEST_FACEBOOK_USER')
self.passwd = setting('TEST_FACEBOOK_PASSWORD')
# check that user and password are setup properly
self.assertTrue(self.user)
self.assertTrue(self.passwd)
REDIRECT_RE = re.compile('window.location.replace\("(.*)"\);')
class FacebookTestLogin(FacebookTestCase):
def test_login_succeful(self):
"""
"""
response = self.client.get('http://%s%s' % (self.SERVER_NAME, self.reverse('socialauth_begin', 'facebook')))
# social_auth must redirect to service page
self.assertEqual(response.status_code, 302)
# Open first redirect page, it contains user login form because
# we don't have cookie to send to twitter
parser = FormParserByID('login_form')
content = self.get_content(response['Location'], use_cookies=True)
parser.feed(content)
auth = {'email': self.user,
'pass': self.passwd}
# Check that action and values were loaded properly
self.assertTrue(parser.action)
self.assertTrue(parser.values)
# Post login form, will return authorization or redirect page
parser.values.update(auth)
redirect = self.get_redirect(parser.action, parser.values,
use_cookies=True)
# If page contains a form#login_form, then we are in the app
# authorization page because the app is not authorized yet,
# otherwise the app already gained permission and twitter sends
# a page that redirects to redirect_url
if 'login_form' in content:
# authorization form post, returns redirect_page
parser = FormParserByID('login_form')
parser.feed(content)
self.assertTrue(parser.action)
self.assertTrue(parser.values)
parser.values.update(auth)
redirect = self.get_redirect(parser.action, parser.values,
use_cookies=True)
redirect_page = redirect.read()
else:
redirect = self.get_redirect(redirect.headers['Location'],
use_cookies=True)
redirect_page = redirect.read()
if 'uiserver_form' in redirect_page:
# authorization form post, returns redirect_page
parser = FormParserByID('uiserver_form')
parser.feed(redirect_page)
self.assertTrue(parser.action)
self.assertTrue(parser.values)
parser.values.update(auth)
redirect = self.get_redirect(parser.action, parser.values,
use_cookies=True)
self.assertTrue(setting('LOGIN_REDIRECT_URL') in self.make_relative(redirect.headers['Location']))
django-social-auth-0.7.23/social_auth/tests/__init__.py 0000644 0001750 0001750 00000000636 12127316474 022714 0 ustar omab omab 0000000 0000000 from social_auth.utils import setting
if setting('SOCIAL_AUTH_TEST_TWITTER', True):
from social_auth.tests.twitter import *
if setting('SOCIAL_AUTH_TEST_FACEBOOK', True):
from social_auth.tests.facebook import *
if setting('SOCIAL_AUTH_TEST_GOOGLE', True):
from social_auth.tests.google import *
if setting('SOCIAL_AUTH_TEST_ODNOKLASSNIKI', True):
from social_auth.tests.odnoklassniki import * django-social-auth-0.7.23/social_auth/tests/base.py 0000644 0001750 0001750 00000014324 12127316474 022066 0 ustar omab omab 0000000 0000000 import re
import urllib2
import cookielib
import urllib
import urlparse
import unittest
from sgmllib import SGMLParser
from django.conf import settings
from django.test.client import Client
from django.core.urlresolvers import reverse
USER_AGENT = 'Mozilla/5.0'
REFRESH_RE = re.compile(r'\d;\s*url=')
class SocialAuthTestsCase(unittest.TestCase):
"""Base class for social auth tests"""
SERVER_NAME = None
SERVER_PORT = None
def __init__(self, *args, **kwargs):
client_kwargs = {}
if self.SERVER_NAME:
client_kwargs['SERVER_NAME'] = self.SERVER_NAME
if self.SERVER_PORT:
client_kwargs['SERVER_PORT'] = self.SERVER_PORT
self.jar = None
self.client = Client(**client_kwargs)
super(SocialAuthTestsCase, self).__init__(*args, **kwargs)
def setUp(self):
from social_auth import backends
self.old_PIPELINE = backends.PIPELINE
backends.PIPELINE = (
'social_auth.backends.pipeline.social.social_auth_user',
'social_auth.backends.pipeline.associate.associate_by_email',
'social_auth.backends.pipeline.user.get_username',
'social_auth.backends.pipeline.user.create_user',
'social_auth.backends.pipeline.social.associate_user',
'social_auth.backends.pipeline.social.load_extra_data',
'social_auth.backends.pipeline.user.update_user_details',
)
super(SocialAuthTestsCase, self).setUp()
def tearDown(self):
from social_auth import backends
backends.PIPELINE = self.old_PIPELINE
super(SocialAuthTestsCase, self).tearDown()
def test_backend_cache(self):
"""Ensure that the backend for the testcase gets cached."""
try:
self.name
except AttributeError:
pass
else:
if self.name not in settings.SOCIAL_AUTH_ENABLED_BACKENDS:
# this backend is not enabled (for example, google-openid/google-oauth2)
return
from social_auth import backends
backends.BACKENDS = {}
self.client.get(self.reverse('socialauth_begin', self.name))
self.assertTrue(self.name in backends.BACKENDSCACHE)
def get_content(self, url, data=None, use_cookies=False):
"""Return content for given url, if data is not None, then a POST
request will be issued, otherwise GET will be used"""
data = data and urllib.urlencode(data, doseq=True) or data
request = urllib2.Request(url)
agent = urllib2.build_opener()
if use_cookies:
agent.add_handler(urllib2.HTTPCookieProcessor(self.get_jar()))
request.add_header('User-Agent', USER_AGENT)
return ''.join(agent.open(request, data=data).readlines())
def get_redirect(self, url, data=None, use_cookies=False):
"""Return content for given url, if data is not None, then a POST
request will be issued, otherwise GET will be used"""
data = data and urllib.urlencode(data, doseq=True) or data
request = urllib2.Request(url)
agent = urllib2.build_opener(RedirectHandler())
if use_cookies:
agent.add_handler(urllib2.HTTPCookieProcessor(self.get_jar()))
request.add_header('User-Agent', USER_AGENT)
return agent.open(request, data=data)
def get_jar(self):
if not self.jar:
self.jar = cookielib.CookieJar()
return self.jar
def reverse(self, name, backend):
"""Reverses backend URL by name"""
return reverse(name, args=(backend,))
def make_relative(self, value):
"""Converst URL to relative, useful for server responses"""
parsed = urlparse.urlparse(value)
return urlparse.urlunparse(('', '', parsed.path, parsed.params,
parsed.query, parsed.fragment))
class CustomParser(SGMLParser):
"""Custom SGMLParser that closes the parser once it's fed"""
def feed(self, data):
SGMLParser.feed(self, data)
self.close()
class FormParser(CustomParser):
"""Form parser, load form data and action for given form"""
def __init__(self, *args, **kwargs):
CustomParser.__init__(self, *args, **kwargs)
self.inside_form = False
self.action = None
self.values = {}
def start_form(self, attributes):
"""Start form parsing detecting if form is the one requested"""
attrs = dict(attributes)
if self.in_form(attrs):
# flag that we are inside the form and save action
self.inside_form = True
self.action = attrs.get('action')
def in_form(self, attrs):
"""Override below"""
return True
def end_form(self):
"""End form parsing, unset inside_form flag"""
self.inside_form = False
def start_input(self, attributes):
"""Parse input fields, we only keep data for fields of type text,
hidden or password and that has a valid name."""
attrs = dict(attributes)
if self.inside_form:
type, name, value = attrs.get('type'), attrs.get('name'), \
attrs.get('value')
if name and type in ('text', 'hidden', 'password'):
self.values[name] = value
class FormParserByID(FormParser):
"""Form parser, load form data and action for given form identified
by its id"""
def __init__(self, form_id, *args, **kwargs):
FormParser.__init__(self, *args, **kwargs)
self.form_id = form_id
def in_form(self, attrs):
return attrs.get('id') == self.form_id
class RefreshParser(CustomParser):
"""Refresh parser, will check refresh by meta tag and store refresh URL"""
def __init__(self, *args, **kwargs):
CustomParser.__init__(self, *args, **kwargs)
self.value = None
def start_meta(self, attributes):
"""Start meta parsing checking by http-equiv attribute"""
attrs = dict(attributes)
if attrs.get('http-equiv') == 'refresh':
self.value = REFRESH_RE.sub('', attrs.get('content')).strip("'")
class RedirectHandler(urllib2.HTTPRedirectHandler):
def http_error_302(self, req, fp, code, msg, headers):
return fp
django-social-auth-0.7.23/social_auth/tests/google.py 0000644 0001750 0001750 00000006130 12127316474 022424 0 ustar omab omab 0000000 0000000 import re
from social_auth.utils import setting
from social_auth.tests.base import SocialAuthTestsCase, FormParserByID, \
FormParser, RefreshParser
from django.conf import settings
class GoogleTestCase(SocialAuthTestsCase):
name = 'google'
def setUp(self, *args, **kwargs):
super(GoogleTestCase, self).setUp(*args, **kwargs)
self.user = setting('TEST_GOOGLE_USER')
self.passwd = setting('TEST_GOOGLE_PASSWORD')
# check that user and password are setup properly
self.assertTrue(self.user)
self.assertTrue(self.passwd)
REDIRECT_RE = re.compile('window.location.replace\("(.*)"\);')
class GoogleOpenIdTestLogin(GoogleTestCase):
SERVER_NAME = 'myapp.com'
SERVER_PORT = '8000'
def test_login_succeful(self):
if self.name not in settings.SOCIAL_AUTH_ENABLED_BACKENDS:
self.skipTest('Google OpenID is not enabled')
response = self.client.get(self.reverse('socialauth_begin', 'google'))
parser = FormParserByID('openid_message')
parser.feed(response.content)
# Check that action and values were loaded properly
self.assertTrue(parser.action)
self.assertTrue(parser.values)
content = self.get_content(parser.action, parser.values,
use_cookies=True)
parser = FormParserByID('gaia_loginform')
parser.feed(content)
auth = {'Email': self.user, 'Passwd': self.passwd}
parser.values.update(auth)
# Check that action and values were loaded properly
self.assertTrue(parser.action)
self.assertTrue(parser.values)
content = self.get_content(parser.action, parser.values,
use_cookies=True)
parser = RefreshParser()
parser.feed(content)
# approved?
result = self.get_redirect(parser.value, use_cookies=True)
if result.headers.get('Location', ''): # approved?
# damn, google has a hell of redirects :-(
result = self.get_redirect(result.headers['Location'],
use_cookies=True)
result = self.get_redirect(result.headers['Location'],
use_cookies=True)
result = self.get_redirect(result.headers['Location'],
use_cookies=True)
# app was not approved
if self.SERVER_NAME not in result.headers.get('Location', ''):
content = self.get_content(parser.value, use_cookies=True)
parser = FormParser()
parser.feed(content)
parser.values['submit_true'] = 'yes'
parser.values['remember_choices'] = 'yes'
result = self.get_redirect(parser.action, parser.values,
use_cookies=True)
response = self.client.get(self.make_relative(
result.headers['Location']))
self.assertTrue(setting('LOGIN_REDIRECT_URL') in \
self.make_relative(response['Location']))
django-social-auth-0.7.23/social_auth/store.py 0000644 0001750 0001750 00000003256 12127316474 021150 0 ustar omab omab 0000000 0000000 """OpenId storage that saves to django models"""
import time
from openid.store.interface import OpenIDStore
from openid.store.nonce import SKEW
from social_auth.models import UserSocialAuth
class DjangoOpenIDStore(OpenIDStore):
"""Storage class"""
def __init__(self):
"""Init method"""
super(DjangoOpenIDStore, self).__init__()
self.max_nonce_age = 6 * 60 * 60 # Six hours
def storeAssociation(self, server_url, association):
"""Store new assocition if doesn't exist"""
UserSocialAuth.store_association(server_url, association)
def removeAssociation(self, server_url, handle):
return UserSocialAuth.remove_association(server_url, handle)
def getAssociation(self, server_url, handle=None):
"""Return stored assocition"""
oid_associations = UserSocialAuth.get_oid_associations(server_url,
handle)
associations = [association
for assoc_id, association in oid_associations
if association.getExpiresIn() > 0]
expired = [assoc_id for assoc_id, association in oid_associations
if association.getExpiresIn() == 0]
if expired: # clear expired associations
UserSocialAuth.delete_associations(expired)
if associations: # return most recet association
return associations[0]
def useNonce(self, server_url, timestamp, salt):
"""Generate one use number and return *if* it was created"""
if abs(timestamp - time.time()) > SKEW:
return False
return UserSocialAuth.use_nonce(server_url, timestamp, salt)
django-social-auth-0.7.23/social_auth/models.py 0000644 0001750 0001750 00000001031 12127316474 021264 0 ustar omab omab 0000000 0000000 """Social auth models"""
import types
from django.utils.importlib import import_module
from social_auth.utils import setting
SOCIAL_AUTH_MODELS_MODULE = import_module(setting('SOCIAL_AUTH_MODELS',
'social_auth.db.django_models'))
globals().update((name, value) for name, value in
((name, getattr(SOCIAL_AUTH_MODELS_MODULE, name))
for name in dir(SOCIAL_AUTH_MODELS_MODULE))
if isinstance(value, (type, types.ClassType)))
django-social-auth-0.7.23/social_auth/db/ 0000755 0001750 0001750 00000000000 12135257233 020015 5 ustar omab omab 0000000 0000000 django-social-auth-0.7.23/social_auth/db/mongoengine_models.py 0000644 0001750 0001750 00000006141 12133321477 024241 0 ustar omab omab 0000000 0000000 """
MongoEngine models for Social Auth
Requires MongoEngine 0.6.10
"""
try:
from django.contrib.auth.hashers import UNUSABLE_PASSWORD
_ = UNUSABLE_PASSWORD # to quiet flake
except (ImportError, AttributeError):
UNUSABLE_PASSWORD = '!'
from django.utils.importlib import import_module
from mongoengine import DictField, Document, IntField, ReferenceField, \
StringField
from mongoengine.queryset import OperationError
from social_auth.utils import setting
from social_auth.db.base import UserSocialAuthMixin, AssociationMixin, \
NonceMixin
USER_MODEL_MODULE, USER_MODEL_NAME = (
setting('SOCIAL_AUTH_USER_MODEL') or
setting('AUTH_USER_MODEL') or
'mongoengine.django.auth.User'
).rsplit('.', 1)
USER_MODEL = getattr(import_module(USER_MODEL_MODULE), USER_MODEL_NAME)
class UserSocialAuth(Document, UserSocialAuthMixin):
"""Social Auth association model"""
user = ReferenceField(USER_MODEL, dbref=True)
provider = StringField(max_length=32)
uid = StringField(max_length=255, unique_with='provider')
extra_data = DictField()
@classmethod
def get_social_auth_for_user(cls, user):
return cls.objects(user=user)
@classmethod
def create_social_auth(cls, user, uid, provider):
if not isinstance(type(uid), basestring):
uid = str(uid)
return cls.objects.create(user=user, uid=uid, provider=provider)
@classmethod
def username_max_length(cls):
return UserSocialAuth.user_model().username.max_length
@classmethod
def email_max_length(cls):
return UserSocialAuth.user_model().email.max_length
@classmethod
def user_model(cls):
return USER_MODEL
@classmethod
def create_user(cls, *args, **kwargs):
# Empty string makes email regex validation fail
if kwargs.get('email') == '':
kwargs['email'] = None
kwargs.setdefault('password', UNUSABLE_PASSWORD)
return cls.user_model().create_user(*args, **kwargs)
@classmethod
def allowed_to_disconnect(cls, user, backend_name, association_id=None):
if association_id is not None:
qs = cls.objects.filter(id__ne=association_id)
else:
qs = cls.objects.filter(provider__ne=backend_name)
qs = qs.filter(user=user)
if hasattr(user, 'has_usable_password'):
valid_password = user.has_usable_password()
else:
valid_password = True
return valid_password or qs.count() > 0
class Nonce(Document, NonceMixin):
"""One use numbers"""
server_url = StringField(max_length=255)
timestamp = IntField()
salt = StringField(max_length=40)
class Association(Document, AssociationMixin):
"""OpenId account association"""
server_url = StringField(max_length=255)
handle = StringField(max_length=255)
secret = StringField(max_length=255) # Stored base64 encoded
issued = IntField()
lifetime = IntField()
assoc_type = StringField(max_length=64)
def is_integrity_error(exc):
return exc.__class__ is OperationError and 'E11000' in exc.message
django-social-auth-0.7.23/social_auth/db/django_models.py 0000644 0001750 0001750 00000006256 12127316474 023211 0 ustar omab omab 0000000 0000000 """Django ORM models for Social Auth"""
from django.db import models
from django.db.utils import IntegrityError
from social_auth.db.base import UserSocialAuthMixin, AssociationMixin, \
NonceMixin
from social_auth.fields import JSONField
from social_auth.utils import setting
# If User class is overridden, it *must* provide the following fields
# and methods work with django-social-auth:
#
# username = CharField()
# last_login = DateTimeField()
# is_active = BooleanField()
# def is_authenticated():
# ...
USER_MODEL = setting('SOCIAL_AUTH_USER_MODEL') or \
setting('AUTH_USER_MODEL') or \
'auth.User'
UID_LENGTH = setting('SOCIAL_AUTH_UID_LENGTH', 255)
NONCE_SERVER_URL_LENGTH = setting('SOCIAL_AUTH_NONCE_SERVER_URL_LENGTH', 255)
ASSOCIATION_SERVER_URL_LENGTH = setting(
'SOCIAL_AUTH_ASSOCIATION_SERVER_URL_LENGTH',
255
)
ASSOCIATION_HANDLE_LENGTH = setting(
'SOCIAL_AUTH_ASSOCIATION_HANDLE_LENGTH',
255
)
class UserSocialAuth(models.Model, UserSocialAuthMixin):
"""Social Auth association model"""
user = models.ForeignKey(USER_MODEL, related_name='social_auth')
provider = models.CharField(max_length=32)
uid = models.CharField(max_length=UID_LENGTH)
extra_data = JSONField(default='{}')
class Meta:
"""Meta data"""
unique_together = ('provider', 'uid')
app_label = 'social_auth'
@classmethod
def get_social_auth(cls, provider, uid):
try:
return cls.objects.select_related('user').get(provider=provider,
uid=uid)
except UserSocialAuth.DoesNotExist:
return None
@classmethod
def username_max_length(cls):
return cls._field_length('USERNAME_FIELD', 'username')
@classmethod
def email_max_length(cls):
return cls._field_length('EMAIL_FIELD', 'email')
@classmethod
def _field_length(self, setting_name, default_name):
model = UserSocialAuth.user_model()
field_name = getattr(model, setting_name, default_name)
return model._meta.get_field(field_name).max_length
@classmethod
def user_model(cls):
return UserSocialAuth._meta.get_field('user').rel.to
class Nonce(models.Model, NonceMixin):
"""One use numbers"""
server_url = models.CharField(max_length=NONCE_SERVER_URL_LENGTH)
timestamp = models.IntegerField(db_index=True)
salt = models.CharField(max_length=40)
class Meta:
app_label = 'social_auth'
unique_together = ('server_url', 'timestamp', 'salt')
class Association(models.Model, AssociationMixin):
"""OpenId account association"""
server_url = models.CharField(max_length=ASSOCIATION_SERVER_URL_LENGTH)
handle = models.CharField(max_length=ASSOCIATION_HANDLE_LENGTH)
secret = models.CharField(max_length=255) # Stored base64 encoded
issued = models.IntegerField(db_index=True)
lifetime = models.IntegerField()
assoc_type = models.CharField(max_length=64)
class Meta:
app_label = 'social_auth'
unique_together = ('server_url', 'handle')
def is_integrity_error(exc):
return exc.__class__ is IntegrityError
django-social-auth-0.7.23/social_auth/db/__init__.py 0000644 0001750 0001750 00000000000 12127316474 022120 0 ustar omab omab 0000000 0000000 django-social-auth-0.7.23/social_auth/db/base.py 0000644 0001750 0001750 00000020541 12127317036 021302 0 ustar omab omab 0000000 0000000 """Models mixins for Social Auth"""
import base64
import time
import re
from datetime import datetime, timedelta
from openid.association import Association as OIDAssociation
# django.contrib.auth and mongoengine.django.auth regex to validate usernames
# '^[\w@.+-_]+$', we use the opposite to clean invalid characters
CLEAN_USERNAME_REGEX = re.compile(r'[^\w.@+-_]+', re.UNICODE)
class UserSocialAuthMixin(object):
user = ''
provider = ''
def __unicode__(self):
"""Return associated user unicode representation"""
return u'%s - %s' % (unicode(self.user), self.provider.title())
def get_backend(self):
# Make import here to avoid recursive imports :-/
from social_auth.backends import get_backends
return get_backends().get(self.provider)
@property
def tokens(self):
"""Return access_token stored in extra_data or None"""
backend = self.get_backend()
if backend:
return backend.AUTH_BACKEND.tokens(self)
else:
return {}
def refresh_token(self):
data = self.extra_data
if 'refresh_token' in data or 'access_token' in data:
backend = self.get_backend()
if hasattr(backend, 'refresh_token'):
token = data.get('refresh_token') or data.get('access_token')
response = backend.refresh_token(token)
self.extra_data.update(
backend.AUTH_BACKEND.extra_data(self.user, self.uid,
response)
)
self.save()
def expiration_datetime(self):
"""Return provider session live seconds. Returns a timedelta ready to
use with session.set_expiry().
If provider returns a timestamp instead of session seconds to live, the
timedelta is inferred from current time (using UTC timezone). None is
returned if there's no value stored or it's invalid.
"""
if self.extra_data and 'expires' in self.extra_data:
try:
expires = int(self.extra_data['expires'])
except (ValueError, TypeError):
return None
now = datetime.utcnow()
# Detect if expires is a timestamp
if expires > time.mktime(now.timetuple()):
# expires is a datetime
return datetime.fromtimestamp(expires) - now
else:
# expires is a timedelta
return timedelta(seconds=expires)
@classmethod
def user_model(cls):
raise NotImplementedError('Implement in subclass')
@classmethod
def username_max_length(cls):
raise NotImplementedError('Implement in subclass')
@classmethod
def email_max_length(cls):
raise NotImplementedError('Implement in subclass')
@classmethod
def clean_username(cls, value):
return CLEAN_USERNAME_REGEX.sub('', value)
@classmethod
def allowed_to_disconnect(cls, user, backend_name, association_id=None):
if association_id is not None:
qs = cls.objects.exclude(id=association_id)
else:
qs = cls.objects.exclude(provider=backend_name)
qs = qs.filter(user=user)
if hasattr(user, 'has_usable_password'):
valid_password = user.has_usable_password()
else:
valid_password = True
return valid_password or qs.count() > 0
@classmethod
def user_username(cls, user):
if hasattr(user, 'USERNAME_FIELD'):
# Django 1.5 custom user model, 'username' is just for internal
# use, doesn't imply that the model should have an username field
field_name = user.USERNAME_FIELD
else:
field_name = 'username'
return getattr(user, field_name)
@classmethod
def username_field(cls, values):
user_model = cls.user_model()
if hasattr(user_model, 'USERNAME_FIELD'):
# Django 1.5 custom user model, 'username' is just for internal
# use, doesn't imply that the model should have an username field
values[user_model.USERNAME_FIELD] = values.pop('username')
return values
@classmethod
def simple_user_exists(cls, *args, **kwargs):
"""
Return True/False if a User instance exists with the given arguments.
Arguments are directly passed to filter() manager method.
TODO: consider how to ensure case-insensitive email matching
"""
kwargs = cls.username_field(kwargs)
return cls.user_model().objects.filter(*args, **kwargs).count() > 0
@classmethod
def create_user(cls, *args, **kwargs):
kwargs = cls.username_field(kwargs)
return cls.user_model().objects.create_user(*args, **kwargs)
@classmethod
def get_user(cls, pk):
try:
return cls.user_model().objects.get(pk=pk)
except cls.user_model().DoesNotExist:
return None
@classmethod
def get_user_by_email(cls, email):
"Case insensitive search"
return cls.user_model().objects.get(email__iexact=email)
@classmethod
def resolve_user_or_id(cls, user_or_id):
if isinstance(user_or_id, cls.user_model()):
return user_or_id
return cls.user_model().objects.get(pk=user_or_id)
@classmethod
def get_social_auth(cls, provider, uid):
if not isinstance(uid, basestring):
uid = str(uid)
try:
return cls.objects.get(provider=provider, uid=uid)
except cls.DoesNotExist:
return None
@classmethod
def get_social_auth_for_user(cls, user):
return user.social_auth.all()
@classmethod
def create_social_auth(cls, user, uid, provider):
if not isinstance(uid, basestring):
uid = str(uid)
return cls.objects.create(user=user, uid=uid, provider=provider)
@classmethod
def store_association(cls, server_url, association):
from social_auth.models import Association
args = {'server_url': server_url, 'handle': association.handle}
try:
assoc = Association.objects.get(**args)
except Association.DoesNotExist:
assoc = Association(**args)
assoc.secret = base64.encodestring(association.secret)
assoc.issued = association.issued
assoc.lifetime = association.lifetime
assoc.assoc_type = association.assoc_type
assoc.save()
@classmethod
def remove_association(cls, server_url, handle):
from social_auth.models import Association
assocs = list(Association.objects.filter(
server_url=server_url, handle=handle))
assocs_exist = len(assocs) > 0
for assoc in assocs:
assoc.delete()
return assocs_exist
@classmethod
def get_oid_associations(cls, server_url, handle=None):
from social_auth.models import Association
args = {'server_url': server_url}
if handle is not None:
args['handle'] = handle
return sorted([
(assoc.id,
OIDAssociation(assoc.handle,
base64.decodestring(assoc.secret),
assoc.issued,
assoc.lifetime,
assoc.assoc_type))
for assoc in Association.objects.filter(**args)
], key=lambda x: x[1].issued, reverse=True)
@classmethod
def delete_associations(cls, ids_to_delete):
from social_auth.models import Association
Association.objects.filter(pk__in=ids_to_delete).delete()
@classmethod
def use_nonce(cls, server_url, timestamp, salt):
from social_auth.models import Nonce
return Nonce.objects.get_or_create(server_url=server_url,
timestamp=timestamp,
salt=salt)[1]
class NonceMixin(object):
"""One use numbers"""
server_url = ''
timestamp = 0
salt = ''
def __unicode__(self):
"""Unicode representation"""
return self.server_url
class AssociationMixin(object):
"""OpenId account association"""
server_url = ''
handle = ''
secret = ''
issued = 0
lifetime = 0
assoc_type = ''
def __unicode__(self):
"""Unicode representation"""
return '%s %s' % (self.handle, self.issued)
django-social-auth-0.7.23/social_auth/fields.py 0000644 0001750 0001750 00000003574 12127316474 021265 0 ustar omab omab 0000000 0000000 from django.core.exceptions import ValidationError
from django.db import models
from django.utils import simplejson
from django.utils.encoding import smart_unicode
class JSONField(models.TextField):
"""Simple JSON field that stores python structures as JSON strings
on database.
"""
__metaclass__ = models.SubfieldBase
def to_python(self, value):
"""
Convert the input JSON value into python structures, raises
django.core.exceptions.ValidationError if the data can't be converted.
"""
if self.blank and not value:
return None
if isinstance(value, basestring):
try:
return simplejson.loads(value)
except Exception, e:
raise ValidationError(str(e))
else:
return value
def validate(self, value, model_instance):
"""Check value is a valid JSON string, raise ValidationError on
error."""
if isinstance(value, basestring):
super(JSONField, self).validate(value, model_instance)
try:
simplejson.loads(value)
except Exception, e:
raise ValidationError(str(e))
def get_prep_value(self, value):
"""Convert value to JSON string before save"""
try:
return simplejson.dumps(value)
except Exception, e:
raise ValidationError(str(e))
def value_to_string(self, obj):
"""Return value from object converted to string properly"""
return smart_unicode(self.get_prep_value(self._get_val_from_obj(obj)))
def value_from_object(self, obj):
"""Return value dumped to string."""
return self.get_prep_value(self._get_val_from_obj(obj))
try:
from south.modelsinspector import add_introspection_rules
add_introspection_rules([], ["^social_auth\.fields\.JSONField"])
except:
pass
django-social-auth-0.7.23/social_auth/admin.py 0000644 0001750 0001750 00000002215 12127316474 021076 0 ustar omab omab 0000000 0000000 """Admin settings"""
from social_auth.utils import setting
if setting('SOCIAL_AUTH_MODELS') in (None, 'social_auth.db.django_models'):
from django.contrib import admin
from social_auth.models import UserSocialAuth, Nonce, Association
class UserSocialAuthOption(admin.ModelAdmin):
"""Social Auth user options"""
list_display = ('id', 'user', 'provider', 'uid')
search_fields = ('user__first_name', 'user__last_name', 'user__email',
'user__username')
list_filter = ('provider',)
raw_id_fields = ('user',)
list_select_related = True
class NonceOption(admin.ModelAdmin):
"""Nonce options"""
list_display = ('id', 'server_url', 'timestamp', 'salt')
search_fields = ('server_url',)
class AssociationOption(admin.ModelAdmin):
"""Association options"""
list_display = ('id', 'server_url', 'assoc_type')
list_filter = ('assoc_type',)
search_fields = ('server_url',)
admin.site.register(UserSocialAuth, UserSocialAuthOption)
admin.site.register(Nonce, NonceOption)
admin.site.register(Association, AssociationOption)
django-social-auth-0.7.23/social_auth/urls.py 0000644 0001750 0001750 00000002166 12127316474 021000 0 ustar omab omab 0000000 0000000 """URLs module"""
try:
from django.conf.urls import patterns, url
except ImportError:
# for Django version less then 1.4
from django.conf.urls.defaults import patterns, url
from social_auth.views import auth, complete, disconnect
urlpatterns = patterns('',
# authentication
url(r'^login/(?P[^/]+)/$', auth,
name='socialauth_begin'),
url(r'^complete/(?P[^/]+)/$', complete,
name='socialauth_complete'),
# XXX: Deprecated, this URLs are deprecated, instead use the login and
# complete ones directly, they will differentiate the user intention
# by checking it's authenticated status association.
url(r'^associate/(?P[^/]+)/$', auth,
name='socialauth_associate_begin'),
url(r'^associate/complete/(?P[^/]+)/$', complete,
name='socialauth_associate_complete'),
# disconnection
url(r'^disconnect/(?P[^/]+)/$', disconnect,
name='socialauth_disconnect'),
url(r'^disconnect/(?P[^/]+)/(?P[^/]+)/$',
disconnect, name='socialauth_disconnect_individual'),
)
django-social-auth-0.7.23/social_auth/locale/ 0000755 0001750 0001750 00000000000 12135257233 020667 5 ustar omab omab 0000000 0000000 django-social-auth-0.7.23/social_auth/locale/ru/ 0000755 0001750 0001750 00000000000 12135257233 021315 5 ustar omab omab 0000000 0000000 django-social-auth-0.7.23/social_auth/locale/ru/LC_MESSAGES/ 0000755 0001750 0001750 00000000000 12135257233 023102 5 ustar omab omab 0000000 0000000 django-social-auth-0.7.23/social_auth/locale/ru/LC_MESSAGES/django.po 0000644 0001750 0001750 00000002551 12127316474 024713 0 ustar omab omab 0000000 0000000 # SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR , YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2012-02-17 15:25+0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME \n"
"Language-Team: LANGUAGE \n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)\n"
#: views.py:71
msgid "Unknown authentication error. Try again later."
msgstr "Непредвиденная ошибка авторизации. Попробуйте позже."
#: backends/__init__.py:635 backends/__init__.py:656
msgid "Authentication process was cancelled"
msgstr "Процесс авторизации был прерван"
#: backends/__init__.py:637 backends/__init__.py:658
#, python-format
msgid "Authentication failed: %s"
msgstr "Ошибка авторизации: %s"
#: backends/pipeline/social.py:25
#, python-format
msgid "This %(provider)s account already in use."
msgstr "Этот аккаунт %(provider)s уже используется."
django-social-auth-0.7.23/social_auth/locale/ru/LC_MESSAGES/django.mo 0000644 0001750 0001750 00000001743 12127316474 024712 0 ustar omab omab 0000000 0000000 D l $ ) . ! ' ; E : b Authentication failed: %s Authentication process was cancelled This %(provider)s account already in use. Unknown authentication error. Try again later. Project-Id-Version: PACKAGE VERSION
Report-Msgid-Bugs-To:
POT-Creation-Date: 2012-02-17 15:25+0400
PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE
Last-Translator: FULL NAME
Language-Team: LANGUAGE
Language:
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)
Ошибка авторизации: %s Процесс авторизации был прерван Этот аккаунт %(provider)s уже используется. Непредвиденная ошибка авторизации. Попробуйте позже. django-social-auth-0.7.23/social_auth/locale/tr/ 0000755 0001750 0001750 00000000000 12135257233 021314 5 ustar omab omab 0000000 0000000 django-social-auth-0.7.23/social_auth/locale/tr/LC_MESSAGES/ 0000755 0001750 0001750 00000000000 12135257233 023101 5 ustar omab omab 0000000 0000000 django-social-auth-0.7.23/social_auth/locale/tr/LC_MESSAGES/django.po 0000644 0001750 0001750 00000001767 12127316474 024722 0 ustar omab omab 0000000 0000000 # SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR , YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2012-05-15 18:58+0300\n"
"PO-Revision-Date: 2012-05-15 22:02+0200\n"
"Last-Translator: Cihan Okyay \n"
"Language-Team: LANGUAGE \n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0\n"
#: backends/exceptions.py:29
msgid "Authentication process was cancelled"
msgstr "Kimlik denetimi işlemi kapatıldı"
#: backends/exceptions.py:31
#, python-format
msgid "Authentication failed: %s"
msgstr "Kimlik denetimi başarısız: %s"
#: backends/pipeline/social.py:25
#, python-format
msgid "This %(provider)s account already in use."
msgstr "Bu %(provider)s hesabı kullanımda."
django-social-auth-0.7.23/social_auth/locale/tr/LC_MESSAGES/django.mo 0000644 0001750 0001750 00000001265 12127316474 024710 0 ustar omab omab 0000000 0000000 <