Back to index

plone3  3.1.7
PropertiedUser.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 """ Classes:  PropertiedUser
00016 
00017 $Id: PropertiedUser.py 76647 2007-06-12 20:18:02Z wichert $
00018 """
00019 
00020 from Acquisition import aq_inner, aq_parent
00021 from AccessControl.User import BasicUser
00022 from AccessControl.PermissionRole import _what_not_even_god_should_do
00023 
00024 from interfaces.authservice import IPropertiedUser
00025 from UserPropertySheet import UserPropertySheet
00026 from utils import classImplements
00027 from Products.PluggableAuthService.interfaces.propertysheets \
00028     import IPropertySheet
00029 
00030 class PropertiedUser( BasicUser ):
00031 
00032     """ User objects which manage propertysheets, obtained from decorators.
00033     """
00034     def __init__( self, id, login=None ):
00035 
00036         self._id = id
00037 
00038         if login is None:
00039             login = id
00040 
00041         self._login = login
00042 
00043         self._propertysheets = {}   # *Not* persistent!
00044         self._groups = {}
00045         self._roles = {}
00046 
00047 
00048     #
00049     #   BasicUser's public interface
00050     #
00051     def getId( self ):
00052 
00053         """ -> user ID
00054         """
00055         return self._id
00056 
00057     def getUserName( self ):
00058 
00059         """ -> login name
00060         """
00061         return self._login
00062 
00063     def getRoles( self ):
00064 
00065         """ -> [ role ]
00066 
00067         o Include only "global" roles.
00068         """
00069         return self._roles.keys()
00070 
00071     def getGroups(self):
00072         """ -> [group]
00073 
00074         o Return the groups the user is in.
00075         """
00076         return self._groups.keys()
00077 
00078     def getDomains( self ):
00079 
00080         """ -> [ domain ]
00081 
00082         o The list represents the only domains from which the user is
00083           allowed to access the system.
00084         """
00085         return ()
00086 
00087     def getRolesInContext( self, object ):
00088 
00089         """ Return the list of roles assigned to the user.
00090 
00091         o Include local roles assigned in context of the passed-in object.
00092 
00093         o Include *both* local roles assigned directly to us *and* those
00094           assigned to our groups.
00095 
00096         o Ripped off from AccessControl.User.BasicUser, which provides
00097           no other extension mechanism. :(
00098         """
00099         user_id = self.getId()
00100         # [ x.getId() for x in self.getGroups() ]
00101         group_ids = self.getGroups()
00102 
00103         principal_ids = list( group_ids )
00104         principal_ids.insert( 0, user_id )
00105 
00106         local ={} 
00107         object = aq_inner( object )
00108 
00109         while 1:
00110 
00111             local_roles = getattr( object, '__ac_local_roles__', None )
00112 
00113             if local_roles:
00114 
00115                 if callable( local_roles ):
00116                     local_roles = local_roles()
00117 
00118                 dict = local_roles or {}
00119 
00120                 for principal_id in principal_ids:
00121                     for role in dict.get( principal_id, [] ):
00122                         local[ role ] = 1
00123 
00124             inner = aq_inner( object )
00125             parent = aq_parent( inner )
00126 
00127             if parent is not None:
00128                 object = parent
00129                 continue
00130 
00131             new = getattr( object, 'im_self', None )
00132 
00133             if new is not None:
00134 
00135                 object = aq_inner( new )
00136                 continue
00137 
00138             break
00139 
00140         return list( self.getRoles() ) + local.keys()
00141 
00142     def allowed( self, object, object_roles=None ):
00143 
00144         """ Check whether the user has access to object.
00145 
00146         o The user must have one of the roles in object_roles to allow access.
00147 
00148         o Include *both* local roles assigned directly to us *and* those
00149           assigned to our groups.
00150 
00151         o Ripped off from AccessControl.User.BasicUser, which provides
00152           no other extension mechanism. :(
00153         """
00154         if object_roles is _what_not_even_god_should_do:
00155             return 0
00156 
00157         # Short-circuit the common case of anonymous access.
00158         if object_roles is None or 'Anonymous' in object_roles:
00159             return 1
00160 
00161         # Provide short-cut access if object is protected by 'Authenticated'
00162         # role and user is not nobody
00163         if 'Authenticated' in object_roles and (
00164             self.getUserName() != 'Anonymous User'):
00165             return 1
00166 
00167         # Check for ancient role data up front, convert if found.
00168         # This should almost never happen, and should probably be
00169         # deprecated at some point.
00170         if 'Shared' in object_roles:
00171             object_roles = self._shared_roles(object)
00172             if object_roles is None or 'Anonymous' in object_roles:
00173                 return 1
00174 
00175         # Check for a role match with the normal roles given to
00176         # the user, then with local roles only if necessary. We
00177         # want to avoid as much overhead as possible.
00178         user_roles = self.getRoles()
00179         for role in object_roles:
00180             if role in user_roles:
00181                 if self._check_context(object):
00182                     return 1
00183                 return None
00184 
00185         # Still have not found a match, so check local roles. We do
00186         # this manually rather than call getRolesInContext so that
00187         # we can incur only the overhead required to find a match.
00188         inner_obj = aq_inner( object )
00189         user_id = self.getId()
00190         # [ x.getId() for x in self.getGroups() ]
00191         group_ids = self.getGroups()
00192 
00193         principal_ids = list( group_ids )
00194         principal_ids.insert( 0, user_id )
00195 
00196         while 1:
00197 
00198             local_roles = getattr( inner_obj, '__ac_local_roles__', None )
00199 
00200             if local_roles:
00201 
00202                 if callable( local_roles ):
00203                     local_roles = local_roles()
00204 
00205                 dict = local_roles or {}
00206 
00207                 for principal_id in principal_ids:
00208 
00209                     local_roles = dict.get( principal_id, [] )
00210 
00211                     for role in object_roles:
00212 
00213                         if role in local_roles:
00214 
00215                             if self._check_context( object ):
00216                                 return 1
00217 
00218                             return 0
00219 
00220             inner = aq_inner( inner_obj )
00221             parent = aq_parent( inner )
00222 
00223             if parent is not None:
00224                 inner_obj = parent
00225                 continue
00226 
00227             new = getattr( inner_obj, 'im_self', None )
00228 
00229             if new is not None:
00230                 inner_obj = aq_inner( new )
00231                 continue
00232 
00233             break
00234 
00235         return None
00236 
00237     #
00238     #   Interfaces to allow user folder plugins to annotate the user.
00239     #
00240     def _addGroups( self, groups=() ):
00241 
00242         """ Extend our set of groups.
00243 
00244         o Don't complain about duplicates.
00245         """
00246         for group in groups:
00247             self._groups[ group ] = 1
00248 
00249     def _addRoles( self, roles=() ):
00250 
00251         """ Extend our set of roles.
00252 
00253         o Don't complain about duplicates.
00254         """
00255         for role in roles:
00256             self._roles[ role ] = 1
00257 
00258 
00259     #
00260     #   Propertysheet management
00261     #
00262     def listPropertysheets( self ):
00263 
00264         """ -> [ propertysheet_id ]
00265         """
00266         return self._propertysheets.keys()
00267 
00268     def getPropertysheet( self, id ):
00269 
00270         """ id -> sheet
00271 
00272         o Raise KeyError if no such seet exists.
00273         """
00274         return self._propertysheets[ id ]
00275 
00276     __getitem__ = getPropertysheet
00277 
00278     def addPropertysheet( self, id, data ):
00279 
00280         """ Add a new propertysheet.
00281 
00282         o Raise KeyError if a sheet of the given ID already exists.
00283         """
00284         if self._propertysheets.get( id ) is not None:
00285             raise KeyError, "Duplicate property sheet: %s" % id
00286 
00287         if IPropertySheet.providedBy(data):
00288             self._propertysheets[ id ] = data
00289         else:
00290             self._propertysheets[ id ] = UserPropertySheet( id, **data )
00291 
00292 
00293 classImplements( PropertiedUser,
00294                  IPropertiedUser )