WIP - Append checkHeaders function (#1658)

This commit is contained in:
Christophe Maudoux 2019-02-24 22:07:55 +01:00
parent 557539805a
commit e296d1d407

View File

@ -1,7 +1,7 @@
# Main running methods file # Main running methods file
package Lemonldap::NG::Handler::Main::Run; package Lemonldap::NG::Handler::Main::Run;
our $VERSION = '2.0.2'; our $VERSION = '2.0.3';
package Lemonldap::NG::Handler::Main; package Lemonldap::NG::Handler::Main;
@ -44,20 +44,20 @@ sub getStatus {
if ( $ENV{LLNGSTATUSHOST} ) { if ( $ENV{LLNGSTATUSHOST} ) {
require IO::Socket::INET; require IO::Socket::INET;
foreach ( 64322 .. 64331 ) { foreach ( 64322 .. 64331 ) {
if ( $statusOut = if ( $statusOut
IO::Socket::INET->new( Proto => 'udp', LocalPort => $_ ) ) = IO::Socket::INET->new( Proto => 'udp', LocalPort => $_ ) )
{ {
$args = $args = ' host='
' host=' . ( $ENV{LLNGSTATUSCLIENT} || 'localhost' ) . ":$_"; . ( $ENV{LLNGSTATUSCLIENT} || 'localhost' ) . ":$_";
last; last;
} }
} }
return $class->abort( $req, return $class->abort( $req,
"$class: status page can not be displayed, unable to open socket" ) "$class: status page can not be displayed, unable to open socket"
unless ($statusOut); ) unless ($statusOut);
} }
return $class->abort( $req, "$class: status page can not be displayed" ) return $class->abort( $req, "$class: status page can not be displayed" )
unless ( $statusPipe and $statusOut ); unless ( $statusPipe and $statusOut );
my $q = $req->{env}->{QUERY_STRING} || ''; my $q = $req->{env}->{QUERY_STRING} || '';
if ( $q =~ /\s/ ) { if ( $q =~ /\s/ ) {
$class->logger->error("Bad characters in query"); $class->logger->error("Bad characters in query");
@ -84,12 +84,12 @@ sub checkType {
if ( time() - $class->lastCheck > $class->checkTime ) { if ( time() - $class->lastCheck > $class->checkTime ) {
die("$class: No configuration found") die("$class: No configuration found")
unless ( $class->checkConf ); unless ( $class->checkConf );
} }
my $vhost = $class->resolveAlias($req); my $vhost = $class->resolveAlias($req);
return ( defined $class->tsv->{type}->{$vhost} ) return ( defined $class->tsv->{type}->{$vhost} )
? $class->tsv->{type}->{$vhost} ? $class->tsv->{type}->{$vhost}
: 'Main'; : 'Main';
} }
## @rmethod int run ## @rmethod int run
@ -125,7 +125,7 @@ sub run {
my ($cond); my ($cond);
( $cond, $protection ) = $class->conditionSub($rule) if ($rule); ( $cond, $protection ) = $class->conditionSub($rule) if ($rule);
$protection = $class->isUnprotected( $req, $uri ) || 0 $protection = $class->isUnprotected( $req, $uri ) || 0
unless ( defined $protection ); unless ( defined $protection );
if ( $protection == $class->SKIP ) { if ( $protection == $class->SKIP ) {
$class->logger->debug("Access control skipped"); $class->logger->debug("Access control skipped");
@ -150,7 +150,7 @@ sub run {
# AUTHORIZATION # AUTHORIZATION
return ( $class->forbidden( $req, $session ), $session ) return ( $class->forbidden( $req, $session ), $session )
unless ( $class->grant( $req, $session, $uri, $cond ) ); unless ( $class->grant( $req, $session, $uri, $cond ) );
$class->updateStatus( $req, 'OK', $class->updateStatus( $req, 'OK',
$session->{ $class->tsv->{whatToTrace} } ); $session->{ $class->tsv->{whatToTrace} } );
@ -168,8 +168,8 @@ sub run {
# Log access granted # Log access granted
$class->logger->debug( "User " $class->logger->debug( "User "
. $session->{ $class->tsv->{whatToTrace} } . $session->{ $class->tsv->{whatToTrace} }
. " was granted to access to $uri" ); . " was granted to access to $uri" );
# Catch POST rules # Catch POST rules
$class->postOutputFilter( $req, $session, $uri ); $class->postOutputFilter( $req, $session, $uri );
@ -192,7 +192,7 @@ sub run {
# Redirect user to the portal # Redirect user to the portal
$class->logger->info("No cookie found") $class->logger->info("No cookie found")
unless ($id); unless ($id);
# if the cookie was fetched, a log is sent by retrieveSession() # if the cookie was fetched, a log is sent by retrieveSession()
$class->updateStatus( $req, $id ? 'EXPIRED' : 'REDIRECT' ); $class->updateStatus( $req, $id ? 'EXPIRED' : 'REDIRECT' );
@ -243,10 +243,10 @@ sub lmLog {
sub checkMaintenanceMode { sub checkMaintenanceMode {
my ( $class, $req ) = @_; my ( $class, $req ) = @_;
my $vhost = $class->resolveAlias($req); my $vhost = $class->resolveAlias($req);
my $_maintenance = my $_maintenance
( defined $class->tsv->{maintenance}->{$vhost} ) = ( defined $class->tsv->{maintenance}->{$vhost} )
? $class->tsv->{maintenance}->{$vhost} ? $class->tsv->{maintenance}->{$vhost}
: $class->tsv->{maintenance}->{_}; : $class->tsv->{maintenance}->{_};
if ($_maintenance) { if ($_maintenance) {
$class->logger->debug("Maintenance mode enabled"); $class->logger->debug("Maintenance mode enabled");
@ -272,17 +272,17 @@ sub grant {
} }
} }
for ( for (
my $i = 0 ; my $i = 0;
$i < ( $class->tsv->{locationCount}->{$vhost} || 0 ) ; $i < ( $class->tsv->{locationCount}->{$vhost} || 0 );
$i++ $i++
) )
{ {
if ( $uri =~ $class->tsv->{locationRegexp}->{$vhost}->[$i] ) { if ( $uri =~ $class->tsv->{locationRegexp}->{$vhost}->[$i] ) {
$class->logger->debug( 'Regexp "' $class->logger->debug( 'Regexp "'
. $class->tsv->{locationConditionText}->{$vhost}->[$i] . $class->tsv->{locationConditionText}->{$vhost}->[$i]
. '" match' ); . '" match' );
return $class->tsv->{locationCondition}->{$vhost}->[$i] return $class->tsv->{locationCondition}->{$vhost}->[$i]
->( $req, $session ); ->( $req, $session );
} }
} }
unless ( $class->tsv->{defaultCondition}->{$vhost} ) { unless ( $class->tsv->{defaultCondition}->{$vhost} ) {
@ -319,8 +319,8 @@ sub forbidden {
# Log forbidding # Log forbidding
$class->userLogger->notice( "User " $class->userLogger->notice( "User "
. $session->{ $class->tsv->{whatToTrace} } . $session->{ $class->tsv->{whatToTrace} }
. " was forbidden to access to $vhost$uri" ); . " was forbidden to access to $vhost$uri" );
$class->updateStatus( $req, 'REJECT', $class->updateStatus( $req, 'REJECT',
$session->{ $class->tsv->{whatToTrace} } ); $session->{ $class->tsv->{whatToTrace} } );
@ -377,9 +377,9 @@ sub goToPortal {
$class->logger->debug( $class->logger->debug(
"Redirect $req->{env}->{REMOTE_ADDR} to portal (url was $url)"); "Redirect $req->{env}->{REMOTE_ADDR} to portal (url was $url)");
$class->set_header_out( $req, $class->set_header_out( $req,
'Location' => $class->tsv->{portal}->() 'Location' => $class->tsv->{portal}->()
. "$path?url=$urlc_init" . "$path?url=$urlc_init"
. ( $arg ? "&$arg" : "" ) ); . ( $arg ? "&$arg" : "" ) );
return $class->REDIRECT; return $class->REDIRECT;
} }
@ -389,9 +389,9 @@ sub goToError {
$class->logger->debug( $class->logger->debug(
"Redirect $req->{env}->{REMOTE_ADDR} to lmError (url was $url)"); "Redirect $req->{env}->{REMOTE_ADDR} to lmError (url was $url)");
$class->set_header_out( $req, $class->set_header_out( $req,
'Location' => $class->tsv->{portal}->() 'Location' => $class->tsv->{portal}->()
. "/lmerror/$code" . "/lmerror/$code"
. "?url=$urlc_init" ); . "?url=$urlc_init" );
return $class->REDIRECT; return $class->REDIRECT;
} }
@ -403,12 +403,12 @@ sub fetchId {
my $t = $req->{env}->{HTTP_COOKIE} or return 0; my $t = $req->{env}->{HTTP_COOKIE} or return 0;
my $vhost = $class->resolveAlias($req); my $vhost = $class->resolveAlias($req);
my $lookForHttpCookie = ( $class->tsv->{securedCookie} =~ /^(2|3)$/ my $lookForHttpCookie = ( $class->tsv->{securedCookie} =~ /^(2|3)$/
and not $class->_isHttps( $req, $vhost ) ); and not $class->_isHttps( $req, $vhost ) );
my $cn = $class->tsv->{cookieName}; my $cn = $class->tsv->{cookieName};
my $value = my $value
$lookForHttpCookie = $lookForHttpCookie
? ( $t =~ /${cn}http=([^,; ]+)/o ? $1 : 0 ) ? ( $t =~ /${cn}http=([^,; ]+)/o ? $1 : 0 )
: ( $t =~ /$cn=([^,; ]+)/o ? $1 : 0 ); : ( $t =~ /$cn=([^,; ]+)/o ? $1 : 0 );
if ( $value && $lookForHttpCookie && $class->tsv->{securedCookie} == 3 ) { if ( $value && $lookForHttpCookie && $class->tsv->{securedCookie} == 3 ) {
$value = $class->tsv->{cipher}->decryptHex( $value, "http" ); $value = $class->tsv->{cipher}->decryptHex( $value, "http" );
@ -446,8 +446,8 @@ sub retrieveSession {
# 2. Get the session from cache or backend # 2. Get the session from cache or backend
my $session = $req->data->{session} = ( my $session = $req->data->{session} = (
Lemonldap::NG::Common::Session->new( { Lemonldap::NG::Common::Session->new(
storageModule => $class->tsv->{sessionStorageModule}, { storageModule => $class->tsv->{sessionStorageModule},
storageModuleOptions => $class->tsv->{sessionStorageOptions}, storageModuleOptions => $class->tsv->{sessionStorageOptions},
cacheModule => $class->tsv->{sessionCacheModule}, cacheModule => $class->tsv->{sessionCacheModule},
cacheModuleOptions => $class->tsv->{sessionCacheOptions}, cacheModuleOptions => $class->tsv->{sessionCacheOptions},
@ -464,36 +464,36 @@ sub retrieveSession {
# Verify that session is valid # Verify that session is valid
$class->logger->error( $class->logger->error(
"_utime is not defined. This should not happen. Check if it is well transmitted to handler" "_utime is not defined. This should not happen. Check if it is well transmitted to handler"
) unless $session->data->{_utime}; ) unless $session->data->{_utime};
$class->logger->debug("Check session validity from Handler"); $class->logger->debug("Check session validity from Handler");
$class->logger->debug( "Session timeout -> " . $class->tsv->{timeout} ); $class->logger->debug(
"Session timeout -> " . $class->tsv->{timeout} );
$class->logger->debug( "Session timeoutActivity -> " $class->logger->debug( "Session timeoutActivity -> "
. $class->tsv->{timeoutActivity} . $class->tsv->{timeoutActivity}
. "s" ) . "s" )
if ( $class->tsv->{timeoutActivity} ); if ( $class->tsv->{timeoutActivity} );
$class->logger->debug( $class->logger->debug(
"Session _utime -> " . $session->data->{_utime} ); "Session _utime -> " . $session->data->{_utime} );
$class->logger->debug( "now -> " . $now ); $class->logger->debug( "now -> " . $now );
$class->logger->debug( "_lastSeen -> " . $session->data->{_lastSeen} ) $class->logger->debug( "_lastSeen -> " . $session->data->{_lastSeen} )
if ( $session->data->{_lastSeen} ); if ( $session->data->{_lastSeen} );
my $delta = $now - $session->data->{_lastSeen} my $delta = $now - $session->data->{_lastSeen}
if ( $session->data->{_lastSeen} ); if ( $session->data->{_lastSeen} );
$class->logger->debug( "now - _lastSeen = " . $delta ) $class->logger->debug( "now - _lastSeen = " . $delta )
if ( $session->data->{_lastSeen} ); if ( $session->data->{_lastSeen} );
$class->logger->debug( "Session timeoutActivityInterval -> " $class->logger->debug( "Session timeoutActivityInterval -> "
. $class->tsv->{timeoutActivityInterval} ) . $class->tsv->{timeoutActivityInterval} )
if ( $class->tsv->{timeoutActivityInterval} ); if ( $class->tsv->{timeoutActivityInterval} );
my $ttl = $class->tsv->{timeout} - $now + $session->data->{_utime}; my $ttl = $class->tsv->{timeout} - $now + $session->data->{_utime};
$class->logger->debug( "Session TTL = " . $ttl ); $class->logger->debug( "Session TTL = " . $ttl );
if ( if ($now - $session->data->{_utime} > $class->tsv->{timeout}
$now - $session->data->{_utime} > $class->tsv->{timeout}
or ( $class->tsv->{timeoutActivity} or ( $class->tsv->{timeoutActivity}
and $session->data->{_lastSeen} and $session->data->{_lastSeen}
and $delta > $class->tsv->{timeoutActivity} ) and $delta > $class->tsv->{timeoutActivity} )
) )
{ {
$class->logger->info("Session $id expired"); $class->logger->info("Session $id expired");
@ -503,11 +503,10 @@ sub retrieveSession {
} }
# Update the session to notify activity, if necessary # Update the session to notify activity, if necessary
if ( if ($class->tsv->{timeoutActivity}
$class->tsv->{timeoutActivity} and ( $now - $session->data->{_lastSeen}
and ( $now - $session->data->{_lastSeen} > > $class->tsv->{timeoutActivityInterval} )
$class->tsv->{timeoutActivityInterval} ) )
)
{ {
$req->data->{session}->update( { '_lastSeen' => $now } ); $req->data->{session}->update( { '_lastSeen' => $now } );
$class->data( $session->data ); $class->data( $session->data );
@ -594,9 +593,9 @@ sub _buildUrl {
my $_https = $class->_isHttps( $req, $vhost ); my $_https = $class->_isHttps( $req, $vhost );
my $portString = $class->_getPort( $req, $vhost ); my $portString = $class->_getPort( $req, $vhost );
$portString = ( $portString = (
( $realvhost =~ /:\d+/ ) ( $realvhost =~ /:\d+/ )
or ( $_https && $portString == 443 ) or ( $_https && $portString == 443 )
or ( !$_https && $portString == 80 ) or ( !$_https && $portString == 80 )
) ? '' : ":$portString"; ) ? '' : ":$portString";
my $url = "http" . ( $_https ? "s" : "" ) . "://$realvhost$portString$s"; my $url = "http" . ( $_https ? "s" : "" ) . "://$realvhost$portString$s";
$class->logger->debug("Build URL $url"); $class->logger->debug("Build URL $url");
@ -612,10 +611,10 @@ sub isUnprotected {
my ( $class, $req, $uri ) = @_; my ( $class, $req, $uri ) = @_;
my $vhost = $class->resolveAlias($req); my $vhost = $class->resolveAlias($req);
for ( for (
my $i = 0 ; my $i = 0;
$i < ( $class->tsv->{locationCount}->{$vhost} || 0 ) ; $i < ( $class->tsv->{locationCount}->{$vhost} || 0 );
$i++ $i++
) )
{ {
if ( $uri =~ $class->tsv->{locationRegexp}->{$vhost}->[$i] ) { if ( $uri =~ $class->tsv->{locationRegexp}->{$vhost}->[$i] ) {
return $class->tsv->{locationProtection}->{$vhost}->[$i]; return $class->tsv->{locationProtection}->{$vhost}->[$i];
@ -632,8 +631,8 @@ sub sendHeaders {
if ( defined $class->tsv->{forgeHeaders}->{$vhost} ) { if ( defined $class->tsv->{forgeHeaders}->{$vhost} ) {
# Log headers in debug mode # Log headers in debug mode
my %headers = my %headers
$class->tsv->{forgeHeaders}->{$vhost}->( $req, $session ); = $class->tsv->{forgeHeaders}->{$vhost}->( $req, $session );
foreach my $h ( sort keys %headers ) { foreach my $h ( sort keys %headers ) {
if ( defined( my $v = $headers{$h} ) ) { if ( defined( my $v = $headers{$h} ) ) {
$class->logger->debug("Send header $h with value $v"); $class->logger->debug("Send header $h with value $v");
@ -646,6 +645,23 @@ sub sendHeaders {
} }
} }
sub checkHeaders {
my ( $class, $req, $session ) = @_;
my $vhost = $class->resolveAlias($req);
my $array_headers = [];
if ( defined $class->tsv->{forgeHeaders}->{$vhost} ) {
# Create array of hashes with headers
my %headers
= $class->tsv->{forgeHeaders}->{$vhost}->( $req, $session );
foreach my $h ( sort keys %headers ) {
push @$array_headers, { key => $h, value => $headers{$h} }
if ( defined $headers{$h} );
}
}
return $array_headers;
}
## @rmethod void cleanHeaders() ## @rmethod void cleanHeaders()
# Unset HTTP headers, when sendHeaders is skipped # Unset HTTP headers, when sendHeaders is skipped
sub cleanHeaders { sub cleanHeaders {
@ -665,7 +681,7 @@ sub resolveAlias {
$vhost =~ s/:\d+//; $vhost =~ s/:\d+//;
return $class->tsv->{vhostAlias}->{$vhost} return $class->tsv->{vhostAlias}->{$vhost}
if ( $class->tsv->{vhostAlias}->{$vhost} ); if ( $class->tsv->{vhostAlias}->{$vhost} );
return $vhost if ( $class->tsv->{defaultCondition}->{$vhost} ); return $vhost if ( $class->tsv->{defaultCondition}->{$vhost} );
my $v = $vhost; my $v = $vhost;
while ( $v =~ s/[\w\-]+/\*/ ) { while ( $v =~ s/[\w\-]+/\*/ ) {
@ -738,8 +754,8 @@ sub postOutputFilter {
$class->logger->debug("Filling a html form with fake data"); $class->logger->debug("Filling a html form with fake data");
$class->unset_header_in( $req, "Accept-Encoding" ); $class->unset_header_in( $req, "Accept-Encoding" );
my %postdata = my %postdata = $class->tsv->{outputPostData}->{$vhost}->{$uri}
$class->tsv->{outputPostData}->{$vhost}->{$uri}->( $req, $session ); ->( $req, $session );
my $formParams = $class->tsv->{postFormParams}->{$vhost}->{$uri}; my $formParams = $class->tsv->{postFormParams}->{$vhost}->{$uri};
my $js = $class->postJavascript( $req, \%postdata, $formParams ); my $js = $class->postJavascript( $req, \%postdata, $formParams );
$class->addToHtmlHead( $req, $js ); $class->addToHtmlHead( $req, $js );
@ -756,8 +772,8 @@ sub postInputFilter {
if ( defined( $class->tsv->{inputPostData}->{$vhost}->{$uri} ) ) { if ( defined( $class->tsv->{inputPostData}->{$vhost}->{$uri} ) ) {
$class->logger->debug("Replacing fake data with real form data"); $class->logger->debug("Replacing fake data with real form data");
my %data = my %data = $class->tsv->{inputPostData}->{$vhost}->{$uri}
$class->tsv->{inputPostData}->{$vhost}->{$uri}->( $req, $session ); ->( $req, $session );
foreach ( keys %data ) { foreach ( keys %data ) {
$data{$_} = uri_escape( $data{$_} ); $data{$_} = uri_escape( $data{$_} );
} }
@ -777,32 +793,33 @@ sub postJavascript {
foreach my $name ( keys %$data ) { foreach my $name ( keys %$data ) {
use bytes; use bytes;
my $value = "x" x bytes::length( $data->{$name} ); my $value = "x" x bytes::length( $data->{$name} );
$filler .= $filler
"form.find('input[name=\"$name\"], select[name=\"$name\"], textarea[name=\"$name\"]').val('$value')\n"; .= "form.find('input[name=\"$name\"], select[name=\"$name\"], textarea[name=\"$name\"]').val('$value')\n";
} }
my $submitter = my $submitter
$formParams->{buttonSelector} eq "none" ? "" = $formParams->{buttonSelector} eq "none" ? ""
: $formParams->{buttonSelector} : $formParams->{buttonSelector}
? "form.find('$formParams->{buttonSelector}').click();\n" ? "form.find('$formParams->{buttonSelector}').click();\n"
: "form.submit();\n"; : "form.submit();\n";
my $jqueryUrl = $formParams->{jqueryUrl} || ""; my $jqueryUrl = $formParams->{jqueryUrl} || "";
$jqueryUrl = &{ $class->tsv->{portal} } . "skins/common/js/jquery-1.10.2.js" $jqueryUrl
if ( $jqueryUrl eq "default" ); = &{ $class->tsv->{portal} } . "skins/common/js/jquery-1.10.2.js"
if ( $jqueryUrl eq "default" );
$jqueryUrl = "<script type='text/javascript' src='$jqueryUrl'></script>\n" $jqueryUrl = "<script type='text/javascript' src='$jqueryUrl'></script>\n"
if ($jqueryUrl); if ($jqueryUrl);
return return
$jqueryUrl $jqueryUrl
. "<script type='text/javascript'>\n" . "<script type='text/javascript'>\n"
. "/* script added by Lemonldap::NG */\n" . "/* script added by Lemonldap::NG */\n"
. "jQuery(window).on('load', function() {\n" . "jQuery(window).on('load', function() {\n"
. "var form = jQuery('$form');\n" . "var form = jQuery('$form');\n"
. "form.attr('autocomplete', 'off');\n" . "form.attr('autocomplete', 'off');\n"
. $filler . $filler
. $submitter . "})\n" . $submitter . "})\n"
. "</script>\n"; . "</script>\n";
} }
1; 1;