init III
This commit is contained in:
816
Perl OTRS/Kernel/System/AuthSession/DB.pm
Normal file
816
Perl OTRS/Kernel/System/AuthSession/DB.pm
Normal file
@@ -0,0 +1,816 @@
|
||||
# --
|
||||
# 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::DB;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use MIME::Base64 qw();
|
||||
|
||||
use Kernel::Language qw(Translatable);
|
||||
|
||||
our @ObjectDependencies = (
|
||||
'Kernel::Config',
|
||||
'Kernel::System::DateTime',
|
||||
'Kernel::System::DB',
|
||||
'Kernel::System::Encode',
|
||||
'Kernel::System::Log',
|
||||
'Kernel::System::Main',
|
||||
'Kernel::System::Storable',
|
||||
);
|
||||
|
||||
sub new {
|
||||
my ( $Type, %Param ) = @_;
|
||||
|
||||
# allocate new hash for object
|
||||
my $Self = {};
|
||||
bless( $Self, $Type );
|
||||
|
||||
$Self->{SessionTable} = $Kernel::OM->Get('Kernel::Config')->Get('SessionTable') || 'sessions';
|
||||
|
||||
# get database type
|
||||
$Self->{DBType} = $Kernel::OM->Get('Kernel::System::DB')->{'DB::Type'} || '';
|
||||
$Self->{DBType} = lc $Self->{DBType};
|
||||
|
||||
return $Self;
|
||||
}
|
||||
|
||||
sub CheckSessionID {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
# check session id
|
||||
if ( !$Param{SessionID} ) {
|
||||
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
||||
Priority => 'error',
|
||||
Message => 'Got no SessionID!!'
|
||||
);
|
||||
return;
|
||||
}
|
||||
my $RemoteAddr = $ENV{REMOTE_ADDR} || 'none';
|
||||
|
||||
# set default message
|
||||
$Self->{SessionIDErrorMessage} = Translatable('Session invalid. Please log in again.');
|
||||
|
||||
# get session data
|
||||
my %Data = $Self->GetSessionIDData( SessionID => $Param{SessionID} );
|
||||
|
||||
if ( !$Data{UserID} || !$Data{UserLogin} ) {
|
||||
$Self->{SessionIDErrorMessage} = Translatable('Session invalid. Please log in again.');
|
||||
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
||||
Priority => 'notice',
|
||||
Message => "SessionID: '$Param{SessionID}' is invalid!!!",
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
# get config object
|
||||
my $ConfigObject = $Kernel::OM->Get('Kernel::Config');
|
||||
|
||||
# remote ip check
|
||||
if (
|
||||
$Data{UserRemoteAddr} ne $RemoteAddr
|
||||
&& $ConfigObject->Get('SessionCheckRemoteIP')
|
||||
)
|
||||
{
|
||||
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
||||
Priority => 'notice',
|
||||
Message => "RemoteIP of '$Param{SessionID}' ($Data{UserRemoteAddr}) is "
|
||||
. "different from registered IP ($RemoteAddr). Invalidating session! "
|
||||
. "Disable config 'SessionCheckRemoteIP' if you don't want this!",
|
||||
);
|
||||
|
||||
# delete session id if it isn't the same remote ip?
|
||||
if ( $ConfigObject->Get('SessionDeleteIfNotRemoteID') ) {
|
||||
$Self->RemoveSessionID( SessionID => $Param{SessionID} );
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
# check session idle time
|
||||
my $TimeNow = $Kernel::OM->Create('Kernel::System::DateTime')->ToEpoch();
|
||||
my $MaxSessionIdleTime = $ConfigObject->Get('SessionMaxIdleTime');
|
||||
|
||||
if ( ( $TimeNow - $MaxSessionIdleTime ) >= $Data{UserLastRequest} ) {
|
||||
|
||||
$Self->{SessionIDErrorMessage} = Translatable('Session has timed out. Please log in again.');
|
||||
|
||||
my $Timeout = int( ( $TimeNow - $Data{UserLastRequest} ) / ( 60 * 60 ) );
|
||||
|
||||
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
||||
Priority => 'notice',
|
||||
Message =>
|
||||
"SessionID ($Param{SessionID}) idle timeout ($Timeout h)! Don't grant access!!!",
|
||||
);
|
||||
|
||||
# delete session id if too old?
|
||||
if ( $ConfigObject->Get('SessionDeleteIfTimeToOld') ) {
|
||||
$Self->RemoveSessionID( SessionID => $Param{SessionID} );
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
# check session time
|
||||
my $MaxSessionTime = $ConfigObject->Get('SessionMaxTime');
|
||||
|
||||
if ( ( $TimeNow - $MaxSessionTime ) >= $Data{UserSessionStart} ) {
|
||||
|
||||
$Self->{SessionIDErrorMessage} = Translatable('Session has timed out. Please log in again.');
|
||||
|
||||
my $Timeout = int( ( $TimeNow - $Data{UserSessionStart} ) / ( 60 * 60 ) );
|
||||
|
||||
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
||||
Priority => 'notice',
|
||||
Message => "SessionID ($Param{SessionID}) too old ($Timeout h)! Don't grant access!!!",
|
||||
);
|
||||
|
||||
# delete session id if too old
|
||||
if ( $ConfigObject->Get('SessionDeleteIfTimeToOld') ) {
|
||||
$Self->RemoveSessionID( SessionID => $Param{SessionID} );
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub SessionIDErrorMessage {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
return $Self->{SessionIDErrorMessage} || '';
|
||||
}
|
||||
|
||||
sub GetSessionIDData {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
# check session id
|
||||
if ( !$Param{SessionID} ) {
|
||||
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
||||
Priority => 'error',
|
||||
Message => 'Got no SessionID!'
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
return %{ $Self->{Cache}->{ $Param{SessionID} } } if $Self->{Cache}->{ $Param{SessionID} };
|
||||
|
||||
# get database object
|
||||
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
|
||||
|
||||
# read data
|
||||
$DBObject->Prepare(
|
||||
SQL => "
|
||||
SELECT id, data_key, data_value, serialized
|
||||
FROM $Self->{SessionTable}
|
||||
WHERE session_id = ?
|
||||
ORDER BY id ASC",
|
||||
Bind => [ \$Param{SessionID} ],
|
||||
);
|
||||
|
||||
# get encode object
|
||||
my $EncodeObject = $Kernel::OM->Get('Kernel::System::Encode');
|
||||
|
||||
# get storable object
|
||||
my $StorableObject = $Kernel::OM->Get('Kernel::System::Storable');
|
||||
|
||||
my %Session;
|
||||
my %SessionID;
|
||||
ROW:
|
||||
while ( my @Row = $DBObject->FetchrowArray() ) {
|
||||
|
||||
# deserialize data if needed
|
||||
if ( $Row[3] ) {
|
||||
my $Value = eval {
|
||||
$StorableObject->Deserialize( Data => MIME::Base64::decode_base64( $Row[2] ) );
|
||||
};
|
||||
|
||||
# workaround for the oracle problem with empty
|
||||
# strings and NULL values in VARCHAR columns
|
||||
if ( $Value && ref $Value eq 'SCALAR' ) {
|
||||
$Value = ${$Value};
|
||||
}
|
||||
|
||||
$EncodeObject->EncodeOutput( \$Value );
|
||||
|
||||
$Session{ $Row[1] } = $Value;
|
||||
}
|
||||
else {
|
||||
$Session{ $Row[1] } = $Row[2];
|
||||
}
|
||||
|
||||
$SessionID{ $Row[1] } = $Row[0];
|
||||
}
|
||||
|
||||
if ( !%Session ) {
|
||||
delete $Self->{Cache}->{ $Param{SessionID} };
|
||||
delete $Self->{CacheID}->{ $Param{SessionID} };
|
||||
delete $Self->{CacheUpdate}->{ $Param{SessionID} };
|
||||
return;
|
||||
}
|
||||
|
||||
# cache result
|
||||
$Self->{Cache}->{ $Param{SessionID} } = \%Session;
|
||||
$Self->{CacheID}->{ $Param{SessionID} } = \%SessionID;
|
||||
|
||||
return %Session;
|
||||
}
|
||||
|
||||
sub CreateSessionID {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
my $TimeNow = $Kernel::OM->Create('Kernel::System::DateTime')->ToEpoch();
|
||||
|
||||
# get remote address and the http user agent
|
||||
my $RemoteAddr = $ENV{REMOTE_ADDR} || 'none';
|
||||
my $RemoteUserAgent = $ENV{HTTP_USER_AGENT} || 'none';
|
||||
|
||||
# get main object
|
||||
my $MainObject = $Kernel::OM->Get('Kernel::System::Main');
|
||||
|
||||
# create session id
|
||||
my $SessionID = $MainObject->GenerateRandomString(
|
||||
Length => 32,
|
||||
);
|
||||
|
||||
# create challenge token
|
||||
my $ChallengeToken = $MainObject->GenerateRandomString(
|
||||
Length => 32,
|
||||
);
|
||||
|
||||
my %Data;
|
||||
KEY:
|
||||
for my $Key ( sort keys %Param ) {
|
||||
|
||||
next KEY if !$Key;
|
||||
|
||||
$Data{$Key} = $Param{$Key};
|
||||
}
|
||||
|
||||
$Data{UserSessionStart} = $TimeNow;
|
||||
$Data{UserRemoteAddr} = $RemoteAddr;
|
||||
$Data{UserRemoteUserAgent} = $RemoteUserAgent;
|
||||
$Data{UserChallengeToken} = $ChallengeToken;
|
||||
|
||||
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
|
||||
|
||||
# create sql data
|
||||
my @SQLs;
|
||||
$Self->_SQLCreate(
|
||||
Data => \%Data,
|
||||
SQLs => \@SQLs,
|
||||
SessionID => $SessionID,
|
||||
);
|
||||
|
||||
return if !@SQLs;
|
||||
|
||||
# delete old session data with the same session id
|
||||
$DBObject->Do(
|
||||
SQL => "
|
||||
DELETE FROM $Self->{SessionTable}
|
||||
WHERE session_id = ?",
|
||||
Bind => [ \$SessionID, ],
|
||||
);
|
||||
|
||||
# store session id and data
|
||||
ROW:
|
||||
for my $Row (@SQLs) {
|
||||
|
||||
next ROW if !$Row;
|
||||
next ROW if ref $Row ne 'HASH';
|
||||
next ROW if !$Row->{SQL};
|
||||
next ROW if !$Row->{Bind};
|
||||
next ROW if ref $Row->{Bind} ne 'ARRAY';
|
||||
|
||||
$DBObject->Do(
|
||||
SQL => $Row->{SQL},
|
||||
Bind => $Row->{Bind},
|
||||
);
|
||||
}
|
||||
|
||||
# set cache
|
||||
$Self->{Cache}->{$SessionID} = \%Data;
|
||||
|
||||
return $SessionID;
|
||||
}
|
||||
|
||||
sub RemoveSessionID {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
# check session id
|
||||
if ( !$Param{SessionID} ) {
|
||||
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
||||
Priority => 'error',
|
||||
Message => 'Got no SessionID!!'
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
# delete session from the database
|
||||
return if !$Kernel::OM->Get('Kernel::System::DB')->Do(
|
||||
SQL => "DELETE FROM $Self->{SessionTable} WHERE session_id = ?",
|
||||
Bind => [ \$Param{SessionID} ],
|
||||
);
|
||||
|
||||
# reset cache
|
||||
delete $Self->{Cache}->{ $Param{SessionID} };
|
||||
delete $Self->{CacheID}->{ $Param{SessionID} };
|
||||
delete $Self->{CacheUpdate}->{ $Param{SessionID} };
|
||||
|
||||
# log event
|
||||
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
||||
Priority => 'notice',
|
||||
Message => "Removed SessionID $Param{SessionID}."
|
||||
);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub UpdateSessionID {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
# check needed stuff
|
||||
for (qw(SessionID Key)) {
|
||||
if ( !$Param{$_} ) {
|
||||
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
||||
Priority => 'error',
|
||||
Message => "Need $_!"
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
# check cache
|
||||
if ( !$Self->{Cache}->{ $Param{SessionID} } ) {
|
||||
my %SessionData = $Self->GetSessionIDData( SessionID => $Param{SessionID} );
|
||||
|
||||
$Self->{Cache}->{ $Param{SessionID} } = \%SessionData;
|
||||
}
|
||||
|
||||
# update the value, set cache
|
||||
$Self->{Cache}->{ $Param{SessionID} }->{ $Param{Key} } = $Param{Value};
|
||||
$Self->{CacheUpdate}->{ $Param{SessionID} }->{ $Param{Key} } = $Param{Value};
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub GetAllSessionIDs {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
# get database object
|
||||
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
|
||||
|
||||
# get all session ids from the database
|
||||
return if !$DBObject->Prepare(
|
||||
SQL => "SELECT DISTINCT(session_id) FROM $Self->{SessionTable}",
|
||||
);
|
||||
|
||||
# fetch the result
|
||||
my @SessionIDs;
|
||||
while ( my @Row = $DBObject->FetchrowArray() ) {
|
||||
push @SessionIDs, $Row[0];
|
||||
}
|
||||
|
||||
return @SessionIDs;
|
||||
}
|
||||
|
||||
sub GetActiveSessions {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
my $MaxSessionIdleTime = $Kernel::OM->Get('Kernel::Config')->Get('SessionMaxIdleTime');
|
||||
|
||||
# get system time
|
||||
my $TimeNow = $Kernel::OM->Create('Kernel::System::DateTime')->ToEpoch();
|
||||
|
||||
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
|
||||
|
||||
$DBObject->Prepare(
|
||||
SQL => "
|
||||
SELECT session_id, data_key, data_value
|
||||
FROM $Self->{SessionTable}
|
||||
WHERE data_key = 'UserType'
|
||||
OR data_key = 'UserLastRequest'
|
||||
OR data_key = 'UserLogin'
|
||||
OR data_key = 'SessionSource'
|
||||
ORDER BY id ASC",
|
||||
);
|
||||
|
||||
my %SessionData;
|
||||
ROW:
|
||||
while ( my @Row = $DBObject->FetchrowArray() ) {
|
||||
|
||||
next ROW if !$Row[0];
|
||||
next ROW if !$Row[1];
|
||||
|
||||
$SessionData{ $Row[0] }->{ $Row[1] } = $Row[2];
|
||||
}
|
||||
|
||||
my $ActiveSessionCount = 0;
|
||||
my %ActiveSessionPerUserCount;
|
||||
SESSIONID:
|
||||
for my $SessionID ( sort keys %SessionData ) {
|
||||
|
||||
next SESSIONID if !$SessionID;
|
||||
next SESSIONID if !$SessionData{$SessionID};
|
||||
|
||||
# Don't count session from source 'GenericInterface'
|
||||
my $SessionSource = $SessionData{$SessionID}->{SessionSource} || '';
|
||||
|
||||
next SESSIONID if $SessionSource eq 'GenericInterface';
|
||||
|
||||
# get needed data
|
||||
my $UserType = $SessionData{$SessionID}->{UserType} || '';
|
||||
my $UserLastRequest = $SessionData{$SessionID}->{UserLastRequest} || $TimeNow;
|
||||
my $UserLogin = $SessionData{$SessionID}->{UserLogin};
|
||||
|
||||
next SESSIONID if $UserType ne $Param{UserType};
|
||||
|
||||
next SESSIONID if ( $UserLastRequest + $MaxSessionIdleTime ) < $TimeNow;
|
||||
|
||||
$ActiveSessionCount++;
|
||||
|
||||
$ActiveSessionPerUserCount{$UserLogin} || 0;
|
||||
$ActiveSessionPerUserCount{$UserLogin}++;
|
||||
}
|
||||
|
||||
my %Result = (
|
||||
Total => $ActiveSessionCount,
|
||||
PerUser => \%ActiveSessionPerUserCount,
|
||||
);
|
||||
|
||||
return %Result;
|
||||
}
|
||||
|
||||
sub GetExpiredSessionIDs {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
# get config object
|
||||
my $ConfigObject = $Kernel::OM->Get('Kernel::Config');
|
||||
|
||||
# get config
|
||||
my $MaxSessionTime = $ConfigObject->Get('SessionMaxTime');
|
||||
my $MaxSessionIdleTime = $ConfigObject->Get('SessionMaxIdleTime');
|
||||
|
||||
# get current time
|
||||
my $TimeNow = $Kernel::OM->Create('Kernel::System::DateTime')->ToEpoch();
|
||||
|
||||
# get database object
|
||||
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
|
||||
|
||||
# get all needed timestamps to investigate the expired sessions
|
||||
$DBObject->Prepare(
|
||||
SQL => "
|
||||
SELECT session_id, data_key, data_value
|
||||
FROM $Self->{SessionTable}
|
||||
WHERE data_key = 'UserSessionStart'
|
||||
OR data_key = 'UserLastRequest'
|
||||
ORDER BY id ASC",
|
||||
);
|
||||
|
||||
my %SessionData;
|
||||
ROW:
|
||||
while ( my @Row = $DBObject->FetchrowArray() ) {
|
||||
|
||||
next ROW if !$Row[0];
|
||||
next ROW if !$Row[1];
|
||||
|
||||
$SessionData{ $Row[0] }->{ $Row[1] } = $Row[2];
|
||||
}
|
||||
|
||||
my @ExpiredSession;
|
||||
my @ExpiredIdle;
|
||||
SESSIONID:
|
||||
for my $SessionID ( sort keys %SessionData ) {
|
||||
|
||||
next SESSIONID if !$SessionID;
|
||||
next SESSIONID if !$SessionData{$SessionID};
|
||||
|
||||
# get needed timestamps
|
||||
my $UserSessionStart = $SessionData{$SessionID}->{UserSessionStart} || $TimeNow;
|
||||
my $UserLastRequest = $SessionData{$SessionID}->{UserLastRequest} || $TimeNow;
|
||||
|
||||
# time calculation
|
||||
my $ValidTime = $UserSessionStart + $MaxSessionTime - $TimeNow;
|
||||
my $ValidIdleTime = $UserLastRequest + $MaxSessionIdleTime - $TimeNow;
|
||||
|
||||
# delete invalid session time
|
||||
if ( $ValidTime <= 0 ) {
|
||||
push @ExpiredSession, $SessionID;
|
||||
}
|
||||
|
||||
# delete invalid idle session time
|
||||
elsif ( $ValidIdleTime <= 0 ) {
|
||||
push @ExpiredIdle, $SessionID;
|
||||
}
|
||||
}
|
||||
|
||||
return ( \@ExpiredSession, \@ExpiredIdle );
|
||||
}
|
||||
|
||||
sub CleanUp {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
# get database object
|
||||
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
|
||||
|
||||
# use 'truncate table' if possible in order to reset the auto increment value
|
||||
if (
|
||||
$Self->{DBType} eq 'mysql'
|
||||
|| $Self->{DBType} eq 'postgresql'
|
||||
|| $Self->{DBType} eq 'oracle'
|
||||
|| $Self->{DBType} eq 'mssql'
|
||||
)
|
||||
{
|
||||
|
||||
return if !$DBObject->Do( SQL => "TRUNCATE TABLE $Self->{SessionTable}" );
|
||||
}
|
||||
else {
|
||||
return if !$DBObject->Do( SQL => "DELETE FROM $Self->{SessionTable}" );
|
||||
}
|
||||
|
||||
# remove cached data
|
||||
delete $Self->{Cache};
|
||||
delete $Self->{CacheID};
|
||||
delete $Self->{CacheUpdate};
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub DESTROY {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
return 1 if !$Self->{CacheUpdate};
|
||||
|
||||
# get database object
|
||||
my $DBObject = $Kernel::OM->Get('Kernel::System::DB');
|
||||
|
||||
SESSIONID:
|
||||
for my $SessionID ( sort keys %{ $Self->{CacheUpdate} } ) {
|
||||
|
||||
next SESSIONID if !$SessionID;
|
||||
|
||||
# extract session data to update
|
||||
my $Data = $Self->{CacheUpdate}->{$SessionID};
|
||||
|
||||
next SESSIONID if !$Data;
|
||||
next SESSIONID if ref $Data ne 'HASH';
|
||||
next SESSIONID if !%{$Data};
|
||||
|
||||
# create sql data
|
||||
my @SQLs;
|
||||
$Self->_SQLCreate(
|
||||
Data => $Data,
|
||||
SQLs => \@SQLs,
|
||||
SessionID => $SessionID,
|
||||
);
|
||||
|
||||
next SESSIONID if !@SQLs;
|
||||
|
||||
# store session id and data
|
||||
ROW:
|
||||
for my $Row (@SQLs) {
|
||||
|
||||
next ROW if !$Row;
|
||||
next ROW if ref $Row ne 'HASH';
|
||||
next ROW if !$Row->{SQL};
|
||||
next ROW if !$Row->{Bind};
|
||||
next ROW if ref $Row->{Bind} ne 'ARRAY';
|
||||
|
||||
$DBObject->Do(
|
||||
SQL => $Row->{SQL},
|
||||
Bind => $Row->{Bind},
|
||||
);
|
||||
}
|
||||
|
||||
KEY:
|
||||
for my $Key ( sort keys %{ $Self->{CacheUpdate}->{$SessionID} } ) {
|
||||
|
||||
next KEY if !$Key;
|
||||
|
||||
# extract database id
|
||||
my $ID = $Self->{CacheID}->{$SessionID}->{$Key} || 1;
|
||||
|
||||
# delete old session data from the database
|
||||
$DBObject->Do(
|
||||
SQL => "
|
||||
DELETE FROM $Self->{SessionTable}
|
||||
WHERE session_id = ?
|
||||
AND data_key = ?
|
||||
AND id <= ?",
|
||||
Bind => [ \$SessionID, \$Key, \$ID ],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
# remove cached data
|
||||
delete $Self->{Cache};
|
||||
delete $Self->{CacheID};
|
||||
delete $Self->{CacheUpdate};
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub _SQLCreate {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
return if !$Param{Data};
|
||||
return if ref $Param{Data} ne 'HASH';
|
||||
return if !%{ $Param{Data} };
|
||||
return if !$Param{SessionID};
|
||||
return if !$Param{SQLs};
|
||||
return if ref $Param{SQLs} ne 'ARRAY';
|
||||
|
||||
my $StorableObject = $Kernel::OM->Get('Kernel::System::Storable');
|
||||
|
||||
if ( $Self->{DBType} eq 'mysql' || $Self->{DBType} eq 'postgresql' ) {
|
||||
|
||||
# define row
|
||||
my $SQL = "INSERT INTO $Self->{SessionTable} "
|
||||
. "(session_id, data_key, data_value, serialized) VALUES ";
|
||||
my @Bind;
|
||||
|
||||
KEY:
|
||||
for my $Key ( sort keys %{ $Param{Data} } ) {
|
||||
|
||||
next KEY if !$Key;
|
||||
|
||||
my $Value = $Param{Data}->{$Key};
|
||||
my $Serialized = 0;
|
||||
|
||||
if (
|
||||
ref $Value eq 'HASH'
|
||||
|| ref $Value eq 'ARRAY'
|
||||
|| ref $Value eq 'SCALAR'
|
||||
)
|
||||
{
|
||||
|
||||
# dump the data
|
||||
$Value = MIME::Base64::encode_base64(
|
||||
$StorableObject->Serialize( Data => $Value )
|
||||
);
|
||||
$Serialized = 1;
|
||||
}
|
||||
|
||||
push @Bind, \$Param{SessionID};
|
||||
push @Bind, \$Key;
|
||||
push @Bind, \$Value;
|
||||
push @Bind, \$Serialized;
|
||||
|
||||
$SQL .= '(?,?,?,?),';
|
||||
}
|
||||
|
||||
# remove the last character
|
||||
chop $SQL;
|
||||
|
||||
my %Row = (
|
||||
SQL => $SQL,
|
||||
Bind => \@Bind,
|
||||
);
|
||||
|
||||
push @{ $Param{SQLs} }, \%Row;
|
||||
|
||||
return 1;
|
||||
}
|
||||
elsif ( $Self->{DBType} eq 'oracle' ) {
|
||||
|
||||
# define row
|
||||
my $SQL = '';
|
||||
my @Bind;
|
||||
my $Counter = 0;
|
||||
|
||||
KEY:
|
||||
for my $Key ( sort keys %{ $Param{Data} } ) {
|
||||
|
||||
next KEY if !$Key;
|
||||
|
||||
$Counter++;
|
||||
|
||||
my $Value = $Param{Data}->{$Key};
|
||||
my $Serialized = 0;
|
||||
|
||||
if (
|
||||
!defined $Value
|
||||
|| $Value eq ''
|
||||
|| ref $Value eq 'HASH'
|
||||
|| ref $Value eq 'ARRAY'
|
||||
|| ref $Value eq 'SCALAR'
|
||||
)
|
||||
{
|
||||
|
||||
# workaround for the oracle problem with empty strings
|
||||
# and NULL values in VARCHAR columns
|
||||
if ( !defined $Value ) {
|
||||
|
||||
my $Empty = undef;
|
||||
$Value = \$Empty;
|
||||
}
|
||||
elsif ( $Value eq '' ) {
|
||||
|
||||
my $Empty = '';
|
||||
$Value = \$Empty;
|
||||
}
|
||||
|
||||
# dump the data
|
||||
$Value = MIME::Base64::encode_base64(
|
||||
$StorableObject->Serialize( Data => $Value )
|
||||
);
|
||||
$Serialized = 1;
|
||||
}
|
||||
|
||||
$SQL ||= 'INSERT ALL ';
|
||||
$SQL .= "INTO $Self->{SessionTable} "
|
||||
. "(session_id, data_key, data_value, serialized) VALUES (?,?,?,?) ";
|
||||
|
||||
push @Bind, \$Param{SessionID};
|
||||
push @Bind, \$Key;
|
||||
push @Bind, \$Value;
|
||||
push @Bind, \$Serialized;
|
||||
|
||||
# split SQLs with more than 4k charecters
|
||||
next KEY if $Counter < 40;
|
||||
|
||||
# copy bind to be able to clean the array reference
|
||||
my @BindCopy = @Bind;
|
||||
|
||||
$SQL .= 'SELECT * FROM dual';
|
||||
|
||||
my %Row = (
|
||||
SQL => $SQL,
|
||||
Bind => \@BindCopy,
|
||||
);
|
||||
|
||||
push @{ $Param{SQLs} }, \%Row;
|
||||
|
||||
# clean variable
|
||||
$SQL = '';
|
||||
@Bind = ();
|
||||
$Counter = 0;
|
||||
}
|
||||
|
||||
if ( $SQL && @Bind ) {
|
||||
|
||||
$SQL .= 'SELECT * FROM dual';
|
||||
|
||||
my %Row = (
|
||||
SQL => $SQL,
|
||||
Bind => \@Bind,
|
||||
);
|
||||
|
||||
push @{ $Param{SQLs} }, \%Row;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
|
||||
KEY:
|
||||
for my $Key ( sort keys %{ $Param{Data} } ) {
|
||||
|
||||
next KEY if !$Key;
|
||||
|
||||
my $Value = $Param{Data}->{$Key};
|
||||
my $Serialized = 0;
|
||||
|
||||
if (
|
||||
ref $Value eq 'HASH'
|
||||
|| ref $Value eq 'ARRAY'
|
||||
|| ref $Value eq 'SCALAR'
|
||||
)
|
||||
{
|
||||
|
||||
# dump the data
|
||||
$Value = MIME::Base64::encode_base64(
|
||||
$StorableObject->Serialize( Data => $Value )
|
||||
);
|
||||
$Serialized = 1;
|
||||
}
|
||||
|
||||
my @Bind;
|
||||
push @Bind, \$Param{SessionID};
|
||||
push @Bind, \$Key;
|
||||
push @Bind, \$Value;
|
||||
push @Bind, \$Serialized;
|
||||
|
||||
my $SQL = "INSERT INTO $Self->{SessionTable} "
|
||||
. "(session_id, data_key, data_value, serialized) VALUES (?,?,?,?)";
|
||||
|
||||
my %Row = (
|
||||
SQL => $SQL,
|
||||
Bind => \@Bind,
|
||||
);
|
||||
|
||||
push @{ $Param{SQLs} }, \%Row;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
||||
594
Perl OTRS/Kernel/System/AuthSession/FS.pm
Normal file
594
Perl OTRS/Kernel/System/AuthSession/FS.pm
Normal file
@@ -0,0 +1,594 @@
|
||||
# --
|
||||
# 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::FS;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use Kernel::Language qw(Translatable);
|
||||
|
||||
our @ObjectDependencies = (
|
||||
'Kernel::Config',
|
||||
'Kernel::System::DateTime',
|
||||
'Kernel::System::Log',
|
||||
'Kernel::System::Main',
|
||||
'Kernel::System::Storable',
|
||||
);
|
||||
|
||||
sub new {
|
||||
my ( $Type, %Param ) = @_;
|
||||
|
||||
# allocate new hash for object
|
||||
my $Self = {};
|
||||
bless( $Self, $Type );
|
||||
|
||||
# get config object
|
||||
my $ConfigObject = $Kernel::OM->Get('Kernel::Config');
|
||||
|
||||
# get more common params
|
||||
$Self->{SessionSpool} = $ConfigObject->Get('SessionDir');
|
||||
$Self->{SystemID} = $ConfigObject->Get('SystemID');
|
||||
|
||||
if ( !-e $Self->{SessionSpool} ) {
|
||||
if ( !mkdir( $Self->{SessionSpool}, 0770 ) ) { ## no critic
|
||||
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
||||
Priority => 'error',
|
||||
Message => "Can't create directory '$Self->{SessionSpool}': $!",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $Self;
|
||||
}
|
||||
|
||||
sub CheckSessionID {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
# check session id
|
||||
if ( !$Param{SessionID} ) {
|
||||
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
||||
Priority => 'error',
|
||||
Message => 'Got no SessionID!!'
|
||||
);
|
||||
return;
|
||||
}
|
||||
my $RemoteAddr = $ENV{REMOTE_ADDR} || 'none';
|
||||
|
||||
# set default message
|
||||
$Self->{SessionIDErrorMessage} = Translatable('Session invalid. Please log in again.');
|
||||
|
||||
# session id check
|
||||
my %Data = $Self->GetSessionIDData( SessionID => $Param{SessionID} );
|
||||
|
||||
if ( !$Data{UserID} || !$Data{UserLogin} ) {
|
||||
$Self->{SessionIDErrorMessage} = Translatable('Session invalid. Please log in again.');
|
||||
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
||||
Priority => 'notice',
|
||||
Message => "SessionID: '$Param{SessionID}' is invalid!!!",
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
# get config object
|
||||
my $ConfigObject = $Kernel::OM->Get('Kernel::Config');
|
||||
|
||||
# remote ip check
|
||||
if (
|
||||
$Data{UserRemoteAddr} ne $RemoteAddr
|
||||
&& $ConfigObject->Get('SessionCheckRemoteIP')
|
||||
)
|
||||
{
|
||||
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
||||
Priority => 'notice',
|
||||
Message => "RemoteIP of '$Param{SessionID}' ($Data{UserRemoteAddr}) is "
|
||||
. "different from registered IP ($RemoteAddr). Invalidating session!"
|
||||
. " Disable config 'SessionCheckRemoteIP' if you don't want this!",
|
||||
);
|
||||
|
||||
# delete session id if it isn't the same remote ip?
|
||||
if ( $ConfigObject->Get('SessionDeleteIfNotRemoteID') ) {
|
||||
$Self->RemoveSessionID( SessionID => $Param{SessionID} );
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
# check session idle time
|
||||
my $TimeNow = $Kernel::OM->Create('Kernel::System::DateTime')->ToEpoch();
|
||||
my $MaxSessionIdleTime = $ConfigObject->Get('SessionMaxIdleTime');
|
||||
|
||||
if ( ( $TimeNow - $MaxSessionIdleTime ) >= $Data{UserLastRequest} ) {
|
||||
|
||||
$Self->{SessionIDErrorMessage} = Translatable('Session has timed out. Please log in again.');
|
||||
|
||||
my $Timeout = int( ( $TimeNow - $Data{UserLastRequest} ) / ( 60 * 60 ) );
|
||||
|
||||
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
||||
Priority => 'notice',
|
||||
Message =>
|
||||
"SessionID ($Param{SessionID}) idle timeout ($Timeout h)! Don't grant access!!!",
|
||||
);
|
||||
|
||||
# delete session id if too old?
|
||||
if ( $ConfigObject->Get('SessionDeleteIfTimeToOld') ) {
|
||||
$Self->RemoveSessionID( SessionID => $Param{SessionID} );
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
# check session time
|
||||
my $MaxSessionTime = $ConfigObject->Get('SessionMaxTime');
|
||||
|
||||
if ( ( $TimeNow - $MaxSessionTime ) >= $Data{UserSessionStart} ) {
|
||||
|
||||
$Self->{SessionIDErrorMessage} = Translatable('Session has timed out. Please log in again.');
|
||||
|
||||
my $Timeout = int( ( $TimeNow - $Data{UserSessionStart} ) / ( 60 * 60 ) );
|
||||
|
||||
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
||||
Priority => 'notice',
|
||||
Message => "SessionID ($Param{SessionID}) too old ($Timeout h)! Don't grant access!!!",
|
||||
);
|
||||
|
||||
# delete session id if too old?
|
||||
if ( $ConfigObject->Get('SessionDeleteIfTimeToOld') ) {
|
||||
$Self->RemoveSessionID( SessionID => $Param{SessionID} );
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub SessionIDErrorMessage {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
return $Self->{SessionIDErrorMessage} || '';
|
||||
}
|
||||
|
||||
sub GetSessionIDData {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
# check session id
|
||||
if ( !$Param{SessionID} ) {
|
||||
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
||||
Priority => 'error',
|
||||
Message => 'Got no SessionID!!'
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
# check cache
|
||||
return %{ $Self->{Cache}->{ $Param{SessionID} } }
|
||||
if $Self->{Cache}->{ $Param{SessionID} };
|
||||
|
||||
# read data
|
||||
my $Content = $Kernel::OM->Get('Kernel::System::Main')->FileRead(
|
||||
Directory => $Self->{SessionSpool},
|
||||
Filename => 'Data-' . $Param{SessionID},
|
||||
Type => 'Local',
|
||||
Mode => 'binmode',
|
||||
DisableWarnings => 1,
|
||||
);
|
||||
|
||||
return if !$Content;
|
||||
return if ref $Content ne 'SCALAR';
|
||||
|
||||
# read data structure back from file dump, use block eval for safety reasons
|
||||
my $Session = eval {
|
||||
$Kernel::OM->Get('Kernel::System::Storable')->Deserialize( Data => ${$Content} );
|
||||
};
|
||||
|
||||
if ( !$Session || ref $Session ne 'HASH' ) {
|
||||
delete $Self->{Cache}->{ $Param{SessionID} };
|
||||
return;
|
||||
}
|
||||
|
||||
# cache result
|
||||
$Self->{Cache}->{ $Param{SessionID} } = $Session;
|
||||
|
||||
return %{$Session};
|
||||
}
|
||||
|
||||
sub CreateSessionID {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
# get system time
|
||||
my $TimeNow = $Kernel::OM->Create('Kernel::System::DateTime')->ToEpoch();
|
||||
|
||||
# get remote address and the http user agent
|
||||
my $RemoteAddr = $ENV{REMOTE_ADDR} || 'none';
|
||||
my $RemoteUserAgent = $ENV{HTTP_USER_AGENT} || 'none';
|
||||
|
||||
my $MainObject = $Kernel::OM->Get('Kernel::System::Main');
|
||||
|
||||
# create session id
|
||||
my $SessionID = $Self->{SystemID} . $MainObject->GenerateRandomString(
|
||||
Length => 32,
|
||||
);
|
||||
|
||||
# create challenge token
|
||||
my $ChallengeToken = $MainObject->GenerateRandomString(
|
||||
Length => 32,
|
||||
);
|
||||
|
||||
my %Data;
|
||||
KEY:
|
||||
for my $Key ( sort keys %Param ) {
|
||||
|
||||
next KEY if !$Key;
|
||||
|
||||
$Data{$Key} = $Param{$Key};
|
||||
}
|
||||
|
||||
$Data{UserSessionStart} = $TimeNow;
|
||||
$Data{UserRemoteAddr} = $RemoteAddr;
|
||||
$Data{UserRemoteUserAgent} = $RemoteUserAgent;
|
||||
$Data{UserChallengeToken} = $ChallengeToken;
|
||||
|
||||
# dump the data
|
||||
my $DataContent = $Kernel::OM->Get('Kernel::System::Storable')->Serialize( Data => \%Data );
|
||||
|
||||
# write data file
|
||||
my $FileLocation = $MainObject->FileWrite(
|
||||
Directory => $Self->{SessionSpool},
|
||||
Filename => 'Data-' . $SessionID,
|
||||
Content => \$DataContent,
|
||||
Type => 'Local',
|
||||
Mode => 'binmode',
|
||||
Permission => '660',
|
||||
DisableWarnings => 1,
|
||||
);
|
||||
|
||||
return if !$FileLocation;
|
||||
|
||||
# set cache
|
||||
$Self->{Cache}->{$SessionID} = \%Data;
|
||||
|
||||
# create needed state content
|
||||
my $UserType = $Self->{Cache}->{$SessionID}->{UserType} || '';
|
||||
my $UserLogin = $Self->{Cache}->{$SessionID}->{UserLogin} || '';
|
||||
my $UserSessionStart = $Self->{Cache}->{$SessionID}->{UserSessionStart} || '';
|
||||
my $UserLastRequest = $Self->{Cache}->{$SessionID}->{UserLastRequest} || '';
|
||||
my $SessionSource = $Self->{Cache}->{$SessionID}->{SessionSource} || '';
|
||||
|
||||
my $StateContent = $UserType . '####' . $UserLogin . '####' . $UserSessionStart . '####' . $UserLastRequest;
|
||||
|
||||
if ($SessionSource) {
|
||||
$StateContent .= '####' . $SessionSource;
|
||||
}
|
||||
|
||||
# write state file
|
||||
$MainObject->FileWrite(
|
||||
Directory => $Self->{SessionSpool},
|
||||
Filename => 'State-' . $SessionID,
|
||||
Content => \$StateContent,
|
||||
Type => 'Local',
|
||||
Mode => 'binmode',
|
||||
Permission => '660',
|
||||
DisableWarnings => 1,
|
||||
);
|
||||
|
||||
return $SessionID;
|
||||
}
|
||||
|
||||
sub RemoveSessionID {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
# check session id
|
||||
if ( !$Param{SessionID} ) {
|
||||
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
||||
Priority => 'error',
|
||||
Message => 'Got no SessionID!!'
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
my $MainObject = $Kernel::OM->Get('Kernel::System::Main');
|
||||
|
||||
# delete file
|
||||
my $DeleteData = $MainObject->FileDelete(
|
||||
Directory => $Self->{SessionSpool},
|
||||
Filename => 'Data-' . $Param{SessionID},
|
||||
Type => 'Local',
|
||||
DisableWarnings => 1,
|
||||
);
|
||||
my $DeleteState = $MainObject->FileDelete(
|
||||
Directory => $Self->{SessionSpool},
|
||||
Filename => 'State-' . $Param{SessionID},
|
||||
Type => 'Local',
|
||||
DisableWarnings => 1,
|
||||
);
|
||||
|
||||
return if !$DeleteData;
|
||||
return if !$DeleteState;
|
||||
|
||||
delete $Self->{Cache}->{ $Param{SessionID} };
|
||||
|
||||
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
||||
Priority => 'notice',
|
||||
Message => "Removed SessionID $Param{SessionID}."
|
||||
);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub UpdateSessionID {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
# check needed stuff
|
||||
for (qw(SessionID Key)) {
|
||||
if ( !$Param{$_} ) {
|
||||
$Kernel::OM->Get('Kernel::System::Log')->Log(
|
||||
Priority => 'error',
|
||||
Message => "Need $_!"
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
# check cache
|
||||
if ( !$Self->{Cache}->{ $Param{SessionID} } ) {
|
||||
my %SessionData = $Self->GetSessionIDData( SessionID => $Param{SessionID} );
|
||||
|
||||
$Self->{Cache}->{ $Param{SessionID} } = \%SessionData;
|
||||
}
|
||||
|
||||
# update the value, set cache
|
||||
$Self->{Cache}->{ $Param{SessionID} }->{ $Param{Key} } = $Param{Value};
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub GetAllSessionIDs {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
# read data
|
||||
my @List = $Kernel::OM->Get('Kernel::System::Main')->DirectoryRead(
|
||||
Directory => $Self->{SessionSpool},
|
||||
Filter => 'Data-' . $Self->{SystemID} . '*',
|
||||
);
|
||||
|
||||
my @SessionIDs;
|
||||
for my $SessionID (@List) {
|
||||
$SessionID =~ s!^.*/!!;
|
||||
$SessionID =~ s{ Data- } {}xms;
|
||||
push @SessionIDs, $SessionID;
|
||||
}
|
||||
|
||||
return @SessionIDs;
|
||||
}
|
||||
|
||||
sub GetActiveSessions {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
my $MaxSessionIdleTime = $Kernel::OM->Get('Kernel::Config')->Get('SessionMaxIdleTime');
|
||||
|
||||
my $TimeNow = $Kernel::OM->Create('Kernel::System::DateTime')->ToEpoch();
|
||||
|
||||
my $MainObject = $Kernel::OM->Get('Kernel::System::Main');
|
||||
|
||||
my @List = $MainObject->DirectoryRead(
|
||||
Directory => $Self->{SessionSpool},
|
||||
Filter => 'State-' . $Self->{SystemID} . '*',
|
||||
);
|
||||
|
||||
my $ActiveSessionCount = 0;
|
||||
my %ActiveSessionPerUserCount;
|
||||
SESSIONID:
|
||||
for my $SessionID (@List) {
|
||||
|
||||
$SessionID =~ s!^.*/!!;
|
||||
$SessionID =~ s{ State- } {}xms;
|
||||
|
||||
next SESSIONID if !$SessionID;
|
||||
|
||||
# read state data
|
||||
my $StateData = $MainObject->FileRead(
|
||||
Directory => $Self->{SessionSpool},
|
||||
Filename => 'State-' . $SessionID,
|
||||
Type => 'Local',
|
||||
Mode => 'binmode',
|
||||
DisableWarnings => 1,
|
||||
);
|
||||
|
||||
next SESSIONID if !$StateData;
|
||||
next SESSIONID if ref $StateData ne 'SCALAR';
|
||||
|
||||
my @SessionData = split '####', ${$StateData};
|
||||
|
||||
# get needed data
|
||||
my $UserType = $SessionData[0] || '';
|
||||
my $UserLogin = $SessionData[1] || '';
|
||||
my $UserLastRequest = $SessionData[3] || $TimeNow;
|
||||
my $SessionSource = $SessionData[4] || '';
|
||||
|
||||
# Don't count sessions from source 'GenericInterface'.
|
||||
next SESSIONID if $SessionSource eq 'GenericInterface';
|
||||
|
||||
next SESSIONID if $UserType ne $Param{UserType};
|
||||
|
||||
next SESSIONID if ( $UserLastRequest + $MaxSessionIdleTime ) < $TimeNow;
|
||||
|
||||
$ActiveSessionCount++;
|
||||
|
||||
$ActiveSessionPerUserCount{$UserLogin} || 0;
|
||||
$ActiveSessionPerUserCount{$UserLogin}++;
|
||||
}
|
||||
|
||||
my %Result = (
|
||||
Total => $ActiveSessionCount,
|
||||
PerUser => \%ActiveSessionPerUserCount,
|
||||
);
|
||||
|
||||
return %Result;
|
||||
}
|
||||
|
||||
sub GetExpiredSessionIDs {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
# get config object
|
||||
my $ConfigObject = $Kernel::OM->Get('Kernel::Config');
|
||||
|
||||
# get config
|
||||
my $MaxSessionTime = $ConfigObject->Get('SessionMaxTime');
|
||||
my $MaxSessionIdleTime = $ConfigObject->Get('SessionMaxIdleTime');
|
||||
|
||||
# get current time
|
||||
my $TimeNow = $Kernel::OM->Create('Kernel::System::DateTime')->ToEpoch();
|
||||
|
||||
# get main object
|
||||
my $MainObject = $Kernel::OM->Get('Kernel::System::Main');
|
||||
|
||||
# read data
|
||||
my @List = $MainObject->DirectoryRead(
|
||||
Directory => $Self->{SessionSpool},
|
||||
Filter => 'State-' . $Self->{SystemID} . '*',
|
||||
);
|
||||
|
||||
my @ExpiredSession;
|
||||
my @ExpiredIdle;
|
||||
SESSIONID:
|
||||
for my $SessionID (@List) {
|
||||
|
||||
$SessionID =~ s!^.*/!!;
|
||||
$SessionID =~ s{ State- } {}xms;
|
||||
|
||||
next SESSIONID if !$SessionID;
|
||||
|
||||
# read state data
|
||||
my $StateData = $MainObject->FileRead(
|
||||
Directory => $Self->{SessionSpool},
|
||||
Filename => 'State-' . $SessionID,
|
||||
Type => 'Local',
|
||||
Mode => 'binmode',
|
||||
DisableWarnings => 1,
|
||||
);
|
||||
|
||||
next SESSIONID if !$StateData;
|
||||
next SESSIONID if ref $StateData ne 'SCALAR';
|
||||
|
||||
my @SessionData = split '####', ${$StateData};
|
||||
|
||||
# get needed data
|
||||
my $UserSessionStart = $SessionData[2] || $TimeNow;
|
||||
my $UserLastRequest = $SessionData[3] || $TimeNow;
|
||||
|
||||
# time calculation
|
||||
my $ValidTime = $UserSessionStart + $MaxSessionTime - $TimeNow;
|
||||
my $ValidIdleTime = $UserLastRequest + $MaxSessionIdleTime - $TimeNow;
|
||||
|
||||
# delete invalid session time
|
||||
if ( $ValidTime <= 0 ) {
|
||||
push @ExpiredSession, $SessionID;
|
||||
}
|
||||
|
||||
# delete invalid idle session time
|
||||
elsif ( $ValidIdleTime <= 0 ) {
|
||||
push @ExpiredIdle, $SessionID;
|
||||
}
|
||||
}
|
||||
|
||||
return ( \@ExpiredSession, \@ExpiredIdle );
|
||||
}
|
||||
|
||||
sub CleanUp {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
# delete fs files
|
||||
my @SessionIDs = $Self->GetAllSessionIDs();
|
||||
|
||||
return 1 if !@SessionIDs;
|
||||
|
||||
SESSIONID:
|
||||
for my $SessionID (@SessionIDs) {
|
||||
|
||||
next SESSIONID if !$SessionID;
|
||||
|
||||
$Self->RemoveSessionID( SessionID => $SessionID );
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub DESTROY {
|
||||
my ( $Self, %Param ) = @_;
|
||||
|
||||
return 1 if !$Self->{Cache};
|
||||
|
||||
# get main object
|
||||
my $MainObject = $Kernel::OM->Get('Kernel::System::Main');
|
||||
|
||||
SESSIONID:
|
||||
for my $SessionID ( sort keys %{ $Self->{Cache} } ) {
|
||||
|
||||
next SESSIONID if !$SessionID;
|
||||
|
||||
my %SessionData;
|
||||
KEY:
|
||||
for my $Key ( sort keys %{ $Self->{Cache}->{$SessionID} } ) {
|
||||
|
||||
next KEY if !$Key;
|
||||
|
||||
$SessionData{$Key} = $Self->{Cache}->{$SessionID}->{$Key};
|
||||
}
|
||||
|
||||
# dump the data
|
||||
my $DataContent = $Kernel::OM->Get('Kernel::System::Storable')->Serialize(
|
||||
Data => \%SessionData,
|
||||
);
|
||||
|
||||
# write data file
|
||||
$MainObject->FileWrite(
|
||||
Directory => $Self->{SessionSpool},
|
||||
Filename => 'Data-' . $SessionID,
|
||||
Content => \$DataContent,
|
||||
Type => 'Local',
|
||||
Mode => 'binmode',
|
||||
Permission => '660',
|
||||
DisableWarnings => 1,
|
||||
);
|
||||
|
||||
# create needed state content
|
||||
my $UserType = $Self->{Cache}->{$SessionID}->{UserType} || '';
|
||||
my $UserLogin = $Self->{Cache}->{$SessionID}->{UserLogin} || '';
|
||||
my $UserSessionStart = $Self->{Cache}->{$SessionID}->{UserSessionStart} || '';
|
||||
my $UserLastRequest = $Self->{Cache}->{$SessionID}->{UserLastRequest} || '';
|
||||
my $SessionSource = $Self->{Cache}->{$SessionID}->{SessionSource} || '';
|
||||
|
||||
my $StateContent = $UserType . '####'
|
||||
. $UserLogin . '####'
|
||||
. $UserSessionStart . '####'
|
||||
. $UserLastRequest;
|
||||
|
||||
if ($SessionSource) {
|
||||
$StateContent .= '####' . $SessionSource;
|
||||
}
|
||||
|
||||
# write state file
|
||||
$MainObject->FileWrite(
|
||||
Directory => $Self->{SessionSpool},
|
||||
Filename => 'State-' . $SessionID,
|
||||
Content => \$StateContent,
|
||||
Type => 'Local',
|
||||
Mode => 'binmode',
|
||||
Permission => '660',
|
||||
DisableWarnings => 1,
|
||||
);
|
||||
}
|
||||
|
||||
# remove cached data
|
||||
delete $Self->{Cache};
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
1;
|
||||
Reference in New Issue
Block a user