Package: py-rbac
py-rbacPython implementation of the NIST model for role based access control (RBAC).The NIST modelproposes four level of role based access control implementation:Flatusers acquire permissions through rolesmust support many-to-many user-role assignmentmust support many-to-many permission-role assignmentmust support user-role assignment reviewusers can use permissions of multiple roles simultaneouslyHierarchicalFlat +must support role hierarchy (partial order)arbitrary hierarchieslimited hierarchiesConstrainedHierarchical +must enforce separation of duties (SOD)arbitrary hierarchieslimited hierarchiesSymmetricConstrained +must support permission-role review with performance effectively comparable to user-role reviewarbitrary hierarchieslimited hierarchiesThis library supports Level 1, 2 and 3.UsageI've tried to explain the usage based on levels but the library is flexible enough to
use any feature freely without thinking about levels.InstallThrough pip:pipinstallpy-rbacFlat ScenarioThis is the simplest scenario an mostly used I think. Let's configure it first:fromrbacimportRBACrbac=RBAC()# a role for junior editorsjr_editor=rbac.create_role('jr_editor')# a domain or resource is also an objectarticle=rbac.create_domain('article')# create permissionscreate=rbac.create_permission('c')read=rbac.create_permission('r')update=rbac.create_permission('u')delete=rbac.create_permission('d')# give junior a read permission for articlesjr_editor.add_permission(read,article)# lets create a subject. a user or a third party clientsubject=rbac.create_subject('some_int_or_str')# our subject is new in the jobsubject.authorize(jr_editor)# lock rbac configuration# this validates the entire structure of our configuration# will sense more meaning as we use advanced features belowrbac.lock()After your application executed some code and is about respond client's request:# check if the client is allowed to...rbac.go('some_int_or_str',article,create)# this will raise an exception since we didn't give a create permission to our junior# raised RBACAuthorizationErrorHierarchical ScenarioIn this example, there are hierarchical relationships between roles. Each role
inherits its children roles and permissions. (Inheriting can be disabled but
review this scenario first.) Configure and lock as always:fromrbacimportRBACrbac=RBAC()jr_editor=rbac.create_role('jr_editor')editor=rbac.create_role('editor',children=jr_editor)it=rbac.create_role('it',children=(jr_editor,editor))article=rbac.create_domain('article')service_conf=rbac.create_domain('service_conf')create=rbac.create_permission('c')read=rbac.create_permission('r')update=rbac.create_permission('u')delete=rbac.create_permission('d')jr_editor.add_permission(read,article)editor.add_permission(create,article)it.add_permission((create,read,update,delete),service_conf)john=rbac.create_subject(1)john.authorize(jr_editor)jack=rbac.create_subject(2)jack.authorize(editor)mark=rbac.create_subject(3)mark.authorize(it)rbac.lock()Run:assertrbac.go(2,article,read)isNoneassertrbac.go(1,article,read)isNoneassertrbac.go(3,article,create)isNoneassertrbac.go(3,service_conf,create)isNone# will raisetry:rbac.go(1,article,create)exceptRBACAuthorizationErrorase:raiseConstrained ScenarioIn this scenario, there are constraints. Constraints restricts the authorization
flow as they are being applied through RBAC objects. Configure and lock:fromrbacimportRBAC# an article from our application! we use this as our domainclassArticle():"""docstring for Article."""def__init__(self,id,author):self.id=idself.author=authorrbac=RBAC()# we can only allow one person to be assigned to this rolejr_editor=rbac.create_role('jr_editor',max_subjects=1)# we may have editors up to 10editor=rbac.create_role('editor',children=jr_editor,max_subjects=10)# a chief role for one person but it won't inherit its children permissionschief=rbac.create_role('chief',children=(jr_editor,editor),inherit=False,max_subjects=1)# we use Article object as input to our RBACDomain but why an object?# specifically for the match_domain_prop constraint.article=rbac.create_domain(Article)# as usualcreate=rbac.create_permission('c')read=rbac.create_permission('r')update=rbac.create_permission('u')delete=rbac.create_permission('d')# our junior can read and create articles...jr_editor.add_permission((create,read),article)# ... but can only remove the ones which he/she wrote# match_domain_prop constraint indicates that the article instance property# "author" should match with the at-then id of the subject.jr_editor.add_permission(delete,article,match_domain_prop='author')editor.add_permission(create,article)# defining 2 jrs... hmmmjohn=rbac.create_subject(1)john.authorize(jr_editor)another_john=rbac.create_subject(2)another_john.authorize(jr_editor)# this will raise because our jr role can have 1 jrs max.try:rbac.lock()exceptRBACConfigurationErrorase:raise# ok then, fire another_john!another_john.revoke(rbac.get_role_by_name('jr_editor'))# now locked.assertrbac.lock()isNone# or unblock and add 2 more subject:rbac.unlock()jack=rbac.create_subject(3)jack.authorize(editor)brad=rbac.create_subject(4)brad.authorize(chief)rbac.lock()Our API received a request about deleting some article:some_article=Article(28372,1)# our junior john trying to delete an article# the library will match the john's id which is 1 with the article's author and# allow the operation if they match.assertrbac.go(1,some_article,delete)isNoneVersioningThis library uses calendar versioning.Thanks for watching 🐬ContributionThis project uses pipenv to manage its dependencies. The only dependency it has
is the pytest package which is used in development.Clone the repository.Runpipenv installMake updates.Runpytestunderpipenv shellRungit push origin masterand create a pull request.