File Coverage

blib/lib/PlugAuth/Role/Flat.pm
Criterion Covered Total %
statement 109 111 98.2
branch 26 34 76.4
condition 14 17 82.3
subroutine 19 19 100.0
pod 0 7 0.0
total 168 188 89.3


line stmt bran cond sub pod time code
1             package PlugAuth::Role::Flat;
2              
3 41     41   21778 use strict;
  41         128  
  41         1298  
4 41     41   261 use warnings;
  41         116  
  41         1108  
5 41     41   884 use 5.010001;
  41         182  
6 41     41   293 use Log::Log4perl qw( :easy );
  41         114  
  41         557  
7 41     41   45469 use File::stat qw( stat );
  41         149  
  41         509  
8 41     41   5299 use Fcntl qw( :flock );
  41         154  
  41         6696  
9 41     41   331 use Role::Tiny;
  41         118  
  41         317  
10 41     41   9610 use File::Temp ();
  41         128  
  41         925  
11 41     41   264 use File::Spec;
  41         111  
  41         1434  
12 41     41   5935 use File::Touch qw( touch );
  41         69163  
  41         31096  
13              
14             # ABSTRACT: private role used by L<FlatAuth|PlugAuth::Plugin::FlatAuth> and L<FlatAuthz|PlugAuth::Plugin::FlatAuthz>.
15             our $VERSION = '0.38'; # VERSION
16              
17             my %MTimes;
18              
19             sub has_changed {
20 2755     2755 0 27305 my $filename = shift;
21 2755 50       66003 -e $filename or LOGDIE "File $filename does not exist";
22 2755         13421 my $mtime = stat($filename)->mtime;
23 2755 100 66     622145 return 0 if $MTimes{$filename} && $MTimes{$filename}==$mtime;
24 257         1062 $MTimes{$filename} = $mtime;
25 257         1495 return 1;
26             }
27              
28             sub mark_changed {
29 192     192 0 5263 delete $MTimes{$_} for @_;
30             }
31              
32             sub read_file { # TODO: cache w/ mtime
33 259     259 0 3896 my($class, $filename, %args) = @_;
34 259   100     1379 $args{nest} ||= 0;
35             #
36             # _read_file:
37             # x : y
38             # z : q
39             # returns ( x => y, z => q )
40             #
41             # _read_file(nest => 1):
42             # a : b,c
43             # d : e,f
44             # returns ( x => { b => 1, c => 1 },
45             # d => { e => 1, f => 1 } )
46             #
47             # _read_file(nest => 2):
48             # a : (b) c,d
49             # a : (g) h,i
50             # d : (e) f,g
51             # returns ( a => { b => { c => 1, d => 1 },
52             # { g => { h => 1, i => 1 },
53             # d => { e => { f => 1, g => 1 } );
54             # Lines beginning with a # are ignored.
55             # All spaces are silently squashed.
56             #
57 259         1808 TRACE "reading $filename";
58 259         227875 my %h;
59 259         12011 open my $fh, '<', $filename;
60 259 50       2921 flock($fh, LOCK_SH) or WARN "Cannot lock $filename - $!\n";
61 259         9449 for my $line ($fh->getlines)
62             {
63 1123         17709 chomp $line;
64 1123         4573 $line =~ s/\s//g;
65 1123 100 100     5777 next if $line =~ /^#/ || !length($line);
66 629         2675 my ($k,$v) = split /:/, $line;
67 629         1352 my $p;
68             # commenting this out because it puts the password salt in
69             # the log file if TRACE is on
70             #TRACE "parsing $v";
71 629 100       2366 ($k,$p) = ( $k =~ m/^(.*)\(([^)]*)\)$/) if $args{nest}==2;
72 629 100       2112 $k = lc $k if $args{lc_keys};
73 629 100       1873 $v = lc $v if $args{lc_values};
74 629 100       2265 my %m = ( map { $_ => 1 } split /,/, $v ) if $args{nest};
  696         2489  
75 629 100       2668 if ($args{nest}==0)
    100          
    50          
76             {
77 208         822 $h{$k} = $v;
78             }
79             elsif ($args{nest}==1)
80             {
81 290   50     1981 $h{$k} ||= {};
82 290         936 @{ $h{$k} }{keys %m} = values %m;
  290         1355  
83             }
84             elsif ($args{nest}==2)
85             {
86 131   100     1134 $h{$k} ||= {};
87 131   100     1046 $h{$k}{$p} ||= {};
88 131         386 @{ $h{$k}{$p} }{keys %m} = values %m;
  131         690  
89             }
90             }
91 259         8652 return %h;
92             }
93              
94             sub temp_dir
95             {
96 84     84 0 182 state $dir;
97 84 100       278 unless(defined $dir)
98             {
99 14         129 $dir = File::Temp::tempdir( CLEANUP => 1);
100             }
101 84         10026 return $dir;
102             }
103              
104             sub flat_init
105             {
106 90     90 0 306 my($self) = @_;
107 90         463 my $config = $self->global_config;
108            
109 90         333 foreach my $file (qw( group_file resource_file user_file ))
110             {
111 270   66     1386 $config->{$file} //= do {
112 84         374 my $fn = File::Spec->catfile($self->temp_dir, $file);
113 84         664 WARN "$file not defined in configuration, using temp $fn, modifiations will be lost on exit";
114 84         128042 touch $fn;
115 84         22791 $fn;
116             };
117             }
118             }
119              
120             sub lock_and_update_file
121             {
122 41     41   465 use autodie;
  41         142  
  41         490  
123 126     126 0 588 my($self, $filename, $cb) = @_;
124              
125 126         303 my $buffer;
126            
127 126         326 eval {
128 126         1005 open my $fh, '+<', $filename;
129 126         81884 eval { flock $fh, LOCK_EX };
  126         795  
130 126 50       16582 WARN "cannot lock $filename - $@" if $@;
131            
132 126         618 $buffer = $cb->($fh);
133            
134 126 50       558 if(defined $buffer)
135             {
136 126         1014 TRACE "updating $filename";
137 126         155665 seek $fh, 0, 0;
138 126         22457 truncate $fh, 0;
139 126         117793 print $fh $buffer;
140             }
141            
142 126         769 mark_changed($filename);
143 126         613 close $fh;
144             };
145              
146 126 50       37857 if(my $error = $@)
147             {
148 0         0 ERROR "update $filename: $error";
149             }
150              
151 126         1026 return defined $buffer;
152             }
153              
154             sub lock_and_read_file
155             {
156 3     3 0 14 my($self, $filename, $cb) = @_;
157            
158 41     41   328784 use autodie;
  41         128  
  41         323  
159            
160 3         10 my $ok = eval {
161            
162 3         26 open my $fh, '<', $filename;
163 3         7053 eval { flock $fh, LOCK_SH };
  3         23  
164 3 50       1240 WARN "cannot lock $filename - $@" if $@;
165            
166 3         21 my $ret = $cb->($fh);
167            
168 3         29 close $fh;
169            
170 3         3187 $ret;
171             };
172            
173 3 50       26 if(my $error = $@)
174             {
175 0         0 ERROR "reading $filename: $error";
176             }
177            
178 3         20 $ok;
179             }
180              
181             1;
182              
183             __END__
184              
185             =pod
186              
187             =encoding UTF-8
188              
189             =head1 NAME
190              
191             PlugAuth::Role::Flat - private role used by L<FlatAuth|PlugAuth::Plugin::FlatAuth> and L<FlatAuthz|PlugAuth::Plugin::FlatAuthz>.
192              
193             =head1 VERSION
194              
195             version 0.38
196              
197             =head1 SEE ALSO
198              
199             L<PlugAuth>,
200             L<PlugAuth::Plugin::FlatAuth>,
201             L<PlugAuth::Plugin::FlatAuthz>,
202             L<PlugAuth::Guide::Plugin>
203              
204             =head1 AUTHOR
205              
206             Graham Ollis <gollis@sesda3.com>
207              
208             =head1 COPYRIGHT AND LICENSE
209              
210             This software is copyright (c) 2012 by NASA GSFC.
211              
212             This is free software; you can redistribute it and/or modify it under
213             the same terms as the Perl 5 programming language system itself.
214              
215             =cut