File Coverage

blib/lib/Lemonldap/NG/Handler/Specific/AuthBasic.pm
Criterion Covered Total %
statement 4 6 66.6
branch n/a
condition n/a
subroutine 2 2 100.0
pod n/a
total 6 8 75.0


line stmt bran cond sub pod time code
1             ##@file
2             # Auth-basic authentication with Lemonldap::NG rights management
3              
4             ##@class
5             # Auth-basic authentication with Lemonldap::NG rights management
6              
7             # This specific handler is intended to be called directly by Apache
8              
9             package Lemonldap::NG::Handler::Specific::AuthBasic;
10              
11 1     1   1710 use strict;
  1         2  
  1         35  
12              
13 1     1   559 use Lemonldap::NG::Handler::SharedConf qw(:all);
  0            
  0            
14             use Digest::MD5 qw(md5_base64);
15             use MIME::Base64;
16             use HTTP::Headers;
17             use SOAP::Lite; # link protected portalRequest
18             use Lemonldap::NG::Handler::Main::Headers;
19             use Lemonldap::NG::Handler::Main::Logger;
20             use Lemonldap::NG::Common::Session;
21              
22             use base qw(Lemonldap::NG::Handler::SharedConf);
23             use utf8;
24             no utf8;
25              
26             our $VERSION = '1.4.1';
27              
28             # We need just this constant, that's why Portal is 'required' but not 'used'
29             *PE_OK = *Lemonldap::NG::Portal::SharedConf::PE_OK;
30              
31             # Apache constants
32             BEGIN {
33             if ( MP() == 2 ) {
34             *AUTH_REQUIRED = \&Apache2::Const::AUTH_REQUIRED;
35             require Apache2::Access;
36             }
37             elsif ( MP() == 0 ) {
38             eval 'sub AUTH_REQUIRED {1}';
39             }
40             }
41              
42             ## @rmethod int run(Apache2::RequestRec apacheRequest)
43             # overload run subroutine to implement Auth-Basic mechanism.
44             # @param $apacheRequest current request
45             # @return Apache constant
46             sub run ($$) {
47             my $class;
48             ( $class, $apacheRequest ) = splice @_;
49             if ( time() - $lastReload > $reloadTime ) {
50             unless ( my $tmp = $class->testConf(1) == OK ) {
51             Lemonldap::NG::Handler::Main::Logger->lmLog(
52             "$class: No configuration found", 'error' );
53             return $tmp;
54             }
55             }
56             return DECLINED unless ( $apacheRequest->is_initial_req );
57             my $uri = $apacheRequest->uri
58             . ( $apacheRequest->args ? "?" . $apacheRequest->args : "" );
59              
60             # AUTHENTICATION
61             # I - recover the WWW-Authentication header
62             my ( $id, $user, $pass );
63             unless (
64             $user = Lemonldap::NG::Handler::Main::Headers->lmHeaderIn(
65             $apacheRequest, 'Authorization'
66             )
67             )
68             {
69             Lemonldap::NG::Handler::Main::Headers->lmSetErrHeaderOut(
70             $apacheRequest,
71             'WWW-Authenticate' => 'Basic realm="LemonLDAP::NG"' );
72             return AUTH_REQUIRED;
73             }
74             $user =~ s/^Basic\s*//;
75              
76             # ID for local cache
77             $id = md5_base64($user);
78              
79             # II - recover the user datas
80             # 2.1 search if the user was the same as previous (very efficient in
81             # persistent connection).
82             unless ( $id eq $datas->{_cache_id} ) {
83              
84             # 2.2 search in the local cache if exists
85             my $session_id;
86             unless ($tsv->{refLocalStorage}
87             and $session_id = $tsv->{refLocalStorage}->get($id) )
88             {
89              
90             # 2.3 Authentication by Lemonldap::NG::Portal using SOAP request
91              
92             # Add client IP as X-Forwarded-For IP in SOAP request
93             my $xheader =
94             Lemonldap::NG::Handler::Main::Headers->lmHeaderIn( $apacheRequest,
95             'X-Forwarded-For' );
96             $xheader .= ", " if ($xheader);
97             $xheader .= $class->ip();
98             my $soapHeaders =
99             HTTP::Headers->new( "X-Forwarded-For" => $xheader );
100              
101             my $soap =
102             SOAP::Lite->proxy( $class->portal(),
103             default_headers => $soapHeaders )
104             ->uri('urn:Lemonldap::NG::Common::CGI::SOAPService');
105             $user = decode_base64($user);
106             ( $user, $pass ) = ( $user =~ /^(.*?):(.*)$/ );
107             Lemonldap::NG::Handler::Main::Logger->lmLog(
108             "AuthBasic authentication for user: $user", 'debug' );
109             my $r = $soap->getCookies( $user, $pass );
110              
111             # Catch SOAP errors
112             if ( $r->fault ) {
113             return $class->abort( "SOAP request to the portal failed: "
114             . $r->fault->{faultstring} );
115             }
116             else {
117             my $res = $r->result();
118              
119             # If authentication failed, display error
120             if ( $res->{errorCode} ) {
121             Lemonldap::NG::Handler::Main::Logger->lmLog(
122             "Authentication failed for $user: "
123             . $soap->error( $res->{errorCode}, 'en' )->result(),
124             'notice'
125             );
126             Lemonldap::NG::Handler::Main::Headers->lmSetErrHeaderOut(
127             $apacheRequest,
128             'WWW-Authenticate' => 'Basic realm="LemonLDAP::NG"' );
129             return AUTH_REQUIRED;
130             }
131             $session_id = $res->{cookies}->{ $tsv->{cookieName} };
132             }
133             }
134              
135             # Get the session
136             my $apacheSession = Lemonldap::NG::Common::Session->new(
137             {
138             storageModule => $tsv->{globalStorage},
139             storageModuleOptions => $tsv->{globalStorageOptions},
140             cacheModule => $tsv->{localSessionStorage},
141             cacheModuleOptions => $tsv->{localSessionStorageOptions},
142             id => $session_id,
143             kind => "SSO",
144             }
145             );
146              
147             if ( $apacheSession->error ) {
148             Lemonldap::NG::Handler::Main::Logger->lmLog(
149             "The cookie $session_id isn't yet available", 'info' );
150             Lemonldap::NG::Handler::Main::Logger->lmLog( $apacheSession->error,
151             'info' );
152             $class->updateStatus( $class->ip(), $apacheRequest->uri,
153             'EXPIRED' );
154             return $class->goToPortal($uri);
155             }
156              
157             $datas->{$_} = $apacheSession->data->{$_}
158             foreach ( keys %{ $apacheSession->data } );
159             $datas->{_cache_id} = $id;
160              
161             # Store now the user in the local storage
162             if ( $tsv->{refLocalStorage} ) {
163             $tsv->{refLocalStorage}
164             ->set( $id, $datas->{_session_id}, "20 minutes" );
165             }
166             }
167              
168             # ACCOUNTING
169             # 1 - Inform Apache
170             $class->lmSetApacheUser( $apacheRequest, $datas->{ $tsv->{whatToTrace} } );
171              
172             # AUTHORIZATION
173             return $class->forbidden($uri) unless ( $class->grant($uri) );
174             $class->updateStatus( $datas->{ $tsv->{whatToTrace} },
175             $apacheRequest->uri, 'OK' );
176             $class->logGranted( $uri, $datas );
177              
178             # SECURITY
179             # Hide Lemonldap::NG cookie
180             $class->hideCookie;
181              
182             # Hide user password
183             Lemonldap::NG::Handler::Main::Headers->lmUnsetHeaderIn( $apacheRequest,
184             "Authorization" );
185              
186             # ACCOUNTING
187             # 2 - Inform remote application
188             Lemonldap::NG::Handler::Main::Headers->sendHeaders( $apacheRequest,
189             $tsv->{forgeHeaders} );
190              
191             OK;
192             }
193              
194             __PACKAGE__->init( {} );
195              
196             1;
197              
198             __END__