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

Last change on this file since 5451 was 5447, checked in by uli, 14 years ago

Move 'get_access_code' to the accesscodes subpackage.

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