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
.PluggableAuthService
.plugins
.BasePlugin
import BasePlugin
30 from Products
.PluggableAuthService
.interfaces
.plugins \
31 import IAuthenticationPlugin
33 from zope
.app
.security
.interfaces
import IAuthentication
34 from zope
.interface
import implements
, alsoProvides
35 from zope
.component
import getUtility
36 from zope
.publisher
.interfaces
import IRequest
39 manage_addAuthenticationPluginForm
= PageTemplateFile(
40 '../www/AuthenticationPluginForm',
41 globals(), __name__
='manage_addAuthenticationPluginForm' )
44 def addAuthenticationPlugin( dispatcher
, id, title
=None, REQUEST
=None ):
45 """Add a paula.plonepas AuthenticationPlugin to a PluggableAuthService.
47 plugin
= AuthenticationPlugin(id, title
)
48 dispatcher
._setObject
(plugin
.getId(), plugin
)
50 if REQUEST
is not None:
51 REQUEST
['RESPONSE'].redirect(
53 '?manage_tabs_message='
54 'paula.plonepas.AuthenticationPlugin+added.'
55 % dispatcher
.absolute_url())
58 class AuthenticationPlugin(BasePlugin
):
61 security
= ClassSecurityInfo()
63 implements(IAuthenticationPlugin
)
65 meta_type
= "Paula PAS Authentication Plugin"
67 def __init__(self
, id, title
=None):
68 self
._id
= self
.id = id
71 security
.declarePrivate('authenticateCredentials')
72 def authenticateCredentials(self
, credentials
):
73 """ credentials -> (userid, login)
75 o 'credentials' will be a mapping, as returned by IExtractionPlugin.
77 o Return a tuple consisting of user ID (which may be different
78 from the login name) and login
80 o If the credentials cannot be authenticated, return None.
84 >>> p = Mock(id = 'login')
86 Mockup IAuthentication
88 >>> au = Mock(authenticate = \\
89 ... lambda x : IRequest.providedBy(x) \\
90 ... and x.has_key('login') \\
91 ... and x.has_key('password') \\
93 ... alsoProvides=(IAuthentication,))
94 >>> provideUtility(au, IAuthentication)
96 our authentication plugin
98 >>> ap = AuthenticationPlugin('ap')
103 >>> creds['login'] = 'foo'
104 >>> ap.authenticateCredentials(creds) is None
109 >>> creds['password'] = 'foo'
110 >>> ap.authenticateCredentials(creds)
113 and otherway wrong creds
115 >>> del creds['login']
116 >>> ap.authenticateCredentials(creds) is None
119 pau
= getUtility(IAuthentication
)
121 # pau expects something providing request
122 # our fake credentials plugin is fine with a mapping
123 request
= UserDict
.UserDict(credentials
)
124 alsoProvides(request
, IRequest
)
126 principal
= pau
.authenticate(request
)
128 return (principal
.id, principal
.id)
130 #if credentials['login'] is 'adam':
131 # return ('adam', 'adam')
135 InitializeClass( AuthenticationPlugin
)