Revision 971ca324
b/djnro/settings.py | ||
---|---|---|
170 | 170 |
'registration', |
171 | 171 |
'tinymce', |
172 | 172 |
'utils', |
173 |
'oauthlib', |
|
173 | 174 |
) |
174 | 175 |
|
175 | 176 |
# A sample logging configuration. The only tangible logging |
... | ... | |
255 | 256 |
('industry', 'industry')] |
256 | 257 |
|
257 | 258 |
|
258 |
SOCIAL_AUTH_PIPELINE = ( |
|
259 |
'social_auth.backends.pipeline.social.social_auth_user', |
|
260 |
'social_auth.backends.pipeline.user.get_username', |
|
261 |
'social_auth.backends.pipeline.user.create_user', |
|
262 |
'social_auth.backends.pipeline.social.associate_user', |
|
263 |
'social_auth.backends.pipeline.social.load_extra_data', |
|
264 |
'social_auth.backends.pipeline.user.update_user_details', |
|
265 |
) |
|
266 |
|
|
267 | 259 |
CAT_INSTANCES = () |
268 | 260 |
|
269 | 261 |
import _version |
b/requirements.txt | ||
---|---|---|
14 | 14 |
requests-oauthlib==0.4.2 |
15 | 15 |
six==1.8.0 |
16 | 16 |
wsgiref==0.1.2 |
17 |
python-social-auth==0.2.1 |
/dev/null | ||
---|---|---|
1 |
""" |
|
2 |
python-social-auth application, allows OpenId or OAuth user |
|
3 |
registration/authentication just adding a few configurations. |
|
4 |
""" |
|
5 |
version = (0, 2, 1) |
|
6 |
extra = '' |
|
7 |
__version__ = '.'.join(map(str, version)) + extra |
/dev/null | ||
---|---|---|
1 |
from social.p3 import quote |
|
2 |
from social.utils import sanitize_redirect, user_is_authenticated, \ |
|
3 |
user_is_active, partial_pipeline_data, setting_url |
|
4 |
|
|
5 |
|
|
6 |
def do_auth(backend, redirect_name='next'): |
|
7 |
# Save any defined next value into session |
|
8 |
data = backend.strategy.request_data(merge=False) |
|
9 |
|
|
10 |
# Save extra data into session. |
|
11 |
for field_name in backend.setting('FIELDS_STORED_IN_SESSION', []): |
|
12 |
if field_name in data: |
|
13 |
backend.strategy.session_set(field_name, data[field_name]) |
|
14 |
|
|
15 |
if redirect_name in data: |
|
16 |
# Check and sanitize a user-defined GET/POST next field value |
|
17 |
redirect_uri = data[redirect_name] |
|
18 |
if backend.setting('SANITIZE_REDIRECTS', True): |
|
19 |
redirect_uri = sanitize_redirect(backend.strategy.request_host(), |
|
20 |
redirect_uri) |
|
21 |
backend.strategy.session_set( |
|
22 |
redirect_name, |
|
23 |
redirect_uri or backend.setting('LOGIN_REDIRECT_URL') |
|
24 |
) |
|
25 |
return backend.start() |
|
26 |
|
|
27 |
|
|
28 |
def do_complete(backend, login, user=None, redirect_name='next', |
|
29 |
*args, **kwargs): |
|
30 |
# pop redirect value before the session is trashed on login() |
|
31 |
data = backend.strategy.request_data() |
|
32 |
redirect_value = backend.strategy.session_get(redirect_name, '') or \ |
|
33 |
data.get(redirect_name, '') |
|
34 |
|
|
35 |
is_authenticated = user_is_authenticated(user) |
|
36 |
user = is_authenticated and user or None |
|
37 |
|
|
38 |
partial = partial_pipeline_data(backend, user, *args, **kwargs) |
|
39 |
if partial: |
|
40 |
xargs, xkwargs = partial |
|
41 |
user = backend.continue_pipeline(*xargs, **xkwargs) |
|
42 |
else: |
|
43 |
user = backend.complete(user=user, *args, **kwargs) |
|
44 |
|
|
45 |
user_model = backend.strategy.storage.user.user_model() |
|
46 |
if user and not isinstance(user, user_model): |
|
47 |
return user |
|
48 |
|
|
49 |
if is_authenticated: |
|
50 |
if not user: |
|
51 |
url = setting_url(backend, redirect_value, 'LOGIN_REDIRECT_URL') |
|
52 |
else: |
|
53 |
url = setting_url(backend, redirect_value, |
|
54 |
'NEW_ASSOCIATION_REDIRECT_URL', |
|
55 |
'LOGIN_REDIRECT_URL') |
|
56 |
elif user: |
|
57 |
if user_is_active(user): |
|
58 |
# catch is_new/social_user in case login() resets the instance |
|
59 |
is_new = getattr(user, 'is_new', False) |
|
60 |
social_user = user.social_user |
|
61 |
login(backend, user, social_user) |
|
62 |
# store last login backend name in session |
|
63 |
backend.strategy.session_set('social_auth_last_login_backend', |
|
64 |
social_user.provider) |
|
65 |
|
|
66 |
if is_new: |
|
67 |
url = setting_url(backend, |
|
68 |
'NEW_USER_REDIRECT_URL', |
|
69 |
redirect_value, |
|
70 |
'LOGIN_REDIRECT_URL') |
|
71 |
else: |
|
72 |
url = setting_url(backend, redirect_value, |
|
73 |
'LOGIN_REDIRECT_URL') |
|
74 |
else: |
|
75 |
url = setting_url(backend, 'INACTIVE_USER_URL', 'LOGIN_ERROR_URL', |
|
76 |
'LOGIN_URL') |
|
77 |
else: |
|
78 |
url = setting_url(backend, 'LOGIN_ERROR_URL', 'LOGIN_URL') |
|
79 |
|
|
80 |
if redirect_value and redirect_value != url: |
|
81 |
redirect_value = quote(redirect_value) |
|
82 |
url += ('?' in url and '&' or '?') + \ |
|
83 |
'{0}={1}'.format(redirect_name, redirect_value) |
|
84 |
|
|
85 |
if backend.setting('SANITIZE_REDIRECTS', True): |
|
86 |
url = sanitize_redirect(backend.strategy.request_host(), url) or \ |
|
87 |
backend.setting('LOGIN_REDIRECT_URL') |
|
88 |
return backend.strategy.redirect(url) |
|
89 |
|
|
90 |
|
|
91 |
def do_disconnect(backend, user, association_id=None, redirect_name='next', |
|
92 |
*args, **kwargs): |
|
93 |
partial = partial_pipeline_data(backend, user, *args, **kwargs) |
|
94 |
if partial: |
|
95 |
xargs, xkwargs = partial |
|
96 |
if association_id and not xkwargs.get('association_id'): |
|
97 |
xkwargs['association_id'] = association_id |
|
98 |
response = backend.disconnect(*xargs, **xkwargs) |
|
99 |
else: |
|
100 |
response = backend.disconnect(user=user, association_id=association_id, |
|
101 |
*args, **kwargs) |
|
102 |
|
|
103 |
if isinstance(response, dict): |
|
104 |
response = backend.strategy.redirect( |
|
105 |
backend.strategy.request_data().get(redirect_name, '') or |
|
106 |
backend.setting('DISCONNECT_REDIRECT_URL') or |
|
107 |
backend.setting('LOGIN_REDIRECT_URL') |
|
108 |
) |
|
109 |
return response |
/dev/null | ||
---|---|---|
1 |
"""Flask SQLAlchemy ORM models for Social Auth""" |
|
2 |
import cherrypy |
|
3 |
|
|
4 |
from sqlalchemy import Column, Integer, String, ForeignKey |
|
5 |
from sqlalchemy.orm import relationship |
|
6 |
from sqlalchemy.ext.declarative import declarative_base |
|
7 |
|
|
8 |
from social.utils import setting_name, module_member |
|
9 |
from social.storage.sqlalchemy_orm import SQLAlchemyUserMixin, \ |
|
10 |
SQLAlchemyAssociationMixin, \ |
|
11 |
SQLAlchemyNonceMixin, \ |
|
12 |
BaseSQLAlchemyStorage |
|
13 |
|
|
14 |
|
|
15 |
SocialBase = declarative_base() |
|
16 |
|
|
17 |
DB_SESSION_ATTR = cherrypy.config.get(setting_name('DB_SESSION_ATTR'), 'db') |
|
18 |
UID_LENGTH = cherrypy.config.get(setting_name('UID_LENGTH'), 255) |
|
19 |
User = module_member(cherrypy.config[setting_name('USER_MODEL')]) |
|
20 |
|
|
21 |
|
|
22 |
class CherryPySocialBase(object): |
|
23 |
@classmethod |
|
24 |
def _session(cls): |
|
25 |
return getattr(cherrypy.request, DB_SESSION_ATTR) |
|
26 |
|
|
27 |
|
|
28 |
class UserSocialAuth(CherryPySocialBase, SQLAlchemyUserMixin, SocialBase): |
|
29 |
"""Social Auth association model""" |
|
30 |
uid = Column(String(UID_LENGTH)) |
|
31 |
user_id = Column(Integer, ForeignKey(User.id), |
|
32 |
nullable=False, index=True) |
|
33 |
user = relationship(User, backref='social_auth') |
|
34 |
|
|
35 |
@classmethod |
|
36 |
def username_max_length(cls): |
|
37 |
return User.__table__.columns.get('username').type.length |
|
38 |
|
|
39 |
@classmethod |
|
40 |
def user_model(cls): |
|
41 |
return User |
|
42 |
|
|
43 |
|
|
44 |
class Nonce(CherryPySocialBase, SQLAlchemyNonceMixin, SocialBase): |
|
45 |
"""One use numbers""" |
|
46 |
pass |
|
47 |
|
|
48 |
|
|
49 |
class Association(CherryPySocialBase, SQLAlchemyAssociationMixin, SocialBase): |
|
50 |
"""OpenId account association""" |
|
51 |
pass |
|
52 |
|
|
53 |
|
|
54 |
class CherryPyStorage(BaseSQLAlchemyStorage): |
|
55 |
user = UserSocialAuth |
|
56 |
nonce = Nonce |
|
57 |
association = Association |
/dev/null | ||
---|---|---|
1 |
import warnings |
|
2 |
from functools import wraps |
|
3 |
|
|
4 |
import cherrypy |
|
5 |
|
|
6 |
from social.utils import setting_name, module_member |
|
7 |
from social.strategies.utils import get_strategy |
|
8 |
from social.backends.utils import get_backend, user_backends_data |
|
9 |
|
|
10 |
|
|
11 |
DEFAULTS = { |
|
12 |
'STRATEGY': 'social.strategies.cherrypy_strategy.CherryPyStrategy', |
|
13 |
'STORAGE': 'social.apps.cherrypy_app.models.CherryPyStorage' |
|
14 |
} |
|
15 |
|
|
16 |
|
|
17 |
def get_helper(name): |
|
18 |
return cherrypy.config.get(setting_name(name), DEFAULTS.get(name, None)) |
|
19 |
|
|
20 |
|
|
21 |
def load_backend(strategy, name, redirect_uri): |
|
22 |
backends = get_helper('AUTHENTICATION_BACKENDS') |
|
23 |
Backend = get_backend(backends, name) |
|
24 |
return Backend(strategy=strategy, redirect_uri=redirect_uri) |
|
25 |
|
|
26 |
|
|
27 |
def psa(redirect_uri=None): |
|
28 |
def decorator(func): |
|
29 |
@wraps(func) |
|
30 |
def wrapper(self, backend=None, *args, **kwargs): |
|
31 |
uri = redirect_uri |
|
32 |
if uri and backend and '%(backend)s' in uri: |
|
33 |
uri = uri % {'backend': backend} |
|
34 |
self.strategy = get_strategy(get_helper('STRATEGY'), |
|
35 |
get_helper('STORAGE')) |
|
36 |
self.backend = load_backend(self.strategy, backend, uri) |
|
37 |
return func(self, backend, *args, **kwargs) |
|
38 |
return wrapper |
|
39 |
return decorator |
|
40 |
|
|
41 |
|
|
42 |
def backends(user): |
|
43 |
"""Load Social Auth current user data to context under the key 'backends'. |
|
44 |
Will return the output of social.backends.utils.user_backends_data.""" |
|
45 |
return user_backends_data(user, get_helper('AUTHENTICATION_BACKENDS'), |
|
46 |
module_member(get_helper('STORAGE'))) |
|
47 |
|
|
48 |
|
|
49 |
def strategy(*args, **kwargs): |
|
50 |
warnings.warn('@strategy decorator is deprecated, use @psa instead') |
|
51 |
return psa(*args, **kwargs) |
/dev/null | ||
---|---|---|
1 |
import cherrypy |
|
2 |
|
|
3 |
from social.utils import setting_name, module_member |
|
4 |
from social.actions import do_auth, do_complete, do_disconnect |
|
5 |
from social.apps.cherrypy_app.utils import psa |
|
6 |
|
|
7 |
|
|
8 |
class CherryPyPSAViews(object): |
|
9 |
@cherrypy.expose |
|
10 |
@psa('/complete/%(backend)s') |
|
11 |
def login(self, backend): |
|
12 |
return do_auth(self.backend) |
|
13 |
|
|
14 |
@cherrypy.expose |
|
15 |
@psa('/complete/%(backend)s') |
|
16 |
def complete(self, backend, *args, **kwargs): |
|
17 |
login = cherrypy.config.get(setting_name('LOGIN_METHOD')) |
|
18 |
do_login = module_member(login) if login else self.do_login |
|
19 |
user = getattr(cherrypy.request, 'user', None) |
|
20 |
return do_complete(self.backend, do_login, user=user, *args, **kwargs) |
|
21 |
|
|
22 |
@cherrypy.expose |
|
23 |
@psa() |
|
24 |
def disconnect(self, backend, association_id=None): |
|
25 |
user = getattr(cherrypy.request, 'user', None) |
|
26 |
return do_disconnect(self.backend, user, association_id) |
|
27 |
|
|
28 |
def do_login(self, backend, user, social_user): |
|
29 |
backend.strategy.session_set('user_id', user.id) |
/dev/null | ||
---|---|---|
1 |
""" |
|
2 |
Django framework support. |
|
3 |
|
|
4 |
To use this: |
|
5 |
* Add 'social.apps.django_app.default' if using default ORM, |
|
6 |
or 'social.apps.django_app.me' if using mongoengine |
|
7 |
* Add url('', include('social.apps.django_app.urls', namespace='social')) to |
|
8 |
urls.py |
|
9 |
* Define SOCIAL_AUTH_STORAGE and SOCIAL_AUTH_STRATEGY, default values: |
|
10 |
SOCIAL_AUTH_STRATEGY = 'social.strategies.django_strategy.DjangoStrategy' |
|
11 |
SOCIAL_AUTH_STORAGE = 'social.apps.django_app.default.models.DjangoStorage' |
|
12 |
""" |
|
13 |
from social.strategies.utils import set_current_strategy_getter |
|
14 |
from social.apps.django_app.utils import load_strategy |
|
15 |
|
|
16 |
|
|
17 |
# Set strategy loader method to workaround current strategy getter needed on |
|
18 |
# get_user() method on authentication backends when working with Django |
|
19 |
set_current_strategy_getter(load_strategy) |
/dev/null | ||
---|---|---|
1 |
from django.contrib.auth import REDIRECT_FIELD_NAME |
|
2 |
from django.utils.functional import SimpleLazyObject |
|
3 |
|
|
4 |
try: |
|
5 |
from django.utils.functional import empty as _empty |
|
6 |
empty = _empty |
|
7 |
except ImportError: # django < 1.4 |
|
8 |
empty = None |
|
9 |
|
|
10 |
|
|
11 |
from social.backends.utils import user_backends_data |
|
12 |
from social.apps.django_app.utils import Storage, BACKENDS |
|
13 |
|
|
14 |
|
|
15 |
class LazyDict(SimpleLazyObject): |
|
16 |
"""Lazy dict initialization.""" |
|
17 |
def __getitem__(self, name): |
|
18 |
if self._wrapped is empty: |
|
19 |
self._setup() |
|
20 |
return self._wrapped[name] |
|
21 |
|
|
22 |
def __setitem__(self, name, value): |
|
23 |
if self._wrapped is empty: |
|
24 |
self._setup() |
|
25 |
self._wrapped[name] = value |
|
26 |
|
|
27 |
|
|
28 |
def backends(request): |
|
29 |
"""Load Social Auth current user data to context under the key 'backends'. |
|
30 |
Will return the output of social.backends.utils.user_backends_data.""" |
|
31 |
return {'backends': LazyDict(lambda: user_backends_data(request.user, |
|
32 |
BACKENDS, |
|
33 |
Storage))} |
|
34 |
|
|
35 |
|
|
36 |
def login_redirect(request): |
|
37 |
"""Load current redirect to context.""" |
|
38 |
value = request.method == 'POST' and \ |
|
39 |
request.POST.get(REDIRECT_FIELD_NAME) or \ |
|
40 |
request.GET.get(REDIRECT_FIELD_NAME) |
|
41 |
querystring = value and (REDIRECT_FIELD_NAME + '=' + value) or '' |
|
42 |
return { |
|
43 |
'REDIRECT_FIELD_NAME': REDIRECT_FIELD_NAME, |
|
44 |
'REDIRECT_FIELD_VALUE': value, |
|
45 |
'REDIRECT_QUERYSTRING': querystring |
|
46 |
} |
/dev/null | ||
---|---|---|
1 |
""" |
|
2 |
Django default ORM backend support. |
|
3 |
|
|
4 |
To enable this app: |
|
5 |
* Add 'social.apps.django_app.default' to INSTALLED_APPS |
|
6 |
* In urls.py include url('', include('social.apps.django_app.urls')) |
|
7 |
""" |
/dev/null | ||
---|---|---|
1 |
"""Admin settings""" |
|
2 |
from django.conf import settings |
|
3 |
from django.contrib import admin |
|
4 |
|
|
5 |
from social.utils import setting_name |
|
6 |
from social.apps.django_app.default.models import UserSocialAuth, Nonce, \ |
|
7 |
Association |
|
8 |
|
|
9 |
|
|
10 |
class UserSocialAuthOption(admin.ModelAdmin): |
|
11 |
"""Social Auth user options""" |
|
12 |
list_display = ('id', 'user', 'provider', 'uid') |
|
13 |
list_filter = ('provider',) |
|
14 |
raw_id_fields = ('user',) |
|
15 |
list_select_related = True |
|
16 |
|
|
17 |
def get_search_fields(self, request=None): |
|
18 |
search_fields = getattr( |
|
19 |
settings, setting_name('ADMIN_USER_SEARCH_FIELDS'), None |
|
20 |
) |
|
21 |
if search_fields is None: |
|
22 |
_User = UserSocialAuth.user_model() |
|
23 |
username = getattr(_User, 'USERNAME_FIELD', None) or \ |
|
24 |
hasattr(_User, 'username') and 'username' or \ |
|
25 |
None |
|
26 |
fieldnames = ('first_name', 'last_name', 'email', username) |
|
27 |
all_names = _User._meta.get_all_field_names() |
|
28 |
search_fields = [name for name in fieldnames |
|
29 |
if name and name in all_names] |
|
30 |
return ['user__' + name for name in search_fields] |
|
31 |
|
|
32 |
|
|
33 |
class NonceOption(admin.ModelAdmin): |
|
34 |
"""Nonce options""" |
|
35 |
list_display = ('id', 'server_url', 'timestamp', 'salt') |
|
36 |
search_fields = ('server_url',) |
|
37 |
|
|
38 |
|
|
39 |
class AssociationOption(admin.ModelAdmin): |
|
40 |
"""Association options""" |
|
41 |
list_display = ('id', 'server_url', 'assoc_type') |
|
42 |
list_filter = ('assoc_type',) |
|
43 |
search_fields = ('server_url',) |
|
44 |
|
|
45 |
|
|
46 |
admin.site.register(UserSocialAuth, UserSocialAuthOption) |
|
47 |
admin.site.register(Nonce, NonceOption) |
|
48 |
admin.site.register(Association, AssociationOption) |
/dev/null | ||
---|---|---|
1 |
import json |
|
2 |
import six |
|
3 |
|
|
4 |
from django.core.exceptions import ValidationError |
|
5 |
from django.db import models |
|
6 |
|
|
7 |
try: |
|
8 |
from django.utils.encoding import smart_unicode as smart_text |
|
9 |
smart_text # placate pyflakes |
|
10 |
except ImportError: |
|
11 |
from django.utils.encoding import smart_text |
|
12 |
|
|
13 |
|
|
14 |
class JSONField(six.with_metaclass(models.SubfieldBase, models.TextField)): |
|
15 |
"""Simple JSON field that stores python structures as JSON strings |
|
16 |
on database. |
|
17 |
""" |
|
18 |
|
|
19 |
def __init__(self, *args, **kwargs): |
|
20 |
kwargs.setdefault('default', '{}') |
|
21 |
super(JSONField, self).__init__(*args, **kwargs) |
|
22 |
|
|
23 |
def to_python(self, value): |
|
24 |
""" |
|
25 |
Convert the input JSON value into python structures, raises |
|
26 |
django.core.exceptions.ValidationError if the data can't be converted. |
|
27 |
""" |
|
28 |
if self.blank and not value: |
|
29 |
return {} |
|
30 |
value = value or '{}' |
|
31 |
if isinstance(value, six.binary_type): |
|
32 |
value = six.text_type(value, 'utf-8') |
|
33 |
if isinstance(value, six.string_types): |
|
34 |
try: |
|
35 |
# with django 1.6 i have '"{}"' as default value here |
|
36 |
if value[0] == value[-1] == '"': |
|
37 |
value = value[1:-1] |
|
38 |
|
|
39 |
return json.loads(value) |
|
40 |
except Exception as err: |
|
41 |
raise ValidationError(str(err)) |
|
42 |
else: |
|
43 |
return value |
|
44 |
|
|
45 |
def validate(self, value, model_instance): |
|
46 |
"""Check value is a valid JSON string, raise ValidationError on |
|
47 |
error.""" |
|
48 |
if isinstance(value, six.string_types): |
|
49 |
super(JSONField, self).validate(value, model_instance) |
|
50 |
try: |
|
51 |
json.loads(value) |
|
52 |
except Exception as err: |
|
53 |
raise ValidationError(str(err)) |
|
54 |
|
|
55 |
def get_prep_value(self, value): |
|
56 |
"""Convert value to JSON string before save""" |
|
57 |
try: |
|
58 |
return json.dumps(value) |
|
59 |
except Exception as err: |
|
60 |
raise ValidationError(str(err)) |
|
61 |
|
|
62 |
def value_to_string(self, obj): |
|
63 |
"""Return value from object converted to string properly""" |
|
64 |
return smart_text(self.get_prep_value(self._get_val_from_obj(obj))) |
|
65 |
|
|
66 |
def value_from_object(self, obj): |
|
67 |
"""Return value dumped to string.""" |
|
68 |
return self.get_prep_value(self._get_val_from_obj(obj)) |
|
69 |
|
|
70 |
|
|
71 |
try: |
|
72 |
from south.modelsinspector import add_introspection_rules |
|
73 |
add_introspection_rules( |
|
74 |
[], |
|
75 |
["^social\.apps\.django_app\.default\.fields\.JSONField"] |
|
76 |
) |
|
77 |
except: |
|
78 |
pass |
/dev/null | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from __future__ import unicode_literals |
|
3 |
|
|
4 |
from django.db import models, migrations |
|
5 |
from django.conf import settings |
|
6 |
|
|
7 |
import social.storage.django_orm |
|
8 |
import social.apps.django_app.default.fields |
|
9 |
|
|
10 |
|
|
11 |
class Migration(migrations.Migration): |
|
12 |
dependencies = [ |
|
13 |
migrations.swappable_dependency(settings.AUTH_USER_MODEL), |
|
14 |
] |
|
15 |
|
|
16 |
operations = [ |
|
17 |
migrations.CreateModel( |
|
18 |
name='Association', |
|
19 |
fields=[ |
|
20 |
('id', models.AutoField(serialize=False, primary_key=True, |
|
21 |
auto_created=True, verbose_name='ID')), |
|
22 |
('server_url', models.CharField(max_length=255)), |
|
23 |
('handle', models.CharField(max_length=255)), |
|
24 |
('secret', models.CharField(max_length=255)), |
|
25 |
('issued', models.IntegerField()), |
|
26 |
('lifetime', models.IntegerField()), |
|
27 |
('assoc_type', models.CharField(max_length=64)), |
|
28 |
], |
|
29 |
options={ |
|
30 |
'db_table': 'social_auth_association', |
|
31 |
}, |
|
32 |
bases=( |
|
33 |
models.Model, |
|
34 |
social.storage.django_orm.DjangoAssociationMixin |
|
35 |
), |
|
36 |
), |
|
37 |
migrations.CreateModel( |
|
38 |
name='Code', |
|
39 |
fields=[ |
|
40 |
('id', models.AutoField(serialize=False, primary_key=True, |
|
41 |
auto_created=True, verbose_name='ID')), |
|
42 |
('email', models.EmailField(max_length=75)), |
|
43 |
('code', models.CharField(db_index=True, max_length=32)), |
|
44 |
('verified', models.BooleanField(default=False)), |
|
45 |
], |
|
46 |
options={ |
|
47 |
'db_table': 'social_auth_code', |
|
48 |
}, |
|
49 |
bases=(models.Model, social.storage.django_orm.DjangoCodeMixin), |
|
50 |
), |
|
51 |
migrations.AlterUniqueTogether( |
|
52 |
name='code', |
|
53 |
unique_together=set([('email', 'code')]), |
|
54 |
), |
|
55 |
migrations.CreateModel( |
|
56 |
name='Nonce', |
|
57 |
fields=[ |
|
58 |
('id', models.AutoField(serialize=False, primary_key=True, |
|
59 |
auto_created=True, verbose_name='ID')), |
|
60 |
('server_url', models.CharField(max_length=255)), |
|
61 |
('timestamp', models.IntegerField()), |
|
62 |
('salt', models.CharField(max_length=65)), |
|
63 |
], |
|
64 |
options={ |
|
65 |
'db_table': 'social_auth_nonce', |
|
66 |
}, |
|
67 |
bases=(models.Model, social.storage.django_orm.DjangoNonceMixin), |
|
68 |
), |
|
69 |
migrations.CreateModel( |
|
70 |
name='UserSocialAuth', |
|
71 |
fields=[ |
|
72 |
('id', models.AutoField(serialize=False, primary_key=True, |
|
73 |
auto_created=True, verbose_name='ID')), |
|
74 |
('provider', models.CharField(max_length=32)), |
|
75 |
('uid', models.CharField(max_length=255)), |
|
76 |
('extra_data', |
|
77 |
social.apps.django_app.default.fields.JSONField(default='{}') |
|
78 |
), |
|
79 |
('user', models.ForeignKey(to=settings.AUTH_USER_MODEL)), |
|
80 |
], |
|
81 |
options={ |
|
82 |
'db_table': 'social_auth_usersocialauth', |
|
83 |
}, |
|
84 |
bases=(models.Model, social.storage.django_orm.DjangoUserMixin), |
|
85 |
), |
|
86 |
migrations.AlterUniqueTogether( |
|
87 |
name='usersocialauth', |
|
88 |
unique_together=set([('provider', 'uid')]), |
|
89 |
), |
|
90 |
] |
/dev/null | ||
---|---|---|
1 |
"""Django ORM models for Social Auth""" |
|
2 |
import six |
|
3 |
|
|
4 |
from django.db import models |
|
5 |
from django.conf import settings |
|
6 |
from django.db.utils import IntegrityError |
|
7 |
|
|
8 |
from social.utils import setting_name |
|
9 |
from social.storage.django_orm import DjangoUserMixin, \ |
|
10 |
DjangoAssociationMixin, \ |
|
11 |
DjangoNonceMixin, \ |
|
12 |
DjangoCodeMixin, \ |
|
13 |
BaseDjangoStorage |
|
14 |
from social.apps.django_app.default.fields import JSONField |
|
15 |
|
|
16 |
|
|
17 |
USER_MODEL = getattr(settings, setting_name('USER_MODEL'), None) or \ |
|
18 |
getattr(settings, 'AUTH_USER_MODEL', None) or \ |
|
19 |
'auth.User' |
|
20 |
UID_LENGTH = getattr(settings, setting_name('UID_LENGTH'), 255) |
|
21 |
NONCE_SERVER_URL_LENGTH = getattr( |
|
22 |
settings, setting_name('NONCE_SERVER_URL_LENGTH'), 255) |
|
23 |
ASSOCIATION_SERVER_URL_LENGTH = getattr( |
|
24 |
settings, setting_name('ASSOCIATION_SERVER_URL_LENGTH'), 255) |
|
25 |
ASSOCIATION_HANDLE_LENGTH = getattr( |
|
26 |
settings, setting_name('ASSOCIATION_HANDLE_LENGTH'), 255) |
|
27 |
|
|
28 |
|
|
29 |
class UserSocialAuth(models.Model, DjangoUserMixin): |
|
30 |
"""Social Auth association model""" |
|
31 |
user = models.ForeignKey(USER_MODEL, related_name='social_auth') |
|
32 |
provider = models.CharField(max_length=32) |
|
33 |
uid = models.CharField(max_length=UID_LENGTH) |
|
34 |
extra_data = JSONField() |
|
35 |
|
|
36 |
class Meta: |
|
37 |
"""Meta data""" |
|
38 |
unique_together = ('provider', 'uid') |
|
39 |
db_table = 'social_auth_usersocialauth' |
|
40 |
|
|
41 |
@classmethod |
|
42 |
def get_social_auth(cls, provider, uid): |
|
43 |
try: |
|
44 |
return cls.objects.select_related('user').get(provider=provider, |
|
45 |
uid=uid) |
|
46 |
except UserSocialAuth.DoesNotExist: |
|
47 |
return None |
|
48 |
|
|
49 |
@classmethod |
|
50 |
def username_max_length(cls): |
|
51 |
username_field = cls.username_field() |
|
52 |
field = UserSocialAuth.user_model()._meta.get_field(username_field) |
|
53 |
return field.max_length |
|
54 |
|
|
55 |
@classmethod |
|
56 |
def user_model(cls): |
|
57 |
user_model = UserSocialAuth._meta.get_field('user').rel.to |
|
58 |
if isinstance(user_model, six.string_types): |
|
59 |
app_label, model_name = user_model.split('.') |
|
60 |
return models.get_model(app_label, model_name) |
|
61 |
return user_model |
|
62 |
|
|
63 |
|
|
64 |
class Nonce(models.Model, DjangoNonceMixin): |
|
65 |
"""One use numbers""" |
|
66 |
server_url = models.CharField(max_length=NONCE_SERVER_URL_LENGTH) |
|
67 |
timestamp = models.IntegerField() |
|
68 |
salt = models.CharField(max_length=65) |
|
69 |
|
|
70 |
class Meta: |
|
71 |
db_table = 'social_auth_nonce' |
|
72 |
|
|
73 |
|
|
74 |
class Association(models.Model, DjangoAssociationMixin): |
|
75 |
"""OpenId account association""" |
|
76 |
server_url = models.CharField(max_length=ASSOCIATION_SERVER_URL_LENGTH) |
|
77 |
handle = models.CharField(max_length=ASSOCIATION_HANDLE_LENGTH) |
|
78 |
secret = models.CharField(max_length=255) # Stored base64 encoded |
|
79 |
issued = models.IntegerField() |
|
80 |
lifetime = models.IntegerField() |
|
81 |
assoc_type = models.CharField(max_length=64) |
|
82 |
|
|
83 |
class Meta: |
|
84 |
db_table = 'social_auth_association' |
|
85 |
|
|
86 |
|
|
87 |
class Code(models.Model, DjangoCodeMixin): |
|
88 |
email = models.EmailField() |
|
89 |
code = models.CharField(max_length=32, db_index=True) |
|
90 |
verified = models.BooleanField(default=False) |
|
91 |
|
|
92 |
class Meta: |
|
93 |
db_table = 'social_auth_code' |
|
94 |
unique_together = ('email', 'code') |
|
95 |
|
|
96 |
|
|
97 |
class DjangoStorage(BaseDjangoStorage): |
|
98 |
user = UserSocialAuth |
|
99 |
nonce = Nonce |
|
100 |
association = Association |
|
101 |
code = Code |
|
102 |
|
|
103 |
@classmethod |
|
104 |
def is_integrity_error(cls, exception): |
|
105 |
return exception.__class__ is IntegrityError |
/dev/null | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
from south.db import db |
|
3 |
from south.v2 import SchemaMigration |
|
4 |
|
|
5 |
from . import get_custom_user_model_for_migrations, custom_user_frozen_models |
|
6 |
|
|
7 |
|
|
8 |
USER_MODEL = get_custom_user_model_for_migrations() |
|
9 |
|
|
10 |
|
|
11 |
class Migration(SchemaMigration): |
|
12 |
def forwards(self, orm): |
|
13 |
# Adding model 'UserSocialAuth' |
|
14 |
db.create_table('social_auth_usersocialauth', ( |
|
15 |
(u'id', self.gf('django.db.models.fields.AutoField')( |
|
16 |
primary_key=True)), |
|
17 |
('user', self.gf('django.db.models.fields.related.ForeignKey')( |
|
18 |
related_name='social_auth', to=orm[USER_MODEL])), |
|
19 |
('provider', self.gf('django.db.models.fields.CharField')( |
|
20 |
max_length=32)), |
|
21 |
('uid', self.gf('django.db.models.fields.CharField')( |
|
22 |
max_length=255)), |
|
23 |
('extra_data', self.gf( |
|
24 |
'social.apps.django_app.default.fields.JSONField' |
|
25 |
)(default='{}')), |
|
26 |
)) |
|
27 |
db.send_create_signal(u'default', ['UserSocialAuth']) |
|
28 |
|
|
29 |
# Adding unique constraint on 'UserSocialAuth', |
|
30 |
# fields ['provider', 'uid'] |
|
31 |
db.create_unique('social_auth_usersocialauth', ['provider', 'uid']) |
|
32 |
|
|
33 |
# Adding model 'Nonce' |
|
34 |
db.create_table('social_auth_nonce', ( |
|
35 |
(u'id', self.gf('django.db.models.fields.AutoField')( |
|
36 |
primary_key=True)), |
|
37 |
('server_url', self.gf('django.db.models.fields.CharField')( |
|
38 |
max_length=255)), |
|
39 |
('timestamp', self.gf('django.db.models.fields.IntegerField')()), |
|
40 |
('salt', self.gf('django.db.models.fields.CharField')( |
|
41 |
max_length=65)), |
|
42 |
)) |
|
43 |
db.send_create_signal(u'default', ['Nonce']) |
|
44 |
|
|
45 |
# Adding model 'Association' |
|
46 |
db.create_table('social_auth_association', ( |
|
47 |
(u'id', self.gf('django.db.models.fields.AutoField')( |
|
48 |
primary_key=True)), |
|
49 |
('server_url', self.gf('django.db.models.fields.CharField')( |
|
50 |
max_length=255)), |
|
51 |
('handle', self.gf('django.db.models.fields.CharField')( |
|
52 |
max_length=255)), |
|
53 |
('secret', self.gf('django.db.models.fields.CharField')( |
|
54 |
max_length=255)), |
|
55 |
('issued', self.gf('django.db.models.fields.IntegerField')()), |
|
56 |
('lifetime', self.gf('django.db.models.fields.IntegerField')()), |
|
57 |
('assoc_type', self.gf('django.db.models.fields.CharField')( |
|
58 |
max_length=64)), |
|
59 |
)) |
|
60 |
db.send_create_signal(u'default', ['Association']) |
|
61 |
|
|
62 |
# Adding model 'Code' |
|
63 |
db.create_table('social_auth_code', ( |
|
64 |
(u'id', self.gf('django.db.models.fields.AutoField')( |
|
65 |
primary_key=True)), |
|
66 |
('email', self.gf('django.db.models.fields.EmailField')( |
|
67 |
max_length=75)), |
|
68 |
('code', self.gf('django.db.models.fields.CharField')( |
|
69 |
max_length=32, |
|
70 |
db_index=True)), |
|
71 |
('verified', self.gf('django.db.models.fields.BooleanField')( |
|
72 |
default=False)), |
|
73 |
)) |
|
74 |
db.send_create_signal(u'default', ['Code']) |
|
75 |
|
|
76 |
# Adding unique constraint on 'Code', fields ['email', 'code'] |
|
77 |
db.create_unique('social_auth_code', ['email', 'code']) |
|
78 |
|
|
79 |
def backwards(self, orm): |
|
80 |
# Removing unique constraint on 'Code', fields ['email', 'code'] |
|
81 |
db.delete_unique('social_auth_code', ['email', 'code']) |
|
82 |
|
|
83 |
# Removing unique constraint on 'UserSocialAuth', |
|
84 |
# fields ['provider', 'uid'] |
|
85 |
db.delete_unique('social_auth_usersocialauth', ['provider', 'uid']) |
|
86 |
|
|
87 |
# Deleting model 'UserSocialAuth' |
|
88 |
db.delete_table('social_auth_usersocialauth') |
|
89 |
|
|
90 |
# Deleting model 'Nonce' |
|
91 |
db.delete_table('social_auth_nonce') |
|
92 |
|
|
93 |
# Deleting model 'Association' |
|
94 |
db.delete_table('social_auth_association') |
|
95 |
|
|
96 |
# Deleting model 'Code' |
|
97 |
db.delete_table('social_auth_code') |
|
98 |
|
|
99 |
models = { |
|
100 |
u'auth.group': { |
|
101 |
'Meta': {'object_name': 'Group'}, |
|
102 |
u'id': ('django.db.models.fields.AutoField', [], |
|
103 |
{'primary_key': 'True'}), |
|
104 |
'name': ('django.db.models.fields.CharField', [], |
|
105 |
{'unique': 'True', 'max_length': '80'}), |
|
106 |
'permissions': ('django.db.models.fields.related.ManyToManyField', |
|
107 |
[], {'to': u"orm['auth.Permission']", |
|
108 |
'symmetrical': 'False', 'blank': 'True'}) |
|
109 |
}, |
|
110 |
u'auth.permission': { |
|
111 |
'Meta': { |
|
112 |
'ordering': |
|
113 |
"(u'content_type__app_label', " |
|
114 |
"u'content_type__model', u'codename')", |
|
115 |
'unique_together': "((u'content_type', u'codename'),)", |
|
116 |
'object_name': 'Permission' |
|
117 |
}, |
|
118 |
'codename': ('django.db.models.fields.CharField', [], |
|
119 |
{'max_length': '100'}), |
|
120 |
'content_type': ('django.db.models.fields.related.ForeignKey', [], |
|
121 |
{'to': u"orm['contenttypes.ContentType']"}), |
|
122 |
u'id': ('django.db.models.fields.AutoField', [], |
|
123 |
{'primary_key': 'True'}), |
|
124 |
'name': ('django.db.models.fields.CharField', [], |
|
125 |
{'max_length': '50'}) |
|
126 |
}, |
|
127 |
u'auth.user': { |
|
128 |
'Meta': {'object_name': 'User'}, |
|
129 |
'date_joined': ('django.db.models.fields.DateTimeField', [], |
|
130 |
{'default': 'datetime.datetime.now'}), |
|
131 |
'email': ('django.db.models.fields.EmailField', [], |
|
132 |
{'max_length': '75', 'blank': 'True'}), |
|
133 |
'first_name': ('django.db.models.fields.CharField', [], |
|
134 |
{'max_length': '30', 'blank': 'True'}), |
|
135 |
'groups': ('django.db.models.fields.related.ManyToManyField', [], |
|
136 |
{'symmetrical': 'False', 'related_name': "u'user_set'", |
|
137 |
'blank': 'True', 'to': u"orm['auth.Group']"}), |
|
138 |
u'id': ('django.db.models.fields.AutoField', [], |
|
139 |
{'primary_key': 'True'}), |
|
140 |
'is_active': ('django.db.models.fields.BooleanField', [], |
|
141 |
{'default': 'True'}), |
|
142 |
'is_staff': ('django.db.models.fields.BooleanField', [], |
|
143 |
{'default': 'False'}), |
|
144 |
'is_superuser': ('django.db.models.fields.BooleanField', [], |
|
145 |
{'default': 'False'}), |
|
146 |
'last_login': ('django.db.models.fields.DateTimeField', [], |
|
147 |
{'default': 'datetime.datetime.now'}), |
|
148 |
'last_name': ('django.db.models.fields.CharField', [], |
|
149 |
{'max_length': '30', 'blank': 'True'}), |
|
150 |
'password': ('django.db.models.fields.CharField', [], |
|
151 |
{'max_length': '128'}), |
|
152 |
'user_permissions': ( |
|
153 |
'django.db.models.fields.related.ManyToManyField', [], |
|
154 |
{'symmetrical': 'False', 'related_name': "u'user_set'", |
|
155 |
'blank': 'True', 'to': u"orm['auth.Permission']"}), |
|
156 |
'username': ('django.db.models.fields.CharField', [], |
|
157 |
{'unique': 'True', 'max_length': '30'}) |
|
158 |
}, |
|
159 |
u'contenttypes.contenttype': { |
|
160 |
'Meta': {'ordering': "('name',)", |
|
161 |
'unique_together': "(('app_label', 'model'),)", |
|
162 |
'object_name': 'ContentType', |
|
163 |
'db_table': "'django_content_type'"}, |
|
164 |
'app_label': ('django.db.models.fields.CharField', [], |
|
165 |
{'max_length': '100'}), |
|
166 |
u'id': ('django.db.models.fields.AutoField', [], |
|
167 |
{'primary_key': 'True'}), |
|
168 |
'model': ('django.db.models.fields.CharField', [], |
|
169 |
{'max_length': '100'}), |
|
170 |
'name': ('django.db.models.fields.CharField', [], |
|
171 |
{'max_length': '100'}) |
|
172 |
}, |
|
173 |
u'default.association': { |
|
174 |
'Meta': {'object_name': 'Association', |
|
175 |
'db_table': "'social_auth_association'"}, |
|
176 |
'assoc_type': ('django.db.models.fields.CharField', [], |
|
177 |
{'max_length': '64'}), |
|
178 |
'handle': ('django.db.models.fields.CharField', [], |
|
179 |
{'max_length': '255'}), |
|
180 |
u'id': ('django.db.models.fields.AutoField', [], |
|
181 |
{'primary_key': 'True'}), |
|
182 |
'issued': ('django.db.models.fields.IntegerField', [], {}), |
|
183 |
'lifetime': ('django.db.models.fields.IntegerField', [], {}), |
|
184 |
'secret': ('django.db.models.fields.CharField', [], |
|
185 |
{'max_length': '255'}), |
|
186 |
'server_url': ('django.db.models.fields.CharField', [], |
|
187 |
{'max_length': '255'}) |
|
188 |
}, |
|
189 |
u'default.code': { |
|
190 |
'Meta': {'unique_together': "(('email', 'code'),)", |
|
191 |
'object_name': 'Code', 'db_table': "'social_auth_code'"}, |
|
192 |
'code': ('django.db.models.fields.CharField', [], |
|
193 |
{'max_length': '32', 'db_index': 'True'}), |
|
194 |
'email': ('django.db.models.fields.EmailField', [], |
|
195 |
{'max_length': '75'}), |
|
196 |
u'id': ('django.db.models.fields.AutoField', [], |
|
197 |
{'primary_key': 'True'}), |
|
198 |
'verified': ('django.db.models.fields.BooleanField', [], |
|
199 |
{'default': 'False'}) |
|
200 |
}, |
|
201 |
u'default.nonce': { |
|
202 |
'Meta': {'object_name': 'Nonce', |
|
203 |
'db_table': "'social_auth_nonce'"}, |
|
204 |
u'id': ('django.db.models.fields.AutoField', [], |
|
205 |
{'primary_key': 'True'}), |
|
206 |
'salt': ('django.db.models.fields.CharField', [], |
|
207 |
{'max_length': '65'}), |
|
208 |
'server_url': ('django.db.models.fields.CharField', [], |
|
209 |
{'max_length': '255'}), |
|
210 |
'timestamp': ('django.db.models.fields.IntegerField', [], {}) |
|
211 |
}, |
|
212 |
u'default.usersocialauth': { |
|
213 |
'Meta': {'unique_together': "(('provider', 'uid'),)", |
|
214 |
'object_name': 'UserSocialAuth', |
|
215 |
'db_table': "'social_auth_usersocialauth'"}, |
|
216 |
'extra_data': ('social.apps.django_app.default.fields.JSONField', |
|
217 |
[], {'default': "'{}'"}), |
|
218 |
u'id': ('django.db.models.fields.AutoField', [], |
|
219 |
{'primary_key': 'True'}), |
|
220 |
'provider': ('django.db.models.fields.CharField', [], |
|
221 |
{'max_length': '32'}), |
|
222 |
'uid': ('django.db.models.fields.CharField', [], |
|
223 |
{'max_length': '255'}), |
|
224 |
'user': ('django.db.models.fields.related.ForeignKey', [], |
|
225 |
{'related_name': "'social_auth'", |
|
226 |
'to': u"orm['auth.User']"}) |
|
227 |
} |
|
228 |
} |
|
229 |
models.update(custom_user_frozen_models(USER_MODEL)) |
|
230 |
|
|
231 |
complete_apps = ['default'] |
/dev/null | ||
---|---|---|
1 |
from django.conf import settings |
|
2 |
from django.db.models.loading import get_model |
|
3 |
|
|
4 |
|
|
5 |
def get_custom_user_model_for_migrations(): |
|
6 |
user_model = getattr(settings, 'SOCIAL_AUTH_USER_MODEL', None) or \ |
|
7 |
getattr(settings, 'AUTH_USER_MODEL', None) or \ |
|
8 |
'auth.User' |
|
9 |
if user_model != 'auth.User': |
|
10 |
# In case of having a proxy model defined as USER_MODEL |
|
11 |
# We use auth.User instead to prevent migration errors |
|
12 |
# Since proxy models aren't present in migrations |
|
13 |
if get_model(*user_model.split('.'))._meta.proxy: |
|
14 |
user_model = 'auth.User' |
|
15 |
return user_model |
|
16 |
|
|
17 |
|
|
18 |
def custom_user_frozen_models(user_model): |
|
19 |
migration_name = getattr(settings, 'INITIAL_CUSTOM_USER_MIGRATION', |
|
20 |
'0001_initial.py') |
|
21 |
if user_model != 'auth.User': |
|
22 |
from south.migration.base import Migrations |
|
23 |
from south.exceptions import NoMigrations |
|
24 |
from south.creator.freezer import freeze_apps |
|
25 |
user_app, user_model = user_model.split('.') |
|
26 |
try: |
|
27 |
user_migrations = Migrations(user_app) |
|
28 |
except NoMigrations: |
|
29 |
extra_model = freeze_apps(user_app) |
|
30 |
else: |
|
31 |
initial_user_migration = user_migrations.migration(migration_name) |
|
32 |
extra_model = initial_user_migration.migration_class().models |
|
33 |
else: |
|
34 |
extra_model = {} |
|
35 |
return extra_model |
/dev/null | ||
---|---|---|
1 |
from social.apps.django_app.tests import * |
/dev/null | ||
---|---|---|
1 |
""" |
|
2 |
Mongoengine backend support. |
|
3 |
|
|
4 |
To enable this app: |
|
5 |
* Add 'social.apps.django_app.me' to INSTALLED_APPS |
|
6 |
* In urls.py include url('', include('social.apps.django_app.urls')) |
|
7 |
""" |
/dev/null | ||
---|---|---|
1 |
""" |
|
2 |
MongoEngine Django models for Social Auth. |
|
3 |
Requires MongoEngine 0.8.6 or higher. |
|
4 |
""" |
|
5 |
from django.conf import settings |
|
6 |
|
|
7 |
from mongoengine import Document, ReferenceField |
|
8 |
from mongoengine.queryset import OperationError |
|
9 |
|
|
10 |
from social.utils import setting_name, module_member |
|
11 |
from social.storage.django_orm import BaseDjangoStorage |
|
12 |
|
|
13 |
from social.storage.mongoengine_orm import MongoengineUserMixin, \ |
|
14 |
MongoengineNonceMixin, \ |
|
15 |
MongoengineAssociationMixin, \ |
|
16 |
MongoengineCodeMixin |
|
17 |
|
|
18 |
|
|
19 |
UNUSABLE_PASSWORD = '!' # Borrowed from django 1.4 |
|
20 |
|
|
21 |
|
|
22 |
def _get_user_model(): |
|
23 |
""" |
|
24 |
Get the User Document class user for MongoEngine authentication. |
|
25 |
|
|
26 |
Use the model defined in SOCIAL_AUTH_USER_MODEL if defined, or |
|
27 |
defaults to MongoEngine's configured user document class. |
|
28 |
""" |
|
29 |
custom_model = getattr(settings, setting_name('USER_MODEL'), None) |
|
30 |
if custom_model: |
|
31 |
return module_member(custom_model) |
|
32 |
|
|
33 |
try: |
|
34 |
# Custom user model support with MongoEngine 0.8 |
|
35 |
from mongoengine.django.mongo_auth.models import get_user_document |
|
36 |
return get_user_document() |
|
37 |
except ImportError: |
|
38 |
return module_member('mongoengine.django.auth.User') |
|
39 |
|
|
40 |
|
|
41 |
USER_MODEL = _get_user_model() |
|
42 |
|
|
43 |
|
|
44 |
class UserSocialAuth(Document, MongoengineUserMixin): |
|
45 |
"""Social Auth association model""" |
|
46 |
user = ReferenceField(USER_MODEL) |
|
47 |
|
|
48 |
@classmethod |
|
49 |
def user_model(cls): |
|
50 |
return USER_MODEL |
|
51 |
|
|
52 |
|
|
53 |
class Nonce(Document, MongoengineNonceMixin): |
|
54 |
"""One use numbers""" |
|
55 |
pass |
|
56 |
|
|
57 |
|
|
58 |
class Association(Document, MongoengineAssociationMixin): |
|
59 |
"""OpenId account association""" |
|
60 |
pass |
|
61 |
|
|
62 |
|
|
63 |
class Code(Document, MongoengineCodeMixin): |
|
64 |
"""Mail validation single one time use code""" |
|
65 |
pass |
|
66 |
|
|
67 |
|
|
68 |
class DjangoStorage(BaseDjangoStorage): |
|
69 |
user = UserSocialAuth |
|
70 |
nonce = Nonce |
|
71 |
association = Association |
|
72 |
code = Code |
|
73 |
|
|
74 |
@classmethod |
|
75 |
def is_integrity_error(cls, exception): |
|
76 |
return exception.__class__ is OperationError and \ |
|
77 |
'E11000' in exception.message |
/dev/null | ||
---|---|---|
1 |
from social.apps.django_app.tests import * |
/dev/null | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
import six |
|
3 |
|
|
4 |
from django.conf import settings |
|
5 |
from django.contrib import messages |
|
6 |
from django.contrib.messages.api import MessageFailure |
|
7 |
from django.shortcuts import redirect |
|
8 |
from django.utils.http import urlquote |
|
9 |
|
|
10 |
from social.exceptions import SocialAuthBaseException |
|
11 |
|
|
12 |
|
|
13 |
class SocialAuthExceptionMiddleware(object): |
|
14 |
"""Middleware that handles Social Auth AuthExceptions by providing the user |
|
15 |
with a message, logging an error, and redirecting to some next location. |
|
16 |
|
|
17 |
By default, the exception message itself is sent to the user and they are |
|
18 |
redirected to the location specified in the SOCIAL_AUTH_LOGIN_ERROR_URL |
|
19 |
setting. |
|
20 |
|
|
21 |
This middleware can be extended by overriding the get_message or |
|
22 |
get_redirect_uri methods, which each accept request and exception. |
|
23 |
""" |
|
24 |
def process_exception(self, request, exception): |
|
25 |
strategy = getattr(request, 'social_strategy', None) |
|
26 |
if strategy is None or self.raise_exception(request, exception): |
|
27 |
return |
|
28 |
|
|
29 |
if isinstance(exception, SocialAuthBaseException): |
|
30 |
backend_name = request.backend.name |
|
31 |
message = self.get_message(request, exception) |
|
32 |
url = self.get_redirect_uri(request, exception) |
|
33 |
try: |
|
34 |
messages.error(request, message, |
|
35 |
extra_tags='social-auth ' + backend_name) |
|
36 |
except MessageFailure: |
|
37 |
url += ('?' in url and '&' or '?') + \ |
|
38 |
'message={0}&backend={1}'.format(urlquote(message), |
|
39 |
backend_name) |
|
40 |
return redirect(url) |
|
41 |
|
|
42 |
def raise_exception(self, request, exception): |
|
43 |
strategy = getattr(request, 'social_strategy', None) |
|
44 |
if strategy is not None: |
|
45 |
return strategy.setting('RAISE_EXCEPTIONS', settings.DEBUG) |
|
46 |
|
|
47 |
def get_message(self, request, exception): |
|
48 |
return six.text_type(exception) |
|
49 |
|
|
50 |
def get_redirect_uri(self, request, exception): |
|
51 |
strategy = getattr(request, 'social_strategy', None) |
|
52 |
return strategy.setting('LOGIN_ERROR_URL') |
/dev/null | ||
---|---|---|
1 |
from social.tests.test_exceptions import * |
|
2 |
from social.tests.test_pipeline import * |
|
3 |
from social.tests.test_storage import * |
|
4 |
from social.tests.test_utils import * |
|
5 |
from social.tests.actions.test_associate import * |
|
6 |
from social.tests.actions.test_disconnect import * |
|
7 |
from social.tests.actions.test_login import * |
|
8 |
from social.tests.backends.test_amazon import * |
|
9 |
from social.tests.backends.test_angel import * |
|
10 |
from social.tests.backends.test_behance import * |
|
11 |
from social.tests.backends.test_bitbucket import * |
|
12 |
from social.tests.backends.test_box import * |
|
13 |
from social.tests.backends.test_broken import * |
|
14 |
from social.tests.backends.test_coinbase import * |
|
15 |
from social.tests.backends.test_dailymotion import * |
|
16 |
from social.tests.backends.test_disqus import * |
|
17 |
from social.tests.backends.test_dropbox import * |
|
18 |
from social.tests.backends.test_dummy import * |
|
19 |
from social.tests.backends.test_email import * |
|
20 |
from social.tests.backends.test_evernote import * |
|
21 |
from social.tests.backends.test_facebook import * |
|
22 |
from social.tests.backends.test_fitbit import * |
|
23 |
from social.tests.backends.test_flickr import * |
|
24 |
from social.tests.backends.test_foursquare import * |
|
25 |
from social.tests.backends.test_google import * |
|
26 |
from social.tests.backends.test_instagram import * |
|
27 |
from social.tests.backends.test_linkedin import * |
|
28 |
from social.tests.backends.test_live import * |
|
29 |
from social.tests.backends.test_livejournal import * |
|
30 |
from social.tests.backends.test_mixcloud import * |
|
31 |
from social.tests.backends.test_podio import * |
|
32 |
from social.tests.backends.test_readability import * |
|
33 |
from social.tests.backends.test_reddit import * |
|
34 |
from social.tests.backends.test_skyrock import * |
|
35 |
from social.tests.backends.test_soundcloud import * |
|
36 |
from social.tests.backends.test_stackoverflow import * |
|
37 |
from social.tests.backends.test_steam import * |
|
38 |
from social.tests.backends.test_stocktwits import * |
|
39 |
from social.tests.backends.test_stripe import * |
|
40 |
from social.tests.backends.test_thisismyjam import * |
|
41 |
from social.tests.backends.test_tripit import * |
|
42 |
from social.tests.backends.test_tumblr import * |
|
43 |
from social.tests.backends.test_twitter import * |
|
44 |
from social.tests.backends.test_username import * |
|
45 |
from social.tests.backends.test_utils import * |
|
46 |
from social.tests.backends.test_vk import * |
|
47 |
from social.tests.backends.test_xing import * |
|
48 |
from social.tests.backends.test_yahoo import * |
|
49 |
from social.tests.backends.test_yammer import * |
|
50 |
from social.tests.backends.test_yandex import * |
/dev/null | ||
---|---|---|
1 |
"""URLs module""" |
|
2 |
try: |
|
3 |
from django.conf.urls import patterns, url |
|
4 |
except ImportError: |
|
5 |
# Django < 1.4 |
|
6 |
from django.conf.urls.defaults import patterns, url |
|
7 |
|
|
8 |
|
|
9 |
urlpatterns = patterns('social.apps.django_app.views', |
|
10 |
# authentication / association |
|
11 |
url(r'^login/(?P<backend>[^/]+)/$', 'auth', |
|
12 |
name='begin'), |
|
13 |
url(r'^complete/(?P<backend>[^/]+)/$', 'complete', |
|
14 |
name='complete'), |
|
15 |
# disconnection |
|
16 |
url(r'^disconnect/(?P<backend>[^/]+)/$', 'disconnect', |
|
17 |
name='disconnect'), |
|
18 |
url(r'^disconnect/(?P<backend>[^/]+)/(?P<association_id>[^/]+)/$', |
|
19 |
'disconnect', name='disconnect_individual'), |
|
20 |
) |
/dev/null | ||
---|---|---|
1 |
import warnings |
|
2 |
|
|
3 |
from functools import wraps |
|
4 |
|
|
5 |
from django.conf import settings |
|
6 |
from django.core.urlresolvers import reverse |
|
7 |
from django.http import Http404 |
|
8 |
|
|
9 |
from social.utils import setting_name, module_member |
|
10 |
from social.exceptions import MissingBackend |
|
11 |
from social.strategies.utils import get_strategy |
|
12 |
from social.backends.utils import get_backend |
|
13 |
|
|
14 |
|
|
15 |
BACKENDS = settings.AUTHENTICATION_BACKENDS |
|
16 |
STRATEGY = getattr(settings, setting_name('STRATEGY'), |
|
17 |
'social.strategies.django_strategy.DjangoStrategy') |
|
18 |
STORAGE = getattr(settings, setting_name('STORAGE'), |
|
19 |
'social.apps.django_app.default.models.DjangoStorage') |
|
20 |
Strategy = module_member(STRATEGY) |
|
21 |
Storage = module_member(STORAGE) |
|
22 |
|
|
23 |
|
|
24 |
def load_strategy(request=None): |
|
25 |
return get_strategy(STRATEGY, STORAGE, request) |
|
26 |
|
|
27 |
|
|
28 |
def load_backend(strategy, name, redirect_uri): |
|
29 |
Backend = get_backend(BACKENDS, name) |
|
30 |
return Backend(strategy, redirect_uri) |
|
31 |
|
|
32 |
|
|
33 |
def psa(redirect_uri=None, load_strategy=load_strategy): |
|
34 |
def decorator(func): |
|
35 |
@wraps(func) |
|
36 |
def wrapper(request, backend, *args, **kwargs): |
|
37 |
uri = redirect_uri |
|
38 |
if uri and not uri.startswith('/'): |
|
39 |
uri = reverse(redirect_uri, args=(backend,)) |
|
40 |
|
|
41 |
request.social_strategy = load_strategy(request) |
|
42 |
# backward compatibility in attribute name, only if not already |
|
43 |
# defined |
|
44 |
if not hasattr(request, 'strategy'): |
|
45 |
request.strategy = request.social_strategy |
|
46 |
|
|
47 |
try: |
|
48 |
request.backend = load_backend(request.social_strategy, |
|
49 |
backend, uri) |
|
50 |
except MissingBackend: |
|
51 |
raise Http404('Backend not found') |
|
52 |
return func(request, backend, *args, **kwargs) |
|
53 |
return wrapper |
|
54 |
return decorator |
|
55 |
|
|
56 |
|
|
57 |
def setting(name, default=None): |
|
58 |
try: |
|
59 |
return getattr(settings, setting_name(name)) |
|
60 |
except AttributeError: |
|
61 |
return getattr(settings, name, default) |
|
62 |
|
|
63 |
|
|
64 |
class BackendWrapper(object): |
|
65 |
# XXX: Deprecated, restored to avoid session issues |
|
66 |
def authenticate(self, *args, **kwargs): |
|
67 |
return None |
|
68 |
|
|
69 |
def get_user(self, user_id): |
|
70 |
return Strategy(storage=Storage).get_user(user_id) |
|
71 |
|
|
72 |
|
|
73 |
def strategy(*args, **kwargs): |
|
74 |
warnings.warn('@strategy decorator is deprecated, use @psa instead') |
|
75 |
return psa(*args, **kwargs) |
/dev/null | ||
---|---|---|
1 |
from django.contrib.auth import login, REDIRECT_FIELD_NAME |
|
2 |
from django.contrib.auth.decorators import login_required |
|
3 |
from django.views.decorators.csrf import csrf_exempt, csrf_protect |
|
4 |
from django.views.decorators.http import require_POST |
|
5 |
|
|
6 |
from social.actions import do_auth, do_complete, do_disconnect |
|
7 |
from social.apps.django_app.utils import psa |
|
8 |
|
|
9 |
|
|
10 |
@psa('social:complete') |
|
11 |
def auth(request, backend): |
|
12 |
return do_auth(request.backend, redirect_name=REDIRECT_FIELD_NAME) |
|
13 |
|
|
14 |
|
|
15 |
@csrf_exempt |
|
16 |
@psa('social:complete') |
|
17 |
def complete(request, backend, *args, **kwargs): |
|
18 |
"""Authentication complete view""" |
|
19 |
return do_complete(request.backend, _do_login, request.user, |
|
20 |
redirect_name=REDIRECT_FIELD_NAME, *args, **kwargs) |
|
21 |
|
|
22 |
|
|
23 |
@login_required |
|
24 |
@psa() |
|
25 |
@require_POST |
|
26 |
@csrf_protect |
|
27 |
def disconnect(request, backend, association_id=None): |
|
28 |
"""Disconnects given backend from current logged in user.""" |
|
29 |
return do_disconnect(request.backend, request.user, association_id, |
|
30 |
redirect_name=REDIRECT_FIELD_NAME) |
|
31 |
|
|
32 |
|
|
33 |
def _do_login(backend, user, social_user): |
|
34 |
user.backend = '{0}.{1}'.format(backend.__module__, |
|
35 |
backend.__class__.__name__) |
|
36 |
login(backend.strategy.request, user) |
|
37 |
if backend.setting('SESSION_EXPIRATION', False): |
|
38 |
# Set session expiration date if present and enabled |
|
39 |
# by setting. Use last social-auth instance for current |
|
40 |
# provider, users can associate several accounts with |
|
41 |
# a same provider. |
|
42 |
expiration = social_user.expiration_datetime() |
|
43 |
if expiration: |
|
44 |
try: |
|
45 |
backend.strategy.request.session.set_expiry( |
|
46 |
expiration.seconds + expiration.days * 86400 |
|
47 |
) |
|
48 |
except OverflowError: |
|
49 |
# Handle django time zone overflow |
|
50 |
backend.strategy.request.session.set_expiry(None) |
/dev/null | ||
---|---|---|
1 |
from social.strategies.utils import set_current_strategy_getter |
|
2 |
from social.apps.flask_app.utils import load_strategy |
|
3 |
|
|
4 |
|
|
5 |
set_current_strategy_getter(load_strategy) |
/dev/null | ||
---|---|---|
1 |
"""Flask SQLAlchemy ORM models for Social Auth""" |
|
2 |
from sqlalchemy import Column, Integer, String, ForeignKey |
|
3 |
from sqlalchemy.orm import relationship, backref |
|
4 |
|
|
5 |
from social.utils import setting_name, module_member |
|
6 |
from social.storage.sqlalchemy_orm import SQLAlchemyUserMixin, \ |
|
7 |
SQLAlchemyAssociationMixin, \ |
|
8 |
SQLAlchemyNonceMixin, \ |
|
9 |
SQLAlchemyCodeMixin, \ |
|
10 |
BaseSQLAlchemyStorage |
|
11 |
|
|
12 |
|
|
13 |
class FlaskStorage(BaseSQLAlchemyStorage): |
|
14 |
user = None |
|
15 |
nonce = None |
|
16 |
association = None |
|
17 |
code = None |
|
18 |
|
|
19 |
|
|
20 |
def init_social(app, db): |
|
21 |
UID_LENGTH = app.config.get(setting_name('UID_LENGTH'), 255) |
|
22 |
User = module_member(app.config[setting_name('USER_MODEL')]) |
|
23 |
app_session = db.session |
|
24 |
|
|
25 |
class _AppSession(object): |
|
26 |
@classmethod |
|
27 |
def _session(cls): |
|
28 |
return app_session |
|
29 |
|
|
30 |
class UserSocialAuth(_AppSession, db.Model, SQLAlchemyUserMixin): |
|
31 |
"""Social Auth association model""" |
|
32 |
uid = Column(String(UID_LENGTH)) |
|
33 |
user_id = Column(Integer, ForeignKey(User.id), |
|
34 |
nullable=False, index=True) |
|
35 |
user = relationship(User, backref=backref('social_auth', |
|
36 |
lazy='dynamic')) |
|
37 |
|
|
38 |
@classmethod |
|
39 |
def username_max_length(cls): |
|
40 |
return User.__table__.columns.get('username').type.length |
|
41 |
|
|
42 |
@classmethod |
|
43 |
def user_model(cls): |
|
44 |
return User |
|
45 |
|
|
46 |
class Nonce(_AppSession, db.Model, SQLAlchemyNonceMixin): |
Also available in: Unified diff