404 rather than 403 when accessing item without permission

I'm in the process of creating a plugin to notify admins when a new record is submitted into a workflow process. They'll receive an email with the admin URL for the record...so something like: http://www.blah.com/admin/items/show/2973.

Obviously, that URL won't be accessible until they've logged in. Currently, however, when you get to this bit of code in application\libraries\controller\omeka\action.php (line #597):

//Check to see whether to record exists at all
            if (!$table->checkExists($id)) {
                throw new Omeka_Controller_Exception_404(get_class($this) . ": No record with ID # $id exists" );
            } else {
                throw new Omeka_Controller_Exception_403('You do not have permission to access this page.');
            }

...it throws a 404 rather than a 403. That appears to be because of the nature of the query that's run in the $table->checkExists() call. If I look at the logs, here's what happens:

2011-08-18T12:20:37+01:00 DEBUG (7): SELECT <code>i</code>.* FROM <code>omeka_items</code> AS <code>i</code>
 INNER JOIN
            (SELECT er_perm.relation_id as item_id
            FROM omeka_entities_relations er_perm
            INNER JOIN omeka_entities e ON e.id = er_perm.entity_id
            INNER JOIN omeka_users u ON u.entity_id = e.id
            INNER JOIN omeka_items i ON i.id = er_perm.relation_id
            LEFT JOIN omeka_entity_relationships ier ON ier.id = er_perm.relationship_id
            WHERE
                (u.id = '11'
                AND (ier.name = "added" OR ier.name = "modified")
                AND er_perm.type = "Item"
                )
            OR i.public = 1) AS <code>i_perm</code> ON i_perm.item_id = i.id WHERE (i.id = 2973) LIMIT 1

2011-08-18T12:20:37+01:00 DEBUG (7): SELECT COUNT(DISTINCT(i.id)) FROM <code>omeka_items</code> AS <code>i</code>
 INNER JOIN
            (SELECT er_perm.relation_id as item_id
            FROM omeka_entities_relations er_perm
            INNER JOIN omeka_entities e ON e.id = er_perm.entity_id
            INNER JOIN omeka_users u ON u.entity_id = e.id
            INNER JOIN omeka_items i ON i.id = er_perm.relation_id
            LEFT JOIN omeka_entity_relationships ier ON ier.id = er_perm.relationship_id
            WHERE
                (u.id = '11'
                AND (ier.name = "added" OR ier.name = "modified")
                AND er_perm.type = "Item"
                )
            OR i.public = 1) AS <code>i_perm</code> ON i_perm.item_id = i.id WHERE (i.id = '2973')

...so it runs the query to check the permission, then runs the same query again as part of the checkExists() call. It isn't clearing any of the permission checks, in other words, so that second query fails too.

Any clues, anyone...?

Many thanks in advance.

A URL to an admin-side items/show page should always result in a redirect to the login page if you're not currently logged in.

As for the 404/403 issue, it's not a bug, but it does seem strange on first glance.

By design, an anonymous user going to the public-side page for a non-public item gets a 404 error, just like for any other non-existent page. This way, there's no way for people on the public side to probe around and discover what item IDs exist. It also keeps people from seeing a potentially confusing "Forbidden" error when they likely just missed the URL.

403 errors normally happen under different circumstances. For example, not all logged-in users have permission to go to every type of page for an item, despite being able to see it.

I'll investigate that particular area of the code some more to see if its, as you say, uselessly doing the check twice when it will always get the same results, but regardless, the 404/403 behavior is unlikely to change.

Many thanks, John.

Are you able to point me at the bit of code which should do the redirect to the login page? It's a call to the admin side which is causing the issue, so it's possible that something I've done has prevented that redirect from working.

If that's the case, then it's presumably doing the 404/403 check rather than the redirect, which explains why the check is behaving oddly.

The code that actually performs the "logged-in" check for the admin side is in application/libraries/Omeka/Controller/Plugin/Admin.php.

That controller plugin should be registered near the end of admin/index.php.

Thanks for your help with this, John. I've now traced the issue to a bit of theme customisation that I'd done; it was redirecting the 'logged-in' check to the wrong place.

Sorted! :)