Many folks have heard me go on about the na_arbitrator and why we need it. Few, it seems, actually understand it.

Problem:
The node_access table is currently free for all. However, the way the query works, if any node has records in the node_access table, then all nodes need node access records. Any module that utilizes node access must, therefore, maintain the node_access table for everyone. This alone is a problem, because a module simply may not be interested in some significant portion of a site's nodes.

But it gets worse: two modules cannot, together, maintain the node_access table. It is impossible. Therefore, one cannot use taxonomy_access, simple_access and organic_groups together.

Solution:
node.module must take ownership of the node_access table. It and it alone will have the right to write records to this table. If modules are interested in access rights on a node, they must tell node.module via a hook.

In this implementation, modules interested in node_access implement a hook (hook_node_access_records) in which they return an array of arrays of node access information, including a simple priority. node_access then takes whomever has the highest priority and writes their information.

If nobody cares, it writes a simple all grant and gives everyone access.

Pros to this approach

  • Multiple node access modules can work together. I have a workflow_access and a forum_access module that happily coexist and do waht they need to do and let the rest of the world do what they might.
  • A module can set its records with a high priority and actually perform a deny.
  • All node access modules have significantly less code than they had before.

Cons to this approach

  • All existing node access modules break, badly, and need to be redone.
  • The deny isn't a good deny, it's very simple. There could be a better method but I'm not sure what it is offhand.
  • Resetting the node_access table can take a long time with thousands of nodes. Not sure that's particularly a con to this approach so much as a con to the node_access table.

Comments

merlinofchaos’s picture

StatusFileSize
new176 bytes

Unable to include node.install in patch, attached here

chx’s picture

Status: Needs review » Needs work

If you want to rename to hook_node_user_grants just do it. Modules need a serious upgrade anyways. I would be extremely wary of a current() call without a reset, what's the problem with array_shift?

These are just nitpicks. Extremely nice work.

chx’s picture

Status: Needs work » Needs review

I set back to review because if i set to needs work , noone will review and my nitpicks are just that.

merlinofchaos’s picture

StatusFileSize
new5.56 KB

While integrating na_arbitrator into this, I'd actually renamed the other hook to be less confusing. Now the two hooks you need are:

hook_node_grants() -- tell node_access what permissions a given user has
hook_node_access_records -- tell node_access what the permissions are on a given node.

current() removed and replaced with array_shift() which is fine in this context. Ordinarily I prefer to avoid array_shift because it is destructive, but the array it's being shifted out of is going to die soon anyway.

moshe weitzman’s picture

this patch makes complete sense, and the code looks reasonable. in order to test it, we really need a compatible node_access module.

@merlinofchaos - is the forum_access in contrib compatible with this patch? i know that dries and others really want private forums and foru moderators in core. perhaps you can update that one (if needed) and attach here or in separate issue. it just might get into core too.

merlinofchaos’s picture

StatusFileSize
new5.03 KB

Here is the forum_access module I was using for testing. I'm not sure the code for this is core worthy, I wasn't being quite as attentive to that when I wrote it.

Due to the fact that I wanted it to support moderator lists, it also includes the acl.module which is just an API for doing user lists with the node access stuff.

moshe weitzman’s picture

Status: Needs review » Reviewed & tested by the community
StatusFileSize
new5.92 KB

I gave this a good code review and good test. It holds up well. I think the benefits here are substantial. Furthermore, the risk is quite small. We are not changing at all how Drupal calculates access to nodes. We are just centralizing the writing to the node_access table so that modules can work together properly. This is consistent with rest of core. We do not have tables which any old module writes into directly.

My patch removes some fuzz, and renames the 'reset' feature to 'rebuild' since the final product is a perfectly recalculated node_access table, not an empty one. I also optimized this function for sites that don't use node_access. Those sites don't have to iterate over all nodes. Nice for the update function especially. I'd for for Earl or someone else to look at my changes in this rebuild function, so I set this top Review for now ... My next post includes a new node.install file.

We will work more on forum_access module once this patch gets in.

moshe weitzman’s picture

StatusFileSize
new129 bytes

as promised

merlinofchaos’s picture

It all looks good, Moshe.

This merits a changelog entry, and I'll need to write up new documentation for node access modules.

moshe weitzman’s picture

StatusFileSize
new6.02 KB

i have converted og in my localhost to this new framework and all is looking good.

here is a new patch which fixes a small bug in the write_grants function. it also takes care not to show the node_access rebuild settings for sites that already have a clean node_access table (the default). earl has reviewed these changes.

the .install files posted here are no longer needed. please ignore them. node_access modules will perform any needed updates themselves. this is required to do the migration without data loss. those modules did the original writing of grants to the DB.

drumm’s picture

Status: Reviewed & tested by the community » Fixed

Committed to HEAD.

I'd like to see documentation, a progress bar for regranting, and automatically doing the regranting in the future.

drumm’s picture

Category: feature » bug
Status: Fixed » Active

Actually, we need some work on the menu item done. It should not mention 'node' in the title and the categorization should be verified.

merlinofchaos’s picture

StatusFileSize
new2.16 KB

Ok, here's a current update that accomplishes the following goals.

1) It renames node_access_rebuild back to node_access_rebuild_page and _node_access_rebuild back to node_access_rebuild. I don't know who changed it to _node_access_rebuild() but this is NOT a private method; modules need this.

2) It changes the text because now that we have enable/disable, the button is really only a safety valve; a way to restore a site whose node_access table has become messed up.

drumm: I don't know what else to call the node access system to hide the word 'node' from the title. 'post access' doesn't work, and it creates multiple names for a system that can only create confusion later on.

merlinofchaos’s picture

Status: Active » Needs review
merlinofchaos’s picture

StatusFileSize
new2.2 KB

Urk. Ignore the preceding patch, it's totally broken. Try this one.

merlinofchaos’s picture

StatusFileSize
new2.28 KB

I gotta stop going back and forth. Having to redo stuff 3 times makes me forget which parts I redid enough times.

merlinofchaos’s picture

StatusFileSize
new13.98 KB

Here's a patch for the documentation. This patch depends on my previous patch, since node_access_rebuild isn't properly named. Conveniently it also provides an updated node access example module.

I can, of course, commit this patch but a review would be good.

m3avrck’s picture

Docs look good, I have a much better understanding of the that whole mess now :-)

drumm’s picture

Status: Needs review » Needs work

Can't the menu callback be simply node_access_rebuild_page, instead of explicityl calling drupal_get_form()?

I think the comma before the 'or' in the changed string is unnecessary since there are only two alternatives. I think that string could in general be made more brief and concise, for example "updated to newer code" could be "upgraded."

merlinofchaos’s picture

Status: Needs work » Needs review
StatusFileSize
new2.31 KB

Can't the menu callback be simply node_access_rebuild_page, instead of explicityl calling drupal_get_form()?

According to Eaton, this is how it should be done if a page is just a form.

Doublechecked on the , -- grammatically speaking, the , can be there or not, but asking a couple of people who write professionally, they prefer the , because it keeps the thoughts distinct. However, I would add a 'when' in the second clause.

I don't see how making that sentence more terse is beneficial to anyone. It may not be clear what 'upgraded' actually means and this page is already a bit unclear.

So repatching to add a 'when' to the 2nd clause.

beginner’s picture

Status: Needs review » Reviewed & tested by the community

Reviewed. Previous concerns have been suitably addressed.
The patch still applies with a small offset.

merlinofchaos’s picture

Priority: Normal » Critical

Moving up to critical --

This patch fixes an API that was incorrectly committed, and the longer this sits the later an API change goes in, which could affect any users who are updating their node access modules.

As well, I can't commit the documentation until this patch goes in, since the doc and example assumes the function is named as it should be.

AjK’s picture

subscribe

dries’s picture

IMO, this is an ugly problem with a ugly solution.

drumm’s picture

The patch seems relatively straightforward and good to me. This is a weird page to have, but we have it and it should work.

Dries, any further review?

drumm’s picture

http://drupal.org/node/84562 marked as a duplicate of this.

drumm’s picture

I managed to test this. +1

Kjartan’s picture

Managed to test this as well, have some comments.

There is a very minor coding style issue in the patch, there is a space before function node_access_rebuild_page_submit() { that needs to be removed. This patch, since the rest has gone in should be committed.

However, going back to the original patches and not the latest fix which should go in. Does the node access menu item really have to be a menu item? The way it is coded now this query will be run on pretty much every page hit. Wouldn't it better to move it out of the menu and instead have it be an additional option on the node settings page? This doesn't strike me as a feature that needs its own menu item as you should only have to run it if something has really gone wrong. Burry it somewhere with lots of warning text to never ever run this unless you have good reason to. This way it a) doesn't have a performance hit unless the user is on a specific page (menu is slow enough as it is), b) users might not get in trouble by playing around with menu items.

Also I wonder if this needs to work like search-index and be able to run in mutiple cron runs. Anyone got any data on how many nodes/node_access modules you can have before a rebuilding of the node_access table can't happen in one run?

The other thing is that in general the node access stuff can very easilly get you in all sorts of trouble, all you need is one poorly coded module that does the wrong thing. To combat this there needs to be more documentation, both for developers so they what the Right Way is, and for end users so when they download a node_access enabled module they some documentation to get them out of trouble.

moshe weitzman’s picture

i'm fine with moving this elsewhere. don't know where though ... the whole point of this feature is to fix the "something bad happenned to my site " problem. you disable the offending module and rebuild and then the site is in a consistent state again.

merlinofchaos’s picture

Kjartan, Moshe, I split off your concerns here: http://drupal.org/node/87415 -- let's discuss that on a separate issue. I'll have more comments for it in about 12 hours.

Kjartan’s picture

StatusFileSize
new6.29 KB

This patch moves the node rebuilding button from the menu to the node settings page, and adds a confirmation step to make sure the user really wants to do this.

moshe weitzman’s picture

StatusFileSize
new6.1 KB

tested and all works well. code looks good.

this reroll fixes a typo and removes inconsistent bold descriptive text for the rebuild button. was bold, and is now normal.

dries’s picture

Code looks good but can't help but think this is one of the ugliest (but necessary?) solutions I've seen in a while. :/ I'll commit it later on.

webchick’s picture

Dries, could you elaborate more on what is ugly? Is it the fact that we need to rebuild the node_access table, or..?

dries’s picture

Status: Reviewed & tested by the community » Needs work

Reading the help text, it is not clear what the consequences are. Will I loose data? Will I have to fix up the individual nodes after I wiped the permissions? What can I loose? It would be great if the documentation was a little bit more 'action oriented' or 'practical' even (focus on what is expected from the user after taking this action).

It also looks weird to do a drupal_goto() in a validate function.

We should avoid using 'node' in user output -- maybe this is a valid exception. It is debatable. The fact is that things like 'node access table' are not user-friendly. My mother would wonder what a 'table' is in this context?

owen barton’s picture

This looks really good work to me.

The only 'ugly' part as far as I can see is the 'rebuild' button. It would be better if we could make a 'hook_module_disable' that fires whenever a module is noted as disabled. The node module could then use that hook to trigger the rebuild.

treksler’s picture

iirc there is already a hook_uninstall just for this purpose?

Kjartan’s picture

Status: Needs work » Needs review
StatusFileSize
new6.52 KB

Updated the help text to be more extensive.

chx’s picture

Status: Needs review » Needs work

This:

 if (db_result(db_query('SELECT COUNT(*) FROM {node_access}')) > 1 || count(module_implements('node_grant'))) {

became:

 if (db_result(db_query('SELECT COUNT(*) FROM {node_access}')) == 1) {

This does not look good to my eyes.

Kjartan’s picture

Status: Needs work » Needs review
StatusFileSize
new6.58 KB

My bad, forgot to undo the debug if(). Fixed that and changed the comment to accurately describe what the check does.

dries’s picture

Status: Needs review » Fixed

A lot better. Committed to CVS HEAD. Thanks.

edrex’s picture

Are these API changes undocumented on converting to 5.x because they're still in flux?

Anonymous’s picture

Status: Fixed » Closed (fixed)
somebodysysop’s picture

Version: x.y.z » 5.1
Priority: Critical » Normal
Status: Closed (fixed) » Postponed (maintainer needs more info)

I keep hearing that Node Arbitrator Module has been incorporated into Version 5.1 (which I have installed), but where is it? How do I get to it? How do I use it? I can't find any documentation on this. Please help. I need it to iron out an issue between OG and TAC. Thanks.

moshe weitzman’s picture

Status: Postponed (maintainer needs more info) » Closed (fixed)

The code is in node.module. There really isn't a UI for it. There is a 'rebuild permissions' option somewhere if you have a node accewss module enabled. thats supposed to be used in rare cases when you think your tables might be out of whack.