Back to index

plone3  3.1.7
plugins.py
Go to the documentation of this file.
00001 ##############################################################################
00002 #
00003 # Copyright (c) 2001 Zope Corporation and Contributors. All Rights
00004 # Reserved.
00005 #
00006 # This software is subject to the provisions of the Zope Public License,
00007 # Version 2.1 (ZPL).  A copy of the ZPL should accompany this
00008 # distribution.
00009 # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
00010 # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00011 # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
00012 # FOR A PARTICULAR PURPOSE.
00013 #
00014 ##############################################################################
00015 """ Interfaces for PluggableAuthService
00016 
00017 $Id: plugins.py 76647 2007-06-12 20:18:02Z wichert $
00018 """
00019 
00020 try:
00021     from zope.interface import Interface
00022 except ImportError:
00023     from Interface import Interface
00024 
00025 class IExtractionPlugin( Interface ):
00026 
00027     """ Extracts login name and credentials from a request.
00028     """
00029 
00030     def extractCredentials( request ):
00031 
00032         """ request -> {...}
00033 
00034         o Return a mapping of any derived credentials.
00035 
00036         o Return an empty mapping to indicate that the plugin found no
00037           appropriate credentials.
00038         """
00039 
00040 class ILoginPasswordExtractionPlugin( IExtractionPlugin ):
00041 
00042     """ Common-case derivative.
00043     """
00044 
00045     def extractCredentials( request ):
00046 
00047         """ request -> { 'login' : login 
00048                        , 'password' : password 
00049                        , k1 : v1
00050                        ,   ...
00051                        , kN : vN
00052                        } | {}
00053 
00054         o If credentials are found, the returned mapping will contain at
00055           least 'login' and 'password' keys, with the password in plaintext.
00056 
00057         o Return an empty mapping to indicate that the plugin found no
00058           appropriate credentials.
00059         """
00060 
00061 class ILoginPasswordHostExtractionPlugin( ILoginPasswordExtractionPlugin ):
00062 
00063     """ Common-case derivative.
00064     """
00065 
00066     def extractCredentials( request ):
00067 
00068         """ request -> { 'login' : login 
00069                        , 'password' : password 
00070                        , 'remote_host' : remote_host
00071                        , 'remote_addr' : remote_addr
00072                        , k1 : v1
00073                        ,   ...
00074                        , kN : vN
00075                        } | {}
00076 
00077         o If credentials are found, the returned mapping will contain at
00078           least 'login', 'password', 'remote_host' and 'remote_addr' keys,
00079           with the password in plaintext.
00080 
00081         o Return an empty mapping to indicate that the plugin found no
00082           appropriate credentials.
00083         """
00084 
00085 class IAuthenticationPlugin( Interface ):
00086 
00087     """ Map credentials to a user ID.
00088     """
00089 
00090     def authenticateCredentials( credentials ):
00091 
00092         """ credentials -> (userid, login)
00093 
00094         o 'credentials' will be a mapping, as returned by IExtractionPlugin.
00095 
00096         o Return a  tuple consisting of user ID (which may be different 
00097           from the login name) and login
00098 
00099         o If the credentials cannot be authenticated, return None.
00100         """
00101 
00102 class IChallengePlugin( Interface ):
00103 
00104     """ Initiate a challenge to the user to provide credentials.
00105 
00106         Challenge plugins have an attribute 'protocol' representing
00107         the protocol the plugin operates under, defaulting to None.
00108 
00109         Plugins operating under the same protocol will all be given an
00110         attempt to fire. The first plugin of a protocol group that
00111         successfully fires establishes the protocol of the overall
00112         challenge.
00113     """
00114 
00115     def challenge( request, response ):
00116 
00117         """ Assert via the response that credentials will be gathered.
00118 
00119         Takes a REQUEST object and a RESPONSE object.
00120 
00121         Returns True if it fired, False otherwise.
00122 
00123         Two common ways to initiate a challenge:
00124 
00125           - Add a 'WWW-Authenticate' header to the response object.
00126 
00127             NOTE: add, since the HTTP spec specifically allows for
00128             more than one challenge in a given response.
00129 
00130           - Cause the response object to redirect to another URL (a
00131             login form page, for instance)
00132         """
00133 
00134 class ICredentialsUpdatePlugin( Interface ):
00135 
00136     """ Callback:  user has changed her password.
00137 
00138     This interface is not responsible for the actual password change,
00139     it is used after a successful password change event.
00140     """
00141 
00142     def updateCredentials( request, response, login, new_password ):
00143 
00144         """ Scribble as appropriate.
00145         """
00146 
00147 class ICredentialsResetPlugin( Interface ):
00148 
00149     """ Callback:  user has logged out.
00150     """
00151 
00152     def resetCredentials( request, response ):
00153 
00154         """ Scribble as appropriate.
00155         """
00156 
00157 class IUserAdderPlugin( Interface ):
00158 
00159     """ Create a new user record in a User Manager
00160     """
00161 
00162     def doAddUser( login, password ):
00163 
00164         """ Add a user record to a User Manager, with the given login
00165             and password
00166 
00167         o Return a Boolean indicating whether a user was added or not
00168         """
00169 
00170 class IRoleAssignerPlugin( Interface ):
00171 
00172     """ Assign a role to an identified principal
00173     """
00174 
00175     def doAssignRoleToPrincipal( principal_id, role ):
00176 
00177         """ Create a principal/role association in a Role Manager
00178 
00179         o Return a Boolean indicating whether the role was assigned or not
00180         """
00181 
00182     def doRemoveRoleFromPrincipal( principal_id, role ):
00183 
00184         """ Remove a principal/role association from a Role Manager
00185 
00186         o Return a Boolean indicating whether the role was removed or not
00187         """
00188 
00189 class IUserFactoryPlugin( Interface ):
00190 
00191     """ Create a new IPropertiedUser.
00192     """
00193 
00194     def createUser( user_id, name ):
00195 
00196         """ Return a user, if possible.
00197 
00198         o Return None to allow another plugin, or the default, to fire.
00199         """
00200 
00201 class IAnonymousUserFactoryPlugin( Interface ):
00202 
00203     """ Create a new anonymous IPropertiedUser.
00204     """
00205 
00206     def createAnonymousUser():
00207 
00208         """ Return an anonymous user, if possible.
00209 
00210         o Return None to allow another plugin, or the default, to fire.
00211         """
00212 
00213 class IPropertiesPlugin( Interface ):
00214 
00215     """ Return a property set for a user.
00216     """
00217 
00218     def getPropertiesForUser( user, request=None ):
00219 
00220         """ user -> {}
00221 
00222         o User will implement IPropertiedUser.
00223 
00224         o Plugin should return a dictionary or an object providing
00225           IPropertiesPlugin.
00226 
00227         o Plugin may scribble on the user, if needed (but must still
00228           return a mapping, even if empty).
00229 
00230         o May assign properties based on values in the REQUEST object, if
00231           present
00232         """
00233 
00234 class IGroupsPlugin( Interface ):
00235 
00236     """ Determine the groups to which a user belongs.
00237     """
00238 
00239     def getGroupsForPrincipal( principal, request=None ):
00240 
00241         """ principal -> ( group_1, ... group_N )
00242 
00243         o Return a sequence of group names to which the principal 
00244           (either a user or another group) belongs.
00245 
00246         o May assign groups based on values in the REQUEST object, if present
00247         """
00248 
00249 class IRolesPlugin( Interface ):
00250 
00251     """ Determine the (global) roles which a user has.
00252     """
00253 
00254     def getRolesForPrincipal( principal, request=None ):
00255 
00256         """ principal -> ( role_1, ... role_N )
00257 
00258         o Return a sequence of role names which the principal has.
00259 
00260         o May assign roles based on values in the REQUEST object, if present.
00261         """
00262 
00263 class IUpdatePlugin( Interface ):
00264 
00265     """ Allow the user or the application to update the user's properties.
00266     """
00267 
00268     def updateUserInfo( user, set_id, set_info ):
00269 
00270         """ Update backing store for 'set_id' using 'set_info'.
00271         """
00272 
00273 class IValidationPlugin( Interface ):
00274 
00275     """ Specify allowable values for user properties.
00276 
00277     o E.g., constrain minimum password length, allowed characters, etc.
00278 
00279     o Operate on entire property sets, not individual properties.
00280     """
00281 
00282     def validateUserInfo( user, set_id, set_info ):
00283 
00284         """ -> ( error_info_1, ... error_info_N )
00285 
00286         o Returned values are dictionaries, containing at least keys:
00287 
00288           'id' -- the ID of the property, or None if the error is not
00289                   specific to one property.
00290 
00291           'error' -- the message string, suitable for display to the user.
00292         """
00293 
00294 class IUserEnumerationPlugin( Interface ):
00295 
00296     """ Allow querying users by ID, and searching for users.
00297 
00298     o XXX:  can these be done by a single plugin?
00299     """
00300 
00301     def enumerateUsers( id=None
00302                       , login=None
00303                       , exact_match=False
00304                       , sort_by=None
00305                       , max_results=None
00306                       , **kw
00307                       ):
00308 
00309         """ -> ( user_info_1, ... user_info_N )
00310 
00311         o Return mappings for users matching the given criteria.
00312 
00313         o 'id' or 'login', in combination with 'exact_match' true, will
00314           return at most one mapping per supplied ID ('id' and 'login'
00315           may be sequences).
00316 
00317         o If 'exact_match' is False, then 'id' and / or login may be
00318           treated by the plugin as "contains" searches (more complicated
00319           searches may be supported by some plugins using other keyword
00320           arguments).
00321 
00322         o If 'sort_by' is passed, the results will be sorted accordingly.
00323           known valid values are 'id' and 'login' (some plugins may support
00324           others).
00325 
00326         o If 'max_results' is specified, it must be a positive integer,
00327           limiting the number of returned mappings.  If unspecified, the
00328           plugin should return mappings for all users satisfying the criteria.
00329 
00330         o Minimal keys in the returned mappings:
00331         
00332           'id' -- (required) the user ID, which may be different than
00333                   the login name
00334 
00335           'login' -- (required) the login name
00336 
00337           'pluginid' -- (required) the plugin ID (as returned by getId())
00338 
00339           'editurl' -- (optional) the URL to a page for updating the
00340                        mapping's user
00341 
00342         o Plugin *must* ignore unknown criteria.
00343 
00344         o Plugin may raise ValueError for invalid criteria.
00345 
00346         o Insufficiently-specified criteria may have catastrophic
00347           scaling issues for some implementations.
00348         """
00349 
00350 class IGroupEnumerationPlugin( Interface ):
00351 
00352     """ Allow querying groups by ID, and searching for groups.
00353 
00354     o XXX:  can these be done by a single plugin?
00355     """
00356 
00357     def enumerateGroups( id=None
00358                        , exact_match=False
00359                        , sort_by=None
00360                        , max_results=None
00361                        , **kw
00362                        ):
00363 
00364         """ -> ( group_info_1, ... group_info_N )
00365 
00366         o Return mappings for groups matching the given criteria.
00367 
00368         o 'id' in combination with 'exact_match' true, will
00369           return at most one mapping per supplied ID ('id' and 'login'
00370           may be sequences).
00371 
00372         o If 'exact_match' is False, then 'id' may be treated by 
00373           the plugin as "contains" searches (more complicated searches 
00374           may be supported by some plugins using other keyword arguments).
00375 
00376         o If 'sort_by' is passed, the results will be sorted accordingly.
00377           known valid values are 'id' (some plugins may support others).
00378 
00379         o If 'max_results' is specified, it must be a positive integer,
00380           limiting the number of returned mappings.  If unspecified, the
00381           plugin should return mappings for all groups satisfying the 
00382           criteria.
00383 
00384         o Minimal keys in the returned mappings:
00385         
00386           'id' -- (required) the group ID
00387 
00388           'pluginid' -- (required) the plugin ID (as returned by getId())
00389 
00390           'properties_url' -- (optional) the URL to a page for updating the
00391                               group's properties.
00392 
00393           'members_url' -- (optional) the URL to a page for updating the
00394                            principals who belong to the group.
00395 
00396         o Plugin *must* ignore unknown criteria.
00397 
00398         o Plugin may raise ValueError for invalid critera.
00399 
00400         o Insufficiently-specified criteria may have catastrophic
00401           scaling issues for some implementations.
00402         """
00403 
00404 class IRoleEnumerationPlugin( Interface ):
00405 
00406     """ Allow querying roles by ID, and searching for roles.
00407     """
00408     def enumerateRoles( id=None
00409                       , exact_match=False
00410                       , sort_by=None
00411                       , max_results=None
00412                       , **kw
00413                       ):
00414 
00415         """ -> ( role_info_1, ... role_info_N )
00416 
00417         o Return mappings for roles matching the given criteria.
00418 
00419         o 'id' in combination with 'exact_match' true, will
00420           return at most one mapping per supplied ID ('id' and 'login'
00421           may be sequences).
00422 
00423         o If 'exact_match' is False, then 'id' may be treated by 
00424           the plugin as "contains" searches (more complicated searches 
00425           may be supported by some plugins using other keyword arguments).
00426 
00427         o If 'sort_by' is passed, the results will be sorted accordingly.
00428           known valid values are 'id' (some plugins may support others).
00429 
00430         o If 'max_results' is specified, it must be a positive integer,
00431           limiting the number of returned mappings.  If unspecified, the
00432           plugin should return mappings for all roles satisfying the 
00433           criteria.
00434 
00435         o Minimal keys in the returned mappings:
00436         
00437           'id' -- (required) the role ID
00438 
00439           'pluginid' -- (required) the plugin ID (as returned by getId())
00440 
00441           'properties_url' -- (optional) the URL to a page for updating the
00442                               role's properties.
00443 
00444           'members_url' -- (optional) the URL to a page for updating the
00445                            principals to whom the role is assigned.
00446 
00447         o Plugin *must* ignore unknown criteria.
00448 
00449         o Plugin may raise ValueError for invalid critera.
00450 
00451         o Insufficiently-specified criteria may have catastrophic
00452           scaling issues for some implementations.
00453         """
00454 
00455 class IRequestTypeSniffer( Interface ):
00456 
00457     """ Given a request, detects the request type for later use by other plugins.
00458     """
00459     def sniffRequestType( request ):
00460         """ Return a interface identifying what kind the request is.
00461         """
00462 
00463 class IChallengeProtocolChooser( Interface ):
00464 
00465     """ Choose a proper set of protocols to be used for challenging
00466     the client given a request.
00467     """
00468     def chooseProtocols( request ):
00469         """ -> ( protocol_1, ... protocol_N) | None
00470         
00471         o If a set of protocols is returned, the first plugin with a
00472             protocol that is in the set will define the protocol to be
00473             used for the current request.
00474 
00475         o If None is returned, the 'first found protocol' wins.
00476 
00477         o Once the protocol is decided, all challenge plugins for that
00478             protocol will be executed.
00479         """
00480 #
00481 #   XXX:  Do we need a LocalRoleAlgorithm plugin type?  E.g., base_cms
00482 #         has two different algorithms, based on whether or not the
00483 #         context object implements IPlacelessSecurity.
00484 #