Personal tools
You are here: Home Products Plone Roadmap #208: Adapter-Based Local Role Lookup
Document Actions

#208: Adapter-Based Local Role Lookup

Contents
  1. Definitions
  2. Motivation
  3. Assumptions
  4. Proposal
  5. Implementation
  6. Deliverables
  7. Risks
  8. Progress log
  9. Participants
by Alec Mitchell last modified March 2, 2008 - 13:49
borg.localrole should become a part of the Plone core
Proposed by
Alec Mitchell
Proposal type
Architecture
Assigned to release
State
completed

Definitions

PAS - Pluggable Authentication System, the mechanism we use for providing configurable authentication, user data, roles, and groups.

PlonePAS - A set of customizations and additional plugins for PAS tailored for Plone's needs.

__ac_local_roles__ - An attribute or method commonly added to persistent objects which returns a mapping of principal ids to roles for that object.

borg.localrole - A python package containing a PAS plugin for local role determination. It uses named adapters providing an ILocalRoleProvider interface for the objects on which local roles should be determined. The plugin provides acquisition of local roles and group support.

Motivation

The current PlonePAS local role plugin is complex and inflexible. It provides features critical to any local role implementation (role acquisition, role acquisition blocking, group support), but it is impossible to reuse those features in other role managers without copying the entire implementation. It also has very few tests (if any), and each of its methods are almost exact duplicates of one another.

As a result of this implementation, objects which need custom local role support have to copy much of the code from the PlonePAS implementation (or one of its predecessors). For example, the Portal Factory needs to obtain local roles from the intended content path. Currently, it overrides the __ac_local_roles__ method with a copy of the mechanism from the PAS local role manager. The result is that it only provides the local roles the default plugin would provide on the intended add path, and not those from any other local role plugins which may be installed. It might make sense for Portal Factory to provide a proper local role plugin, but it would have to be run for every object regardless of whether it was in the factory or not. It would also still have to re-implement much of the same functionality.

Providing a custom local role mechanism can be time consuming and painful with the current PAS implementation. After re-implementing all the basic functionality with new tests, one needs to develop a persistent component and register it as a plugin. This additional complexity is particularly onerous since it's generally unlikely that the plugin itself will store any persistent state. Local role determination is well suited to the use of adapters.

Fortunately, we already have a PAS plugin for local roles which uses adapters for local role determination. It has a simple and clear implementation, and has excellent test coverage. It provides group support, local role acquisition, and local role blocking automatically for all the adapters registered for it. It allows local role adapters to easily be overridden (more specific adapters), or supplemented (via named adapters).

Assumptions

 

Proposal

There are only three simple steps needed for this PLIP to be implemented:

  1. Include the borg.localrole package in the next Plone release.

  2. Provide an adapter for borg.localrole that implements the functionality of the current default plugin. An example implementation follows, which hopefully demonstrates how much simpler and more testable an adapter based implementation can be:

    class DefaultLocalRoleAdapter(object):
        """Looks at __ac_local_roles__ to find local roles stored
        persistently on the object"""
        implements(ILocalRoleProvider)
        adapts(Interface)
    
        @property
        def _rolemap(self):
            rolemap = getattr(self.context, '__ac_local_roles__', {})
            if callable(rolemap):
                rolemap = rolemap()
            return rolemap
    
        def getRoles(self, principal_id):
            rolemap = self._rolemap
            return local_roles.get(principal_id, [])
    
        def getAllRoles(self):
            return self._rolemap.iteritems()
    

This will of course require a couple unit tests.

  1. Add a migration that removes the existing default plugin and adds the new borg.localrole plugin.

Optional step: An adapter to handle the portal_factory role issue is included with borg.local_role, and should probably be enabled. Additionally, this will allow the current __ac_local_roles__ hack in PortalFactory.py to be removed.

Implementation

See proposal

Deliverables

See proposal

Risks

It's likely that adding an adapter lookup, in place of direct attribute lookup, will add a small performance penalty. Role lookups need to be very fast. The adapter registry is, however, quite fast and provides its own internal caching. When multiple local role providers are involved, its very likely that having all the adapters looked up within the same loop in a single PAS plugin will be significantly faster than having multiple persistent plugins each with its own loops for acquisition.

The use of generators in the acquisition calculation and other optimizations already in place in borg.localrole may already make this performance discrepancy negligible. Some benchmarking may be useful, however the benefits are likely to outweigh anything less than a serious performance discrepancy. Caching may provide some benefit, but it is potentially risky, and should not be attempted without some solid benchmarks.

Progress log

 

Participants

Alec Mitchell

Framework team vote

Posted by Andreas Zeidler at December 14, 2007 - 16:45
+1 (see http://lists.plone.org/pipermail/framework-team/2007-December/001547.html)

Framework team vote

Posted by Martijn Pieters at December 14, 2007 - 17:07
+1

Framework team vote

Posted by Raphael Ritz at December 17, 2007 - 12:36
+1

Framework team vote

Posted by Tom Lazar at December 20, 2007 - 13:22
+1 yes, please!

Framework team vote

Posted by Danny Bloemendaal at December 22, 2007 - 17:46
+1

For any issues with the web site functionality, please file a ticket.

Please consult the policy on plone.org content if you want your content published on this site.

Servers and hosting by