Authentication succeeds (#595)
This commit is contained in:
parent
a8c64033a6
commit
4fe318a5ea
|
@ -152,7 +152,8 @@ sub init {
|
|||
sub handler { _mustBeDefined(@_) }
|
||||
|
||||
sub sendHtml {
|
||||
my ( $self, $req, $template ) = @_;
|
||||
my ( $self, $req, $template, %args ) = @_;
|
||||
$args{headers} ||= [];
|
||||
my $htpl;
|
||||
$template = $self->templateDir . "/$template.tpl";
|
||||
return $self->sendError( $req, "Unable to read $template", 500 )
|
||||
|
@ -190,7 +191,7 @@ sub sendHtml {
|
|||
'debug' );
|
||||
|
||||
# Set headers
|
||||
my $hdrs = [ 'Content-Type' => 'text/html' ];
|
||||
my $hdrs = [ 'Content-Type' => 'text/html', @{ $args{headers} } ];
|
||||
unless ( $self->logLevel eq 'debug' ) {
|
||||
push @$hdrs,
|
||||
ETag => "LMNG-manager-$VERSION",
|
||||
|
|
|
@ -126,7 +126,7 @@ has CONTENT_LENGTH => (
|
|||
);
|
||||
has error => ( is => 'rw', isa => 'Str', default => '' );
|
||||
|
||||
has respHeaders => ( is => 'rw', isa => 'HashRef', default => sub { {} } );
|
||||
has respHeaders => ( is => 'rw', isa => 'ArrayRef', default => sub { [] } );
|
||||
|
||||
# JSON parser
|
||||
sub jsonBodyToObj {
|
||||
|
|
|
@ -95,7 +95,7 @@ sub unset_header_in {
|
|||
sub set_header_out {
|
||||
my ( $class, %headers ) = @_;
|
||||
while ( my ( $h, $v ) = each %headers ) {
|
||||
$request->{respHeaders}->{"-$h"} = $v;
|
||||
push @{ $request->{respHeaders} }, "-$h" => $v;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ sub new {
|
|||
"You don't have rights to access this page" );
|
||||
}
|
||||
elsif ($res) {
|
||||
print $self->header( -status => $res, %{ $request->{respHeaders} } );
|
||||
print $self->header( -status => $res, @{ $request->{respHeaders} } );
|
||||
$self->quit;
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -14,7 +14,7 @@ our $VERSION = '2.0.0';
|
|||
our $keepConf = 0;
|
||||
|
||||
sub import {
|
||||
if($_[1] eq 'keepConf') {
|
||||
if($_[1] and $_[1] eq 'keepConf') {
|
||||
$keepConf = 1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ extends 'Lemonldap::NG::Handler::PSGI';
|
|||
sub init {
|
||||
my $self = shift;
|
||||
$self->api('Lemonldap::NG::Handler::PSGI::API::Server');
|
||||
my $tmp = $self->SUPER::init(@_);
|
||||
my $tmp = $self->SUPER::init(@_);
|
||||
}
|
||||
|
||||
## @method void _run()
|
||||
|
@ -64,18 +64,19 @@ sub _run {
|
|||
sub handler {
|
||||
my ( $self, $req ) = @_;
|
||||
my $hdrs = $req->{respHeaders};
|
||||
$req->{respHeaders} = {};
|
||||
$req->{respHeaders} = [];
|
||||
my @convertedHdrs =
|
||||
( 'Content-Length' => 0, Cookie => ( $req->cookies // '' ) );
|
||||
my $i = 0;
|
||||
foreach my $k ( keys %$hdrs ) {
|
||||
while( my $k = shift @$hdrs ) {
|
||||
my $v = shift @$hdrs;
|
||||
if ( $k =~ /^(?:Lm-Remote-User|Cookie)$/ ) {
|
||||
push @convertedHdrs, $k, $hdrs->{$k};
|
||||
push @convertedHdrs, $k, $v;
|
||||
}
|
||||
else {
|
||||
$i++;
|
||||
push @convertedHdrs, "Headername$i", $k, "Headervalue$i",
|
||||
$hdrs->{$k}, $k, $hdrs->{$k};
|
||||
push @convertedHdrs, "Headername$i", $k, "Headervalue$i", $v, $k,
|
||||
$v;
|
||||
}
|
||||
}
|
||||
return [ 200, \@convertedHdrs, [] ];
|
||||
|
|
|
@ -52,7 +52,7 @@ sub newRequest {
|
|||
# @param user string username
|
||||
sub set_user {
|
||||
my ( $class, $user ) = @_;
|
||||
$request->{respHeaders}->{'Lm-Remote-User'} = $user;
|
||||
push @{ $request->respHeaders }, 'Lm-Remote-User' => $user;
|
||||
}
|
||||
|
||||
## @method string header_in(string header)
|
||||
|
@ -91,7 +91,7 @@ sub unset_header_in {
|
|||
sub set_header_out {
|
||||
my ( $class, %headers ) = @_;
|
||||
while ( my ( $h, $v ) = each %headers ) {
|
||||
$request->{respHeaders}->{$h} = $v;
|
||||
push @{ $request->respHeaders }, $h => $v;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -14,36 +14,38 @@ sub set_header_in {
|
|||
my ( $class, %headers ) = @_;
|
||||
for my $k ( keys %headers ) {
|
||||
$Lemonldap::NG::Handler::PSGI::API::request->{ cgiName($k) } =
|
||||
$Lemonldap::NG::Handler::PSGI::API::request->{respHeaders}->{$k} =
|
||||
$headers{$k};
|
||||
}
|
||||
push @{ $Lemonldap::NG::Handler::PSGI::API::request->{respHeaders} },
|
||||
%headers;
|
||||
}
|
||||
|
||||
sub unset_header_in {
|
||||
my ( $class, $header ) = @_;
|
||||
delete $Lemonldap::NG::Handler::PSGI::API::request->{respHeaders}
|
||||
->{$header};
|
||||
$Lemonldap::NG::Handler::PSGI::API::request->{respHeaders} =
|
||||
[ grep { $_ ne $header }
|
||||
@{ $Lemonldap::NG::Handler::PSGI::API::request->{respHeaders} } ];
|
||||
$header =~ s/-/_/g;
|
||||
delete $Lemonldap::NG::Handler::PSGI::API::request->{ cgiName($header) };
|
||||
}
|
||||
|
||||
# Inheritence is broken in this case with Debian >= jessie
|
||||
*setServerSignature = *Lemonldap::NG::Handler::PSGI::API::setServerSignature;
|
||||
*thread_share = *Lemonldap::NG::Handler::PSGI::API::thread_share ;
|
||||
*newRequest = *Lemonldap::NG::Handler::PSGI::API::newRequest ;
|
||||
*set_user = *Lemonldap::NG::Handler::PSGI::API::set_user ;
|
||||
*header_in = *Lemonldap::NG::Handler::PSGI::API::header_in ;
|
||||
*set_header_out = *Lemonldap::NG::Handler::PSGI::API::set_header_out ;
|
||||
*hostname = *Lemonldap::NG::Handler::PSGI::API::hostname ;
|
||||
*remote_ip = *Lemonldap::NG::Handler::PSGI::API::remote_ip ;
|
||||
*is_initial_req = *Lemonldap::NG::Handler::PSGI::API::is_initial_req ;
|
||||
*args = *Lemonldap::NG::Handler::PSGI::API::args ;
|
||||
*uri = *Lemonldap::NG::Handler::PSGI::API::uri ;
|
||||
*uri_with_args = *Lemonldap::NG::Handler::PSGI::API::uri_with_args ;
|
||||
*unparsed_uri = *Lemonldap::NG::Handler::PSGI::API::unparsed_uri ;
|
||||
*thread_share = *Lemonldap::NG::Handler::PSGI::API::thread_share;
|
||||
*newRequest = *Lemonldap::NG::Handler::PSGI::API::newRequest;
|
||||
*set_user = *Lemonldap::NG::Handler::PSGI::API::set_user;
|
||||
*header_in = *Lemonldap::NG::Handler::PSGI::API::header_in;
|
||||
*set_header_out = *Lemonldap::NG::Handler::PSGI::API::set_header_out;
|
||||
*hostname = *Lemonldap::NG::Handler::PSGI::API::hostname;
|
||||
*remote_ip = *Lemonldap::NG::Handler::PSGI::API::remote_ip;
|
||||
*is_initial_req = *Lemonldap::NG::Handler::PSGI::API::is_initial_req;
|
||||
*args = *Lemonldap::NG::Handler::PSGI::API::args;
|
||||
*uri = *Lemonldap::NG::Handler::PSGI::API::uri;
|
||||
*uri_with_args = *Lemonldap::NG::Handler::PSGI::API::uri_with_args;
|
||||
*unparsed_uri = *Lemonldap::NG::Handler::PSGI::API::unparsed_uri;
|
||||
*get_server_port = *Lemonldap::NG::Handler::PSGI::API::get_server_port;
|
||||
*method = *Lemonldap::NG::Handler::PSGI::API::method ;
|
||||
*print = *Lemonldap::NG::Handler::PSGI::API::print ;
|
||||
*cgiName = *Lemonldap::NG::Handler::PSGI::API::cgiName ;
|
||||
*addToHtmlHead = *Lemonldap::NG::Handler::PSGI::API::addToHtmlHead ;
|
||||
*method = *Lemonldap::NG::Handler::PSGI::API::method;
|
||||
*print = *Lemonldap::NG::Handler::PSGI::API::print;
|
||||
*cgiName = *Lemonldap::NG::Handler::PSGI::API::cgiName;
|
||||
*addToHtmlHead = *Lemonldap::NG::Handler::PSGI::API::addToHtmlHead;
|
||||
1;
|
||||
|
|
|
@ -68,7 +68,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->{respHeaders} };
|
||||
return $res;
|
||||
};
|
||||
}
|
||||
|
@ -85,7 +85,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->{respHeaders} } ], [ $req->{respBody} ] ];
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -101,11 +101,11 @@ sub _authAndTrace {
|
|||
if ( $res < 300 ) {
|
||||
$self->lmLog( 'User authenticated, calling handler()', 'debug' );
|
||||
$res = $self->handler($req);
|
||||
push @{ $res->[1] }, %{ $req->{respHeaders} };
|
||||
push @{ $res->[1] }, @{ $req->{respHeaders} };
|
||||
return $res;
|
||||
}
|
||||
else {
|
||||
my %h = $req->{respHeaders} ? %{ $req->{respHeaders} } : ();
|
||||
my %h = $req->{respHeaders} ? @{ $req->{respHeaders} } : ();
|
||||
my $s = $self->api->tsv->{portal}->() . "?lmError=$res";
|
||||
$s =
|
||||
'<html><head><title>Redirection</title></head><body>'
|
||||
|
|
|
@ -23,7 +23,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->respHeaders },
|
||||
Cookie => ( $req->{Cookie} // '' );
|
||||
return $res;
|
||||
};
|
||||
|
|
|
@ -57,6 +57,8 @@ sub _run {
|
|||
$req->userData( $self->api->datas );
|
||||
}
|
||||
else {
|
||||
# Unset headers (handler adds a Location header)
|
||||
$req->respHeaders( [] );
|
||||
$self->routes( $self->unAuthRoutes );
|
||||
}
|
||||
return $self->handler($req);
|
||||
|
|
|
@ -49,9 +49,9 @@ count(2);
|
|||
# Check headers
|
||||
%h = @{ $res->[1] };
|
||||
ok( $h{'Headername1'} eq 'Auth-User', 'Headername1 is set to "Auth-User"' )
|
||||
or explain( $h, 'Headername1 => "Auth-User"' );
|
||||
or explain( \%h, 'Headername1 => "Auth-User"' );
|
||||
ok( $h{'Headervalue1'} eq 'dwho', 'Headervalue1 is set to "dwho"' )
|
||||
or explain( $h, 'Headervalue1 => "dwho"' );
|
||||
or explain( \%h, 'Headervalue1 => "dwho"' );
|
||||
count(2);
|
||||
|
||||
# Denied query
|
||||
|
|
|
@ -241,6 +241,7 @@ sub store {
|
|||
# Main session
|
||||
my $session = $self->getApacheSession( $req->{id}, 0, $self->{force} );
|
||||
return PE_APACHESESSIONERROR unless ($session);
|
||||
$req->id( $session->{id} );
|
||||
|
||||
# Compute unsecure cookie value if needed
|
||||
if ( $self->conf->{securedCookie} == 3 ) {
|
||||
|
@ -253,7 +254,9 @@ sub store {
|
|||
foreach my $k ( keys %{ $req->{sessionInfo} } ) {
|
||||
next unless defined $req->{sessionInfo}->{$k};
|
||||
my $displayValue = $req->{sessionInfo}->{$k};
|
||||
if ( $self->conf->{hiddenAttributes} =~ /\b$k\b/ ) {
|
||||
if ( $self->conf->{hiddenAttributes}
|
||||
and $self->conf->{hiddenAttributes} =~ /\b$k\b/ )
|
||||
{
|
||||
$displayValue = '****';
|
||||
}
|
||||
$self->lmLog( "Store $displayValue in session key $k", 'debug' );
|
||||
|
@ -267,27 +270,26 @@ sub store {
|
|||
|
||||
sub buildCookie {
|
||||
my ( $self, $req ) = @_;
|
||||
push @{ $req->respCookies },
|
||||
$self->cookie(
|
||||
name => $self->{cookieName},
|
||||
value => $self->{id},
|
||||
domain => $self->{domain},
|
||||
push @{ $req->respHeaders },
|
||||
'Set-Cookie' => $self->cookie(
|
||||
name => $self->conf->{cookieName},
|
||||
value => $req->{id},
|
||||
domain => $self->conf->{domain},
|
||||
path => "/",
|
||||
secure => $self->{securedCookie},
|
||||
HttpOnly => $self->{httpOnly},
|
||||
expires => $self->{cookieExpiration},
|
||||
@_,
|
||||
secure => $self->conf->{securedCookie},
|
||||
HttpOnly => $self->conf->{httpOnly},
|
||||
expires => $self->conf->{cookieExpiration},
|
||||
);
|
||||
if ( $self->conf->{securedCookie} >= 2 ) {
|
||||
push @{ $req->respCookies },
|
||||
$self->cookie(
|
||||
name => $self->{cookieName} . "http",
|
||||
value => $self->{sessionInfo}->{_httpSession},
|
||||
domain => $self->{domain},
|
||||
push @{ $req->respHeaders },
|
||||
'Set-Cookie' => $self->cookie(
|
||||
name => $self->conf->{cookieName} . "http",
|
||||
value => $req->{sessionInfo}->{_httpSession},
|
||||
domain => $self->conf->{domain},
|
||||
path => "/",
|
||||
secure => 0,
|
||||
HttpOnly => $self->{httpOnly},
|
||||
expires => $self->{cookieExpiration},
|
||||
HttpOnly => $self->conf->{httpOnly},
|
||||
expires => $self->conf->{cookieExpiration},
|
||||
@_,
|
||||
);
|
||||
}
|
||||
|
@ -301,8 +303,8 @@ sub cookie {
|
|||
$res[0] .= "=$h{value}";
|
||||
foreach (qw(domain path expires max_age)) {
|
||||
my $f = $_;
|
||||
s/_/-/g;
|
||||
push @res, "$_=$h{$f}" if ( $h{$f} );
|
||||
$f =~ s/_/-/g;
|
||||
push @res, "$f=$h{$_}" if ( $h{$_} );
|
||||
}
|
||||
return join( '; ', @res );
|
||||
}
|
||||
|
|
|
@ -115,13 +115,20 @@ sub do {
|
|||
];
|
||||
}
|
||||
else {
|
||||
return $self->senfJSONresponse(
|
||||
{ result => 1, message => 'Authenticated' } );
|
||||
return $self->sendJSONresponse(
|
||||
$req,
|
||||
{ result => 1, message => 'Authenticated' },
|
||||
headers => $req->respHeaders
|
||||
);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ($err) {
|
||||
return $self->sendHtml( $req, $req->template || 'login' );
|
||||
return $self->sendHtml(
|
||||
$req,
|
||||
$req->template || 'login',
|
||||
headers => $req->respHeaders
|
||||
);
|
||||
}
|
||||
else {
|
||||
return $self->autoRedirect($req);
|
||||
|
@ -165,13 +172,99 @@ sub autoRedirect {
|
|||
|
||||
# Redirection should be made if urldc defined
|
||||
if ( $req->datas->{urldc} ) {
|
||||
return [ 302, [ Location => $req->datas->{urldc} ], [] ];
|
||||
return [
|
||||
302, [ Location => $req->datas->{urldc}, @{ $req->respHeaders } ],
|
||||
[]
|
||||
];
|
||||
}
|
||||
else {
|
||||
return $self->sendHtml( $req->template || 'menu' );
|
||||
}
|
||||
}
|
||||
|
||||
# Try to recover the session corresponding to id and return session datas.
|
||||
# If $id is set to undef or if $force is true, return a new session.
|
||||
# @param id session reference
|
||||
# @param noInfo do not set Apache REMOTE_USER
|
||||
# @param force Force session creation if it does not exist
|
||||
# return Lemonldap::NG::Common::Session object
|
||||
sub getApacheSession {
|
||||
my ( $self, $id, $noInfo, $force ) = @_;
|
||||
|
||||
my $as = Lemonldap::NG::Common::Session->new(
|
||||
{
|
||||
storageModule => $self->conf->{globalStorage},
|
||||
storageModuleOptions => $self->conf->{globalStorageOptions},
|
||||
cacheModule => $self->conf->{localSessionStorage},
|
||||
cacheModuleOptions => $self->conf->{localSessionStorageOptions},
|
||||
id => $id,
|
||||
force => $force,
|
||||
kind => "SSO",
|
||||
}
|
||||
);
|
||||
|
||||
if ( $as->error ) {
|
||||
$self->lmLog( $as->error, 'debug' );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( $id and !$force and !$as->data ) {
|
||||
$self->lmLog( "Session $id not found", 'debug' );
|
||||
return;
|
||||
}
|
||||
|
||||
unless ($noInfo) {
|
||||
$self->setApacheUser( $as->data->{ $self->{whatToTrace} } )
|
||||
if ($id);
|
||||
$self->{id} = $as->id;
|
||||
}
|
||||
return $as;
|
||||
}
|
||||
|
||||
# Try to recover the persistent session corresponding to uid and return session datas.
|
||||
sub getPersistentSession {
|
||||
my ( $self, $uid ) = @_;
|
||||
|
||||
return unless defined $uid;
|
||||
|
||||
# Compute persistent identifier
|
||||
my $pid = $self->_md5hash($uid);
|
||||
|
||||
my $ps = Lemonldap::NG::Common::Session->new(
|
||||
{
|
||||
storageModule => $self->{persistentStorage},
|
||||
storageModuleOptions => $self->{persistentStorageOptions},
|
||||
cacheModule => $self->{localSessionStorage},
|
||||
cacheModuleOptions => $self->{localSessionStorageOptions},
|
||||
id => $pid,
|
||||
force => 1,
|
||||
kind => "Persistent",
|
||||
}
|
||||
);
|
||||
|
||||
if ( $ps->error ) {
|
||||
$self->lmLog( $ps->error, 'debug' );
|
||||
}
|
||||
|
||||
# Set _session_uid if not already present
|
||||
unless ( defined $ps->data->{_session_uid} ) {
|
||||
$ps->update( { '_session_uid' => $uid } );
|
||||
}
|
||||
|
||||
# Set _utime if not already present
|
||||
unless ( defined $ps->data->{_utime} ) {
|
||||
$ps->update( { '_utime' => time } );
|
||||
}
|
||||
|
||||
return $ps;
|
||||
}
|
||||
|
||||
# Return md5(s)
|
||||
sub _md5hash {
|
||||
my ( $self, $s ) = @_;
|
||||
return substr( Digest::MD5::md5_hex($s), 0, 32 );
|
||||
}
|
||||
|
||||
# Check if an URL's domain name is declared in LL::NG config or is declared as
|
||||
# trusted domain
|
||||
sub isTrustedUrl {
|
||||
|
|
|
@ -11,23 +11,16 @@ ok( $res->[0] == 401, 'Response is 401' ) or explain( $res, 401 );
|
|||
count(2);
|
||||
|
||||
ok(
|
||||
$res = eval {
|
||||
&client->jsonPostResponse(
|
||||
'/', '',
|
||||
IO::String->new('user=dwho&password=dwho'),
|
||||
'application/x-www-form-urlencoded', 23
|
||||
);
|
||||
},
|
||||
'Auth query'
|
||||
)
|
||||
or explain(
|
||||
&client->_post(
|
||||
$res = &client->_post(
|
||||
'/', '',
|
||||
IO::String->new('user=dwho&password=dwho'),
|
||||
'application/x-www-form-urlencoded', 23
|
||||
),
|
||||
200
|
||||
);
|
||||
'Auth query'
|
||||
);
|
||||
print STDERR Dumper($res);
|
||||
count(1);
|
||||
|
||||
clean_sessions();
|
||||
|
||||
done_testing( count() );
|
||||
|
|
0
lemonldap-ng-portal/t/sessions/lock/.exists
Normal file
0
lemonldap-ng-portal/t/sessions/lock/.exists
Normal file
|
@ -43,4 +43,11 @@ sub explain {
|
|||
print STDERR "Expect $ref, get $get\n";
|
||||
}
|
||||
|
||||
sub clean_sessions {
|
||||
opendir D, 't/sessions' or die $!;
|
||||
foreach ( grep { /^[^\.]/ } readdir(D) ) {
|
||||
unlink "t/sessions/$_", "t/sessions/lock/Apache-Session-$_.lock";
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
||||
|
|
Loading…
Reference in New Issue
Block a user