Size: 5159
Comment: refactor
|
Size: 5228
Comment:
|
Deletions are marked like this. | Additions are marked like this. |
Line 11: | Line 11: |
=== acl_before, acl_default and acl_after are duplicated for every page === | === acl_before, acl_default and acl_after are duplicated for every page === |
Line 31: | Line 31: |
Line 32: | Line 33: |
* acl_rights_default is treated as the wiki virtual root page acl, which all page inherit from. If a page does not have acl, it inherit from its parent, if the parent does not have acl, it inherit from acl_rights_default. | |
Line 35: | Line 37: |
Flow of acl checking: | Flow of acl chekcing: |
Line 37: | Line 40: |
1. All pages inherit the wiki acl rights, whats called now acl_rights_default. We can see this as the acl of the virtual parent page of all the wiki pages. 1. Each page inherit its parent acl 1. Each page may override its parent acl - depending on the implementation |
1. acl_rights_default, pages and sub pages are checked - the order depending on the implementation |
Line 102: | Line 103: |
= Implementation = |
Here is a patch for this solution: |
Applying access control lists using wiki hierarchy.
How does AccessControlList class work currently?
Acl objects are made from acl lines in config and page. First acl_before line is copied, then page lines are copied from page, or acl_default if page does not have acl lines. Last, acl_after line is copied. Then, acl object is created from the lines. This object contain a list of right dictionaries. This object is created for each page and cached.
When accessing pages, user may mehtod is called, which retrive the acl object from the page and check for rights.
problems
acl_before, acl_default and acl_after are duplicated for every page
Worst case example: in a 1000 pags wiki with no acls, we copy acl_before, acl_default and acl_after to any page acl, then parse the same lines 1000 times, and finally cache 1000 equal acl instances.
With hierarchical acl, we would parse once acl_before, acl_after and acl_default, and keep them in memory, then cache None for every other page in the acl cache.
Too much work to use
You must add acl lines to any page you want to protect with different acl then the default acls. For example, if you would like to create few pages for one project, you will have to add acl lines to each new page. If you want to change the project acl rights, you have to do it again on all the pages of the projects.
An example is the acl rights of the help and system pages. To change these we use a script the edit all those pages text outside the wiki.
How hierarchial acl should work
before -> default -> parent page -> sub page -> after -> No!
Changes:
- acl_rights_xx are splited from the page acl. Each acl_right_xx is parsed and saved in the wiki config, then can be checked separately.
- acl_rights_default is treated as the wiki virtual root page acl, which all page inherit from. If a page does not have acl, it inherit from its parent, if the parent does not have acl, it inherit from acl_rights_default.
- replace that lambda in security with real function
- make that fuction avoid loading page acl if that not needed
Flow of acl chekcing:
- acl_rights_before checked, so the admin can define rights nobody can override.
- acl_rights_default, pages and sub pages are checked - the order depending on the implementation
- acl_rights_after is checked, so we can add default rights to all pages.
- Last, if no acl match, we deny the access.
Benefits
- Less work to define acl, define only few acls for whole wiki using sub pages.
Needs very small cache which can be loaded from disk very fast - see MoinCaching.
Performance Issues
- In the best case when acl_rights_before match, we don't have to get acl from the page/s, which means preventing expensive disk access.
- In the worst case we have to check more than one page acl, which means multiple expensive disk accesses. We can solve this by better acl caching.
Changes to current code
The current AccessControlList.may check a composite acl object, made from all acl_rights and page rights, and return True or False. The new may function will check a single acl object, and return 3 answers: True, False or None, which means "don't know". The basic acl check look like this:
1 allowed = acl.may(request, name, what)
2 if allowed is not None:
3 return allowed
The complete acl checking will move from AccessControlList.may to the SecurityPolicy .xxx, e.g. SecurityPolicy.read
Checking the page hierarchy can be done in two ways: Posix file system like, or traditional acls.
Posix file system like hierarchy
The should work like file system permissions. Say there are the following pages, TopSecret and !TopSecret/!PasswordFiles . If the user "protects" TopSecret by removing read right to everyone but himself, it would naturally expect everything bellow TopSecret to be procected.
For example, for the path a/b/c:
- check acl_rights_before
- check acl_rights_default
- check a
- check a/b
- check a/b/c
- check acl_rights_after
- return False
Benefits:
- Can't give more rights to a part of a tree, you can only add protection
- Familiar and simple concept, less error prone
Traditional ACL hierarchy
Check each page acl, starting with the longest path, so each page can override the parent.
For example, for the path a/b/c:
- check acl_rights_before
- check a/b/c
- check a/b
- check a
- check acl_rights_default
- check acl_rights_after
- return False
Benefits:
- More power, you can define any acl to any page, ignoring the parent acl
Here is a patch for this solution: attachment:hierachical-acl.diff
Reference
NTFS ACL
In NTFS' ACLs, it works like this:
- Each object has an ACL.
- Each object has a virtual flag "inherited_acl".
- Each object can contain its own ACL.
- Each entry of the ACL might be allow or revoke.
- If it is inherited, every change of the parent ACL is inherited.
- The ACL of the object may enhance or narrow done the inherited ACL. This is possible because there is allow and revoke.