#!/usr/bin/perl package Catalyst::Plugin::Authorization::Abilities; use strict; use warnings; use Scalar::Util (); use Catalyst::Exception (); our $VERSION = '0.01'; sub check_user_ability { my ($c, @actions) = @_; local $@; eval { $c->assert_user_ability(@actions) }; } sub assert_user_ability { my ($c, @actions) = @_; my $user; if (Scalar::Util::blessed($actions[0]) && $actions[0]->isa("Catalyst::Authentication::User")) { $user = shift @actions; } $user ||= $c->user; unless ($user) { Catalyst::Exception->throw("No logged in user, and none supplied as argument"); } my $gflag; # Global flag for all actions foreach (@actions) { my $lflag; # Local flag for one action foreach my $act ($user->actions) { # Check specific user abilities if ($act->name eq $_) { $lflag = 1; } } unless ($lflag) { # Check user abilities via roles foreach my $role ($user->user_roles) { foreach my $act ($role->actions) { if ($act->name eq $_) { $lflag = 1; } } } } if ($lflag) { # Action granted, set gflag to 1 temporarily $gflag = 1; } else { # Action not granted, undef gflag and exit loop undef $gflag; last; } } local $" = ", "; if ($gflag) { $c->log->debug("Ability granted: @actions") if $c->debug; return 1; } else { $c->log->debug("Ability denied: @actions") if $c->debug; Catalyst::Exception->throw("Missing abilities"); } } __PACKAGE__; __END__ =pod =head1 NAME Catalyst::Plugin::Authorization::Abilities - Ability based authorization for Catalyst based on Catalyst::Plugin::Authentication and Catalyst::Plugin::Authorization::Roles =head1 SYNOPSIS use Catalyst qw/ Authentication Authorization::Abilities /; sub delete : Local { my ( $self, $c ) = @_; $c->assert_user_ability( qw/delete_foo/ ); # check if the user can perform a certain action, such as delete_foo $c->model("Foo")->delete_all(); } =head1 DESCRIPTION Ability based access control is an extension of the role based access control available through L. In this plugin, however, every user has a list of actions he is allowed to perform, and every restricted part of the application makes an assertion about the necessary abilities. Abilities to perform certain actions can be given to a user specifically, or via roles the user can assume. For example, if user 'user01' is member of role 'admin', and this user wishes to perform some action, for example 'delete_foo', than they will only be able to do so if the 'delete_foo' ability was given to either the user itself or the 'admin' role itself. With C and C, these conditionals are checked to grant or deny the user access to the required action. This method of authorization allows for much more flexibility with regards to access control, such that roles and abilities can be added/edited/deleted using the application itself (Via your own controllers). This is useful for applications such as message boards, where the administrator might wish to create roles with certain actions and associate users with those roles. For example, the admin can create an 'editor' role, giving users of this role the ability to edit and delete posts, but not any other administrative action. Note that this plugin is not to be used in conjunction with L, and that it requires several tables to be present in the database/schema. =head1 METHODS =over 4 =item assert_user_ability [ $user ], @actions Checks that the user (as supplied by the first argument, or, if omitted, C<< $c->user >>) has the ability to perform specified actions. If for any reason (C<< $c->user >> is not defined, the user is missing the appropriate action/role, etc.) the check fails, an error is thrown. You can either catch these errors with an eval, or clean them up in your C action. =item check_user_ability [ $user ], @roles Takes the same args as C, and performs the same check, but instead of throwing errors returns a boolean value. =back =head1 SEE ALSO L L =head1 AUTHOR Ido Perelmutter Eido50@yahoo.comE =head1 COPYRIGHT & LICENSE Copyright (c) 2008 the aforementioned authors. This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut