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

Last change on this file since 5640 was 5497, checked in by uli, 14 years ago

Make applicant credentials work also if other credentials plugins
stored a different structured credentials set in session.

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