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

View File

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

View File

@ -134,7 +134,7 @@ sub _tie_session {
my %h;
eval {
# SOAP session module must be directly tied
# SOAP/REST session module must be directly tied
if ( $self->storageModule =~ /^Lemonldap::NG::Common::Apache::Session/ )
{
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'
},
'loginHistoryEnabled' => {
'default' => 1,
'default' => 0,
'type' => 'bool'
},
'logoutServices' => {

View File

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

File diff suppressed because one or more lines are too long

View File

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

View File

@ -146,7 +146,17 @@ sub newSession {
or return $self->p->sendError( $req, undef, 400 );
$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 )
unless ($session);
@ -168,8 +178,18 @@ sub updateSession {
my $infos = $req->jsonBodyToObj
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
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 );
return $self->p->sendJSONresponse( $req, { result => 1 } );

View File

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