[Alg] rechtensysteem/RBAC

Pagina: 1
Acties:

  • B-Man
  • Registratie: Februari 2000
  • Niet online
Ik weet dat er al aardig wat topics over dit onderwerp geweest zijn, maar ik zit met een vraagstuk dat ik nog niet fatsoenlijk heb kunnen oplossen.

Het gaat om een applicatie met daarin verschillende objecten en functies (objects en operations volgens RBAC), verschillende gebruikers en verschillende rollen.
Om het geheel in dit stadium overzichtelijk te houden ga ik er van uit dat een gebruiker maximaal een rol krijgt toegewezen.
Objecten en rollen zijn hierarchisch
(Klant -> Medewerker -> Taak) (Beheer -> beheer database X -> beheer tabel Y).

Nu zit ik met het volgende vraagstuk:
Een login geeft toegang tot:
a) objecten en functies (bijv: een klant toevoegen)
b) implementaties van objecten (bijv: klant met id=10 wijzigen)

Nu heb ik op dit moment reeds een implementatie die het mogelijk maakt om ook de implementaties van objecten te gebruiken in rechten. Concreet betekent dit dat ik kan zeggen:
- Bekijk overzicht klanten: toestaan
- Object: klanten, implementatie: id=10: weigeren
Wat resulteert in een overzicht met klanten, waarin klant '10' niet zichtbaar is.

Wat ook al mogelijk is, is hierarchie van implementaties, die de hierarchie van de objecten die ze implementeren volgt.
Concreet: als ik klant '10' blokkeer en vervolgens het overzicht met alle medewerkers in het systeem opvraag (medewerker is een child van klant), dan worden alle medewerkers die onder klant '10' vallen verborgen.

Tot dusver de inleiding. Waar ik mee zit is het volgende: hoe sla ik dit fatsoenlijk op? Nu houd ik de implementaties bij in een aparte tabel die de hierarchische structuur van objecten volgt.

Mijn tabellen op dit moment
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
table object(
  id, name, nleft, nright, nlevel (laatste drie zijn mptt kolommen)
)

table function (
  id, object_id, name
)

table object_impl (
  id, object_id, realid, nleft, nright, nlevel
)

table user (
  id, name, ...
)

table role (
  id, name, nleft, nright, nlevel
)

table user_role (
  user, role
)

table permission (
  id, role_id, object_id, function_id, object_impl_id, access (boolean)
)


Hoe zorg ik ervoor dat ik kan zeggen:
- gebruiker X kan nieuwe klanten toevoegen
- gebruiker X kan het overzicht met klanten bekijken
- gebruiker X kan niet bij klant '10' en alle objecten die eronder hangen

Nu zit ik te denken aan domains, die ook hierarchisch zijn:
domain 'Klant' - objects (medewerker, taak)
- domain 'Klant X' - objects (impl van medewerker, impl van taak)
- domain 'Klant Y' - idem

dit zou mogelijk zijn door de tabel met objecten uit te breiden:
code:
1
2
3
tabel objects (
  id, domain_id, name, impl_domain, impl_object, impl_id, nleft, nright, nlevel
)

Waarin de impl_* velden optioneel zijn.

Redelijk ranzig vind ik echter ;) Het makkelijkst zou zijn de implementaties direct onder het object te hangen dat ze implementeren, maar dan ben ik de hierachie van de implementaties kwijt (medewerker X hoort bij klant Y, enz).

Ik ben al een half jaartje hiermee bezig (in de vrije uurtjes), en het verbaast me dat hier vrijwel niets over te vinden is. Zaken als bijvoorbeeld phpGACL implementeren wel iets waarmee je implementaties kunt verwerken in je rechten, maar niet hoe je de hierarchie van deze implementaties kunt meenemen.
Het vraagstuk: ik wil een functie in mijn applicatie toestaan, maar niet voor een implementatie en de childnodes van die implementatie, lijkt me toch niet zo heel erg ongebruikelijk.
Misschien is er een makkelijkere manier om dit te doen, haha.

Aangezien er al aardig wat topics over rechten geweest zijn, zullen er vermoedelijk wel mensen zijn die hier wat nuttigs over kunnen zeggen. Brand los zou ik zeggen ;)

  • B-Man
  • Registratie: Februari 2000
  • Niet online
Even een extra post (anders wordt de vorige erg lang):

Wat screenshots van de huidige implementatie, en wat code fragments:

Object beheer (linkerframe treeview met objecten, rechterframe details object):
Afbeeldingslocatie: http://217.160.111.136/got/rbac/objecten.gif

Rolbeheer, hier zonder implementatie(s):
Afbeeldingslocatie: http://217.160.111.136/got/rbac/rollen.gif

Rolbeheer, hier met een implementatie, die een object recht override (alle acties op het object 'client' zijn enkel mogelijk voor de implementatie met id=2 en alle childnodes van 'client'.
Afbeeldingslocatie: http://217.160.111.136/got/rbac/rolimpl.jpg

Codefragments:

- opvragen op welke implementaties ik een actie mag uitvoeren:
PHP:
1
2
3
4
5
6
Auth::getACLObjs('client:list', 'client');
// Geeft een array met als eerste waarde ALL, NONE of LIST terug, waarbij 
// bij LIST een tweede waarde in het array een lijst (array) met geldige id's is
Auth::isAllowedObj('worker:add', 'client', 10);
// retourneert een boolean. Ik controleer hier of ik een medewerker toe mag voegen
// aan 'klant 10' met mijn huidige rechten/rol.


Het werkt op dit moment prima, vanwege MPTT en zeer efficiente caching. Alleen heb ik al tijden het gevoel dat het beter kan, wat minder ranzig.

[ Voor 7% gewijzigd door B-Man op 11-12-2004 16:39 . Reden: plaatje vergeten ]


  • drm
  • Registratie: Februari 2001
  • Laatst online: 09-06-2025

drm

f0pc0dert

Hoewel ik nog niet helemaal tevreden ben over mijn eigen implementatie in ons CMS, zal ik even uitleggen hoe ik het heb gedaan. 't Is hier en daar een beetje ranzig, maar zie maar of je er iets aan hebt. :)

Ik heb een aantal gecategoriseerde privileges. De privileges zijn puur op basis van "has" en "has not". Dus: als een koppeling tussen een gebruiker en een privilege bestaat, mag de gebruiker datgeen, zo niet, dan niet. Ik wil dit eigenlijk nog uitbreiden in de toekomst met een drievoudig "allow", "deny" en "don't care", maar tot dusver is het wel aardig toereikend.

De categorien van privileges zijn de volgende:
- global
- per entity
- per record

De global privileges zijn algemene dingetjes als "men mag inloggen" en zo. Vul maar in, alles wat niet direct betrekking heeft op een bepaalde entity of een bepaalde record, komt onder die categorie te vallen. De relatie is dan eenvoudig, namelijk een n:m relatie tussen een privilege en een gebruiker (of gebruikersgroep, of rol, hoe je dat maar wilt implementeren).

De per-entity privileges zijn: create, list en ownership. De create geeft aan dat er binnen die entity records aangemaakt mogen worden, list dat er een overzicht gegenereerd mag worden en ownership betekent dat alle onderliggende privileges toegekend zijn (ter optimalisatie).

De per-record privileges zijn: view, edit, delete, rel_add en rel_remove. De eerste drie zijn wel duidelijk, denk ik, de laatste twee zijn voor het aanbrengen en verwijderen van relaties. Wanneer een object (record) naar een bepaald ander record (hetzij uit dezelfde entity, hetzij uit een andere entity) verwijst, moet over het rel_remove-privilege op dat object beschikken om de verwijzing te wijzigen (n:1) of te verwijderen (n:m). De rel_add privilege is om verwijzingen aan te mogen maken naar een bepaald ander object uit hetzij dezelfde entity, hetzij uit een andere.

e.e.a wordt opgeslagen in 3 verschillende koppeltabellen die wat parameters bevatten:
code:
1
2
3
4
5
6
7
8
globale privileges
privilege_id  role_id

per entity privileges
privilege_id role_id entity_id

per record privileges
privilege_id role_id entity_id record_id


Daarmee kun je zo goed als alles in rollen onderverdelen.

In het geval dat er een gebruiker enkel een select overzicht uit een bepaalde entity mag krijgen, moet hij dus allereerst de 'list' privilege hebben, en vervolgens op elk relevant record een 'view'-privilege. Dat laatste is heel eenvoudig te implementeren door een inner join te doen op de per-entity privilege-tabel.

Het grootste nadeel op dit moment is dat er nog geen gebruik gemaakt wordt van ownership op records. Wanneer een gebruiker ergens een record in stopt, is het nu (gemakshalve O-)) zo dat de gebruiker alle per-record privileges op dat record krijgt. Dat is behoorlijk braque, maar ik heb helaas nog geen tijd gehad om daar eens goed over na te denken.

Ik hoop dat je hier wat aan hebt :) Ook als je nog (andere) flaws in dit systeem ziet, be my guest to mention :)

Music is the pleasure the human mind experiences from counting without being aware that it is counting
~ Gottfried Leibniz


  • alienfruit
  • Registratie: Maart 2003
  • Laatst online: 09-05 23:44

alienfruit

the alien you never expected

Hoe ondersteun je vertalingen? Ik neem aan dat je niet altijd alles wilt laten vertalen... Misschien ook een recht van maken i.e. mag pietje een vertaling maken/starten van record X.

[ Voor 20% gewijzigd door alienfruit op 11-12-2004 17:12 ]


  • B-Man
  • Registratie: Februari 2000
  • Niet online
drm, ik lees niets over inheritance in je rechtensysteem? Je slaat dus voor iedere privilege een (database) record op?
Als je met inheritance zou werken, zou je je probleem (hetgeen je nu brak vindt) niet meer hebben: je zou dan simpelweg geen rechten instellen op het nieuw aangemaakte record, maar het record zou dan de entity rechten overerven.

  • B-Man
  • Registratie: Februari 2000
  • Niet online
alienfruit schreef op zaterdag 11 december 2004 @ 17:11:
Hoe ondersteun je vertalingen? Ik neem aan dat je niet altijd alles wilt laten vertalen... Misschien ook een recht van maken i.e. mag pietje een vertaling maken/starten van record X.
Op wie reageer je? ik neem aan op drm ;)
Komisch trouwens, in een aantal topics dat ik tegenkwam in mijn queeste naar RBAC op GoT kwam ik posts van jou tegen die geregeld over 'rechten voor vertalen' gingen ;)

  • drm
  • Registratie: Februari 2001
  • Laatst online: 09-06-2025

drm

f0pc0dert

B-Man:
drm, ik lees niets over inheritance in je rechtensysteem? Je slaat dus voor iedere privilege een (database) record op?
Ja, voor zover die privileges per record gelden wel.
Als je met inheritance zou werken, zou je je probleem (hetgeen je nu brak vindt) niet meer hebben: je zou dan simpelweg geen rechten instellen op het nieuw aangemaakte record, maar het record zou dan de entity rechten overerven.
Overerven waarvan dan? :)

edit:
alienfruit:
Hoe ondersteun je vertalingen? Ik neem aan dat je niet altijd alles wilt laten vertalen... Misschien ook een recht van maken i.e. mag pietje een vertaling maken/starten van record X.
Het is nu zo dat een taal ook een entity is en een vertaling van een object dus altijd een extra relatie is tussen taal en object die een aantal attributen bevat. Da's trouwens wel nog een flaw van dit systeem, je kunt niet per relatie tussen entiteiten aangeven wat wel en niet mag. Wat dat betreft zouden die rel_add en rel_remove privileges weer van een 4e categorie moeten zijn...

offtopic:
overigens lijkt dit best wel schaamteloze topic-kaping :D, da's niet mijn bedoeling :)

[ Voor 43% gewijzigd door drm op 11-12-2004 17:22 ]

Music is the pleasure the human mind experiences from counting without being aware that it is counting
~ Gottfried Leibniz


  • alienfruit
  • Registratie: Maart 2003
  • Laatst online: 09-05 23:44

alienfruit

the alien you never expected

Oh Oh, okay :)

  • B-Man
  • Registratie: Februari 2000
  • Niet online
drm: overerven van entity (voorzover mogelijk).

Ik zit wat te zoeken met google, op zoek naar andere complexe implementaties van rechtenbeheer, en kom phpBB2 en mambo tegen (mambo gebruikt phpGACL).

Zojuist nog een interessant topic gevonden:
[rml][ Alg] Rechtensysteem voor extranet *[/rml]

[ Voor 21% gewijzigd door B-Man op 11-12-2004 18:22 ]


  • B-Man
  • Registratie: Februari 2000
  • Niet online
Ik 'vis' deze weer even op, omdat ik nog steeds met dit probleem aan het stoeien ben.

Voorbeeld:

Neem een verhuurbedrijf.
Ze verhuren auto's en hebben klanten (twee objecttypen).
Ze willen kunnen zeggen:
- De toyota corolla (sedan) mag niet verhuurd worden
- Dhr. X mag geen sedans huren
- Dhr. X mag wel de toyota avensis huren

Als dhr X nu vraagt welke auto's hij kan huren, moet het systeem alle sedans laten zien, behalve de toyota corolla.

Bovenstaand voorbeeld illustreert mijn vraagstuk goed: ik wil rechten kunnen geven op generieke objecten (sedans in dit geval), en op specifieke implementaties ervan (de toyota corolla).

Probleem in mijn applicatie is dat de objectenstructuur hierarchisch is (gemodelleerd naar de functies in de applicatie), en dat de implementaties ook hierarchisch zijn, volgens de hierachie van de objecten, maar tevens een 'eigen' parent-child relatie.

Nog een voorbeeld, een boekenwinkel:

Er staan boekenkasten, in die kasten zitten planken, en op de planken staan boekcategorieen, waar boeken onder vallen.
De boekenwinkel staat Dhr. X toe om science fiction boeken te lenen, behalve boeken die in boekenkast 12 staan.

Ik krijg dit maar niet naar een fatsoenlijk datamodel vertaald, mogelijk omdat ik zaken onnodig complex maak. Ik zie echter niet hoe ik e.e.a. simpeler op zou kunnen lossen. Kunnen jullie hier eens een mening/advies over geven?

Verwijderd

Misschien volg ik je niet helemaal, maar waarom moet je deze tabel:
code:
1
2
3
table object(
  id, name, nleft, nright, nlevel (laatste drie zijn mptt kolommen)
)

uitbreiden naar
code:
1
2
3
tabel objects (
  id, domain_id, name, impl_domain, impl_object, impl_id, nleft, nright, nlevel
)

terwijl je ook een hierarchie kan bouwen door deze zo uit te breiden:
code:
1
2
3
table object(
  id, name, parent_id, nleft, nright, nlevel (laatste drie zijn mptt kolommen)
)

  • B-Man
  • Registratie: Februari 2000
  • Niet online
Nextgeneration: een 'domein' is van een andere orde als een object, en hoort niet in dezelfde tabel thuis. Tevens ben je zo te zien niet bekend met MPTT, aangezien deze juist het werken met parent_id-achtige kolommen overbodig maakt.
Voor uitleg over MPTT kun je hier kijken. Als je met databases werkt sowieso interessant leesvoer.
Pagina: 1