Minimize persistentSession tie/untie (#713, #LEMONLDAP-1173)
This commit is contained in:
parent
babb7f9230
commit
c0c67fd0bd
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -101,7 +101,6 @@ sub defaultValues {
|
||||||
'locationRules' => {
|
'locationRules' => {
|
||||||
'default' => 'deny'
|
'default' => 'deny'
|
||||||
},
|
},
|
||||||
'loginHistoryEnabled' => 1,
|
|
||||||
'logoutServices' => {},
|
'logoutServices' => {},
|
||||||
'macros' => {},
|
'macros' => {},
|
||||||
'mailCharset' => 'utf-8',
|
'mailCharset' => 'utf-8',
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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' => {
|
||||||
|
|
|
@ -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
|
@ -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} ||= [];
|
||||||
|
|
|
@ -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 } );
|
||||||
|
|
|
@ -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',
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user