Opened 3 years ago
Last modified 9 months ago
#2517 new Defect
Add gatekeeper that checks access to entity
| Reported by: | ewinslow | Owned by: | |
|---|---|---|---|
| Priority: | normal | Milestone: | Near Term Future Release |
| Component: | Core | Version: | 1.7 |
| Severity: | minor | Keywords: | |
| Cc: | brettp | Difficulty: | difficult |
Description (last modified by mrclay)
if get_entity() returns FALSE, there are two possibilites:
- The entity does not exist at all
- The entity exists, but is not visible to the user
As it stands, there is no indication which one it is when you visit a protected resource. This has caused great confusion amongst our users. They complain to each other that links are broken when in reality it's because the resource that contains the link is visible but the resource being linked to is not visible. We need a clean way of explaining to the user what the problem is. That is, we need to give either a 404 (broken link) or 403 (access denied) page in the appropriate case.
So I propose entity_gatekeeper():
- When the entity is visible, it returns the entity (makes for a nice shortcut).
- When the entity is not visible, it calls forward and specifies '403' for the "reason" (see #2237).
- When the entity is non-existent, it forwards and specifies '404' for the reason.
Change History (9)
comment:1 Changed 3 years ago by ewinslow
- Summary changed from Add gatekeeper than checks access to entity to Add gatekeeper that checks access to entity
comment:2 Changed 3 years ago by brettp
- Difficulty set to difficult
- Milestone changed from Elgg 1.8 to Elgg 1.9
comment:3 Changed 3 years ago by ewinslow
Here's what I'm using right now...
function entity_gatekeeper($entity_guid) {
$entity = get_entity($entity_guid);
if ($entity) {
return $entity;
}
$ignore = elgg_get_ignore_access();
elgg_set_ignore_access(TRUE);
$entity = get_entity($entity_guid);
elgg_set_ignore_access($ignore);
if (!$entity) {
//Entity does not exist
forward('', '404');
} else {
//User does not have access to entity
forward('', '403');
}
exit;
}
comment:4 Changed 3 years ago by brettp
That'd be the "not clean way" I mentioned :-X It works, but it feels pretty dirty...
comment:5 Changed 2 years ago by cash
This has been a big issue in my testing of svn trunk. Hit a page logged out where the entity is set to logged in only. The breadcrumbs are broken (shows a partial url) and many pages do not have proper messages to the user on what happened.
Why don't we add:
function elgg_does_entity_exist($guid) {
$query = "...";
...
}
or maybe call it elgg_entity_exists(). Have it do a query against the entities table and return true or false.
From there we can come up with a scheme for handling #2814
Thoughts?
comment:6 Changed 2 years ago by brettp
elgg_enity_exists() works for me. The problem I had with the proposed solution above is disabling the access levels in the gatekeeper.
comment:7 Changed 2 years ago by cash
I was thinking that in the page handler I would get the entity. If I got back false, I could ask elgg_entity_exists() and based on the result tell the user, the content does not exist or they do not have permissions to it (and if they are not logged in, tell them they should log in).
I don't really like returning an entity out of a gatekeeper like the proposal on this ticket. We should come up with a way to do this without copying the entity access checking code into every page handler.
comment:8 Changed 2 years ago by ewinslow
So we keep a gatekeeper function that does:
- Check if it exists using elgg_entity_exists()
- If it doesn't exist, output 404. Otherwise, try to fetch it.
- If we didn't get anything, output 403 page. Otherwise, return.
I just figured that returning the entity would be a nice shorthand, but that's not necessary by any means. Definitely agreed that page handlers should not have to reimplement access checks.
comment:9 Changed 9 months ago by mrclay
- Description modified (diff)
Do we still need this considering the noaccess and route-through-login boilerplate we're now using? The small advantage I see in the current code is privacy: hitting a URL doesn't leak info.
I *would* like to wrap that boilerplate into a function that does a few things: fetch the item, validate type/subtype, optionally apply group_gatekeeper, and reroute through login if necessary.

The data model doesn't differentiate between unauthorized and non-existent entities--the DB functions return a null set for either. Offhand I can't think of a clean way to implement this without major changes to the access system.