Merge branch 'v2.0'
This commit is contained in:
commit
4193f4fb51
|
@ -248,7 +248,7 @@ sub _FileGKFAS {
|
|||
closedir DIR;
|
||||
my %res;
|
||||
for my $f (@t) {
|
||||
open F, "$args->{Directory}/$f";
|
||||
open F, '<', "$args->{Directory}/$f";
|
||||
my $row = join '', <F>;
|
||||
if ( ref($data) eq 'CODE' ) {
|
||||
eval { $res{$f} = &$data( $args->{unserialize}->($row), $f ); };
|
||||
|
@ -288,7 +288,7 @@ sub _PHPGKFAS {
|
|||
closedir DIR;
|
||||
my %res;
|
||||
for my $f (@t) {
|
||||
open F, "$args->{SavePath}/$f";
|
||||
open F, '<', "$args->{SavePath}/$f";
|
||||
my $row = join '', <F>;
|
||||
if ( ref($data) eq 'CODE' ) {
|
||||
$res{$f} =
|
||||
|
|
|
@ -40,7 +40,7 @@ sub available {
|
|||
closedir D;
|
||||
@conf =
|
||||
sort { $a <=> $b }
|
||||
map { /lmConf-(\d+)(?:\.js(?:on))?/ ? ( $1 + 0 ) : () } @conf;
|
||||
map { /lmConf-(\d+)(?:\.js(?:on))?/ ? ( $1 + 0 ) : () } @conf;
|
||||
return @conf;
|
||||
}
|
||||
|
||||
|
@ -106,7 +106,7 @@ sub load {
|
|||
if ($filename) {
|
||||
local $/ = '';
|
||||
my $ret;
|
||||
unless ( open FILE, $filename ) {
|
||||
unless ( open FILE, '<', $filename ) {
|
||||
$Lemonldap::NG::Common::Conf::msg .= "Read error: $!$@";
|
||||
return undef;
|
||||
}
|
||||
|
@ -124,9 +124,9 @@ sub load {
|
|||
|
||||
# Old format
|
||||
elsif ( -e "$self->{dirName}/lmConf-$cfgNum" ) {
|
||||
open FILE, "$self->{dirName}/lmConf-$cfgNum" or die "$!$@";
|
||||
open FILE, '<', "$self->{dirName}/lmConf-$cfgNum" or die "$!$@";
|
||||
local $/ = "";
|
||||
unless ( open FILE, $self->{dirName} . "/lmConf-$cfgNum" ) {
|
||||
unless ( open FILE, '<', $self->{dirName} . "/lmConf-$cfgNum" ) {
|
||||
$Lemonldap::NG::Common::Conf::msg .= "Open file failed: $! \n";
|
||||
return undef;
|
||||
}
|
||||
|
|
|
@ -101,7 +101,7 @@ sub load {
|
|||
$filename = $self->_yamlFile($cfgNum);
|
||||
local $/ = '';
|
||||
my $ret;
|
||||
unless ( open FILE, $filename ) {
|
||||
unless ( open FILE, '<', $filename ) {
|
||||
$Lemonldap::NG::Common::Conf::msg .= "Read error: $!$@";
|
||||
return undef;
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ sub get {
|
|||
|
||||
my $files;
|
||||
foreach my $file (@notif) {
|
||||
unless ( open F, $self->{dirName} . "/$file" ) {
|
||||
unless ( open F, '<', $self->{dirName} . "/$file" ) {
|
||||
$self->logger->error(
|
||||
"Unable to read notification $self->{dirName}/$file");
|
||||
next;
|
||||
|
@ -116,7 +116,8 @@ sub newNotif {
|
|||
return ( 0, 'This notification still exists' ) if ( -e $filename );
|
||||
my $old = ( $filename =~ /(.*?)(?:\.$ext)$/ )[0] . '.done';
|
||||
return ( 0, 'This notification has been done' ) if ( -e $old );
|
||||
open my $F, ">$filename" or return ( 0, "Unable to create $filename ($!)" );
|
||||
open my $F, '>', $filename
|
||||
or return ( 0, "Unable to create $filename ($!)" );
|
||||
binmode($F);
|
||||
print $F $content;
|
||||
return ( 0, "Unable to close $filename ($!)" ) unless ( close $F );
|
||||
|
|
|
@ -122,7 +122,7 @@ sub userError {
|
|||
sub sendJSONresponse {
|
||||
my ( $self, $req, $j, %args ) = @_;
|
||||
$args{code} ||= 200;
|
||||
$args{headers} ||= $req->respHeaders || [];
|
||||
$args{headers} ||= [ $req->spliceHdrs ];
|
||||
my $type = 'application/json; charset=utf-8';
|
||||
if ( ref $j ) {
|
||||
eval { $j = $_json->encode($j); };
|
||||
|
@ -152,9 +152,9 @@ sub sendError {
|
|||
return [
|
||||
$code,
|
||||
[
|
||||
'Content-Type' => 'application/xml; charset=utf-8',
|
||||
@{ $req->respHeaders || [] },
|
||||
'Content-Length' => length($s)
|
||||
'Content-Type' => 'application/xml; charset=utf-8',
|
||||
'Content-Length' => length($s),
|
||||
$req->spliceHdrs,
|
||||
],
|
||||
[$s]
|
||||
];
|
||||
|
@ -189,8 +189,9 @@ body{background:#000;color:#fff;padding:10px 50px;font-family:sans-serif;}a{text
|
|||
return [
|
||||
$code,
|
||||
[
|
||||
'Content-Type' => 'text/html; charset=utf-8',
|
||||
@{ $req->respHeaders || [] }, 'Content-Length' => length($s)
|
||||
'Content-Type' => 'text/html; charset=utf-8',
|
||||
'Content-Length' => length($s),
|
||||
$req->spliceHdrs,
|
||||
],
|
||||
[$s]
|
||||
];
|
||||
|
@ -248,7 +249,7 @@ sub sendHtml {
|
|||
$sc = '.' unless ($sc);
|
||||
$sc =~ s#/*$#/#;
|
||||
$args{code} ||= 200;
|
||||
$args{headers} ||= $req->respHeaders || [];
|
||||
$args{headers} ||= [ $req->spliceHdrs ];
|
||||
my $htpl;
|
||||
|
||||
unless ( ref $template ) {
|
||||
|
|
|
@ -58,6 +58,11 @@ sub respHeaders {
|
|||
return $self->{respHeaders};
|
||||
}
|
||||
|
||||
sub spliceHdrs {
|
||||
my ($self) = @_;
|
||||
return splice @{ $self->{respHeaders} };
|
||||
}
|
||||
|
||||
sub accept { $_[0]->env->{HTTP_ACCEPT} }
|
||||
sub encodings { $_[0]->env->{HTTP_ACCEPT_ENCODING} }
|
||||
sub languages { $_[0]->env->{HTTP_ACCEPT_LANGUAGE} }
|
||||
|
@ -192,6 +197,10 @@ Example:
|
|||
# Add header
|
||||
$req->respHeaders->{"X-Key"} = "Value";
|
||||
|
||||
=head2 spliceHdrs
|
||||
|
||||
Returns headers array and flush it.
|
||||
|
||||
=head2 set_param( $key, $value )
|
||||
|
||||
L<Plack::Request> param() method is read-only. This method can be used to
|
||||
|
|
|
@ -69,7 +69,7 @@ sub _run {
|
|||
return sub {
|
||||
my $req = Lemonldap::NG::Common::PSGI::Request->new( $_[0] );
|
||||
my $res = $self->handler($req);
|
||||
push @{ $res->[1] }, @{ $req->{respHeaders} };
|
||||
push @{ $res->[1] }, $req->spliceHdrs;
|
||||
return $res;
|
||||
};
|
||||
}
|
||||
|
@ -89,7 +89,7 @@ sub status {
|
|||
return sub {
|
||||
my $req = Lemonldap::NG::Common::PSGI::Request->new( $_[0] );
|
||||
$self->api->status($req);
|
||||
return [ 200, [ @{ $req->{respHeaders} } ], [ $req->{respBody} ] ];
|
||||
return [ 200, [ $req->spliceHdrs ], [ $req->{respBody} ] ];
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -107,7 +107,7 @@ sub reload {
|
|||
return sub {
|
||||
my $req = Lemonldap::NG::Common::PSGI::Request->new( $_[0] );
|
||||
$self->api->reload($req);
|
||||
return [ 200, [ @{ $req->{respHeaders} } ], [ $req->{respBody} ] ];
|
||||
return [ 200, [ $req->spliceHdrs ], [ $req->{respBody} ] ];
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -132,28 +132,19 @@ sub _authAndTrace {
|
|||
|
||||
if ( $res < 300 ) {
|
||||
if ($noCall) {
|
||||
return [ $res, $req->{respHeaders}, [] ];
|
||||
return [ $res, [ $req->spliceHdrs ], [] ];
|
||||
}
|
||||
else {
|
||||
$self->logger->debug('User authenticated, calling handler()');
|
||||
$res = $self->handler($req);
|
||||
|
||||
# Insert respHeaders in response only if not already set
|
||||
my %hdr1 = @{ $res->[1] };
|
||||
my %hdr2 = @{ $req->{respHeaders} };
|
||||
foreach ( keys %hdr2 ) {
|
||||
unless ( $hdr1{$_} and $hdr2{$_} eq $hdr1{$_} ) {
|
||||
push @{ $res->[1] }, ( $_ => $hdr2{$_} );
|
||||
}
|
||||
}
|
||||
push @{ $res->[1] }, $req->spliceHdrs;
|
||||
return $res;
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
elsif ( $res < 400 ) {
|
||||
return [ $res, $req->{respHeaders}, [] ];
|
||||
return [ $res, [ $req->spliceHdrs ], [] ];
|
||||
}
|
||||
else {
|
||||
my %h = $req->{respHeaders} ? @{ $req->{respHeaders} } : ();
|
||||
my $s = $type->tsv->{portal}->() . "/lmerror/$res";
|
||||
$s =
|
||||
'<html><head><title>Redirection</title></head><body>'
|
||||
|
@ -161,9 +152,15 @@ sub _authAndTrace {
|
|||
. '<h1>Please wait</h1>'
|
||||
. qq{<p>An error occurs, you're going to be redirected to <a href="$s">$s</a>.</p>}
|
||||
. '</body></html>';
|
||||
$h{'Content-Type'} = 'text/html';
|
||||
$h{'Content-Length'} = length $s;
|
||||
return [ $res, [%h], [$s] ];
|
||||
return [
|
||||
$res,
|
||||
[
|
||||
$req->spliceHdrs,
|
||||
'Content-Type' => 'text/html',
|
||||
'Content-Length' => length $s
|
||||
],
|
||||
[$s]
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ BEGIN {
|
|||
sub run {
|
||||
my $class = shift;
|
||||
my $r = $_[0];
|
||||
my $ret = $class->Lemonldap::NG::Handler::Main::run($r);
|
||||
my ( $ret, $session ) = $class->Lemonldap::NG::Handler::Main::run($r);
|
||||
|
||||
# Continue only if user is authorized
|
||||
return $ret unless ( $ret == $class->OK );
|
||||
|
@ -107,7 +107,7 @@ sub run {
|
|||
eval 'use Apache2::Filter' unless ( $INC{"Apache2/Filter.pm"} );
|
||||
|
||||
if ( $INC{"Apache2/Filter.pm"} ) {
|
||||
$r->add_output_filter(
|
||||
$r->{env}->{'psgi.r'}->add_output_filter(
|
||||
sub {
|
||||
my $f = shift;
|
||||
while ( $f->read( my $buffer, 1024 ) ) {
|
||||
|
@ -158,7 +158,7 @@ sub _setToken {
|
|||
$secureTokenExpiration );
|
||||
|
||||
unless ($res) {
|
||||
$class->( "Unable to store secure token $key", 'error' );
|
||||
$class->logger->error("Unable to store secure token $key");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -177,7 +177,7 @@ sub _deleteToken {
|
|||
my $res = $secureTokenMemcachedConnection->delete($key);
|
||||
|
||||
unless ($res) {
|
||||
$class->( "Unable to delete secure token $key", 'error' );
|
||||
$class->logger->error("Unable to delete secure token $key");
|
||||
}
|
||||
else {
|
||||
$class->logger->info("Token $key deleted");
|
||||
|
@ -201,15 +201,14 @@ sub _isAlive {
|
|||
my $total_c = $stats->{'total'}->{'connection_structures'};
|
||||
my $total_i = $stats->{'total'}->{'total_items'};
|
||||
|
||||
$class->(
|
||||
"Memcached connection is alive ($total_c connections / $total_i items)",
|
||||
'debug'
|
||||
$class->logger->debug->(
|
||||
"Memcached connection is alive ($total_c connections / $total_i items)"
|
||||
);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
$class->( "Memcached connection is not alive", 'error' );
|
||||
$class->logger->error("Memcached connection is not alive");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -222,7 +221,7 @@ sub _returnError {
|
|||
my ( $class, $r, $secureTokenAllowOnError ) = @_;
|
||||
|
||||
if ($secureTokenAllowOnError) {
|
||||
$class->( "Allow request without secure token", 'debug' );
|
||||
$class->logger->debug("Allow request without secure token");
|
||||
return $class->OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -348,16 +348,18 @@ sub sessionStorageInit {
|
|||
if ( $conf->{status} ) {
|
||||
my $params = "";
|
||||
if ( $class->tsv->{sessionCacheModule} ) {
|
||||
require Data::Dumper;
|
||||
$params = ' '
|
||||
. $class->tsv->{sessionCacheModule} . ','
|
||||
. Data::Dumper->new( [ $class->tsv->{sessionCacheOptions} ] )
|
||||
->Terse(1)->Indent(0)->Dump; # To send params on one line
|
||||
$params = ' ' . join(
|
||||
',',
|
||||
$class->tsv->{sessionCacheModule} . map {
|
||||
"$_ => "
|
||||
. $class->tsv->{sessionCacheOptions}->{$_}
|
||||
} keys %{ $class->tsv->{sessionCacheOptions} // {} }
|
||||
);
|
||||
}
|
||||
$class->tsv->{statusPipe}->print("RELOADCACHE $params\n");
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
## @imethod void headersInit(hashRef args)
|
||||
|
|
|
@ -147,7 +147,9 @@ sub run {
|
|||
|
||||
# ACCOUNTING (1. Inform web server)
|
||||
$class->set_user( $req, $session->{ $class->tsv->{whatToTrace} } );
|
||||
$class->set_custom( $req, $session->{ $class->tsv->{customToTrace} } );
|
||||
$class->set_custom( $req, $session->{ $class->tsv->{customToTrace} } )
|
||||
if $class->tsv->{customToTrace}
|
||||
and $session->{ $class->tsv->{customToTrace} };
|
||||
|
||||
# AUTHORIZATION
|
||||
return ( $class->forbidden( $req, $session ), $session )
|
||||
|
@ -409,7 +411,7 @@ sub fetchId {
|
|||
my $value =
|
||||
$lookForHttpCookie
|
||||
? ( $t =~ /${cn}http=([^,; ]+)/o ? $1 : 0 )
|
||||
: ( $t =~ /$cn=([^,; ]+)/o ? $1 : 0 );
|
||||
: ( $t =~ /$cn=([^,; ]+)/o ? $1 : 0 );
|
||||
|
||||
if ( $value && $lookForHttpCookie && $class->tsv->{securedCookie} == 3 ) {
|
||||
$value = $class->tsv->{cipher}->decryptHex( $value, "http" );
|
||||
|
|
|
@ -47,7 +47,7 @@ sub addAuthRouteWithRedirect {
|
|||
sub _auth_and_redirect {
|
||||
my ( $self, $req ) = @_;
|
||||
$self->api->goToPortal( $req, $req->{env}->{REQUEST_URI} );
|
||||
return [ 302, $req->respHeaders, [] ];
|
||||
return [ 302, [$req->spliceHdrs], [] ];
|
||||
}
|
||||
|
||||
sub defaultAuthRoute {
|
||||
|
@ -71,6 +71,7 @@ sub _run {
|
|||
if ( $res->[0] < 300 ) {
|
||||
$self->routes( $self->authRoutes );
|
||||
$req->userData( $self->api->data );
|
||||
$req->respHeaders($res->[1]);
|
||||
}
|
||||
elsif ( $res->[0] != 403 and not $req->data->{noTry} ) {
|
||||
|
||||
|
@ -85,15 +86,7 @@ sub _run {
|
|||
return $res;
|
||||
}
|
||||
$res = $self->handler($req);
|
||||
|
||||
# Insert respHeaders in response only if not already set
|
||||
my %hdr1 = @{ $res->[1] };
|
||||
my %hdr2 = @{ $req->{respHeaders} };
|
||||
foreach ( keys %hdr2 ) {
|
||||
unless ( $hdr1{$_} and $hdr2{$_} eq $hdr1{$_} ) {
|
||||
push @{ $res->[1] }, ( $_ => $hdr2{$_} );
|
||||
}
|
||||
}
|
||||
push @{ $res->[1] }, $req->spliceHdrs;
|
||||
return $res;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ sub _run {
|
|||
return sub {
|
||||
my $req = Lemonldap::NG::Common::PSGI::Request->new( $_[0] );
|
||||
my $res = $self->_authAndTrace($req);
|
||||
push @{ $res->[1] }, @{ $req->respHeaders },
|
||||
push @{ $res->[1] }, $req->spliceHdrs,
|
||||
Cookie => ( $req->{Cookie} // '' );
|
||||
return $res;
|
||||
};
|
||||
|
|
|
@ -65,13 +65,10 @@ sub _run {
|
|||
#@param $req Lemonldap::NG::Common::PSGI::Request
|
||||
sub handler {
|
||||
my ( $self, $req ) = @_;
|
||||
my $hdrs = $req->{respHeaders};
|
||||
$req->{respHeaders} = [];
|
||||
my @convertedHdrs =
|
||||
( 'Content-Length' => 0, Cookie => ( $req->env->{HTTP_COOKIE} // '' ) );
|
||||
my $i = 0;
|
||||
while ( my $k = shift @$hdrs ) {
|
||||
my $v = shift @$hdrs;
|
||||
while ( my ( $k, $v ) = splice( @{ $req->{respHeaders} }, 0, 2 ) ) {
|
||||
if ( $k =~ /^(?:Lm-Remote-(?:User|Custom)|Cookie)$/ ) {
|
||||
push @convertedHdrs, $k, $v;
|
||||
}
|
||||
|
|
|
@ -53,9 +53,9 @@ count(2);
|
|||
|
||||
my @headers = grep { /service|^XFromVH$/ } @{ $res->[1] };
|
||||
my @values = grep { /\.example\.com|^$sessionId$/ } @{ $res->[1] };
|
||||
ok( @headers == 4, 'Found 4 service headers' )
|
||||
ok( @headers == 2, 'Found 2 service headers' )
|
||||
or print STDERR Data::Dumper::Dumper( $res->[1] );
|
||||
ok( @values == 4, 'Found 4 service header values' )
|
||||
ok( @values == 2, 'Found 2 service header values' )
|
||||
or print STDERR Data::Dumper::Dumper( $res->[1] );
|
||||
count(2);
|
||||
|
||||
|
@ -75,9 +75,9 @@ count(2);
|
|||
|
||||
@headers = grep { /service|^XFromVH$/ } @{ $res->[1] };
|
||||
@values = grep { /\.example\.com|^$sessionId$/ } @{ $res->[1] };
|
||||
ok( @headers == 4, 'Found 4 service headers' )
|
||||
ok( @headers == 2, 'Found 2 service headers' )
|
||||
or print STDERR Data::Dumper::Dumper( $res->[1] );
|
||||
ok( @values == 4, 'Found 4 service header values' )
|
||||
ok( @values == 2, 'Found 2 service header values' )
|
||||
or print STDERR Data::Dumper::Dumper( $res->[1] );
|
||||
count(2);
|
||||
|
||||
|
@ -116,9 +116,9 @@ count(2);
|
|||
|
||||
@headers = grep { /service|^XFromVH$/ } @{ $res->[1] };
|
||||
@values = grep { /\.example\.com|^$sessionId$/ } @{ $res->[1] };
|
||||
ok( @headers == 4, 'Found 4 service headers' )
|
||||
ok( @headers == 2, 'Found 2 service headers' )
|
||||
or print STDERR Data::Dumper::Dumper( $res->[1] );
|
||||
ok( @values == 4, 'Found 4 service header values' )
|
||||
ok( @values == 2, 'Found 2 service header values' )
|
||||
or print STDERR Data::Dumper::Dumper( $res->[1] );
|
||||
count(2);
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<link rel="shortcut icon" type="image/vnd.microsoft.icon" sizes="16x16 32x32 48x48 64x64 128x128" href="<TMPL_VAR NAME="STATIC_PREFIX">logos/favicon.ico" />
|
||||
<link rel="icon" type="image/vnd.microsoft.icon" sizes="16x16 32x32 48x48 64x64 128x128" href="<TMPL_VAR NAME="STATIC_PREFIX">logos/favicon.ico" />
|
||||
<!-- //if:usedebianlibs
|
||||
|
|
|
@ -506,7 +506,7 @@ t/32-Auth-and-issuer-OIDC-implicit.t
|
|||
t/32-Auth-and-issuer-OIDC-sorted.t
|
||||
t/32-CAS-10.t
|
||||
t/32-OIDC-RP-rule.t
|
||||
t/32-OIDC-Token-Spoof.t
|
||||
t/32-OIDC-Token-Security.t
|
||||
t/33-Auth-and-issuer-OpenID2.t
|
||||
t/34-Auth-Proxy-and-REST-Server.t
|
||||
t/34-Auth-Proxy-and-SOAP-Server.t
|
||||
|
@ -577,7 +577,7 @@ t/66-CDA-with-REST.t
|
|||
t/66-CDA-with-SOAP.t
|
||||
t/66-CDA.t
|
||||
t/67-CheckUser-with-Global-token.t
|
||||
t/67-Checkuser-with-Impersonation-and-whatToTrace.t
|
||||
t/67-CheckUser-with-Impersonation-and-whatToTrace.t
|
||||
t/67-CheckUser-with-issuer-SAML-POST.t
|
||||
t/67-CheckUser-with-token.t
|
||||
t/67-CheckUser.t
|
||||
|
@ -615,6 +615,7 @@ t/77-2F-Mail-with-global-storage.t
|
|||
t/77-2F-Mail.t
|
||||
t/78-2F-Upgrade.t
|
||||
t/90-Translations.t
|
||||
t/99-Dont-load-Dumper.t
|
||||
t/99-pod.t
|
||||
t/gpghome/key.asc
|
||||
t/gpghome/openpgp-revocs.d/9482CEFB055809CBAFE6D71AAB2D5542891D1677.rev
|
||||
|
|
|
@ -85,7 +85,7 @@ sub run {
|
|||
else {
|
||||
|
||||
# Use HTML template
|
||||
$body = $self->loadTemplate(
|
||||
$body = $self->loadMailTemplate(
|
||||
$req,
|
||||
'mail_2fcode',
|
||||
filter => $tr,
|
||||
|
|
|
@ -163,7 +163,7 @@ sub handler {
|
|||
);
|
||||
|
||||
# Redirect
|
||||
return [ 302, [ Location => $urldc, @{ $req->respHeaders } ], [] ];
|
||||
return [ 302, [ Location => $urldc, $req->spliceHdrs ], [] ];
|
||||
|
||||
}
|
||||
|
||||
|
@ -180,7 +180,7 @@ sub handler {
|
|||
[
|
||||
'Content-Type' => 'text/plain',
|
||||
'Content-Length' => 2,
|
||||
@{ $req->respHeaders }
|
||||
$req->spliceHdrs,
|
||||
],
|
||||
['OK']
|
||||
];
|
||||
|
|
|
@ -3,7 +3,6 @@ package Lemonldap::NG::Portal::Lib::Notifications::JSON;
|
|||
use strict;
|
||||
use Mouse;
|
||||
use JSON qw(from_json);
|
||||
use Data::Dumper;
|
||||
|
||||
our $VERSION = '2.1.0';
|
||||
|
||||
|
@ -260,7 +259,8 @@ sub notificationServer {
|
|||
return $self->p->sendError( $req, "Unable to decode JSON file: $@",
|
||||
400 )
|
||||
if ($@);
|
||||
$self->p->logger->debug( "Notification $notif: " . Dumper($json) );
|
||||
$self->p->logger->debug(
|
||||
"Notification $notif: " . $notifs->{$notif} );
|
||||
if ($ref) {
|
||||
push( @$res,
|
||||
map { "$_" => $json->{$_} },
|
||||
|
|
|
@ -81,6 +81,21 @@ has transport => (
|
|||
},
|
||||
);
|
||||
|
||||
sub loadMailTemplate {
|
||||
my ( $self, $req, $name, %prm ) = @_;
|
||||
|
||||
# HTML::Template cache interferes with email translation (#1897)
|
||||
$prm{cache} = 0 unless defined $prm{cache};
|
||||
$prm{params}->{STATIC_PREFIX} = $self->p->staticPrefix;
|
||||
my %extra =
|
||||
$self->p->can('tplParams')
|
||||
? $self->p->tplParams($req)
|
||||
: ();
|
||||
$prm{params}->{$_} = $extra{$_} for keys %extra;
|
||||
|
||||
return $self->loadTemplate( $req, $name, %prm );
|
||||
}
|
||||
|
||||
sub translate {
|
||||
my ( $self, $req ) = @_;
|
||||
|
||||
|
@ -89,7 +104,7 @@ sub translate {
|
|||
my $json = $self->conf->{templateDir} . "/common/mail/$lang_code.json";
|
||||
$json = $self->conf->{templateDir} . '/common/mail/en.json'
|
||||
unless ( -f $json );
|
||||
open F, $json
|
||||
open F, '<', $json
|
||||
or die 'Installation error: '
|
||||
. $!
|
||||
. " ($self->{conf}->{templateDir}/$lang_code.json or $self->{conf}->{templateDir}/common/mail/en.json)";
|
||||
|
|
|
@ -8,7 +8,6 @@ package Lemonldap::NG::Portal::Main;
|
|||
use strict;
|
||||
use Mouse;
|
||||
use JSON;
|
||||
use Data::Dumper;
|
||||
|
||||
use constant CommonPrms => {
|
||||
MAIN_LOGO => 'portalMainLogo',
|
||||
|
@ -139,8 +138,9 @@ sub display {
|
|||
# 1.3 There is a message to display
|
||||
elsif ( my $info = $req->info ) {
|
||||
$self->logger->debug('Display: info detected');
|
||||
$self->logger->debug(
|
||||
'Hidden values -> ' . Dumper( $req->{portalHiddenFormValues} ) );
|
||||
$self->logger->debug('Hidden values :');
|
||||
$self->logger->debug( " $_: " . $req->{portalHiddenFormValues}->{$_} )
|
||||
for keys %{ $req->{portalHiddenFormValues} // {} };
|
||||
$skinfile = 'info';
|
||||
%templateParams = (
|
||||
AUTH_ERROR => $self->error,
|
||||
|
|
|
@ -342,8 +342,7 @@ sub autoRedirect {
|
|||
$req->data->{redirectFormMethod} = "get";
|
||||
}
|
||||
else {
|
||||
return [ 302,
|
||||
[ Location => $req->{urldc}, @{ $req->respHeaders } ], [] ];
|
||||
return [ 302, [ Location => $req->{urldc}, $req->spliceHdrs ], [] ];
|
||||
}
|
||||
}
|
||||
return $self->display($req);
|
||||
|
@ -759,10 +758,12 @@ sub cookie {
|
|||
|
||||
sub _dump {
|
||||
my ( $self, $variable ) = @_;
|
||||
require Data::Dumper;
|
||||
$Data::Dumper::Indent = 0;
|
||||
$Data::Dumper::Useperl = 1;
|
||||
$self->logger->debug( "Dump: " . Data::Dumper::Dumper($variable) );
|
||||
if ( $self->conf->{logLevel} eq 'debug' ) {
|
||||
require Data::Dumper;
|
||||
$Data::Dumper::Indent = 0;
|
||||
$Data::Dumper::Useperl = 1;
|
||||
$self->logger->debug( "Dump: " . Data::Dumper::Dumper($variable) );
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -816,11 +817,11 @@ sub sendHtml {
|
|||
'Pragma' => 'no-cache', # HTTP 1.0
|
||||
'Expires' => '0'; # Proxies
|
||||
|
||||
my @cors = split /;/, $self->cors;
|
||||
if ( $self->conf->{corsEnabled} ) {
|
||||
my @cors = split /;/, $self->cors;
|
||||
push @{ $res->[1] }, @cors;
|
||||
$self->logger->debug(
|
||||
"Apply following CORS policy : " . Data::Dumper::Dumper( \@cors ) );
|
||||
$self->logger->debug('Apply following CORS policy :');
|
||||
$self->logger->debug(" $_") for @cors;
|
||||
}
|
||||
|
||||
# Set authorized URL for POST
|
||||
|
@ -1005,7 +1006,7 @@ sub registerLogin {
|
|||
}
|
||||
|
||||
my $history = $req->sessionInfo->{_loginHistory} ||= {};
|
||||
my $type = ( $req->authResult > 0 ? 'failed' : 'success' ) . 'Login';
|
||||
my $type = ( $req->authResult > 0 ? 'failed' : 'success' ) . 'Login';
|
||||
$history->{$type} ||= [];
|
||||
$self->logger->debug("Current login saved into $type");
|
||||
|
||||
|
@ -1059,7 +1060,7 @@ sub loadTemplate {
|
|||
search_path_on_include => 1,
|
||||
die_on_bad_params => 0,
|
||||
die_on_missing_include => 1,
|
||||
cache => 1,
|
||||
cache => ( defined $prm{cache} ? $prm{cache} : 1 ),
|
||||
global_vars => 0,
|
||||
( $prm{filter} ? ( filter => $prm{filter} ) : () ),
|
||||
);
|
||||
|
|
|
@ -39,7 +39,7 @@ sub hAttr {
|
|||
sub init {
|
||||
my ($self) = @_;
|
||||
my $hd = $self->p->HANDLER;
|
||||
$self->addAuthRoute( checkuser => 'check', ['POST'] );
|
||||
$self->addAuthRoute( checkuser => 'check', ['POST'] );
|
||||
$self->addAuthRouteWithRedirect( checkuser => 'display', ['GET'] );
|
||||
|
||||
# Parse identity rule
|
||||
|
@ -173,10 +173,10 @@ sub check {
|
|||
? 'checkUserMerged'
|
||||
: 'checkUser';
|
||||
if ($compute) {
|
||||
$msg = 'checkUserComputeSession';
|
||||
$msg = 'checkUserComputeSession';
|
||||
$attrs->{authenticationLevel} = $authLevel;
|
||||
$attrs->{_auth} = $authMode;
|
||||
|
||||
|
||||
if ( $self->conf->{impersonationRule} ) {
|
||||
$self->logger->debug("Map real attributes...");
|
||||
my %realAttrs = map {
|
||||
|
@ -270,7 +270,7 @@ sub check {
|
|||
}
|
||||
|
||||
sub display {
|
||||
my ( $self, $req ) = @_;
|
||||
my ( $self, $req ) = @_;
|
||||
my ( $attrs, $array_attrs ) = ( {}, [] );
|
||||
|
||||
$self->logger->debug("Display current session data...");
|
||||
|
@ -420,8 +420,8 @@ sub _splitAttributes {
|
|||
$self->logger->debug("Dispatching attributes...");
|
||||
while (@$attrs) {
|
||||
my $element = shift @$attrs;
|
||||
$self->logger->debug(
|
||||
'Processing element: ' . Data::Dumper::Dumper($element) );
|
||||
$self->logger->debug( "Processing element: $element->{key} => "
|
||||
. ( $element->{value} // '' ) );
|
||||
my $ok = 0;
|
||||
if ( $element->{key} eq 'groups' ) {
|
||||
$self->logger->debug('Key "groups" found');
|
||||
|
@ -450,14 +450,15 @@ sub _splitAttributes {
|
|||
my $prefix = "$self->{conf}->{impersonationPrefix}";
|
||||
while (@$others) {
|
||||
my $element = shift @$others;
|
||||
$self->logger->debug(
|
||||
'Processing attribute: ' . Data::Dumper::Dumper($element) );
|
||||
$self->logger->debug( "Processing attribute $element->{key} => "
|
||||
. ( $element->{value} // '' ) );
|
||||
if ( $element->{key} =~ /^$prefix.+$/ ) {
|
||||
push @$realAttrs, $element;
|
||||
$self->logger->debug(' -> Real attribute');
|
||||
}
|
||||
else {
|
||||
push @$spoofedAttrs, $element;
|
||||
|
||||
#$self->logger->debug(' -> Spoofed attribute');
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ has rules => ( is => 'rw', default => sub { {} } );
|
|||
sub init {
|
||||
my ($self) = @_;
|
||||
my $hd = $self->p->HANDLER;
|
||||
foreach ( keys %{ $self->conf->{grantSessionRules} } ) {
|
||||
foreach ( keys %{ $self->conf->{grantSessionRules} // {} } ) {
|
||||
$self->logger->debug("GrantRule key -> $_");
|
||||
$self->logger->debug(
|
||||
"GrantRule value -> " . $self->conf->{grantSessionRules}->{$_} );
|
||||
|
|
|
@ -334,7 +334,7 @@ sub _reset {
|
|||
else {
|
||||
|
||||
# Use HTML template
|
||||
$body = $self->loadTemplate(
|
||||
$body = $self->loadMailTemplate(
|
||||
$req,
|
||||
'mail_confirm',
|
||||
filter => $tr,
|
||||
|
@ -473,7 +473,7 @@ sub changePwd {
|
|||
else {
|
||||
|
||||
# Use HTML template
|
||||
$body = $self->loadTemplate(
|
||||
$body = $self->loadMailTemplate(
|
||||
$req,
|
||||
'mail_password',
|
||||
filter => $tr,
|
||||
|
|
|
@ -309,7 +309,7 @@ sub _register {
|
|||
my $html = 1;
|
||||
|
||||
# Use HTML template
|
||||
$body = $self->loadTemplate(
|
||||
$body = $self->loadMailTemplate(
|
||||
$req,
|
||||
'mail_register_confirm',
|
||||
filter => $tr,
|
||||
|
@ -369,7 +369,7 @@ sub _register {
|
|||
my $html = 1;
|
||||
|
||||
# Use HTML template
|
||||
$body = $self->loadTemplate(
|
||||
$body = $self->loadMailTemplate(
|
||||
$req,
|
||||
'mail_register_done',
|
||||
filter => $tr,
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
<meta http-equiv="Pragma" content="no-cache" />
|
||||
<meta http-equiv="Expires" content="0" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<!-- //if:usedebianlibs
|
||||
<link rel="stylesheet" type="text/css" href="/javascript/bootstrap4/css/bootstrap.min.css" />
|
||||
<link rel="stylesheet" type="text/css" href="/javascript/font-awesome/css/font-awesome.min.css" />
|
||||
|
|
|
@ -10,10 +10,7 @@ BEGIN {
|
|||
}
|
||||
|
||||
my ( $res, $user, $pwd );
|
||||
my $maintests = 9;
|
||||
my $mailSend = 0;
|
||||
|
||||
my $mail2 = 0;
|
||||
my $maintests = 12;
|
||||
|
||||
SKIP: {
|
||||
eval
|
||||
|
@ -50,7 +47,20 @@ SKIP: {
|
|||
$res = $client->_post(
|
||||
'/resetpwd', IO::String->new($query),
|
||||
length => length($query),
|
||||
accept => 'text/html'
|
||||
accept => 'text/html',
|
||||
cookie => 'llnglanguage=fr',
|
||||
),
|
||||
'Post mail'
|
||||
);
|
||||
like( mail(), qr#<span>Bonjour</span>#, "Found french greeting" );
|
||||
|
||||
# Test another language (#1897)
|
||||
ok(
|
||||
$res = $client->_post(
|
||||
'/resetpwd', IO::String->new($query),
|
||||
length => length($query),
|
||||
accept => 'text/html',
|
||||
cookie => 'llnglanguage=en',
|
||||
),
|
||||
'Post mail'
|
||||
);
|
||||
|
@ -62,6 +72,8 @@ SKIP: {
|
|||
ok( mail() =~ m%Content-Type: image/png; name="logo_llng_old.png"%,
|
||||
'Found custom Main logo in mail' )
|
||||
or print STDERR Dumper( mail() );
|
||||
like( mail(), qr#<span>Hello</span>#, "Found english greeting" );
|
||||
|
||||
ok( mail() =~ m#a href="http://auth.example.com/resetpwd\?(.*?)"#,
|
||||
'Found link in mail' );
|
||||
$query = $1;
|
||||
|
@ -89,8 +101,6 @@ SKIP: {
|
|||
);
|
||||
|
||||
ok( mail() =~ /Your password was changed/, 'Password was changed' );
|
||||
|
||||
#print STDERR Dumper($query);
|
||||
}
|
||||
count($maintests);
|
||||
|
||||
|
|
|
@ -166,7 +166,6 @@ SKIP: {
|
|||
expectAuthenticatedAs( $res, 'davros@badguy.org@idp' );
|
||||
|
||||
# Simple SP access
|
||||
my $res;
|
||||
ok(
|
||||
$res = $sp->_get(
|
||||
'/', accept => 'text/html',
|
||||
|
@ -179,7 +178,7 @@ SKIP: {
|
|||
$res->[1],
|
||||
'Set-Cookie => lemonldapidp=http://auth.idp.com/saml/metadata; domain=.sp.com; path=/'
|
||||
);
|
||||
my ( $host, $url, $s ) =
|
||||
( $host, $url, $s ) =
|
||||
expectAutoPost( $res, 'auth.idp.com', '/saml/singleSignOn',
|
||||
'SAMLRequest' );
|
||||
|
||||
|
@ -195,7 +194,7 @@ SKIP: {
|
|||
'Post SAML request to IdP'
|
||||
);
|
||||
expectOK($res);
|
||||
my $pdata = 'lemonldappdata=' . expectCookie( $res, 'lemonldappdata' );
|
||||
$pdata = 'lemonldappdata=' . expectCookie( $res, 'lemonldappdata' );
|
||||
|
||||
# Try to authenticate with an authorized user to IdP
|
||||
$s = "user=french&password=french&$s";
|
||||
|
@ -254,7 +253,8 @@ SKIP: {
|
|||
),
|
||||
'CheckUser form',
|
||||
);
|
||||
my ( $host, $url, $query ) =
|
||||
my $query;
|
||||
( $host, $url, $query ) =
|
||||
expectForm( $res, undef, '/checkuser', 'user', 'url' );
|
||||
ok( $res->[2]->[0] =~ m%<span trspan="checkUser">%,
|
||||
'Found trspan="checkUser"' )
|
||||
|
@ -263,10 +263,14 @@ SKIP: {
|
|||
or explain( $res->[2]->[0], 'Attribute uid' );
|
||||
ok( $res->[2]->[0] =~ m%<td scope="row">french</td>%, 'Found value french' )
|
||||
or explain( $res->[2]->[0], 'Value french' );
|
||||
ok( $res->[2]->[0] =~ m%<td scope="row">_lassoSessionDump</td>%, 'Found attribute _lassoSessionDump' )
|
||||
ok( $res->[2]->[0] =~ m%<td scope="row">_lassoSessionDump</td>%,
|
||||
'Found attribute _lassoSessionDump' )
|
||||
or explain( $res->[2]->[0], 'Attribute _lassoSessionDump' );
|
||||
ok( $res->[2]->[0] =~ m%ProviderID="http://auth.idp.com/saml/metadata" AssertionID=%, 'Found ProviderID & AssertionID values' )
|
||||
or explain( $res->[2]->[0], 'Provider & Assertion Ids' );
|
||||
ok(
|
||||
$res->[2]->[0] =~
|
||||
m%ProviderID="http://auth.idp.com/saml/metadata" AssertionID=%,
|
||||
'Found ProviderID & AssertionID values'
|
||||
) or explain( $res->[2]->[0], 'Provider & Assertion Ids' );
|
||||
count(6);
|
||||
|
||||
# CheckUser request with an unknown user
|
||||
|
@ -301,7 +305,7 @@ m%<div class="message message-positive alert"><span trspan="PE5"></span></div>%,
|
|||
'POST checkuser'
|
||||
);
|
||||
|
||||
my ( $host, $url, $query ) =
|
||||
( $host, $url, $query ) =
|
||||
expectForm( $res, undef, '/checkuser', 'user', 'url' );
|
||||
ok( $res->[2]->[0] =~ m%<span trspan="checkUser">%,
|
||||
'Found trspan="checkUser"' )
|
||||
|
|
|
@ -197,7 +197,7 @@ ok(
|
|||
);
|
||||
count(3);
|
||||
|
||||
my ( $host, $url, $query ) =
|
||||
( $host, $url, $query ) =
|
||||
expectForm( $res, undef, '/checkuser', 'user', 'url' );
|
||||
ok( $res->[2]->[0] =~ m%<span trspan="checkUser">%, 'Found trspan="checkUser"' )
|
||||
or explain( $res->[2]->[0], 'trspan="checkUser"' );
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
use Test::More tests => 5;
|
||||
|
||||
use_ok('Lemonldap::NG::Portal::Main');
|
||||
|
||||
my ( $p, $app );
|
||||
my $ini = {
|
||||
configStorage => {
|
||||
type => 'File',
|
||||
dirName => 't',
|
||||
},
|
||||
localSessionStorage => 'Cache::FileCache',
|
||||
localSessionStorageOptions => {
|
||||
namespace => 'lemonldap-ng-session',
|
||||
cache_root => 't/',
|
||||
cache_depth => 0,
|
||||
},
|
||||
logLevel => 'error',
|
||||
cookieName => 'lemonldap',
|
||||
domain => 'example.com',
|
||||
templateDir => 'site/templates',
|
||||
staticPrefix => '/static',
|
||||
loginHistoryEnabled => 1,
|
||||
securedCookie => 0,
|
||||
https => 0,
|
||||
portalDisplayResetPassword => 1,
|
||||
portalStatus => 1,
|
||||
cda => 1,
|
||||
notification => 1,
|
||||
portalCheckLogins => 1,
|
||||
stayConnected => 1,
|
||||
bruteForceProtection => 1,
|
||||
grantSessionRules => 1,
|
||||
upgradeSession => 1,
|
||||
autoSigninRules => { a => 1 },
|
||||
checkState => 1,
|
||||
portalForceAuthn => 1,
|
||||
checkUser => 1,
|
||||
impersonationRule => 1,
|
||||
contextSwitchingRule => 1,
|
||||
grantSessionRules => { a => 1 },
|
||||
checkStateSecret => 'x',
|
||||
};
|
||||
|
||||
ok( $p = Lemonldap::NG::Portal::Main->new, 'Portal object' );
|
||||
ok( $p->init($ini), 'Init' );
|
||||
ok( $app = $p->run, 'App' );
|
||||
|
||||
eval { Data::Dumper::Dumper( {} ) };
|
||||
ok( $@, "Portal doesn't depend on Data::Dumper" );
|
Loading…
Reference in New Issue