When I was talking on IRC with AlexanderSchremmer about using moin as a blog, he mentioned that people may want to write things up for the future that are not immediately visible. He half-jokingly suggested ACL Plugins. After thinking this through, I think it makes sense. So here's a plan for it.
Idea
Currently, we have 4 types of ACL rights (which I'll denote in italics):
read
write
delete
admin
There rights will be kept, but we'll add another layer of indirection. Specifically:
There will be the 4 basic ACL plugins (which I'll denote in typewriter):
read
write
delete
admin
which always return True for the right they're named after, and None otherwise. This helps to ensure backward compatibility, see below.
Currently we have this syntax:
#acl UserOrGroup:right1,right2,right3
This will be expanded to
#acl UserOrGroup:plugin1(param1, param2, param3),plugin2,plugin3(...)
where of course the parentheses and parameters are optional (and the 4 basic plugins don't take any at least for now). If the parentheses are left off, the arguments are parsed as None, otherwise the string inbetween is used.
plugin API
Plugins will have to provide these methods:
__init__(request, string args) - initialize a plugin, raises InvalidACLArgumentException if arguments are rejected
may(string right) - returns True if the right is granted, False if not, and None if no decision
example basic plugin
1 class read:
2 def __init__(self, request, args):
3 if not args is None: # no arguments allowed for this basic plugin
4 raise InvalidACLArgumentException
5 def may(self, right):
6 if right != self.__class__.__name__:
7 return None
8 return True
9
10 # other basic classes can inherit stuff
11 class write(read):
12 pass
13 class delete(read):
14 pass
15 class admin(read):
16 pass
what changes
Well, instead of just saving the rights, plugin instances are created and saved with the ACL. Then, when the ACL is queried for a specific right, the plugins are asked in turn. If one of them says that it determines the right the query is looking for (that is, returns True or False), then the right is granted or denied, and ACL processing stops after that point. Otherwise, the next plugin is queried. This ensures full backward compatibility.
I have a patch for wikiacl.py that changes the way ACLs are parsed (yes, it still passes tests) and additionally allows quoting usernames. The only non-backward compatible part is ACLs that have usernames containing quotes. See /wikiacl.patch.
example of a more interesting plugin
further ideas
We could fold the SecurityPolicy into pluggable ACLs. Currently, differences are that the SecurityPolicy is evaluated on save, and the ACL is already evaluated before. But the ACL obviously also has to be evaluated on saving, this could be extended by adding a save right (which the write plugin would automatically grant as well as write), but which is evaluated with the extra parameters editor, newtext, rev, **kw from saveText(). Then a custom security policy could be replaced by a acl_before statement and an ACL plugin, making custom security policies aggregable (read: you can download ACL plugins from anyone and use them in whatever way you like). This needs some more thought (read: I haven't fully thought through the implications).
discussion
- Possibly the rights should be treated specially by the ACL parser, and no plugins are instantiated for them. This would make the common code path (the current one) about as fast as it currently is.
- There has to be some thought given to caching. Currently, ACLs are cached in memory and re-evaluated every time a result is needed, so there's no problem. I don't think the result should need to be cached since evaluating them is likely fast enough.
Why we need more complex syntax and what we gain by that? Currently I don't see any reason to change the current setup. Instead of making acl system more complicated so you can use it for bloging, simply write nice and simple blog action/macro, maybe even complete blog module, and use the current acl system. -- NirSoffer 2005-02-08 12:18:25
No, that's not possible, because then you can hide new pages that are supposed to be seen in the future, but not make them unreadable. -- JohannesBerg 2005-02-08 13:55:34
Whats wrong with #acl All:? When you want to publish, change the acl, or the blog system will do it for you automatically.
- You don't want to have to do anything to publish. Take the following scenario: You write a short article every week, and it should always be published at the same day of week and time. Now, you're on the road. Wouldn't it be nice to be able to edit the article and mark it available after the given day/time? For a blog system to do this it'd need to manipulate the pages when they are requested, or have a cron-job.
- It would be very nice, but this should be handled by your bloging code - not by moin core. The bloging system can save the content in an hidden way, and create visible page on the correct date, or just remove the blocking acl on the first request after certain date. For example in a custom security policy class.
A custom security class is something like your idea, just less flexible and a little bit outdated compared to the current ACL system. So if you propose that solution, going for an extension of the ACL system to handle SecurityPolicy like things is nearly a mandatory step if you want to see progress somewhere. BTW, antispam (the most used SecurityPolicy component) could be modeled quite well using JBACLs
this got me thinking -- we could unify SecurityPolicy and ACL Plugins, see above (further ideas) -- JohannesBerg 2005-02-09 10:29:04
- It would be very nice, but this should be handled by your bloging code - not by moin core. The bloging system can save the content in an hidden way, and create visible page on the correct date, or just remove the blocking acl on the first request after certain date. For example in a custom security policy class.
- You don't want to have to do anything to publish. Take the following scenario: You write a short article every week, and it should always be published at the same day of week and time. Now, you're on the road. Wouldn't it be nice to be able to edit the article and mark it available after the given day/time? For a blog system to do this it'd need to manipulate the pages when they are requested, or have a cron-job.
I don't see how security policy is less flexible and outdated, and why extending acl is mandatory if we want to see some progress. A security policy class is the most flexible thing you can have - run you own code on any event. What is mandatory is the rule - don't touch the core unless its really needed.
Anyway, if we have a new concept of date when a page is available, and its really needed to be in the core of the wiki, the simple solution is to add a processing instruction, like #date date, that will make the page available from date. Of course in a wiki, this concept is problematic - what do you do with the page? show missing page? show "Page will be published in date"? This is typical trouble when trying to do things a wiki should not do. -- NirSoffer 2005-02-09 14:48:22
I agree that this particular example is not the best one for a security-related subsystem. Maybe we can think of others ... -- AlexanderSchremmer 2005-02-09 17:05:00
I don't think you see the point. I could do this using a SecurityPolicy. And I could plug this into the current system by adding #pragma blogacl ... to a page. But then I end up copying the ACL code to support the blogacl, because it'd also have to look like #pragma blogacl JohannesBerg:dont_restrict All:validafter(date)1. Then I could of course evaluate that pragma in a new SecurityPolicy. There's just no point in doing that, the code required would be large, mostly copied from the ACL code, and unmaintainable. Also, it would probably not work correctly with the Include macro since the pragmas are stored in the request for some reason.
The problem of what happens is pretty clear -- you deny access to the page. But people wouldn't find the page, since it shouldn't be listed anywhere unless you explicitly link to it since it's not readable by them. -- JohannesBerg 2005-02-09 16:53:00
unless I explicitly exclude a single user in code, or add another pragma, or ... I'm thinking along the lines of a new way to do a class of things, not just solving a single problem. (1)