Authentication succeeds (#595)

This commit is contained in:
Xavier Guimard 2016-04-04 20:39:22 +00:00
parent a8c64033a6
commit 4fe318a5ea
17 changed files with 177 additions and 76 deletions

View File

@ -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",

View File

@ -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 {

View File

@ -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;
}
}

View File

@ -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 {

View File

@ -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;
}
}

View File

@ -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, [] ];

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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>'

View File

@ -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;
};

View File

@ -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);

View File

@ -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

View File

@ -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 );
}

View File

@ -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 {

View File

@ -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() );

View 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;