File Coverage

blib/lib/Data/LazyACL.pm
Criterion Covered Total %
statement 78 78 100.0
branch 25 28 89.2
condition n/a
subroutine 12 12 100.0
pod 8 8 100.0
total 123 126 97.6


line stmt bran cond sub pod time code
1             package Data::LazyACL;
2              
3 2     2   91679 use strict;
  2         5  
  2         74  
4 2     2   3530 use Math::BigInt;
  2         53354  
  2         14  
5 2     2   39242 use Carp;
  2         12  
  2         205  
6 2     2   12 use vars qw/$VERSION/;
  2         5  
  2         1686  
7              
8             $VERSION = '0.05';
9              
10             my $ADMIN_NUMBER = -1;
11              
12             sub new {
13 2     2 1 1427 my $class = shift;
14 2         5 my $s = {};
15              
16 2         9 bless $s , $class;
17             }
18              
19             sub get_all_access_keys {
20 1     1 1 4 my $s = shift;
21 1         8 return $s->{all_access_keys};
22             }
23              
24             sub set_all_access_keys {
25 3     3 1 21354 my $s = shift;
26 3         6 my $access_keys = shift;
27              
28 3         21 $s->{all_access_keys} = $access_keys ;
29              
30 3         8 my $digit = 1;
31 3         5 for my $access_key ( @{ $access_keys } ) {
  3         11  
32            
33 10005 100       19393 if( $access_key eq 'admin' ) {
34 1         37 croak q{You can not use reserved word 'admin' as access key.};
35             }
36            
37 10004         26410 $s->{access_key}{ $access_key } = $digit;
38 10004         12897 $digit++;
39             }
40 2         15 $s->{access_key}{admin} = $ADMIN_NUMBER;
41             }
42              
43             sub has_privilege {
44 9     9 1 3590 my $s = shift;
45 9         14 my $access_key = shift;
46              
47 9 50       30 return 0 unless defined $s->{token};
48             # admin
49 9 100       26 return 1 if $s->{token} eq $ADMIN_NUMBER ;
50              
51             # required admin
52 8 100       26 return 0 if $access_key eq 'admin';
53              
54 7         16 my $access_digit = $s->{access_key}{ $access_key } ;
55            
56 7 100       44 croak 'can not find access key [' . $access_key . ']' unless $access_digit;
57 6         176 my $acl = Math::BigInt->new( 2 );
58 6         229 $acl->bpow( $access_digit - 1 );
59 6 100       63521 return $acl->band( $s->{token} ) ? 1 : 0;
60             }
61              
62             sub set_token {
63 3     3 1 52 my $s = shift;
64 3         5 my $token = shift;
65 3         11 $s->{token} = $token ;
66             }
67              
68             sub generate_token {
69 3     3 1 17 my $s = shift;
70 3         6 my $access_keys = shift;
71            
72 3         23 my $acl = Math::BigInt->new();
73              
74 3         208 for my $access_key ( @{ $access_keys } ) {
  3         7  
75 6 100       748 return $ADMIN_NUMBER if $access_key eq 'admin';
76              
77 5         11 my $digit = $s->{access_key}{ $access_key } ;
78            
79 5 50       14 croak 'can not find access key [' . $access_key . ']' unless $digit;
80              
81 5         17 my $i = Math::BigInt->new( 2 );
82              
83 5         188 $acl->badd( $i->bpow( $digit -1 ) );
84             }
85 2         336 return $acl->numify();
86              
87             }
88              
89             sub retrieve_access_keys_for {
90 2     2 1 1524 my $s = shift;
91 2         5 my $token = shift;
92 2         4 my @access_keys = ();
93              
94 2 100       10 return ['admin'] if $token eq $ADMIN_NUMBER;
95              
96 1         2 foreach my $key ( keys %{ $s->{access_key} } ) {
  1         5  
97 4 100       268 next if $key eq 'admin';
98 3         11 my $mb = Math::BigInt->new('2');
99 3         86 my $digit = $s->{access_key}{ $key };
100              
101 3         8 $mb->bpow( $digit - 1 );
102            
103 3 100       401 if( $mb->band( $token ) ) {
104 2         352 push @access_keys , $key ;
105             }
106              
107             }
108              
109 1         4 return \@access_keys;
110             }
111              
112             sub retrieve_access_keys_in_hash_for {
113 1     1 1 1778 my $s = shift;
114 1         3 my $token = shift;
115 1         3 my $access_keys = {};
116              
117 1 50       6 return {admin => 1} if $token eq $ADMIN_NUMBER;
118              
119 1         2 foreach my $key ( keys %{ $s->{access_key} } ) {
  1         5  
120 4 100       205 next if $key eq 'admin';
121 3         9 my $mb = Math::BigInt->new('2');
122 3         85 my $digit = $s->{access_key}{ $key };
123              
124 3         9 $mb->bpow( $digit - 1 );
125            
126 3 100       392 if( $mb->band( $token ) ) {
127 2         345 $access_keys->{ $key } = 1;
128             }
129              
130             }
131 1         5 return $access_keys;
132             }
133             1;
134              
135             =head1 NAME
136              
137             Data::LazyACL - Simple and Easy Access Control List
138              
139             =head1 DESCRIPTION
140              
141             I am tired of having multiple flags or columns or whatever to implement Access
142             Control List , so I create this module.
143              
144             This module is simple and easy to use, a user only need to have a token
145             to check having access or not.
146              
147             =head1 SYNOPSYS
148              
149             my $acl = Data::LazyACL->new();
150             $acl->set_all_access_keys( [qw/edit insert view/]);
151              
152             my ( $edit , insert , view ) = $s->get_all_access_keys();
153              
154             # maybe you want to store this token into user record.
155             my $token = $acl->generate_token([qw/view insert/]);
156              
157             $acl->set_token( $token );
158              
159             if ( $acl->has_privilege( 'view' ) ) {
160             print "You can view me!!\n";
161             }
162              
163             if ( $acl->has_privilege( 'edit' ) ) {
164             print "Never Dispaly\n";
165             }
166            
167             my $access_keys_ref
168             = $acl->retrieve_access_keys_for( $token );
169            
170             my $access_keys_hash_ref
171             = $acl->retrieve_access_keys_in_hash_for( $token );
172              
173             =head1 METHODS
174              
175             =head2 new()
176              
177             Constractor.
178              
179             =head2 set_all_access_keys( \@access_keys )
180              
181             Set all access keys. You can never change this array of order once you
182             generate token , otherwise you will messup permissins. When you want to add new keys then just append.
183              
184             =head2 $token = generate_token( \@user_access_keys )
185              
186             Generate token. You may want to save this token for per user.
187              
188             =head2 \@access_keys = get_all_access_keys()
189              
190             Get access keys which you set with set_all_access_keys() .. means not include
191             'admin'.
192              
193             =head2 set_token( $token )
194              
195             You need to set $token to use has_privilege() method. the has_privilege()
196             method check privilege based on this token.
197              
198             If you want to have all access then use reserve keyword 'admin' .
199              
200             my $admin_token = $acl->set_token( 'admin' );
201              
202             =head2 has_privilege( $access_key )
203              
204             check having privilege or not for the access_key.
205              
206             =head2 $keys_ref = retrieve_access_keys_for( $token )
207              
208             Get access keys array ref for a token.
209              
210             =head2 $keys_hash_ref = retrieve_access_keys_in_hash_for( $token )
211              
212             Get access keys as hash key. value is 1.
213              
214             =head1 Token can be big number
215              
216             Token can be big number when you add a lot of access keys, so I suggest
217             you treat Token as String not Integer when you want to store it into database.
218              
219             =head1 AUTHOR
220              
221             Tomohiro Teranishi
222              
223             =head1 COPYRIGHT
224              
225             This program is free software. you can redistribute it and/or modify it under
226             the same terms as Perl itself.
227              
228             =cut