File Coverage

blib/lib/Catalyst/Plugin/Authorization/RoleAbilities.pm
Criterion Covered Total %
statement 32 32 100.0
branch 10 12 83.3
condition 5 6 83.3
subroutine 6 6 100.0
pod 2 2 100.0
total 55 58 94.8


line stmt bran cond sub pod time code
1             package Catalyst::Plugin::Authorization::RoleAbilities;
2              
3             # ABSTRACT: Ability based authorization for Catalyst (using only Roles)
4              
5 1     1   504608 use Moose;
  1         2  
  1         6  
6             extends 'Catalyst::Plugin::Authorization::Roles';
7              
8 1     1   4975 use Set::Object ();
  1         5745  
  1         18  
9 1     1   5 use Scalar::Util ();
  1         2  
  1         9  
10 1     1   402 use Catalyst::Exception ();
  1         138529  
  1         511  
11              
12             sub check_user_ability {
13 2     2 1 414 my ($c, @roles) = @_;
14 2         3 local $@;
15 2         3 eval { $c->assert_user_ability(@roles) };
  2         4  
16 2 100       114 return $@ ? 0 : 1;
17             }
18              
19             sub assert_user_ability {
20 9     9 1 8138 my ($c, @actions) = @_;
21              
22 9         9 my $user;
23              
24 9 100 66     35 if (Scalar::Util::blessed($actions[0]) && $actions[0]->isa("Catalyst::Authentication::User")) {
25              
26             # A user was supplied in the arguments
27 1         2 $user = shift @actions;
28             }
29              
30 9   100     29 $user ||= $c->user;
31              
32 9 100       43 Catalyst::Exception->throw("No logged in user, and none supplied as argument") unless $user;
33              
34 8         14 my $have = Set::Object->new(map { $_->name } $user->user_roles->search_related('role')->search_related('role_actions')->search_related('action'));
  24         212  
35 8         78 my $need = Set::Object->new(@actions);
36              
37 8 100       17 if ($have->superset($need)) {
38 4 50       48 $c->log->debug("Action granted: @actions") if $c->debug;
39 4         30 return 1;
40             } else {
41 4 50       40 $c->log->debug("Action denied: @actions") if $c->debug;
42 4         18 my @missing = $need->difference($have)->members;
43 4         104 Catalyst::Exception->throw("Missing actions: @missing");
44             }
45             }
46              
47             __PACKAGE__->meta->make_immutable;
48             1;
49              
50              
51             __END__
52             =pod
53              
54             =head1 NAME
55              
56             Catalyst::Plugin::Authorization::RoleAbilities - Ability based authorization for Catalyst (using only Roles)
57              
58             =head1 VERSION
59              
60             version 0.002
61              
62             =head1 SYNOPSIS
63              
64             use Catalyst qw/
65             Authentication
66             Authorization::RoleAbilities
67             /;
68              
69             sub delete : Local {
70             my ( $self, $c ) = @_;
71              
72             $c->assert_user_ability( qw/delete_user/ ); # only users with roles that can perform this action can delete
73              
74             $c->model("User")->delete_it();
75             }
76              
77             =head1 DESCRIPTION
78              
79             Ability based authorization allows more flexibility than role based authorization. Users can have roles, which then
80             have many actions associated. An action can be associated with several roles. With this you don't check whether a user
81             has specific roles, but instead whether the roles can perform specific actions.
82              
83             L<Catalyst::Plugin::Authorization::RoleAbilities> extends L<Catalyst::Plugin::Authorization::Roles> so every method of
84             L<Catalyst::Plugin::Authorization::Roles> still can be used.
85              
86             See L<SEE ALSO> for other authorization modules.
87              
88             =head1 METHODS
89              
90             =head2 assert_user_ability [ $user ], @actions
91              
92             Checks that the roles of the user (as supplied by the first argument, or, if omitted,
93             C<< $c->user >>) has the ability to perform specified actions.
94              
95             If for any reason (C<< $c->user >> is not defined, the user's roles are missing the
96             appropriate action, etc.) the check fails, an error is thrown.
97              
98             You can either catch these errors with an eval, or clean them up in your C<end>
99             action.
100              
101             =head2 check_user_ability [ $user ], @actions
102              
103             Takes the same args as C<assert_user_ability>, and performs the same check, but
104             instead of throwing errors returns a boolean value.
105              
106             =head1 REQUIRED TABLES
107              
108             =head2 Actions
109              
110             Table name: C<actions>
111              
112             Columns:
113              
114             =over 4
115              
116             =item *
117              
118             C<id>, as C<integer>, Primary Key
119              
120             =item *
121              
122             C<name>, as C<character varying> or C<text>
123              
124             =back
125              
126             =head2 Roles to Actions
127              
128             Table name: C<role_actions>
129              
130             Columns:
131              
132             =over 4
133              
134             =item *
135              
136             C<id>, as C<integer>, Primary Key
137              
138             =item *
139              
140             C<role_id>, as C<integer>, Foreign Key to C<roles.id>
141              
142             =item *
143              
144             C<action_id>, as C<integer>, Foreign Key to C<actions.id>
145              
146             =back
147              
148             =head1 SEE ALSO
149              
150             =over 4
151              
152             =item *
153              
154             L<Catalyst::Plugin::Authorization::Roles>
155              
156             =item *
157              
158             L<Catalyst::Plugin::Authorization::Abilities> - A more complex ability based authorization module
159              
160             =back
161              
162             =head1 AUTHOR
163              
164             Matthias Dietrich <perl@rainboxx.de>
165              
166             =head1 COPYRIGHT AND LICENSE
167              
168             This software is copyright (c) 2012 by Matthias Dietrich.
169              
170             This is free software; you can redistribute it and/or modify it under
171             the same terms as the Perl 5 programming language system itself.
172              
173             =cut
174