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):
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff