Statistics
| Branch: | Tag: | Revision:

root / snf-astakos-app / astakos / im / auth_providers.py @ 480ce06b

History | View | Annotate | Download (8.6 kB)

1 d2633501 Kostas Papadimitriou
# Copyright 2011 GRNET S.A. All rights reserved.
2 d2633501 Kostas Papadimitriou
#
3 d2633501 Kostas Papadimitriou
# Redistribution and use in source and binary forms, with or
4 d2633501 Kostas Papadimitriou
# without modification, are permitted provided that the following
5 d2633501 Kostas Papadimitriou
# conditions are met:
6 d2633501 Kostas Papadimitriou
#
7 d2633501 Kostas Papadimitriou
#   1. Redistributions of source code must retain the above
8 d2633501 Kostas Papadimitriou
#      copyright notice, this list of conditions and the following
9 d2633501 Kostas Papadimitriou
#      disclaimer.
10 d2633501 Kostas Papadimitriou
#
11 d2633501 Kostas Papadimitriou
#   2. Redistributions in binary form must reproduce the above
12 d2633501 Kostas Papadimitriou
#      copyright notice, this list of conditions and the following
13 d2633501 Kostas Papadimitriou
#      disclaimer in the documentation and/or other materials
14 d2633501 Kostas Papadimitriou
#      provided with the distribution.
15 d2633501 Kostas Papadimitriou
#
16 d2633501 Kostas Papadimitriou
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 d2633501 Kostas Papadimitriou
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 d2633501 Kostas Papadimitriou
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 d2633501 Kostas Papadimitriou
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 d2633501 Kostas Papadimitriou
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 d2633501 Kostas Papadimitriou
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 d2633501 Kostas Papadimitriou
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 d2633501 Kostas Papadimitriou
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 d2633501 Kostas Papadimitriou
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 d2633501 Kostas Papadimitriou
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 d2633501 Kostas Papadimitriou
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 d2633501 Kostas Papadimitriou
# POSSIBILITY OF SUCH DAMAGE.
28 d2633501 Kostas Papadimitriou
#
29 d2633501 Kostas Papadimitriou
# The views and conclusions contained in the software and
30 d2633501 Kostas Papadimitriou
# documentation are those of the authors and should not be
31 d2633501 Kostas Papadimitriou
# interpreted as representing official policies, either expressed
32 d2633501 Kostas Papadimitriou
# or implied, of GRNET S.A.
33 d2633501 Kostas Papadimitriou
34 d2633501 Kostas Papadimitriou
35 d2633501 Kostas Papadimitriou
from django.core.urlresolvers import reverse
36 d2633501 Kostas Papadimitriou
from django.utils.translation import ugettext as _
37 081070a5 Kostas Papadimitriou
from django.utils.datastructures import SortedDict
38 d2633501 Kostas Papadimitriou
39 081070a5 Kostas Papadimitriou
from django.conf import settings
40 c4b1a172 Kostas Papadimitriou
41 081070a5 Kostas Papadimitriou
from astakos.im import settings as astakos_settings
42 c4b1a172 Kostas Papadimitriou
from astakos.im import messages as astakos_messages
43 d2633501 Kostas Papadimitriou
44 d2633501 Kostas Papadimitriou
import logging
45 dd5f8f4d Kostas Papadimitriou
import urllib
46 d2633501 Kostas Papadimitriou
47 d2633501 Kostas Papadimitriou
logger = logging.getLogger(__name__)
48 d2633501 Kostas Papadimitriou
49 d2633501 Kostas Papadimitriou
# providers registry
50 6012535a Kostas Papadimitriou
PROVIDERS = {}
51 badcb2a9 Kostas Papadimitriou
REQUIRED_PROVIDERS = {}
52 d2633501 Kostas Papadimitriou
53 d2633501 Kostas Papadimitriou
class AuthProviderBase(type):
54 d2633501 Kostas Papadimitriou
55 d2633501 Kostas Papadimitriou
    def __new__(cls, name, bases, dct):
56 d2633501 Kostas Papadimitriou
        include = False
57 d2633501 Kostas Papadimitriou
        if [b for b in bases if isinstance(b, AuthProviderBase)]:
58 d2633501 Kostas Papadimitriou
            type_id = dct.get('module')
59 d2633501 Kostas Papadimitriou
            if type_id:
60 d2633501 Kostas Papadimitriou
                include = True
61 081070a5 Kostas Papadimitriou
            if type_id in astakos_settings.IM_MODULES:
62 d2633501 Kostas Papadimitriou
                dct['module_enabled'] = True
63 d2633501 Kostas Papadimitriou
64 d2633501 Kostas Papadimitriou
        newcls = super(AuthProviderBase, cls).__new__(cls, name, bases, dct)
65 d2633501 Kostas Papadimitriou
        if include:
66 6012535a Kostas Papadimitriou
            PROVIDERS[type_id] = newcls
67 badcb2a9 Kostas Papadimitriou
            if newcls().is_required():
68 badcb2a9 Kostas Papadimitriou
                REQUIRED_PROVIDERS[type_id] = newcls
69 d2633501 Kostas Papadimitriou
        return newcls
70 d2633501 Kostas Papadimitriou
71 d2633501 Kostas Papadimitriou
72 d2633501 Kostas Papadimitriou
class AuthProvider(object):
73 d2633501 Kostas Papadimitriou
74 d2633501 Kostas Papadimitriou
    __metaclass__ = AuthProviderBase
75 d2633501 Kostas Papadimitriou
76 d2633501 Kostas Papadimitriou
    module = None
77 d2633501 Kostas Papadimitriou
    module_active = False
78 d2633501 Kostas Papadimitriou
    module_enabled = False
79 d2633501 Kostas Papadimitriou
    one_per_user = False
80 450093ec Kostas Papadimitriou
    login_prompt = _('Login using ')
81 450093ec Kostas Papadimitriou
    primary_login_prompt = _('Login using ')
82 d2633501 Kostas Papadimitriou
83 c4b1a172 Kostas Papadimitriou
    def get_message(self, msg, **kwargs):
84 c4b1a172 Kostas Papadimitriou
        params = kwargs
85 c4b1a172 Kostas Papadimitriou
        params.update({'provider': self.get_title_display})
86 c4b1a172 Kostas Papadimitriou
87 c4b1a172 Kostas Papadimitriou
        override_msg = getattr(self, 'get_%s_message_display' % msg.lower(), None)
88 c4b1a172 Kostas Papadimitriou
        msg = 'AUTH_PROVIDER_%s' % msg
89 c4b1a172 Kostas Papadimitriou
        return override_msg or getattr(astakos_messages, msg, msg) % params
90 c4b1a172 Kostas Papadimitriou
91 dd5f8f4d Kostas Papadimitriou
    @property
92 dd5f8f4d Kostas Papadimitriou
    def add_url(self):
93 dd5f8f4d Kostas Papadimitriou
        return reverse(self.login_view)
94 dd5f8f4d Kostas Papadimitriou
95 d2633501 Kostas Papadimitriou
    def __init__(self, user=None):
96 d2633501 Kostas Papadimitriou
        self.user = user
97 dd5f8f4d Kostas Papadimitriou
        for tpl in ['login_prompt', 'login', 'signup_prompt']:
98 dd5f8f4d Kostas Papadimitriou
            tpl_name = '%s_%s' % (tpl, 'template')
99 dd5f8f4d Kostas Papadimitriou
            override = self.get_setting(tpl_name)
100 dd5f8f4d Kostas Papadimitriou
            if override:
101 dd5f8f4d Kostas Papadimitriou
                setattr(self, tpl_name, override)
102 d2633501 Kostas Papadimitriou
103 91bbc1a4 Kostas Papadimitriou
        for key in ['one_per_user']:
104 91bbc1a4 Kostas Papadimitriou
            override = self.get_setting(key)
105 91bbc1a4 Kostas Papadimitriou
            if override != None:
106 91bbc1a4 Kostas Papadimitriou
                setattr(self, key, override)
107 91bbc1a4 Kostas Papadimitriou
108 081070a5 Kostas Papadimitriou
    def __getattr__(self, key):
109 081070a5 Kostas Papadimitriou
        if not key.startswith('get_'):
110 6974e526 Kostas Papadimitriou
            return super(AuthProvider, self).__getattribute__(key)
111 081070a5 Kostas Papadimitriou
112 081070a5 Kostas Papadimitriou
        if key.endswith('_display') or key.endswith('template'):
113 081070a5 Kostas Papadimitriou
            attr = key.replace('_display', '').replace('get_','')
114 081070a5 Kostas Papadimitriou
            settings_attr = self.get_setting(attr.upper())
115 081070a5 Kostas Papadimitriou
            if not settings_attr:
116 081070a5 Kostas Papadimitriou
                return getattr(self, attr)
117 cb4714e7 Kostas Papadimitriou
            return _(settings_attr)
118 081070a5 Kostas Papadimitriou
        else:
119 081070a5 Kostas Papadimitriou
            return super(AuthProvider, self).__getattr__(key)
120 081070a5 Kostas Papadimitriou
121 d2633501 Kostas Papadimitriou
    def get_setting(self, name, default=None):
122 081070a5 Kostas Papadimitriou
        attr = 'ASTAKOS_AUTH_PROVIDER_%s_%s' % (self.module.upper(), name.upper())
123 1d59653f Kostas Papadimitriou
        attr_sec = 'ASTAKOS_%s_%s' % (self.module.upper(), name.upper())
124 1d59653f Kostas Papadimitriou
        if not hasattr(settings, attr):
125 1d59653f Kostas Papadimitriou
            return getattr(settings, attr_sec, default)
126 91bbc1a4 Kostas Papadimitriou
127 d2633501 Kostas Papadimitriou
        return getattr(settings, attr, default)
128 d2633501 Kostas Papadimitriou
129 d2633501 Kostas Papadimitriou
    def is_available_for_login(self):
130 d2633501 Kostas Papadimitriou
        """ A user can login using authentication provider"""
131 d2633501 Kostas Papadimitriou
        return self.is_active() and self.get_setting('CAN_LOGIN',
132 d2633501 Kostas Papadimitriou
                                                     self.is_active())
133 d2633501 Kostas Papadimitriou
134 d2633501 Kostas Papadimitriou
    def is_available_for_create(self):
135 d2633501 Kostas Papadimitriou
        """ A user can create an account using this provider"""
136 d2633501 Kostas Papadimitriou
        return self.is_active() and self.get_setting('CAN_CREATE',
137 d2633501 Kostas Papadimitriou
                                                   self.is_active())
138 d2633501 Kostas Papadimitriou
139 d2633501 Kostas Papadimitriou
    def is_available_for_add(self):
140 d2633501 Kostas Papadimitriou
        """ A user can assign provider authentication method"""
141 d2633501 Kostas Papadimitriou
        return self.is_active() and self.get_setting('CAN_ADD',
142 d2633501 Kostas Papadimitriou
                                                   self.is_active())
143 d2633501 Kostas Papadimitriou
144 badcb2a9 Kostas Papadimitriou
    def is_required(self):
145 badcb2a9 Kostas Papadimitriou
        """Provider required (user cannot remove the last one)"""
146 badcb2a9 Kostas Papadimitriou
        return self.is_active() and self.get_setting('REQUIRED', False)
147 badcb2a9 Kostas Papadimitriou
148 d2633501 Kostas Papadimitriou
    def is_active(self):
149 081070a5 Kostas Papadimitriou
        return self.module in astakos_settings.IM_MODULES
150 d2633501 Kostas Papadimitriou
151 d2633501 Kostas Papadimitriou
152 d2633501 Kostas Papadimitriou
class LocalAuthProvider(AuthProvider):
153 d2633501 Kostas Papadimitriou
    module = 'local'
154 d2633501 Kostas Papadimitriou
    title = _('Local password')
155 d2633501 Kostas Papadimitriou
    description = _('Create a local password for your account')
156 081070a5 Kostas Papadimitriou
    add_prompt =  _('Create a local password for your account')
157 cb4714e7 Kostas Papadimitriou
    login_prompt = _('if you already have a username and password')
158 450093ec Kostas Papadimitriou
    signup_prompt = _('New to ~okeanos ?')
159 450093ec Kostas Papadimitriou
    signup_link_prompt = _('create an account now')
160 dd5f8f4d Kostas Papadimitriou
    login_view = 'password_change'
161 d2633501 Kostas Papadimitriou
162 d2633501 Kostas Papadimitriou
    one_per_user = True
163 081070a5 Kostas Papadimitriou
164 081070a5 Kostas Papadimitriou
    login_template = 'im/auth/local_login_form.html'
165 081070a5 Kostas Papadimitriou
    login_prompt_template = 'im/auth/local_login_prompt.html'
166 081070a5 Kostas Papadimitriou
    signup_prompt_template = 'im/auth/local_signup_prompt.html'
167 d2633501 Kostas Papadimitriou
    details_tpl = _('You can login to your account using your'
168 d2633501 Kostas Papadimitriou
                    ' %(auth_backend)s password.')
169 d2633501 Kostas Papadimitriou
170 d2633501 Kostas Papadimitriou
    @property
171 d2633501 Kostas Papadimitriou
    def extra_actions(self):
172 d2633501 Kostas Papadimitriou
        return [(_('Change password'), reverse('password_change')), ]
173 d2633501 Kostas Papadimitriou
174 74796dd8 Kostas Papadimitriou
175 d2633501 Kostas Papadimitriou
class ShibbolethAuthProvider(AuthProvider):
176 d2633501 Kostas Papadimitriou
    module = 'shibboleth'
177 d2633501 Kostas Papadimitriou
    title = _('Academic credentials (Shibboleth)')
178 450093ec Kostas Papadimitriou
    add_prompt = _('Allows you to login to your account using your academic '
179 450093ec Kostas Papadimitriou
                    'account')
180 b9231ded Kostas Papadimitriou
    details_tpl = _('Shibboleth account \'%(identifier)s\' is connected to your '
181 3a72a5d4 Kostas Papadimitriou
                    ' account.')
182 3a72a5d4 Kostas Papadimitriou
    user_title = _('Academic credentials (%(identifier)s)')
183 cb4714e7 Kostas Papadimitriou
    primary_login_prompt = _('If you are a student/researcher/faculty you can'
184 cb4714e7 Kostas Papadimitriou
                             ' login using your university-credentials in'
185 cb4714e7 Kostas Papadimitriou
                             ' the following page')
186 dd5f8f4d Kostas Papadimitriou
    login_view = 'astakos.im.target.shibboleth.login'
187 d2633501 Kostas Papadimitriou
188 081070a5 Kostas Papadimitriou
    login_template = 'im/auth/shibboleth_login.html'
189 dd5f8f4d Kostas Papadimitriou
    login_prompt_template = 'im/auth/third_party_provider_generic_login_prompt.html'
190 d2633501 Kostas Papadimitriou
191 d2633501 Kostas Papadimitriou
192 c101b32b Kostas Papadimitriou
class TwitterAuthProvider(AuthProvider):
193 c101b32b Kostas Papadimitriou
    module = 'twitter'
194 c101b32b Kostas Papadimitriou
    title = _('Twitter')
195 450093ec Kostas Papadimitriou
    add_prompt = _('Allows you to login to your account using Twitter')
196 3a72a5d4 Kostas Papadimitriou
    details_tpl = _('Twitter screen name: %(info_screen_name)s')
197 3a72a5d4 Kostas Papadimitriou
    user_title = _('Twitter (%(info_screen_name)s)')
198 dd5f8f4d Kostas Papadimitriou
    login_view = 'astakos.im.target.twitter.login'
199 c101b32b Kostas Papadimitriou
200 450093ec Kostas Papadimitriou
    login_template = 'im/auth/third_party_provider_generic_login.html'
201 450093ec Kostas Papadimitriou
    login_prompt_template = 'im/auth/third_party_provider_generic_login_prompt.html'
202 c101b32b Kostas Papadimitriou
203 74796dd8 Kostas Papadimitriou
204 74796dd8 Kostas Papadimitriou
class GoogleAuthProvider(AuthProvider):
205 74796dd8 Kostas Papadimitriou
    module = 'google'
206 74796dd8 Kostas Papadimitriou
    title = _('Google')
207 450093ec Kostas Papadimitriou
    add_prompt = _('Allows you to login to your account using Google')
208 74796dd8 Kostas Papadimitriou
    details_tpl = _('Google account: %(info_email)s')
209 74796dd8 Kostas Papadimitriou
    user_title = _('Google (%(info_email)s)')
210 dd5f8f4d Kostas Papadimitriou
    login_view = 'astakos.im.target.google.login'
211 74796dd8 Kostas Papadimitriou
212 74796dd8 Kostas Papadimitriou
    login_template = 'im/auth/third_party_provider_generic_login.html'
213 74796dd8 Kostas Papadimitriou
    login_prompt_template = 'im/auth/third_party_provider_generic_login_prompt.html'
214 74796dd8 Kostas Papadimitriou
215 74796dd8 Kostas Papadimitriou
216 74796dd8 Kostas Papadimitriou
class LinkedInAuthProvider(AuthProvider):
217 74796dd8 Kostas Papadimitriou
    module = 'linkedin'
218 74796dd8 Kostas Papadimitriou
    title = _('LinkedIn')
219 450093ec Kostas Papadimitriou
    add_prompt = _('Allows you to login to your account using LinkedIn')
220 74796dd8 Kostas Papadimitriou
    user_title = _('LinkedIn (%(info_emailAddress)s)')
221 450093ec Kostas Papadimitriou
    details_tpl = _('LinkedIn account: %(info_emailAddress)s')
222 dd5f8f4d Kostas Papadimitriou
    login_view = 'astakos.im.target.linkedin.login'
223 74796dd8 Kostas Papadimitriou
224 74796dd8 Kostas Papadimitriou
    login_template = 'im/auth/third_party_provider_generic_login.html'
225 74796dd8 Kostas Papadimitriou
    login_prompt_template = 'im/auth/third_party_provider_generic_login_prompt.html'
226 74796dd8 Kostas Papadimitriou
227 74796dd8 Kostas Papadimitriou
228 d2633501 Kostas Papadimitriou
def get_provider(id, user_obj=None, default=None):
229 d2633501 Kostas Papadimitriou
    """
230 d2633501 Kostas Papadimitriou
    Return a provider instance from the auth providers registry.
231 d2633501 Kostas Papadimitriou
    """
232 d2633501 Kostas Papadimitriou
    return PROVIDERS.get(id, default)(user_obj)