## ## authentication.py ## Login : ## Started on Fri Sep 2 15:22:47 2011 Uli Fouquet ## $Id$ ## ## Copyright (C) 2011 Uli Fouquet ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as published by ## the Free Software Foundation; either version 2 of the License, or ## (at your option) any later version. ## ## This program is distributed in the hope that it will be useful, ## but WITHOUT ANY WARRANTY; without even the implied warranty of ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ## GNU General Public License for more details. ## ## You should have received a copy of the GNU General Public License ## along with this program; if not, write to the Free Software ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ## """ Authenticate students. """ import grok from zope.component import getUtility from zope.password.interfaces import IPasswordManager from zope.pluggableauth.interfaces import IAuthenticatorPlugin from waeup.sirp.authentication import PrincipalInfo, get_principal_role_manager from waeup.sirp.interfaces import IAuthPluginUtility, IUserAccount from waeup.sirp.students.interfaces import IStudent class StudentAccount(grok.Adapter): """An adapter to turn student objects into accounts on-the-fly. """ grok.context(IStudent) grok.implements(IUserAccount) @property def name(self): return self.context.student_id @property def password(self): return getattr(self.context, 'password', None) @property def title(self): return self.context.name @property def description(self): return self.title def _get_roles(self): prm = get_principal_role_manager() roles = [x[0] for x in prm.getRolesForPrincipal(self.name) if x[0].startswith('waeup.')] return roles def _set_roles(self, roles): """Set roles for principal denoted by this account. """ prm = get_principal_role_manager() old_roles = self.roles for role in old_roles: # Remove old roles, not to be set now... if role.startswith('waeup.') and role not in roles: prm.unsetRoleForPrincipal(role, self.name) for role in roles: prm.assignRoleToPrincipal(role, self.name) return roles = property(_get_roles, _set_roles) def setPassword(self, password): """Set a password (LDAP-compatible) SSHA encoded. We do not store passwords in plaintext. Encrypted password is stored as unicode string. """ passwordmanager = getUtility(IPasswordManager, 'SSHA') self.context.password = u'%s' % ( passwordmanager.encodePassword(password)) def checkPassword(self, password): """Check whether the given `password` matches the one stored. """ if not isinstance(password, basestring): return False passwordmanager = getUtility(IPasswordManager, 'SSHA') return passwordmanager.checkPassword( self.context.password.encode('utf-8'), # turn unicode into bytes password) class StudentsAuthenticatorPlugin(grok.GlobalUtility): grok.implements(IAuthenticatorPlugin) grok.provides(IAuthenticatorPlugin) grok.name('students') def authenticateCredentials(self, credentials): """Authenticate `credentials`. `credentials` is a tuple (login, password). We look up students to find out whether a respective student exists, then check the password and return the resulting `PrincipalInfo` or ``None`` if no such student can be found. """ if not isinstance(credentials, dict): return None if not ('login' in credentials and 'password' in credentials): return None account = self.getAccount(credentials['login']) if account is None: return None if not account.checkPassword(credentials['password']): return None return PrincipalInfo(id=account.name, title=account.title, description=account.description) def principalInfo(self, id): """Get a principal identified by `id`. This one is required by IAuthenticatorPlugin. """ account = self.getAccount(id) if account is None: return None return PrincipalInfo(id=account.name, title=account.title, description=account.description) def getAccount(self, login): """Look up a student identified by `login`. Returns an account. Currently, we simply look up the key under which the student is stored in the portal. That means we hit if login name and name under which the student is stored match. Returns not a student but an account object adapted from any student found. If no such student exists, ``None`` is returned. """ site = grok.getSite() if site is None: return None studentscontainer = site.get('students', None) if studentscontainer is None: return None student = studentscontainer.get(login, None) if student is None: return None return IUserAccount(student) class StudentsAuthenticatorSetup(grok.GlobalUtility): """Register or unregister student authentication for a PAU. This piece is called when a new site is created. """ grok.implements(IAuthPluginUtility) def register(self, pau): plugins = list(pau.authenticatorPlugins) plugins.append('students') pau.authenticatorPlugins = tuple(plugins) return pau def unregister(self, pau): plugins = [x for x in pau.authenticatorPlugins if x != 'students'] pau.authenticatorPlugins = tuple(plugins) return pau