Back to index

plone3  3.1.7
Public Member Functions | Public Attributes | Static Public Attributes | Private Member Functions
borg.localrole.workspace.WorkspaceLocalRoleManager Class Reference
Inheritance diagram for borg.localrole.workspace.WorkspaceLocalRoleManager:
Inheritance graph
[legend]
Collaboration diagram for borg.localrole.workspace.WorkspaceLocalRoleManager:
Collaboration graph
[legend]

List of all members.

Public Member Functions

def __init__
def getRolesInContext
def checkLocalRolesAllowed
def getAllLocalRolesInContext

Public Attributes

 id
 title

Static Public Attributes

string meta_type = "Workspace Roles Manager"
tuple security = ClassSecurityInfo()

Private Member Functions

def _get_userfolder
def _getAdapters
def _parent_chain
def _get_principal_ids
def _groups

Detailed Description

This is the actual plug-in. It takes care of looking up
ILocalRolesProvider adapters (when available) and granting local roles
appropriately.

First we need to make and register an adapter to provide some roles::

    >>> from zope.interface import implements, Interface
    >>> from zope.component import adapts
    >>> from borg.localrole.tests import SimpleLocalRoleProvider
    >>> from borg.localrole.tests import DummyUser
    >>> from zope.component import provideAdapter
    >>> provideAdapter(SimpleLocalRoleProvider, adapts=(Interface,))


We need an object to adapt, we require nothing of this object,
except it must be adaptable (e.g. have an interface)::

    >>> class DummyObject(object):
    ...     implements(Interface)
    >>> ob = DummyObject()

And we need some users that we'll check the permissions of::

    >>> user1 = DummyUser('bogus_user')
    >>> user2 = DummyUser('bogus_user2')

Now we're ready to make one of our RoleManagers and try it out.
First we'll verify that our users have the 'Foo' role, then we'll
make sure they can access objects which require that role, but not
others::

    >>> rm = WorkspaceLocalRoleManager('rm', 'A Role Manager')
    >>> rm.getRolesInContext(user1, ob)
    ['Foo']
    >>> rm.checkLocalRolesAllowed(user1, ob, ['Bar', 'Foo', 'Baz'])
    1
    >>> rm.checkLocalRolesAllowed(user1, ob, ['Bar', 'Baz']) is None
    True
    >>> rm.getAllLocalRolesInContext(ob)
    {'bogus_user': set(['Foo'])}


Multiple Role Providers
-----------------------

It is a bit more interesting when we have more than one adapter
registered.  We register it with a name so that it supplements,
rather than conflict with or override the existing adapter::

    >>> class LessSimpleLocalRoleProvider(SimpleLocalRoleProvider):
    ...     userid = 'bogus_user2'
    ...     roles = ('Foo', 'Baz')
    ...     def getRoles(self, userid):
    ...         '''Grant bogus_user2 the 'Foo' and 'Baz' roles'''
    ...         if userid == self.userid:
    ...             return self.roles
    ...         return ()
    ...
    ...     def getAllRoles(self):
    ...         yield (self.userid, self.roles)

    >>> provideAdapter(LessSimpleLocalRoleProvider, adapts=(Interface,),
    ...                name='adapter2')

   This should have no effect on our first user::

    >>> rm.getRolesInContext(user1, ob)
    ['Foo']
    >>> rm.checkLocalRolesAllowed(user1, ob, ['Bar', 'Foo', 'Baz'])
    1
    >>> rm.checkLocalRolesAllowed(user1, ob, ['Bar', 'Baz']) is None
    True
    >>> rm.getAllLocalRolesInContext(ob)
    {'bogus_user2': set(['Foo', 'Baz']), 'bogus_user': set(['Foo'])}

But our second user notices the change, note that even though two
of our local role providers grant the role 'Foo', it is not duplicated::

    >>> rm.getRolesInContext(user2, ob)
    ['Foo', 'Baz']
    >>> rm.checkLocalRolesAllowed(user2, ob, ['Bar', 'Foo', 'Baz'])
    1
    >>> rm.checkLocalRolesAllowed(user2, ob, ['Bar', 'Baz'])
    1
    >>> rm.checkLocalRolesAllowed(user2, ob, ['Bar']) is None
    True


Role Acquisition and Blocking
-----------------------------

This plugin will acquire role definitions from parent objects,
unless explicitly blocked.  To test this, we need some objects
which support acquisition::

    >>> from Acquisition import Implicit
    >>> class DummyImplicit(DummyObject, Implicit):
    ...     def stupid_method(self):
    ...         return 1
    >>> root = DummyImplicit()
    >>> next = DummyImplicit().__of__(root)
    >>> last = DummyImplicit().__of__(next)
    >>> other = DummyImplicit().__of__(root)

So we now have /root/next/last and /root/other, we'll create and
register special adapters for our next and other objects.

    >>> class ISpecial1(Interface):
    ...     pass
    >>> class ISpecial2(Interface):
    ...     pass
    >>> from zope.interface import directlyProvides
    >>> directlyProvides(next, ISpecial1)
    >>> directlyProvides(other, ISpecial2)
    >>> class Adapter1(LessSimpleLocalRoleProvider):
    ...     adapts(ISpecial1)
    ...     userid = 'bogus_user'
    ...     roles = ('Bar',)
    >>> class Adapter2(LessSimpleLocalRoleProvider):
    ...     adapts(ISpecial2)
    ...     userid = 'bogus_user3'
    ...     roles = ('Foobar',)
    >>> user3 = DummyUser('bogus_user3')

We'll register these to override the existing unnamed adapter:

    >>> provideAdapter(Adapter1)
    >>> provideAdapter(Adapter2)

Now we can show how acquisition of roles works, first we look at the
'last' item, which should have roles provided by
SimpleLocalRoleProvider, and LessSimpleLocalRoleProvider, as well
as acquired from Adapter1 on 'next':

    >>> rm.getRolesInContext(user1, last)
    ['Foo', 'Bar']

    >>> rm.getRolesInContext(user2, last)
    ['Foo', 'Baz']

If we look at the parent, we get the same results, because the
SimpleLocalRoleProvider adapter also applies to the 'root'
object. However, if we enable local role blocking on 'next' we
won't see the roles from the 'root'::

    >>> rm.getRolesInContext(user1, next)
    ['Foo', 'Bar']
    >>> next.__ac_local_roles_block__ = True
    >>> rm.getRolesInContext(user1, next)
    ['Bar']

The checkLocalRolesAllowed and getAllLocalRolesInContext methods
take acquisition and blocking into account as well::

    >>> rm.checkLocalRolesAllowed(user1, last,  ['Bar'])
    1
    >>> rm.checkLocalRolesAllowed(user1, next,  ['Foo', 'Baz']) is None
    True
    >>> rm.getAllLocalRolesInContext(last)
    {'bogus_user2': set(['Foo', 'Baz']), 'bogus_user': set(['Foo', 'Bar'])}

It's important to note, that roles are acquired only by
containment.  Additional wrapping cannot change the security on an
object.  For example if we were to wrap 'last' in the context of
other, which provides a special role for 'user3', we should see no
effect::

    >>> rm.getRolesInContext(user3, last)
    ['Foo']
    >>> rm.getRolesInContext(user3, other)
    ['Foobar', 'Foo']
    >>> rm.getRolesInContext(user3, last.__of__(other))
    ['Foo']

It's also important that methods of objects yield the same local
roles as the objects would

    >>> rm.getRolesInContext(user3, other.stupid_method)
    ['Foobar', 'Foo']

Group Support
-------------

This plugin also handles roles granted to user groups, calling up
the adapters to get roles for any groups the user might belong
to::

    >>> user4 = DummyUser('bogus_user4', ('Group1', 'Group2'))
    >>> user4.getGroups()
    ('Group1', 'Group2')
    >>> rm.getRolesInContext(user4, last)
    ['Foo']
    >>> class Adapter3(LessSimpleLocalRoleProvider):
    ...     userid = 'Group2'
    ...     roles = ('Foobar',)

    >>> provideAdapter(Adapter3, adapts=(Interface,), name='group_adapter')
    >>> rm.getRolesInContext(user4, last)
    ['Foobar', 'Foo']


Wrong User Folder
-----------------

Finally, to ensure full test coverage, we provide a user object
which pretends to be wrapped in such a way that the user folder
does not recognize it.  We check that it always gets an empty set
of roles and a special 0 value when checking access::

    >>> class BadUser(DummyUser):
    ...     def _check_context(self, obj):
    ...         return False
    >>> bad_user = BadUser('bad_user')
    >>> rm.getRolesInContext(bad_user, ob)
    []
    >>> rm.checkLocalRolesAllowed(bad_user, ob, ['Bar', 'Foo', 'Baz'])
    0

Definition at line 134 of file workspace.py.


Constructor & Destructor Documentation

def borg.localrole.workspace.WorkspaceLocalRoleManager.__init__ (   self,
  id,
  title = "" 
)

Definition at line 357 of file workspace.py.

00357 
00358     def __init__(self, id, title=""):
00359         self.id = id
00360         self.title = title

Here is the caller graph for this function:


Member Function Documentation

Returns a list of the ids of all involved security
principals: the user and all groups that they belong
to. (Note: recursive groups are not yet supported

Definition at line 394 of file workspace.py.

00394 
00395     def _get_principal_ids(self, user):
00396         """Returns a list of the ids of all involved security
00397         principals: the user and all groups that they belong
00398         to. (Note: recursive groups are not yet supported"""
00399         principal_ids = list(user.getGroups())
00400         principal_ids.insert(0, user.getId())
00401         return principal_ids

Here is the caller graph for this function:

Gets the unwrapped user folder for the user, because we may
need to rewrap

Definition at line 361 of file workspace.py.

00361 
00362     def _get_userfolder(user, obj):
00363         """Gets the unwrapped user folder for the user, because we may
00364         need to rewrap"""
00365         context = user
00366         while context is not None:
00367             if hasattr(context, 'getId'):
00368                 if context.getId() == 'acl_users':
00369                     break
00370             context = aq_parent(aq_inner(context))
00371         else:
00372             return None
        return aq_inner(context)

Here is the caller graph for this function:

Definition at line 377 of file workspace.py.

00377 
00378     def _getAdapters(self, obj):
00379         adapters = getAdapters((obj,), ILocalRoleProvider)
00380         # this is sequence of tuples of the form (name, adapter),
00381         # we don't really care about the names
00382         return (a[1] for a in adapters)

Here is the caller graph for this function:

def borg.localrole.workspace.WorkspaceLocalRoleManager._groups (   self,
  obj,
  user,
  workspace 
) [private]
If workspace provides IGroupAwareWorkspace and the user has
a getGroups() method, yield each group_id returned by that method.

Definition at line 494 of file workspace.py.

00494 
00495     def _groups(self, obj, user, workspace):
00496         """If workspace provides IGroupAwareWorkspace and the user has
00497         a getGroups() method, yield each group_id returned by that method.
00498         """
00499         if IGroupAwareWorkspace.providedBy(workspace):
00500             getGroups = getattr(user, 'getGroups', None)
00501             if getGroups is not None:
00502                 acl_users = aq_parent(aq_inner(self))
00503                 for group_id in getGroups():
00504                     yield acl_users.getGroupById(group_id)
00505 
00506 classImplements(WorkspaceLocalRoleManager, ILocalRolesPlugin)
00507 InitializeClass(WorkspaceLocalRoleManager)

Here is the call graph for this function:

Here is the caller graph for this function:

Iterate over the containment chain, stopping if we hit a
local role blocker

Definition at line 383 of file workspace.py.

00383 
00384     def _parent_chain(self, obj):
00385         """Iterate over the containment chain, stopping if we hit a
00386         local role blocker"""
00387         while obj is not None:
00388             yield obj
00389             if getattr(obj, '__ac_local_roles_block__', None):
00390                 raise StopIteration
00391             new = aq_parent(aq_inner(obj))
00392             # if the obj is a method we get the class
00393             obj = getattr(obj, 'im_self', new)

Here is the caller graph for this function:

def borg.localrole.workspace.WorkspaceLocalRoleManager.checkLocalRolesAllowed (   self,
  user,
  object,
  object_roles 
)
Checks if the user has one of the specified roles in the
given context, short circuits when the first provider granting
one of the roles is found.

Definition at line 431 of file workspace.py.

00431 
00432     def checkLocalRolesAllowed(self, user, object, object_roles):
00433         """Checks if the user has one of the specified roles in the
00434         given context, short circuits when the first provider granting
00435         one of the roles is found."""
00436         uf = self._get_userfolder(user)
00437         if uf is not None:
00438             # rewrap user with an unwrapped user folder, so
00439             # _check_context works appropriately
00440             user = aq_inner(user)
00441             user = user.__of__(uf)
00442         check_roles = dict(izip(object_roles, repeat(True)))
00443         principal_ids = self._get_principal_ids(user)
00444         for obj in self._parent_chain(object):
00445             count = -1
00446             for count, a in enumerate(self._getAdapters(obj)):
00447                 for pid in principal_ids:
00448                     roles = a.getRoles(pid)
00449                     for role in check_roles:
00450                         if role in roles:
00451                             if user._check_context(obj):
00452                                 return 1
00453                             else:
00454                                 return 0
00455             # XXX: BBB code, kicks in only if there's no proper adapter
00456             if count == -1:
00457                 workspace = IGroupAwareWorkspace(obj, IWorkspace(obj, None))
00458                 if workspace is not None:
00459                     roles = workspace.getLocalRolesForPrincipal(user)
00460                     for role in check_roles:
00461                         if role in roles:
00462                             if user._check_context(obj):
00463                                 return 1
00464                             else:
00465                                 return 0
00466                     for group in self._groups(obj, user, workspace):
00467                         roles = workspace.getLocalRolesForPrincipal(group)
00468                         for role in check_roles:
00469                             if role in roles:
00470                                 if user._check_context(obj):
00471                                     return 1
00472                                 else:
00473                                     return 0
00474 
00475         return None

Here is the call graph for this function:

Definition at line 477 of file workspace.py.

00477 
00478     def getAllLocalRolesInContext(self, object):
00479         rolemap = {}
00480         for obj in self._parent_chain(object):
00481             for a in self._getAdapters(obj):
00482                 iter_roles = a.getAllRoles()
00483                 for principal, roles in iter_roles:
00484                     rolemap.setdefault(principal, set()).update(roles)
00485             else: # XXX: BBB code, kicks in only if there's no proper ddapter
00486                 workspace = IGroupAwareWorkspace(obj, IWorkspace(obj, None))
00487                 if workspace is not None:
00488                     rolemap.update(workspace.getLocalRoles())
00489 
00490         return rolemap
               

Here is the call graph for this function:

Definition at line 403 of file workspace.py.

00403 
00404     def getRolesInContext(self, user, object):
00405         # we combine the permission of the user with those of the
00406         # groups she belongs to
00407         uf = self._get_userfolder(user)
00408         if uf is not None:
00409             # rewrap user with an unwrapped user folder, so
00410             # _check_context works appropriately
00411             user = aq_inner(user)
00412             user = user.__of__(uf)
00413         principal_ids = self._get_principal_ids(user)
00414         roles = set()
00415         for obj in self._parent_chain(object):
00416             if user._check_context(obj):
00417                 count = -1
00418                 for count, a in enumerate(self._getAdapters(obj)):
00419                     for pid in principal_ids:
00420                         roles.update(a.getRoles(pid))
00421                 # XXX: BBB code, kicks in only if there's no proper adapter
00422                 if count == -1:
00423                     workspace = IGroupAwareWorkspace(obj, IWorkspace(obj, None))
00424                     if workspace is not None:
00425                         roles.update(workspace.getLocalRolesForPrincipal(user))
00426                         for group in self._groups(obj, user, workspace):
00427                             roles.update(workspace.getLocalRolesForPrincipal(group))
00428         return list(roles)

Here is the call graph for this function:

Here is the caller graph for this function:


Member Data Documentation

Definition at line 358 of file workspace.py.

string borg.localrole.workspace.WorkspaceLocalRoleManager.meta_type = "Workspace Roles Manager" [static]

Definition at line 354 of file workspace.py.

Definition at line 355 of file workspace.py.

Definition at line 359 of file workspace.py.


The documentation for this class was generated from the following file: