diff --git a/Kernel/System/AuthSession.pm b/Kernel/System/AuthSession.pm index 464b900d6fc..f54f8b6b7f5 100644 --- a/Kernel/System/AuthSession.pm +++ b/Kernel/System/AuthSession.pm @@ -265,7 +265,13 @@ sub RemoveSessionByUser { SessionID => $SessionID, ); - next SESSIONID if $SessionData{UserLogin} ne $Param{UserLogin}; + if ( + defined $SessionData{UserLogin} + && ( $SessionData{UserLogin} ne $Param{UserLogin} ) + ) + { + next SESSIONID; + } $Self->{Backend}->RemoveSessionID( SessionID => $SessionID, @@ -376,6 +382,34 @@ sub GetActiveSessions { return $Self->{Backend}->GetActiveSessions(%Param); } +=head2 GetOrphanedSessionIDs() + +returns an array with orphaned session ids, +missing user-login defines an orphaned session for now + + my @Sessions = $SessionObject->GetOrphanedSessionIDs(); + +=cut + +sub GetOrphanedSessionIDs { + my ( $Self, %Param ) = @_; + + my @OrphanedSessionIDs; + my @SessionIDs = $Self->GetAllSessionIDs(); + for my $SessionID (@SessionIDs) { + + my %SessionData = $Self->{Backend}->GetSessionIDData( + SessionID => $SessionID, + ); + + if ( !defined $SessionData{UserLogin} ) { + push @OrphanedSessionIDs, $SessionID; + } + } + + return @OrphanedSessionIDs; +} + =head2 CleanUp() clean-up of sessions in your system diff --git a/Kernel/System/Console/Command/Maint/Session/DeleteOrphaned.pm b/Kernel/System/Console/Command/Maint/Session/DeleteOrphaned.pm new file mode 100644 index 00000000000..3fc48c35f7c --- /dev/null +++ b/Kernel/System/Console/Command/Maint/Session/DeleteOrphaned.pm @@ -0,0 +1,56 @@ +# -- +# Copyright (C) 2021 Znuny GmbH, https://znuny.org/ +# -- +# This software comes with ABSOLUTELY NO WARRANTY. For details, see +# the enclosed file COPYING for license information (AGPL). If you +# did not receive this file, see http://www.gnu.org/licenses/agpl.txt. +# -- + +package Kernel::System::Console::Command::Maint::Session::DeleteOrphaned; + +use strict; +use warnings; +use utf8; + +use parent qw(Kernel::System::Console::BaseCommand); + +our @ObjectDependencies = ( + 'Kernel::System::AuthSession', +); + +sub Configure { + my ( $Self, %Param ) = @_; + + $Self->Description('Delete orphaned sessions.'); + + return; +} + +sub Run { + my ( $Self, %Param ) = @_; + + my $SessionObject = $Kernel::OM->Get('Kernel::System::AuthSession'); + + $Self->Print("Deleting orphaned sessions...\n"); + + my @OrphanedSessions = $SessionObject->GetOrphanedSessionIDs(); + + for my $SessionID ( @OrphanedSessions ) { + my $Success = $SessionObject->RemoveSessionID( + SessionID => $SessionID, + ); + + if ( !$Success ) { + $Self->PrintError("Session $SessionID could not be deleted."); + return $Self->ExitCodeError(); + } + + $Self->Print(" $SessionID\n"); + } + + $Self->Print("Done.\n"); + + return $Self->ExitCodeOk(); +} + +1; diff --git a/Kernel/System/Console/Command/Maint/Session/ListOrphaned.pm b/Kernel/System/Console/Command/Maint/Session/ListOrphaned.pm new file mode 100644 index 00000000000..7f471221051 --- /dev/null +++ b/Kernel/System/Console/Command/Maint/Session/ListOrphaned.pm @@ -0,0 +1,47 @@ +# -- +# Copyright (C) 2021 Znuny GmbH, https://znuny.org/ +# -- +# This software comes with ABSOLUTELY NO WARRANTY. For details, see +# the enclosed file COPYING for license information (AGPL). If you +# did not receive this file, see http://www.gnu.org/licenses/agpl.txt. +# -- + +package Kernel::System::Console::Command::Maint::Session::ListOrphaned; + +use strict; +use warnings; +use utf8; + +use parent qw(Kernel::System::Console::BaseCommand); + +our @ObjectDependencies = ( + 'Kernel::System::AuthSession', +); + +sub Configure { + my ( $Self, %Param ) = @_; + + $Self->Description('List orphaned sessions.'); + + return; +} + +sub Run { + my ( $Self, %Param ) = @_; + + my $SessionObject = $Kernel::OM->Get('Kernel::System::AuthSession'); + + $Self->Print("Listing orphaned sessions...\n"); + + my @OrphanedSessions = $SessionObject->GetOrphanedSessionIDs(); + + for my $SessionID (@OrphanedSessions) { + $Self->Print(" $SessionID\n"); + } + + $Self->Print("Done.\n"); + + return $Self->ExitCodeOk(); +} + +1; diff --git a/scripts/test/RemoveOrphanedSessions.t b/scripts/test/RemoveOrphanedSessions.t new file mode 100644 index 00000000000..e944ca935b3 --- /dev/null +++ b/scripts/test/RemoveOrphanedSessions.t @@ -0,0 +1,100 @@ +# -- +# Copyright (C) 2021 Znuny GmbH, https://znuny.org/ +# -- +# This software comes with ABSOLUTELY NO WARRANTY. For details, see +# the enclosed file COPYING for license information (AGPL). If you +# did not receive this file, see http://www.gnu.org/licenses/agpl.txt. +# -- + +use strict; +use warnings; +use utf8; + +use vars (qw($Self)); + +my $SessionObject = $Kernel::OM->Get('Kernel::System::AuthSession'); +my $UserObject = $Kernel::OM->Get('Kernel::System::User'); + +$Kernel::OM->ObjectParamAdd( + 'Kernel::System::UnitTest::Helper' => { + RestoreDatabase => 1, + }, +); +my $HelperObject = $Kernel::OM->Get('Kernel::System::UnitTest::Helper'); + +# Create test users and a session for every one. +my @TestUserLogins; +for my $Count ( 1 .. 3 ) { + my ( $TestUserLogin, $TestUserID ) = $HelperObject->TestUserCreate(); + push @TestUserLogins, $TestUserLogin; + + my %UserData = $UserObject->GetUserData( + UserID => $TestUserID, + NoOutOfOffice => 1, + ); + + my $NewSessionID = $SessionObject->CreateSessionID( + %UserData, + UserLastRequest => $Kernel::OM->Create('Kernel::System::DateTime')->ToEpoch(), + UserType => 'User', + SessionSource => 'AgentInterface', + ); + $Self->True( + $NewSessionID, + "SessionID '$NewSessionID' is created for user '$TestUserLogin'", + ); +} + +# orphan first session +my @SessionIDs = $SessionObject->GetAllSessionIDs(); +my $OrphanedTestUserSessionID = $SessionIDs[0]; + +$SessionObject->UpdateSessionID( + SessionID => $OrphanedTestUserSessionID, + Key => 'UserLogin', + Value => undef, +); +$Self->True( + $OrphanedTestUserSessionID, + "SessionID '$OrphanedTestUserSessionID' has been orphaned", +); + +# delete orphaned session via console command method +# ( i.e. bin/znuny.Console.pl Maint::Session::DeleteOrphaned for maintenance ) +my $CommandObject = $Kernel::OM->Get('Kernel::System::Console::Command::Maint::Session::DeleteOrphaned'); +my $ExitCode = $CommandObject->Execute(); + +$Self->Is( + $ExitCode, + $CommandObject->ExitCodeOk(), + "Orphaned session '$OrphanedTestUserSessionID' was deleted", +); + +# Check for remaining sessions. +my @RemainingSessionIDs = $SessionObject->GetAllSessionIDs(); + +$Self->Is( + scalar @RemainingSessionIDs, + 2, + "Ok, only one session was deleted, two remaining.", +); + +# Check if orphaned session is removed. +for my $SessionID (@RemainingSessionIDs) { + if ( $SessionID eq $OrphanedTestUserSessionID ) { + $Self->False( + $OrphanedTestUserSessionID, + "Orphaned session: '$OrphanedTestUserSessionID' was not deleted", + ); + } + else { + $Self->True( + $SessionID, + "Session '$SessionID' is found", + ); + } +} + +# Restore to the previous state is done by RestoreDatabase. + +1;