Přístupová práva

V kapitole Autorizace a přístupová práva byl podle pojetí [20] popsán rozdíl mezi výrazy „autorizace“ a „řízení přístupu“. Přístupový mechanizmus frameworku phpBASE vyhovuje z větší míry oběma těmto definicím. Je primárně založen na přidělování oprávnění jednotlivým uživatelům či uživatelským skupinám, což odpovídá pojetí ve smyslu autorizace. Nicméně uživatelské skupiny je zde možné definovat i jinak, než prostým výčtem jejich členů. Například právě určením IP adres, ze kterých se přistupuje, povinným zabezpečením přenosu SSL šifrováním apod. To je i v souladu s obecnější druhou definicí.

Pravidla

Přístupová práva v phpBASE jsou určena jednotlivými pravidly. Předpis každého pravidla má tvar:

Podoba přístupových pravidel.

Podoba přístupových pravidel.

V aplikaci nesmí být definována dvě pravidla, která jsou zcela stejná, nebo která se liší jen hodnotou permission. Jednotlivé položky mohou nabývat následujících hodnot:

user

Identifikace jednoho konkrétního uživatele, kterého se dané pravidlo týká. Položka také může nabývat hodnoty ALL, vzahuje-li se pravilo na všechny uživatele.

group

Identifikace jedné konkrétní uživatelské skupiny, které se dané pravidlo týká. Položka také může nabývat hodnoty ALL, jestliže se pravilo vztahuje na všechny uživatelské skupiny (resp. pokud nezáleží na zařazení uživatele do některé z uživatelských skupin).

entity

Identifikace jedné konkrétní entity, ke které se dané pravidlo přiřazuje. Položka také může nabývat hodnoty ALL, týká-li se pravidlo všech entit.

permission

Hodnota přístupového práva. Může být buď PERMIT (přístup povolen), nebo DENY (přístup zakázán).

Seznam přístupových pravidel v ukázkové aplikaci

Seznam přístupových pravidel v ukázkové aplikaci

Jako příklad si popíšeme tři pravidla uvedená v následující tabulce. První je nejobecnější v celé aplikaci, určuje výchozí hodnotu, není-li konkrétnějším předpisem určeno jinak. Říká, že všichni uživatelé ve všech uživatelských skupinách mají zakázaný přístup ke všem entitám. V druhém případě mají všichni uživatelé z uživatelské skupiny admin povolen přístup k modulu /main/ i ke všem jeho stránkám, není-li specifičtějším předpisem určeno jinak. A poslední pravidlo říká, že uživatel pepa, jestliže je zařazen do skupiny admin, má povolený přístup k modulu /private/. Pokud ale uživatel není členem skupiny admin, pak se ho uvedený předpis netýká a pravidlo nemá v aplikaci smysl, protože se nikdy nepoužije.

Příklad správně zadaných přístupových pravidel.

Příklad správně zadaných přístupových pravidel.

Další tři předpisy nemohou být v aplikaci definovány najednou (dokonce ani libovolné dva z nich), neboť popisují pravidla pro stejného uživatele, uživatelskou skupinu i entitu. Tím porušují výše zmíněnou zásadu unikátnosti předpisu:

Nemožná kombinace přístupových pravidel.

Nemožná kombinace přístupových pravidel.

Dotaz na přístupové právo

Pokud chceme získat pro některého uživatele či uživatelskou skupinu hodnotu přístupového práva k nějaké entitě, musíme nejdříve specifikovat dotaz na přístupové právo. Ten má tvar:

Podoba dotazu na přístupové právo.

Podoba dotazu na přístupové právo.

Položky dotazu mohou nabývat konkrétních hodnot i obecné hodnoty ALL, a to navzájem v libovolné kombinaci. Dotazem se tak určí:

Například následujícím dotazem se ptáme na přístupové právo k modulu /main/ pro všechny uživatele ze skupiny admin.

Příklad dotazu na přístupové právo k modulu /main/.

Příklad dotazu na přístupové právo k modulu /main/.

Je-li zadán konkrétní query-user a zároveň je query-group=ALL, berou se v úvahu jen skupiny, do kterých je zadaný uživatel přiřazený, nikoliv všechny skupiny v celé aplikaci. Následující dotaz tedy hledá hodnotu přístupového práva k modulu /private/ pro uživatele pepa ve všech uživatelských skupinách, do kterých je zařazen.

Příklad dotazu na přístupové právo pro uživatele pepa.

Příklad dotazu na přístupové právo pro uživatele pepa.

V praxi se samozřejmě daleko nejčastěji používají dotazy na přístupové právo ke konkrétní komponentě pro aktuálního uživatele ve všech jeho skupinách. Ostatní varianty jsou k dispozici víceméně pro úplnost.

Vyhodnocování přístupových práv

Výsledkem dotazu je vždy hodnota přístupového práva pro zadané parametry, tzn. jedna z hodnot PERMIT nebo DENY. Ta se určí takto:

  1. Vyberou se všechna relevantní pravidla, která odpovídají zadanému dotazu.

  2. Z nich se vybere nejspecifičtější pravidlo.

  3. Jeho hodnota se vrátí jako výsledné přístupové právo.

Výběr relevantních pravidel

Pravidla relevantní zadanému dotazu jsou všechna pravidla definovaná v aplikaci, pro která zároveň platí:

Zde je nutné vysvětlit pojem „předek entity“. Při výchozí konfiguraci phpBASE se přístupová práva dědí jen z modulu na jeho vlastní komponenty a akce, ale už nikoliv na podmoduly a jejich komponenty a akce. Máme-li tedy například stránku /news/admin/index, pak přístup k ní žádným způsobem neovlivní pravidlo definované pro modul /news/. Jestliže je ale v konfiguraci frameworku nastavena direktiva APP_INHERIT, pak se přístupová práva na dědí nejen z daného modulu na komponenty a akce přímo v něm, ale i na všechny jeho podmoduly a jejich komponenty a akce. Neboli při dotazu na stránku /news/admin/index přichází v úvahu i pravidla určená pro modul /news/.

Výběr nejspecifičtějšího pravidla

V další fázi ze všech relevantních pravidel vybereme to nejspecifičtější. Tedy konkrétnější pravidlo má přednost před obecnějšími. Zásady uspořádání jsou následující (dříve uvedená zásada má vyšší prioritu):

  1. Pravidlo pro konkrétního uživatele je specifičtější, než pravidlo s položkou user=ALL.

  2. Pravidlo pro konkrétní uživatelskou skupinu je specifičtější, než pravidlo s položkou group=ALL. U více různých konkrétních skupin se pravidla seřadí podle předem pevně daného pořadí těchto skupin.

  3. Pravidlo pro konkrétní entitu je specifičtější, než pravidlo s položkou entity=ALL. Přitom potomek entity je specifičtější, než jeho předek.

Přednost uživatelů před entitami při vyhodnocování přístupu.

Přednost uživatelů před entitami při vyhodnocování přístupu.

Z uvedených zásad je patrné, že uživatelská část pravidla má přednost před částí entitní. Například z následujících dvou pravidel je první specifičtější. Toto by se stejně dobře mohlo udělat i úplně naopak, tedy předností entitní části před uživatelskou (pak by třetí zásada uspořádání byla na prvním místě). Zvolený přístup však více odpovídá intuitivnímu chápání priorit pravidel.

Výsledná hodnota přístupového práva

Konečnou hodnotou přístupového práva získaného k zadanému dotazu je hodnota nejspecifičtějšího relevantního pravidla.

Grafický přehled vyhodnocování výsledného práva k jednotlivým entitám pro zadaného uživatele

Grafický přehled vyhodnocování výsledného práva k jednotlivým entitám pro zadaného uživatele

Může však dojít k situaci, že k zadanému dotazu nebude nalezeno ani jedno definované pravidlo. Pak přichází na řadu implicitní zákaz přístupu, neboli je vráceno DENY. Implicitní zákaz existuje z bezpečnostních důvodů. Je totiž mnohem bezpečnější mít vše zakázáno a pak postupně přístup k jednotlivým entitám pro jednotlivé uživatele či skupiny povolovat. V opačném případě (při implicitním PERMIT a explicitním zakazování) reálně hrozí, že administrátor přístup do některé chráněné oblasti zapomene zakázat či takovou chybu přehlédne. A obecně zde platí zásada „least privileges“ [20], neboli přidělení jen nejnutnějších oprávnění. Lépe je tak omylem nezpřístupnit jinak veřejnou část aplikace, než omylem zpřístupnit část citlivou.

Implementace v phpBASE

Pro zjištění přístupového práva k určité entitě definuje framework funkci Perm. Tu lze použít v libovolné stránce, skriptu i knihovně. Prvním parametrem funkce je identifikátor entity. Implicitně se dotaz vyhodnocuje pro aktuálního uživatele. Volitelným druhým a třetím parametrem lze ale zadat i jiného uživatele resp. uživatelskou skupinu. Funkce vrací příslušnou booleovskou hodnotu. V následujícím příkladu první příkaz vrátí přístupové právo ke komponentě /main/index pro aktuálního uživatele, druhý zjistí přístup ke stejné komponentě, ale pro uživatele číslo 1.

<?php
Perm
("/main/index");
Perm("/main/index"1);
?>