Jogosultság kezelés - csak a szerző tudja szerkeszteni a cikkét
Sziasztok!
Jogosultság kezeléssel van egy problémám, amire nem tudtam kiagyalni általánosan használható rendszert. Vagy nem létezik ilyen, vagy a hiba bennem van.
Alapból úgy tárolom a szabályokat, hogy van egy listám az erőforrásokról és a műveletekről, amiket rajtuk lehet végezni. Ezt beszórtam egy táblába, aztán csináltam szerepköröket, amikhez hozzárendeltem ezeket a jogokat. A szerepköröket meg nyilván felhasználókhoz rendeltem hozzá. Ezzel így szerintem megfelelő.
A gond ott kezdődik, ha olyan dolgok jönnek be, ahol megszorítások vannak 1-1 erőforrásra. Ha mondjuk egy adminnak adok jogot a cikkek szerkesztésére, akkor "PUT article/*" jogkört kap, viszont ha egy mezei felhasználónak akarom megengedni, hogy az általa beküldött tartalmakat tudja szerkeszteni, akkor az előbbi jogkört úgy kell szűkítenem, hogy a * csak a saját cikkeinek az id-jére érvényes.
Ez egy általánosan előforduló dolog, pl a felhasználónak van egy munkamenete, aminél azt szeretném, hogy ki tudjon jelentkezni. Nyilván ilyenkor a "DELETE session/*" -re kap engedélyt, ahol a * az aktuális session ID lehet csak.
Egyelőre csak annyi jutott eszembe, hogy berakok egy flag-et a jogosultságokhoz, hogy általánosan vagy szűkítetten kell e értelmezni őket, illetve kézzel megírom minden egyes táblára az ellenőrzést, hogy az adott munkamenet felhasználójához tartozik e az adott sor... Esetleg van erre valami jobb megoldás? Egyelőre úgy vagyok vele, hogy adatbázis szinten meg tudom oldani a jogosultság kezelést, de egyre inkább úgy néz ki, hogy kénytelen leszek áttenni szerver oldali nyelvre, ahhoz, hogy rugalmas szabályokat tudjak csinálni.
Van egy másik lehetőség is, a felhasználók kapnak egyedi jogköröket, pl: "PUT article/123", és így tovább az összes cikkre külön külön. Ez nekem egy kicsit fapadosnak tűnik, de első ránézésre működőképes elgondolás. Ennek annyi a nehézsége, hogy bele kell írni a tárolt eljárásokba, hogy cikk létrehozásnál hozzáadjon és cikk törlésnél elvegyen jogköröket a rendszer az adott felhasználótól.
Mindkét megoldásnak közös problémája, hogy a kliens-nek el kéne küldenem az információt, hogy mihez van joga, hogy az alapján csak olyan menüpontokat rajzoljon ki, amik tényleg működnek is. Ez az első esetben az adatbázisban vagy php-ban tárolt szabályrendszer miatt nem megy, a második esetben meg azért, mert pusholni kellene a kliens-nek a változásokat, a php meg erre alkalmatlan. Esetleg response header-ben, vagy valami hasonlóban ki lehetne küldeni a második esetben, hogy frissítse a jogkörök listáját...
Döcögősnek érzem mindkét megoldásom. Szinte biztos, hogy van jobb. Bármi ötlet?
■ Jogosultság kezeléssel van egy problémám, amire nem tudtam kiagyalni általánosan használható rendszert. Vagy nem létezik ilyen, vagy a hiba bennem van.
Alapból úgy tárolom a szabályokat, hogy van egy listám az erőforrásokról és a műveletekről, amiket rajtuk lehet végezni. Ezt beszórtam egy táblába, aztán csináltam szerepköröket, amikhez hozzárendeltem ezeket a jogokat. A szerepköröket meg nyilván felhasználókhoz rendeltem hozzá. Ezzel így szerintem megfelelő.
A gond ott kezdődik, ha olyan dolgok jönnek be, ahol megszorítások vannak 1-1 erőforrásra. Ha mondjuk egy adminnak adok jogot a cikkek szerkesztésére, akkor "PUT article/*" jogkört kap, viszont ha egy mezei felhasználónak akarom megengedni, hogy az általa beküldött tartalmakat tudja szerkeszteni, akkor az előbbi jogkört úgy kell szűkítenem, hogy a * csak a saját cikkeinek az id-jére érvényes.
Ez egy általánosan előforduló dolog, pl a felhasználónak van egy munkamenete, aminél azt szeretném, hogy ki tudjon jelentkezni. Nyilván ilyenkor a "DELETE session/*" -re kap engedélyt, ahol a * az aktuális session ID lehet csak.
Egyelőre csak annyi jutott eszembe, hogy berakok egy flag-et a jogosultságokhoz, hogy általánosan vagy szűkítetten kell e értelmezni őket, illetve kézzel megírom minden egyes táblára az ellenőrzést, hogy az adott munkamenet felhasználójához tartozik e az adott sor... Esetleg van erre valami jobb megoldás? Egyelőre úgy vagyok vele, hogy adatbázis szinten meg tudom oldani a jogosultság kezelést, de egyre inkább úgy néz ki, hogy kénytelen leszek áttenni szerver oldali nyelvre, ahhoz, hogy rugalmas szabályokat tudjak csinálni.
Van egy másik lehetőség is, a felhasználók kapnak egyedi jogköröket, pl: "PUT article/123", és így tovább az összes cikkre külön külön. Ez nekem egy kicsit fapadosnak tűnik, de első ránézésre működőképes elgondolás. Ennek annyi a nehézsége, hogy bele kell írni a tárolt eljárásokba, hogy cikk létrehozásnál hozzáadjon és cikk törlésnél elvegyen jogköröket a rendszer az adott felhasználótól.
Mindkét megoldásnak közös problémája, hogy a kliens-nek el kéne küldenem az információt, hogy mihez van joga, hogy az alapján csak olyan menüpontokat rajzoljon ki, amik tényleg működnek is. Ez az első esetben az adatbázisban vagy php-ban tárolt szabályrendszer miatt nem megy, a második esetben meg azért, mert pusholni kellene a kliens-nek a változásokat, a php meg erre alkalmatlan. Esetleg response header-ben, vagy valami hasonlóban ki lehetne küldeni a második esetben, hogy frissítse a jogkörök listáját...
Döcögősnek érzem mindkét megoldásom. Szinte biztos, hogy van jobb. Bármi ötlet?
Egyelőre a legbiztosabbnak
Szinte biztos, hogy van
Nincs. Akkor lesz a leggenerikusabb a kódod, ha létrehozáskor külön adsz jogot a felhasználónak az erőforrásra.
Köszi! Ez lesz, mert amúgy is
Szerintem ezt pont jól
Megnézem később, hogy ez
Zed Shaw - The ACL is Dead
Te miért nem jöttél a
Jó a szövege a csávónak :D
azonosítók
én hasonló rendszert találtam ki, nálam reguláris kifejezések vannak a jogok táblában, amik matchelnek egy adott instance stringre, amit a model (article) dönt el hogy néz ki nála, pl néha benne van a slug is, vagy mondjuk egy category_id, illetve egyéb dolgok amikre szűkíteni lehet a jogokat.
(az ellenörző lekérdezés eredményei persze gyorítótárazva vannak adott sessiönön belül.)
Ja, ez is egy megoldás, hogy
nem a linkekbe
"a-cikk-cime" alapján kikeresi a controller, megkapjuk az entity-t, amin vagy egy method (->instance()) ami visszadja h "én az articles/117:a-cikk-cime:19:2 (itt pl "table/id:slug:author:cat" van) belső azonosítójú példány vagyok", és ezt ellenőrzöm az acles patternekre h van e megfelelő jog rá.
Második
Ja közben agyaltam egy sort.
Pl van egy felhasználód, és azt szeretnéd, hogy ő maga ne lássa a jogköreit, csak a nevét és esetleg az email címét:
A lekérdezés:
Azért annyira bonyolult ez a kérdéskör, mert sok esetben a queryString-ben beállítot szűrők is beleszólnak a dologba. Aztán vagy a visszatérő adatból kell utólag kiszűrni azt, amire nincs joga az illetőnek, vagy a mezők listájából.
Pl a
Nehéz kiválasztani, hogy az egyes url-ek között milyen kapcsolat legyen, pl ha a /users/13 engedélyezve van, akkor a /users/13/usersPermissions engedélyezve legyen-e, mert az a /users/13 alatt található, vagy egyenként meg kelljen e adni az ilyen alsóbb erőforrásokat. Az sem teljesen tiszta, hogy a router-rel milyen kapcsolata legyen, mert ha nem implementálom mondjuk a /user/13/userPermissions-t - ha ráhívok arra az url-re, akkor 404-et - akkor mi alapján veszem fel a jogosultságok közé, hiszen nem is létezik... Egyelőre még nem tiszta az algoritmus, ami alapján el fogja dönteni, hogy mire ad engedélyt, és mire nem. Azt hiszem utánanézek jobban a resource linking & expansion témaköröknek, hátha ott választ kapok...
Nem sok
Mint itt egy-egy komment: ha (még nem válaszoltak rá és a tiéd) vagy (moderátor vagy), akkor szerkesztheted. Ez nem sok kód, ezért nem érdemes szerintem bonyolítani. Én jobban híve vagyok a jogok~júzerek párosításnak, de nem mindenhova elég, gyanítom nem szórakozásból keresel más megoldást.
SZERK.: én elég sokat "lestem" a Drupal adatbázisából, mind felhasználó- és jogosultságkezelés, mind tartalomtípusok terén. De legtöbbször (nekem) sokkal egyszerűbb is elég: felhasználók - jogok - merge tábla. A tartalomtípusok másik kérdés.
Minden megoldható lenne
Specialis felhasznalo
kétszintű szűrő?
PUT article/*
DELETE session/*
szerepkör pedig lenne a következő
admin
user
és egyéb felhasználóhierarchia ha szükséges (csoportadmin)
és a felhasználókhoz egy jogosultság + szűrő párost kellene rendelned.
-bejön a kérés
-átmegy a PUT article/* feltételen, megvan az adott erőforrás
-ezután az erőforrást és a felhasználót még átadod egy szűrőnek is, pl isOwner(), ami admin-nál mindig true, groupadmin-nál, sima user-nél pedig már nem.
ha itt sem bukik meg a dolog, akkor csinálhatod a dolgod.
amúgy tényleg a zend-et kellene megnézned egy kicsit.
gondolom már késő a válasz, de hátha segít.
Ez a szűrő nem rossz ötlet,
Nem számít, hogy késő válasz, vagy ilyesmi, így is lehet tanulni belőle...
Na közben rájöttem magamtól, hogy max szövegként lehet letárolni, és a megvalósítást a php-ben megoldani:
Lehet, hogy valami kavarodás volt régen, nem olvasom vissza, de úgy emlékszem, hogy már akkor is elég jól elkülönült a szerepkör és a jogkör fogalma.
Ez az endpoint + filter egyértelműen jogkör, a szerepkörökhöz pedig jogköröket és felhasználókat lehet társítani. Amiben nálam más volt az előző változat, hogy pl owner filter helyett felsoroltam az összes endpoint-ot, ami a felhasználóhoz tartozik. Ez kevésbé takarékos sorok terén, mint a filterezés, de ugyanúgy működik. A filter azért jobb, mert az aktuális projection-t queryString-ben szokták megadni, így akár arra is lehet külön jogosultságot ellenőrizni. A másik, ami miatt jobb, hogyha a munkamenetben akarom cachelni a jogokat, akkor nem kell több ezer sort beolvasni onnan minden lekéréskor - ha olyan sok tartalmat hozott létre az illető - hanem elég csak egyet. Szóval a méret növekedésével nem fog lassulni a jogosultság ellenőrzés, szemben az én megoldásommal.
Közben kiderült, hogy kétféle
Átgondoltam több aspektusból
Két megközelítése van a témának, az egyik a hardcodolt, amikor az
endpoint
controllerébe tesszük be a hozzáférés ellenőrzéséhez dolgokat:Plusz példa wikipediaról:
XACML (extendable access control markup laguage):
if Subject match DesignatedDoctorOfPatient
and action is read
with obligation
on Permit: doLog_Inform(patientID, Subject, time)
on Deny : doLog_UnauthorizedLogin(patientID, Subject, time)
transzformálva:
Az obligation-ös részhez nyilván új táblák kellenek, de azt sem lehet valami nehéz letárolni adatbázisban. És akkor ez egy direkt ilyen célra alkotott nyelv volt... (Biztosan többet is tud az a nyelv, de azt hiszem, hogy a megközelítésem elég jó. Hízik a májam :D)
A kimenő dolgok szűrését is meg lehet oldani ugyanilyen ellenőrzéssel. Azt nyilván már muszáj hardcodolni és kézzel hívni... Továbbá kell majd egy megoldás a szűrők összepárosítására a megfelelő osztályokkal, de azzal sem hiszem, hogy probléma lesz. Az egyedüli hátránya az egésznek, hogy a rugalmasságért cserébe lassabb valamivel, mert az összes - a felhasználóhoz tartozó - szabályt le kell rántani bejelentkezéskor a munkamenetbe, aztán kikeresni, hogy illik e valamelyik az aktuális kérésre. Ha elég gyors az algoritmus, és nincs indokolatlanul sok szabály, akkor szerintem megéri a használata.
Még majd tuningolni kellene az alkalmazás kódján annotációkkal, és akkor egész pofásan lehet majd használni ezt a megoldást. Neki fogok ülni, megvalósítom, aztán majd kiszórom github-ra.
szerk: Közben találtam olyat, aki hasonló eredményre jutott: http://wuher-random.blogspot.hu/2011/09/access-control-for-your-restful-api.html pythonban fejlesztett egy hasonló middleware-t...
Körülbelül általánosságban az
- A filterek döntik el, hogy joga van e az illetőnek az adott műveletre. Ha listázzuk az illető összes jogosultságát, és egy jogosultságnál sem mennek át a filterek az adott kérésre, akkor nincs joga a műveletre. Két filter típus lehet, a global és a local. A global a method és az url szűrő, mert azokat minden kérésnél meg lehet mondani. De ugyanígy lehet http header-re és minden másra szűrni... A local mondjuk az isOwner, azt máshogy kell lekérdezni egy profil oldalnál és egy cikknél is, más az sql mögötte, így helyben kell megvalósítani.
- A projection a művelet lefutását módosíthatja, pl ha csak olyan projection-re van joga valakinek, ami id-t és felhasználói nevet tartalmaz, akkor nem kaphat vissza email címet, vagy ha törlést hív, és csak elrejtéshez van joga, akkor nyilván elrejteni fogja a rendszer a hozzászólást.
- Az obligations tartalmazza a jogosultság ellenőrzéssel kapcsolatos eseménykezelőket. Mondjuk ha sikertelenül próbálkozik valaki a belépéssel egy fiókba, akkor arról lehet üzenetet küldeni a fiók tulajdonosának.
Ezeket mind le lehet tárolni adatbázisban, vagy többé-kevésbé beleégetni a kódba. Az, hogy melyiket válasszuk attól függ, hogy mennyire rugalmas rendszer felel meg az igényeinknek. Ha mondjuk két csoport van: olvasók, szerkesztők, akkor teljesen felesleges emiatt egy bonyolult rendszert felépíteni, elég az adatbázisban csak a csoportokat letárolni és hardcodolni a csoport tagság ellenőrzését. Ha ennél bonyolultabb a helyzet, az egyre inkább a kevesebb hardcodolás és több automatizálás + adatbázisban mentés felé tolja el a mérleget.
Na általános rendszert se ma csinálok erre, nekem jelenleg simán elég egy durva szemcsés hardcodolt megoldás 2 csoporttal meg egy isOwner szűrővel, viszont ezt az egészet beteszem egy külön projektbe, aztán ha több időm lesz, akkor foglalkozom vele.
Példának szerintem elég ennyi:
hardcode:
Lehet...
A jogosultság ellenőrzés
Egy komolyabb jogosultság ellenőrző rendszerhez kb ennyi kell:
SecurityGuard
(sokan AccessManager-nek hívnák, de ilyen melót nem szívesen bíznék menedzserekre), ami végigfuttatja a Session-höz tartozó összes Policy-t a bennük található Constraint-ekkel az adott kérésre, és ahol minden Constraint stimmel, ott megkapja a munkamenet az összes Permission-t, ami a Policy-hez tartozik. (Általában ezt meg szokták optimalizálni, hogy szűrjön endpointonként, stb.. különben baromi lassú lenne.) Ezek után lefut a Controller és a Permission-ök alapján megcsinálja, amit kell. Ha egy Policy-t sem sikerül begyűjteni, akkor a játéknak vége, és 403-as status-t küld vissza a szerver. (Egy perc és nyersz, vagy miben tolnak ilyen szövegeket?! :D Na mindegy, ez csak úgy jött...)Onnan tudom, hogy valamit már értek, hogy a lehető legtömörebben el tudom mondani. Általában ez van, mint ennél a témánál, hogy futok 10-20 kört, újra, és újra átfogalmazom, míg a végén teljesen betömörödik az egész pár mondatba. A gond akkor szokott kezdődni, ha közben valakinek magyarázok erről, mert a végén bele szoktak őrülni az emberek :D
Lábjegyzet: az XACML szabvánnyal is hasonlóan oldják meg a dolgot, mint én, szóval ha egy adott nyelven implementálva van az a szabvány, akkor érdemes azt használni saját könyvtár gányolása helyett.
Unix
Nem elég általános, egy