Drupal - How do I debug permissions?
One way you can do is make a custom module, print access info on every page, every node, every block.
menu_get_item() function return a router item which has access_arguments property for current page.
/**
* Show access permission of current page.
*/
function yourmodule_get_page_access() {
$router_item = menu_get_item();
if ($router_item) {
$access_arguments = unserialize($router_item['access_arguments']);
$arguments = array();
foreach ($access_arguments as $access_argument) {
$arguments[] = $access_argument;
}
if ($arguments) {
$output = '<p>';
$output .= t('This page needs user to have %p permission(s) to access', array(
'%p' => implode(', ', $arguments),
));
$output .= '</p>';
}
else {
$output = '<p>' . t('This page needs no user permissions') . ' </p>';
}
return $output;
}
}
Then you can hook_page_alter, to display the access info on top of every page.
/**
* Implements hook_page_alter().
*
* Display access information on top of every page.
*/
function yourmodule_page_alter(&$page) {
// Make a new area on top of the page for displaying access information.
$page['content']['theverytop']['#markup'] = yourmodule_get_page_access();
$page['content']['theverytop']['#weight'] = -10;
$page['content']['#sorted'] = FALSE;
}
Next you can display out the block permission info like this:
/**
* Implement hook_block_alter
*
* To display block permission information to the block title.
*/
function yourmodule_block_view_alter(&$data, $block) {
$delta = $block->delta;
$output = '';
$rid = db_query("SELECT rid FROM {block_role} WHERE delta = :delta", array(':delta' => $delta))->fetchCol();
if (empty($rid)) {
$output = ' This block does not have any role permission restriction.';
} else {
$output = ' This block is viewable for users have role(s): ';
foreach ($rid as $role_id) {
$rolename = db_query("SELECT name from {role} where rid = :rid", array(':rid' => $role_id))->fetchField();
$output .= $rolename . ' ';
}
}
// append the permission info to block title for every block
$block->title .= $output;
}
And so forth, basically the same concept, you can do the same to node, form, views. Hope this helps.
Edit the User module main file; find the user_access()
function, add 2 lines before the return
statement, and monitor the PHP error log.
$granted = isset($perm[$account->uid][$string]);
error_log(sprintf('--- user_access: %s "%s" = %s', $account->name, $string, $granted ? 'yes' : 'no'));
return isset($perm[$account->uid][$string]);
It looks like like you've got all the GUI-based tools already to troubleshoot permissions. One more advanced (and probably more difficult) trick I've used effectively in the past is:
- Construct a View with the fields, roles, node-types, etc. that I want to test for.
- Enable "display query" on the Views advanced options page.
- Execute the View and paste the SQL query into a GUI-based SQL editor such as Navicat (commercial) or MySQL Workbench (free).
- See what nodes don't show up.
- Tweak the query to your needs.
I many cases the queries that Views spit out are rather complex (shock full of joins) and to construct them manually would take a little bit more time (plus it would be a little bit more error-prone). Also this approach ensures that you are testing against what the user is seeing. If you have any permissions modules enabled (that make use of Drupal core permissions), their table joins will show up in the query used by Views. Once I got this query I tweak it to show how many nodes of content type x are allowed for role x, for example. It's as accurate and fine-grained as reporting can get. And those are my "advanced" reports.