Catalyst Advent - Day 24 - Authorization
NOTE: This article is now obsolete. Please refer to http://dev.catalyst.perl.org/wiki/gettingstarted/howtos/interim_authorization_and_authentication_example.
Introduction
Authorization is the step that comes after authentication. Authentication establishes that the user agent is really representing the user we think it's representing, and then authorization determines what this user is allowed to do.
Role Based Access Control
Under role based access control each user is allowed to perform any number of roles. For example, at a zoo no one but specially trained personnel can enter the moose cage (Mynd you, moose bites kan be pretty nasti!). For example:
package Zoo::Controller::MooseCage; sub feed_moose : Local { my ( $self, $c ) = @_; $c->model( "Moose" )->eat( $c->req->param("food") ); }
With this action, anyone can just come into the moose cage and feed the moose, which is a very dangerous thing. We need to restrict this action, so that only a qualified moose feeder can perform that action.
The Authorization::Roles plugin let's us perform role based access control checks. Let's load it:
use Catalyst qw/ Authentication # yadda yadda Authorization::Roles /;
And now our action should look like this:
sub feed_moose : Local { my ( $self, $c ) = @_; if ( $c->check_user_roles( "moose_feeder" ) ) { $c->model( "Moose" )->eat( $c->req->param("food") ); } else { $c->stash->{error} = "unauthorized"; } }
This checks $c->user
, and only if the user has all the roles in the
list, a true value is returned.
check_user_roles
has a sister method, assert_user_roles
, which throws an
exception if any roles are missing.
Some roles that might actually make sense in, say, a forum application:
- administrator
- moderator
each with a distinct task (system administration versus content administration).
Access Control Lists
Checking for roles all the time can be tedious and error prone.
The Authorization::ACL plugin let's us declare where we'd like checks to be done automatically for us.
For example, we may want to completely block out anyone who isn't a
moose_feeder
from the entire MooseCage
controller:
Zoo->deny_access_unless( "/moose_cage", [qw/moose_feeder/] );
The role list behaves in the same way as check_user_roles
. However, the ACL
plugin isn't limited to just interacting with the Roles plugin. We can use a
code reference instead. For example, to allow either moose trainers or moose
feeders into the moose cage, we can create a more complex check:
Zoo->deny_access_unless( "/moose_cage", sub { my $c = shift; $c->check_user_roles( "moose_trainer" ) || $c->check_user_roles( "moose_feeder" ); });
The more specific a role, the earlier it will be checked. Let's say moose
feeders are now restricted to only the feed_moose
action, while moose
trainers get access everywhere:
Zoo->deny_access_unless( "/moose_cage", [qw/moose_trainer/] ); Zoo->allow_access_if( "/moose_cage/feed_moose", [qw/moose_feeder/]);
When the feed_moose
action is accessed the second check will be made. If the
user is a moose_feeder
, then access will be immediately granted. Otherwise,
the next rule in line will be tested - the one checking for a moose_trainer
.
If this rule is not satisfied, access will be immediately denied.
Rules applied to the same path will be checked in the order they were added.
Lastly, handling access denial events is done by creating an access_denied
private action:
sub access_denied : Private { my ( $self, $c, $action ) = @_; }
This action works much like auto, in that it is inherited across namespaces
(not like object oriented code). This means that the access_denied
action
which is nearest to the action which was blocked will be triggered.
If this action does not exist, an error will be thrown, which you can clean up
in your end
private action instead.
Also, it's important to note that if you restrict access to "/" then end
,
default
, etc will also be restricted.
MyApp->acl_allow_root_internals;
will create rules that permit access to end
, begin
, and auto
in the
root of your app (but not in any other controller).
More Information
- Previous
- Next