source: main/waeup.sirp/trunk/src/waeup/sirp/students/authentication.py @ 6688

Last change on this file since 6688 was 6680, checked in by uli, 13 years ago

Add support for assigning roles to student accounts and let password setter create unicode passwords.

File size: 5.9 KB
Line 
1##
2## authentication.py
3## Login : <uli@pu.smp.net>
4## Started on  Fri Sep  2 15:22:47 2011 Uli Fouquet
5## $Id$
6##
7## Copyright (C) 2011 Uli Fouquet
8## This program is free software; you can redistribute it and/or modify
9## it under the terms of the GNU General Public License as published by
10## the Free Software Foundation; either version 2 of the License, or
11## (at your option) any later version.
12##
13## This program is distributed in the hope that it will be useful,
14## but WITHOUT ANY WARRANTY; without even the implied warranty of
15## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16## GNU General Public License for more details.
17##
18## You should have received a copy of the GNU General Public License
19## along with this program; if not, write to the Free Software
20## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21##
22"""
23Authenticate students.
24"""
25import grok
26from zope.component import getUtility
27from zope.password.interfaces import IPasswordManager
28from zope.pluggableauth.interfaces import IAuthenticatorPlugin
29from waeup.sirp.authentication import PrincipalInfo, get_principal_role_manager
30from waeup.sirp.interfaces import IAuthPluginUtility, IUserAccount
31from waeup.sirp.students.interfaces import IStudent
32
33class StudentAccount(grok.Adapter):
34    """An adapter to turn student objects into accounts on-the-fly.
35    """
36    grok.context(IStudent)
37    grok.implements(IUserAccount)
38
39    @property
40    def name(self):
41        return self.context.student_id
42
43    @property
44    def password(self):
45        return getattr(self.context, 'password', None)
46
47    @property
48    def title(self):
49        return self.context.name
50
51    @property
52    def description(self):
53        return self.title
54
55    def _get_roles(self):
56        prm = get_principal_role_manager()
57        roles = [x[0] for x in prm.getRolesForPrincipal(self.name)
58                 if x[0].startswith('waeup.')]
59        return roles
60
61    def _set_roles(self, roles):
62        """Set roles for principal denoted by this account.
63        """
64        prm = get_principal_role_manager()
65        old_roles = self.roles
66        for role in old_roles:
67            # Remove old roles, not to be set now...
68            if role.startswith('waeup.') and role not in roles:
69                prm.unsetRoleForPrincipal(role, self.name)
70        for role in roles:
71            prm.assignRoleToPrincipal(role, self.name)
72        return
73
74    roles = property(_get_roles, _set_roles)
75
76    def setPassword(self, password):
77        """Set a password (LDAP-compatible) SSHA encoded.
78
79        We do not store passwords in plaintext. Encrypted password is
80        stored as unicode string.
81        """
82        passwordmanager = getUtility(IPasswordManager, 'SSHA')
83        self.context.password = u'%s' % (
84            passwordmanager.encodePassword(password))
85
86    def checkPassword(self, password):
87        """Check whether the given `password` matches the one stored.
88        """
89        if not isinstance(password, basestring):
90            return False
91        passwordmanager = getUtility(IPasswordManager, 'SSHA')
92        return passwordmanager.checkPassword(
93            self.context.password.encode('utf-8'), # turn unicode into bytes
94            password)
95
96class StudentsAuthenticatorPlugin(grok.GlobalUtility):
97    grok.implements(IAuthenticatorPlugin)
98    grok.provides(IAuthenticatorPlugin)
99    grok.name('students')
100
101    def authenticateCredentials(self, credentials):
102        """Authenticate `credentials`.
103
104        `credentials` is a tuple (login, password).
105
106        We look up students to find out whether a respective student
107        exists, then check the password and return the resulting
108        `PrincipalInfo` or ``None`` if no such student can be found.
109        """
110        if not isinstance(credentials, dict):
111            return None
112        if not ('login' in credentials and 'password' in credentials):
113            return None
114        account = self.getAccount(credentials['login'])
115
116        if account is None:
117            return None
118        if not account.checkPassword(credentials['password']):
119            return None
120        return PrincipalInfo(id=account.name,
121                             title=account.title,
122                             description=account.description)
123
124    def principalInfo(self, id):
125        """Get a principal identified by `id`.
126
127        This one is required by IAuthenticatorPlugin.
128        """
129        account = self.getAccount(id)
130        if account is None:
131            return None
132        return PrincipalInfo(id=account.name,
133                             title=account.title,
134                             description=account.description)
135
136    def getAccount(self, login):
137        """Look up a student identified by `login`. Returns an account.
138
139        Currently, we simply look up the key under which the student
140        is stored in the portal. That means we hit if login name and
141        name under which the student is stored match.
142
143        Returns not a student but an account object adapted from any
144        student found.
145
146        If no such student exists, ``None`` is returned.
147        """
148        site = grok.getSite()
149        if site is None:
150            return None
151        studentscontainer = site.get('students', None)
152        if studentscontainer is None:
153            return None
154        student = studentscontainer.get(login, None)
155        if student is None:
156            return None
157        return IUserAccount(student)
158
159class StudentsAuthenticatorSetup(grok.GlobalUtility):
160    """Register or unregister student authentication for a PAU.
161
162    This piece is called when a new site is created.
163    """
164    grok.implements(IAuthPluginUtility)
165
166    def register(self, pau):
167        plugins = list(pau.authenticatorPlugins)
168        plugins.append('students')
169        pau.authenticatorPlugins = tuple(plugins)
170        return pau
171
172    def unregister(self, pau):
173        plugins = [x for x in pau.authenticatorPlugins
174                   if x != 'students']
175        pau.authenticatorPlugins = tuple(plugins)
176        return pau
Note: See TracBrowser for help on using the repository browser.