WARNING: Using multiple access control modules is a very powerful capability. It is assumed that if you are doing this you understand basic boolean algerbra and know enough to test things before deploying them. The use of a single access control module is not affected by these patches WARNING 2: This project is in Alpha and while I have working code for all features except the user interface, it needs more testing before I feel comfortable releasing it into the wild. Proposal (code in Alpha stage) Allow multiple access control modules to work together (ACM). An ACM is defined as one that hooks into node_grants and manipulates the nodes_access table. Drupal 4.6.1 effectvly ORs the permissions of all access control modules rendering their usage confusing and unreliable. Following is a mechanism that allows an intermediate to advanced Drupal administrator to combine access control modules more reliably. 1. Normal sites with zero or more ACMs operate the same with simular levels of performance. * Done! 2. Site Admins have as much control over ACM precedence as can be managed with the current ACM API. * I think a tremendous amout of control has been added to Drupal's access model. 3. Optimize code for speed where ever possible. * See Benchmarks below. Performance for 0 or 1 ACM is identical to the current Drupal. As soon as 2 or more modules are added a performance hit occurs. 4. Avoid changes to anything outside node.module * No changes are needed outside of node.module 5. Avoid changes to any current ACMs * Taxonomy Access, Organic Groups and NodePerm_Role all seem to work. 6. Code for PostgreSQL and MySQL * Although I prefer PostgreSQL the current alpha code is coded for MySQL and I have not tested it under PostgreSQL. The queries are all straight forward so it should work fine. Do note that I have found PostgreSQL's handling of the IN clause to be very slow but that appleis to the current Drupal version as well. Access Control Templates This is probably the hardest part to explain. I am working on the interface but that involves yet another learning curve so examples will have to suffice. First I wish to ephisize that I consider using multiple ACMs an advanced subject and anyone doing so probably has the knowledge to make a simple template. If you do not then use 0 or 1 ACMs and everything will work as it does with no configuration needed. Image a nice node_access user interface. It has some help text, 3 input fields and follows with help text optionally added by each ACM. The 3 input fields allow you to specify how the ACMs should be processed using SQL like boolean logic. The complexity of the ACT has almost no impact on performance. All the matters is the number of unique modules the ACT includes. ACTs consist of 1 or more module names (without the .module) suffixe, connected using AND or OR and parenthesis. In addition the permission to check in each module defaults to the ACTs permission but can be overridden by appending the permission (view, update, delete) to the module name with a '.'. The global 'all' realm is automatically disabled if an ACT is defined. If desired it can be accessed with the 'node' module name. Be aware that most ACMs delete the 'all' realm upon activation. Also note that most modules re-create the 'all' realm on deactivation! This is why it is ignored if an ACT is defined. The default ACT is blank and the will be treated as a simple ACT ORing all loaded/activated ACMs. This is the same as in Drupal 4.6.1. Examples View : If a user has any of these permissions the node can be views. Note that this is a simple ACT since it does not include an AND statement. Note that if this check fails, the more complex TACs will not be triggered since Drupal doesn't botehr checking for write permission if view does not exist. og OR taxonomy_access OR nodeperm_role Update : If the user is in the group AND taxonomy allows it OR the node has explictly granted permission then allow editing. Note that the 'view' permission was defined for 'og' since it lacks 'update' and 'delete' for nodes and sets these to 0. (og.view AND taxonomy_access) OR nodeperm_role Delete : Same as update. (og.view AND taxonomy_access) OR nodeperm_role User Interface This is a BIG to do. See Access Control Templates. I intend to include syntax checking and help text. The proto type code currently hardcodes the ACT strings. But first I need to learn how to build a module settings page ... Benchmarks For a default install with 0 or 1 ACMs installed the speed is identical to the current speed. I spent a great deal of time adding code to optimize OR based ACMs (which is fine for the default configuration). More generally speaking if your ACT avoids the use of the AND logical then a high speed query is built instead. For more complex ACTs where an AND is required the speed of Drupal is impacted. I optimized the query process and added some simple caching to reduce the impact. The following list was based on my test system, an Athlon XP 2600+ with 512MB, using a node_access table with 13,000 entries evenly split among 4 ACMs. This represents about 3250 content nodes. The use of 4 ACMs is probably unusual but I wanted to do a stress test. * 20 ms to build base temporary table * 16-33 ms for each module * ACT logic is almost instantanios * These are cached (1 hit includes all permissions) for the session so they are a one-time per page hit. These are quite a hit on performance. For me this jumps a page load from 161 ms to 267 ms! The performance can be increased somewhat by limiting which nodes are protected by which module. My example placed all 3,250 nodes under the influence of ALL modules. In most cases this would not be the case. In general it is a linear scale, the more nodes that are under the influence of a module the longer the queries take. NOTE: I did try a very complex inner join query and that works wonderfully as long as there is a where clause set by the caller to a nid or series of nids. For open ended queries, for example first 10 nodes the user can view, the query time jumped to 5 (with indexes) to 34 (no indexes) SECONDS per page. Obviously the more queries performed the slower things go. Basically assume that performance will be reduced in a near linear fashion for each ACM you install and enable. There is the possibility of some improvements in execution speed but these are outside the node.module and currently beyond my scope. Optimizations Where, Join, From clauses are all cached for the current session/user. For complex ACTs the temporary table is will be built using one query for each module regardless of the number of times that module's name appears in the ACT. For simple ACTs (do not use AND) the queries are optimized to avoid using a temporary table and are as fast as the current Drupal. This applies even if permissions are explictly specified. Limitations: There is no concept of node type. This limits some access logic since OG has two realms it uses in the node_access table. I do not have need for this level of control and am not sure it is benifical. Performance when 2+ mdoules are active is an issue. By limiting the nodes impacted performance can increase. Changes to node.module: * Optional templates define the logic for combining multiple grants_node hook modules * Split node access components into a separate module (node_access.inc) that is included by node.module * module was named .inc to avoid confusing Drupal's module loader * include once was added to node.module * Exiting methods were left formatted as is to avoid polluting diffs * The following are depreciated * node_access_grants : unchanged but no longer used. No core code outside of node.module was found that called this. It's functionality was replaced with node_access_grants_sql. Using this method for building access queries will bypass this patch. * _node_access_join_sql : recoded to use node_access_grants_sql. Its input/output is backwards compatible. No core code outside of node.module was found to use this. * _node_access_where_sql : recoded to use node_access_grants_sql. Its input/output is backwards compatible. No core code outside of node.module was found to use this. * The 'all' realm is disabled if there are any modules overriding the 'node_grants' hook * This is probably the riskiest modification I did and the one I am most concerned about long term * But there is way to restore it, see below * node_grants modules must delete the 'all' realm to have any effectiveness therefor ignoring it should be OK if there are any node_grant hooks in place. * If it is NOT ignored then when a module is deactivated and RESTORES the 'all' realm the node filters become useless * The default 'all' realm can be checked by explicitly using it in a template * node OR (.....) * If there are no 'node_grants' hooks then the 'all' realm is used even if not listed in templates and is used as an OR condition.