Skip to content

Commit

Permalink
fix(access): updates no longer mistakenly blocked in some scenarios
Browse files Browse the repository at this point in the history
In order to fix `canEdit()` in 1.9, `update()` needed to load a fresh copy of
entity from the DB to check the persisted attributes. In that fix,
66eb9e6,
a corner case was checked out of my paranoia that a dev would load an
invisible entity with access control on, but try to delete it with access
off.

I now believe this check was unnecessary (we never did similar checks for
`delete()`). When the original `canEdit()` attributes issue was resolved in
#9434, I should've made this change.
  • Loading branch information
mrclay committed Aug 22, 2016
1 parent 139bb14 commit 6186282
Show file tree
Hide file tree
Showing 7 changed files with 45 additions and 15 deletions.
6 changes: 0 additions & 6 deletions engine/classes/ElggEntity.php
Expand Up @@ -1592,12 +1592,6 @@ protected function update() {

_elgg_services()->boot->invalidateCache($this->guid);

if (!has_access_to_entity($this)) {
// Why worry about this case? If access control was off when the user fetched $this, but
// was turned back on again. Better to just bail than to turn access control off again.
return false;
}

if (!$this->canEdit()) {
return false;
}
Expand Down
2 changes: 1 addition & 1 deletion engine/classes/ElggSession.php
Expand Up @@ -209,7 +209,7 @@ public function setLoggedInUser(\ElggUser $user) {
/**
* Gets the logged in user
*
* @return \ElggUser
* @return \ElggUser|null
* @since 1.9
*/
public function getLoggedInUser() {
Expand Down
7 changes: 3 additions & 4 deletions engine/tests/ElggCoreMetadataAPITest.php
Expand Up @@ -161,8 +161,7 @@ public function test_elgg_metadata_multiple_values() {

// need to fake different logins.
// good times without mocking.
$original_user = elgg_get_logged_in_user_entity();
$_SESSION['user'] = $u1;
$original_user = $this->replaceSession($u1);

elgg_set_ignore_access(false);

Expand All @@ -182,7 +181,7 @@ public function test_elgg_metadata_multiple_values() {
}

// add md w/ same name as a different user
$_SESSION['user'] = $u2;
$this->replaceSession($u2);
$md_values2 = array(
'four',
'five',
Expand All @@ -202,7 +201,7 @@ public function test_elgg_metadata_multiple_values() {
$this->assertEqual('test', $md->name);
}

$_SESSION['user'] = $original_user;
$this->replaceSession($original_user);

$obj->delete();
$u1->delete();
Expand Down
17 changes: 17 additions & 0 deletions engine/tests/ElggCoreUnitTest.php
Expand Up @@ -48,6 +48,23 @@ public function assertIdenticalEntities(\ElggEntity $first, \ElggEntity $second,
return $this->assert(new IdenticalEntityExpectation($first), $second, $message);
}

/**
* Replace the current user session
*
* @param ElggUser $user New user to login as (null to log out)
* @return ElggUser|null Removed session user (or null)
*/
public function replaceSession(ElggUser $user = null) {
$session = elgg_get_session();
$old = $session->getLoggedInUser();
if ($user) {
$session->setLoggedInUser($user);
} else {
$session->removeLoggedInUser();
}
return $old;
}

}

/**
Expand Down
21 changes: 21 additions & 0 deletions engine/tests/ElggEntityTest.php
Expand Up @@ -379,4 +379,25 @@ public function testCreateWithContainerGuidEqualsZero() {
$user->delete();

}

public function testUpdateAbilityDependsOnCanEdit() {
$this->entity->access_id = ACCESS_PRIVATE;

$user = new ElggUser();
$user->save();
$old_user = $this->replaceSession($user);

$this->assertFalse($this->entity->save());

elgg_register_plugin_hook_handler('permissions_check', 'object', [Elgg\Values::class, 'getTrue']);

// even though this user can't look up the entity via the DB, permission allows update.
$this->assertFalse(has_access_to_entity($this->entity, $user));
$this->assertTrue($this->entity->save());

elgg_unregister_plugin_hook_handler('permissions_check', 'object', [Elgg\Values::class, 'getTrue']);

$this->replaceSession($old_user);
$user->delete();
}
}
5 changes: 2 additions & 3 deletions engine/tests/ElggObjectTest.php
Expand Up @@ -201,14 +201,13 @@ public function testElggEntityRecursiveDisableWhenLoggedOut() {
$guid2 = $e2->getGUID();

// fake being logged out
$user = $_SESSION['user'];
unset($_SESSION['user']);
$old_user = $this->replaceSession();
$ia = elgg_set_ignore_access(true);

$this->assertTrue($e1->disable(null, true));

// "log in" original user
$_SESSION['user'] = $user;
$this->replaceSession($old_user);
elgg_set_ignore_access($ia);

$this->assertFalse(get_entity($guid1));
Expand Down
2 changes: 1 addition & 1 deletion engine/tests/ElggUserTest.php
Expand Up @@ -98,7 +98,7 @@ public function testElggUserConstructorWithGarbage() {
public function testElggUserConstructorByDbRow() {
$row = $this->fetchUser(elgg_get_logged_in_user_guid());
$user = new \ElggUser($row);
$this->assertIdenticalEntities($user, $_SESSION['user']);
$this->assertIdenticalEntities($user, elgg_get_logged_in_user_entity());
}

public function testElggUserSave() {
Expand Down

0 comments on commit 6186282

Please sign in to comment.