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 Globals
import InitializeClass
26 from Products
.PageTemplates
.PageTemplateFile
import PageTemplateFile
28 from Products
.PlonePAS
.interfaces
.capabilities
import IDeleteCapability
29 from Products
.PlonePAS
.interfaces
.capabilities
import IPasswordSetCapability
30 from Products
.PlonePAS
.interfaces
.plugins
import IUserIntrospection
31 from Products
.PlonePAS
.interfaces
.plugins
import IUserManagement
33 from Products
.PluggableAuthService
.interfaces
.plugins \
34 import IAuthenticationPlugin
35 from Products
.PluggableAuthService
.interfaces
.plugins
import IUserAdderPlugin
36 from Products
.PluggableAuthService
.interfaces
.plugins \
37 import IUserEnumerationPlugin
39 from Products
.PluggableAuthService
.plugins
.BasePlugin
import BasePlugin
41 from zope
.app
.security
.interfaces
import IAuthentication
42 from zope
.app
.security
.interfaces
import PrincipalLookupError
44 from zope
.interface
import implements
, alsoProvides
45 from zope
.component
import getUtility
46 from zope
.publisher
.interfaces
import IRequest
48 from paula
.pasplugins
.tests
.fake_pau_ap
import FAKE_LOGIN
50 manage_addAuthenticationPluginForm
= PageTemplateFile(
51 '../www/AuthenticationPluginForm',
52 globals(), __name__
='manage_addAuthenticationPluginForm' )
55 def addAuthenticationPlugin( dispatcher
, id, title
=None, REQUEST
=None ):
56 """Add a paula.plonepas AuthenticationPlugin to a PluggableAuthService.
58 plugin
= AuthenticationPlugin(id, title
)
59 dispatcher
._setObject
(plugin
.getId(), plugin
)
61 if REQUEST
is not None:
62 REQUEST
['RESPONSE'].redirect(
64 '?manage_tabs_message='
65 'paula.pasplugins.AuthenticationPlugin+added.'
66 % dispatcher
.absolute_url())
70 IAuthenticationPlugin
,
72 IUserEnumerationPlugin
,
77 class AuthenticationPlugin(BasePlugin
):
82 IPasswordSetCapability
,
86 meta_type
= "Paula PAS Authentication Plugin"
88 def __init__(self
, id, title
=None):
89 self
._id
= self
.id = id
92 # IAuthenticationPlugin
94 def authenticateCredentials(self
, credentials
):
95 """ credentials -> (userid, login)
97 o 'credentials' will be a mapping, as returned by IExtractionPlugin.
99 o Return a tuple consisting of user ID (which may be different
100 from the login name) and login
102 o If the credentials cannot be authenticated, return None.
106 >>> p = Mock(id = 'login')
108 Mockup IPluggableAuthentication
110 >>> au = Mock(authenticate = \\
111 ... lambda x : IRequest.providedBy(x) \\
112 ... and x.has_key('login') \\
113 ... and x.has_key('password') \\
115 ... alsoProvides=(IAuthentication,))
116 >>> provideUtility(au, IAuthentication)
118 our authentication plugin
120 >>> ap = AuthenticationPlugin('ap')
125 >>> creds['login'] = 'foo'
126 >>> ap.authenticateCredentials(creds) is None
131 >>> creds['password'] = 'foo'
132 >>> ap.authenticateCredentials(creds)
135 and otherway wrong creds
137 >>> del creds['login']
138 >>> ap.authenticateCredentials(creds) is None
141 pau
= getUtility(IAuthentication
)
143 # pau expects something providing request
144 # our fake credentials plugin is fine with a mapping
145 request
= UserDict
.UserDict(credentials
)
146 alsoProvides(request
, IRequest
)
148 principal
= pau
.authenticate(request
)
150 return (principal
.id, principal
.id)
152 #if credentials['login'] is 'adam':
153 # return ('adam', 'adam')
159 def doAddUser(self
, login
, password
):
160 """ Add a user record to a User Manager, with the given login
163 o Return a Boolean indicating whether a user was added or not
165 pau
= getUtility(IAuthentication
)
166 if pau
.addUser(login
, password
):
174 def allowDeletePrincipal(self
, id):
175 """True iff this plugin can delete a certain user/group.
177 #XXX: We need to check with PAU whether we can delete the principal
178 pau
= getUtility(IAuthentication
)
179 return pau
.allowDeletePrincipal(id)
181 # IPasswordSetCapability
183 def allowPasswordSet(self
, id):
184 """True iff this plugin can set the password of a certain user.
186 pau
= getUtility(IAuthentication
)
187 return pau
.allowPasswordSet(id)
191 def doChangeUser(self
, login
, password
, **kws
):
193 Change a user's password (differs from role) roles are set in
194 the pas engine api for the same but are set via a role
197 pau
= getUtility(IAuthentication
)
198 if not pau
.doChangeUser(login
, password
, **kws
):
199 # maybe should be moved to the PAU auth plugins
202 def doDeleteUser(self
, login
):
204 Remove a user record from a User Manager, with the given login
207 o Return a Boolean indicating whether a user was removed or
210 pau
= getUtility(IAuthentication
)
211 return pau
.delPrincipal(login
)
213 # IUserEnumerationPlugin
215 def enumerateUsers( self
223 pau
= getUtility(IAuthentication
)
226 #XXX: id and login are treated equal - fixme!
228 principal
= pau
.getPrincipal( id or login
)
229 except PrincipalLookupError
:
232 #XXX: do something with the data from the returned principal?!
235 'login': login
or id,
236 'pluginid': self
.getId(),
239 # XXX: no exact_match, we need to search for the user in PAU
241 # # IUserIntrospection
243 # def getUserIds(self):
244 # # called eg when going into the memberdata tool contents
245 # return ('fakelogin',)
247 # # IUserIntrospection
249 # def getUserNames(self):
250 # return ('fakelogin',)
252 # # IUserIntrospection
254 # def getUsers(self):
256 # Return a list of users
258 # XXX DON'T USE THIS, it will kill performance
260 # uf = getToolByName(self, 'acl_users')
261 # return tuple([uf.getUserById(x) for x in self.getUserIds()])
264 InitializeClass( AuthenticationPlugin
)