Custom 403 page not available to user who doesn't have 'access content' permissions
simon.males - December 8, 2007 - 04:00
| Project: | Drupal |
| Version: | 6.14 |
| Component: | menu system |
| Category: | bug report |
| Priority: | normal |
| Assigned: | Unassigned |
| Status: | active |
Description
If an anonymous user does not permission to access content, then an anonymous user is unable to access a custom 403 (access denied) page.
Steps to reproduce:
- node/add/page > Title 'Custom 403 page' > Save (node/1)
- admin/settings/error-reporting > Default 403 (access denied) page: node/1
- admin/user/permissions > anonymous user: de-select 'access content' under 'node module' > Save
Outcome:
Accessing the site as an anonymous user will display the default Access denied message. The expected result is view the contents of node/1.
I tried to do some digging and discovered that the default 403 page was being casued by MENU_ACCESS_DENIED being returned in menu_execute_active_handler(). I got lost after menu_get_item().

#1
Bug can be replicated in 6.0-rc1, updated version accordingly.
#2
I was able to reproduce this in 6.x-dev. Patch is attached. Removed check for MENU_ACCESS_DENIED, which doesn't make sense when attempting to serve the custom access denied page.
#3
Bug replicated in RC2... I am unsure about current status of patch, as MENU_ACCESS_DENIED may or may not need to stay there.
#4
Anyone mind taking a look at this? It's a relatively minor change and I think should be patched in 6.x, and applied to 7.x as well.
#5
This is still a bug in the production release. It seems the above patch was included in -- but seems to still not give access to the "custom page"
#6
The patch was never applied to core. It still needs review.
#7
Moving to 7.x in hopes of being backported.
Patch still applies successively to HEAD.
#8
Subscribing, and will probably be willing to backport to 6/5.x if needed and if noone beats me to it.
#9
Pretty sure this a non issue in 5.x, I have this setup working in 5.x and was trying to do the same in 6 when I discovered the bug.
#10
Here is a test for Simpletest module for this issue.
The patch #2 has passed the test.
<?php
class TestCase198975 extends DrupalTestCase {
function get_info() {
return array(
'name' => t('[198975] Custom 403 page not available to user who doesn\'t have \'access content\' permissions'),
'desc' => t('If an anonymous user does not permission to access content, then an anonymous user is unable to access a custom 403 (access denied) page.'),
'group' => t('Drupal 7 Tests'),
);
}
function testIssue() {
// save original perms for 'anonymous user'
$anonymous_user_perm_orig = db_result(db_query('SELECT perm FROM {permission} WHERE rid = %d', DRUPAL_ANONYMOUS_RID));
// create a custom 'Default 403 (access denied) page'
$web_user = $this->drupalCreateUserRolePerm(array('edit own page content', 'create page content'));
$this->drupalLoginUser($web_user);
$edit = array();
$edit['title'] = 'Custom 403 page ' . $this->randomName();
$edit['body'] = 'Custom 403 page ' . $this->randomName();
$this->drupalPost('node/add/page', $edit, 'Save');
$node = node_load(array('title' => $edit['title']));
$this->drupalGet('logout');
// set a custom 'Default 403 (access denied) page'
$this->drupalVariableSet('site_403', "node/{$node->nid}");
// check 'anonymous user' can reach custom 403 page with 'access content' perm
db_query("DELETE FROM {permission} WHERE rid = %d", DRUPAL_ANONYMOUS_RID);
db_query("INSERT INTO {permission} (rid, perm) VALUES (%d, '%s')", DRUPAL_ANONYMOUS_RID, 'access content');
$this->drupalGet('admin'); // a common restricted url
$this->assertWantedRaw($edit['title'], "Check with 'access content': %s");
// check 'anonymous user' can reach custom 403 page without 'access content' perm
db_query("DELETE FROM {permission} WHERE rid = %d", DRUPAL_ANONYMOUS_RID);
$this->drupalGet('admin'); // a common restricted url
$this->assertWantedRaw($edit['title'], "Check without 'access content': %s");
// delete the custom 403 page
node_delete($node->nid);
// restore original anonymous user perms
if (!empty($anonymous_user_perm_orig)) {
db_query("INSERT INTO {permission} (rid, perm) VALUES (%d, '%s')", DRUPAL_ANONYMOUS_RID, $anonymous_user_perm_orig);
}
}
}
?>
#11
@Vladimir, thanks for the tests, looks good and should be good for further iterations of the patch as well.
@Everyone: Why would getting a custom 403 page result in a MENU_ACCESS_DENIED return value at all? The idea of this check is if there was no return value, or it was a stock menu constant, the stock error page should be output, if I understand this right.
#12
I'm not sure that I've gone about this the right way, but shouldn't the developer who committed the change be contacted. In this case 'goba'.
http://cvs.drupal.org/viewvc.py/drupal/drupal/includes/common.inc?view=d...
#13
simon.males: Why should I be contacted? The patch you pointed out was http://drupal.org/node/84754 so refer there.
#14
#15
Here's a re-rolled patch that is applicable from Drupal root. Looks good, but not tested.
#16
Bug replicated on a on a clean D7 from head.
Applying http://drupal.org/files/issues/403-access-denied-fix_0.patch doesn't fully work for me:
- the custom access denied page (node/1) is shown, but its body content isn't. Instead, the digit '3' is shown.
- the custom access denied page (node/1) is not shown when trying to access it directly via node/1. In this case you get the default access denied page
#17
Forgot to change status > needs work
#18
jopsesen, i think the behavior you raise in your second point is actually correct... you only want them to be able to view the node in the context of a 403 error.
#19
Subscribing
#20
I can confirm that this is a problem in 6.4 and is not a problem in 5.10. Is this being worked on now for the 6.x codeline?
#21
@gtaylor: Is it no longer a problem in 7.x? If it is still a problem there, that's where it should be fixed. The fix for 6.x follows after.
#22
sorry for the confusion. I can't speak one way or the other to 7.x.
But I can confirm that's it's working in 5.10 if the node number is greater than 2.
#23
Uhh.. not a problem in 5.10?
We have to use a hack (revert #84754-32: Fix of non-existent/denied 403/404 pages) to allow users to get a logon screen when anonymous users don't have access to a page. So i would say this one is an issue even for 5.10.
And we have /node/7 as our 403 page.
#24
subscribing
#25
Bug replicated in 6.5. Does anyone know any fixes for 6.x or somewhere where it is discussed?
#26
subscribing
#27
@durum please when marking as duplicate say where is the other issue to be able to follow that one instead
#28
@arhak,@others: sorry, i don't remember.
But I found something: After adding about 20 pages(I didn't check after each page, so probably it is less) the function works regardless of the id of your custom 403 page.Hth.
#29
well, if somebody hits the other issue, please let us know
#30
Seeing this post, I added 22 pages to my site. The 403 page still does not appear, and I get the "Access Denied" still. This is a serious issue for my client. I am very seriously considering dropping Drupal if this is not fixed soon.
#31
BENWECHSLER, I am sorry about it but it worked for me. Just check it out: www.littlebigventures.com/asdasd#32
durum, Can you give me details about the pages you added? I tried up to 30 new pages and still no success. See my site at http://riverwalklofts.org/content.
#33
BENWECHSLER, I AM SUCH A DUMB! I am very very sorry for misleading you and others. Nothing was changed. I had just allowed unregistered user to see content and custom 404's were working and I didn't realized that nuance and my poor brain acted like it was working.
BTW, I found something else in my new site but it may not work if your default language is English. I just translated the strings for
into something like
and I at least have the message given.
If you can't find a way of re-translating or changing the built-in interface strings (i don't know any), you can download the English translation pack (if there is any) and show it to drupal as it is some language else (like 'de') by changing all the occurences of 'en' and then install it and make the modifications you want.
If there is no language pack for English or you don't want to have such a load in database, maybe you can search for an occurence of "Access denied" in database and then change that one into "Under Maintenance". Doing this, make sure you have everything backed up!
Or, -I am not sure if this will work- you can create any new Language by Languages>Add Language, and than make it default. Since it will not have any strings in it, the English strings will be used. And in Translate Interface you will be able to search for and change the string "Access denied". I think this will work and looks like the best solution among all.
Anyways, you better have a full backup before trying any of these.
Sorry again. Hope the latter solution helps.
#34
I was having a related (if not the same) problem on my installation of Drupal 6.10
Here is my fix. It works. Use it at your own risk.
I got tired of searching through the Drupal APIs for functions to retrieve a node's title and content given its path so I just used a query.
original common.inc
<?php
function drupal_access_denied() {
drupal_set_header('HTTP/1.1 403 Forbidden');
watchdog('access denied', check_plain($_GET['q']), NULL, WATCHDOG_WARNING);
// Keep old path for reference.
if (!isset($_REQUEST['destination'])) {
$_REQUEST['destination'] = $_GET['q'];
}
$path = drupal_get_normal_path(variable_get('site_403', ''));
if ($path && $path != $_GET['q']) {
// Set the active item in case there are tabs to display or other
// dependencies on the path.
menu_set_active_item($path);
$return = menu_execute_active_handler($path);
}
if (empty($return) || $return == MENU_NOT_FOUND || $return == MENU_ACCESS_DENIED) {
drupal_set_title(t('Access denied'));
$return = t('You are not authorized to access this page.');
}
print theme('page', $return);
}
?>
altered common.inc
<?php
function drupal_access_denied() {
drupal_set_header('HTTP/1.1 403 Forbidden');
watchdog('access denied', check_plain($_GET['q']), NULL, WATCHDOG_WARNING);
// Keep old path for reference.
if (!isset($_REQUEST['destination'])) {
$_REQUEST['destination'] = $_GET['q'];
}
$path = drupal_get_normal_path(variable_get('site_403', ''));
if ($path && $path != $_GET['q']) {
// Set the active item in case there are tabs to display or other
// dependencies on the path.
menu_set_active_item($path);
$return = menu_execute_active_handler($path);
}
if (empty($return) || $return == MENU_NOT_FOUND || $return == MENU_ACCESS_DENIED) {
if ($path && preg_match('/^node\/\d+$/', $path)) {
$nid = preg_replace('/^node\/(\d+)$/', '$1', $path);
$r = db_fetch_object(db_query("SELECT `title`, `body` FROM `node_revisions` WHERE `nid` = '$nid' LIMIT 1;"));
drupal_set_title(t($r->title));
$return = t($r->body);
} else {
drupal_set_title(t('Access denied'));
$return = t('You are not authorized to access this page.');
}
}
print theme('page', $return);
}
?>
#35
Just installed the freshly-minted D6.13, and it is still having the same problem. I've also got a site that needs to have all content hidden from anonymous users, but instead of getting my defined 403 page served up, I get the stock "Access denied" page.
Is anyone working on this one? It seems like something that would be critical for a non-public site running Drupal... In our case, we are using it as a secure CMS for our customer base.
Problem page can be seen here (bear with me - it's under development so still mostly stock right now, depending on when you read this):
http://www.peirspeed.com/support
Any help would be greatly appreciated! I'm also going to look into delving into bug fixes myself in the near future, but simply don't have the time right now (large site I have to have built in 30 days - which is why I went with Drupal).
Thanks!
-R
#36
arpieb,
As far as I can see your problem seems server related - meaning that your server doesn't redirect the error back to Drupal and lets Drupal show its message, but serves the default server based message. This might be an .htaccess or server configuration issue rather than a Drupal problem.
The problem the rest of us have (yes, I have it too), is that Drupal seems to serve it's own fairly primitive Access denied text rather than our own meticulously crafted, intelligent error page made within Drupal.
The replacement works nicely for my 404-page, but the 403-ditto reclines all appearances. Haven't tried the patches, but this certainly ought to work out of the box. As a temporary remedy I have used the translation function to write a somewhat more explanatory text in Danish (the site is in Danish), but I would very much like to be able to replace it with a real page.
Martin
#37
Well, I solved my own 403-problem. Using URL aliases and pathauto my system had set the URL for the 403-page to a name, which contained diacritical Danish letters, and I simply pasted this URL into the admin/settings/error-reporting page.
On a hunch I tried setting the URL manually to something "harmless" and changing the 403-settings and voila! It works nicely now, and I get my custom made Access denied page with more links and more help than is available in Drupal's default message.
Martin
#38
I can say #34 works for me too, except that I use a database prefix, so `node_revisions` needs to be changed to `prefix_node_revisions`. I'm not a programming expert, but hopefully someone can fix this to accommodate for database prefixes.
#39
@#38 change where
`node_revisions`for{node_revisions}and it will work for prefixes#40
Ok. I just updated a site from D5.7 - it was a pretty customized site - and ran into this issue as well. My solution was two-fold. Utilizing the code change in #34 as well as modifying the Error Pages in IIS(7.5) to point to index?q=node/4 (my 403 error page) seemed to take care of it. I did have to do BOTH..
I'm not sure why this "feature" has been ongoing since D6 and continues in D7 apparently. It would seem logical that some folks would want to create a private site where you need to be a member to gain access to the content - so content access being disallowed for Anonymous would be out of the question. I really dislike changing .inc code because I have to remember it for the next update.
#41
I can confirm that this feature works in Drupal 5.19, but not in 6.14. Implemented the patch in #34 and it looks good for what I need. Thanks.