# -- # Copyright (C) 2001-2019 OTRS AG, https://otrs.com/ # -- # This software comes with ABSOLUTELY NO WARRANTY. For details, see # the enclosed file COPYING for license information (GPL). If you # did not receive this file, see https://www.gnu.org/licenses/gpl-3.0.txt. # -- package Kernel::System::AuthSession; use strict; use warnings; use Kernel::Language qw(Translatable); our @ObjectDependencies = ( 'Kernel::Config', 'Kernel::System::Cache', 'Kernel::System::Log', 'Kernel::System::Main', 'Kernel::System::SystemData', 'Kernel::System::SysConfig', ); =head1 NAME Kernel::System::AuthSession - global session interface =head1 DESCRIPTION All session functions. =head1 PUBLIC INTERFACE =head2 new() Don't use the constructor directly, use the ObjectManager instead: my $SessionObject = $Kernel::OM->Get('Kernel::System::AuthSession'); =cut sub new { my ( $Type, %Param ) = @_; # allocate new hash for object my $Self = {}; bless( $Self, $Type ); # get configured session backend my $GenericModule = $Kernel::OM->Get('Kernel::Config')->Get('SessionModule'); $GenericModule ||= 'Kernel::System::AuthSession::DB'; # get main object my $MainObject = $Kernel::OM->Get('Kernel::System::Main'); # load session backend module if ( !$MainObject->Require($GenericModule) ) { $MainObject->Die("Can't load backend module $GenericModule! $@"); } $Self->{Backend} = $GenericModule->new(); my $ConfigObject = $Kernel::OM->Get('Kernel::Config'); for my $SessionLimitConfigKey ( qw(AgentSessionLimitPriorWarning AgentSessionLimit AgentSessionPerUserLimit CustomerSessionLimit CustomerSessionPerUserLimit) ) { $Self->{$SessionLimitConfigKey} = $ConfigObject->Get($SessionLimitConfigKey); } return $Self; } =head2 CheckSessionID() checks a session, returns true (session ok) or false (session invalid) my $Ok = $SessionObject->CheckSessionID( SessionID => '1234567890123456', ); =cut sub CheckSessionID { my ( $Self, %Param ) = @_; return $Self->{Backend}->CheckSessionID(%Param); } =head2 CheckAgentSessionLimitPriorWarning() Get the agent session limit prior warning message, if the limit is reached. my $PriorMessage = $SessionObject->CheckAgentSessionLimitPriorWarning(); returns the prior warning message (AgentSessionLimitPriorWarning reached) or false (AgentSessionLimitPriorWarning not reached) =cut sub CheckAgentSessionLimitPriorWarning { my ( $Self, %Param ) = @_; my $CacheObject = $Kernel::OM->Get('Kernel::System::Cache'); my $Cache = $CacheObject->Get( Type => 'AuthSession', Key => 'AgentSessionLimitPriorWarningMessage', ); return $Cache if defined $Cache; my %OTRSBusinessSystemData = $Kernel::OM->Get('Kernel::System::SystemData')->SystemDataGroupGet( Group => 'OTRSBusiness', ); my $SessionLimitPriorWarning = $OTRSBusinessSystemData{AgentSessionLimitPriorWarning}; if ( !$SessionLimitPriorWarning || ( $Self->{AgentSessionLimitPriorWarning} && $Self->{AgentSessionLimitPriorWarning} < $SessionLimitPriorWarning ) ) { $SessionLimitPriorWarning = $Self->{AgentSessionLimitPriorWarning}; } my $PriorWarningMessage = ''; if ($SessionLimitPriorWarning) { my %ActiveSessions = $Self->GetActiveSessions( UserType => 'User', ); if ( defined $ActiveSessions{Total} && $ActiveSessions{Total} > $SessionLimitPriorWarning ) { if ( $OTRSBusinessSystemData{AgentSessionLimitPriorWarning} && $OTRSBusinessSystemData{AgentSessionLimitPriorWarning} == $SessionLimitPriorWarning ) { $PriorWarningMessage = Translatable('You have exceeded the number of concurrent agents - contact sales@otrs.com.'); } else { $PriorWarningMessage = Translatable('Please note that the session limit is almost reached.'); } } } $CacheObject->Set( Type => 'AuthSession', TTL => 60 * 15, Key => 'AgentSessionLimitPriorWarningMessage', Value => $PriorWarningMessage, ); return $PriorWarningMessage; } =head2 SessionIDErrorMessage() returns an error in the session handling my $Message = $SessionObject->SessionIDErrorMessage(); =cut sub SessionIDErrorMessage { my ( $Self, %Param ) = @_; return $Self->{SessionIDErrorMessage} || $Self->{Backend}->SessionIDErrorMessage(%Param); } =head2 GetSessionIDData() get session data in a hash my %Data = $SessionObject->GetSessionIDData( SessionID => '1234567890123456', ); Returns: %Data = ( UserSessionStart => '1293801801', UserRemoteAddr => '127.0.0.1', UserRemoteUserAgent => 'Some User Agent x.x', UserLastname => 'SomeLastName', UserFirstname => 'SomeFirstname', # and all other preferences values ); =cut sub GetSessionIDData { my ( $Self, %Param ) = @_; return $Self->{Backend}->GetSessionIDData(%Param); } =head2 CreateSessionID() create a new session with given data my $SessionID = $SessionObject->CreateSessionID( UserLogin => 'root', UserEmail => 'root@example.com', ); =cut sub CreateSessionID { my ( $Self, %Param ) = @_; if ( !$Param{UserType} ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => 'Got no UserType!' ); return; } if ( $Param{UserType} ne 'User' && $Param{UserType} ne 'Customer' ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => 'Got wrong UserType!' ); return; } my %OTRSBusinessSystemData = $Kernel::OM->Get('Kernel::System::SystemData')->SystemDataGroupGet( Group => 'OTRSBusiness', ); my $SessionLimit; if ( $Param{UserType} eq 'User' ) { # Use the AgentSessionLimit from the business solution, if a session limit exists and use the AgentSessionLimit # from the config, if the value is lower the business solution value. $SessionLimit = $OTRSBusinessSystemData{AgentSessionLimit}; if ( !$SessionLimit || ( $Self->{AgentSessionLimit} && $Self->{AgentSessionLimit} < $SessionLimit ) ) { $SessionLimit = $Self->{AgentSessionLimit}; } } elsif ( $Param{UserType} eq 'Customer' && $Self->{CustomerSessionLimit} ) { $SessionLimit = $Self->{CustomerSessionLimit}; } # get session per user limit config my $SessionPerUserLimit; if ( $Param{UserType} eq 'User' && $Self->{AgentSessionPerUserLimit} ) { $SessionPerUserLimit = $Self->{AgentSessionPerUserLimit}; } elsif ( $Param{UserType} eq 'Customer' && $Self->{CustomerSessionPerUserLimit} ) { $SessionPerUserLimit = $Self->{CustomerSessionPerUserLimit}; } my $SessionSource = $Param{SessionSource} || ''; # Don't check the session limit for sessions from the source 'GenericInterface'. if ( $SessionSource ne 'GenericInterface' && ( $SessionLimit || $SessionPerUserLimit ) ) { my %ActiveSessions = $Self->GetActiveSessions(%Param); if ( $SessionLimit && defined $ActiveSessions{Total} && $ActiveSessions{Total} >= $SessionLimit ) { if ( $Param{UserType} eq 'User' && $OTRSBusinessSystemData{AgentSessionLimit} && $OTRSBusinessSystemData{AgentSessionLimit} == $SessionLimit ) { $Self->{SessionIDErrorMessage} = Translatable( 'Login rejected! You have exceeded the maximum number of concurrent Agents! Contact sales@otrs.com immediately!' ); } else { $Self->{SessionIDErrorMessage} = Translatable('Session limit reached! Please try again later.'); } return; } if ( $SessionPerUserLimit && $Param{UserLogin} && defined $ActiveSessions{PerUser}->{ $Param{UserLogin} } && $ActiveSessions{PerUser}->{ $Param{UserLogin} } >= $SessionPerUserLimit ) { $Self->{SessionIDErrorMessage} = Translatable('Session per user limit reached!'); return; } } $Kernel::OM->Get('Kernel::System::Cache')->Delete( Type => 'AuthSession', Key => 'AgentSessionLimitPriorWarningMessage', ); return $Self->{Backend}->CreateSessionID(%Param); } =head2 RemoveSessionID() removes a session and returns true (session deleted), false (if session can't get deleted) $SessionObject->RemoveSessionID(SessionID => '1234567890123456'); =cut sub RemoveSessionID { my ( $Self, %Param ) = @_; $Kernel::OM->Get('Kernel::System::Cache')->Delete( Type => 'AuthSession', Key => 'AgentSessionLimitPriorWarningMessage', ); return $Self->{Backend}->RemoveSessionID(%Param); } =head2 UpdateSessionID() update session info by key and value, returns true (if ok) and false (if can't update) $SessionObject->UpdateSessionID( SessionID => '1234567890123456', Key => 'LastScreenOverview', Value => 'SomeInfo', ); =cut sub UpdateSessionID { my ( $Self, %Param ) = @_; if ( $Param{Key} ) { my @Parts = split /:/, $Param{Key}; if ( defined $Parts[1] ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Can't update key: '$Param{Key}' because ':' is not allowed!", ); return; } } return $Self->{Backend}->UpdateSessionID(%Param); } =head2 GetExpiredSessionIDs() returns a array of an array of session ids that have expired, and one array of session ids that have been idle for too long. my @Sessions = $SessionObject->GetExpiredSessionIDs(); my @ExpiredSession = @{$Session[0]}; my @ExpiredIdle = @{$Session[1]}; =cut sub GetExpiredSessionIDs { my ( $Self, %Param ) = @_; return $Self->{Backend}->GetExpiredSessionIDs(%Param); } =head2 GetAllSessionIDs() returns an array with all session ids my @Sessions = $SessionObject->GetAllSessionIDs(); =cut sub GetAllSessionIDs { my ( $Self, %Param ) = @_; return $Self->{Backend}->GetAllSessionIDs(%Param); } =head2 GetActiveSessions() Get the current active sessions for the given UserType. my %Result = $SessionObject->GetActiveSessions( UserType => '(User|Customer)', ); returns %Result = ( Total => 8, PerUser => { UserID1 => 2, UserID2 => 1, }, ); =cut sub GetActiveSessions { my ( $Self, %Param ) = @_; if ( !$Param{UserType} ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => 'Got no UserType!' ); return; } if ( $Param{UserType} ne 'User' && $Param{UserType} ne 'Customer' ) { $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => 'Got wrong UserType!' ); return; } return $Self->{Backend}->GetActiveSessions(%Param); } =head2 CleanUp() clean-up of sessions in your system $SessionObject->CleanUp(); =cut sub CleanUp { my ( $Self, %Param ) = @_; $Kernel::OM->Get('Kernel::System::Cache')->Delete( Type => 'AuthSession', Key => 'AgentSessionLimitPriorWarningMessage', ); return $Self->{Backend}->CleanUp(%Param); } 1; =head1 TERMS AND CONDITIONS This software is part of the OTRS project (L). This software comes with ABSOLUTELY NO WARRANTY. For details, see the enclosed file COPYING for license information (GPL). If you did not receive this file, see L. =cut