* Add a new process step (authFinish) run after session store
* Create SAML session linked to real session to store NameID and SessionIndex, in order to use searchOn on them (will not force globalStorage to be compatible with searchOn) * Control SessionIndex sent by IDP on a SLO request is now managed in SP to get the correct local session * This solves issue #51
This commit is contained in:
parent
18bda4be2e
commit
df4198399f
@ -221,6 +221,19 @@ sub extractFormInfo {
|
||||
# (avoid displaying the whole SAML URL in user browser URL field)
|
||||
$self->{mustRedirect} = 1 unless ( $self->{urldc} );
|
||||
|
||||
# Get SessionIndex
|
||||
my $session_index;
|
||||
|
||||
eval {
|
||||
$session_index = $assertion->AuthnStatement()->SessionIndex();
|
||||
};
|
||||
if ( $@ or !defined($session_index) ) {
|
||||
$self->lmLog( "No SessionIndex found", 'debug' );
|
||||
}
|
||||
else {
|
||||
$self->lmLog( "Found SessionIndex $session_index", 'debug' );
|
||||
}
|
||||
|
||||
# Get NameID
|
||||
my $nameid = $login->nameIdentifier;
|
||||
|
||||
@ -232,13 +245,15 @@ sub extractFormInfo {
|
||||
return PE_USERNOTFOUND;
|
||||
}
|
||||
|
||||
$self->lmLog( "Find NameID: $user", 'debug' );
|
||||
$self->lmLog( "Found NameID: $user", 'debug' );
|
||||
$self->{user} = $user;
|
||||
|
||||
# Store Lasso objects
|
||||
$self->{_lassoLogin} = $login;
|
||||
$self->{_idp} = $idp;
|
||||
$self->{_idpConfKey} = $idpConfKey;
|
||||
$self->{_nameID} = $nameid->dump;
|
||||
$self->{_sessionIndex} = $session_index;
|
||||
|
||||
return PE_OK;
|
||||
}
|
||||
@ -412,46 +427,90 @@ sub extractFormInfo {
|
||||
my $session_index = $logout->request()->SessionIndex;
|
||||
my $user = $name_id->content;
|
||||
|
||||
unless ($user) {
|
||||
$self->lmLog( "Fail to get NameID content from logout request",
|
||||
unless ($name_id) {
|
||||
$self->lmLog( "Fail to get NameID from logout request",
|
||||
'error' );
|
||||
$logout_error = 1;
|
||||
}
|
||||
|
||||
$self->lmLog( "Logout request NameID content: $user", 'debug' );
|
||||
|
||||
# Get corresponding session
|
||||
# TODO use SAML sessionIndex
|
||||
# Get SAML sessions with the same NameID
|
||||
my $local_sessions =
|
||||
$self->{globalStorage}
|
||||
->searchOn( $self->{globalStorageOptions}, "_user", $user, );
|
||||
$self->{samlStorage}->searchOn( $self->{samlStorageOptions},
|
||||
"_nameID", $name_id->dump );
|
||||
|
||||
if ( my @local_sessions_keys = keys %$local_sessions ) {
|
||||
|
||||
# A session was found
|
||||
# At least one session was found
|
||||
foreach (@local_sessions_keys) {
|
||||
|
||||
my $local_session = $_;
|
||||
|
||||
# Get session
|
||||
$self->lmLog(
|
||||
"Retrieve session $local_session for user $user",
|
||||
"Retrieve SAML session $local_session for user $user",
|
||||
'debug' );
|
||||
|
||||
my $sessionInfo =
|
||||
$self->getApacheSession( $local_session, 1 );
|
||||
|
||||
# Get Lasso::Session dump
|
||||
$session_dump = $sessionInfo->{_lassoSessionDump}
|
||||
if $sessionInfo->{_lassoSessionDump};
|
||||
# If session index is defined and not equal to SAML session index,
|
||||
# jump to next session
|
||||
if ( defined $session_index
|
||||
and $session_index ne $sessionInfo->{_sessionIndex} )
|
||||
{
|
||||
$self->lmLog(
|
||||
"Session $local_session has not the good session index, skipping",
|
||||
'debug'
|
||||
);
|
||||
next;
|
||||
}
|
||||
|
||||
# Delete session
|
||||
else {
|
||||
|
||||
# Open real session
|
||||
my $real_session = $sessionInfo->{_id};
|
||||
|
||||
my $realSessionInfo =
|
||||
$self->getApacheSession( $sessionInfo->{_id}, 1 );
|
||||
|
||||
# Get Lasso::Session dump
|
||||
# This value is erased if a next session match the SLO request
|
||||
if ( $realSessionInfo
|
||||
&& $realSessionInfo->{_lassoSessionDump} )
|
||||
{
|
||||
$self->lmLog(
|
||||
"Get Lasso::Session dump from session $real_session",
|
||||
'debug'
|
||||
);
|
||||
$session_dump =
|
||||
$realSessionInfo->{_lassoSessionDump};
|
||||
}
|
||||
|
||||
# Delete real session
|
||||
my $del_real_result =
|
||||
$self->_deleteSession($realSessionInfo);
|
||||
|
||||
# Delete Session
|
||||
$self->lmLog(
|
||||
"Delete session $local_session for user $user",
|
||||
'debug' );
|
||||
my $logout_result = $self->_deleteSession($sessionInfo);
|
||||
$self->lmLog( "Local Logout result: $logout_result",
|
||||
'debug' );
|
||||
$logout_error = 1 unless $logout_result;
|
||||
"Delete real session $real_session result: $del_real_result",
|
||||
'debug'
|
||||
);
|
||||
|
||||
$logout_error = 1 unless $del_real_result;
|
||||
|
||||
# Delete SAML session
|
||||
my $del_saml_result =
|
||||
$self->_deleteSession($sessionInfo);
|
||||
|
||||
$self->lmLog(
|
||||
"Delete SAML session $local_session result: $del_saml_result",
|
||||
'debug'
|
||||
);
|
||||
|
||||
$logout_error = 1 unless $del_saml_result;
|
||||
}
|
||||
}
|
||||
|
||||
# Set session from dump
|
||||
@ -465,8 +524,7 @@ sub extractFormInfo {
|
||||
else {
|
||||
|
||||
# No corresponding session found
|
||||
$self->lmLog( "No local session found for user $user",
|
||||
'debug' );
|
||||
$self->lmLog( "No SAML session found for user $user", 'debug' );
|
||||
|
||||
$logout_error = 1;
|
||||
|
||||
@ -967,8 +1025,44 @@ sub authLogout {
|
||||
my $self = shift;
|
||||
my $idp = $self->{sessionInfo}->{_idp};
|
||||
my $idpConfKey = $self->{sessionInfo}->{_idpConfKey};
|
||||
my $session_id = $self->{sessionInfo}->{_session_id};
|
||||
my $method;
|
||||
|
||||
# Real session was previously deleted,
|
||||
# remove corresponding SAML sessions
|
||||
my $local_sessions =
|
||||
$self->{samlStorage}
|
||||
->searchOn( $self->{samlStorageOptions}, "_id", $session_id );
|
||||
|
||||
if ( my @local_sessions_keys = keys %$local_sessions ) {
|
||||
|
||||
# At least one session was found
|
||||
foreach (@local_sessions_keys) {
|
||||
|
||||
my $local_session = $_;
|
||||
|
||||
# Get session
|
||||
$self->lmLog(
|
||||
"Retrieve SAML session $local_session (linked to $session_id)",
|
||||
'debug'
|
||||
);
|
||||
|
||||
my $sessionInfo = $self->getApacheSession( $local_session, 1 );
|
||||
|
||||
# Delete session
|
||||
my $del_saml_result = $self->_deleteSession($sessionInfo);
|
||||
|
||||
$self->lmLog(
|
||||
"Delete SAML session $local_session result: $del_saml_result",
|
||||
'debug' );
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
# No corresponding session found
|
||||
$self->lmLog( "No SAML session found for $session_id", 'debug' );
|
||||
}
|
||||
|
||||
# Get Lasso Server
|
||||
unless ( $self->{_lassoServer} ) {
|
||||
$self->_sub('authInit');
|
||||
@ -1129,6 +1223,48 @@ sub authForce {
|
||||
return 0;
|
||||
}
|
||||
|
||||
## @apmethod boolean authFinish()
|
||||
# Associate NameID and SessionIndex to a local session
|
||||
# @return Lemonldap::NG::Portal error code
|
||||
sub authFinish {
|
||||
my $self = shift;
|
||||
my %h;
|
||||
|
||||
# Real session was stored, get id and utime
|
||||
my $id = $self->{id};
|
||||
my $utime = $self->{sessionInfo}->{_utime};
|
||||
|
||||
# Get saved Lasso objects
|
||||
my $nameid = $self->{_nameID};
|
||||
my $session_index = $self->{_sessionIndex};
|
||||
|
||||
$self->lmLog(
|
||||
"Store NameID $nameid and SessionIndex $session_index for session $id",
|
||||
'debug'
|
||||
);
|
||||
|
||||
# Save SAML session
|
||||
eval { tie %h, $self->{samlStorage}, undef, $self->{samlStorageOptions}; };
|
||||
if ($@) {
|
||||
$self->lmLog( "Unable to create SAML session: $@", 'error' );
|
||||
return PE_ERROR;
|
||||
}
|
||||
|
||||
$h{type} = 'saml'; # Session type
|
||||
$h{_utime} = $utime; # Creation time
|
||||
$h{_id} = $id; # SSO session id
|
||||
$h{_nameID} = $nameid; # SAML NameID
|
||||
$h{_sessionIndex} = $session_index; # SAML SessionIndex
|
||||
|
||||
my $session_id = $h{_session_id};
|
||||
|
||||
untie %h;
|
||||
|
||||
$self->lmLog( "Link session $id to SAML session $session_id", 'debug' );
|
||||
|
||||
return PE_OK;
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
__END__
|
||||
|
@ -855,7 +855,7 @@ sub issuerForAuthUser {
|
||||
my $session_index = $logout->request()->SessionIndex;
|
||||
|
||||
# SLO requests without session index are not accepted
|
||||
unless ($session_index) {
|
||||
unless (defined $session_index) {
|
||||
$self->lmLog(
|
||||
"No session index in SLO request from $spConfKey SP",
|
||||
'error' );
|
||||
|
@ -711,6 +711,12 @@ sub _deleteSession {
|
||||
my ( $self, $h, $preserveCookie ) = @_;
|
||||
my $result = 1;
|
||||
|
||||
# Return false if $h is not a hashref
|
||||
if (ref $h ne "HASH") {
|
||||
$self->lmLog("_deleteSession: \$h is not a session object", 'error');
|
||||
return 0;
|
||||
}
|
||||
|
||||
# Try to find a linked http session (securedCookie=>2)
|
||||
if ( my $id2 = $h->{_httpSession} ) {
|
||||
if ( my $h2 = $self->getApacheSession( $id2, 1 ) ) {
|
||||
@ -836,6 +842,7 @@ sub printImage {
|
||||
# - extractFormInfo
|
||||
# - setAuthSessionInfo
|
||||
# - authenticate
|
||||
# - authFinish
|
||||
# - userDB module:
|
||||
# - userDBInit
|
||||
# - getUser
|
||||
@ -858,8 +865,8 @@ sub process {
|
||||
issuerForUnAuthUser authInit extractFormInfo userDBInit getUser
|
||||
setAuthSessionInfo passwordDBInit modifyPassword setSessionInfo
|
||||
setMacros setLocalGroups setGroups authenticate removeOther
|
||||
grantSession store buildCookie checkNotification issuerForAuthUser
|
||||
autoRedirect)
|
||||
grantSession store authFinish buildCookie checkNotification
|
||||
issuerForAuthUser autoRedirect)
|
||||
);
|
||||
$self->updateStatus;
|
||||
return ( ( $self->{error} > 0 ) ? 0 : 1 );
|
||||
@ -1064,7 +1071,7 @@ sub existingSession {
|
||||
qw(issuerDBInit issuerForUnAuthUser authInit extractFormInfo
|
||||
userDBInit getUser setAuthSessionInfo setSessionInfo
|
||||
setMacros setLocalGroups setGroups authenticate
|
||||
store)
|
||||
store authFinish)
|
||||
);
|
||||
return $self->{error} || PE_DONE;
|
||||
}
|
||||
@ -1171,8 +1178,6 @@ sub setSessionInfo {
|
||||
return $self->SUPER::setSessionInfo();
|
||||
}
|
||||
|
||||
# resetPasswordByMail(): must be implemented in PasswordDB* module
|
||||
|
||||
##@apmethod int setMacro()
|
||||
# Macro mechanism.
|
||||
# * store macro results in $self->{sessionInfo}
|
||||
@ -1391,6 +1396,23 @@ sub store {
|
||||
PE_OK;
|
||||
}
|
||||
|
||||
## @apmethod int authFinish
|
||||
# Call authFinish method from authentication module
|
||||
# @return Lemonldap::NG::Portal constant
|
||||
sub authFinish {
|
||||
my $self = shift;
|
||||
|
||||
eval { $self->{error} = $self->SUPER::authFinish; };
|
||||
if ($@) {
|
||||
$self->lmLog(
|
||||
"Optional authFinish method not defined in current authentication module: $@",
|
||||
'debug' );
|
||||
return PE_OK;
|
||||
}
|
||||
|
||||
return $self->{error};
|
||||
}
|
||||
|
||||
##@apmethod int buildCookie()
|
||||
# Build the Lemonldap::NG cookie.
|
||||
#@return Lemonldap::NG::Portal constant
|
||||
|
@ -78,7 +78,7 @@ sub getCookies {
|
||||
$self->{error} = $self->_subProcess(
|
||||
qw(authInit userDBInit getUser setAuthSessionInfo setSessionInfo
|
||||
setMacros setLocalGroups setGroups authenticate removeOther grantSession
|
||||
store buildCookie)
|
||||
store authFinish buildCookie)
|
||||
);
|
||||
$self->updateSession();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user