source: main/waeup.sirp/trunk/src/waeup/sirp/applicants/authentication.py @ 5806

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

Fix imports of moved helper functions.

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