Fixed checking ACL for another user in a Flex Object or Directory, added support getting Flex page permissions

This commit is contained in:
Matias Griese
2019-12-18 18:23:50 +02:00
parent 276b4bb0ab
commit 2437112f3c
6 changed files with 52 additions and 32 deletions

View File

@@ -4,7 +4,10 @@
1. [](#bugfix)
* Grav 1.7: Fixed error on page initialization [#2753](https://github.com/getgrav/grav/issues/2753)
1. [](#improved)
* Twig filter `|yaml_serialize`: added support for `JsonSerializable` objects
* Twig filter `|yaml_serialize`: added support for `JsonSerializable` objects and other array-like objects
* Added support for returning Flex Page specific permissions for admin and testing
1. [](#bugfix)
* Fixed checking ACL for another user (who is not currently logged in) in a Flex Object or Directory
# v1.7.0-rc.2
## 12/04/2019

View File

@@ -223,6 +223,7 @@ class UserObject extends FlexObject implements UserInterface, MediaManipulationI
return $authorized;
}
// If specific rule isn't hit, check if user is super user.
if ($access->authorize('admin.super') === true) {
return true;
}
@@ -521,16 +522,17 @@ class UserObject extends FlexObject implements UserInterface, MediaManipulationI
* @param UserInterface $user
* @param string $action
* @param string $scope
* @param bool $isMe
* @return bool|null
*/
protected function isAuthorizedOverride(UserInterface $user, string $action, string $scope): ?bool
protected function isAuthorizedOverride(UserInterface $user, string $action, string $scope, bool $isMe = false): ?bool
{
if ($user instanceof self && $user->getStorageKey() === $this->getStorageKey()) {
// User cannot delete his own account, otherwise he has full access.
return $action !== 'delete';
}
return parent::isAuthorizedOverride($user, $action, $scope);
return parent::isAuthorizedOverride($user, $action, $scope, $isMe);
}
/**

View File

@@ -48,7 +48,7 @@ class Access implements \JsonSerializable, \IteratorAggregate, \Countable
public function authorize(string $action, string $scope = null): ?bool
{
if (null !== $scope) {
$action = "{$scope}.{$action}";
$action = $scope !== 'test' ? "{$scope}.{$action}" : $action;
}
return $this->acl[$action] ?? null;

View File

@@ -17,6 +17,7 @@ use Grav\Common\Page\Traits\PageFormTrait;
use Grav\Common\User\Interfaces\UserCollectionInterface;
use Grav\Framework\File\Formatter\YamlFormatter;
use Grav\Framework\Flex\FlexObject;
use Grav\Framework\Flex\Interfaces\FlexCollectionInterface;
use Grav\Framework\Flex\Interfaces\FlexObjectInterface;
use Grav\Framework\Flex\Interfaces\FlexTranslateInterface;
use Grav\Framework\Flex\Pages\Traits\PageAuthorsTrait;
@@ -424,10 +425,10 @@ class FlexPageObject extends FlexObject implements PageInterface, MediaManipulat
}
/**
* @return UserCollectionInterface|null
* @return UserCollectionInterface|FlexCollectionInterface|null
* @internal
*/
protected function loadAccounts(): ?UserCollectionInterface
protected function loadAccounts()
{
return Grav::instance()['accounts'] ?? null;
}

View File

@@ -54,12 +54,17 @@ trait PageAuthorsTrait
public function getAuthors(): array
{
if (null === $this->_authors) {
$this->_authors = (array)$this->loadAuthors($this->getNestedProperty('header.authors'));
$this->_authors = (array)$this->loadAuthors($this->getNestedProperty('header.authors', []));
}
return $this->_authors;
}
public function getPermissions()
{
return $this->loadPermissions();
}
/**
* @param iterable $authors
* @return array<int,UserInterface>
@@ -86,13 +91,14 @@ trait PageAuthorsTrait
* @param UserInterface $user
* @param string $action
* @param string $scope
* @param bool $isMe
* @return bool|null
*/
protected function isAuthorizedOverride(UserInterface $user, string $action, string $scope): ?bool
protected function isAuthorizedOverride(UserInterface $user, string $action, string $scope, bool $isMe): ?bool
{
$authorized = $this->isAuthorizedByGroup($user, $action, $scope);
return $authorized ?? parent::isAuthorizedOverride($user, $action, $scope);
return $authorized ?? parent::isAuthorizedOverride($user, $action, $scope, $isMe);
}
/**
@@ -110,16 +116,28 @@ trait PageAuthorsTrait
protected function isAuthorizedByGroup(UserInterface $user, string $action, string $scope): ?bool
{
$authorized = null;
$username = $user->username;
// In admin we want to check against group permissions.
$groups = $this->loadPermissions($user);
$pageGroups = $this->loadPermissions();
$userGroups = (array)$user->groups;
/** @var Access $access */
foreach ($groups as $access) {
foreach ($pageGroups as $group => $access) {
if ($group === 'authors') {
if (!$this->hasAuthor($username)) {
continue;
}
} elseif (!in_array($group, $userGroups, true)) {
continue;
}
$auth = $access->authorize($action, $scope);
if (is_bool($auth)) {
if ($auth === false) {
return false;
}
$authorized = true;
}
}
@@ -128,10 +146,9 @@ trait PageAuthorsTrait
}
/**
* @param UserInterface $user
* @return array
*/
protected function loadPermissions(UserInterface $user): array
protected function loadPermissions(): array
{
$permissions = $this->getNestedProperty('header.permissions');
if (empty($permissions)) {
@@ -143,18 +160,8 @@ trait PageAuthorsTrait
if (is_string($access)) {
$access = $this->resolvePermissions($access);
}
if ($group === 'author') {
// Special case for authors.
if ($this->hasAuthor($user->username)) {
$list[$group] = new Access($permissions);
}
} else {
$groups = (array)$user->groups;
if (in_array($groups, $groups, true)) {
$list[$group] = new Access($permissions);
}
}
$list[$group] = $access;
$list[$group] = new Access($access);
}
return $list;
@@ -192,6 +199,6 @@ trait PageAuthorsTrait
}
abstract public function getNestedProperty($property, $default = null, $separator = null);
abstract protected function loadAccounts(): ?UserCollectionInterface;
abstract protected function loadAccounts();
}

View File

@@ -41,13 +41,18 @@ trait FlexAuthorizeTrait
{
$action = $this->getAuthorizeAction($action);
$scope = $scope ?? $this->getAuthorizeScope();
$user = $user ?? $this->getActiveUser();
$isMe = null === $user;
if ($isMe) {
$user = $this->getActiveUser();
}
if (null === $user) {
return false;
}
// Finally authorize against given action.
return $this->isAuthorizedOverride($user, $action, $scope);
return $this->isAuthorizedOverride($user, $action, $scope, $isMe);
}
/**
@@ -56,11 +61,12 @@ trait FlexAuthorizeTrait
* @param UserInterface $user
* @param string $action
* @param string $scope
* @param bool $isMe
* @return bool|null
*/
protected function isAuthorizedOverride(UserInterface $user, string $action, string $scope): ?bool
protected function isAuthorizedOverride(UserInterface $user, string $action, string $scope, bool $isMe): ?bool
{
return $this->isAuthorizedAction($user, $action, $scope);
return $this->isAuthorizedAction($user, $action, $scope, $isMe);
}
/**
@@ -69,9 +75,10 @@ trait FlexAuthorizeTrait
* @param UserInterface $user
* @param string $action
* @param string $scope
* @param bool $isMe
* @return bool|null
*/
protected function isAuthorizedAction(UserInterface $user, string $action, string $scope): ?bool
protected function isAuthorizedAction(UserInterface $user, string $action, string $scope, bool $isMe): ?bool
{
// Check if the action has been denied in the flex type configuration.
$directory = $this instanceof FlexDirectory ? $this : $this->getFlexDirectory();
@@ -88,7 +95,7 @@ trait FlexAuthorizeTrait
}
// Finally authorize the action.
return $user->authorize($this->getAuthorizeRule($scope, $action));
return $user->authorize($this->getAuthorizeRule($scope, $action), !$isMe ? 'test' : null);
}
/**