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

Last change on this file since 6670 was 6669, checked in by uli, 13 years ago

First bits of authentication for students. Based on IUserAccount we
simply adapt existing student objects for password verification and
the like.

Also some setup run when a new university is created is already
working.

File size: 5.7 KB
RevLine 
[6669]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
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    @property
56    def roles(self):
57        return getattr(self.context, 'roles', None)
58
59    def setPassword(self, password):
60        """Set a password (LDAP-compatible) SSHA encoded.
61
62        We do not store passwords in plaintext.
63        """
64        passwordmanager = getUtility(IPasswordManager, 'SSHA')
65        self.context.password = passwordmanager.encodePassword(password)
66
67    def checkPassword(self, password):
68        """Check whether the given `password` matches the one stored.
69        """
70        if not isinstance(password, basestring):
71            return False
72        passwordmanager = getUtility(IPasswordManager, 'SSHA')
73        return passwordmanager.checkPassword(self.context.password, password)
74
75class StudentsAuthenticatorPlugin(grok.GlobalUtility):
76    grok.implements(IAuthenticatorPlugin)
77    grok.provides(IAuthenticatorPlugin)
78    grok.name('students')
79
80    def authenticateCredentials(self, credentials):
81        """Authenticate `credentials`.
82
83        `credentials` is a tuple (login, password).
84
85        We look up students to find out whether a respective student
86        exists, then check the password and return the resulting
87        `PrincipalInfo` or ``None`` if no such student can be found.
88        """
89        if not isinstance(credentials, dict):
90            return None
91        if not ('login' in credentials and 'password' in credentials):
92            return None
93        account = self.getAccount(credentials['login'])
94
95        if account is None:
96            return None
97        if not account.checkPassword(credentials['password']):
98            return None
99        return PrincipalInfo(id=account.name,
100                             title=account.title,
101                             description=account.description)
102
103    def principalInfo(self, id):
104        """Get a principal identified by `id`.
105
106        This one is required by IAuthenticatorPlugin.
107        """
108        account = self.getAccount(id)
109        if account is None:
110            return None
111        return PrincipalInfo(id=account.name,
112                             title=account.title,
113                             description=account.description)
114
115    def getAccount(self, login):
116        """Look up a student identified by `login`. Returns an account.
117
118        Currently, we simply look up the key under which the student
119        is stored in the portal. That means we hit if login name and
120        name under which the student is stored match.
121
122        Returns not a student but an account object adapted from any
123        student found.
124
125        If no such student exists, ``None`` is returned.
126        """
127        site = grok.getSite()
128        if site is None:
129            return None
130        studentscontainer = site.get('students', None)
131        if studentscontainer is None:
132            return None
133        student = studentscontainer.get(login, None)
134        if student is None:
135            return None
136        return IUserAccount(student)
137
138    #def addAccount(self, account):
139    #    usercontainer = self.getUserContainer()
140    #    if usercontainer is None:
141    #        return
142    #    # XXX: complain if name already exists...
143    #    usercontainer.addAccount(account)
144
145    #def addUser(self, name, password, title=None, description=None):
146    #    usercontainer = self.getUserContainer()
147    #    if usercontainer is None:
148    #        return
149    #    usercontainer.addUser(name, password, title, description)
150
151    #def getUserContainer(self):
152    #    site = grok.getSite()
153    #    return site['users']
154
155
156class StudentsAuthenticatorSetup(grok.GlobalUtility):
157    """Register or unregister student authentication for a PAU.
158
159    This piece is called when a new site is created.
160    """
161    grok.implements(IAuthPluginUtility)
162
163    def register(self, pau):
164        plugins = list(pau.authenticatorPlugins)
165        plugins.append('students')
166        pau.authenticatorPlugins = tuple(plugins)
167        return pau
168
169    def unregister(self, pau):
170        plugins = [x for x in pau.authenticatorPlugins
171                   if x != 'students']
172        pau.authenticatorPlugins = tuple(plugins)
173        return pau
Note: See TracBrowser for help on using the repository browser.