source: main/waeup.sirp/trunk/src/waeup/sirp/jambtables/authentication.py @ 5445

Last change on this file since 5445 was 5444, checked in by uli, 14 years ago

Use different fields when authenticating applicants.

File size: 9.4 KB
Line 
1##
2## authentication.py
3## Login : <uli@pu.smp.net>
4## Started on  Tue Jul 27 14:26:35 2010 Uli Fouquet
5## $Id$
6##
7## Copyright (C) 2010 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"""Special authentication for applicants.
23
24   XXX: This is work in progress, experimental code! Don't do that at home!
25"""
26import grok
27from zope.event import notify
28from zope.pluggableauth.factories import Principal
29from zope.pluggableauth.interfaces import (
30    ICredentialsPlugin, IAuthenticatorPlugin, IPrincipalInfo,
31    IAuthenticatedPrincipalFactory, AuthenticatedPrincipalCreated)
32from zope.pluggableauth.plugins.session import SessionCredentialsPlugin
33from zope.publisher.interfaces import IRequest
34from zope.publisher.interfaces.http import IHTTPRequest
35from zope.session.interfaces import ISession
36from waeup.sirp.authentication import Account, PrincipalInfo
37from waeup.sirp.jambtables.interfaces import (
38    IApplicantPrincipalInfo, IApplicantPrincipal, IApplicantSessionCredentials,
39    IJAMBApplicantSessionCredentials)
40from waeup.sirp.jambtables.util import get_applicant_data
41
42class PortalUser(grok.Role):
43    """A role for applicants.
44    """
45    grok.name('waeup.Applicant')
46    grok.permissions('waeup.Public')
47
48class ApplicantAccount(Account):
49    """An account for applicants.
50
51    XXX: Very likely we do not need this at all.
52    """
53    def __init__(self, reg_no, ac):
54        self.name = u'applicant'
55        self.title = u'Applicant'
56        self.description = u'Applicant'
57        self.reg_no = reg_no
58        self.access_code = ac
59        roles = ['waeup.Applicant']
60        self.setRoles(roles)
61
62    def checkPassword(self, reg_no, ac):
63        """Check whether the given credentials exist.
64
65        `reg_no` is a JAMB registration number. `ac` an access code
66        string like ``PUDE-23-1234567890``.
67        """
68        if self.reg_no != reg_no or self.access_code != ac:
69            return False
70        return True
71        site = grok.getSite()
72        if not reg_no in site['applications']:
73            return False
74        data = get_applicant_data(reg_no, ac)
75        if data is None:
76            return False
77        return True
78
79class ApplicantPrincipalInfo(object):
80    """Infos about an applicant principal.
81    """
82    grok.implements(IApplicantPrincipalInfo)
83
84    # def __init__(self, id, title, description):
85    # def __init__(self, reg_no, access_code):
86    def __init__(self, access_code, jamb_reg_no=None):
87        self.id = principal_id(access_code, jamb_reg_no)
88        self.title = u'Applicant'
89        self.description = u'An Applicant'
90        self.credentialsPlugin = None
91        self.authenticatorPlugin = None
92        self.reg_no = jamb_reg_no
93        self.access_code = access_code
94
95class ApplicantPrincipal(Principal):
96    """An applicant principal.
97
98    Applicant principals provide an extra `access_code` and `reg_no`
99    attribute extending ordinary principals.
100    """
101
102    grok.implements(IApplicantPrincipal)
103
104    def __init__(self, reg_no, access_code):
105        self.id = '%s-%s' % (reg_no, access_code)
106        self.title = u'Applicant'
107        self.description = u'An applicant'
108        self.groups = []
109        self.reg_no = reg_no
110        self.access_code = access_code
111
112    def __repr__(self):
113        return 'ApplicantPrincipal(%r)' % self.id
114
115class AuthenticatedApplicantPrincipalFactory(grok.MultiAdapter):
116    """Creates 'authenticated' applicant principals.
117
118    Adapts (principal info, request) to an ApplicantPrincipal instance.
119
120    This adapter is used by the standard PAU to transform
121    PrincipalInfos into Principal instances.
122    """
123    grok.adapts(IApplicantPrincipalInfo, IRequest)
124    grok.implements(IAuthenticatedPrincipalFactory)
125
126    def __init__(self, info, request):
127        self.info = info
128        self.request = request
129
130    def __call__(self, authentication):
131        principal = ApplicantPrincipal(
132            authentication.prefix + self.info.reg_no,
133            self.info.access_code
134            )
135        notify(
136            AuthenticatedPrincipalCreated(
137                authentication, principal, self.info, self.request))
138        return principal
139
140
141#
142# Credentials plugins and related....
143#
144
145class ApplicantCredentials(object):
146    """Credentials class for ordinary applicants.
147    """
148    grok.implements(IApplicantSessionCredentials)
149
150    def __init__(self, access_code):
151        self.access_code = access_code
152
153    def getAccessCode(self):
154        """Get the access code.
155        """
156        return self.access_code
157
158    def getLogin(self):
159        """Stay compatible with non-applicant authenticators.
160        """
161        return None
162
163    def getPassword(self):
164        """Stay compatible with non-applicant authenticators.
165        """
166        return None
167   
168class JAMBApplicantCredentials(ApplicantCredentials):
169    """Credentials class for JAMB-screened applicants.
170    """
171    grok.implements(IJAMBApplicantSessionCredentials)
172
173    def __init__(self, access_code, jamb_reg_no):
174        self.access_code = access_code
175        self.jamb_reg_no = jamb_reg_no
176
177    def getJAMBRegNo(self):
178        """Get the JAMB registration no.
179        """
180        return self.jamb_reg_no
181
182class WAeUPApplicantCredentialsPlugin(grok.GlobalUtility,
183                                      SessionCredentialsPlugin):
184    """A credentials plugin that scans requests for applicant credentials.
185    """
186    grok.provides(ICredentialsPlugin)
187    grok.name('applicant_credentials')
188
189    loginpagename = 'login'
190    accesscode_prefix_field = 'form.prefix'
191    accesscode_series_field = 'form.ac_series'
192    accesscode_number_field = 'form.ac_number'
193    jamb_reg_no_field = 'form.jamb_reg_no'
194
195    def extractCredentials(self, request):
196        """Extracts credentials from a session if they exist.
197        """
198        if not IHTTPRequest.providedBy(request):
199            return None
200        session = ISession(request)
201        sessionData = session.get(
202            'zope.pluggableauth.browserplugins')
203        access_code_prefix = request.get(self.accesscode_prefix_field, None)
204        access_code_series = request.get(self.accesscode_series_field, None)
205        access_code_no = request.get(self.accesscode_number_field, None)
206        jamb_reg_no = request.get(self.jamb_reg_no_field, None)
207        access_code = '%s-%s-%s' % (
208            access_code_prefix, access_code_series, access_code_no)
209        if None in [access_code_prefix, access_code_series, access_code_no]:
210            access_code = None
211        credentials = None
212
213        print "CRED2: %s, %s" % (access_code, jamb_reg_no)
214        if access_code and jamb_reg_no:
215            credentials = JAMBApplicantCredentials(
216                access_code, jamb_reg_no)
217        elif access_code:
218            credentials = ApplicantCredentials(access_code)
219        elif not sessionData:
220            return None
221        sessionData = session[
222            'zope.pluggableauth.browserplugins']
223        if credentials:
224            sessionData['credentials'] = credentials
225        else:
226            credentials = sessionData.get('credentials', None)
227        if not credentials:
228            return None
229        if credentials.getJAMBRegNo() is not None:
230            return {'accesscode': credentials.getAccessCode(),
231                    'jambregno': credentials.getJAMBRegNo()}
232        return {'accesscode': credentials.getAccessCode()}
233
234
235class ApplicantsAuthenticatorPlugin(grok.GlobalUtility):
236    """Authenticate applicants.
237
238    XXX: This plugin currently accepts any input and authenticates the
239    user as applicant.
240    """
241    grok.provides(IAuthenticatorPlugin)
242    grok.name('applicants')
243
244    def authenticateCredentials(self, credentials):
245        #print "AUTH: ", credentials
246        if not isinstance(credentials, dict):
247            return None
248        if not 'accesscode' in credentials.keys():
249            return None
250        if not 'jambregno' in credentials.keys():
251            credentials['jambregno'] = None
252        return ApplicantPrincipalInfo(
253            credentials['accesscode'], credentials['jambregno']
254            # credentials['login'], credentials['password']
255            )
256
257    def principalInfo(self, id):
258        """Returns an IPrincipalInfo object for the specified principal id.
259
260        This method is used by the stadard PAU to lookup for instance
261        groups. If a principal belongs to a group, the group is looked
262        up by the id.  Currently we always return ``None``,
263        indicating, that the principal could not be found. This also
264        means, that is has no effect if applicant users belong to a
265        certain group. They can not gain extra-permissions this way.
266        """
267        return None
268
269def principal_id(access_code, jamb_reg_no=None):
270    """Get a principal ID for applicants.
271
272    We need unique principal ids for appliants. As access codes must
273    be unique we simply return them.
274    """
275    return access_code
Note: See TracBrowser for help on using the repository browser.