1 # Copyright (c) 2008 by Florian Friesdorf
3 # GNU Affero General Public License (AGPL)
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License as
7 # published by the Free Software Foundation; either version 3 of the
8 # License, or (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU Affero General Public License for more details.
15 # You should have received a copy of the GNU Affero General Public
16 # License along with this program. If not, see
17 # <http://www.gnu.org/licenses/>.
20 __author__
= "Florian Friesdorf <flo@chaoflow.net>"
21 __docformat__
= "plaintext"
25 from AccessControl
import ClassSecurityInfo
26 from Globals
import InitializeClass
27 from Products
.PageTemplates
.PageTemplateFile
import PageTemplateFile
29 #from Products.PlonePAS.interfaces.plugins import IUserIntrospection
30 from Products
.PluggableAuthService
.interfaces
.plugins \
31 import IAuthenticationPlugin
32 from Products
.PluggableAuthService
.interfaces
.plugins
import IUserAdderPlugin
33 from Products
.PluggableAuthService
.interfaces
.plugins \
34 import IUserEnumerationPlugin
35 from Products
.PluggableAuthService
.plugins
.BasePlugin
import BasePlugin
37 from zope
.app
.security
.interfaces
import IAuthentication
38 from zope
.app
.security
.interfaces
import PrincipalLookupError
40 from zope
.interface
import implements
, alsoProvides
41 from zope
.component
import getUtility
42 from zope
.publisher
.interfaces
import IRequest
44 from paula
.pasplugins
.tests
.fake_pau_ap
import FAKE_LOGIN
46 manage_addAuthenticationPluginForm
= PageTemplateFile(
47 '../www/AuthenticationPluginForm',
48 globals(), __name__
='manage_addAuthenticationPluginForm' )
51 def addAuthenticationPlugin( dispatcher
, id, title
=None, REQUEST
=None ):
52 """Add a paula.plonepas AuthenticationPlugin to a PluggableAuthService.
54 plugin
= AuthenticationPlugin(id, title
)
55 dispatcher
._setObject
(plugin
.getId(), plugin
)
57 if REQUEST
is not None:
58 REQUEST
['RESPONSE'].redirect(
60 '?manage_tabs_message='
61 'paula.pasplugins.AuthenticationPlugin+added.'
62 % dispatcher
.absolute_url())
65 class AuthenticationPlugin(BasePlugin
):
68 security
= ClassSecurityInfo()
71 IAuthenticationPlugin
,
72 IUserEnumerationPlugin
,
77 meta_type
= "Paula PAS Authentication Plugin"
79 def __init__(self
, id, title
=None):
80 self
._id
= self
.id = id
83 # IAuthenticationPlugin
85 security
.declarePrivate('authenticateCredentials')
86 def authenticateCredentials(self
, credentials
):
87 """ credentials -> (userid, login)
89 o 'credentials' will be a mapping, as returned by IExtractionPlugin.
91 o Return a tuple consisting of user ID (which may be different
92 from the login name) and login
94 o If the credentials cannot be authenticated, return None.
98 >>> p = Mock(id = 'login')
100 Mockup IPluggableAuthentication
102 >>> au = Mock(authenticate = \\
103 ... lambda x : IRequest.providedBy(x) \\
104 ... and x.has_key('login') \\
105 ... and x.has_key('password') \\
107 ... alsoProvides=(IAuthentication,))
108 >>> provideUtility(au, IAuthentication)
110 our authentication plugin
112 >>> ap = AuthenticationPlugin('ap')
117 >>> creds['login'] = 'foo'
118 >>> ap.authenticateCredentials(creds) is None
123 >>> creds['password'] = 'foo'
124 >>> ap.authenticateCredentials(creds)
127 and otherway wrong creds
129 >>> del creds['login']
130 >>> ap.authenticateCredentials(creds) is None
133 pau
= getUtility(IAuthentication
)
135 # pau expects something providing request
136 # our fake credentials plugin is fine with a mapping
137 request
= UserDict
.UserDict(credentials
)
138 alsoProvides(request
, IRequest
)
140 principal
= pau
.authenticate(request
)
142 return (principal
.id, principal
.id)
144 #if credentials['login'] is 'adam':
145 # return ('adam', 'adam')
151 security
.declarePrivate( 'enumerateUsers' )
152 def doAddUser(self
, login
, password
):
153 # if successful add return True
158 # IUserEnumerationPlugin
160 security
.declarePrivate( 'enumerateUsers' )
161 def enumerateUsers( self
169 pau
= getUtility(IAuthentication
)
171 #XXX: currently we only know exact match
173 if exact_match
or not exact_match
:
174 #XXX: id and login are treated equal - fixme!
176 principal
= pau
.getPrincipal( id or login
)
177 except PrincipalLookupError
:
180 #XXX: do something with the data from the returned principal?!
183 'login': login
or id,
184 'pluginid': self
.getId(),
189 #security.declarePrivate('getUserIds')
190 #def getUserIds(self):
191 # return ('fakelogin',)
195 #security.declarePrivate('getUserNames')
196 #def getUserNames(self):
197 # return ('fakelogin',)
201 #security.declarePrivate('getUsers')
204 # Return a list of users
206 # XXX DON'T USE THIS, it will kill performance
208 # uf = getToolByName(self, 'acl_users')
209 # return tuple([uf.getUserById(x) for x in self.getUserIds()])
212 InitializeClass( AuthenticationPlugin
)