Minimize persistentSession tie/untie (#713, #LEMONLDAP-1173)

This commit is contained in:
Xavier Guimard 2017-02-27 20:48:00 +00:00
parent babb7f9230
commit c0c67fd0bd
9 changed files with 82 additions and 39 deletions

View File

@ -2,10 +2,13 @@ package Lemonldap::NG::Common::Apache::Session::REST;
use strict; use strict;
use Lemonldap::NG::Common::UserAgent; use Lemonldap::NG::Common::UserAgent;
use Lemonldap::NG::Common::Apache::Session::Generate::SHA256;
use JSON qw(from_json to_json); use JSON qw(from_json to_json);
our $VERSION = '2.0.0'; our $VERSION = '2.0.0';
our @ISA = qw(Lemonldap::NG::Common::Apache::Session::Generate::SHA256);
# PUBLIC INTERFACE # PUBLIC INTERFACE
# Constructor for Perl TIE mechanism. See perltie(3) for more. # Constructor for Perl TIE mechanism. See perltie(3) for more.
@ -29,6 +32,10 @@ sub TIEHASH {
die "unexistant session $session_id" die "unexistant session $session_id"
unless ( $self->get($session_id) ); unless ( $self->get($session_id) );
} }
elsif ( $args->{setId} ) {
$self->{data}->{_session_id} = $args->{setId};
$self->newSession;
}
else { else {
die "unable to create session" die "unable to create session"
unless ( $self->newSession() ); unless ( $self->newSession() );
@ -151,7 +158,7 @@ sub get {
my $res = $self->getJson("$id") or return 0; my $res = $self->getJson("$id") or return 0;
$self->{data} = $res; $self->{data} = $res;
$self->cache->set( "soap$id", $self->{data} ) if $self->{localStorage}; $self->cache->set( "rest$id", $self->{data} ) if $self->{localStorage};
return $self->{data}; return $self->{data};
} }
@ -161,30 +168,33 @@ sub get {
# @return User datas (just the session ID) # @return User datas (just the session ID)
sub newSession { sub newSession {
my $self = shift; my $self = shift;
my $req = HTTP::Request->new( POST => $self->base ); $self->generate unless ( $self->{data}->{_session_id} );
$req->content( to_json( { _utime => time } ) ); $self->{data}->{_utime} = time;
$req->header( 'Content-Type' => 'application/json' );
my $resp = $self->ua->request($req);
if ( $resp->is_success ) {
my $res;
eval { $res = from_json( $resp->content ) };
if ( $@ or !$res->{result} ) {
die "Unable to create session: bad REST response $@";
}
$self->{data} = $res->{session};
}
else {
die "REST server returns " . $resp->status_line;
}
# Set cache #my $req = HTTP::Request->new( POST => $self->base );
if ( $self->{localStorage} ) { #$req->content( to_json( { _utime => time } ) );
my $id = "rest" . $self->{data}->{_session_id}; #$req->header( 'Content-Type' => 'application/json' );
if ( $self->cache->get($id) ) { #my $resp = $self->ua->request($req);
$self->cache->remove($id); #if ( $resp->is_success ) {
} # my $res;
$self->cache->set( $id, $self->{data} ); # eval { $res = from_json( $resp->content ) };
} # if ( $@ or !$res->{result} ) {
# die "Unable to create session: bad REST response $@";
# }
# $self->{data} = $res->{session};
#}
#else {
# die "REST server returns " . $resp->status_line;
#}
## Set cache
#if ( $self->{localStorage} ) {
# my $id = "rest" . $self->{data}->{_session_id};
# if ( $self->cache->get($id) ) {
# $self->cache->remove($id);
# }
# $self->cache->set( $id, $self->{data} );
#}
return $self->{data}; return $self->{data};
} }
@ -197,7 +207,7 @@ sub save {
# Update session in cache # Update session in cache
if ( $self->{localStorage} ) { if ( $self->{localStorage} ) {
my $id = "soap" . $self->{data}->{_session_id}; my $id = "rest" . $self->{data}->{_session_id};
if ( $self->cache->get($id) ) { if ( $self->cache->get($id) ) {
$self->cache->remove($id); $self->cache->remove($id);
} }
@ -207,9 +217,15 @@ sub save {
# REST # REST
my $req = my $req =
HTTP::Request->new( PUT => $self->base . $self->{data}->{_session_id} ); HTTP::Request->new( PUT => $self->base . $self->{data}->{_session_id} );
eval {
$self->{data}->{__secret} =
Lemonldap::NG::Handler::Main->tsv->{cipher}->encrypt(1);
};
$req->content( to_json( $self->{data} ) ); $req->content( to_json( $self->{data} ) );
delete $self->{data}->{__secret};
$req->header( 'Content-Type' => 'application/json' ); $req->header( 'Content-Type' => 'application/json' );
my $resp = $self->ua->request($req); my $resp = $self->ua->request($req);
if ( $resp->is_success ) { if ( $resp->is_success ) {
my $res; my $res;
eval { $res = from_json( $resp->content ) }; eval { $res = from_json( $resp->content ) };
@ -231,7 +247,7 @@ sub delete {
# Remove session from cache # Remove session from cache
if ( $self->{localStorage} ) { if ( $self->{localStorage} ) {
my $id = "soap" . $self->{data}->{_session_id}; my $id = "rest" . $self->{data}->{_session_id};
if ( $self->cache->get($id) ) { if ( $self->cache->get($id) ) {
$self->cache->remove($id); $self->cache->remove($id);
} }

View File

@ -101,7 +101,6 @@ sub defaultValues {
'locationRules' => { 'locationRules' => {
'default' => 'deny' 'default' => 'deny'
}, },
'loginHistoryEnabled' => 1,
'logoutServices' => {}, 'logoutServices' => {},
'macros' => {}, 'macros' => {},
'mailCharset' => 'utf-8', 'mailCharset' => 'utf-8',

View File

@ -134,7 +134,7 @@ sub _tie_session {
my %h; my %h;
eval { eval {
# SOAP session module must be directly tied # SOAP/REST session module must be directly tied
if ( $self->storageModule =~ /^Lemonldap::NG::Common::Apache::Session/ ) if ( $self->storageModule =~ /^Lemonldap::NG::Common::Apache::Session/ )
{ {
tie %h, $self->storageModule, $self->id, tie %h, $self->storageModule, $self->id,

View File

@ -1307,7 +1307,7 @@ qr/^(?:(?:(?:(?:[a-zA-Z0-9][-a-zA-Z0-9]*)?[a-zA-Z0-9])[.])*(?:[a-zA-Z][-a-zA-Z0-
'type' => 'ruleContainer' 'type' => 'ruleContainer'
}, },
'loginHistoryEnabled' => { 'loginHistoryEnabled' => {
'default' => 1, 'default' => 0,
'type' => 'bool' 'type' => 'bool'
}, },
'logoutServices' => { 'logoutServices' => {

View File

@ -576,7 +576,6 @@ sub attributes {
loginHistoryEnabled => { loginHistoryEnabled => {
default => 0, default => 0,
type => 'bool', type => 'bool',
default => 1,
documentation => 'Enable login history', documentation => 'Enable login history',
}, },
portalDisplayLoginHistory => { portalDisplayLoginHistory => {

File diff suppressed because one or more lines are too long

View File

@ -346,6 +346,8 @@ sub getPersistentSession {
# Compute persistent identifier # Compute persistent identifier
my $pid = $self->_md5hash($uid); my $pid = $self->_md5hash($uid);
$info->{_session_uid} = $uid;
my $ps = Lemonldap::NG::Common::Session->new( my $ps = Lemonldap::NG::Common::Session->new(
{ {
storageModule => $self->conf->{persistentStorage}, storageModule => $self->conf->{persistentStorage},
@ -363,12 +365,12 @@ sub getPersistentSession {
# Set _session_uid if not already present # Set _session_uid if not already present
unless ( defined $ps->data->{_session_uid} ) { unless ( defined $ps->data->{_session_uid} ) {
$ps->update( { '_session_uid' => $uid } ); $ps->update( { _session_uid => $uid } );
} }
# Set _utime if not already present # Set _utime if not already present
unless ( defined $ps->data->{_utime} ) { unless ( defined $ps->data->{_utime} ) {
$ps->update( { '_utime' => time } ); $ps->update( { _utime => time } );
} }
return $ps; return $ps;
@ -728,7 +730,9 @@ sub tplParams {
sub registerLogin { sub registerLogin {
my ( $self, $req ) = @_; my ( $self, $req ) = @_;
return unless ( defined $req->authResult ); return
unless ( $self->conf->{loginHistoryEnabled}
and defined $req->authResult );
my $history = $req->sessionInfo->{loginHistory} ||= {}; my $history = $req->sessionInfo->{loginHistory} ||= {};
my $type = ( $req->authResult > 0 ? 'failed' : 'success' ) . 'Login'; my $type = ( $req->authResult > 0 ? 'failed' : 'success' ) . 'Login';
$history->{$type} ||= []; $history->{$type} ||= [];

View File

@ -146,7 +146,17 @@ sub newSession {
or return $self->p->sendError( $req, undef, 400 ); or return $self->p->sendError( $req, undef, 400 );
$infos->{_utime} = time(); $infos->{_utime} = time();
my $session = $self->getApacheSession($mod, undef, $infos); my $force = 0;
if ( my $s = delete $infos->{__secret} ) {
if ( $self->conf->{cipher}->decrypt($s) == 1 ) {
$force = 1;
}
else {
$self->userLogger->error('Bad key, force denied');
}
}
my $session = $self->getApacheSession( $mod, undef, $infos, $force );
return $self->p->sendError( $req, 'Unable to create session', 500 ) return $self->p->sendError( $req, 'Unable to create session', 500 )
unless ($session); unless ($session);
@ -168,8 +178,18 @@ sub updateSession {
my $infos = $req->jsonBodyToObj my $infos = $req->jsonBodyToObj
or return $self->p->sendError( $req, undef, 400 ); or return $self->p->sendError( $req, undef, 400 );
# Get secret if given
my $force = 0;
if ( my $s = delete $infos->{__secret} ) {
if ( $self->conf->{cipher}->decrypt($s) == 1 ) {
$force = 1;
}
else {
$self->userLogger->error('Bad key, force denied');
}
}
# Get session and store info # Get session and store info
my $session = $self->getApacheSession( $mod, $id, $infos ) my $session = $self->getApacheSession( $mod, $id, $infos, $force )
or return $self->p->sendError( $req, 'Session id does not exists', 400 ); or return $self->p->sendError( $req, 'Session id does not exists', 400 );
return $self->p->sendJSONresponse( $req, { result => 1 } ); return $self->p->sendJSONresponse( $req, { result => 1 } );

View File

@ -40,6 +40,11 @@ count(2);
expectRedirection( $res, 'http://auth.sp.com' ); expectRedirection( $res, 'http://auth.sp.com' );
$spId = expectCookie($res); $spId = expectCookie($res);
# Test auth
ok( $res = $sp->_get( '/', cookie => "lemonldap=$spId" ), 'Auth test' );
count(1);
expectOK($res);
# Test other REST queries # Test other REST queries
switch ('issuer'); switch ('issuer');
@ -182,10 +187,10 @@ sub sp {
globalStorageOptions => { globalStorageOptions => {
baseUrl => 'http://auth.idp.com/sessions/global/' baseUrl => 'http://auth.idp.com/sessions/global/'
}, },
persistentStorage => 'Apache::Session::File', persistentStorage =>
'Lemonldap::NG::Common::Apache::Session::REST',
persistentStorageOptions => { persistentStorageOptions => {
Directory => 't/sessions', baseUrl => 'http://auth.idp.com/sessions/persistent/'
LockDirectory => 't/sessions/lock',
}, },
}, },
} }