diff --git a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Plugins/Impersonation.pm b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Plugins/Impersonation.pm index c261fbe27..c807485ef 100644 --- a/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Plugins/Impersonation.pm +++ b/lemonldap-ng-portal/lib/Lemonldap/NG/Portal/Plugins/Impersonation.pm @@ -55,7 +55,6 @@ sub init { sub run { my ( $self, $req ) = @_; - my $savedHttpSession = $req->{sessionInfo}->{_httpSession} //= ''; my $spoofId = $req->param('spoofId') || $req->{user}; $self->logger->debug("No impersonation required") if ( $spoofId eq $req->{user} ); @@ -142,8 +141,7 @@ sub run { $req->steps( [ $self->p->validSession, @{ $self->p->endAuth } ] ); # Restore _httpSession for double Cookies - $req->{sessionInfo}->{_httpSession} = $savedHttpSession - if $savedHttpSession; + $req->{sessionInfo}->{_httpSession} = $req->{sessionInfo}->{real__httpSession} if $req->{sessionInfo}->{real__httpSession}; return $statut; } diff --git a/lemonldap-ng-portal/t/68-Impersonation-with-doubleCookies.t b/lemonldap-ng-portal/t/68-Impersonation-with-doubleCookies.t new file mode 100644 index 000000000..65a3b83db --- /dev/null +++ b/lemonldap-ng-portal/t/68-Impersonation-with-doubleCookies.t @@ -0,0 +1,309 @@ +use Test::More; +use strict; +use IO::String; + +BEGIN { + require 't/test-lib.pm'; +} + +my $res; + +my $client = LLNG::Manager::Test->new( { + ini => { + logLevel => 'error', + authentication => 'Demo', + userDB => 'Same', + loginHistoryEnabled => 0, + brutForceProtection => 0, + portalMainLogo => 'common/logos/logo_llng_old.png', + requireToken => 0, + checkUser => 1, + impersonationRule => '$uid ne "msmith"', + impersonationIdRule => '$uid ne "msmith"', + impersonationPrefix => 'testPrefix_', + securedCookie => 2, + https => 1, + checkUserDisplayPersistentInfo => 0, + checkUserDisplayEmptyValues => 0, + impersonationMergeSSOgroups => 0, + macros => { + test_impersonation => '"$testPrefix__user/$_user"', + _whatToTrace => + '$_auth eq "SAML" ? "$_user@$_idpConfKey" : $_user', + }, + } + } +); + +## Try to impersonate with a bad spoofed user +ok( $res = $client->_get( '/', accept => 'text/html' ), 'Get Menu', ); +count(1); +my ( $host, $url, $query ) = + expectForm( $res, '#', undef, 'user', 'password', 'spoofId' ); + +$query =~ s/user=/user=rtyler/; +$query =~ s/password=/password=rtyler/; +$query =~ s/spoofId=/spoofId=dwho*/; +ok( + $res = $client->_post( + '/', + IO::String->new($query), + length => length($query), + accept => 'text/html', + ), + 'Auth query' +); +ok( $res->[2]->[0] =~ m%%, ' PE40 found' ) + or explain( $res->[2]->[0], "PE40 - Bad formed user" ); +count(2); + +ok( $res = $client->_get( '/', accept => 'text/html' ), 'Get Menu', ); +count(1); +expectForm( $res, '#', undef, 'user', 'password', 'spoofId' ); + +## Try to impersonate with a forbidden identity +ok( $res = $client->_get( '/', accept => 'text/html' ), 'Get Menu', ); +count(1); +( $host, $url, $query ) = + expectForm( $res, '#', undef, 'user', 'password', 'spoofId' ); + +$query =~ s/user=/user=rtyler/; +$query =~ s/password=/password=rtyler/; +$query =~ s/spoofId=/spoofId=msmith/; +ok( + $res = $client->_post( + '/', + IO::String->new($query), + length => length($query), + accept => 'text/html', + ), + 'Auth query' +); +ok( + $res->[2]->[0] =~ +m%
%, + ' PE5 found' +) or explain( $res->[2]->[0], "PE5 - Forbidden identity" ); +count(2); + +ok( $res = $client->_get( '/', accept => 'text/html' ), 'Get Menu', ); +count(1); +expectForm( $res, '#', undef, 'user', 'password', 'spoofId' ); + +## An unauthorized user try to impersonate +ok( $res = $client->_get( '/', accept => 'text/html' ), 'Get Menu', ); +count(1); +( $host, $url, $query ) = + expectForm( $res, '#', undef, 'user', 'password', 'spoofId' ); + +$query =~ s/user=/user=msmith/; +$query =~ s/password=/password=msmith/; +$query =~ s/spoofId=/spoofId=rtyler/; +ok( + $res = $client->_post( + '/', + IO::String->new($query), + length => length($query), + accept => 'text/html', + ), + 'Auth query' +); +ok( + $res->[2]->[0] =~ +m%
%, + ' PE93 found' +) or explain( $res->[2]->[0], "PE93 - Impersonation service not allowed" ); +count(2); + +ok( $res = $client->_get( '/', accept => 'text/html' ), 'Get Menu', ); +count(1); +expectForm( $res, '#', undef, 'user', 'password', 'spoofId' ); + +## An unauthorized user to impersonate tries to authenticate +ok( $res = $client->_get( '/', accept => 'text/html' ), 'Get Menu', ); +count(1); +( $host, $url, $query ) = + expectForm( $res, '#', undef, 'user', 'password', 'spoofId' ); + +$query =~ s/user=/user=msmith/; +$query =~ s/password=/password=msmith/; +ok( + $res = $client->_post( + '/', + IO::String->new($query), + length => length($query), + accept => 'text/html', + ), + 'Auth query' +); +count(1); + +my $id = expectCookie($res); +expectRedirection( $res, 'http://auth.example.com/' ); + +# CheckUser form +# ------------------------ +ok( + $res = $client->_get( + '/checkuser', + cookie => "lemonldap=$id", + accept => 'text/html' + ), + 'CheckUser form', +); +count(1); +( $host, $url, $query ) = + expectForm( $res, undef, '/checkuser', 'user', 'url' ); +ok( $res->[2]->[0] =~ m%%, 'Found trspan="checkUser"' ) + or explain( $res->[2]->[0], 'trspan="checkUser"' ); +count(1); + +ok( + $res = $client->_post( + '/checkuser', + IO::String->new($query), + cookie => "lemonldap=$id", + length => length($query), + accept => 'text/html', + ), + 'POST checkuser' +); +count(1); + +ok( $res->[2]->[0] =~ m%test_impersonation%, + 'Found macro test_impersonation' ) + or explain( $res->[2]->[0], 'test_impersonation' ); +ok( $res->[2]->[0] =~ m%msmith/msmith%, + 'Found msmith/msmith' ) + or explain( $res->[2]->[0], 'Found msmith/msmith' ); +count(2); + +$client->logout($id); + +## Try to authenticate +ok( $res = $client->_get( '/', accept => 'text/html' ), 'Get Menu', ); +count(1); +( $host, $url, $query ) = + expectForm( $res, '#', undef, 'user', 'password', 'spoofId' ); + +$query =~ s/user=/user=rtyler/; +$query =~ s/password=/password=rtyler/; +$query =~ s/spoofId=/spoofId=dwho/; +ok( + $res = $client->_post( + '/', + IO::String->new($query), + length => length($query), + accept => 'text/html', + ), + 'Auth query' +); +count(1); + +$id = expectCookie($res); +expectRedirection( $res, 'http://auth.example.com/' ); + +# CheckUser form +# ------------------------ +ok( + $res = $client->_get( + '/checkuser', + cookie => "lemonldap=$id", + accept => 'text/html' + ), + 'CheckUser form', +); +count(1); +( $host, $url, $query ) = + expectForm( $res, undef, '/checkuser', 'user', 'url' ); +ok( $res->[2]->[0] =~ m%%, 'Found trspan="checkUser"' ) + or explain( $res->[2]->[0], 'trspan="checkUser"' ); +count(1); + +$query =~ s/url=/url=test1.example.com/; + +ok( + $res = $client->_post( + '/checkuser', + IO::String->new($query), + cookie => "lemonldap=$id", + length => length($query), + accept => 'text/html', + ), + 'POST checkuser' +); +count(1); + +( $host, $url, $query ) = + expectForm( $res, undef, '/checkuser', 'user', 'url' ); +ok( $res->[2]->[0] =~ m%%, 'Found trspan="checkUser"' ) + or explain( $res->[2]->[0], 'trspan="checkUser"' ); +ok( + $res->[2]->[0] =~ +m%
%, + 'Found trspan="allowed"' +) or explain( $res->[2]->[0], 'trspan="allowed"' ); +ok( $res->[2]->[0] =~ m%%, 'Found trspan="headers"' ) + or explain( $res->[2]->[0], 'trspan="headers"' ); + +ok( $res->[2]->[0] !~ m%%, + 'trspan="groups_sso" NOT found' ) + or explain( $res->[2]->[0], 'trspan="groups_sso"' ); + +ok( $res->[2]->[0] =~ m%%, 'Found trspan="macros"' ) + or explain( $res->[2]->[0], 'trspan="macros"' ); +ok( $res->[2]->[0] =~ m%%, + 'Found trspan="attributes"' ) + or explain( $res->[2]->[0], 'trspan="attributes"' ); +ok( $res->[2]->[0] =~ m%_userDB%, 'Found _userDB' ) + or explain( $res->[2]->[0], '_userDB' ); +ok( $res->[2]->[0] =~ m%Auth-User%, + 'Found Auth-User' ) + or explain( $res->[2]->[0], 'Header Key: Auth-User' ); +ok( $res->[2]->[0] =~ m%dwho%, 'Found dwho' ) + or explain( $res->[2]->[0], 'Header Value: dwho' ); + +ok( $res->[2]->[0] =~ m%_whatToTrace%, + 'Found _whatToTrace' ) + or explain( $res->[2]->[0], 'Macro Key _whatToTrace' ); +ok( $res->[2]->[0] =~ m%testPrefix_groups%, + 'Found testPrefix_groups' ) + or explain( $res->[2]->[0], 'testPrefix_groups' ); +ok( $res->[2]->[0] =~ m%su%, 'Found su' ) + or explain( $res->[2]->[0], 'su' ); +ok( $res->[2]->[0] =~ m%testPrefix_uid%, + 'Found testPrefix_uid' ) + or explain( $res->[2]->[0], 'testPrefix_groups' ); +ok( $res->[2]->[0] =~ m%rtyler%, 'Found rtyler' ) + or explain( $res->[2]->[0], 'su' ); +ok( $res->[2]->[0] =~ m%test_impersonation%, + 'Found macro test_impersonation' ) + or explain( $res->[2]->[0], 'test_impersonation' ); +ok( $res->[2]->[0] =~ m%rtyler/dwho%, + 'Found rtyler/dwo' ) + or explain( $res->[2]->[0], 'Found rtyler/dwo' ); +count(16); + +my @attributes = map /(.+)?<\/td>/g, $res->[2]->[0]; +ok( scalar @attributes == 62, 'Found 61 attributes' ) + or print STDERR ( @attributes < 62 ) + ? "Missing attributes -> " . scalar @attributes + : "Too much attributes -> " . scalar @attributes; +ok( $attributes[0] eq '_auth', '_auth' ) or print STDERR Dumper( \@attributes ); +ok( $attributes[1] eq 'Demo', 'Demo' ) or print STDERR Dumper( \@attributes ); +ok( $attributes[2] eq '_httpSession', '_httpSession' ) or print STDERR Dumper( \@attributes ); +ok( $attributes[28] eq 'uid', 'uid' ) or print STDERR Dumper( \@attributes ); +ok( $attributes[30] eq 'testPrefix__auth', 'testPrefix__auth' ) + or print STDERR Dumper( \@attributes ); +ok( $attributes[32] eq 'testPrefix__httpSession', 'testPrefix__httpSession' ) + or print STDERR Dumper( \@attributes ); +ok( $attributes[60] eq 'testPrefix_uid', 'testPrefix_uid' ) + or print STDERR Dumper( \@attributes ); +ok( $attributes[61] eq 'rtyler', 'rtyler' ) + or print STDERR Dumper( \@attributes ); +count(9); + +$client->logout($id); +clean_sessions(); + +done_testing( count() );