| 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 |  | 2093 | use strict; | 
|  | 1 |  |  |  |  | 3 |  | 
|  | 1 |  |  |  |  | 53 |  | 
| 12 |  |  |  |  |  |  |  | 
| 13 | 1 |  |  | 1 |  | 576 | 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__ |