| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | ## @file | 
| 2 |  |  |  |  |  |  | # Base file for Lemonldap::NG handlers | 
| 3 |  |  |  |  |  |  |  | 
| 4 |  |  |  |  |  |  | ## @class | 
| 5 |  |  |  |  |  |  | # Base class for Lemonldap::NG handlers. | 
| 6 |  |  |  |  |  |  | # All methods in handler are class methods: in ModPerl environment, handlers | 
| 7 |  |  |  |  |  |  | # are always launched without object created. | 
| 8 |  |  |  |  |  |  | # | 
| 9 |  |  |  |  |  |  | # The main method is run() who is called by Apache for each requests (using | 
| 10 |  |  |  |  |  |  | # handler() wrapper). | 
| 11 |  |  |  |  |  |  | # | 
| 12 |  |  |  |  |  |  | # The main initialization subroutine is init() who launch localInit() and | 
| 13 |  |  |  |  |  |  | # globalInit(). | 
| 14 |  |  |  |  |  |  | package Lemonldap::NG::Handler::Main; | 
| 15 |  |  |  |  |  |  |  | 
| 16 |  |  |  |  |  |  | #use strict; | 
| 17 |  |  |  |  |  |  |  | 
| 18 | 8 |  |  | 8 |  | 23609 | use MIME::Base64; | 
|  | 8 |  |  |  |  | 5486 |  | 
|  | 8 |  |  |  |  | 537 |  | 
| 19 | 8 |  |  | 8 |  | 46 | use Exporter 'import'; | 
|  | 8 |  |  |  |  | 13 |  | 
|  | 8 |  |  |  |  | 225 |  | 
| 20 |  |  |  |  |  |  |  | 
| 21 |  |  |  |  |  |  | #use AutoLoader 'AUTOLOAD'; | 
| 22 | 8 |  |  | 8 |  | 1962 | use Lemonldap::NG::Common::Crypto; | 
|  | 0 |  |  |  |  |  |  | 
|  | 0 |  |  |  |  |  |  | 
| 23 |  |  |  |  |  |  | use Lemonldap::NG::Common::Session; | 
| 24 |  |  |  |  |  |  | require POSIX; | 
| 25 |  |  |  |  |  |  | use CGI::Util 'expires'; | 
| 26 |  |  |  |  |  |  | use constant UNPROTECT        => 1; | 
| 27 |  |  |  |  |  |  | use constant SKIP             => 2; | 
| 28 |  |  |  |  |  |  | use constant MAINTENANCE_CODE => 503; | 
| 29 |  |  |  |  |  |  |  | 
| 30 |  |  |  |  |  |  | #inherits Cache::Cache | 
| 31 |  |  |  |  |  |  | #inherits Apache::Session | 
| 32 |  |  |  |  |  |  | #link Lemonldap::NG::Common::Apache::Session::SOAP protected globalStorage | 
| 33 |  |  |  |  |  |  |  | 
| 34 |  |  |  |  |  |  | our $VERSION = '1.4.1'; | 
| 35 |  |  |  |  |  |  |  | 
| 36 |  |  |  |  |  |  | our %EXPORT_TAGS; | 
| 37 |  |  |  |  |  |  |  | 
| 38 |  |  |  |  |  |  | our @EXPORT_OK; | 
| 39 |  |  |  |  |  |  |  | 
| 40 |  |  |  |  |  |  | our @EXPORT; | 
| 41 |  |  |  |  |  |  |  | 
| 42 |  |  |  |  |  |  | # my @tSharedVar = qw( | 
| 43 |  |  |  |  |  |  | #     cookieName           customFunctions        defaultCondition | 
| 44 |  |  |  |  |  |  | #     defaultProtection    forgeHeaders           globalStorage | 
| 45 |  |  |  |  |  |  | #     globalStorageOptions headerList             https | 
| 46 |  |  |  |  |  |  | #     key                  localStorage           localStorageOptions | 
| 47 |  |  |  |  |  |  | #     locationCondition    locationConditionText  locationCount | 
| 48 |  |  |  |  |  |  | #     locationProtection   locationRegexp         maintenance | 
| 49 |  |  |  |  |  |  | #     port                 refLocalStorage        securedCookie | 
| 50 |  |  |  |  |  |  | #     statusOut            statusPipe             timeoutActivity | 
| 51 |  |  |  |  |  |  | #     useRedirectOnError   useRedirectOnForbidden useSafeJail | 
| 52 |  |  |  |  |  |  | #     whatToTrace | 
| 53 |  |  |  |  |  |  | # ); | 
| 54 |  |  |  |  |  |  | # | 
| 55 |  |  |  |  |  |  | # my @nontSharedVar = qw( | 
| 56 |  |  |  |  |  |  | #     safe | 
| 57 |  |  |  |  |  |  | #     cipher               datasUpdate            transform | 
| 58 |  |  |  |  |  |  | #     cda                  childInitDone          httpOnly | 
| 59 |  |  |  |  |  |  | #     cookieExpiration | 
| 60 |  |  |  |  |  |  | # ); | 
| 61 |  |  |  |  |  |  | # | 
| 62 |  |  |  |  |  |  | # non threaded shared vars non being part of $ntsv hashref | 
| 63 |  |  |  |  |  |  | # (because of share_from in Jail.pm): | 
| 64 |  |  |  |  |  |  | # $apacheRequest | 
| 65 |  |  |  |  |  |  | # $datas | 
| 66 |  |  |  |  |  |  |  | 
| 67 |  |  |  |  |  |  | # Shared variables | 
| 68 |  |  |  |  |  |  | our ( $apacheRequest, $datas, $tsv, $ntsv, ); | 
| 69 |  |  |  |  |  |  |  | 
| 70 |  |  |  |  |  |  | ########################################## | 
| 71 |  |  |  |  |  |  | # COMPATIBILITY WITH APACHE AND APACHE 2 # | 
| 72 |  |  |  |  |  |  | ########################################## | 
| 73 |  |  |  |  |  |  |  | 
| 74 |  |  |  |  |  |  | BEGIN { | 
| 75 |  |  |  |  |  |  |  | 
| 76 |  |  |  |  |  |  | # globalStorage and locationRules are set for Manager compatibility only | 
| 77 |  |  |  |  |  |  | %EXPORT_TAGS = ( | 
| 78 |  |  |  |  |  |  | globalStorage  => [qw(  )], | 
| 79 |  |  |  |  |  |  | locationRules  => [qw( )], | 
| 80 |  |  |  |  |  |  | jailSharedVars => [qw( $apacheRequest $datas )], | 
| 81 |  |  |  |  |  |  | tsv            => [qw( $tsv )], | 
| 82 |  |  |  |  |  |  | ntsv           => [qw( $ntsv )], | 
| 83 |  |  |  |  |  |  | import         => [qw( import @EXPORT_OK @EXPORT %EXPORT_TAGS )], | 
| 84 |  |  |  |  |  |  | headers        => [ | 
| 85 |  |  |  |  |  |  | qw( | 
| 86 |  |  |  |  |  |  | lmHeaderIn lmSetHeaderIn lmHeaderOut | 
| 87 |  |  |  |  |  |  | lmSetHeaderOut lmSetErrHeaderOut | 
| 88 |  |  |  |  |  |  | ) | 
| 89 |  |  |  |  |  |  | ], | 
| 90 |  |  |  |  |  |  | apache => [ | 
| 91 |  |  |  |  |  |  | qw( MP OK REDIRECT FORBIDDEN DONE DECLINED SERVER_ERROR | 
| 92 |  |  |  |  |  |  | ) | 
| 93 |  |  |  |  |  |  | ], | 
| 94 |  |  |  |  |  |  | post => [qw(postFilter)], | 
| 95 |  |  |  |  |  |  | ); | 
| 96 |  |  |  |  |  |  | push( @EXPORT_OK, @{ $EXPORT_TAGS{$_} } ) foreach ( keys %EXPORT_TAGS ); | 
| 97 |  |  |  |  |  |  | $EXPORT_TAGS{all} = \@EXPORT_OK; | 
| 98 |  |  |  |  |  |  | if ( exists $ENV{MOD_PERL} ) { | 
| 99 |  |  |  |  |  |  | if ( $ENV{MOD_PERL_API_VERSION} and $ENV{MOD_PERL_API_VERSION} >= 2 ) { | 
| 100 |  |  |  |  |  |  | eval 'use constant MP => 2;'; | 
| 101 |  |  |  |  |  |  | } | 
| 102 |  |  |  |  |  |  | else { | 
| 103 |  |  |  |  |  |  | eval 'use constant MP => 1;'; | 
| 104 |  |  |  |  |  |  | } | 
| 105 |  |  |  |  |  |  | } | 
| 106 |  |  |  |  |  |  | else { | 
| 107 |  |  |  |  |  |  | eval 'use constant MP => 0;'; | 
| 108 |  |  |  |  |  |  | } | 
| 109 |  |  |  |  |  |  | if ( MP() == 2 ) { | 
| 110 |  |  |  |  |  |  | require Apache2::Log; | 
| 111 |  |  |  |  |  |  | require Apache2::RequestUtil; | 
| 112 |  |  |  |  |  |  | Apache2::RequestUtil->import(); | 
| 113 |  |  |  |  |  |  | require Apache2::RequestRec; | 
| 114 |  |  |  |  |  |  | Apache2::RequestRec->import(); | 
| 115 |  |  |  |  |  |  | require Apache2::ServerUtil; | 
| 116 |  |  |  |  |  |  | Apache2::ServerUtil->import(); | 
| 117 |  |  |  |  |  |  | require Apache2::Connection; | 
| 118 |  |  |  |  |  |  | Apache2::Connection->import(); | 
| 119 |  |  |  |  |  |  | require Apache2::RequestIO; | 
| 120 |  |  |  |  |  |  | Apache2::RequestIO->import(); | 
| 121 |  |  |  |  |  |  | require APR::Table; | 
| 122 |  |  |  |  |  |  | APR::Table->import(); | 
| 123 |  |  |  |  |  |  | require Apache2::URI; | 
| 124 |  |  |  |  |  |  | Apache2::URI->import(); | 
| 125 |  |  |  |  |  |  | require Apache2::Const; | 
| 126 |  |  |  |  |  |  | Apache2::Const->import( '-compile', qw(:common :log) ); | 
| 127 |  |  |  |  |  |  | eval ' | 
| 128 |  |  |  |  |  |  | use constant FORBIDDEN    => Apache2::Const::FORBIDDEN; | 
| 129 |  |  |  |  |  |  | use constant REDIRECT     => Apache2::Const::REDIRECT; | 
| 130 |  |  |  |  |  |  | use constant OK           => Apache2::Const::OK; | 
| 131 |  |  |  |  |  |  | use constant DECLINED     => Apache2::Const::DECLINED; | 
| 132 |  |  |  |  |  |  | use constant DONE         => Apache2::Const::DONE; | 
| 133 |  |  |  |  |  |  | use constant SERVER_ERROR => Apache2::Const::SERVER_ERROR; | 
| 134 |  |  |  |  |  |  | '; | 
| 135 |  |  |  |  |  |  | eval { | 
| 136 |  |  |  |  |  |  | require threads::shared; | 
| 137 |  |  |  |  |  |  | threads::shared::share($tsv); | 
| 138 |  |  |  |  |  |  | }; | 
| 139 |  |  |  |  |  |  | print "eval error: $@" if ($@); | 
| 140 |  |  |  |  |  |  | } | 
| 141 |  |  |  |  |  |  | elsif ( MP() == 1 ) { | 
| 142 |  |  |  |  |  |  | require Apache; | 
| 143 |  |  |  |  |  |  | require Apache::Log; | 
| 144 |  |  |  |  |  |  | require Apache::Constants; | 
| 145 |  |  |  |  |  |  | Apache::Constants->import(':common'); | 
| 146 |  |  |  |  |  |  | Apache::Constants->import(':response'); | 
| 147 |  |  |  |  |  |  | } | 
| 148 |  |  |  |  |  |  | else {    # For Test or CGI | 
| 149 |  |  |  |  |  |  | eval ' | 
| 150 |  |  |  |  |  |  | use constant FORBIDDEN    => 1; | 
| 151 |  |  |  |  |  |  | use constant REDIRECT     => 1; | 
| 152 |  |  |  |  |  |  | use constant OK           => 1; | 
| 153 |  |  |  |  |  |  | use constant DECLINED     => 1; | 
| 154 |  |  |  |  |  |  | use constant DONE         => 1; | 
| 155 |  |  |  |  |  |  | use constant SERVER_ERROR => 1; | 
| 156 |  |  |  |  |  |  | '; | 
| 157 |  |  |  |  |  |  | } | 
| 158 |  |  |  |  |  |  | *handler = ( MP() == 2 ) ? \&handler_mp2 : \&handler_mp1; | 
| 159 |  |  |  |  |  |  | *logout  = ( MP() == 2 ) ? \&logout_mp2  : \&logout_mp1; | 
| 160 |  |  |  |  |  |  | } | 
| 161 |  |  |  |  |  |  |  | 
| 162 |  |  |  |  |  |  | use Lemonldap::NG::Handler::Initialization::LocalInit; | 
| 163 |  |  |  |  |  |  | use Lemonldap::NG::Handler::Initialization::GlobalInit; | 
| 164 |  |  |  |  |  |  | use Lemonldap::NG::Handler::Main::Jail; | 
| 165 |  |  |  |  |  |  | use Lemonldap::NG::Handler::Main::Headers; | 
| 166 |  |  |  |  |  |  | use Lemonldap::NG::Handler::Main::PostForm; | 
| 167 |  |  |  |  |  |  | use Lemonldap::NG::Handler::Main::Logger; | 
| 168 |  |  |  |  |  |  |  | 
| 169 |  |  |  |  |  |  | ## @rmethod protected int handler_mp2() | 
| 170 |  |  |  |  |  |  | # Launch run() when used under mod_perl version 2 | 
| 171 |  |  |  |  |  |  | # @return Apache constant | 
| 172 |  |  |  |  |  |  | sub handler_mp2 : method { | 
| 173 |  |  |  |  |  |  | shift->run(@_); | 
| 174 |  |  |  |  |  |  | } | 
| 175 |  |  |  |  |  |  |  | 
| 176 |  |  |  |  |  |  | ## @rmethod protected int logout_mp2() | 
| 177 |  |  |  |  |  |  | # Launch unlog() when used under mod_perl version 2 | 
| 178 |  |  |  |  |  |  | # @return Apache constant | 
| 179 |  |  |  |  |  |  | sub logout_mp2 : method { | 
| 180 |  |  |  |  |  |  | shift->unlog(@_); | 
| 181 |  |  |  |  |  |  | } | 
| 182 |  |  |  |  |  |  |  | 
| 183 |  |  |  |  |  |  | ## @rmethod protected void lmSetApacheUser(Apache2::RequestRec r,string s) | 
| 184 |  |  |  |  |  |  | # Inform Apache for the data to use as user for logs | 
| 185 |  |  |  |  |  |  | # @param $r current request | 
| 186 |  |  |  |  |  |  | # @param $s string to use | 
| 187 |  |  |  |  |  |  | sub lmSetApacheUser { | 
| 188 |  |  |  |  |  |  | my ( $class, $r, $s ) = splice @_; | 
| 189 |  |  |  |  |  |  | return unless ($s); | 
| 190 |  |  |  |  |  |  | if ( MP() == 2 ) { | 
| 191 |  |  |  |  |  |  | $r->user($s); | 
| 192 |  |  |  |  |  |  | } | 
| 193 |  |  |  |  |  |  | else { | 
| 194 |  |  |  |  |  |  | $r->connection->user($s); | 
| 195 |  |  |  |  |  |  | } | 
| 196 |  |  |  |  |  |  | } | 
| 197 |  |  |  |  |  |  |  | 
| 198 |  |  |  |  |  |  | ## @rmethod protected void updateStatus(string user,string url,string action) | 
| 199 |  |  |  |  |  |  | # Inform the status process of the result of the request if it is available. | 
| 200 |  |  |  |  |  |  | sub updateStatus { | 
| 201 |  |  |  |  |  |  | my ( $class, $user, $url, $action ) = splice @_; | 
| 202 |  |  |  |  |  |  | my $statusPipe = $tsv->{statusPipe}; | 
| 203 |  |  |  |  |  |  | eval { | 
| 204 |  |  |  |  |  |  | print $statusPipe "$user => " | 
| 205 |  |  |  |  |  |  | . $apacheRequest->hostname | 
| 206 |  |  |  |  |  |  | . "$url $action\n" | 
| 207 |  |  |  |  |  |  | if ($statusPipe); | 
| 208 |  |  |  |  |  |  | }; | 
| 209 |  |  |  |  |  |  | } | 
| 210 |  |  |  |  |  |  |  | 
| 211 |  |  |  |  |  |  | ## @rmethod protected int forbidden(string uri) | 
| 212 |  |  |  |  |  |  | # Used to reject non authorized requests. | 
| 213 |  |  |  |  |  |  | # Inform the status processus and call logForbidden(). | 
| 214 |  |  |  |  |  |  | # @param uri URI requested | 
| 215 |  |  |  |  |  |  | # @return Apache2::Const::REDIRECT or Apache2::Const::FORBIDDEN | 
| 216 |  |  |  |  |  |  | sub forbidden { | 
| 217 |  |  |  |  |  |  | my ( $class, $uri ) = splice @_; | 
| 218 |  |  |  |  |  |  | if ( $datas->{_logout} ) { | 
| 219 |  |  |  |  |  |  | $class->updateStatus( $datas->{ $tsv->{whatToTrace} }, $_[0], | 
| 220 |  |  |  |  |  |  | 'LOGOUT' ); | 
| 221 |  |  |  |  |  |  | my $u = $datas->{_logout}; | 
| 222 |  |  |  |  |  |  | $class->localUnlog; | 
| 223 |  |  |  |  |  |  | return $class->goToPortal( $u, 'logout=1' ); | 
| 224 |  |  |  |  |  |  | } | 
| 225 |  |  |  |  |  |  | $class->updateStatus( $datas->{ $tsv->{whatToTrace} }, $_[0], 'REJECT' ); | 
| 226 |  |  |  |  |  |  | $apacheRequest->push_handlers( | 
| 227 |  |  |  |  |  |  | PerlLogHandler => sub { | 
| 228 |  |  |  |  |  |  | $_[0]->status(FORBIDDEN); | 
| 229 |  |  |  |  |  |  | $class->logForbidden( $uri, $datas ); | 
| 230 |  |  |  |  |  |  | DECLINED; | 
| 231 |  |  |  |  |  |  | } | 
| 232 |  |  |  |  |  |  | ); | 
| 233 |  |  |  |  |  |  |  | 
| 234 |  |  |  |  |  |  | # Redirect or Forbidden? | 
| 235 |  |  |  |  |  |  | if ( $tsv->{useRedirectOnForbidden} ) { | 
| 236 |  |  |  |  |  |  | Lemonldap::NG::Handler::Main::Logger->lmLog( | 
| 237 |  |  |  |  |  |  | "Use redirect for forbidden access", 'debug' ); | 
| 238 |  |  |  |  |  |  | return $class->goToPortal( $uri, 'lmError=403' ); | 
| 239 |  |  |  |  |  |  | } | 
| 240 |  |  |  |  |  |  | else { | 
| 241 |  |  |  |  |  |  | Lemonldap::NG::Handler::Main::Logger->lmLog( "Return forbidden access", | 
| 242 |  |  |  |  |  |  | 'debug' ); | 
| 243 |  |  |  |  |  |  | return FORBIDDEN; | 
| 244 |  |  |  |  |  |  | } | 
| 245 |  |  |  |  |  |  | } | 
| 246 |  |  |  |  |  |  |  | 
| 247 |  |  |  |  |  |  | ## @rmethod protected void logForbidden(string uri,hashref datas) | 
| 248 |  |  |  |  |  |  | # Insert a log in Apache errors log system to inform that the user was rejected. | 
| 249 |  |  |  |  |  |  | # This method has to be overloaded to use different logs systems | 
| 250 |  |  |  |  |  |  | # @param $uri uri asked | 
| 251 |  |  |  |  |  |  | # @param $datas hash re to user's datas | 
| 252 |  |  |  |  |  |  | sub logForbidden { | 
| 253 |  |  |  |  |  |  | my ( $class, $uri, $datas ) = splice @_; | 
| 254 |  |  |  |  |  |  | Lemonldap::NG::Handler::Main::Logger->lmLog( | 
| 255 |  |  |  |  |  |  | 'User "' | 
| 256 |  |  |  |  |  |  | . $datas->{ $tsv->{whatToTrace} } | 
| 257 |  |  |  |  |  |  | . '" was reject when he tried to access to ' | 
| 258 |  |  |  |  |  |  | . $uri, | 
| 259 |  |  |  |  |  |  | 'notice' | 
| 260 |  |  |  |  |  |  | ); | 
| 261 |  |  |  |  |  |  | } | 
| 262 |  |  |  |  |  |  |  | 
| 263 |  |  |  |  |  |  | ## @rmethod protected void logGranted(string uri) | 
| 264 |  |  |  |  |  |  | # Insert a log in Apache errors log system to inform that the user was | 
| 265 |  |  |  |  |  |  | # authorizated. This method has to be overloaded to use different logs systems | 
| 266 |  |  |  |  |  |  | # @param $uri uri asked | 
| 267 |  |  |  |  |  |  | sub logGranted { | 
| 268 |  |  |  |  |  |  | my ( $class, $uri, $datas ) = splice @_; | 
| 269 |  |  |  |  |  |  | Lemonldap::NG::Handler::Main::Logger->lmLog( | 
| 270 |  |  |  |  |  |  | 'User "' | 
| 271 |  |  |  |  |  |  | . $datas->{ $tsv->{whatToTrace} } | 
| 272 |  |  |  |  |  |  | . '" was granted to access to ' | 
| 273 |  |  |  |  |  |  | . $uri, | 
| 274 |  |  |  |  |  |  | 'debug' | 
| 275 |  |  |  |  |  |  | ); | 
| 276 |  |  |  |  |  |  | } | 
| 277 |  |  |  |  |  |  |  | 
| 278 |  |  |  |  |  |  | ## @rmethod protected void hideCookie() | 
| 279 |  |  |  |  |  |  | # Hide Lemonldap::NG cookie to the protected application. | 
| 280 |  |  |  |  |  |  | sub hideCookie { | 
| 281 |  |  |  |  |  |  | my $class = shift; | 
| 282 |  |  |  |  |  |  | Lemonldap::NG::Handler::Main::Logger->lmLog( "removing cookie", 'debug' ); | 
| 283 |  |  |  |  |  |  | my $tmp = Lemonldap::NG::Handler::Main::Headers->lmHeaderIn( $apacheRequest, | 
| 284 |  |  |  |  |  |  | 'Cookie' ); | 
| 285 |  |  |  |  |  |  | $tmp =~ s/$tsv->{cookieName}(http)?=[^,;]*[,;\s]*//og; | 
| 286 |  |  |  |  |  |  | if ($tmp) { | 
| 287 |  |  |  |  |  |  | Lemonldap::NG::Handler::Main::Headers->lmSetHeaderIn( $apacheRequest, | 
| 288 |  |  |  |  |  |  | 'Cookie' => $tmp ); | 
| 289 |  |  |  |  |  |  | } | 
| 290 |  |  |  |  |  |  | else { | 
| 291 |  |  |  |  |  |  | Lemonldap::NG::Handler::Main::Headers->lmUnsetHeaderIn( $apacheRequest, | 
| 292 |  |  |  |  |  |  | 'Cookie' ); | 
| 293 |  |  |  |  |  |  | } | 
| 294 |  |  |  |  |  |  | } | 
| 295 |  |  |  |  |  |  |  | 
| 296 |  |  |  |  |  |  | ## @rmethod protected string encodeUrl(string url) | 
| 297 |  |  |  |  |  |  | # Encode URl in the format used by Lemonldap::NG::Portal for redirections. | 
| 298 |  |  |  |  |  |  | # @return Base64 encoded string | 
| 299 |  |  |  |  |  |  | sub encodeUrl { | 
| 300 |  |  |  |  |  |  | my ( $class, $url ) = splice @_; | 
| 301 |  |  |  |  |  |  | $url = $class->_buildUrl($url) if ( $url !~ m#^https?://# ); | 
| 302 |  |  |  |  |  |  | return encode_base64( $url, '' ); | 
| 303 |  |  |  |  |  |  | } | 
| 304 |  |  |  |  |  |  |  | 
| 305 |  |  |  |  |  |  | ## @rmethod protected int goToPortal(string url, string arg) | 
| 306 |  |  |  |  |  |  | # Redirect non-authenticated users to the portal by setting "Location:" header. | 
| 307 |  |  |  |  |  |  | # @param $url Url requested | 
| 308 |  |  |  |  |  |  | # @param $arg optionnal GET parameters | 
| 309 |  |  |  |  |  |  | # @return Apache2::Const::REDIRECT | 
| 310 |  |  |  |  |  |  | sub goToPortal { | 
| 311 |  |  |  |  |  |  | my ( $class, $url, $arg ) = splice @_; | 
| 312 |  |  |  |  |  |  | Lemonldap::NG::Handler::Main::Logger->lmLog( | 
| 313 |  |  |  |  |  |  | "Redirect " . $class->ip() . " to portal (url was $url)", 'debug' ); | 
| 314 |  |  |  |  |  |  | my $urlc_init = $class->encodeUrl($url); | 
| 315 |  |  |  |  |  |  | Lemonldap::NG::Handler::Main::Headers->lmSetHeaderOut( $apacheRequest, | 
| 316 |  |  |  |  |  |  | 'Location' => $class->portal() | 
| 317 |  |  |  |  |  |  | . "?url=$urlc_init" | 
| 318 |  |  |  |  |  |  | . ( $arg ? "&$arg" : "" ) ); | 
| 319 |  |  |  |  |  |  | return REDIRECT; | 
| 320 |  |  |  |  |  |  | } | 
| 321 |  |  |  |  |  |  |  | 
| 322 |  |  |  |  |  |  | ## @rmethod protected $ fetchId() | 
| 323 |  |  |  |  |  |  | # Get user cookies and search for Lemonldap::NG cookie. | 
| 324 |  |  |  |  |  |  | # @return Value of the cookie if found, 0 else | 
| 325 |  |  |  |  |  |  | sub fetchId { | 
| 326 |  |  |  |  |  |  | my $t = Lemonldap::NG::Handler::Main::Headers->lmHeaderIn( $apacheRequest, | 
| 327 |  |  |  |  |  |  | 'Cookie' ); | 
| 328 |  |  |  |  |  |  | my $vhost = $apacheRequest->hostname; | 
| 329 |  |  |  |  |  |  | my $lookForHttpCookie = $tsv->{securedCookie} =~ /^(2|3)$/ | 
| 330 |  |  |  |  |  |  | && !( | 
| 331 |  |  |  |  |  |  | defined( $tsv->{https}->{$vhost} ) | 
| 332 |  |  |  |  |  |  | ? $tsv->{https}->{$vhost} | 
| 333 |  |  |  |  |  |  | : $tsv->{https}->{_} | 
| 334 |  |  |  |  |  |  | ); | 
| 335 |  |  |  |  |  |  | my $value = | 
| 336 |  |  |  |  |  |  | $lookForHttpCookie | 
| 337 |  |  |  |  |  |  | ? ( $t =~ /$tsv->{cookieName}http=([^,; ]+)/o ? $1 : 0 ) | 
| 338 |  |  |  |  |  |  | : ( $t =~ /$tsv->{cookieName}=([^,; ]+)/o ? $1 : 0 ); | 
| 339 |  |  |  |  |  |  |  | 
| 340 |  |  |  |  |  |  | $value = $ntsv->{cipher}->decryptHex( $value, "http" ) | 
| 341 |  |  |  |  |  |  | if ( $value && $lookForHttpCookie && $tsv->{securedCookie} == 3 ); | 
| 342 |  |  |  |  |  |  | return $value; | 
| 343 |  |  |  |  |  |  | } | 
| 344 |  |  |  |  |  |  |  | 
| 345 |  |  |  |  |  |  | ## @rmethod protected boolean retrieveSession(id) | 
| 346 |  |  |  |  |  |  | # Tries to retrieve the session whose index is id | 
| 347 |  |  |  |  |  |  | # @return true if the session was found, false else | 
| 348 |  |  |  |  |  |  | sub retrieveSession { | 
| 349 |  |  |  |  |  |  | my ( $class, $id ) = @_; | 
| 350 |  |  |  |  |  |  |  | 
| 351 |  |  |  |  |  |  | # 1. Search if the user was the same as previous (very efficient in | 
| 352 |  |  |  |  |  |  | # persistent connection). | 
| 353 |  |  |  |  |  |  | return 1 | 
| 354 |  |  |  |  |  |  | if (  defined $datas->{_session_id} | 
| 355 |  |  |  |  |  |  | and $id eq $datas->{_session_id} | 
| 356 |  |  |  |  |  |  | and ( time() - $ntsv->{datasUpdate} < 60 ) ); | 
| 357 |  |  |  |  |  |  |  | 
| 358 |  |  |  |  |  |  | # 2. Get the session from cache or backend | 
| 359 |  |  |  |  |  |  | my $apacheSession = Lemonldap::NG::Common::Session->new( | 
| 360 |  |  |  |  |  |  | { | 
| 361 |  |  |  |  |  |  | storageModule        => $tsv->{globalStorage}, | 
| 362 |  |  |  |  |  |  | storageModuleOptions => $tsv->{globalStorageOptions}, | 
| 363 |  |  |  |  |  |  | cacheModule          => $tsv->{localSessionStorage}, | 
| 364 |  |  |  |  |  |  | cacheModuleOptions   => $tsv->{localSessionStorageOptions}, | 
| 365 |  |  |  |  |  |  | id                   => $id, | 
| 366 |  |  |  |  |  |  | kind                 => "SSO", | 
| 367 |  |  |  |  |  |  | } | 
| 368 |  |  |  |  |  |  | ); | 
| 369 |  |  |  |  |  |  |  | 
| 370 |  |  |  |  |  |  | unless ( $apacheSession->error ) { | 
| 371 |  |  |  |  |  |  |  | 
| 372 |  |  |  |  |  |  | $datas = $apacheSession->data; | 
| 373 |  |  |  |  |  |  |  | 
| 374 |  |  |  |  |  |  | # Update the session to notify activity, if necessary | 
| 375 |  |  |  |  |  |  | if ( $tsv->{timeoutActivity} ) { | 
| 376 |  |  |  |  |  |  | $apacheSession->update( { '_lastSeen' => time } ); | 
| 377 |  |  |  |  |  |  |  | 
| 378 |  |  |  |  |  |  | if ( $apacheSession->error ) { | 
| 379 |  |  |  |  |  |  | Lemonldap::NG::Handler::Main::Logger->lmLog( | 
| 380 |  |  |  |  |  |  | "Cannot update session $id", 'error' ); | 
| 381 |  |  |  |  |  |  | Lemonldap::NG::Handler::Main::Logger->lmLog( | 
| 382 |  |  |  |  |  |  | $apacheSession->error, 'error' ); | 
| 383 |  |  |  |  |  |  | } | 
| 384 |  |  |  |  |  |  | } | 
| 385 |  |  |  |  |  |  |  | 
| 386 |  |  |  |  |  |  | $datasUpdate = time(); | 
| 387 |  |  |  |  |  |  | return 1; | 
| 388 |  |  |  |  |  |  | } | 
| 389 |  |  |  |  |  |  | else { | 
| 390 |  |  |  |  |  |  | Lemonldap::NG::Handler::Main::Logger->lmLog( | 
| 391 |  |  |  |  |  |  | "Session $id can't be retrieved", 'info' ); | 
| 392 |  |  |  |  |  |  | Lemonldap::NG::Handler::Main::Logger->lmLog( $apacheSession->error, | 
| 393 |  |  |  |  |  |  | 'info' ); | 
| 394 |  |  |  |  |  |  |  | 
| 395 |  |  |  |  |  |  | return 0; | 
| 396 |  |  |  |  |  |  | } | 
| 397 |  |  |  |  |  |  | } | 
| 398 |  |  |  |  |  |  |  | 
| 399 |  |  |  |  |  |  | sub ip { | 
| 400 |  |  |  |  |  |  | my $ip = 'unknownIP'; | 
| 401 |  |  |  |  |  |  | eval { | 
| 402 |  |  |  |  |  |  | $ip = | 
| 403 |  |  |  |  |  |  | ( MP() == 2 ) | 
| 404 |  |  |  |  |  |  | ? $apacheRequest->connection->remote_ip | 
| 405 |  |  |  |  |  |  | : $apacheRequest->remote_ip; | 
| 406 |  |  |  |  |  |  | }; | 
| 407 |  |  |  |  |  |  | return $ip; | 
| 408 |  |  |  |  |  |  | } | 
| 409 |  |  |  |  |  |  |  | 
| 410 |  |  |  |  |  |  | # MAIN SUBROUTINE called by Apache (using PerlHeaderParserHandler option) | 
| 411 |  |  |  |  |  |  |  | 
| 412 |  |  |  |  |  |  | ## @rmethod int run(Apache2::RequestRec apacheRequest) | 
| 413 |  |  |  |  |  |  | # Main method used to control access. | 
| 414 |  |  |  |  |  |  | # Calls : | 
| 415 |  |  |  |  |  |  | # - fetchId() | 
| 416 |  |  |  |  |  |  | # - retrieveSession() | 
| 417 |  |  |  |  |  |  | # - lmSetApacheUser() | 
| 418 |  |  |  |  |  |  | # - grant() | 
| 419 |  |  |  |  |  |  | # - forbidden() if user is rejected | 
| 420 |  |  |  |  |  |  | # - sendHeaders() if user is granted | 
| 421 |  |  |  |  |  |  | # - hideCookie() | 
| 422 |  |  |  |  |  |  | # - updateStatus() | 
| 423 |  |  |  |  |  |  | # @param $apacheRequest Current request | 
| 424 |  |  |  |  |  |  | # @return Apache2::Const value (OK, FORBIDDEN, REDIRECT or SERVER_ERROR) | 
| 425 |  |  |  |  |  |  | sub run ($$) { | 
| 426 |  |  |  |  |  |  | my $class; | 
| 427 |  |  |  |  |  |  | ( $class, $apacheRequest ) = splice @_; | 
| 428 |  |  |  |  |  |  | return DECLINED unless ( $apacheRequest->is_initial_req ); | 
| 429 |  |  |  |  |  |  | my $args = $apacheRequest->args; | 
| 430 |  |  |  |  |  |  |  | 
| 431 |  |  |  |  |  |  | # Direct return if maintenance mode is active | 
| 432 |  |  |  |  |  |  | if ( $class->checkMaintenanceMode() ) { | 
| 433 |  |  |  |  |  |  |  | 
| 434 |  |  |  |  |  |  | if ( $tsv->{useRedirectOnError} ) { | 
| 435 |  |  |  |  |  |  | Lemonldap::NG::Handler::Main::Logger->lmLog( | 
| 436 |  |  |  |  |  |  | "Got to portal with maintenance error code", 'debug' ); | 
| 437 |  |  |  |  |  |  | return $class->goToPortal( '/', 'lmError=' . MAINTENANCE_CODE ); | 
| 438 |  |  |  |  |  |  | } | 
| 439 |  |  |  |  |  |  | else { | 
| 440 |  |  |  |  |  |  | Lemonldap::NG::Handler::Main::Logger->lmLog( | 
| 441 |  |  |  |  |  |  | "Return maintenance error code", 'debug' ); | 
| 442 |  |  |  |  |  |  | return MAINTENANCE_CODE; | 
| 443 |  |  |  |  |  |  | } | 
| 444 |  |  |  |  |  |  | } | 
| 445 |  |  |  |  |  |  |  | 
| 446 |  |  |  |  |  |  | # Cross domain authentication | 
| 447 |  |  |  |  |  |  | if (    $ntsv->{cda} | 
| 448 |  |  |  |  |  |  | and $args =~ s/[\?&]?($tsv->{cookieName}(http)?=\w+)$//oi ) | 
| 449 |  |  |  |  |  |  | { | 
| 450 |  |  |  |  |  |  | my $str = $1; | 
| 451 |  |  |  |  |  |  | Lemonldap::NG::Handler::Main::Logger->lmLog( 'CDA request', 'debug' ); | 
| 452 |  |  |  |  |  |  | $apacheRequest->args($args); | 
| 453 |  |  |  |  |  |  | my $redirectUrl = $class->_buildUrl( $apacheRequest->uri ); | 
| 454 |  |  |  |  |  |  | my $redirectHttps = ( $redirectUrl =~ m/^https/ ); | 
| 455 |  |  |  |  |  |  | Lemonldap::NG::Handler::Main::Headers->lmSetErrHeaderOut( | 
| 456 |  |  |  |  |  |  | $apacheRequest, | 
| 457 |  |  |  |  |  |  | 'Location' => $redirectUrl . ( $args ? "?" . $args : "" ) ); | 
| 458 |  |  |  |  |  |  | Lemonldap::NG::Handler::Main::Headers->lmSetErrHeaderOut( | 
| 459 |  |  |  |  |  |  | $apacheRequest, | 
| 460 |  |  |  |  |  |  | 'Set-Cookie' => "$str; path=/" | 
| 461 |  |  |  |  |  |  | . ( $redirectHttps    ? "; secure"   : "" ) | 
| 462 |  |  |  |  |  |  | . ( $ntsv->{httpOnly} ? "; HttpOnly" : "" ) | 
| 463 |  |  |  |  |  |  | . ( | 
| 464 |  |  |  |  |  |  | $ntsv->{cookieExpiration} | 
| 465 |  |  |  |  |  |  | ? "; expires=" . expires( $ntsv->{cookieExpiration}, 'cookie' ) | 
| 466 |  |  |  |  |  |  | : "" | 
| 467 |  |  |  |  |  |  | ) | 
| 468 |  |  |  |  |  |  | ); | 
| 469 |  |  |  |  |  |  | return REDIRECT; | 
| 470 |  |  |  |  |  |  | } | 
| 471 |  |  |  |  |  |  | my $uri      = $apacheRequest->unparsed_uri(); | 
| 472 |  |  |  |  |  |  | my $uri_orig = $uri; | 
| 473 |  |  |  |  |  |  | Apache2::URI::unescape_url($uri); | 
| 474 |  |  |  |  |  |  |  | 
| 475 |  |  |  |  |  |  | my $protection = $class->isUnprotected($uri); | 
| 476 |  |  |  |  |  |  |  | 
| 477 |  |  |  |  |  |  | if ( $protection == SKIP ) { | 
| 478 |  |  |  |  |  |  | Lemonldap::NG::Handler::Main::Logger->lmLog( "Access control skipped", | 
| 479 |  |  |  |  |  |  | "debug" ); | 
| 480 |  |  |  |  |  |  | $class->updateStatus( $class->ip(), $apacheRequest->uri, 'SKIP' ); | 
| 481 |  |  |  |  |  |  | $class->hideCookie; | 
| 482 |  |  |  |  |  |  | Lemonldap::NG::Handler::Main::Headers->cleanHeaders( $apacheRequest, | 
| 483 |  |  |  |  |  |  | $tsv->{forgeHeaders}, $tsv->{headerList} ); | 
| 484 |  |  |  |  |  |  | return OK; | 
| 485 |  |  |  |  |  |  | } | 
| 486 |  |  |  |  |  |  |  | 
| 487 |  |  |  |  |  |  | my $id; | 
| 488 |  |  |  |  |  |  |  | 
| 489 |  |  |  |  |  |  | # Try to recover cookie and user session | 
| 490 |  |  |  |  |  |  | if ( $id = $class->fetchId and $class->retrieveSession($id) ) { | 
| 491 |  |  |  |  |  |  |  | 
| 492 |  |  |  |  |  |  | # AUTHENTICATION done | 
| 493 |  |  |  |  |  |  |  | 
| 494 |  |  |  |  |  |  | # Local macros | 
| 495 |  |  |  |  |  |  | my $kc = keys %$datas;    # in order to detect new local macro | 
| 496 |  |  |  |  |  |  |  | 
| 497 |  |  |  |  |  |  | # ACCOUNTING (1. Inform Apache) | 
| 498 |  |  |  |  |  |  | $class->lmSetApacheUser( $apacheRequest, | 
| 499 |  |  |  |  |  |  | $datas->{ $tsv->{whatToTrace} } ); | 
| 500 |  |  |  |  |  |  |  | 
| 501 |  |  |  |  |  |  | # AUTHORIZATION | 
| 502 |  |  |  |  |  |  | return $class->forbidden($uri) | 
| 503 |  |  |  |  |  |  | unless ( $class->grant($uri) ); | 
| 504 |  |  |  |  |  |  | $class->updateStatus( $datas->{ $tsv->{whatToTrace} }, | 
| 505 |  |  |  |  |  |  | $apacheRequest->uri, 'OK' ); | 
| 506 |  |  |  |  |  |  |  | 
| 507 |  |  |  |  |  |  | # ACCOUNTING (2. Inform remote application) | 
| 508 |  |  |  |  |  |  | Lemonldap::NG::Handler::Main::Headers->sendHeaders( $apacheRequest, | 
| 509 |  |  |  |  |  |  | $tsv->{forgeHeaders} ); | 
| 510 |  |  |  |  |  |  |  | 
| 511 |  |  |  |  |  |  | # Store local macros | 
| 512 |  |  |  |  |  |  | if ( keys %$datas > $kc and $tsv->{refLocalStorage} ) { | 
| 513 |  |  |  |  |  |  | Lemonldap::NG::Handler::Main::Logger->lmLog( "Update local cache", | 
| 514 |  |  |  |  |  |  | "debug" ); | 
| 515 |  |  |  |  |  |  | $tsv->{refLocalStorage}->set( $id, $datas, "10 minutes" ); | 
| 516 |  |  |  |  |  |  | } | 
| 517 |  |  |  |  |  |  |  | 
| 518 |  |  |  |  |  |  | # Hide Lemonldap::NG cookie | 
| 519 |  |  |  |  |  |  | $class->hideCookie; | 
| 520 |  |  |  |  |  |  |  | 
| 521 |  |  |  |  |  |  | # Log | 
| 522 |  |  |  |  |  |  | $apacheRequest->push_handlers( PerlLogHandler => | 
| 523 |  |  |  |  |  |  | sub { $class->logGranted( $uri, $datas ); DECLINED }, ); | 
| 524 |  |  |  |  |  |  |  | 
| 525 |  |  |  |  |  |  | #  Catch POST rules | 
| 526 |  |  |  |  |  |  | Lemonldap::NG::Handler::Main::PostForm->transformUri($uri); | 
| 527 |  |  |  |  |  |  |  | 
| 528 |  |  |  |  |  |  | return OK; | 
| 529 |  |  |  |  |  |  | } | 
| 530 |  |  |  |  |  |  |  | 
| 531 |  |  |  |  |  |  | elsif ( $protection == UNPROTECT ) { | 
| 532 |  |  |  |  |  |  |  | 
| 533 |  |  |  |  |  |  | # Ignore unprotected URIs | 
| 534 |  |  |  |  |  |  | Lemonldap::NG::Handler::Main::Logger->lmLog( | 
| 535 |  |  |  |  |  |  | "No valid session but unprotected access", "debug" ); | 
| 536 |  |  |  |  |  |  | $class->updateStatus( $class->ip(), $apacheRequest->uri, 'UNPROTECT' ); | 
| 537 |  |  |  |  |  |  | $class->hideCookie; | 
| 538 |  |  |  |  |  |  | Lemonldap::NG::Handler::Main::Headers->cleanHeaders( $apacheRequest, | 
| 539 |  |  |  |  |  |  | $tsv->{forgeHeaders}, $tsv->{headerList} ); | 
| 540 |  |  |  |  |  |  | return OK; | 
| 541 |  |  |  |  |  |  | } | 
| 542 |  |  |  |  |  |  |  | 
| 543 |  |  |  |  |  |  | else { | 
| 544 |  |  |  |  |  |  |  | 
| 545 |  |  |  |  |  |  | # Redirect user to the portal | 
| 546 |  |  |  |  |  |  | Lemonldap::NG::Handler::Main::Logger->lmLog( "$class: No cookie found", | 
| 547 |  |  |  |  |  |  | 'info' ) | 
| 548 |  |  |  |  |  |  | unless ($id); | 
| 549 |  |  |  |  |  |  |  | 
| 550 |  |  |  |  |  |  | # if the cookie was fetched, a log is sent by retrieveSession() | 
| 551 |  |  |  |  |  |  | $class->updateStatus( $class->ip(), $apacheRequest->uri, | 
| 552 |  |  |  |  |  |  | $id ? 'EXPIRED' : 'REDIRECT' ); | 
| 553 |  |  |  |  |  |  | return $class->goToPortal($uri_orig); | 
| 554 |  |  |  |  |  |  | } | 
| 555 |  |  |  |  |  |  | } | 
| 556 |  |  |  |  |  |  |  | 
| 557 |  |  |  |  |  |  | ## @rmethod protected boolean checkMaintenanceMode | 
| 558 |  |  |  |  |  |  | # Check if we are in maintenance mode | 
| 559 |  |  |  |  |  |  | # @return true if maintenance mode | 
| 560 |  |  |  |  |  |  | sub checkMaintenanceMode { | 
| 561 |  |  |  |  |  |  | my ($class) = splice @_; | 
| 562 |  |  |  |  |  |  | my $vhost = $apacheRequest->hostname; | 
| 563 |  |  |  |  |  |  | my $_maintenance = | 
| 564 |  |  |  |  |  |  | ( defined $tsv->{maintenance}->{$vhost} ) | 
| 565 |  |  |  |  |  |  | ? $tsv->{maintenance}->{$vhost} | 
| 566 |  |  |  |  |  |  | : $tsv->{maintenance}->{_}; | 
| 567 |  |  |  |  |  |  |  | 
| 568 |  |  |  |  |  |  | if ($_maintenance) { | 
| 569 |  |  |  |  |  |  | Lemonldap::NG::Handler::Main::Logger->lmLog( | 
| 570 |  |  |  |  |  |  | "Maintenance mode activated", 'debug' ); | 
| 571 |  |  |  |  |  |  | return 1; | 
| 572 |  |  |  |  |  |  | } | 
| 573 |  |  |  |  |  |  |  | 
| 574 |  |  |  |  |  |  | return 0; | 
| 575 |  |  |  |  |  |  | } | 
| 576 |  |  |  |  |  |  |  | 
| 577 |  |  |  |  |  |  | ## @rmethod int abort(string mess) | 
| 578 |  |  |  |  |  |  | # Logs message and exit or redirect to the portal if "useRedirectOnError" is | 
| 579 |  |  |  |  |  |  | # set to true. | 
| 580 |  |  |  |  |  |  | # @param $mess Message to log | 
| 581 |  |  |  |  |  |  | # @return Apache2::Const::REDIRECT or Apache2::Const::SERVER_ERROR | 
| 582 |  |  |  |  |  |  | sub abort { | 
| 583 |  |  |  |  |  |  | my ( $class, $mess ) = splice @_; | 
| 584 |  |  |  |  |  |  |  | 
| 585 |  |  |  |  |  |  | # If abort is called without a valid request, fall to die | 
| 586 |  |  |  |  |  |  | eval { | 
| 587 |  |  |  |  |  |  | my $args = $apacheRequest->args; | 
| 588 |  |  |  |  |  |  | my $uri  = $apacheRequest->unparsed_uri(); | 
| 589 |  |  |  |  |  |  |  | 
| 590 |  |  |  |  |  |  | # Set error 500 in logs even if "useRedirectOnError" is set | 
| 591 |  |  |  |  |  |  | $apacheRequest->push_handlers( | 
| 592 |  |  |  |  |  |  | PerlLogHandler => sub { $_[0]->status(SERVER_ERROR); DECLINED; } ); | 
| 593 |  |  |  |  |  |  | Lemonldap::NG::Handler::Main::Logger->lmLog( $mess, 'error' ); | 
| 594 |  |  |  |  |  |  |  | 
| 595 |  |  |  |  |  |  | # Redirect or die | 
| 596 |  |  |  |  |  |  | if ( $tsv->{useRedirectOnError} ) { | 
| 597 |  |  |  |  |  |  | Lemonldap::NG::Handler::Main::Logger->lmLog( | 
| 598 |  |  |  |  |  |  | "Use redirect for error", 'debug' ); | 
| 599 |  |  |  |  |  |  | return $class->goToPortal( $uri, 'lmError=500' ); | 
| 600 |  |  |  |  |  |  | } | 
| 601 |  |  |  |  |  |  | else { | 
| 602 |  |  |  |  |  |  | return SERVER_ERROR; | 
| 603 |  |  |  |  |  |  | } | 
| 604 |  |  |  |  |  |  | }; | 
| 605 |  |  |  |  |  |  | die $mess if ($@); | 
| 606 |  |  |  |  |  |  | } | 
| 607 |  |  |  |  |  |  |  | 
| 608 |  |  |  |  |  |  | ## @rmethod protected int handler_mp1() | 
| 609 |  |  |  |  |  |  | # Launch run() when used under mod_perl version 1 | 
| 610 |  |  |  |  |  |  | # @return Apache constant | 
| 611 |  |  |  |  |  |  | sub handler_mp1 ($$) { shift->run(@_); } | 
| 612 |  |  |  |  |  |  |  | 
| 613 |  |  |  |  |  |  | ## @rmethod protected int logout_mp1() | 
| 614 |  |  |  |  |  |  | # Launch unlog() when used under mod_perl version 1 | 
| 615 |  |  |  |  |  |  | # @return Apache constant | 
| 616 |  |  |  |  |  |  | sub logout_mp1 ($$) { shift->unlog(@_); } | 
| 617 |  |  |  |  |  |  |  | 
| 618 |  |  |  |  |  |  | ## @imethod void localInit(hashRef args) | 
| 619 |  |  |  |  |  |  | # instanciate a LocalInit object with variables: | 
| 620 |  |  |  |  |  |  | # localStorage, localStorageOptions, refLocalStorage, childInitDone | 
| 621 |  |  |  |  |  |  | # launch localInit method: | 
| 622 |  |  |  |  |  |  | #  - calls purgeCache() to purge the local cache, | 
| 623 |  |  |  |  |  |  | #  - launch the status processus, | 
| 624 |  |  |  |  |  |  | #  - launch childInit (to init / clean local storage) | 
| 625 |  |  |  |  |  |  | # @param $args reference to the initialization hash | 
| 626 |  |  |  |  |  |  | sub localInit($$) { | 
| 627 |  |  |  |  |  |  | my ( $class, $args ) = splice @_; | 
| 628 |  |  |  |  |  |  |  | 
| 629 |  |  |  |  |  |  | my $localinit = Lemonldap::NG::Handler::Initialization::LocalInit->new( | 
| 630 |  |  |  |  |  |  | localStorage        => $tsv->{localStorage}, | 
| 631 |  |  |  |  |  |  | refLocalStorage     => $tsv->{refLocalStorage}, | 
| 632 |  |  |  |  |  |  | localStorageOptions => $tsv->{localStorageOptions}, | 
| 633 |  |  |  |  |  |  | childInitDone       => $tsv->{childInitDone}, | 
| 634 |  |  |  |  |  |  | ); | 
| 635 |  |  |  |  |  |  | ( | 
| 636 |  |  |  |  |  |  | @$tsv{ | 
| 637 |  |  |  |  |  |  | qw( localStorage refLocalStorage localStorageOptions statusPipe statusOut ) | 
| 638 |  |  |  |  |  |  | }, | 
| 639 |  |  |  |  |  |  | $ntsv->{childInitDone} | 
| 640 |  |  |  |  |  |  | ) = $localinit->localInit($args); | 
| 641 |  |  |  |  |  |  |  | 
| 642 |  |  |  |  |  |  | } | 
| 643 |  |  |  |  |  |  |  | 
| 644 |  |  |  |  |  |  | ## @imethod void globalInit(hashRef args) | 
| 645 |  |  |  |  |  |  | # instanciate a GlobalInit object with variables: | 
| 646 |  |  |  |  |  |  | # customFunctions, useSafeJail, and safe | 
| 647 |  |  |  |  |  |  | # Global initialization process launches : | 
| 648 |  |  |  |  |  |  | # - defaultValuesInit() | 
| 649 |  |  |  |  |  |  | # - portalInit() | 
| 650 |  |  |  |  |  |  | # - locationRulesInit() | 
| 651 |  |  |  |  |  |  | # - globalStorageInit() | 
| 652 |  |  |  |  |  |  | # - localSessionStorageInit() | 
| 653 |  |  |  |  |  |  | # - headerListInit() | 
| 654 |  |  |  |  |  |  | # - forgeHeadersInit() | 
| 655 |  |  |  |  |  |  | # - postUrlInit() | 
| 656 |  |  |  |  |  |  | # @param $args reference to the configuration hash | 
| 657 |  |  |  |  |  |  | sub globalInit { | 
| 658 |  |  |  |  |  |  | my $class = shift; | 
| 659 |  |  |  |  |  |  |  | 
| 660 |  |  |  |  |  |  | my $globalinit = Lemonldap::NG::Handler::Initialization::GlobalInit->new( | 
| 661 |  |  |  |  |  |  | customFunctions => $tsv->{customFunctions}, | 
| 662 |  |  |  |  |  |  | useSafeJail     => $tsv->{useSafeJail}, | 
| 663 |  |  |  |  |  |  | safe            => $ntsv->{safe}, | 
| 664 |  |  |  |  |  |  | ); | 
| 665 |  |  |  |  |  |  |  | 
| 666 |  |  |  |  |  |  | ( | 
| 667 |  |  |  |  |  |  | @$tsv{ | 
| 668 |  |  |  |  |  |  | qw( cookieName      securedCookie      whatToTrace | 
| 669 |  |  |  |  |  |  | https           port               customFunctions | 
| 670 |  |  |  |  |  |  | timeoutActivity useRedirectOnError useRedirectOnForbidden | 
| 671 |  |  |  |  |  |  | useSafeJail     key                maintenance ) | 
| 672 |  |  |  |  |  |  | }, | 
| 673 |  |  |  |  |  |  | @$ntsv{ | 
| 674 |  |  |  |  |  |  | qw( cda             httpOnly           cookieExpiration | 
| 675 |  |  |  |  |  |  | cipher | 
| 676 |  |  |  |  |  |  | ) | 
| 677 |  |  |  |  |  |  | } | 
| 678 |  |  |  |  |  |  | ) | 
| 679 |  |  |  |  |  |  | = $globalinit->defaultValuesInit( | 
| 680 |  |  |  |  |  |  | @$tsv{ | 
| 681 |  |  |  |  |  |  | qw( cookieName      securedCookie      whatToTrace | 
| 682 |  |  |  |  |  |  | https           port               customFunctions | 
| 683 |  |  |  |  |  |  | timeoutActivity useRedirectOnError useRedirectOnForbidden | 
| 684 |  |  |  |  |  |  | useSafeJail     key                maintenance ) | 
| 685 |  |  |  |  |  |  | }, | 
| 686 |  |  |  |  |  |  | @$ntsv{ | 
| 687 |  |  |  |  |  |  | qw( cda             httpOnly           cookieExpiration | 
| 688 |  |  |  |  |  |  | cipher ) | 
| 689 |  |  |  |  |  |  | }, | 
| 690 |  |  |  |  |  |  | @_ | 
| 691 |  |  |  |  |  |  | ); | 
| 692 |  |  |  |  |  |  |  | 
| 693 |  |  |  |  |  |  | ( *portal, $ntsv->{safe} ) = $globalinit->portalInit( $class, @_ ); | 
| 694 |  |  |  |  |  |  |  | 
| 695 |  |  |  |  |  |  | ( | 
| 696 |  |  |  |  |  |  | @$tsv{ | 
| 697 |  |  |  |  |  |  | qw( locationCount defaultCondition | 
| 698 |  |  |  |  |  |  | defaultProtection locationCondition | 
| 699 |  |  |  |  |  |  | locationProtection locationRegexp | 
| 700 |  |  |  |  |  |  | locationConditionText ) | 
| 701 |  |  |  |  |  |  | }, | 
| 702 |  |  |  |  |  |  | $ntsv->{safe} | 
| 703 |  |  |  |  |  |  | ) | 
| 704 |  |  |  |  |  |  | = $globalinit->locationRulesInit( | 
| 705 |  |  |  |  |  |  | $class, | 
| 706 |  |  |  |  |  |  | @$tsv{ | 
| 707 |  |  |  |  |  |  | qw( locationCount defaultCondition | 
| 708 |  |  |  |  |  |  | defaultProtection locationCondition | 
| 709 |  |  |  |  |  |  | locationProtection locationRegexp | 
| 710 |  |  |  |  |  |  | locationConditionText ) | 
| 711 |  |  |  |  |  |  | }, | 
| 712 |  |  |  |  |  |  | @_ | 
| 713 |  |  |  |  |  |  | ); | 
| 714 |  |  |  |  |  |  |  | 
| 715 |  |  |  |  |  |  | @$tsv{qw( globalStorage globalStorageOptions )} = | 
| 716 |  |  |  |  |  |  | $globalinit->globalStorageInit( | 
| 717 |  |  |  |  |  |  | @$tsv{qw( globalStorage globalStorageOptions )}, @_ ); | 
| 718 |  |  |  |  |  |  |  | 
| 719 |  |  |  |  |  |  | @$tsv{qw( localSessionStorage localSessionStorageOptions )} = | 
| 720 |  |  |  |  |  |  | $globalinit->localSessionStorageInit( | 
| 721 |  |  |  |  |  |  | @$tsv{qw( localSessionStorage localSessionStorageOptions )}, @_ ); | 
| 722 |  |  |  |  |  |  |  | 
| 723 |  |  |  |  |  |  | $tsv->{headerList} = $globalinit->headerListInit( $tsv->{headerList}, @_ ); | 
| 724 |  |  |  |  |  |  |  | 
| 725 |  |  |  |  |  |  | $tsv->{forgeHeaders} = | 
| 726 |  |  |  |  |  |  | $globalinit->forgeHeadersInit( $tsv->{forgeHeaders}, @_ ); | 
| 727 |  |  |  |  |  |  |  | 
| 728 |  |  |  |  |  |  | $ntsv->{transform} = $globalinit->postUrlInit( $ntsv->{transform}, @_ ); | 
| 729 |  |  |  |  |  |  |  | 
| 730 |  |  |  |  |  |  | } | 
| 731 |  |  |  |  |  |  |  | 
| 732 |  |  |  |  |  |  | ## @rmethod boolean grant() | 
| 733 |  |  |  |  |  |  | # Grant or refuse client using compiled regexp and functions | 
| 734 |  |  |  |  |  |  | # @return True if the user is granted to access to the current URL | 
| 735 |  |  |  |  |  |  | sub grant { | 
| 736 |  |  |  |  |  |  | my ( $class, $uri ) = splice @_; | 
| 737 |  |  |  |  |  |  | my $vhost = $apacheRequest->hostname; | 
| 738 |  |  |  |  |  |  | for ( my $i = 0 ; $i < $tsv->{locationCount}->{$vhost} ; $i++ ) { | 
| 739 |  |  |  |  |  |  | if ( $uri =~ $tsv->{locationRegexp}->{$vhost}->[$i] ) { | 
| 740 |  |  |  |  |  |  | Lemonldap::NG::Handler::Main::Logger->lmLog( | 
| 741 |  |  |  |  |  |  | 'Regexp "' | 
| 742 |  |  |  |  |  |  | . $tsv->{locationConditionText}->{$vhost}->[$i] | 
| 743 |  |  |  |  |  |  | . '" match', | 
| 744 |  |  |  |  |  |  | 'debug' | 
| 745 |  |  |  |  |  |  | ); | 
| 746 |  |  |  |  |  |  | return &{ $tsv->{locationCondition}->{$vhost}->[$i] }($datas); | 
| 747 |  |  |  |  |  |  | } | 
| 748 |  |  |  |  |  |  | } | 
| 749 |  |  |  |  |  |  | unless ( $tsv->{defaultCondition}->{$vhost} ) { | 
| 750 |  |  |  |  |  |  | Lemonldap::NG::Handler::Main::Logger->lmLog( | 
| 751 |  |  |  |  |  |  | "User rejected because VirtualHost \"$vhost\" has no configuration", | 
| 752 |  |  |  |  |  |  | 'warn' | 
| 753 |  |  |  |  |  |  | ); | 
| 754 |  |  |  |  |  |  | return 0; | 
| 755 |  |  |  |  |  |  | } | 
| 756 |  |  |  |  |  |  | Lemonldap::NG::Handler::Main::Logger->lmLog( "$vhost: Apply default rule", | 
| 757 |  |  |  |  |  |  | 'debug' ); | 
| 758 |  |  |  |  |  |  | return &{ $tsv->{defaultCondition}->{$vhost} }($datas); | 
| 759 |  |  |  |  |  |  | } | 
| 760 |  |  |  |  |  |  |  | 
| 761 |  |  |  |  |  |  | ## @cmethod private string _buildUrl(string s) | 
| 762 |  |  |  |  |  |  | # Transform /  into http(s?)://:/s  | 
| 763 |  |  |  |  |  |  | # @param $s path | 
| 764 |  |  |  |  |  |  | # @return URL | 
| 765 |  |  |  |  |  |  | sub _buildUrl { | 
| 766 |  |  |  |  |  |  | my ( $class, $s ) = splice @_; | 
| 767 |  |  |  |  |  |  | my $vhost = $apacheRequest->hostname; | 
| 768 |  |  |  |  |  |  | my $portString = | 
| 769 |  |  |  |  |  |  | $tsv->{port}->{$vhost} | 
| 770 |  |  |  |  |  |  | || $tsv->{port}->{_} | 
| 771 |  |  |  |  |  |  | || $apacheRequest->get_server_port(); | 
| 772 |  |  |  |  |  |  | my $_https = ( | 
| 773 |  |  |  |  |  |  | defined( $tsv->{https}->{$vhost} ) | 
| 774 |  |  |  |  |  |  | ? $tsv->{https}->{$vhost} | 
| 775 |  |  |  |  |  |  | : $tsv->{https}->{_} | 
| 776 |  |  |  |  |  |  | ); | 
| 777 |  |  |  |  |  |  | $portString = | 
| 778 |  |  |  |  |  |  | ( $_https  && $portString == 443 ) ? '' | 
| 779 |  |  |  |  |  |  | : ( !$_https && $portString == 80 )  ? '' | 
| 780 |  |  |  |  |  |  | :                                      ':' . $portString; | 
| 781 |  |  |  |  |  |  | my $url = "http" | 
| 782 |  |  |  |  |  |  | . ( $_https ? "s" : "" ) . "://" | 
| 783 |  |  |  |  |  |  | . $apacheRequest->get_server_name() | 
| 784 |  |  |  |  |  |  | . $portString | 
| 785 |  |  |  |  |  |  | . $s; | 
| 786 |  |  |  |  |  |  | Lemonldap::NG::Handler::Main::Logger->lmLog( "Build URL $url", 'debug' ); | 
| 787 |  |  |  |  |  |  | return $url; | 
| 788 |  |  |  |  |  |  | } | 
| 789 |  |  |  |  |  |  |  | 
| 790 |  |  |  |  |  |  | ## @rmethod int unprotect() | 
| 791 |  |  |  |  |  |  | # Used to unprotect an area. | 
| 792 |  |  |  |  |  |  | # To use it, set "PerlHeaderParserHandler My::Package->unprotect" Apache | 
| 793 |  |  |  |  |  |  | # configuration file. | 
| 794 |  |  |  |  |  |  | # It replace run() by doing nothing. | 
| 795 |  |  |  |  |  |  | # @return Apache2::Const::OK | 
| 796 |  |  |  |  |  |  | sub unprotect { | 
| 797 |  |  |  |  |  |  | OK; | 
| 798 |  |  |  |  |  |  | } | 
| 799 |  |  |  |  |  |  |  | 
| 800 |  |  |  |  |  |  | ## @rmethod protected void localUnlog() | 
| 801 |  |  |  |  |  |  | # Delete current user from local cache entry. | 
| 802 |  |  |  |  |  |  | sub localUnlog { | 
| 803 |  |  |  |  |  |  | my $class = shift; | 
| 804 |  |  |  |  |  |  | if ( my $id = $class->fetchId ) { | 
| 805 |  |  |  |  |  |  |  | 
| 806 |  |  |  |  |  |  | # Delete Apache thread datas | 
| 807 |  |  |  |  |  |  | if ( $id eq $datas->{_session_id} ) { | 
| 808 |  |  |  |  |  |  | $datas = {}; | 
| 809 |  |  |  |  |  |  | } | 
| 810 |  |  |  |  |  |  |  | 
| 811 |  |  |  |  |  |  | # Delete Apache local cache | 
| 812 |  |  |  |  |  |  | if ( $tsv->{refLocalStorage} and $tsv->{refLocalStorage}->get($id) ) { | 
| 813 |  |  |  |  |  |  | $tsv->{refLocalStorage}->remove($id); | 
| 814 |  |  |  |  |  |  | } | 
| 815 |  |  |  |  |  |  | } | 
| 816 |  |  |  |  |  |  | } | 
| 817 |  |  |  |  |  |  |  | 
| 818 |  |  |  |  |  |  | ## @rmethod protected int unlog(Apache::RequestRec apacheRequest) | 
| 819 |  |  |  |  |  |  | # Call localUnlog() then goToPortal() to unlog the current user. | 
| 820 |  |  |  |  |  |  | # @return Apache2::Const value returned by goToPortal() | 
| 821 |  |  |  |  |  |  | sub unlog ($$) { | 
| 822 |  |  |  |  |  |  | my $class; | 
| 823 |  |  |  |  |  |  | ( $class, $apacheRequest ) = splice @_; | 
| 824 |  |  |  |  |  |  | $class->localUnlog; | 
| 825 |  |  |  |  |  |  | $class->updateStatus( $class->ip(), $apacheRequest->uri, 'LOGOUT' ); | 
| 826 |  |  |  |  |  |  | return $class->goToPortal( '/', 'logout=1' ); | 
| 827 |  |  |  |  |  |  | } | 
| 828 |  |  |  |  |  |  |  | 
| 829 |  |  |  |  |  |  | ## @rmethod int status(Apache2::RequestRec $r) | 
| 830 |  |  |  |  |  |  | # Get the result from the status process and launch a PerlResponseHandler to | 
| 831 |  |  |  |  |  |  | # display it. | 
| 832 |  |  |  |  |  |  | # @param $r Current request | 
| 833 |  |  |  |  |  |  | # @return Apache2::Const::OK | 
| 834 |  |  |  |  |  |  | sub status($$) { | 
| 835 |  |  |  |  |  |  | my ( $class, $r ) = splice @_; | 
| 836 |  |  |  |  |  |  |  | 
| 837 |  |  |  |  |  |  | my $statusOut  = $tsv->{statusOut}; | 
| 838 |  |  |  |  |  |  | my $statusPipe = $tsv->{statusPipe}; | 
| 839 |  |  |  |  |  |  |  | 
| 840 |  |  |  |  |  |  | Lemonldap::NG::Handler::Main::Logger->lmLog( "$class: request for status", | 
| 841 |  |  |  |  |  |  | 'debug' ); | 
| 842 |  |  |  |  |  |  | return $class->abort("$class: status page can not be displayed") | 
| 843 |  |  |  |  |  |  | unless ( $statusPipe and $statusOut ); | 
| 844 |  |  |  |  |  |  | $r->handler("perl-script"); | 
| 845 |  |  |  |  |  |  | print $statusPipe "STATUS" . ( $r->args ? " " . $r->args : '' ) . "\n"; | 
| 846 |  |  |  |  |  |  | my $buf; | 
| 847 |  |  |  |  |  |  | while (<$statusOut>) { | 
| 848 |  |  |  |  |  |  | last if (/^END$/); | 
| 849 |  |  |  |  |  |  | $buf .= $_; | 
| 850 |  |  |  |  |  |  | } | 
| 851 |  |  |  |  |  |  | if ( MP() == 2 ) { | 
| 852 |  |  |  |  |  |  | $r->push_handlers( | 
| 853 |  |  |  |  |  |  | 'PerlResponseHandler' => sub { | 
| 854 |  |  |  |  |  |  | my $r = shift; | 
| 855 |  |  |  |  |  |  | $r->content_type('text/html; charset=UTF-8'); | 
| 856 |  |  |  |  |  |  | $r->print($buf); | 
| 857 |  |  |  |  |  |  | OK; | 
| 858 |  |  |  |  |  |  | } | 
| 859 |  |  |  |  |  |  | ); | 
| 860 |  |  |  |  |  |  | } | 
| 861 |  |  |  |  |  |  | else { | 
| 862 |  |  |  |  |  |  | $r->push_handlers( | 
| 863 |  |  |  |  |  |  | 'PerlHandler' => sub { | 
| 864 |  |  |  |  |  |  | my $r = shift; | 
| 865 |  |  |  |  |  |  | $r->content_type('text/html; charset=UTF-8'); | 
| 866 |  |  |  |  |  |  | $r->send_http_header; | 
| 867 |  |  |  |  |  |  | $r->print($buf); | 
| 868 |  |  |  |  |  |  | OK; | 
| 869 |  |  |  |  |  |  | } | 
| 870 |  |  |  |  |  |  | ); | 
| 871 |  |  |  |  |  |  | } | 
| 872 |  |  |  |  |  |  | return OK; | 
| 873 |  |  |  |  |  |  | } | 
| 874 |  |  |  |  |  |  |  | 
| 875 |  |  |  |  |  |  | ## @rmethod protected int redirectFilter(string url, Apache2::Filter f) | 
| 876 |  |  |  |  |  |  | # Launch the current HTTP request then redirects the user to $url. | 
| 877 |  |  |  |  |  |  | # Used by logout_app and logout_app_sso targets | 
| 878 |  |  |  |  |  |  | # @param $url URL to redirect the user | 
| 879 |  |  |  |  |  |  | # @param $f Current Apache2::Filter object | 
| 880 |  |  |  |  |  |  | # @return Apache2::Const::OK | 
| 881 |  |  |  |  |  |  | sub redirectFilter { | 
| 882 |  |  |  |  |  |  | my $class = shift; | 
| 883 |  |  |  |  |  |  | my $url   = shift; | 
| 884 |  |  |  |  |  |  | my $f     = shift; | 
| 885 |  |  |  |  |  |  | unless ( $f->ctx ) { | 
| 886 |  |  |  |  |  |  |  | 
| 887 |  |  |  |  |  |  | # Here, we can use Apache2 functions instead of lmSetHeaderOut because | 
| 888 |  |  |  |  |  |  | # this function is used only with Apache2. | 
| 889 |  |  |  |  |  |  | $f->r->status(REDIRECT); | 
| 890 |  |  |  |  |  |  | $f->r->status_line("303 See Other"); | 
| 891 |  |  |  |  |  |  | $f->r->headers_out->unset('Location'); | 
| 892 |  |  |  |  |  |  | $f->r->err_headers_out->set( 'Location' => $url ); | 
| 893 |  |  |  |  |  |  | $f->ctx(1); | 
| 894 |  |  |  |  |  |  | } | 
| 895 |  |  |  |  |  |  | while ( $f->read( my $buffer, 1024 ) ) { | 
| 896 |  |  |  |  |  |  | } | 
| 897 |  |  |  |  |  |  | $class->updateStatus( | 
| 898 |  |  |  |  |  |  | ( | 
| 899 |  |  |  |  |  |  | $datas->{ $tsv->{whatToTrace} } | 
| 900 |  |  |  |  |  |  | ? $datas->{ $tsv->{whatToTrace} } | 
| 901 |  |  |  |  |  |  | : $f->r->connection->remote_ip | 
| 902 |  |  |  |  |  |  | ), | 
| 903 |  |  |  |  |  |  | 'filter', | 
| 904 |  |  |  |  |  |  | 'REDIRECT' | 
| 905 |  |  |  |  |  |  | ); | 
| 906 |  |  |  |  |  |  | return OK; | 
| 907 |  |  |  |  |  |  | } | 
| 908 |  |  |  |  |  |  |  | 
| 909 |  |  |  |  |  |  | ## @rmethod protected int isUnprotected() | 
| 910 |  |  |  |  |  |  | # @return 0 if URI is protected, | 
| 911 |  |  |  |  |  |  | # UNPROTECT if it is unprotected by "unprotect", | 
| 912 |  |  |  |  |  |  | # SKIP if is is unprotected by "skip" | 
| 913 |  |  |  |  |  |  | sub isUnprotected { | 
| 914 |  |  |  |  |  |  | my ( $class, $uri ) = splice @_; | 
| 915 |  |  |  |  |  |  | my $vhost = $apacheRequest->hostname; | 
| 916 |  |  |  |  |  |  | for ( my $i = 0 ; $i < $tsv->{locationCount}->{$vhost} ; $i++ ) { | 
| 917 |  |  |  |  |  |  | if ( $uri =~ $tsv->{locationRegexp}->{$vhost}->[$i] ) { | 
| 918 |  |  |  |  |  |  | return $tsv->{locationProtection}->{$vhost}->[$i]; | 
| 919 |  |  |  |  |  |  | } | 
| 920 |  |  |  |  |  |  | } | 
| 921 |  |  |  |  |  |  | return $tsv->{defaultProtection}->{$vhost}; | 
| 922 |  |  |  |  |  |  | } | 
| 923 |  |  |  |  |  |  |  | 
| 924 |  |  |  |  |  |  | 1; |