1 # Copyright 2011 GRNET S.A. All rights reserved.
3 # Redistribution and use in source and binary forms, with or
4 # without modification, are permitted provided that the following
7 # 1. Redistributions of source code must retain the above
8 # copyright notice, this list of conditions and the following
11 # 2. Redistributions in binary form must reproduce the above
12 # copyright notice, this list of conditions and the following
13 # disclaimer in the documentation and/or other materials
14 # provided with the distribution.
16 # THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 # USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 # AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 # POSSIBILITY OF SUCH DAMAGE.
29 # The views and conclusions contained in the software and
30 # documentation are those of the authors and should not be
31 # interpreted as representing official policies, either expressed
32 # or implied, of GRNET S.A.
35 from django.core.urlresolvers import reverse
36 from django.utils.translation import ugettext as _
37 from django.utils.datastructures import SortedDict
39 from django.conf import settings
41 from astakos.im import settings as astakos_settings
42 from astakos.im import messages as astakos_messages
46 logger = logging.getLogger(__name__)
51 class AuthProviderBase(type):
53 def __new__(cls, name, bases, dct):
55 if [b for b in bases if isinstance(b, AuthProviderBase)]:
56 type_id = dct.get('module')
59 if type_id in astakos_settings.IM_MODULES:
60 dct['module_enabled'] = True
62 newcls = super(AuthProviderBase, cls).__new__(cls, name, bases, dct)
64 PROVIDERS[type_id] = newcls
68 class AuthProvider(object):
70 __metaclass__ = AuthProviderBase
74 module_enabled = False
76 login_prompt = _('Login using ')
77 primary_login_prompt = _('Login using ')
79 def get_message(self, msg, **kwargs):
81 params.update({'provider': self.get_title_display})
83 override_msg = getattr(self, 'get_%s_message_display' % msg.lower(), None)
84 msg = 'AUTH_PROVIDER_%s' % msg
85 return override_msg or getattr(astakos_messages, msg, msg) % params
87 def __init__(self, user=None):
90 def __getattr__(self, key):
91 if not key.startswith('get_'):
92 return super(AuthProvider, self).__getattribute__(key)
94 if key.endswith('_display') or key.endswith('template'):
95 attr = key.replace('_display', '').replace('get_','')
96 settings_attr = self.get_setting(attr.upper())
98 return getattr(self, attr)
99 return _(settings_attr)
101 return super(AuthProvider, self).__getattr__(key)
103 def get_setting(self, name, default=None):
104 attr = 'ASTAKOS_AUTH_PROVIDER_%s_%s' % (self.module.upper(), name.upper())
105 attr_sec = 'ASTAKOS_%s_%s' % (self.module.upper(), name.upper())
106 if not hasattr(settings, attr):
107 return getattr(settings, attr_sec, default)
108 return getattr(settings, attr, default)
110 def is_available_for_login(self):
111 """ A user can login using authentication provider"""
112 return self.is_active() and self.get_setting('CAN_LOGIN',
115 def is_available_for_create(self):
116 """ A user can create an account using this provider"""
117 return self.is_active() and self.get_setting('CAN_CREATE',
120 def is_available_for_add(self):
121 """ A user can assign provider authentication method"""
122 return self.is_active() and self.get_setting('CAN_ADD',
126 return self.module in astakos_settings.IM_MODULES
129 class LocalAuthProvider(AuthProvider):
131 title = _('Local password')
132 description = _('Create a local password for your account')
133 add_prompt = _('Create a local password for your account')
134 login_prompt = _('if you already have a username and password')
135 signup_prompt = _('New to ~okeanos ?')
136 signup_link_prompt = _('create an account now')
141 return reverse('password_change')
145 login_template = 'im/auth/local_login_form.html'
146 login_prompt_template = 'im/auth/local_login_prompt.html'
147 signup_prompt_template = 'im/auth/local_signup_prompt.html'
148 details_tpl = _('You can login to your account using your'
149 ' %(auth_backend)s password.')
152 def extra_actions(self):
153 return [(_('Change password'), reverse('password_change')), ]
156 class ShibbolethAuthProvider(AuthProvider):
157 module = 'shibboleth'
158 title = _('Academic credentials (Shibboleth)')
159 add_prompt = _('Allows you to login to your account using your academic '
161 details_tpl = _('Shibboleth account \'%(identifier)s\' is connected to your '
163 user_title = _('Academic credentials (%(identifier)s)')
164 primary_login_prompt = _('If you are a student/researcher/faculty you can'
165 ' login using your university-credentials in'
166 ' the following page')
170 return reverse('astakos.im.target.shibboleth.login')
172 login_template = 'im/auth/shibboleth_login.html'
173 login_prompt_template = 'im/auth/shibboleth_login_prompt.html'
176 class TwitterAuthProvider(AuthProvider):
179 add_prompt = _('Allows you to login to your account using Twitter')
180 details_tpl = _('Twitter screen name: %(info_screen_name)s')
181 user_title = _('Twitter (%(info_screen_name)s)')
185 return reverse('astakos.im.target.twitter.login')
187 login_template = 'im/auth/third_party_provider_generic_login.html'
188 login_prompt_template = 'im/auth/third_party_provider_generic_login_prompt.html'
191 class GoogleAuthProvider(AuthProvider):
194 add_prompt = _('Allows you to login to your account using Google')
195 details_tpl = _('Google account: %(info_email)s')
196 user_title = _('Google (%(info_email)s)')
200 return reverse('astakos.im.target.google.login')
202 login_template = 'im/auth/third_party_provider_generic_login.html'
203 login_prompt_template = 'im/auth/third_party_provider_generic_login_prompt.html'
206 class LinkedInAuthProvider(AuthProvider):
208 title = _('LinkedIn')
209 add_prompt = _('Allows you to login to your account using LinkedIn')
210 user_title = _('LinkedIn (%(info_emailAddress)s)')
211 details_tpl = _('LinkedIn account: %(info_emailAddress)s')
215 return reverse('astakos.im.target.linkedin.login')
217 login_template = 'im/auth/third_party_provider_generic_login.html'
218 login_prompt_template = 'im/auth/third_party_provider_generic_login_prompt.html'
221 def get_provider(id, user_obj=None, default=None):
223 Return a provider instance from the auth providers registry.
225 return PROVIDERS.get(id, default)(user_obj)