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   23759 use strict;
  41         99  
  41         1645  
4 41     41   213 use warnings;
  41         71  
  41         1309  
5 41     41   947 use 5.010001;
  41         134  
6 41     41   253 use Log::Log4perl qw( :easy );
  41         62  
  41         565  
7 41     41   33061 use File::stat qw( stat );
  41         50070  
  41         457  
8 41     41   4309 use Fcntl qw( :flock );
  41         97  
  41         7068  
9 41     41   280 use Role::Tiny;
  41         106  
  41         289  
10 41     41   7263 use File::Temp ();
  41         80  
  41         870  
11 41     41   180 use File::Spec;
  41         108  
  41         1497  
12 41     41   7099 use File::Touch qw( touch );
  41         67906  
  41         32246  
13              
14             # ABSTRACT: private role used by L<FlatAuth|PlugAuth::Plugin::FlatAuth> and L<FlatAuthz|PlugAuth::Plugin::FlatAuthz>.
15             our $VERSION = '0.35'; # VERSION
16              
17             my %MTimes;
18              
19             sub has_changed {
20 2755     2755 0 15425 my $filename = shift;
21 2755 50       65941 -e $filename or LOGDIE "File $filename does not exist";
22 2755         9164 my $mtime = stat($filename)->mtime;
23 2755 100 66     409512 return 0 if $MTimes{$filename} && $MTimes{$filename}==$mtime;
24 257         716 $MTimes{$filename} = $mtime;
25 257         1334 return 1;
26             }
27              
28             sub mark_changed {
29 192     192 0 2308 delete $MTimes{$_} for @_;
30             }
31              
32             sub read_file { # TODO: cache w/ mtime
33 259     259 0 3774 my($class, $filename, %args) = @_;
34 259   100     1059 $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         1272 TRACE "reading $filename";
58 259         111746 my %h;
59 259         11167 open my $fh, '<', $filename;
60 259 50       1981 flock($fh, LOCK_SH) or WARN "Cannot lock $filename - $!\n";
61 259         9075 for my $line ($fh->getlines)
62             {
63 1123         14317 chomp $line;
64 1123         3176 $line =~ s/\s//g;
65 1123 100 100     4965 next if $line =~ /^#/ || !length($line);
66 629         1888 my ($k,$v) = split /:/, $line;
67 629         946 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       1882 ($k,$p) = ( $k =~ m/^(.*)\(([^)]*)\)$/) if $args{nest}==2;
72 629 100       1548 $k = lc $k if $args{lc_keys};
73 629 100       1447 $v = lc $v if $args{lc_values};
74 629 100       1676 my %m = ( map { $_ => 1 } split /,/, $v ) if $args{nest};
  696         1714  
75 629 100       1989 if ($args{nest}==0)
    100          
    50          
76             {
77 208         502 $h{$k} = $v;
78             }
79             elsif ($args{nest}==1)
80             {
81 290   50     1364 $h{$k} ||= {};
82 290         625 @{ $h{$k} }{keys %m} = values %m;
  290         1068  
83             }
84             elsif ($args{nest}==2)
85             {
86 131   100     654 $h{$k} ||= {};
87 131   100     637 $h{$k}{$p} ||= {};
88 131         287 @{ $h{$k}{$p} }{keys %m} = values %m;
  131         530  
89             }
90             }
91 259         7791 return %h;
92             }
93              
94             sub temp_dir
95             {
96 84     84 0 100 state $dir;
97 84 100       205 unless(defined $dir)
98             {
99 14         92 $dir = File::Temp::tempdir( CLEANUP => 1);
100             }
101 84         8308 return $dir;
102             }
103              
104             sub flat_init
105             {
106 90     90 0 213 my($self) = @_;
107 90         516 my $config = $self->global_config;
108            
109 90         312 foreach my $file (qw( group_file resource_file user_file ))
110             {
111 270   66     1199 $config->{$file} //= do {
112 84         267 my $fn = File::Spec->catfile($self->temp_dir, $file);
113 84         485 WARN "$file not defined in configuration, using temp $fn, modifiations will be lost on exit";
114 84         38667 touch $fn;
115 84         16627 $fn;
116             };
117             }
118             }
119              
120             sub lock_and_update_file
121             {
122 41     41   417 use autodie;
  41         83  
  41         476  
123 126     126 0 293 my($self, $filename, $cb) = @_;
124              
125 126         184 my $buffer;
126            
127 126         260 eval {
128 126         701 open my $fh, '+<', $filename;
129 126         64478 eval { flock $fh, LOCK_EX };
  126         643  
130 126 50       13055 WARN "cannot lock $filename - $@" if $@;
131            
132 126         584 $buffer = $cb->($fh);
133            
134 126 50       442 if(defined $buffer)
135             {
136 126         763 TRACE "updating $filename";
137 126         49084 seek $fh, 0, 0;
138 126         17855 truncate $fh, 0;
139 126         108926 print $fh $buffer;
140             }
141            
142 126         499 mark_changed($filename);
143 126         501 close $fh;
144             };
145              
146 126 50       32057 if(my $error = $@)
147             {
148 0         0 ERROR "update $filename: $error";
149             }
150              
151 126         725 return defined $buffer;
152             }
153              
154             sub lock_and_read_file
155             {
156 3     3 0 8 my($self, $filename, $cb) = @_;
157            
158 41     41   228788 use autodie;
  41         80  
  41         244  
159            
160 3         7 my $ok = eval {
161            
162 3         20 open my $fh, '<', $filename;
163 3         5417 eval { flock $fh, LOCK_SH };
  3         18  
164 3 50       970 WARN "cannot lock $filename - $@" if $@;
165            
166 3         15 my $ret = $cb->($fh);
167            
168 3         19 close $fh;
169            
170 3         2520 $ret;
171             };
172            
173 3 50       16 if(my $error = $@)
174             {
175 0         0 ERROR "reading $filename: $error";
176             }
177            
178 3         14 $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.35
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