Authorize::Rule - Rule-based authorization mechanism
version 0.001
A simple example:
my $auth = Authorize::Rule->new( rules => { # Marge can do everything Marge => [ allow => '*' ], # Homer can do everything except go to the kitchen Homer => [ deny => ['oven'], allow => '*', ], # kids can clean and eat at the kitchen # but nothing else # and they can do whatever they want in their bedroom kids => [ allow => { kitchen => { action => ['eat', 'clean'], }, bedroom => '*', }, deny => ['kitchen'], ], }, ); $auth->check( Marge => 'kitchen' ); # 1 $auth->check( Marge => 'garage' ); # 1 $auth->check( Marge => 'bedroom' ); # 1 $auth->check( Homer => 'oven' ); # 0 $auth->check( Homer => 'kitchen' ); # 1 $auth->check( kids => 'kitchen', { action => 'eat' } ); # 1 $auth->check( kids => 'kitchen', { action => 'destroy' } ); # 0
Authorize::Rule allows you to provide a set of rules for authorizing access of entities to resources. This does not cover authentication. While authentication asks "who are you?", authorization asks "what are you allowed to do?"
The system is based on decisions per resources and their parameters.
The following two authorization decisions are available:
allow
Allow an action. If something is allowed, 1 (indicating true) is returned.
deny
Deny an action. If something is denied, 0 (indicating false) is returned.
The following levels of authorization are available:
For all resources
Cats think they can do everything.
my $rules = { cats => [ allow => '*' ] }; my $auth = Authorize::Rule->new( rules => $rules ); $auth->check( cats => 'kitchen' ); # 1, success $auth->check( cats => 'bedroom' ); # 1, success
The star (*) character means 'allow/deny all resources to this entity'. By setting the cats entity to allow, we basically allow cats on all resources. The resources can be anything such as couch, counter, tables, etc.
cats
If you don't like the example of cats (what's wrong with you?), try to think of a department (or person) given all access to all resources in your company:
$rules = { syadmins => [ allow => '*' ], CEO => [ allow => '*' ], }
Per resource
Dogs, however, provide less of a problem. Mostly if you tell them they aren't allowed somewhere, they will comply. Dogs can't get on the table. Except the table, we do want them to have access everywhere.
$rules = { cats => [ allow => '*' ], dogs => [ deny => ['table'], # they can't go on the table allow => '*', # otherwise, allow everything ], }
To provide access (allow/deny) to resources, you have specify them as an array. This helps differ between the star character for 'all'.
Rules are read consecutively and as soon as a rule matches the matching stops.
You can provide multiple resources in a single rule. That way we can ask dogs to also keep away from the laundry room:
$rules = { cats => [ allow => '*' ], dogs => [ deny => [ 'table', 'laundry room' ], # they can't go on the table allow => '*', # otherwise, allow everything ], }
Suppose we adopted kitties and we want to keep them safe until they grow older, we keep them in our room and keep others out:
$rules = { cats => [ deny => ['bedroom'], allow => '*' ], dogs => [ deny => [ 'table', 'laundry room', 'bedroom' ], allow => '*', ], kitties => [ allow => ['bedroom'], deny => '*', ], }
A corporate example might refer to some departments (or persons) having access to some resources while denied everything else, or a certain resource not available to some while all others are.
$rules = { CEO => [ deny => ['Payroll'], allow => '*', ], support => [ allow => [ 'UserPreferences', 'UserComplaintHistory' ], deny => '*', ], }
You might ask 'what if there is no last catch-all rule at the end?' - the answer is that the default clause will be used. You can find an explanation of it under ATTRIBUTES.
default
Per resource and per conditions
This is the most extensive control you can have. This allows you to set permissions based on conditions, such as specific parameters per resource.
The conditions are sent to the check method as additional parameters and checked against it.
check
Suppose we have no problem for the dogs to walk on that one table we don't like?
my $rules => { dogs => [ allow => { table => { owner => ['someone-else'] } }, deny => ['table'], allow => '*', ] }; my $auth = Authorize::Rule->new( rules => $rules ); $auth->check( dogs => 'table', { owner => 'me' } ); # 0, fails
Of course you can use a star (*) as the value which means 'all'.
*
Since you specify values as an array, you can specify multiple values. They will each be checked against the value of each hash key. We assume the hash value for each key is a single string.
Here we specify a list of people whose things we don't mind the dog ruining:
my $rules => { dogs => [ allow => { table => { owner => ['jim', 'john'] } }, deny => ['table'], allow => '*', ] }; my $auth = Authorize::Rule->new( rules => $rules ); $auth->check( dogs => 'table', { owner => 'me' } ); # 0, fails $auth->check( dogs => 'table', { owner => 'jim' } ); # 1, succeeds $auth->check( dogs => 'table', { owner => 'john' } ); # 1, succeeds
More complicated structures (other than hashref of keys to string values) are currently not supported, though there are plans to add callbacks in order to allow the user to specify their own checks of conditions.
I can't promise some of this won't change in the next few versions.
Stay tuned.
In case there is no matching rule for the entity/resource/conditions, what would you like to do. The default is to deny (0), but you can change it to allow by default if there is no match.
0
Authorize::Rule->new( default => 1, # allow by default rules => {...}, );
A hash reference of your permissions.
Top level keys are the entities. This can be groups, users, whichever way you choose to view it.
{ ENTITY => RULES, }
For each entity you provide an arrayref of the rules. The will be read and matched in sequential order. It's good practice to have an explicit last one as the catch-all for that entity. However, take into account that there is also the default. By default it will deny unless you change the default to allow.
{ ENTITY => [ RULE1, RULE2, ], }
Each rule contains a key of the action, either to allow or deny, followed by a resource definition.
{ ENTITY => [ ACTION => RESOURCE ] }
You can provide a value of star (*) to say 'this entity can do everything' or 'this entity cannot do anyting'. You can provide an arrayref of the resources you want to allow/deny.
{ Bender => [ deny => [ 'fly ship', 'command team' ], allow => '*', # allow everything else ], Leila => [ deny => ['goof off'], allow => [ 'fly ship', 'command team' ], # if none are matched, it will take the default ] }
You can also provide conditions as a hashref for each resource. The value should be either a star (*) to match key existence, or an arrayref to try and match the value.
{ Bender => [ allow => { # must have booze to function functioning => { booze => '*' } }, # allow friendship to these people allow => { friendship => { person => [ 'Leila', 'Fry', 'Amy' ] }, # deny friendship to everyone else deny => ['friendship'], ] }
$auth->check( ENTITY, RESOURCE ); $auth->check( ENTITY, RESOURCE, { CONDITIONS } );
You decide what entities and resources you have according to how you define the rules.
You can think of resources as possible actions on an interface:
my $auth = Authorize::Rule->new( rules => { Sawyer => [ allow => [ 'view', 'edit' ] ] } ); $auth->check( Sawyer => 'edit' ) or die 'Sawyer is not allowed to edit';
However, if you have multiple interfaces (which you usually do in more complicated environments), your resources are those interfaces:
my $auth = Authorize::Rule->new( rules => { Sawyer => [ allow => [ 'Dashboard', 'Forum' ] ], } ); # can I access the dashboard? $auth->check( Sawyer => 'Dashboard' );
That's better. However, it doesn't describe what Sawyer can do in each resource. This is why you have conditions.
my $auth = Authorize::Rule->new( rules => { Sawyer => [ allow => { Dashboard => { action => ['edit', 'view'] } } ] } ); $auth->check( Sawyer => 'Dashboard', { action => 'delete' } ) or die 'Stop trying to delete the Dashboard, Sawyer!';
Sawyer X <xsawyerx@cpan.org>
This software is copyright (c) 2013 by Sawyer X.
This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.
To install Authorize::Rule, copy and paste the appropriate command in to your terminal.
cpanm
cpanm Authorize::Rule
CPAN shell
perl -MCPAN -e shell install Authorize::Rule
For more information on module installation, please visit the detailed CPAN module installation guide.