ACL – vice roli, vlastnictvi zdroje

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
libik
Člen | 96
+
0
-

Ahoj,

mam nasledujici autorizator:

<?php

namespace App\Services;

use Nette\Security\IAuthorizator,
    Nette\Security\Permission,
    Nette\Security\IResource;

class AuthorizatorFactory
{

    /**
     * @return IAuthorizator
     */
    public function create()
    {
        $authorizator = new Permission;

        $authorizator->addRole("host");
        $authorizator->addRole("redaktor");
        $authorizator->addRole("editor");
        $authorizator->addRole("superAdministrator");

        $authorizator->addResource('entity');
        $authorizator->addResource('Menu', 'entity');
        $authorizator->addResource('User', 'entity');

        $authorizator->allow('superAdministrator', 'entity', IAuthorizator::ALL);

        $authorizator->allow('host', 'Menu', array('edit','delete'), [$this,  'isOwner']);
        $authorizator->allow('editor', 'Menu', array('edit','delete'), [$this,  'isOwner']);
        $authorizator->allow('redaktor', 'Menu', 'edit', [$this,  'isOwner']);

        return $authorizator;
    }

    /**
     * Zjisti, zda je uzivatel role vlastnikem zdroje
     *
     * @return bool
     */
    public function isOwner(Permission $permission, $role, $resource, $privilege)
    {
        if ($permission->getQueriedResource() instanceof IResource)
        {
            $resourceOwners = $permission->getQueriedResource()->getOwnerId(); //vrati pole vlastniku zdroje
            $roleOwner = $permission->getQueriedRole()->getId(); // vrati id vlastnika role
            $resourceRole = $permission->getQueriedResource()->getOwnerRole($permission->getQueriedRole()->getId()); // vrati typ vlastnictvi (role) zdroje
            $resourceRoleName = $resourceRole->getRole();

            // pokud je vlastnikem a zaroven typ vlastnictvi odpovida jeho roli, vraci TRUE
            return in_array($roleOwner, $resourceOwners) && $role == $resourceRoleName;
        } else
        {
            return TRUE;
        }
    }

}

A ted mam problem v tom, ze user muze mit roli vic a nektery zdroj vlastnit jako host, nektery jako editor:

Nette\Security\Identity #0320
id private => 13
roles private => array (3)
5 => "editor"
6 => "redaktor"
7 => "host"
data private => array (1)
userName => "user.name"

Kontrola pres:

$this->acl->isAllowed(UserEntity $ue,MenuEntity $um14, 'delete');

Metoda isOwner() se vola vzdy jen pro roli ‚editor‘ a nevrati TRUE pro zdroj $um14, ve kterem ma uzivatel nastaveno vlastnictvi jako host (protoze podminka editor !== host).

Jak s tim pohnout? Nebo je to slepa ulicka?

Diky za rady.

David Matějka
Moderator | 6445
+
+1
-

Ahoj, zkus mrknout na moji prednasku z posoboty, o necem podobnem tam povidam :)

libik
Člen | 96
+
0
-

Ahoj, diky. Videl jsem a zkousim implementovat. Zasekl jsem se na prazdne identite – Authorizator mi v getRoles() hlasi Call to a member function getRoles() on null.

User Entity mam:

<?php

namespace App\Model\Entities;

use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use App\Model\Entities\Role;
use App\Services\Security\Identity;

/**
 * Users
 * @package App\Model\Entities
 * @ORM\Table(name="17_user", uniqueConstraints={@ORM\UniqueConstraint(name="name_UNIQUE", columns={"name"})})
 * @ORM\Entity
 */
class User
{

    const MAX_LENGTH_NAME = 50;
    const MAX_LENGTH_EMAIL = 100;

    public function __construct()
    {
        $this->roles = new ArrayCollection();
        $this->menuPermission = new ArrayCollection();
    }

    /** @var Identity */
    private $identity;

    /**
     *
     * @return Identity
     */
    public function getIdentity()
    {
        return $this->identity;
    }
...

Identity class:

<?php

namespace App\Services\Security;

use Nette\SmartObject;

class Identity implements \Nette\Security\IIdentity
{
	use SmartObject;

	const ROLE_SUPERADMIN = 'superAdmin';
	const ROLE_REDAKTOR = 'redaktor';
	const ROLE_EDITOR = 'editor';
	const ROLE_HOST = 'host';

	private $id;

	private $roles = [];


	public function getRoles()
	{
		return $this->roles;
	}

	public function getId()
	{
		return $this->id;
	}

}

A v permission create:

	public function create()
	{
		$permission = new Permission();

		$permission->addResource(Menu::class);

		$permission->addRole(Identity::ROLE_SUPERADMIN);
		$permission->addRole(Identity::ROLE_EDITOR);
		$permission->addRole(Identity::ROLE_REDAKTOR);
		$permission->addRole(Identity::ROLE_HOST);

$permission->addRole(Menu::MENU_OWNER);

$this->allow($permission, Menu::MENU_OWNER, Menu::ACTION_EDIT);

		$permission->allow(Identity::ROLE_SUPERADMIN, $permission::ALL, $permission::ALL);

		return $permission;
	}

Mam chaos v te Identite, kde ji vezmu, kdyz ne klasickou Nette\Security.

Diky.

David Matějka
Moderator | 6445
+
0
-

identita v tom ACL neodpovida identite z nette/security. v tvem pripade klidne entita User muze vystupovat jako identita. mrkni kdyztak na GH na example – https://github.com/…tion-example (jen nevim, jestli funguje, psal jsem to tenkrat narychlo ve vlaku :))

libik
Člen | 96
+
0
-

Tak uz jsem to rozchodil, diky!

Mam jeste jednu vec, ktera primo s problemem implementace nesouvisi, ale premyslim, jak to udelat nejlepe.
Mam stromovou strukturu podobnou adresarove strukture (pro zjednoduseni).
Prava muzu pridelovat bud na konkretnim adresari nebo jen konkretnimu souboru.
Uzivatel (admin) muze mit pravo nakladat s celym adresarem nebo jen konkretnimi soubory (jako user) v jinem adresari, kde neni vedeny jako admin. Jiny uzivatel muze mit pravo pouze k jednomu souboru (jako user).
Vaham, zda:

  1. je nejlepsi prima rekurze (tedy pravo nastavene adresari explicitne ulozim i ke vsem souborum, ktere obsahuje) a pri zjistovani opravneni u souboru se nemusim dotazovat na prava nastavena na adresari.
  2. nebo setrivejsi zpusob, a to ukladat jen user opravneni, protoze kdyz bude u adresare uzivatel s opravnenim jako admin, ma pristup k souborum jasny. Ale tady zase musim zjistovat prava dvakrat, na soubor – pokud ne, na adresar.