File Coverage

blib/lib/CAS/Apache/Auth.pm
Criterion Covered Total %
statement 7 9 77.7
branch n/a
condition n/a
subroutine 3 3 100.0
pod n/a
total 10 12 83.3


line stmt bran cond sub pod time code
1             package CAS::Apache::Auth;
2              
3 1     1   5045 use warnings FATAL => 'all', NONFATAL => 'redefine';
  1         3  
  1         53  
4 1     1   6 use strict;
  1         2  
  1         58  
5              
6             =head1 NAME
7              
8             CAS::Apache::Auth - The great new CAS::Apache::Auth!
9              
10             =head1 VERSION
11              
12             Version 0.01
13              
14             =cut
15              
16             our $VERSION = '0.01';
17             #use Apache2::RequestRec ();
18             # use Apache2::RequestIO ();
19              
20             # AUTH_REQUIRED DECLINED DONE FORBIDDEN NOT_FOUND OK REDIRECT SERVER_ERROR
21 1     1   410 use Apache2::Const qw(OK AUTH_REQUIRED FORBIDDEN HTTP_UNAUTHORIZED);
  0            
  0            
22              
23             use Apache2::Access ();
24             use Apache2::RequestUtil ();
25             use base qw(CAS::Apache CAS);
26             use CGI ();
27             use Apache2::Response ();
28              
29             =head1 SYNOPSIS
30              
31             Quick summary of what the module does.
32              
33             Perhaps a little code snippet.
34              
35             use CAS::Apache::Auth;
36              
37             my $foo = CAS::Apache::Auth->new();
38             ...
39              
40             =head1 METHODS
41              
42             =head2 function1
43              
44             =cut
45              
46             sub new {
47             my $proto = shift;
48             my $class = ref($proto) || $proto;
49             my $self = $class->SUPER::new(@_);
50            
51             # now, db caching doesn't work well in mod_perl as is - generates a lot
52             # of 'Commands out of sync' errors
53             $self->{dbh} = undef;
54            
55             return $self;
56             } # new
57              
58              
59             # because this package doesn't cache the db connection itself, depending on
60             # ApACHE::DBI to do it, we need to have a local version of the dbh method to
61             # reconnect
62             sub dbh {
63             my $self = shift;
64             return &{$self->{cas_db_connect}};
65             } # dbh
66              
67              
68             sub authen {
69             my $self = shift;
70             my $r = shift;
71             my $user = shift || '';
72             my $password = shift || '';
73             $self->gripe("Apache::Auth::authen called");
74            
75             my $cookie_name = $self->client->{Cookie_Name};
76             my $cookies = my $session_key = undef;
77             $cookies = $r->headers_in->{Cookie} || '';
78             if ($cookies =~ /$cookie_name=(\w{32})/) {
79             $session_key = $1;
80             $self->gripe("User already logged in: $cookie_name=$session_key");
81             return OK;
82             } # if key, assume user logged in, let authz do the rest
83            
84             unless ($user && $password) {
85             my $base_cas_dir = $r->dir_config('CAS_BASE_URI') || '';
86             my $request = $r->unparsed_uri;
87             my $login = "/$base_cas_dir/public/login?return=$request";
88             $r->custom_response(AUTH_REQUIRED, $login);
89             $self->gripe("No username or password provided - send to login page: "
90             . $login);
91             return AUTH_REQUIRED;
92             } # if no username or password provided, send to login page
93            
94             my $rem_ip = $r->connection->remote_ip;
95            
96             warn "Authenticating: USERNAME => $user, PASSWORD => $password, IP => $rem_ip";
97             $session_key = $self->authenticate({USERNAME => $user,
98             PASSWORD => $password, IP => $rem_ip});
99            
100             unless (defined $session_key) {
101             # get messages and throw error - really this should go to custom page
102             my $messages = $self->messages;
103             $r->note_auth_failure;
104             $self->gripe("Authen failed: $messages");
105             return HTTP_UNAUTHORIZED;
106             } # unless authentication succeeded
107            
108             # we set the cookie in err headers in case of internal redirect
109             $r->err_headers_out->add('Set-Cookie' => "$cookie_name=$session_key; PATH=/");
110             $self->gripe("User autheticated, Set-Cookie $cookie_name=$session_key");
111            
112             $self->_clear_result;
113             return OK;
114             }
115              
116              
117             sub authz {
118             my $self = shift;
119             my $r = shift;
120             return OK unless $r->is_initial_req;
121            
122             my $base_dir = $r->dir_config('CAS_BASE_URI') || '';
123             my $request = $r->uri;
124             my $full_request = $r->unparsed_uri;
125             # what if it isn't under /public?!
126             my $login = "/$base_dir/public/login?return=$full_request";
127             $r->custom_response(AUTH_REQUIRED, $login);
128            
129             my $cookie_name = $self->client->{Cookie_Name};
130             my $cookies = $r->headers_in->{Cookie} || '';
131             $cookies =~ /$cookie_name=(\w{32})/;
132             my $session_key = $1 || '';
133             $self->gripe("cookies = $cookies");
134            
135             unless ($session_key) {
136             # check header in case initial auth/internal redirect
137             $session_key = $r->headers_out->{'Set-Cookie'};
138            
139             # need to check err_headers separately?
140            
141             if ($session_key) {
142             $session_key =~ /$cookie_name=(\w*)/;
143             $session_key = $1 || '';
144             } # must be first authz after authen
145            
146             else {
147             my $CGI = new CGI;
148             my %params = $CGI->Vars;
149             $session_key = $params{$cookie_name};
150             } # not internal redirect, get desperate and check CGI param?
151            
152             $self->gripe("cookie_name $cookie_name found $session_key.")
153             if $self->debug;
154            
155             unless ($session_key) {
156             $self->gripe("No cookie named $cookie_name found.");
157             return AUTH_REQUIRED;
158             } # if no session key, have user log in
159             } # if no cookie
160            
161             # Some s may be configured so that all files under that location
162             # need only to check against a single resource.
163             my $there_is_only_one = $r->dir_config('SinglePermissionTree') || 0;
164             if ($there_is_only_one) { $request = $base_dir }
165            
166             # And still other s may want to use only the top level file or
167             # subdirectory. This could be useful for handlers or pages that parse the
168             # remainder of the URL as arguments, or where the subdirectoires are all
169             # assigned to individual users, who own everything therein
170             my $down_one_only = $r->dir_config('OneStepOnly') || 0;
171             if ($down_one_only) {
172             $request =~ s{$base_dir(/[^/]+).+}{$base_dir$1};
173             } # filter out sub'directories'
174            
175             my $rem_ip = $r->connection->remote_ip;
176             warn "Authorizing: SESSION => $session_key, RESOURCE => $request, MASK => 8, IP => $rem_ip";
177             my $is_authorized = $self->authorize({SESSION => $session_key,
178             RESOURCE => $request, MASK => 8, IP => $rem_ip, DEBUG => 1});
179             $self->gripe("SESSION => $session_key, "
180             . "RESOURCE => $request, MASK => 8, IP => $rem_ip");
181            
182             unless (defined $is_authorized){
183             # Check if authorization indicates new authentication required (like
184             # if the session timed out
185             my $messages = $self->messages;
186             if ($self->response_is('AUTH_REQUIRED')) {
187             $r->err_headers_out->set('Set-Cookie' => "$cookie_name=; PATH=/");
188             $self->gripe("authorization returned AUTH_REQUIRED: $messages")
189             if $self->debug;
190             $self->_clear_result;
191             return AUTH_REQUIRED;
192             } # if authen needed
193            
194             $self->gripe("Authorization failed: $messages");
195             $self->_clear_result;
196             return FORBIDDEN;
197             }
198            
199             $self->_clear_result;
200             return OK;
201             } # authz
202              
203              
204              
205             =head1 AUTHOR
206              
207             Sean P. Quinlan, C<< >>
208              
209             =head1 BUGS
210              
211             Please report any bugs or feature requests to
212             C, or through the web interface at
213             L.
214             I will be notified, and then you'll automatically be notified of progress on
215             your bug as I make changes.
216              
217             =head1 SUPPORT
218              
219             You can find documentation for this module with the perldoc command.
220              
221             perldoc CAS::Apache
222              
223             You can also look for information at:
224              
225             =over 4
226              
227             =item * AnnoCPAN: Annotated CPAN documentation
228              
229             L
230              
231             =item * CPAN Ratings
232              
233             L
234              
235             =item * RT: CPAN's request tracker
236              
237             L
238              
239             =item * Search CPAN
240              
241             L
242              
243             =back
244              
245             =head1 ACKNOWLEDGEMENTS
246              
247             =head1 COPYRIGHT & LICENSE
248              
249             Copyright 2006 Sean P. Quinlan, all rights reserved.
250              
251             This program is free software; you can redistribute it and/or modify it
252             under the same terms as Perl itself.
253              
254             =cut
255              
256             1; # End of CAS::Apache::Auth