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

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

Add a utility that will modify an existing PAU so that the applicants
specific authenticators and credentials plugins are added to that PAU.

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