Používání ACL a zabezpečení formuláře, metody isAllowed

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

Ahoj,

už nějakou dobu Nette používám a zatím jsem si vždycky vystačil s jednoduchou autorizací pomocí metod isLoggedIn a isInRole. O možnosti vlastní autorizace vím, jen jsem zatím neměl potřebu ji nikde použít.

Přichází na řadu nějaké ACL, díky dobrému článku na statický ACL

Hned mě napadají tyto dotazy:

  1. Je to sice pěkné a funkční, ale po dokončení aplikace ji musím celou projít, nastavit zdroje (tzn. všechny presentery) a privilegia (akce presenterů). Pokud něco někde změním nebo doplním, musím na to myslet a poté ACL upravit. Jednodušeji to asi nejde? :)
  2. Bezpečnost a nastavení práv k odeslání formuláře. Co když budu mít v jednom presenteru více akcí a k některým budou mít přístup jen nějaké role. Pokud by v jedné z nich byl formulář, jak kontrolovat zda daná role má právo formulář odeslat? Pokud se nepletu, formulář bych mohl odeslat (tj. obejít zabezpečení) přes nějakou akci, ke které mám přístup. To bych měl vyřešit jak?
  3. Metodu/y isAllowed psát taky do modelů? Někde jsem četl, že by měly být až tam a ne řešit to na úrovni presenteru.

Díky za odpovědi od zkušenějších ;-)

Matúš Matula
Člen | 257
+
0
-
  1. robim to tak isto, ak to ide jednoduchsie, budem len rad :)
  2. kontroluj prava v onSuccess[](onSubmit[]) metode, ne v actionXYZ, resp. vid bod 3
  3. kontrolujem na urovni modelov a vyhadzujem vynimky, kt. odchytavam v presenteroch..Mas to v jednom mieste a viaze sa to priamo na akciu, na ktoru sa to viazat ma :)
joe
Člen | 313
+
0
-

Matúš Matula:

díky

1 – Proto jsem to radši dělal bez ACL, protože to je jednak rychejší (edituju jen jeden soubor), nemusím myslet na změnu při připsání nové akce a navíc po kouknutí do kódu ihned vidím, jak se bude pro danou roli chovat (pokud je nějak omezena).

2 – jasné, musím kontrolovat po odeslání (tedy onSuccess) a to pro každý takový formulář pak vymyslíš jméno jako název privilegia?

3 – zdá se mi to taky dobré kontrolovat to až v modelech (a při renderování v šabloně pro zobrazení/skrytí)

newPOPE
Člen | 648
+
0
-

Pokial pouzivas formulare ako samostatne triedy tak nic vymyslat nemusis. Do daneho formulara este mozes injektnut usera a kontrolovat priamo v nom. resp sa buildne inak tomu a inak tomu…

tot moje riesenie (nikdy nepouzite, ale domnievam sa, ze ta prva vec by sla automatizovat)

joe
Člen | 313
+
0
-

newPOPE
Nepoužívám :-) Píšu továrničky na formuláře do presenterů z toho samého důvodu – jsou přímo v tom souboru (presenteru), se kterým pracuju a nemusím se pořád překlikávat sem a tam. Ale šlo by to.

newPOPE
Člen | 648
+
0
-

joe tiez som v minulosti vyrabal priamo v presenteroch, teraz uz to nerobim. Pozeram na to skor opacne. Scroll alebo Klik na iny subor ;-) (NBeans ma skratky, cize je to jedno), co je jednoduchsie? To ale problem nie je. Skor je problem (a to dost velky) ked ten projekt uvidis po čase a kym sa z toho vysomaris tak mozes (nemusis) stratit hodnú chvilu.

Dalsi dovod preco pouzivam formulare ako samostatne triedy

  • mozem ich pouzit cross APP
  • su v podstate komponenta, ktora robi nieco sama, mozem si ju nastavit
  • skus to a uvidis ci je to lepsie alebo nie
nanuqcz
Člen | 822
+
0
-

Pokial pouzivas formulare ako samostatne triedy tak nic vymyslat nemusis.

Můžu se zeptat proč? Nějak mi nedochází, v čem je přístup formulářů jako samostatné třídy ve výsledku jiný…

EDIT: Chápu to dobře, že to byla odpověď na otázku č.2 ?

Editoval xxxObiWan (10. 8. 2011 0:31)

Matúš Matula
Člen | 257
+
0
-

joe napsal(a):

2 – jasné, musím kontrolovat po odeslání (tedy onSuccess) a to pro každý takový formulář pak vymyslíš jméno jako název privilegia?

ano

newPOPE napsal(a):

tot moje riesenie (nikdy nepouzite, ale domnievam sa, ze ta prva vec by sla automatizovat)

mozes nacrtnut, ako by si riesil tu automatizaciu? Predsa len to ACL musis niekde nadefinovat..

Matúš Matula
Člen | 257
+
0
-

xxxObiWan: sice to nepouzivam (zatial), ale mozes napriklad rovno v konstruktore overovat, ci ma dany user povolenu danu akciu – kt. bude odvodena prave od className daneho formulara..cize to mozes pichnut do nejakeho spolocneho predka pre formulare a mas vystarane.. (aspon tak si myslim :D)

joe
Člen | 313
+
0
-

newPOPE
Každý v tom může vidět výhody i nevýhody :-) Jenom by mě zajímalo, kam pak píšeš metody zpracování formuláře (xxxFormSubmitted($form))? Pokud do presenteru, tak pak tu autorizaci stejně musíš řešit tam, ne? Nebo to dáš třeba do konstruktoru (jak píše Matúš Matula), ale pak zase musíš někam ukládat ty data, co odesílal, aby o ně nepřišel, jestli se nepletu.

Matúš Matula
Jestli tomu dobře rozumim, pokud bych to udělal tak, jak jsi napsal (pak bych musel řešit to ukládání odeslaných dat, jak jsem před chvilkou napsal), tak bych pak zase do ACL musel připsat novou privilegii, je to tak? :)


Vlastně se mi nelíbí to, že pokud mám formulář (pro jednoduchost s metodou GET; presenter TestPresenter) zobrazený na nějaké „akci“, například actionDefault, jen pro nějaké role a pak mám akci actionFail, tak pokud si pak adresu ručně změním na /test/fail?do=formTest-submit, tak formulář odešlu i přes to, že s ním pracuji jenom v actionDefault a actionFail o něm není ani zmínka. Pokud by to tak nebylo, pak bych žádné oprávnění formuláře nemusel řešit. Nejedná se o bezpečnostní riziko?

Filip Procházka
Moderator | 4668
+
0
-

@**joe**: Jediná relativní „nevýhoda“ formulářů v oddělených třídách je, že jsou v jiném souboru. Slyšel jsem i zcestný „argument“, že programátor „nechce aby měl zasraný app třídami“.

O data ani o žádné hlouposti se starat nemusíš, protože formulář funguje úplně stejně, jako formulář v presenteru. Jenom je logicky oddělen do vlastní třídy od presenteru.

Ukázka takového formuláře:

namespace Kdyby\Application\UI;

class Form extends Nette\Application\UI\Form
{

	public function __construct()
	{
		parent::__construct();
		$this->configure();
	}


	protected function configure() { }

}
class UserForm extends Kdyby\Application\UI\Form
{

	/** @var UsersModel */
	private $users;


	public function __construct(UsersModel $users)
	{
		parent::__construct(); // nutnost
		$this->users = $users;
	}


	protected function configure()
	{
		$this->addText('name', 'Jméno');
		$this->addText('surname', 'Příjmení');
		$this->onSubmit[] = callback($this, 'Submitted')
	}


	public function Submitted()
	{
		// tady bude ACL a validace
		$this->users->create($this->values);
	}

}

Jediný tvůj argument je, že se ti to nelíbí :)


To co jsi uvedl o odesílání formuláře z jiné akce máš pravdu. A jako bonus, protože presenter umře až na neexistující šabloně, taková akce nemusí vůbec existovat. Můžeš klidně volat /test/failbog?do=formTest-submit ;)

Jak se tomuhle bráním? V každém presenteru mám důsledně pouze jednu akci, pokud není nějaké další zpracování, které chci mít v jiné akci (pouze výjimky).

Editoval HosipLan (10. 8. 2011 8:21)

joe
Člen | 313
+
0
-

@HosipLan
Já nechám na každém, ať používá ten svůj způsob. Tohle bych zařadil zrovna mezi to, o čem jsem ti odpovídal tady

Je to sice fajn, že je to logicky oddělené, ale k čemu mi to je :-) Zatím se mi málokdy stalo, že bych stejný formulář použil na více místech. Pokud už by k tomu došlo, takhle bych ho oddělil a nebo dal třeba do BasePresenteru (asi nic moc :-)) Nepoužívám to z toho důvodu, protože:

  • do presenteru bych stejně psal továrničku na formulář
  • mám radši, když nemusím otvírat další záložku se souborem
  • mi to přijde celkem zdlouhavé, napřed nějakou třídu, od které budu dědit, pak třídu pro formulář, kde píšu konstruktor a předávám modely. Když se rozhodnu, že budu používat další model, zase to musím upravovat, přidávat si atributy apod., to mi v presenteru všechno odpadá
  • budu mít ve slože app hodně tříd :))
  • přidělám zbytečně práci robot loaderu

Jinak ano, pak se to všechno chová stejně. Šlo mi o to ACL, že si musím vymyslet zase název pro privilegium, to kontrolovat v onSuccess a přidat ho (staticky) do toho ACL. To je taky věc, kterou moc nemusím, proto jsem to dřív nepoužíval – protože nevidím z metody hned, kdo k ní má přístup. A po dokončení aplikace musim zkontrolovat, jestli sedí názvy zdrojů/akcí v presenterech a v ACL a všechno si to prostě ohlídat. A když vytvořím novou akci, hned zase musím jít do ACL atd… Proto si to radši podmínkuju (zatím jsem nedělal nic moc pro více rolí, takže to nebylo tak hrozné).


S tím formulářem ještě.

A jako bonus, protože presenter umře až na neexistující šabloně, taková akce nemusí vůbec existovat.

Tohle mi teď zase nedošlo, už jsi mi to jednou někde psal. Vlastně by to mohlo být kontrolováno přímo frameworkem, ne? K čemu by měl „fungovat“ formulář jinde (po přidání ?do=form-submit), než tam, kam je směřován? Nějak na to nemůžu přijít, proč to není nějak zablokované, ale dal by se k tomu využít ChangeTracker

22
Člen | 1478
+
0
-

@joe: a proč nepoužít anotace? Hned vidíš nad metodou, kdo k ní má oprávnění a aspoň tě to donutí psát komentáře :-)

newPOPE
Člen | 648
+
0
-

@Matúš Matula

No keby na to doslo, tak by som to riesil asi nejak takto. Mam komponenty (Controls, Forms, etc…) to by boli resources, kazda ma nejake akcie Control ma render*, Form zase render, submit, click*

A uz len nastavim role, a ked tak rozmyslam tak by to zrejme u mna riesila sluzba (som komponenta tu ma mas, tu mas usera a povedz mi ci ma k tomu pristup alebo nie).

Ale ako hovorim, mam to len v hlave. Cize ci je to realne netusim ;-) (no paci sa mi to)

Filip Procházka
Moderator | 4668
+
0
-

joe napsal(a):

Je to sice fajn, že je to logicky oddělené, ale k čemu mi to je :-) …

Znovupoužitelnost, když děláš na větší aplikaci, jsi pak neskutečně vděčný, za každou ušetřenou komponentu. Já je dělím ještě na jednotlivé Containery, z nich pak skládám formuláře.

  • do presenteru bych stejně psal továrničku na formulář

ano to psal, měla by cca 4 řádky.

  • mám radši, když nemusím otvírat další záložku se souborem

to je ale jenom tvoje lenost :)

  • mi to přijde celkem zdlouhavé, napřed nějakou třídu, od které budu dědit, pak třídu pro formulář, kde píšu konstruktor a předávám modely. Když se rozhodnu, že budu používat další model, zase to musím upravovat, přidávat si atributy apod., to mi v presenteru všechno odpadá

Ano máš pravdu, můj přístup je založen striktně na Dependency Injection. A ten BaseForm je tam proto, že metoda configure se mi líbí a vypadá to lépe než v konstruktoru :)

  • budu mít ve slože app hodně tříd :))

:))

  • přidělám zbytečně práci robot loaderu

Žádné flákání! :)

Jinak ano, pak se to všechno chová stejně. Šlo mi o to ACL, …

Většinu z toho co jsi napsal můžeš zautomatizovat, nebo je to otázka dvou kliknutí, pokud máš hotový nějaký backend základ.


Vlastně by to mohlo být kontrolováno přímo frameworkem, ne? K čemu by měl „fungovat“ formulář jinde, než tam, kam je směřován?

Mohlo, ale není. S někým jsem to řešil na Jabber #nette chatu, jak to udělat pěkně pomocí annotací. Další věc je, že pokud to nikomu do teď nevadilo, znamená to, že

  • má buď aplikaci napsanou robustně a kontroluje ve zpracování formuláře, jestli má uživatel právo provést co provádí a je mu jedno, jestli si adresu sesmolil sám v address baru, nebo klikl na odkaz
  • nebo to má zblastlené

Editoval HosipLan (10. 8. 2011 11:10)

joe
Člen | 313
+
0
-

@22 Anotace jsem v tý rychlosti zapomněl zmínit, vlastně jsem myslel, že ve frameworku ještě nejsou a teď ani nevím jak to s nimi je. Taky jsou dobré, ale zase je to jako komentář, lehce se to přehlídne :-) Nakonec to asi vyřeším voláním jednoduché metody všude tam, kde chci mít kontrolu oprávnění → zautomatizování je super, ale co když bych chtěl při každé kontrole provést v každé metodě (v případě neúspěchu) pokaždé trochu něco jinýho?

To například používám při AJAXu, nevyužívám žádný JS framework a pokud potřebuji, pošlu si do payloadu callback, tzn. metodu, která se mi v JavaScriptu provede.
(K čemu je to dobré? Je to například taková náhrada za livequery z jQuery – že při změně znovu zAJAXovatím odkazy, přesunu flash zprávičky tam, kam potřebuju, inicializuji znovu nějaký blok, nastavím způsob přidávání elementů při stránkování apod.)

HosipLan

Znovupoužitelnost, když děláš na větší aplikaci, jsi pak neskutečně vděčný, za každou ušetřenou komponentu.

Líbit se ti to nebude :) ale jaký je rozdíl mezi tím, že zkopíruju do jiného projektu komponentu a nebo kus kódu z jednoho presenteru do presenteru v novém projektu? V tom druhém případě to budu mít ještě rychlejší, protože nebudu muset nikde nic nastavovat a zkopíruju kus hotového kódu, který funguje. Ve tvém případě musím komponentu nějak nastavit (tzn. zkopírovat komponentu, zkopírovat kód pro nastavení).
Zatím jsem dělal spíš takové věci, které by se asi jinde nedaly moc využít.

ano to psal, měla by cca 4 řádky.

Měla, ale při používání code folding by měly obě jen jeden :)

22
Člen | 1478
+
0
-

@joe: https://api.nette.org/…lection.html – klidně si udělej svoji anotaci @mysecurity blabla1 blabla2