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

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