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

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

Experimental code for authenticating Applicants.

Instead of checking the credentials of applicants by resubmitting a
JAMB no and registration number via form on every request, we can also
try to authenticate applicants properly as such deploying the
pluggable authentication utility. That's what we try here.

This stuff is quite complex and needs to be done slowly and step by
step. Right now we have an authenticator plugin that accepts any
username/password combination (if the authenticator plugin is enabled,
which can be done via the Z3-UI).

Next goal is to implement an additional CredentialsPlugin? that
extracts applicant form fields from a request and delivers them as
'the credentials' to the local authentication utility and the
authenticator plugins.

Authenticating applicants properly means that every applicant can be
identified in logs and we have a single properly defined place to care
for permissions.

The drawback is, that infos about logged-in applicants are stored in a
session container, which by default is held in RAM. If thousands of
users try to register simultanously, this might be overkill so that we
might have to rethink about a specialized session container for this
kind of data.

File size: 6.4 KB
Line 
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 (
38    IApplicantPrincipalInfo, IApplicantPrincipal)
39
40class PortalUser(grok.Role):
41    """A role for applicants.
42    """
43    grok.name('waeup.Applicant')
44    grok.permissions('waeup.Public')
45
46class ApplicantAccount(Account):
47    """An account for applicants.
48    """
49    def __init__(self, reg_no, ac):
50        self.name = u'applicant'
51        self.title = u'Applicant'
52        self.description = u'Applicant'
53        self.reg_no = reg_no
54        self.access_code = ac
55        roles = ['waeup.Applicant']
56        self.setRoles(roles)
57
58    def checkPassword(self, reg_no, ac):
59        """Check whether the given credentials exist.
60
61        `reg_no` is a JAMB registration number. `ac` an access code
62        string like ``PUDE-23-1234567890``.
63        """
64        if self.reg_no != reg_no or self.access_code != ac:
65            return False
66        return True
67        site = grok.getSite()
68        if not reg_no in site['applications']:
69            return False
70        data = get_applicant_data(reg_no, ac)
71        if data is None:
72            return False
73        return True
74
75class ApplicantPrincipalInfo(object):
76    grok.implements(IApplicantPrincipalInfo)
77
78    # def __init__(self, id, title, description):
79    def __init__(self, reg_no, access_code):
80        self.id = '%s-%s' % (reg_no, access_code)
81        self.title = u'Applicant'
82        self.description = u'An Applicant'
83        self.credentialsPlugin = None
84        self.authenticatorPlugin = None
85        self.reg_no = reg_no
86        self.access_code = access_code
87
88class ApplicantPrincipal(Principal):
89
90    grok.implements(IApplicantPrincipal)
91
92    def __init__(self, reg_no, access_code):
93        self.id = '%s-%s' % (reg_no, access_code)
94        self.title = u'Applicant'
95        self.description = u'An applicant'
96        self.groups = []
97        self.reg_no = reg_no
98        self.access_code = access_code
99
100    def __repr__(self):
101        return 'ApplicantPrincipal(%r)' % self.id
102
103class AuthenticatedApplicantPrincipalFactory(grok.MultiAdapter):
104    """Creates 'authenticated' applicant principals.
105    """
106    grok.adapts(IApplicantPrincipalInfo, IRequest)
107    grok.implements(IAuthenticatedPrincipalFactory)
108
109    def __init__(self, info, request):
110        self.info = info
111        self.request = request
112
113    def __call__(self, authentication):
114        principal = ApplicantPrincipal(
115            authentication.prefix + self.info.reg_no,
116            self.info.access_code
117            )
118        notify(
119            AuthenticatedPrincipalCreated(
120                authentication, principal, self.info, self.request))
121        return principal
122
123   
124class WAeUPApplicantCredentialsPlugin(grok.GlobalUtility,
125                                      SessionCredentialsPlugin):
126    grok.provides(ICredentialsPlugin)
127    grok.name('applicant_credentials')
128
129    loginpagename = 'login'
130    loginfield = 'form.login'
131    passwordfield = 'form.password'
132
133    def extractCredentials(self, request):
134        """Extracts credentials from a session if they exist.
135
136        This is currently the implementation from zope.pluggableauth.
137
138        XXX: Make this plugin handle login_pde-like input.
139        """
140        if not IHTTPRequest.providedBy(request):
141            return None
142        session = ISession(request)
143        sessionData = session.get(
144            'zope.pluggableauth.browserplugins')
145        login = request.get(self.loginfield, None)
146        password = request.get(self.passwordfield, None)
147        credentials = None
148
149        if login and password:
150            credentials = SessionCredentials(login, password)
151        elif not sessionData:
152            return None
153        sessionData = session[
154            'zope.pluggableauth.browserplugins']
155        if credentials:
156            sessionData['credentials'] = credentials
157        else:
158            credentials = sessionData.get('credentials', None)
159        if not credentials:
160            return None
161        return {'login': credentials.getLogin(),
162                'password': credentials.getPassword()}
163
164
165class ApplicantsAuthenticatorPlugin(grok.GlobalUtility):
166    """Authenticate applicants.
167
168    XXX: This plugin currently accepts any input and authenticates the
169    user as applicant.
170    """
171    grok.provides(IAuthenticatorPlugin)
172    grok.name('applicants')
173
174    def authenticateCredentials(self, credentials):
175        #print "AUTH: ", credentials
176        if not isinstance(credentials, dict):
177            return None
178        if not 'login' in credentials.keys():
179            return None
180        if not 'password' in credentials.keys():
181            return None
182        return ApplicantPrincipalInfo(
183            credentials['login'], credentials['password']
184            )
185
186    def principalInfo(self, id):
187        """Returns an IPrincipalInfo object for the specified principal id.
188
189        Currently we always return ``None``, indicating, that the principal
190        could not be found.
191        """
192        return None
Note: See TracBrowser for help on using the repository browser.