Plugins currently often use hard-coded security.

Use ACLs

Plugins could use Acls to protect the data they show. This is already done by some plugins but most times hard coded.

Proposal:

Examples

This could be especially useful for plugins that show data that is not directly stored in pages/in the wiki itself. Like a DB interface.

Would also solve FeatureRequests/NewUserCreationACL.

Hierarchy of keys

Key names can represent the wiki parts:

And so on. The dict would replace acl_rights_before or acl_rights_default or both, with a much more powerful system.

Example - checking rights for UserPreferences macro:

  1. check acl_before - if we want to keep this
  2. Check wiki/plugin/macro/UserPreferences

  3. Check wiki/plugin/macro

  4. Check wiki/plugin

  5. Check wiki

  6. return False

Example - checking rights for PageName/SubPage:

  1. check acl_before - if we want to keep this
  2. Check wiki/pages/PageName/SubPage (check acl on the page)

  3. Check wiki/pages/PageName (check acl on the page)

  4. Check wiki/pages - acl_rights_before or the current system

  5. Check wiki

  6. return False

It's not clear what right you need to execute a plugin - read? Maybe read for operations that display data, write for operations that change data?

Example - code that need rights in a plugin:

# Before running any code in the plugin:
if not request.user.may.read('wiki/plugin/action/name'):
    raise UserNotAllowed

# Before doing something that changes wiki data
if not request.user.may.write('wiki/plugin/action/name'):
    raise UserNotAllowd
# rather may.write('wiki/pages') ?
#  The action may not change pages data, like delete user action, or wiki admin

The caller will handle these errors by sending the current page with an error message.

SecurityPolicy may implement the cascade checking. When you call it with a path, it will check all the components of the path in the correct order. If you call with a path that does not exist, you will get False, which is safe.

Configuration

If the user define acl dict, use it. If not, use the default acl dict.

To change some rights in the acl dict, use:

    acl = DefaultConfig.acl
    acl[key] = new value

Or, use always the default acl, and if the user define his own acl, update the default acl with the user keys.

When a config object is created, each key in the acl dict will be replaced with an ACL object that can answer the may() call.

ACL checking

SecurityPolicy will use this code to check rights:

# resource is an acl path e.g 'wiki/plugin/action/backup'

for path in reversePathIterator(resource):
    acl = request.cfg.acl.get(path)
    if acl is None:
        continue
    may = acl.may()
    if may is not None:
        return may

return False # default safe answer

reversePathIterator is needed in other places, for example, in code that create bread crumbs:

def reversePathIterator(path):
    components = path.split('/')
    length = len(commponents)

    for i in range(len(components)):
        path = components[:length - i]
        path = '/'.join(path)
        yield path 

For pages, we need a way to check the acl on the page instead of the acl dict. We can do this by using a modified dict that returns the pages acl object for keys that starts with wiki/pages/.

Performance

The proposed acl dict is in memory, and contain acl objects. The most expensive thing is the acl matching, which is few dictionary lookups. If we want, we can cache the results of all keys per one request. For example, when you create a page list, and no pages have any, and the acl are defined in wiki/pages, you can cash True or False on the first time the user query wiki/pages, and then the next 1000 queries will just be one dictionary lookup.

We will have to profile such code to see if there are any performance problems.

Usability

Another thing is usability. Quite some user's don't get ACLs right now. They will get more if you make it more complicated.

This will not make acl eaiser to use as the same acl syntax is used. However, admins that can work with this syntax will have more control on the wiki. Maybe it can save the need to write a custom SecurityPolicy for some cases, which of course much more complicated then setting acl rights on an object.

The hierarchy can make your life easier when you can define acl once on on one item in the hierarchy, instead of repeating the same acl on many sub items.

The ChainOfResponsibilityPattern pattern used by the acl tree is used successfully in other systems, for example HyperCard, which was always considered very easy to use system. Also, the tree structure resemble the directory tree of the wiki directory, which should make it easy to grasp.

Today we have 3 levels, before, page, and after, which is rather confusing model compared with wiki, wiki/pages and wiki/pages/pagename.

We should do usability tests to see if people can work with this hierarchy.

Check order

The check order described start the acl check on the last leaf, so you can override the acl of the root of the tree, (called today acl_rights_before), which is not possible today, and its a feature some people requested and complained about.

Of course it possible to use acl_rights_before with the tree check order if we like, it not related to the way acl checked on wiki objects.

Pages acl creation

This solution assume that pages do not use the current system of copying all acl lines from acl_before, default and after, and then creating acl object from all the lines, but creating acl object from the page lines, and creating separate acl objects for each dict key. This design make the page acl cache much smaller and faster to create. MoinCaching contains timings for this global acl cache.


I am looking at the Gallery2 parser to develop a web album/interface to photo images already organized into directories on a network disk. This is an Intraweb and I am not too concerned about security, but there are reasons to progress cautiously since I was proposing changes that would allow a wiki user to read images from any directory that the web server process could access.

I also was looking at the http://moinmoin.wikiwikiweb.de/FormatterMarket/application_pdf.py and noticed the warning about security.

I suggest that ACL could possibly be extended to control access to the plugins. Maybe the default access would only allow read access to a specific directory. Maybe it could even be on a plugin by plugin basis. I don't have a specific proposal on the ACL format, it might be messy enough to just cause a bunch of problems, but here it is for people to look at.

Since at the current time there is no security whatsoever on the plugins, any way to improve the situation would be better than nothing. I remember a restricted environment in Python that was removed because it didn't work very well. Did anything come along to replace it?


I thought of a simpler way to accomplish this. As moinmoin runs a plugin, it looks in the plugin's directory for an ACL of the same name. In other words the ACL is not associated with the page, but installed with the plugin.

  /moinmoin_data/engineering/data/plugin/macro/examplemacro.py
  /moinmoin_data/engineering/data/plugin/macro/examplemacro.acl

The ACL could even limit the use of the plugin to specific pages (for example - you could have plugins that only work with Category* pages). -- TimCera 2005-08-31 16:07:01

see also FeatureRequests/AclRefactoring


CategoryFeatureRequest

MoinMoin: FeatureRequests/AclExtendedToMakePluginsSecure (last edited 2009-09-05 14:58:28 by ReimarBauer)