Hi, (I use WebDAV ACL specification terminology in this message)
Need ==== At Hippo we are building a CMS and like all other CMSes we need to be able to specify authorization rules. Slide provides this possiblity because it implements the WebDAV ACL specification. Unfortunately this is not flexible enough for our requirements. We want to do the following things: = assign a user/group to a role per object (e.g. John is an author for /files/news/ and an editor for /files/departments/sales/, Sue is an editor for /files/news/); = use Slide to store authorization rules for external systems (e.g. who is allowed to invoke the 'publish' action of the workflow). The first issue can be solve in two ways: = grant the appropriate read, write, etc. privileges associated with a specific role. This is undesirable for two reasons: - the role gets 'lost'; there is no direct indication of which role the user has, but this has to be deduced from the privileges granted. - when the privileges associated with a role change, the ACLs of all objects have to be modified. This is difficult to do, because it is hard to deduce if a user/group was in a specific role before the change. = create a uniquely-named group for each role for each object and assign users/groups to these groups. This solution would introduce enormous administrative overhead to keep the data and groups in sync, and would litter the repository with loads of generated groups. The second issue can be solved by adding a custom property to an object which would indicate who is authorized for what. All solutions to both issues need custom programming to maintain them which prevents standard WebDAV tools from using them. Solution ======== Our solution to the problem is to introduce custom privileges to emulate privileges for external systems and to emulate roles. Some examples (xmlns:D="DAV:" xmlns:hp="http://hippo.nl/cms/privileges" xmlns:hr="http://hippo.nl/cms/roles"): = hp:requestReview: request a review for changes; = hp:publish: publish the changes; = hp:disapprove: disapprove the changes; = hp:all: aggregation of the three privileges above; = hr:author: this is the author role. It is an aggregation of: D:read, D:write and hp:requestReview; = hr:editor: this is the editor role. It is an aggregation of: D:read, D:write, hp:publish and hp:disapprove. The ACLs for /files/news/ and for /files/departments/sales/ would contain this: /files/news/ ... grant /users/John/ privilege hr:author grant /users/Sue/ privilege hr:editor ... /files/departments/sales/ ... grant /users/Johan/ privilege hr:editor ... As you can see this is a simple way to specify what role a subject plays for an object. It makes the system a lot easier to use because users don't have to deal with loads of 'obscure', low-level privileges. When the privileges of a role change, the changes are reflected immediatly throughout the repository. These custom privileges are treated like the normal (D:read, D:write, etc.) privileges so all DACL properties and DACL reports will work as expected. A PROPFIND for D:current-user-privilege-set for user John on /files/news/ would return: hr:author hp:requestReview D:read D:write ... (all aggregated privileges of D:read and D:write) How === To implement the above solution I had to come up with a way to define custom privileges. The implementation had to be backwards-compatible with existing repositories. Privileges (including the standard ones) are defined in the following way: all leaf nodes (at any depth) under /actions/ are considered to be a privilege. The last segment of their URI determines their name. If a privilege has a D:privilege-namespace property than this will be used as its namespace, otherwise the DAV: namespace is assumed. For example: /actions/read/ (no D:privilege-namespace property) -> D:read /actions/hippo-privileges/publish/ (D:privilege-namespace = http://hippo.nl/cms/privileges) -> hp:publish /actions/hippo-roles/editor/ (D:privilege-namespace = http://hippo.nl/cms/roles) -> hr:editor The namespace prefixes for custom privileges are there for brevity. There is currently no way to specify the namespace prefix to use for a namespace, because there is no single point of definition of a namespace. Results from DACL queries will therefore contain 'xmlns:' attributes in elements representing custom privileges. Changes ======= I modified SecurityImpl to be aware of the custom privileges. The privileges cache was only loaded during construction of the object, but I added a detection of changes to the privileges which invalidates the cache. Because the cache is not needed very often this won't lead to a lot of reloading of the cache when multiple changes to the privileges are taking place. A namespace attribute has been added to ActionNode which is set to the D:privilege-namespace property of the privilege. This namespace is not needed and it is expensive to determine in certain situations, so it is optional. However when an attempt is made to retrieve the namespace and it is not present an exception will be thrown (hasn't happened to me yet). The PropPatchMethod converts absolute URIs in href elements to relative ones (the Servlet context path is removed). This is a reversal of the conversion in PropertyRetrieverImpl. Throughout the code comparison of ObjectNode and its subtypes, and subject and privilege URIs were performed by an identity comparison. I changed all these identity comparison into the use of equals. I also removed code from SubjectNode which retrieved the singleton of a specific URI (for both Strings and SubjectNodes). Remarks ======= Currently the knowledge about how actions are defined is in multiple locations. This will have to refactored. The locations are: =SecurityImpl.addActionLeafsToActionAggregation(...) = AclMethod.findAction(...) = PropertyHelper.addGrantedActionsToPrivilegeSet(...) Cache invalidation detection is done by the checkPermission(...) methods of SecurityImpl. This is obviously not the way to go, so suggestions for a better location are welcome. The system was and still is very fragile. Granting/denying a privilege which does not exists leads to exceptions. More checks need to be built in to handle invalid input and inconsistent state (e.g. a privilege which has been granted/denied and has its defining node under /actions/ deleted). Some DACL reports did not and still do not work according to the specification. That's it. I hope this extension is useful for other people as well. I am eagerly awaiting your questions and/or comments. Kind regards, Johan Stuyts Hippo --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
