File Coverage

blib/lib/CGI/Authent.pm
Criterion Covered Total %
statement 23 49 46.9
branch 13 38 34.2
condition 6 27 22.2
subroutine 1 4 25.0
pod 0 3 0.0
total 43 121 35.5


line stmt bran cond sub pod time code
1             package CGI::Authent;
2             $VERSION='0.2.1';
3              
4             sub can_read {
5 0     0 0 0 foreach (@_) {
6 0 0       0 return undef unless (-r $_);
7             }
8 0         0 1;
9             }
10              
11             sub isbetween {
12 0     0 0 0 my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) =
13             localtime(time);
14 0         0 my ($h1,$m1,$h2,$m2) = $_[0] =~ /(\d+):(\d+)-(\d+):(\d+)/;
15              
16 0 0 0     0 my $res = (
      0        
17             ($h1<=$h2) ?
18             (
19             (
20             $h1 < $hour
21             or
22             ($h1 == $hour and $m1 <= $min)
23             )
24             and
25             (
26             $hour < $h2
27             or
28             ($hour == $h2 and $min <= $m2)
29             )
30             ) : (
31             (
32             $hour < $h2
33             or
34             ($h2 == $hour and $min <= $m2)
35             )
36             or
37             (
38             $h1 < $hour
39             or
40             ($hour == $h1 and $m1 <= $min)
41             )
42             )
43             );
44 0         0 $res;
45             }
46              
47             sub between ($) {
48 0 0   0 0 0 unless (isbetween(@_)) {
49 0         0 $header =~ s/401.*?\n/403 Forbidden\x0D\x0A/m;
50 0         0 $msg = <<"*END*";
51            
52             Temporarily forbidden
53            
54            

Temporarily forbidden

55             This resource is available only at $_[0]. Please come later.
56            
57            
58             *END*
59             }
60 0         0 return $res;
61             }
62              
63             sub import {
64 1 50   1   11 ($header,$msg) = ($ENV{PERLXS} eq 'PerlIS' ? "HTTP/1.0 401 Access Denied\r\n" : "Status: 401 Access Denied\r\n",<<'*END*');
65            
66             UnAuthentificated
67            
68            

UnAuthentificated

69             You have to provide a correct login&password to access this page!
70            
71            
72             *END*
73 1         2 shift @_;
74 1         2 my ($hash,$value,$test);
75 1 50       4 if (ref $_[0] eq 'HASH') {
76 0         0 $hash = shift @_;
77 0   0     0 $msg = (shift @_ or $msg);
78             } else {
79 1 50       5 if (@_ & 1) {
80 0   0     0 $msg = (pop @_ or $msg);
81             }
82 1         6 my %tmp = @_;
83 1         2 $hash = \%tmp;
84             }
85 1 50       5 eval {require 'CGI/Authent.config.pl';} unless %default;
  1         445  
86 1         5 foreach (keys %$hash) {@default{$_} = $hash->{$_}};
  0         0  
87 1         2 my $authent;
88 1         6 while (($_,$value) = each %default) {
89              
90 2 100 66     15 if ($_ eq 'NTLM' and $value) {
    50          
    0          
    0          
    0          
    0          
91 1         2 $header .= "WWW-Authenticate: NTLM\r\n";
92 1         4 $authent=1;
93             } elsif (/^Basic$/i) {
94 1 50 33     13 if ($value and !($value =~ '_default' or $value =~ 'IP')) {
      33        
95 0         0 $header .= qq{WWW-Authenticate: Basic realm="$value"\r\n}
96             } else {
97 1         3 $header .= qq{WWW-Authenticate: Basic realm="$ENV{LOCAL_ADDR}"\r\n}
98             }
99 1         6 $authent=1;
100             } elsif (/^Authent/i) {
101 0         0 $header .= 'WWW-Authenticate: '.join("\r\nWWW-Authenticate: ",split(/\r?\n/,$value))."\r\n";
102 0         0 $authent=1;
103             } elsif (/^msg$/i) {
104 0         0 $msg = $value;
105             } elsif (/^head/) {
106 0         0 $header .= $value;
107             } elsif (/^test$/i) {
108 0         0 $test = $value;
109             }
110             }
111 1 50       5 $header .= qq{WWW-Authenticate: Basic realm="$ENV{LOCAL_ADDR}"\r\n} unless $authent;
112 1         2 my $res;
113 1 50 33     8 if (ref $test eq 'CODE') {
    50          
114 0         0 $res = &$test
115             } elsif (!defined $test or $test =~ /^_default$/i) {
116 1 50 33     4 $res = 1 unless ($ENV{HTTP_HOST} and ! $ENV{REMOTE_USER})
117             } else {
118 0         0 $res = eval ($test);
119             }
120 1 50       1756 if (! $res) {
121 0           $header .= "Content-Type: text/html\r\n\r\n";
122 0           print $header,$msg;
123 0           exit;
124             }
125             }
126              
127             1;
128              
129             =head1 NAME
130              
131             CGI::Authent - request a HTTP authentification under specified conditions
132              
133             version 0.2.1
134              
135             =head1 SYNOPSIS
136              
137             use CGI::Authent Basic => 'The realm name', test => 'CGI::Authent::between "h:m-h:m"';
138              
139             =head1 DESCRIPTION
140              
141             Send the HTTP 401 UnAuthentified header if a condition (by default
142             "defined $ENV{REMOTE_USER}") fails. Since your script doesn't get the
143             password the user entered, you cannot use it as the only
144             authentification scheme. And it was not intended to work like this. You
145             have to find some other way to check the username/password pair.
146              
147             It was written primarily to overcome a bug in MS IIS/3.0.
148             IIS usualy sends a HTTP 401 response if it finds out that it cannot
149             access a file using the current users premissions
150             (IUSR_... or the login/password you entered),
151             but since IIS doesn't check the permissions to the script before launching
152             perl, you get an error message :
153              
154             CGI Error
155              
156             The specified CGI application misbehaved by not returning a complete set
157             of HTTP headers. The headers it did return are:
158              
159             Can't open perl script "...": Permission denied
160              
161             instead of a login/password dialog.
162              
163             So instead of restricting the permissions for the scripts,
164             you will add
165              
166             use CGI::Authent;
167              
168             at the very beginning of your scripts and update CGI/Authent.config.pl
169             to suggest your servers authentification method.
170              
171             The login/password pair your user will enter into the dialog /s?he/ will
172             get will be checked by the server and mapped to an account, so all
173             you have to do, if all authentified users are to be able to access
174             your script, is to check the system variable REMOTE_USER - the default test.
175              
176             If you want to restrict the access to a group of users you may
177             check whether the script as it runs has enough permissions
178             to access a file and then restrict the access to this file.
179              
180             use CGI::Authent {test => 'CGI::Authent::can_read "c:\\inetpub\\group1.lck"'}
181              
182             =head2 Ussage
183              
184             use CGI::Authent;
185             Use the default options as set in CGI/Authent.config.pl.
186             use CGI::Authent {options}, [$msg];
187             use CGI::Authent options, [$msg];
188             Replace the default options from CGI/Authent.congfig.pl, by the ones
189             presented here.
190              
191             =head2 Options
192              
193             NTLM => 1/0
194             Should we use/suggest NTLM authentification?
195            
196             Basic => ''/'IP'/'_default'/'the realm'
197             Should we use the Basic authentification?
198             '', 'IP' and '_default' both mean that the realm will
199             be the servers IP address, which is default for MS IIS.
200            
201             msg => 'the message that should be showed if the authentification fails'
202            
203             test => \&some_boolean_function / 'some perl code' / '_default'
204             / 'Authent::can_read "filename"' / 'Authent::between "h:m-h:m"'
205             The test that should be performed. You may use either a reference to
206             a function, or a string to be eval()uated. The string '_default' has
207             a special meaning, it gets translated to 'defined $ENV{REMOTE_USER}',
208             so it checks if the user was authentificated by the server.
209             If the function/expression returns a true value, the script runs,
210             otherwise the user gets asked for a login/password pair.
211              
212             header => 'Some: additional headers'
213             You may add some headers to the response that will be sent if the test fails.
214             You may add several headers either as
215             header => 'Header1\r\nHeader2'
216             or
217             header1 => 'Header1',
218             header2 => 'Header2'
219            
220             Authenticate => 'Additional authentification methods'
221             You may specify additional authentification methods here.
222             The string you specify will be prepended by 'WWW-Authenticate: ' and
223             added to the headers.
224             You may use the same methods for several methods as with headers.
225              
226             =head2 Tests
227              
228             The default test is 'defined $ENV{REMOTE_USER}' which only checks
229             whether the user entered any login/password pair that was accepted
230             by the server.
231              
232             Other predefined tests are :
233              
234             CGI::Authent::can_read $file[, $file2, ...]
235             Does the script have permissions to read the file(s)?
236            
237             CGI::Authent::isbetween 'h:m-h:m';
238             It the time in this range?
239              
240             CGI::Authent::between 'h:m-h:m';
241             It the time in this range? This version will disallow
242             access buring other times completely! No request for authentification,
243             just 403 Forbiden response!
244              
245              
246             You may of course combine several tests :
247              
248             test => 'CGI::Authent::can_read "c:\\inetpub\\group1.lck" and CGIAuthent::between '8:00-17:00'
249             or
250             CGI::Authent::can_read "c:\\inetpub\\group2.lck" and CGI::Authent::between '17:00-8:00'
251             '
252              
253             =head2 Other functions
254              
255             CGI::Authent::forbide [$message]
256             Send the "HTTP 403 Forbiden" response.
257              
258             CGI::Authent::login [$message]
259             Send the "HTTP 401 UnAuthentified" response.
260              
261             =head2 REMINDER
262              
263             CGI::Authent doesn't validate the passwords. It cannot even see them. It
264             just does a few tests and if the tests fail it sends to the user a
265             request for authentication. But it's the server's task to validate the
266             credentials passed by the browser.
267              
268             If you want for example to validate passwords against a database,
269             consult your servers documentation. You will probably have to install some filter or plugin.
270             It should be relatively easy to find such beasts on the net. I've written an ISAPI filter for this,
271             you may get it at http://jenda.krynicky.cz/authfilter.1.0.zip . Take it as an example, not as a solution!
272              
273             =head2 Guts
274              
275             All options are parsed and added to the headers before yout test runs,
276             so you may change the headers from it.
277              
278             The headers are in $CGI::Authent::header, the message is in $CGI::Authent::message.
279              
280             =head2 AUTHOR
281              
282             Jan Krynicky
283             7/26/1999
284              
285             =cut