diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..a2d7cfd
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+dist/*.opm
diff --git a/.includepath b/.includepath
new file mode 100644
index 0000000..da00c9f
--- /dev/null
+++ b/.includepath
@@ -0,0 +1,6 @@
+
+
+
+
+
+
diff --git a/.project b/.project
new file mode 100644
index 0000000..40a4a47
--- /dev/null
+++ b/.project
@@ -0,0 +1,18 @@
+
+
+ otrs-cas
+
+
+ otrs
+
+
+
+ org.epic.perleditor.perlbuilder
+
+
+
+
+
+ org.epic.perleditor.perlnature
+
+
diff --git a/CASAuthentication.sopm b/CASAuthentication.sopm
new file mode 100755
index 0000000..0880f2d
--- /dev/null
+++ b/CASAuthentication.sopm
@@ -0,0 +1,56 @@
+
+
+ CASAuthentication
+ 1.3.0
+ 6.0.1
+ Rodrigo Gonçalves (rodrigo@goncalves.pro.br)
+ http://www.goncalves.pro.br/
+ AGPL
+
+ First Version
+ Support for OTRS 4
+ Bug in customer authentication for OTRS 4
+ Support for users not in database (custom redirect)
+ Fix for authentication with redirect URL
+ Support for OTRS 5.0.x and fix for agent redirection on first link
+ Support for OTRS 6.0.1
+
+ CAS Authentication (Jasig) Module
+
+ ?
+ ?
+
+
+
+ In order to active the module, the following lines should be included/changed in Kernel/Config.pm:
+
+ $Self->{'AuthModule'} = 'Kernel::System::Auth::CAS';
+ $Self->{'AuthModule::CAS::Gateway'} = 0;
+ $Self->{'AuthModule::CAS::ServiceUrl'} = 'URL FOR OTRS AGENT INDEX (ex: https://host.com/otrs/index.pl)';
+ $Self->{'AuthModule::CAS::CASUrl'} = 'URL FOR CAS SERVICE (WITHOUT TRAILING /) - ex: https://cas.systems.com';
+
+ $Self->{'Customer::AuthModule'} = 'Kernel::System::CustomerAuth::CAS';
+ $Self->{'Customer::AuthModule::CAS::Gateway'} = 0;
+ $Self->{'Customer::AuthModule::CAS::ServiceUrl'} = 'URL FOR OTRS CUSTOMER INDEX (ex: https://host.com/otrs/customer.pl)';
+ $Self->{'Customer::AuthModule::CAS::CASUrl'} = 'URL FOR CAS SERVICE (WITHOUT TRAILING /) - ex: https://cas.systems.com';
+
+ ]]>
+
+ AuthCAS
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Custom/Kernel/System/Web/InterfaceAgent.pm b/Custom/Kernel/System/Web/InterfaceAgent.pm
new file mode 100644
index 0000000..6ab18a7
--- /dev/null
+++ b/Custom/Kernel/System/Web/InterfaceAgent.pm
@@ -0,0 +1,1242 @@
+# --
+# Copyright (C) 2001-2017 OTRS AG, http://otrs.com/
+# --
+# 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.
+#
+#
+# Custom version for CAS authentication - rodrigo@goncalves.pro.br
+#
+# Version 18/01/2016 - RG - Version for OTRS 5.0.6
+# Version 2017-12-07 - RG - Version for OTRS 6.0.1
+#
+# --
+
+package Kernel::System::Web::InterfaceAgent;
+
+use strict;
+use warnings;
+
+# CAS Custom
+use CGI;
+use URI::Escape;
+# CAS Custom
+
+use Kernel::Language qw(Translatable);
+use Kernel::System::DateTime;
+
+our @ObjectDependencies = (
+ 'Kernel::Config',
+ 'Kernel::Output::HTML::Layout',
+ 'Kernel::System::Auth',
+ 'Kernel::System::AuthSession',
+ 'Kernel::System::DB',
+ 'Kernel::System::Email',
+ 'Kernel::System::Group',
+ 'Kernel::System::Log',
+ 'Kernel::System::Main',
+ 'Kernel::System::Scheduler',
+ 'Kernel::System::DateTime',
+ 'Kernel::System::User',
+ 'Kernel::System::Web::Request',
+ 'Kernel::System::Valid',
+);
+
+=head1 NAME
+
+Kernel::System::Web::InterfaceAgent - the agent web interface
+
+=head1 DESCRIPTION
+
+the global agent web interface (authentication, session handling, ...)
+
+=head1 PUBLIC INTERFACE
+
+=head2 new()
+
+create agent web interface object. Do not use it directly, instead use:
+
+ use Kernel::System::ObjectManager;
+ my $Debug = 0,
+ local $Kernel::OM = Kernel::System::ObjectManager->new(
+ 'Kernel::System::Web::InterfaceAgent' => {
+ Debug => 0,
+ WebRequest => CGI::Fast->new(), # optional, e. g. if fast cgi is used,
+ # the CGI object is already provided
+ }
+ );
+ my $InterfaceAgent = $Kernel::OM->Get('Kernel::System::Web::InterfaceAgent');
+
+=cut
+
+sub new {
+ my ( $Type, %Param ) = @_;
+ my $Self = {};
+ bless( $Self, $Type );
+
+ # Performance log
+ $Self->{PerformanceLogStart} = time();
+
+ # get debug level
+ $Self->{Debug} = $Param{Debug} || 0;
+
+ $Kernel::OM->ObjectParamAdd(
+ 'Kernel::System::Log' => {
+ LogPrefix => $Kernel::OM->Get('Kernel::Config')->Get('CGILogPrefix'),
+ },
+ 'Kernel::System::Web::Request' => {
+ WebRequest => $Param{WebRequest} || 0,
+ },
+ );
+
+ # debug info
+ if ( $Self->{Debug} ) {
+ $Kernel::OM->Get('Kernel::System::Log')->Log(
+ Priority => 'debug',
+ Message => 'Global handle started...',
+ );
+ }
+
+ return $Self;
+}
+
+=head2 Run()
+
+execute the object
+
+ $InterfaceAgent->Run();
+
+=cut
+
+sub Run {
+ my $Self = shift;
+
+ # CAS Custom
+ if ($Self->CASLogout()) {
+ return;
+ }
+ # CAS Custom
+
+ my $ConfigObject = $Kernel::OM->Get('Kernel::Config');
+
+ my $QueryString = $ENV{QUERY_STRING} || '';
+
+ # Check if https forcing is active, and redirect if needed.
+ if ( $ConfigObject->Get('HTTPSForceRedirect') ) {
+
+ # Some web servers do not set HTTPS environment variable, so it's not possible to easily know if we are using
+ # https protocol. Look also for similarly named keys in environment hash, since this should prevent loops in
+ # certain cases.
+ if (
+ (
+ !defined $ENV{HTTPS}
+ && !grep {/^HTTPS(?:_|$)/} keys %ENV
+ )
+ || $ENV{HTTPS} ne 'on'
+ )
+ {
+ my $Host = $ENV{HTTP_HOST} || $ConfigObject->Get('FQDN');
+
+ # Redirect with 301 code. Add two new lines at the end, so HTTP headers are validated correctly.
+ print "Status: 301 Moved Permanently\nLocation: https://$Host$ENV{REQUEST_URI}\n\n";
+ return;
+ }
+ }
+
+ my $ParamObject = $Kernel::OM->Get('Kernel::System::Web::Request');
+
+ my %Param;
+
+ # get session id
+ $Param{SessionName} = $ConfigObject->Get('SessionName') || 'SessionID';
+ $Param{SessionID} = $ParamObject->GetParam( Param => $Param{SessionName} ) || '';
+
+ # drop old session id (if exists)
+ $QueryString =~ s/(\?|&|;|)$Param{SessionName}(=&|=;|=.+?&|=.+?$)/;/g;
+
+ # define framework params
+ my $FrameworkParams = {
+ Lang => '',
+ Action => '',
+ Subaction => '',
+ RequestedURL => $QueryString,
+ };
+ for my $Key ( sort keys %{$FrameworkParams} ) {
+ $Param{$Key} = $ParamObject->GetParam( Param => $Key )
+ || $FrameworkParams->{$Key};
+ }
+
+ # validate language
+ if ( $Param{Lang} && $Param{Lang} !~ m{\A[a-z]{2}(?:_[A-Z]{2})?\z}xms ) {
+ delete $Param{Lang};
+ }
+
+ # check if the browser sends the SessionID cookie and set the SessionID-cookie
+ # as SessionID! GET or POST SessionID have the lowest priority.
+ my $BrowserHasCookie = 0;
+ if ( $ConfigObject->Get('SessionUseCookie') ) {
+ $Param{SessionIDCookie} = $ParamObject->GetCookie( Key => $Param{SessionName} );
+ if ( $Param{SessionIDCookie} ) {
+ $Param{SessionID} = $Param{SessionIDCookie};
+ }
+ }
+
+ $Kernel::OM->ObjectParamAdd(
+ 'Kernel::Output::HTML::Layout' => {
+ Lang => $Param{Lang},
+ UserLanguage => $Param{Lang},
+ },
+ 'Kernel::Language' => {
+ UserLanguage => $Param{Lang}
+ },
+ );
+
+ my $CookieSecureAttribute;
+ if ( $ConfigObject->Get('HttpType') eq 'https' ) {
+
+ # Restrict Cookie to HTTPS if it is used.
+ $CookieSecureAttribute = 1;
+ }
+
+ my $DBCanConnect = $Kernel::OM->Get('Kernel::System::DB')->Connect();
+
+ if ( !$DBCanConnect || $ParamObject->Error() ) {
+ my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
+ if ( !$DBCanConnect ) {
+ $LayoutObject->FatalError(
+ Comment => Translatable('Please contact the administrator.'),
+ );
+ return;
+ }
+ if ( $ParamObject->Error() ) {
+ $LayoutObject->FatalError(
+ Message => $ParamObject->Error(),
+ Comment => Translatable('Please contact the administrator.'),
+ );
+ return;
+ }
+ }
+
+ # get common application and add-on application params
+ my %CommonObjectParam = %{ $ConfigObject->Get('Frontend::CommonParam') };
+ for my $Key ( sort keys %CommonObjectParam ) {
+ $Param{$Key} = $ParamObject->GetParam( Param => $Key ) || $CommonObjectParam{$Key};
+ }
+
+ # security check Action Param (replace non word chars)
+ $Param{Action} =~ s/\W//g;
+
+ my $SessionObject = $Kernel::OM->Get('Kernel::System::AuthSession');
+ my $UserObject = $Kernel::OM->Get('Kernel::System::User');
+
+ # check request type
+ if ( $Param{Action} eq 'PreLogin' ) {
+ my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
+ $Param{RequestedURL} = $Param{RequestedURL} || "Action=AgentDashboard";
+
+ # login screen
+ $LayoutObject->Print(
+ Output => \$LayoutObject->Login(
+ Title => 'Login',
+ Mode => 'PreLogin',
+ %Param,
+ ),
+ );
+
+ return;
+ }
+ elsif ( $Param{Action} eq 'Login' ) {
+
+ # get params
+ my $PostUser = $ParamObject->GetParam( Param => 'User' ) || '';
+ my $PostPw = $ParamObject->GetParam(
+ Param => 'Password',
+ Raw => 1
+ ) || '';
+ my $PostTwoFactorToken = $ParamObject->GetParam(
+ Param => 'TwoFactorToken',
+ Raw => 1
+ ) || '';
+
+ # create AuthObject
+ my $AuthObject = $Kernel::OM->Get('Kernel::System::Auth');
+
+ # check submitted data
+ my $User = $AuthObject->Auth(
+ User => $PostUser,
+ Pw => $PostPw,
+ TwoFactorToken => $PostTwoFactorToken,
+ RequestedURL => $Param{RequestedURL},
+ );
+
+ # login is invalid
+ if ( !$User ) {
+
+ # CAS Custom
+ # Fixes OTRS Layout bug when redirecting
+ my $cgi = new CGI();
+ print $cgi->redirect( -URL => $ConfigObject->Get("AuthModule::CAS::CASUrl") . "/login?service=" . $ConfigObject->Get("AuthModule::CAS::ServiceUrl") . "?" . $Param{RequestedURL});
+ return;
+ # CAS Custom
+
+ my $Expires = '+' . $ConfigObject->Get('SessionMaxTime') . 's';
+ if ( !$ConfigObject->Get('SessionUseCookieAfterBrowserClose') ) {
+ $Expires = '';
+ }
+
+ $Kernel::OM->ObjectParamAdd(
+ 'Kernel::Output::HTML::Layout' => {
+ SetCookies => {
+ OTRSBrowserHasCookie => $ParamObject->SetCookie(
+ Key => 'OTRSBrowserHasCookie',
+ Value => 1,
+ Expires => $Expires,
+ Path => $ConfigObject->Get('ScriptAlias'),
+ Secure => $CookieSecureAttribute,
+ HTTPOnly => 1,
+ ),
+ },
+ }
+ );
+ my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
+
+ # redirect to alternate login
+ if ( $ConfigObject->Get('LoginURL') ) {
+ $Param{RequestedURL} = $LayoutObject->LinkEncode( $Param{RequestedURL} );
+ print $LayoutObject->Redirect(
+ ExtURL => $ConfigObject->Get('LoginURL')
+ . "?Reason=LoginFailed&RequestedURL=$Param{RequestedURL}",
+ );
+ return;
+ }
+
+ # show normal login
+ $LayoutObject->Print(
+ Output => \$LayoutObject->Login(
+ Title => 'Login',
+ Message => $Kernel::OM->Get('Kernel::System::Log')->GetLogEntry(
+ Type => 'Info',
+ What => 'Message',
+ )
+ || $LayoutObject->{LanguageObject}->Translate( $AuthObject->GetLastErrorMessage() )
+ || Translatable('Login failed! Your user name or password was entered incorrectly.'),
+ LoginFailed => 1,
+ MessageType => 'Error',
+ User => $User,
+ %Param,
+ ),
+ );
+ return;
+ }
+
+ # login is successful
+ my %UserData = $UserObject->GetUserData(
+ User => $User,
+ Valid => 1
+ );
+
+ # check if the browser supports cookies
+ if ( $ParamObject->GetCookie( Key => 'OTRSBrowserHasCookie' ) ) {
+ $Kernel::OM->ObjectParamAdd(
+ 'Kernel::Output::HTML::Layout' => {
+ BrowserHasCookie => 1,
+ },
+ );
+ }
+
+ # check needed data
+ if ( !$UserData{UserID} || !$UserData{UserLogin} ) {
+
+ # redirect to alternate login
+ if ( $ConfigObject->Get('LoginURL') ) {
+ print $Kernel::OM->Get('Kernel::Output::HTML::Layout')->Redirect(
+ ExtURL => $ConfigObject->Get('LoginURL') . '?Reason=SystemError',
+ );
+ return;
+ }
+
+ my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
+
+ # show need user data error message
+ $LayoutObject->Print(
+ Output => \$LayoutObject->Login(
+ Title => 'Error',
+ Message =>
+ Translatable(
+ 'Authentication succeeded, but no user data record is found in the database. Please contact the administrator.'
+ ),
+ %Param,
+ MessageType => 'Error',
+ ),
+ );
+ return;
+ }
+
+ my $DateTimeObj = $Kernel::OM->Create('Kernel::System::DateTime');
+
+ # create new session id
+ my $NewSessionID = $SessionObject->CreateSessionID(
+ %UserData,
+ UserLastRequest => $DateTimeObj->ToEpoch(),
+ UserType => 'User',
+ SessionSource => 'AgentInterface',
+ );
+
+ # show error message if no session id has been created
+ if ( !$NewSessionID ) {
+
+ # get error message
+ my $Error = $SessionObject->SessionIDErrorMessage() || '';
+
+ # output error message
+ my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
+ $LayoutObject->Print(
+ Output => \$LayoutObject->Login(
+ Title => 'Login',
+ Message => $Error,
+ MessageType => 'Error',
+ %Param,
+ ),
+ );
+ return;
+ }
+
+ # execution in 20 seconds
+ my $ExecutionTimeObj = $DateTimeObj->Clone();
+ $ExecutionTimeObj->Add( Seconds => 20 );
+ my $ExecutionTime = $ExecutionTimeObj->ToString();
+
+ # add a asychronous executor scheduler task to count the concurrent user
+ $Kernel::OM->Get('Kernel::System::Scheduler')->TaskAdd(
+ ExecutionTime => $ExecutionTime,
+ Type => 'AsynchronousExecutor',
+ Name => 'PluginAsynchronous::ConcurrentUser',
+ MaximumParallelInstances => 1,
+ Data => {
+ Object => 'Kernel::System::SupportDataCollector::PluginAsynchronous::OTRS::ConcurrentUsers',
+ Function => 'RunAsynchronous',
+ },
+ );
+
+ # get time zone
+ my $UserTimeZone = $UserData{UserTimeZone} || Kernel::System::DateTime->UserDefaultTimeZoneGet();
+ $SessionObject->UpdateSessionID(
+ SessionID => $NewSessionID,
+ Key => 'UserTimeZone',
+ Value => $UserTimeZone,
+ );
+
+ # check if the time zone offset reported by the user's browser differs from that
+ # of the OTRS user's time zone offset
+ my $DateTimeObject = $Kernel::OM->Create(
+ 'Kernel::System::DateTime',
+ ObjectParams => {
+ TimeZone => $UserTimeZone,
+ },
+ );
+ my $OTRSUserTimeZoneOffset = $DateTimeObject->Format( Format => '%{offset}' ) / 60;
+ my $BrowserTimeZoneOffset = ( $ParamObject->GetParam( Param => 'TimeZoneOffset' ) || 0 ) * -1;
+
+ # TimeZoneOffsetDifference contains the difference of the time zone offset between
+ # the user's OTRS time zone setting and the one reported by the user's browser.
+ # If there is a difference it can be evaluated later to e. g. show a message
+ # for the user to check his OTRS time zone setting.
+ my $UserTimeZoneOffsetDifference = abs( $OTRSUserTimeZoneOffset - $BrowserTimeZoneOffset );
+ $SessionObject->UpdateSessionID(
+ SessionID => $NewSessionID,
+ Key => 'UserTimeZoneOffsetDifference',
+ Value => $UserTimeZoneOffsetDifference,
+ );
+
+ # create a new LayoutObject with SessionIDCookie
+ my $Expires = '+' . $ConfigObject->Get('SessionMaxTime') . 's';
+ if ( !$ConfigObject->Get('SessionUseCookieAfterBrowserClose') ) {
+ $Expires = '';
+ }
+
+ my $SecureAttribute;
+ if ( $ConfigObject->Get('HttpType') eq 'https' ) {
+
+ # Restrict Cookie to HTTPS if it is used.
+ $SecureAttribute = 1;
+ }
+
+ $Kernel::OM->ObjectParamAdd(
+ 'Kernel::Output::HTML::Layout' => {
+ SetCookies => {
+ SessionIDCookie => $ParamObject->SetCookie(
+ Key => $Param{SessionName},
+ Value => $NewSessionID,
+ Expires => $Expires,
+ Path => $ConfigObject->Get('ScriptAlias'),
+ Secure => scalar $CookieSecureAttribute,
+ HTTPOnly => 1,
+ ),
+ OTRSBrowserHasCookie => $ParamObject->SetCookie(
+ Key => 'OTRSBrowserHasCookie',
+ Value => '',
+ Expires => '-1y',
+ Path => $ConfigObject->Get('ScriptAlias'),
+ Secure => $CookieSecureAttribute,
+ HTTPOnly => 1,
+ ),
+ },
+ SessionID => $NewSessionID,
+ SessionName => $Param{SessionName},
+ },
+ );
+
+ # Check if Chat is active
+ if ( $Kernel::OM->Get('Kernel::Config')->Get('ChatEngine::Active') ) {
+ my $ChatReceivingAgentsGroup
+ = $Kernel::OM->Get('Kernel::Config')->Get('ChatEngine::PermissionGroup::ChatReceivingAgents');
+
+ my $ChatReceivingAgentsGroupPermission = $Kernel::OM->Get('Kernel::System::Group')->PermissionCheck(
+ UserID => $UserData{UserID},
+ GroupName => $ChatReceivingAgentsGroup,
+ Type => 'rw',
+ );
+
+ if (
+ $UserData{UserID} != -1
+ && $ChatReceivingAgentsGroup
+ && $ChatReceivingAgentsGroupPermission
+ && $Kernel::OM->Get('Kernel::Config')->Get('Ticket::Agent::UnavailableForExternalChatsOnLogin')
+ )
+ {
+ # Get user preferences
+ my %Preferences = $Kernel::OM->Get('Kernel::System::User')->GetPreferences(
+ UserID => $UserData{UserID},
+ );
+
+ if ( $Preferences{ChatAvailability} && $Preferences{ChatAvailability} == 2 ) {
+
+ # User is available for external chats. Set his availability to internal only.
+ $Kernel::OM->Get('Kernel::System::User')->SetPreferences(
+ Key => 'ChatAvailability',
+ Value => '1',
+ UserID => $UserData{UserID},
+ );
+
+ # Set ChatAvailabilityNotification to display notification in agent interface (only once)
+ $Kernel::OM->Get('Kernel::System::User')->SetPreferences(
+ Key => 'ChatAvailabilityNotification',
+ Value => '1',
+ UserID => $UserData{UserID},
+ );
+ }
+ }
+ }
+
+ # redirect with new session id and old params
+ # prepare old redirect URL -- do not redirect to Login or Logout (loop)!
+ if ( $Param{RequestedURL} =~ /Action=(Logout|Login|LostPassword|PreLogin)/ ) {
+ $Param{RequestedURL} = '';
+ }
+
+ # redirect with new session id
+ print $Kernel::OM->Get('Kernel::Output::HTML::Layout')->Redirect(
+ OP => $Param{RequestedURL},
+ Login => 1,
+ );
+ return 1;
+ }
+
+ # logout
+ elsif ( $Param{Action} eq 'Logout' ) {
+
+ my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
+
+ # check session id
+ if ( !$SessionObject->CheckSessionID( SessionID => $Param{SessionID} ) ) {
+
+ # redirect to alternate login
+ if ( $ConfigObject->Get('LoginURL') ) {
+ $Param{RequestedURL} = $LayoutObject->LinkEncode( $Param{RequestedURL} );
+ print $LayoutObject->Redirect(
+ ExtURL => $ConfigObject->Get('LoginURL')
+ . "?Reason=InvalidSessionID&RequestedURL=$Param{RequestedURL}",
+ );
+ return;
+ }
+
+ # show login screen
+ $LayoutObject->Print(
+ Output => \$LayoutObject->Login(
+ Title => 'Logout',
+ %Param,
+ ),
+ );
+ return;
+ }
+
+ # get session data
+ my %UserData = $SessionObject->GetSessionIDData(
+ SessionID => $Param{SessionID},
+ );
+
+ # create a new LayoutObject with %UserData
+ $Kernel::OM->ObjectParamAdd(
+ 'Kernel::Output::HTML::Layout' => {
+ SetCookies => {
+ SessionIDCookie => $ParamObject->SetCookie(
+ Key => $Param{SessionName},
+ Value => '',
+ Expires => '-1y',
+ Path => $ConfigObject->Get('ScriptAlias'),
+ Secure => scalar $CookieSecureAttribute,
+ HTTPOnly => 1,
+ ),
+ },
+ %UserData,
+ },
+ );
+ $Kernel::OM->ObjectsDiscard( Objects => ['Kernel::Output::HTML::Layout'] );
+ $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
+
+ # Prevent CSRF attacks
+ $LayoutObject->ChallengeTokenCheck();
+
+ # remove session id
+ if ( !$SessionObject->RemoveSessionID( SessionID => $Param{SessionID} ) ) {
+ $LayoutObject->FatalError(
+ Message => Translatable('Can`t remove SessionID.'),
+ Comment => Translatable('Please contact the administrator.'),
+ );
+ return;
+ }
+
+ # redirect to alternate login
+ if ( $ConfigObject->Get('LogoutURL') ) {
+ print $LayoutObject->Redirect(
+ ExtURL => $ConfigObject->Get('LogoutURL') . "?Reason=Logout",
+ );
+ return 1;
+ }
+
+ # show logout screen
+ my $LogoutMessage = $LayoutObject->{LanguageObject}->Translate('Logout successful.');
+
+ $LayoutObject->Print(
+ Output => \$LayoutObject->Login(
+ Title => 'Logout',
+ Message => $LogoutMessage,
+ MessageType => 'Success',
+ %Param,
+ ),
+ );
+ return 1;
+ }
+
+ # user lost password
+ elsif ( $Param{Action} eq 'LostPassword' ) {
+
+ my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
+
+ # check feature
+ if ( !$ConfigObject->Get('LostPassword') ) {
+
+ # show normal login
+ $LayoutObject->Print(
+ Output => \$LayoutObject->Login(
+ Title => 'Login',
+ Message => Translatable('Feature not active!'),
+ MessageType => 'Error',
+ ),
+ );
+ return;
+ }
+
+ # get params
+ my $User = $ParamObject->GetParam( Param => 'User' ) || '';
+ my $Token = $ParamObject->GetParam( Param => 'Token' ) || '';
+
+ # get user login by token
+ if ( !$User && $Token ) {
+ my %UserList = $UserObject->SearchPreferences(
+ Key => 'UserToken',
+ Value => $Token,
+ );
+ USERS:
+ for my $UserID ( sort keys %UserList ) {
+ my %UserData = $UserObject->GetUserData(
+ UserID => $UserID,
+ Valid => 1,
+ );
+ if (%UserData) {
+ $User = $UserData{UserLogin};
+ last USERS;
+ }
+ }
+ }
+
+ # get user data
+ my %UserData = $UserObject->GetUserData(
+ User => $User,
+ Valid => 1
+ );
+
+ # verify user is valid when requesting password reset
+ my @ValidIDs = $Kernel::OM->Get('Kernel::System::Valid')->ValidIDsGet();
+ my $UserIsValid = grep { $UserData{ValidID} && $UserData{ValidID} == $_ } @ValidIDs;
+ if ( !$UserData{UserID} || !$UserIsValid ) {
+
+ # Security: pretend that password reset instructions were actually sent to
+ # make sure that users cannot find out valid usernames by
+ # just trying and checking the result message.
+ $LayoutObject->Print(
+ Output => \$LayoutObject->Login(
+ Title => 'Login',
+ Message => Translatable('Sent password reset instructions. Please check your email.'),
+ MessageType => 'Success',
+ %Param,
+ ),
+ );
+ return;
+ }
+
+ # create email object
+ my $EmailObject = $Kernel::OM->Get('Kernel::System::Email');
+
+ # send password reset token
+ if ( !$Token ) {
+
+ # generate token
+ $UserData{Token} = $UserObject->TokenGenerate(
+ UserID => $UserData{UserID},
+ );
+
+ # send token notify email with link
+ my $Body = $ConfigObject->Get('NotificationBodyLostPasswordToken')
+ || 'ERROR: NotificationBodyLostPasswordToken is missing!';
+ my $Subject = $ConfigObject->Get('NotificationSubjectLostPasswordToken')
+ || 'ERROR: NotificationSubjectLostPasswordToken is missing!';
+ for ( sort keys %UserData ) {
+ $Body =~ s//$UserData{$_}/gi;
+ }
+ my $Sent = $EmailObject->Send(
+ To => $UserData{UserEmail},
+ Subject => $Subject,
+ Charset => $LayoutObject->{UserCharset},
+ MimeType => 'text/plain',
+ Body => $Body
+ );
+ if ( !$Sent->{Success} ) {
+ $LayoutObject->FatalError(
+ Comment => Translatable('Please contact the administrator.'),
+ );
+ return;
+ }
+ $LayoutObject->Print(
+ Output => \$LayoutObject->Login(
+ Title => 'Login',
+ Message => Translatable('Sent password reset instructions. Please check your email.'),
+ MessageType => 'Success',
+ %Param,
+ ),
+ );
+ return 1;
+ }
+
+ # reset password
+ # check if token is valid
+ my $TokenValid = $UserObject->TokenCheck(
+ Token => $Token,
+ UserID => $UserData{UserID},
+ );
+ if ( !$TokenValid ) {
+ $LayoutObject->Print(
+ Output => \$LayoutObject->Login(
+ Title => 'Login',
+ Message => Translatable('Invalid Token!'),
+ MessageType => 'Error',
+ %Param,
+ ),
+ );
+ return;
+ }
+
+ # get new password
+ $UserData{NewPW} = $UserObject->GenerateRandomPassword();
+
+ # update new password
+ $UserObject->SetPassword(
+ UserLogin => $User,
+ PW => $UserData{NewPW}
+ );
+
+ # send notify email
+ my $Body = $ConfigObject->Get('NotificationBodyLostPassword')
+ || 'New Password is: ';
+ my $Subject = $ConfigObject->Get('NotificationSubjectLostPassword')
+ || 'New Password!';
+ for ( sort keys %UserData ) {
+ $Body =~ s//$UserData{$_}/gi;
+ }
+ my $Sent = $EmailObject->Send(
+ To => $UserData{UserEmail},
+ Subject => $Subject,
+ Charset => $LayoutObject->{UserCharset},
+ MimeType => 'text/plain',
+ Body => $Body
+ );
+
+ if ( !$Sent->{Success} ) {
+ $LayoutObject->FatalError(
+ Comment => Translatable('Please contact the administrator.'),
+ );
+ return;
+ }
+ my $Message = $LayoutObject->{LanguageObject}->Translate(
+ 'Sent new password to %s. Please check your email.',
+ $UserData{UserEmail},
+ );
+ $LayoutObject->Print(
+ Output => \$LayoutObject->Login(
+ Title => 'Login',
+ Message => $Message,
+ User => $User,
+ MessageType => 'Success',
+ %Param,
+ ),
+ );
+ return 1;
+ }
+
+ # show login site
+ elsif ( !$Param{SessionID} ) {
+
+ # create AuthObject
+ my $AuthObject = $Kernel::OM->Get('Kernel::System::Auth');
+ my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
+ if ( $AuthObject->GetOption( What => 'PreAuth' ) ) {
+
+ # automatic login
+ $Param{RequestedURL} = $LayoutObject->LinkEncode( $Param{RequestedURL} );
+ print $LayoutObject->Redirect(
+ OP => "Action=PreLogin&RequestedURL=$Param{RequestedURL}",
+ );
+ return;
+ }
+ elsif ( $ConfigObject->Get('LoginURL') ) {
+
+ # redirect to alternate login
+ $Param{RequestedURL} = $LayoutObject->LinkEncode( $Param{RequestedURL} );
+ print $LayoutObject->Redirect(
+ ExtURL => $ConfigObject->Get('LoginURL')
+ . "?RequestedURL=$Param{RequestedURL}",
+ );
+ return;
+ }
+
+ # login screen
+ $LayoutObject->Print(
+ Output => \$LayoutObject->Login(
+ Title => 'Login',
+ %Param,
+ ),
+ );
+ return;
+ }
+
+ # run modules if a version value exists
+ elsif ( $Kernel::OM->Get('Kernel::System::Main')->Require("Kernel::Modules::$Param{Action}") ) {
+
+ # check session id
+ if ( !$SessionObject->CheckSessionID( SessionID => $Param{SessionID} ) ) {
+
+ # put '%Param' into LayoutObject
+ $Kernel::OM->ObjectParamAdd(
+ 'Kernel::Output::HTML::Layout' => {
+ SetCookies => {
+ SessionIDCookie => $ParamObject->SetCookie(
+ Key => $Param{SessionName},
+ Value => '',
+ Expires => '-1y',
+ Path => $ConfigObject->Get('ScriptAlias'),
+ Secure => scalar $CookieSecureAttribute,
+ HTTPOnly => 1,
+ ),
+ },
+ %Param,
+ },
+ );
+
+ $Kernel::OM->ObjectsDiscard( Objects => ['Kernel::Output::HTML::Layout'] );
+ my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
+
+ # create AuthObject
+ my $AuthObject = $Kernel::OM->Get('Kernel::System::Auth');
+ if ( $AuthObject->GetOption( What => 'PreAuth' ) ) {
+
+ # automatic re-login
+ $Param{RequestedURL} = $LayoutObject->LinkEncode( $Param{RequestedURL} );
+ print $LayoutObject->Redirect(
+ OP => "?Action=PreLogin&RequestedURL=$Param{RequestedURL}",
+ );
+ return;
+ }
+ elsif ( $ConfigObject->Get('LoginURL') ) {
+
+ # redirect to alternate login
+ $Param{RequestedURL} = $LayoutObject->LinkEncode( $Param{RequestedURL} );
+ print $LayoutObject->Redirect(
+ ExtURL => $ConfigObject->Get('LoginURL')
+ . "?Reason=InvalidSessionID&RequestedURL=$Param{RequestedURL}",
+ );
+ return;
+ }
+
+ # show login
+ $LayoutObject->Print(
+ Output => \$LayoutObject->Login(
+ Title => 'Login',
+ Message =>
+ $LayoutObject->{LanguageObject}->Translate( $SessionObject->SessionIDErrorMessage() ),
+ MessageType => 'Error',
+ %Param,
+ ),
+ );
+ return;
+ }
+
+ # get session data
+ my %UserData = $SessionObject->GetSessionIDData(
+ SessionID => $Param{SessionID},
+ );
+
+ # check needed data
+ if ( !$UserData{UserID} || !$UserData{UserLogin} || $UserData{UserType} ne 'User' ) {
+
+ my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
+
+ # redirect to alternate login
+ if ( $ConfigObject->Get('LoginURL') ) {
+ print $LayoutObject->Redirect(
+ ExtURL => $ConfigObject->Get('LoginURL') . '?Reason=SystemError',
+ );
+ return;
+ }
+
+ # show login screen
+ $LayoutObject->Print(
+ Output => \$LayoutObject->Login(
+ Title => 'Error',
+ Message => Translatable('Error: invalid session.'),
+ MessageType => 'Error',
+ %Param,
+ ),
+ );
+ return;
+ }
+
+ # check module registry
+ my $ModuleReg = $ConfigObject->Get('Frontend::Module')->{ $Param{Action} };
+ if ( !$ModuleReg ) {
+
+ $Kernel::OM->Get('Kernel::System::Log')->Log(
+ Priority => 'error',
+ Message =>
+ "Module Kernel::Modules::$Param{Action} not registered in Kernel/Config.pm!",
+ );
+ $Kernel::OM->Get('Kernel::Output::HTML::Layout')->FatalError(
+ Comment => Translatable('Please contact the administrator.'),
+ );
+ return;
+ }
+
+ # module permisson check
+ if (
+ ref $ModuleReg->{GroupRo} eq 'ARRAY'
+ && !scalar @{ $ModuleReg->{GroupRo} }
+ && ref $ModuleReg->{Group} eq 'ARRAY'
+ && !scalar @{ $ModuleReg->{Group} }
+ )
+ {
+ $Param{AccessRo} = 1;
+ $Param{AccessRw} = 1;
+ }
+ else {
+ my $GroupObject = $Kernel::OM->Get('Kernel::System::Group');
+
+ PERMISSION:
+ for my $Permission (qw(GroupRo Group)) {
+ my $AccessOk = 0;
+ my $Group = $ModuleReg->{$Permission};
+ next PERMISSION if !$Group;
+ if ( ref $Group eq 'ARRAY' ) {
+ INNER:
+ for my $GroupName ( @{$Group} ) {
+ next INNER if !$GroupName;
+ next INNER if !$GroupObject->PermissionCheck(
+ UserID => $UserData{UserID},
+ GroupName => $GroupName,
+ Type => $Permission eq 'GroupRo' ? 'ro' : 'rw',
+
+ );
+ $AccessOk = 1;
+ last INNER;
+ }
+ }
+ else {
+ my $HasPermission = $GroupObject->PermissionCheck(
+ UserID => $UserData{UserID},
+ GroupName => $Group,
+ Type => $Permission eq 'GroupRo' ? 'ro' : 'rw',
+
+ );
+ if ($HasPermission) {
+ $AccessOk = 1;
+ }
+ }
+ if ( $Permission eq 'Group' && $AccessOk ) {
+ $Param{AccessRo} = 1;
+ $Param{AccessRw} = 1;
+ }
+ elsif ( $Permission eq 'GroupRo' && $AccessOk ) {
+ $Param{AccessRo} = 1;
+ }
+ }
+ if ( !$Param{AccessRo} && !$Param{AccessRw} || !$Param{AccessRo} && $Param{AccessRw} ) {
+
+ print $Kernel::OM->Get('Kernel::Output::HTML::Layout')->NoPermission(
+ Message => Translatable('No Permission to use this frontend module!')
+ );
+ return;
+ }
+ }
+
+ # put '%Param' and '%UserData' into LayoutObject
+ $Kernel::OM->ObjectParamAdd(
+ 'Kernel::Output::HTML::Layout' => {
+ %Param,
+ %UserData,
+ ModuleReg => $ModuleReg,
+ },
+ );
+ $Kernel::OM->ObjectsDiscard( Objects => ['Kernel::Output::HTML::Layout'] );
+
+ # update last request time
+ if (
+ !$ParamObject->IsAJAXRequest()
+ || $Param{Action} eq 'AgentVideoChat'
+ ||
+ (
+ $Param{Action} eq 'AgentChat'
+ &&
+ $Param{Subaction} ne 'ChatGetOpenRequests' &&
+ $Param{Subaction} ne 'ChatMonitorCheck'
+ )
+ )
+ {
+ my $DateTimeObject = $Kernel::OM->Create('Kernel::System::DateTime');
+
+ $SessionObject->UpdateSessionID(
+ SessionID => $Param{SessionID},
+ Key => 'UserLastRequest',
+ Value => $DateTimeObject->ToEpoch(),
+ );
+ }
+
+ # Override user settings.
+ my $Home = $ConfigObject->Get('Home');
+ my $File = "$Home/Kernel/Config/Files/User/$UserData{UserID}.pm";
+ if ( -e $File ) {
+ if ( !require $File ) {
+ die "ERROR: $!\n";
+ }
+
+ # prepare file
+ $File =~ s/\Q$Home\E//g;
+ $File =~ s/^\///g;
+ $File =~ s/\/\//\//g;
+ $File =~ s/\//::/g;
+ $File =~ s/\.pm$//g;
+ $File->Load($ConfigObject);
+ }
+
+ # pre application module
+ my $PreModule = $ConfigObject->Get('PreApplicationModule');
+ if ($PreModule) {
+ my %PreModuleList;
+ if ( ref $PreModule eq 'HASH' ) {
+ %PreModuleList = %{$PreModule};
+ }
+ else {
+ $PreModuleList{Init} = $PreModule;
+ }
+
+ MODULE:
+ for my $PreModuleKey ( sort keys %PreModuleList ) {
+ my $PreModule = $PreModuleList{$PreModuleKey};
+ next MODULE if !$PreModule;
+ next MODULE if !$Kernel::OM->Get('Kernel::System::Main')->Require($PreModule);
+
+ # debug info
+ if ( $Self->{Debug} ) {
+ $Kernel::OM->Get('Kernel::System::Log')->Log(
+ Priority => 'debug',
+ Message => "PreApplication module $PreModule is used.",
+ );
+ }
+
+ my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
+
+ # use module
+ my $PreModuleObject = $PreModule->new(
+ %Param,
+ %UserData,
+ ModuleReg => $ModuleReg,
+ );
+ my $Output = $PreModuleObject->PreRun();
+ if ($Output) {
+ $LayoutObject->Print( Output => \$Output );
+ return 1;
+ }
+ }
+ }
+
+ # debug info
+ if ( $Self->{Debug} ) {
+ $Kernel::OM->Get('Kernel::System::Log')->Log(
+ Priority => 'debug',
+ Message => 'Kernel::Modules::' . $Param{Action} . '->new',
+ );
+ }
+
+ my $FrontendObject = ( 'Kernel::Modules::' . $Param{Action} )->new(
+ %Param,
+ %UserData,
+ ModuleReg => $ModuleReg,
+ Debug => $Self->{Debug},
+ );
+
+ # debug info
+ if ( $Self->{Debug} ) {
+ $Kernel::OM->Get('Kernel::System::Log')->Log(
+ Priority => 'debug',
+ Message => 'Kernel::Modules::' . $Param{Action} . '->run',
+ );
+ }
+
+ # ->Run $Action with $FrontendObject
+ $Kernel::OM->Get('Kernel::Output::HTML::Layout')->Print( Output => \$FrontendObject->Run() );
+
+ # log request time
+ if ( $ConfigObject->Get('PerformanceLog') ) {
+ if ( ( !$QueryString && $Param{Action} ) || $QueryString !~ /Action=/ ) {
+ $QueryString = 'Action=' . $Param{Action} . '&Subaction=' . $Param{Subaction};
+ }
+ my $File = $ConfigObject->Get('PerformanceLog::File');
+ ## no critic
+ if ( open my $Out, '>>', $File ) {
+ ## use critic
+ print $Out time()
+ . '::Agent::'
+ . ( time() - $Self->{PerformanceLogStart} )
+ . "::$UserData{UserLogin}::$QueryString\n";
+ close $Out;
+
+ $Kernel::OM->Get('Kernel::System::Log')->Log(
+ Priority => 'debug',
+ Message => "Response::Agent: "
+ . ( time() - $Self->{PerformanceLogStart} )
+ . "s taken (URL:$QueryString:$UserData{UserLogin})",
+ );
+ }
+ else {
+ $Kernel::OM->Get('Kernel::System::Log')->Log(
+ Priority => 'error',
+ Message => "Can't write $File: $!",
+ );
+ }
+ }
+ return 1;
+ }
+
+ # print an error screen
+ my %Data = $SessionObject->GetSessionIDData(
+ SessionID => $Param{SessionID},
+ );
+ $Kernel::OM->ObjectParamAdd(
+ 'Kernel::Output::HTML::Layout' => {
+ %Param,
+ %Data,
+ },
+ );
+ $Kernel::OM->Get('Kernel::Output::HTML::Layout')->FatalError(
+ Comment => Translatable('Please contact the administrator.'),
+ );
+ return;
+}
+
+sub DESTROY {
+ my $Self = shift;
+
+ # debug info
+ if ( $Self->{Debug} ) {
+ $Kernel::OM->Get('Kernel::System::Log')->Log(
+ Priority => 'debug',
+ Message => 'Global handle stopped.',
+ );
+ }
+
+ return 1;
+}
+
+# CAS Custom
+=item
+ Check if it is a CAS logout - if true, logs out user for the session ticket
+=cut
+sub CASLogout {
+ my $Self = shift;
+
+ # get post data
+ my $cgi = new CGI;
+ my $request = uri_unescape($cgi->query_string());
+
+ # check if it is CAS logout
+ if ($request =~ /(logoutRequest=([^<]+)/);
+ if (! $ticket) {
+ return 1;
+ }
+
+ my $DBObject = $Kernel::OM->Get("Kernel::System::DB");
+
+ # get login for session
+ my $sqlLogin = 'SELECT UserLogin from cas_session where Ticket=?';
+ $DBObject->Prepare(SQL => $sqlLogin, Bind => [\$ticket]);
+
+ my $login;
+ while (my @Row = $DBObject->FetchrowArray()) {
+ $login = $Row[0];
+ }
+
+ # if a login was found, kill the user session
+ if ($login) {
+ $DBObject->Do(SQL => "DELETE FROM sessions WHERE session_id IN (select session_id from (select session_id FROM sessions WHERE data_key='UserLogin' AND data_value=?) as x)",
+ Bind => [\$login]);
+ } else {
+ }
+ return 1;
+ } else {
+ return 0;
+ }
+
+}
+# CAS Custom
+
+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 (AGPL). If you
+did not receive this file, see L.
+
+=cut
diff --git a/Custom/Kernel/System/Web/InterfaceCustomer.pm b/Custom/Kernel/System/Web/InterfaceCustomer.pm
new file mode 100644
index 0000000..a26628d
--- /dev/null
+++ b/Custom/Kernel/System/Web/InterfaceCustomer.pm
@@ -0,0 +1,1512 @@
+# --
+# Copyright (C) 2001-2017 OTRS AG, http://otrs.com/
+# --
+# 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.
+#
+#
+# Custom version for CAS authentication - rodrigo@goncalves.pro.br
+#
+# Version 2016-01-18 - RG - Version for OTRS 5.0.6
+# Version 2017-12-07 - RG - Version for OTRS 6.0.1
+#
+# --
+
+package Kernel::System::Web::InterfaceCustomer;
+
+use strict;
+use warnings;
+
+# CAS Custom
+use CGI;
+use URI::Escape;
+# CAS Custom
+
+use Kernel::System::DateTime;
+use Kernel::System::Email;
+use Kernel::System::VariableCheck qw(IsArrayRefWithData IsHashRefWithData);
+use Kernel::Language qw(Translatable);
+
+our @ObjectDependencies = (
+ 'Kernel::Config',
+ 'Kernel::Output::HTML::Layout',
+ 'Kernel::System::AuthSession',
+ 'Kernel::System::CustomerAuth',
+ 'Kernel::System::CustomerGroup',
+ 'Kernel::System::CustomerUser',
+ 'Kernel::System::DB',
+ 'Kernel::System::Group',
+ 'Kernel::System::Log',
+ 'Kernel::System::Main',
+ 'Kernel::System::Scheduler',
+ 'Kernel::System::DateTime',
+ 'Kernel::System::Web::Request',
+ 'Kernel::System::Valid',
+);
+
+=head1 NAME
+
+Kernel::System::Web::InterfaceCustomer - the customer web interface
+
+=head1 DESCRIPTION
+
+the global customer web interface (authentication, session handling, ...)
+
+=head1 PUBLIC INTERFACE
+
+=head2 new()
+
+create customer web interface object
+
+ use Kernel::System::Web::InterfaceCustomer;
+
+ my $Debug = 0;
+ my $InterfaceCustomer = Kernel::System::Web::InterfaceCustomer->new(
+ Debug => $Debug,
+ WebRequest => CGI::Fast->new(), # optional, e. g. if fast cgi is used, the CGI object is already provided
+ );
+
+=cut
+
+sub new {
+ my ( $Type, %Param ) = @_;
+
+ # allocate new hash for object
+ my $Self = {};
+ bless( $Self, $Type );
+
+ # get debug level
+ $Self->{Debug} = $Param{Debug} || 0;
+
+ # performance log
+ $Self->{PerformanceLogStart} = time();
+
+ $Kernel::OM->ObjectParamAdd(
+ 'Kernel::System::Log' => {
+ LogPrefix => $Kernel::OM->Get('Kernel::Config')->Get('CGILogPrefix'),
+ },
+ 'Kernel::System::Web::Request' => {
+ WebRequest => $Param{WebRequest} || 0,
+ },
+ );
+
+ # debug info
+ if ( $Self->{Debug} ) {
+ $Kernel::OM->Get('Kernel::System::Log')->Log(
+ Priority => 'debug',
+ Message => 'Global handle started...',
+ );
+ }
+
+ return $Self;
+}
+
+=head2 Run()
+
+execute the object
+
+ $InterfaceCustomer->Run();
+
+=cut
+
+sub Run {
+ my $Self = shift;
+
+ # CAS Custom
+ if ($Self->CASLogout()) {
+ return;
+ }
+ # CAS Custom
+
+ my $ConfigObject = $Kernel::OM->Get('Kernel::Config');
+
+ my $QueryString = $ENV{QUERY_STRING} || '';
+
+ # Check if https forcing is active, and redirect if needed.
+ if ( $ConfigObject->Get('HTTPSForceRedirect') ) {
+
+ # Some web servers do not set HTTPS environment variable, so it's not possible to easily know if we are using
+ # https protocol. Look also for similarly named keys in environment hash, since this should prevent loops in
+ # certain cases.
+ if (
+ (
+ !defined $ENV{HTTPS}
+ && !grep {/^HTTPS(?:_|$)/} keys %ENV
+ )
+ || $ENV{HTTPS} ne 'on'
+ )
+ {
+ my $Host = $ENV{HTTP_HOST} || $ConfigObject->Get('FQDN');
+
+ # Redirect with 301 code. Add two new lines at the end, so HTTP headers are validated correctly.
+ print "Status: 301 Moved Permanently\nLocation: https://$Host$ENV{REQUEST_URI}\n\n";
+ return;
+ }
+ }
+
+ my $ParamObject = $Kernel::OM->Get('Kernel::System::Web::Request');
+
+ my %Param;
+
+ # get session id
+ $Param{SessionName} = $ConfigObject->Get('CustomerPanelSessionName') || 'CSID';
+ $Param{SessionID} = $ParamObject->GetParam( Param => $Param{SessionName} ) || '';
+
+ # drop old session id (if exists)
+ $QueryString =~ s/(\?|&|;|)$Param{SessionName}(=&|=;|=.+?&|=.+?$)/;/g;
+
+ # define framework params
+ my $FrameworkParams = {
+ Lang => '',
+ Action => '',
+ Subaction => '',
+ RequestedURL => $QueryString,
+ };
+ for my $Key ( sort keys %{$FrameworkParams} ) {
+ $Param{$Key} = $ParamObject->GetParam( Param => $Key )
+ || $FrameworkParams->{$Key};
+ }
+
+ # validate language
+ if ( $Param{Lang} && $Param{Lang} !~ m{\A[a-z]{2}(?:_[A-Z]{2})?\z}xms ) {
+ delete $Param{Lang};
+ }
+
+ my $BrowserHasCookie = 0;
+
+ # Check if the browser sends the SessionID cookie and set the SessionID-cookie
+ # as SessionID! GET or POST SessionID have the lowest priority.
+ if ( $ConfigObject->Get('SessionUseCookie') ) {
+ $Param{SessionIDCookie} = $ParamObject->GetCookie( Key => $Param{SessionName} );
+ if ( $Param{SessionIDCookie} ) {
+ $Param{SessionID} = $Param{SessionIDCookie};
+ }
+ }
+
+ my $CookieSecureAttribute;
+ if ( $ConfigObject->Get('HttpType') eq 'https' ) {
+
+ # Restrict Cookie to HTTPS if it is used.
+ $CookieSecureAttribute = 1;
+ }
+
+ $Kernel::OM->ObjectParamAdd(
+ 'Kernel::Output::HTML::Layout' => {
+ Lang => $Param{Lang},
+ },
+ 'Kernel::Language' => {
+ UserLanguage => $Param{Lang},
+ },
+ );
+
+ my $DBCanConnect = $Kernel::OM->Get('Kernel::System::DB')->Connect();
+
+ if ( !$DBCanConnect || $ParamObject->Error() ) {
+ my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
+ if ( !$DBCanConnect ) {
+ $LayoutObject->CustomerFatalError(
+ Comment => Translatable('Please contact the administrator.'),
+ );
+ return;
+ }
+ if ( $ParamObject->Error() ) {
+ $LayoutObject->CustomerFatalError(
+ Message => $ParamObject->Error(),
+ Comment => Translatable('Please contact the administrator.'),
+ );
+ return;
+ }
+ }
+
+ my $UserObject = $Kernel::OM->Get('Kernel::System::CustomerUser');
+ my $SessionObject = $Kernel::OM->Get('Kernel::System::AuthSession');
+
+ # get common application and add on application params
+ my %CommonObjectParam = %{ $ConfigObject->Get('CustomerFrontend::CommonParam') };
+ for my $Key ( sort keys %CommonObjectParam ) {
+ $Param{$Key} = $ParamObject->GetParam( Param => $Key ) || $CommonObjectParam{$Key};
+ }
+
+ # security check Action Param (replace non-word chars)
+ $Param{Action} =~ s/\W//g;
+
+ # check request type
+ if ( $Param{Action} eq 'PreLogin' ) {
+ my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
+
+ # login screen
+ $LayoutObject->Print(
+ Output => \$LayoutObject->CustomerLogin(
+ Title => 'Login',
+ Mode => 'PreLogin',
+ %Param,
+ ),
+ );
+
+ return;
+ }
+ elsif ( $Param{Action} eq 'Login' ) {
+
+ # get params
+ my $PostUser = $ParamObject->GetParam( Param => 'User' ) || '';
+ my $PostPw = $ParamObject->GetParam(
+ Param => 'Password',
+ Raw => 1
+ ) || '';
+ my $PostTwoFactorToken = $ParamObject->GetParam(
+ Param => 'TwoFactorToken',
+ Raw => 1
+ ) || '';
+
+ # create AuthObject
+ my $AuthObject = $Kernel::OM->Get('Kernel::System::CustomerAuth');
+
+ # check submitted data
+ my $User = $AuthObject->Auth(
+ User => $PostUser,
+ Pw => $PostPw,
+ TwoFactorToken => $PostTwoFactorToken,
+ RequestedURL => $Param{RequestedURL},
+ );
+
+ my $Expires = '+' . $ConfigObject->Get('SessionMaxTime') . 's';
+ if ( !$ConfigObject->Get('SessionUseCookieAfterBrowserClose') ) {
+ $Expires = '';
+ }
+
+ # login is invalid
+ if ( !$User ) {
+
+ # CAS Custom
+ # Fixes OTRS Layout bug when redirecting
+ my $cgi = new CGI();
+ print $cgi->redirect( -URL => $ConfigObject->Get("Customer::AuthModule::CAS::CASUrl") . "/login?service=" . $ConfigObject->Get("Customer::AuthModule::CAS::ServiceUrl") . "?" . $Param{RequestedURL});
+ return;
+ # CAS Custom
+
+ $Kernel::OM->ObjectParamAdd(
+ 'Kernel::Output::HTML::Layout' => {
+ SetCookies => {
+ OTRSBrowserHasCookie => $ParamObject->SetCookie(
+ Key => 'OTRSBrowserHasCookie',
+ Value => 1,
+ Expires => $Expires,
+ Path => $ConfigObject->Get('ScriptAlias'),
+ Secure => $CookieSecureAttribute,
+ HTTPOnly => 1,
+ ),
+ },
+ },
+ );
+
+ my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
+
+ # redirect to alternate login
+ if ( $ConfigObject->Get('CustomerPanelLoginURL') ) {
+ $Param{RequestedURL} = $LayoutObject->LinkEncode( $Param{RequestedURL} );
+ print $LayoutObject->Redirect(
+ ExtURL => $ConfigObject->Get('CustomerPanelLoginURL')
+ . "?Reason=LoginFailed;RequestedURL=$Param{RequestedURL}",
+ );
+ return;
+ }
+
+ # show normal login
+ $LayoutObject->Print(
+ Output => \$LayoutObject->CustomerLogin(
+ Title => 'Login',
+ Message => $Kernel::OM->Get('Kernel::System::Log')->GetLogEntry(
+ Type => 'Info',
+ What => 'Message',
+ )
+ || $AuthObject->GetLastErrorMessage()
+ || Translatable('Login failed! Your user name or password was entered incorrectly.'),
+ User => $PostUser,
+ LoginFailed => 1,
+ %Param,
+ ),
+ );
+ return;
+ }
+
+ # login is successful
+ my %UserData = $UserObject->CustomerUserDataGet(
+ User => $User,
+ Valid => 1
+ );
+
+ # check if the browser supports cookies
+ if ( $ParamObject->GetCookie( Key => 'OTRSBrowserHasCookie' ) ) {
+ $Kernel::OM->ObjectParamAdd(
+ 'Kernel::Output::HTML::Layout' => {
+ BrowserHasCookie => 1,
+ },
+ );
+ }
+
+ # check needed data
+ if ( !$UserData{UserID} || !$UserData{UserLogin} ) {
+
+ my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
+
+ # CAS Custom
+ my $url = $Kernel::OM->Get("Kernel::Config")->Get('Customer::AuthModule::CAS::InvalidUserURL');
+
+ if ($url) {
+ print $LayoutObject->Redirect( ExtURL => $url, );
+ return;
+ }
+ # CAS Custom
+
+ # redirect to alternate login
+ if ( $ConfigObject->Get('CustomerPanelLoginURL') ) {
+ print $LayoutObject->Redirect(
+ ExtURL => $ConfigObject->Get('CustomerPanelLoginURL')
+ . '?Reason=SystemError',
+ );
+ return;
+ }
+
+ # show need user data error message
+ $LayoutObject->Print(
+ Output => \$LayoutObject->CustomerLogin(
+ Title => 'Error',
+ Message => Translatable(
+ 'Authentication succeeded, but no customer record is found in the customer backend. Please contact the administrator.'
+ ),
+ %Param,
+ ),
+ );
+ return;
+ }
+
+ # create datetime object
+ my $SessionDTObject = $Kernel::OM->Create('Kernel::System::DateTime');
+
+ # create new session id
+ my $NewSessionID = $SessionObject->CreateSessionID(
+ %UserData,
+ UserLastRequest => $SessionDTObject->ToEpoch(),
+ UserType => 'Customer',
+ SessionSource => 'CustomerInterface',
+ );
+
+ # show error message if no session id has been created
+ if ( !$NewSessionID ) {
+
+ # get error message
+ my $Error = $SessionObject->SessionIDErrorMessage() || '';
+
+ my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
+
+ # output error message
+ $LayoutObject->Print(
+ Output => \$LayoutObject->CustomerLogin(
+ Title => 'Login',
+ Message => $Error,
+ %Param,
+ ),
+ );
+ return;
+ }
+
+ # execution in 20 seconds
+ my $ExecutionTimeObj = $Kernel::OM->Create('Kernel::System::DateTime');
+ $ExecutionTimeObj->Add( Seconds => 20 );
+
+ # add a asynchronous executor scheduler task to count the concurrent user
+ $Kernel::OM->Get('Kernel::System::Scheduler')->TaskAdd(
+ ExecutionTime => $ExecutionTimeObj->ToString(),
+ Type => 'AsynchronousExecutor',
+ Name => 'PluginAsynchronous::ConcurrentUser',
+ MaximumParallelInstances => 1,
+ Data => {
+ Object => 'Kernel::System::SupportDataCollector::PluginAsynchronous::OTRS::ConcurrentUsers',
+ Function => 'RunAsynchronous',
+ },
+ );
+
+ # get time zone
+ my $UserTimeZone = $UserData{UserTimeZone} || Kernel::System::DateTime->UserDefaultTimeZoneGet();
+ $SessionObject->UpdateSessionID(
+ SessionID => $NewSessionID,
+ Key => 'UserTimeZone',
+ Value => $UserTimeZone,
+ );
+
+ # check if the time zone offset reported by the user's browser differs from that
+ # of the OTRS user's time zone offset
+ my $DateTimeObject = $Kernel::OM->Create(
+ 'Kernel::System::DateTime',
+ ObjectParams => {
+ TimeZone => $UserTimeZone,
+ },
+ );
+ my $OTRSUserTimeZoneOffset = $DateTimeObject->Format( Format => '%{offset}' ) / 60;
+ my $BrowserTimeZoneOffset = ( $ParamObject->GetParam( Param => 'TimeZoneOffset' ) || 0 ) * -1;
+
+ # TimeZoneOffsetDifference contains the difference of the time zone offset between
+ # the user's OTRS time zone setting and the one reported by the user's browser.
+ # If there is a difference it can be evaluated later to e. g. show a message
+ # for the user to check his OTRS time zone setting.
+ my $UserTimeZoneOffsetDifference = abs( $OTRSUserTimeZoneOffset - $BrowserTimeZoneOffset );
+ $SessionObject->UpdateSessionID(
+ SessionID => $NewSessionID,
+ Key => 'UserTimeZoneOffsetDifference',
+ Value => $UserTimeZoneOffsetDifference,
+ );
+
+ $Kernel::OM->ObjectParamAdd(
+ 'Kernel::Output::HTML::Layout' => {
+ SetCookies => {
+ SessionIDCookie => $ParamObject->SetCookie(
+ Key => $Param{SessionName},
+ Value => $NewSessionID,
+ Expires => $Expires,
+ Path => $ConfigObject->Get('ScriptAlias'),
+ Secure => scalar $CookieSecureAttribute,
+ HTTPOnly => 1,
+ ),
+ OTRSBrowserHasCookie => $ParamObject->SetCookie(
+ Key => 'OTRSBrowserHasCookie',
+ Value => '',
+ Expires => '-1y',
+ Path => $ConfigObject->Get('ScriptAlias'),
+ Secure => $CookieSecureAttribute,
+ HTTPOnly => 1,
+ ),
+
+ },
+ SessionID => $NewSessionID,
+ SessionName => $Param{SessionName},
+ },
+ );
+
+ # redirect with new session id and old params
+ # prepare old redirect URL -- do not redirect to Login or Logout (loop)!
+ if ( $Param{RequestedURL} =~ /Action=(Logout|Login|LostPassword|PreLogin)/ ) {
+ $Param{RequestedURL} = '';
+ }
+
+ # redirect with new session id
+ print $Kernel::OM->Get('Kernel::Output::HTML::Layout')->Redirect(
+ OP => $Param{RequestedURL},
+ Login => 1,
+ );
+ return 1;
+ }
+
+ # logout
+ elsif ( $Param{Action} eq 'Logout' ) {
+
+ # check session id
+ if ( !$SessionObject->CheckSessionID( SessionID => $Param{SessionID} ) ) {
+
+ # new layout object
+ my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
+
+ # redirect to alternate login
+ if ( $ConfigObject->Get('CustomerPanelLoginURL') ) {
+ $Param{RequestedURL} = $LayoutObject->LinkEncode( $Param{RequestedURL} );
+ print $LayoutObject->Redirect(
+ ExtURL => $ConfigObject->Get('CustomerPanelLoginURL')
+ . "?Reason=InvalidSessionID;RequestedURL=$Param{RequestedURL}",
+ );
+ }
+
+ # show login screen
+ print $LayoutObject->CustomerLogin(
+ Title => 'Logout',
+ Message => Translatable('Session invalid. Please log in again.'),
+ %Param,
+ );
+ return;
+ }
+
+ # get session data
+ my %UserData = $SessionObject->GetSessionIDData(
+ SessionID => $Param{SessionID},
+ );
+
+ # create new LayoutObject with new '%Param' and '%UserData'
+ $Kernel::OM->ObjectParamAdd(
+ 'Kernel::Output::HTML::Layout' => {
+ SetCookies => {
+ SessionIDCookie => $ParamObject->SetCookie(
+ Key => $Param{SessionName},
+ Value => '',
+ Expires => '-1y',
+ Path => $ConfigObject->Get('ScriptAlias'),
+ Secure => scalar $CookieSecureAttribute,
+ HTTPOnly => 1,
+ ),
+ },
+ %Param,
+ %UserData,
+ },
+ );
+
+ $Kernel::OM->ObjectsDiscard( Objects => ['Kernel::Output::HTML::Layout'] );
+ my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
+
+ # remove session id
+ if ( !$SessionObject->RemoveSessionID( SessionID => $Param{SessionID} ) ) {
+ $LayoutObject->CustomerFatalError(
+ Comment => Translatable('Please contact the administrator.')
+ );
+ return;
+ }
+
+ # redirect to alternate login
+ if ( $ConfigObject->Get('CustomerPanelLogoutURL') ) {
+ print $LayoutObject->Redirect(
+ ExtURL => $ConfigObject->Get('CustomerPanelLogoutURL')
+ . "?Reason=Logout",
+ );
+ }
+
+ # show logout screen
+ my $LogoutMessage = $LayoutObject->{LanguageObject}->Translate('Logout successful.');
+
+ $LayoutObject->Print(
+ Output => \$LayoutObject->CustomerLogin(
+ Title => 'Logout',
+ Message => $LogoutMessage,
+ MessageType => 'Success',
+ %Param,
+ ),
+ );
+ return 1;
+ }
+
+ # CustomerLostPassword
+ elsif ( $Param{Action} eq 'CustomerLostPassword' ) {
+
+ # new layout object
+ my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
+
+ # check feature
+ if ( !$ConfigObject->Get('CustomerPanelLostPassword') ) {
+
+ # show normal login
+ $LayoutObject->Print(
+ Output => \$LayoutObject->CustomerLogin(
+ Title => 'Login',
+ Message => Translatable('Feature not active!'),
+ ),
+ );
+ return;
+ }
+
+ # get params
+ my $User = $ParamObject->GetParam( Param => 'User' ) || '';
+ my $Token = $ParamObject->GetParam( Param => 'Token' ) || '';
+
+ # get user login by token
+ if ( !$User && $Token ) {
+ my %UserList = $UserObject->SearchPreferences(
+ Key => 'UserToken',
+ Value => $Token,
+ );
+ USER_ID:
+ for my $UserID ( sort keys %UserList ) {
+ my %UserData = $UserObject->CustomerUserDataGet(
+ User => $UserID,
+ Valid => 1,
+ );
+ if (%UserData) {
+ $User = $UserData{UserLogin};
+ last USER_ID;
+ }
+ }
+ }
+
+ # get user data
+ my %UserData = $UserObject->CustomerUserDataGet( User => $User );
+
+ # verify customer user is valid when requesting password reset
+ my @ValidIDs = $Kernel::OM->Get('Kernel::System::Valid')->ValidIDsGet();
+ my $UserIsValid = grep { $UserData{ValidID} && $UserData{ValidID} == $_ } @ValidIDs;
+ if ( !$UserData{UserID} || !$UserIsValid ) {
+
+ # Security: pretend that password reset instructions were actually sent to
+ # make sure that users cannot find out valid usernames by
+ # just trying and checking the result message.
+ $LayoutObject->Print(
+ Output => \$LayoutObject->CustomerLogin(
+ Title => 'Login',
+ Message => Translatable('Sent password reset instructions. Please check your email.'),
+ MessageType => 'Success',
+ ),
+ );
+ return;
+ }
+
+ # create email object
+ my $EmailObject = Kernel::System::Email->new( %{$Self} );
+
+ # send password reset token
+ if ( !$Token ) {
+
+ # generate token
+ $UserData{Token} = $UserObject->TokenGenerate(
+ UserID => $UserData{UserID},
+ );
+
+ # send token notify email with link
+ my $Body = $ConfigObject->Get('CustomerPanelBodyLostPasswordToken')
+ || 'ERROR: CustomerPanelBodyLostPasswordToken is missing!';
+ my $Subject = $ConfigObject->Get('CustomerPanelSubjectLostPasswordToken')
+ || 'ERROR: CustomerPanelSubjectLostPasswordToken is missing!';
+ for ( sort keys %UserData ) {
+ $Body =~ s//$UserData{$_}/gi;
+ }
+ my $Sent = $EmailObject->Send(
+ To => $UserData{UserEmail},
+ Subject => $Subject,
+ Charset => $LayoutObject->{UserCharset},
+ MimeType => 'text/plain',
+ Body => $Body
+ );
+ if ( !$Sent->{Success} ) {
+ $LayoutObject->FatalError(
+ Comment => Translatable('Please contact the administrator.'),
+ );
+ return;
+ }
+ $LayoutObject->Print(
+ Output => \$LayoutObject->CustomerLogin(
+ Title => 'Login',
+ Message => Translatable('Sent password reset instructions. Please check your email.'),
+ %Param,
+ MessageType => 'Success',
+ ),
+ );
+ return 1;
+
+ }
+
+ # reset password
+ # check if token is valid
+ my $TokenValid = $UserObject->TokenCheck(
+ Token => $Token,
+ UserID => $UserData{UserID},
+ );
+ if ( !$TokenValid ) {
+ $LayoutObject->Print(
+ Output => \$LayoutObject->CustomerLogin(
+ Title => 'Login',
+ Message => Translatable('Invalid Token!'),
+ %Param,
+ ),
+ );
+ return;
+ }
+
+ # get new password
+ $UserData{NewPW} = $UserObject->GenerateRandomPassword();
+
+ # update new password
+ my $Success = $UserObject->SetPassword(
+ UserLogin => $User,
+ PW => $UserData{NewPW}
+ );
+
+ if ( !$Success ) {
+ $LayoutObject->Print(
+ Output => \$LayoutObject->CustomerLogin(
+ Title => 'Login',
+ Message => Translatable('Reset password unsuccessful. Please contact the administrator.'),
+ User => $User,
+ ),
+ );
+ return;
+ }
+
+ # send notify email
+ my $Body = $ConfigObject->Get('CustomerPanelBodyLostPassword')
+ || 'New Password is: ';
+ my $Subject = $ConfigObject->Get('CustomerPanelSubjectLostPassword')
+ || 'New Password!';
+ for ( sort keys %UserData ) {
+ $Body =~ s//$UserData{$_}/gi;
+ }
+ my $Sent = $EmailObject->Send(
+ To => $UserData{UserEmail},
+ Subject => $Subject,
+ Charset => $LayoutObject->{UserCharset},
+ MimeType => 'text/plain',
+ Body => $Body
+ );
+ if ( !$Sent->{Success} ) {
+ $LayoutObject->CustomerFatalError(
+ Comment => Translatable('Please contact the administrator.')
+ );
+ return;
+ }
+ my $Message = $LayoutObject->{LanguageObject}->Translate(
+ 'Sent new password to %s. Please check your email.',
+ $UserData{UserEmail},
+ );
+ $LayoutObject->Print(
+ Output => \$LayoutObject->CustomerLogin(
+ Title => 'Login',
+ Message => $Message,
+ User => $User,
+ MessageType => 'Success',
+ ),
+ );
+ return 1;
+ }
+
+ # create new customer account
+ elsif ( $Param{Action} eq 'CustomerCreateAccount' ) {
+
+ # new layout object
+ my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
+
+ # check feature
+ if ( !$ConfigObject->Get('CustomerPanelCreateAccount') ) {
+
+ # show normal login
+ $LayoutObject->Print(
+ Output => \$LayoutObject->CustomerLogin(
+ Title => 'Login',
+ Message => Translatable('Feature not active!'),
+ ),
+ );
+ return;
+ }
+
+ # get params
+ my %GetParams;
+ for my $Entry ( @{ $ConfigObject->Get('CustomerUser')->{Map} } ) {
+ $GetParams{ $Entry->[0] } = $ParamObject->GetParam( Param => $Entry->[1] )
+ || '';
+ }
+ $GetParams{ValidID} = 1;
+
+ # check needed params
+ if ( !$GetParams{UserCustomerID} ) {
+ $GetParams{UserCustomerID} = $GetParams{UserEmail};
+ }
+ if ( !$GetParams{UserLogin} ) {
+ $GetParams{UserLogin} = $GetParams{UserEmail};
+ }
+
+ # get new password
+ $GetParams{UserPassword} = $UserObject->GenerateRandomPassword();
+
+ # get user data
+ my %UserData = $UserObject->CustomerUserDataGet( User => $GetParams{UserLogin} );
+ if ( $UserData{UserID} || !$GetParams{UserLogin} ) {
+
+ # send data to JS
+ $LayoutObject->AddJSData(
+ Key => 'SignupError',
+ Value => 1,
+ );
+
+ $LayoutObject->Print(
+ Output => \$LayoutObject->CustomerLogin(
+ Title => 'Login',
+ Message =>
+ Translatable('This e-mail address already exists. Please log in or reset your password.'),
+ UserTitle => $GetParams{UserTitle},
+ UserFirstname => $GetParams{UserFirstname},
+ UserLastname => $GetParams{UserLastname},
+ UserEmail => $GetParams{UserEmail},
+ ),
+ );
+ return;
+ }
+
+ # check for mail address restrictions
+ my @Whitelist = @{
+ $ConfigObject->Get('CustomerPanelCreateAccount::MailRestrictions::Whitelist') // []
+ };
+ my @Blacklist = @{
+ $ConfigObject->Get('CustomerPanelCreateAccount::MailRestrictions::Blacklist') // []
+ };
+
+ my $WhitelistMatched;
+ for my $WhitelistEntry (@Whitelist) {
+ my $Regex = eval {qr/$WhitelistEntry/i};
+ if ($@) {
+ $Kernel::OM->Get('Kernel::System::Log')->Log(
+ Priority => 'error',
+ Message =>
+ $LayoutObject->{LanguageObject}->Translate(
+ 'The customer panel mail address whitelist contains the invalid regular expression $WhitelistEntry, please check and correct it.'
+ ),
+ );
+ }
+ elsif ( $GetParams{UserEmail} =~ $Regex ) {
+ $WhitelistMatched++;
+ }
+ }
+ my $BlacklistMatched;
+ for my $BlacklistEntry (@Blacklist) {
+ my $Regex = eval {qr/$BlacklistEntry/i};
+ if ($@) {
+ $Kernel::OM->Get('Kernel::System::Log')->Log(
+ Priority => 'error',
+ Message =>
+ $LayoutObject->{LanguageObject}->Translate(
+ 'The customer panel mail address blacklist contains the invalid regular expression $BlacklistEntry, please check and correct it.'
+ ),
+ );
+ }
+ elsif ( $GetParams{UserEmail} =~ $Regex ) {
+ $BlacklistMatched++;
+ }
+ }
+
+ if ( ( @Whitelist && !$WhitelistMatched ) || ( @Blacklist && $BlacklistMatched ) ) {
+
+ # send data to JS
+ $LayoutObject->AddJSData(
+ Key => 'SignupError',
+ Value => 1,
+ );
+
+ $LayoutObject->Print(
+ Output => \$LayoutObject->CustomerLogin(
+ Title => 'Login',
+ Message =>
+ Translatable('This email address is not allowed to register. Please contact support staff.'),
+ UserTitle => $GetParams{UserTitle},
+ UserFirstname => $GetParams{UserFirstname},
+ UserLastname => $GetParams{UserLastname},
+ UserEmail => $GetParams{UserEmail},
+ ),
+ );
+
+ return;
+ }
+
+ # create account
+ my $DateTimeObject = $Kernel::OM->Create('Kernel::System::DateTime');
+
+ my $Now = $DateTimeObject->ToString();
+
+ my $Add = $UserObject->CustomerUserAdd(
+ %GetParams,
+ Comment => $LayoutObject->{LanguageObject}->Translate( 'Added via Customer Panel (%s)', $Now ),
+ ValidID => 1,
+ UserID => $ConfigObject->Get('CustomerPanelUserID'),
+ );
+ if ( !$Add ) {
+
+ # send data to JS
+ $LayoutObject->AddJSData(
+ Key => 'SignupError',
+ Value => 1,
+ );
+
+ $LayoutObject->Print(
+ Output => \$LayoutObject->CustomerLogin(
+ Title => 'Login',
+ Message => Translatable('Customer user can\'t be added!'),
+ UserTitle => $GetParams{UserTitle},
+ UserFirstname => $GetParams{UserFirstname},
+ UserLastname => $GetParams{UserLastname},
+ UserEmail => $GetParams{UserEmail},
+ ),
+ );
+ return;
+ }
+
+ # send notify email
+ my $EmailObject = Kernel::System::Email->new( %{$Self} );
+ my $Body = $ConfigObject->Get('CustomerPanelBodyNewAccount')
+ || 'No Config Option found!';
+ my $Subject = $ConfigObject->Get('CustomerPanelSubjectNewAccount')
+ || 'New OTRS Account!';
+ for ( sort keys %GetParams ) {
+ $Body =~ s//$GetParams{$_}/gi;
+ }
+
+ # send account info
+ my $Sent = $EmailObject->Send(
+ To => $GetParams{UserEmail},
+ Subject => $Subject,
+ Charset => $LayoutObject->{UserCharset},
+ MimeType => 'text/plain',
+ Body => $Body
+ );
+ if ( !$Sent->{Success} ) {
+ my $Output = $LayoutObject->CustomerHeader(
+ Area => 'Core',
+ Title => 'Error'
+ );
+ $Output .= $LayoutObject->CustomerWarning(
+ Comment => Translatable('Can\'t send account info!')
+ );
+ $Output .= $LayoutObject->CustomerFooter();
+ $LayoutObject->Print( Output => \$Output );
+ return;
+ }
+
+ # show sent account info
+ if ( $ConfigObject->Get('CustomerPanelLoginURL') ) {
+
+ # redirect to alternate login
+ $Param{RequestedURL} = $LayoutObject->LinkEncode( $Param{RequestedURL} );
+ print $LayoutObject->Redirect(
+ ExtURL => $ConfigObject->Get('CustomerPanelLoginURL')
+ . "?RequestedURL=$Param{RequestedURL};User=$GetParams{UserLogin};"
+ . "Email=$GetParams{UserEmail};Reason=NewAccountCreated",
+ );
+ return 1;
+ }
+
+ my $AccountCreatedMessage = $LayoutObject->{LanguageObject}->Translate(
+ 'New account created. Sent login information to %s. Please check your email.',
+ $GetParams{UserEmail},
+ );
+
+ # login screen
+ $LayoutObject->Print(
+ Output => \$LayoutObject->CustomerLogin(
+ Title => 'Login',
+ Message => $AccountCreatedMessage,
+ User => $GetParams{UserLogin},
+ MessageType => 'Success',
+ ),
+ );
+ return 1;
+ }
+
+ # show login site
+ elsif ( !$Param{SessionID} ) {
+
+ # new layout object
+ my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
+
+ # create AuthObject
+ my $AuthObject = $Kernel::OM->Get('Kernel::System::CustomerAuth');
+ if ( $AuthObject->GetOption( What => 'PreAuth' ) ) {
+
+ # automatic login
+ $Param{RequestedURL} = $LayoutObject->LinkEncode( $Param{RequestedURL} );
+ print $LayoutObject->Redirect(
+ OP => "Action=PreLogin;RequestedURL=$Param{RequestedURL}",
+ );
+ return;
+ }
+ elsif ( $ConfigObject->Get('CustomerPanelLoginURL') ) {
+
+ # redirect to alternate login
+ $Param{RequestedURL} = $LayoutObject->LinkEncode( $Param{RequestedURL} );
+ print $LayoutObject->Redirect(
+ ExtURL => $ConfigObject->Get('CustomerPanelLoginURL')
+ . "?RequestedURL=$Param{RequestedURL}",
+ );
+ return;
+ }
+
+ # login screen
+ $LayoutObject->Print(
+ Output => \$LayoutObject->CustomerLogin(
+ Title => 'Login',
+ %Param,
+ ),
+ );
+ return 1;
+ }
+
+ # run modules if a version value exists
+ elsif ( $Kernel::OM->Get('Kernel::System::Main')->Require("Kernel::Modules::$Param{Action}") ) {
+
+ # check session id
+ if ( !$SessionObject->CheckSessionID( SessionID => $Param{SessionID} ) ) {
+
+ # create new LayoutObject with new '%Param'
+ $Kernel::OM->ObjectParamAdd(
+ 'Kernel::Output::HTML::Layout' => {
+ SetCookies => {
+ SessionIDCookie => $ParamObject->SetCookie(
+ Key => $Param{SessionName},
+ Value => '',
+ Expires => '-1y',
+ Path => $ConfigObject->Get('ScriptAlias'),
+ Secure => scalar $CookieSecureAttribute,
+ HTTPOnly => 1,
+ ),
+ },
+ %Param,
+ }
+ );
+
+ $Kernel::OM->ObjectsDiscard( Objects => ['Kernel::Output::HTML::Layout'] );
+ my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
+
+ # create AuthObject
+ my $AuthObject = $Kernel::OM->Get('Kernel::System::CustomerAuth');
+ if ( $AuthObject->GetOption( What => 'PreAuth' ) ) {
+
+ # automatic re-login
+ $Param{RequestedURL} = $LayoutObject->LinkEncode( $Param{RequestedURL} );
+ print $LayoutObject->Redirect(
+ OP => "?Action=PreLogin&RequestedURL=$Param{RequestedURL}",
+ );
+ return;
+ }
+
+ # redirect to alternate login
+ elsif ( $ConfigObject->Get('CustomerPanelLoginURL') ) {
+
+ # redirect to alternate login
+ $Param{RequestedURL} = $LayoutObject->LinkEncode( $Param{RequestedURL} );
+ print $LayoutObject->Redirect(
+ ExtURL => $ConfigObject->Get('CustomerPanelLoginURL')
+ . "?Reason=InvalidSessionID;RequestedURL=$Param{RequestedURL}",
+ );
+ return;
+ }
+
+ # show login
+ $LayoutObject->Print(
+ Output => \$LayoutObject->CustomerLogin(
+ Title => 'Login',
+ Message =>
+ $LayoutObject->{LanguageObject}->Translate( $SessionObject->SessionIDErrorMessage() ),
+ %Param,
+ ),
+ );
+ return;
+ }
+
+ # get session data
+ my %UserData = $SessionObject->GetSessionIDData(
+ SessionID => $Param{SessionID},
+ );
+
+ # check needed data
+ if ( !$UserData{UserID} || !$UserData{UserLogin} || $UserData{UserType} ne 'Customer' ) {
+ my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
+
+ # redirect to alternate login
+ if ( $ConfigObject->Get('CustomerPanelLoginURL') ) {
+ print $LayoutObject->Redirect(
+ ExtURL => $ConfigObject->Get('CustomerPanelLoginURL')
+ . "?Reason=SystemError",
+ );
+ return;
+ }
+
+ # show login screen
+ $LayoutObject->Print(
+ Output => \$LayoutObject->CustomerLogin(
+ Title => 'Error',
+ Message => Translatable('Error: invalid session.'),
+ %Param,
+ ),
+ );
+ return;
+ }
+
+ # module registry
+ my $ModuleReg = $ConfigObject->Get('CustomerFrontend::Module')->{ $Param{Action} };
+ if ( !$ModuleReg ) {
+
+ # new layout object
+ my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
+ $Kernel::OM->Get('Kernel::System::Log')->Log(
+ Priority => 'error',
+ Message =>
+ "Module Kernel::Modules::$Param{Action} not registered in Kernel/Config.pm!",
+ );
+ $LayoutObject->CustomerFatalError(
+ Comment => Translatable('Please contact the administrator.'),
+ );
+ return;
+ }
+
+ # module permission check for action
+ if (
+ ref $ModuleReg->{GroupRo} eq 'ARRAY'
+ && !scalar @{ $ModuleReg->{GroupRo} }
+ && ref $ModuleReg->{Group} eq 'ARRAY'
+ && !scalar @{ $ModuleReg->{Group} }
+ )
+ {
+ $Param{AccessRo} = 1;
+ $Param{AccessRw} = 1;
+ }
+ else {
+
+ ( $Param{AccessRo}, $Param{AccessRw} ) = $Self->_CheckModulePermission(
+ ModuleReg => $ModuleReg,
+ %UserData,
+ );
+
+ if ( !$Param{AccessRo} ) {
+
+ # new layout object
+ my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
+ $Kernel::OM->Get('Kernel::System::Log')->Log(
+ Priority => 'error',
+ Message => 'No Permission to use this frontend action module!'
+ );
+ $LayoutObject->CustomerFatalError(
+ Comment => Translatable('Please contact the administrator.'),
+ );
+ return;
+ }
+
+ }
+
+ my $NavigationConfig = $ConfigObject->Get('CustomerFrontend::Navigation')->{ $Param{Action} };
+
+ # module permission check for submenu item
+ if ( IsHashRefWithData($NavigationConfig) ) {
+
+ KEY:
+ for my $Key ( sort keys %{$NavigationConfig} ) {
+ next KEY if $Key !~ m/^\d+/i;
+ next KEY if $Param{RequestedURL} !~ m/Subaction/i;
+
+ my @ModuleNavigationConfigs;
+
+ # FIXME: Support both old (HASH) and new (ARRAY of HASH) navigation configurations, for reasons of
+ # backwards compatibility. Once we are sure everything has been migrated correctly, support for
+ # HASH-only configuration can be dropped in future major release.
+ if ( IsHashRefWithData( $NavigationConfig->{$Key} ) ) {
+ push @ModuleNavigationConfigs, $NavigationConfig->{$Key};
+ }
+ elsif ( IsArrayRefWithData( $NavigationConfig->{$Key} ) ) {
+ push @ModuleNavigationConfigs, @{ $NavigationConfig->{$Key} };
+ }
+
+ # Skip incompatible configuration.
+ else {
+ next KEY;
+ }
+
+ ITEM:
+ for my $Item (@ModuleNavigationConfigs) {
+ if (
+ $Item->{Link} =~ m/Subaction=/i
+ && $Item->{Link} !~ m/$Param{Subaction}/i
+ )
+ {
+ next ITEM;
+ }
+ $Param{AccessRo} = 0;
+ $Param{AccessRw} = 0;
+
+ # module permission check for submenu item
+ if (
+ ref $Item->{GroupRo} eq 'ARRAY'
+ && !scalar @{ $Item->{GroupRo} }
+ && ref $Item->{Group} eq 'ARRAY'
+ && !scalar @{ $Item->{Group} }
+ )
+ {
+ $Param{AccessRo} = 1;
+ $Param{AccessRw} = 1;
+ }
+ else {
+
+ ( $Param{AccessRo}, $Param{AccessRw} ) = $Self->_CheckModulePermission(
+ ModuleReg => $Item,
+ %UserData,
+ );
+
+ if ( !$Param{AccessRo} ) {
+
+ # new layout object
+ my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
+ $Kernel::OM->Get('Kernel::System::Log')->Log(
+ Priority => 'error',
+ Message => 'No Permission to use this frontend subaction module!'
+ );
+ $LayoutObject->CustomerFatalError(
+ Comment => Translatable('Please contact the administrator.')
+ );
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ # create new LayoutObject with new '%Param' and '%UserData'
+ $Kernel::OM->ObjectParamAdd(
+ 'Kernel::Output::HTML::Layout' => {
+ %Param,
+ %UserData,
+ ModuleReg => $ModuleReg,
+ },
+ );
+
+ $Kernel::OM->ObjectsDiscard( Objects => ['Kernel::Output::HTML::Layout'] );
+ my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
+
+ # update last request time
+ if (
+ !$ParamObject->IsAJAXRequest()
+ || $Param{Action} eq 'CustomerVideoChat'
+ )
+ {
+ my $DateTimeObject = $Kernel::OM->Create('Kernel::System::DateTime');
+
+ $SessionObject->UpdateSessionID(
+ SessionID => $Param{SessionID},
+ Key => 'UserLastRequest',
+ Value => $DateTimeObject->ToEpoch(),
+ );
+ }
+
+ # pre application module
+ my $PreModule = $ConfigObject->Get('CustomerPanelPreApplicationModule');
+ if ($PreModule) {
+ my %PreModuleList;
+ if ( ref $PreModule eq 'HASH' ) {
+ %PreModuleList = %{$PreModule};
+ }
+ else {
+ $PreModuleList{Init} = $PreModule;
+ }
+
+ MODULE:
+ for my $PreModuleKey ( sort keys %PreModuleList ) {
+ my $PreModule = $PreModuleList{$PreModuleKey};
+ next MODULE if !$PreModule;
+ next MODULE if !$Kernel::OM->Get('Kernel::System::Main')->Require($PreModule);
+
+ # debug info
+ if ( $Self->{Debug} ) {
+ $Kernel::OM->Get('Kernel::System::Log')->Log(
+ Priority => 'debug',
+ Message => "CustomerPanelPreApplication module $PreModule is used.",
+ );
+ }
+
+ # use module
+ my $PreModuleObject = $PreModule->new(
+ %Param,
+ %UserData,
+
+ );
+ my $Output = $PreModuleObject->PreRun();
+ if ($Output) {
+ $LayoutObject->Print( Output => \$Output );
+ return 1;
+ }
+ }
+ }
+
+ # debug info
+ if ( $Self->{Debug} ) {
+ $Kernel::OM->Get('Kernel::System::Log')->Log(
+ Priority => 'debug',
+ Message => 'Kernel::Modules::' . $Param{Action} . '->new',
+ );
+ }
+
+ my $FrontendObject = ( 'Kernel::Modules::' . $Param{Action} )->new(
+ %Param,
+ %UserData,
+ ModuleReg => $ModuleReg,
+ Debug => $Self->{Debug},
+ );
+
+ # debug info
+ if ( $Self->{Debug} ) {
+ $Kernel::OM->Get('Kernel::System::Log')->Log(
+ Priority => 'debug',
+ Message => 'Kernel::Modules::' . $Param{Action} . '->run',
+ );
+ }
+
+ # ->Run $Action with $FrontendObject
+ $LayoutObject->Print( Output => \$FrontendObject->Run() );
+
+ # log request time
+ if ( $ConfigObject->Get('PerformanceLog') ) {
+ if ( ( !$QueryString && $Param{Action} ) || $QueryString !~ /Action=/ ) {
+ $QueryString = 'Action=' . $Param{Action} . ';Subaction=' . $Param{Subaction};
+ }
+ my $File = $ConfigObject->Get('PerformanceLog::File');
+ ## no critic
+ if ( open my $Out, '>>', $File ) {
+ ## use critic
+ print $Out time()
+ . '::Customer::'
+ . ( time() - $Self->{PerformanceLogStart} )
+ . "::$UserData{UserLogin}::$QueryString\n";
+ close $Out;
+ $Kernel::OM->Get('Kernel::System::Log')->Log(
+ Priority => 'debug',
+ Message => 'Response::Customer: '
+ . ( time() - $Self->{PerformanceLogStart} )
+ . "s taken (URL:$QueryString:$UserData{UserLogin})",
+ );
+ }
+ else {
+ $Kernel::OM->Get('Kernel::System::Log')->Log(
+ Priority => 'error',
+ Message => "Can't write $File: $!",
+ );
+ }
+ }
+ return 1;
+ }
+
+ # print an error screen
+ my %Data = $SessionObject->GetSessionIDData(
+ SessionID => $Param{SessionID},
+ );
+ $Kernel::OM->ObjectParamAdd(
+ 'Kernel::Output::HTML::Layout' => {
+ %Param,
+ %Data,
+ },
+ );
+ my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
+ $LayoutObject->CustomerFatalError(
+ Comment => Translatable('Please contact the administrator.'),
+ );
+ return;
+}
+
+=begin Internal:
+
+=head2 _CheckModulePermission()
+
+module permission check
+
+ ($AccessRo, $AccessRw = $AutoResponseObject->_CheckModulePermission(
+ ModuleReg => $ModuleReg,
+ %UserData,
+ );
+
+=cut
+
+sub _CheckModulePermission {
+ my ( $Self, %Param ) = @_;
+
+ my $AccessRo = 0;
+ my $AccessRw = 0;
+
+ PERMISSION:
+ for my $Permission (qw(GroupRo Group)) {
+ my $AccessOk = 0;
+ my $Group = $Param{ModuleReg}->{$Permission};
+
+ next PERMISSION if !$Group;
+
+ my $GroupObject = $Kernel::OM->Get('Kernel::System::CustomerGroup');
+
+ if ( IsArrayRefWithData($Group) ) {
+ GROUP:
+ for my $Item ( @{$Group} ) {
+ next GROUP if !$Item;
+ next GROUP if !$GroupObject->PermissionCheck(
+ UserID => $Param{UserID},
+ GroupName => $Item,
+ Type => $Permission eq 'GroupRo' ? 'ro' : 'rw',
+ );
+
+ $AccessOk = 1;
+ last GROUP;
+ }
+ }
+ else {
+ my $HasPermission = $GroupObject->PermissionCheck(
+ UserID => $Param{UserID},
+ GroupName => $Group,
+ Type => $Permission eq 'GroupRo' ? 'ro' : 'rw',
+ );
+ if ($HasPermission) {
+ $AccessOk = 1;
+ }
+ }
+ if ( $Permission eq 'Group' && $AccessOk ) {
+ $AccessRo = 1;
+ $AccessRw = 1;
+ }
+ elsif ( $Permission eq 'GroupRo' && $AccessOk ) {
+ $AccessRo = 1;
+ }
+ }
+
+ return ( $AccessRo, $AccessRw );
+}
+
+=end Internal:
+
+=cut
+
+sub DESTROY {
+ my $Self = shift;
+
+ # debug info
+ if ( $Self->{Debug} ) {
+ $Kernel::OM->Get('Kernel::System::Log')->Log(
+ Priority => 'debug',
+ Message => 'Global handle stopped.',
+ );
+ }
+
+ return 1;
+}
+
+# CAS Custom
+=item
+ Check if it is a CAS logout - if true, logs out user for the session ticket
+=cut
+sub CASLogout {
+ my $Self = shift;
+
+ # get post data
+ my $cgi = new CGI;
+ my $request = uri_unescape($cgi->query_string());
+
+ # check if it is CAS logout
+ if ($request =~ /(logoutRequest=([^<]+)/);
+ if (! $ticket) {
+ return 1;
+ } else {
+ }
+
+ my $DBObject = $Kernel::OM->Get("Kernel::System::DB");
+
+ # get login for session
+ my $sqlLogin = 'SELECT UserLogin from cas_session where Ticket=?';
+ $DBObject->Prepare(SQL => $sqlLogin, Bind => [\$ticket]);
+ my $login;
+ while (my @Row = $DBObject->FetchrowArray()) {
+ $login = $Row[0];
+ }
+
+ # if a login was found, kill the user session
+ if ($login) {
+ $DBObject->Do(SQL => "DELETE FROM sessions WHERE session_id IN (select session_id from (select session_id FROM sessions WHERE data_key='UserLogin' AND data_value=?) as x)",
+ Bind => [\$login]);
+ } else {
+ }
+ return 1;
+ } else {
+ return 0;
+ }
+}
+# CAS Custom
+
+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 (AGPL). If you
+did not receive this file, see L.
+
+=cut
diff --git a/Custom/Kernel/System/Web/Request.pm b/Custom/Kernel/System/Web/Request.pm
new file mode 100644
index 0000000..dc0cdc8
--- /dev/null
+++ b/Custom/Kernel/System/Web/Request.pm
@@ -0,0 +1,582 @@
+# --
+# Copyright (C) 2001-2017 OTRS AG, http://otrs.com/
+# --
+# 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.
+#
+# Custom version for CAS authentication - rodrigo@goncalves.pro.br
+#
+# Version 2016-01-18 - RG - Version for OTRS 5.0.6
+# Version 2017-12-07 - RG - Version for OTRS 6.0.1
+#
+# --
+
+package Kernel::System::Web::Request;
+
+use strict;
+use warnings;
+
+use CGI ();
+use CGI::Carp;
+use File::Path qw();
+
+use Kernel::System::VariableCheck qw(:all);
+
+our @ObjectDependencies = (
+ 'Kernel::Config',
+ 'Kernel::System::CheckItem',
+ 'Kernel::System::Encode',
+ 'Kernel::System::Web::UploadCache',
+ 'Kernel::System::FormDraft',
+);
+
+=head1 NAME
+
+Kernel::System::Web::Request - global CGI interface
+
+=head1 DESCRIPTION
+
+All cgi param functions.
+
+=head1 PUBLIC INTERFACE
+
+=head2 new()
+
+create param object. Do not use it directly, instead use:
+
+ use Kernel::System::ObjectManager;
+ local $Kernel::OM = Kernel::System::ObjectManager->new(
+ 'Kernel::System::Web::Request' => {
+ WebRequest => CGI::Fast->new(), # optional, e. g. if fast cgi is used
+ }
+ );
+ my $ParamObject = $Kernel::OM->Get('Kernel::System::Web::Request');
+
+If Kernel::System::Web::Request is instantiated several times, they will share the
+same CGI data (this can be helpful in filters which do not have access to the
+ParamObject, for example.
+
+If you need to reset the CGI data before creating a new instance, use
+
+ CGI::initialize_globals();
+
+before calling Kernel::System::Web::Request->new();
+
+=cut
+
+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');
+
+ # max 5 MB posts
+ $CGI::POST_MAX = $ConfigObject->Get('WebMaxFileUpload') || 1024 * 1024 * 5; ## no critic
+
+ # query object (in case use already existing WebRequest, e. g. fast cgi)
+ $Self->{Query} = $Param{WebRequest} || CGI->new();
+
+ return $Self;
+}
+
+=head2 Error()
+
+to get the error back
+
+ if ( $ParamObject->Error() ) {
+ print STDERR $ParamObject->Error() . "\n";
+ }
+
+=cut
+
+sub Error {
+ my ( $Self, %Param ) = @_;
+
+ # Workaround, do not check cgi_error() with perlex, CGI module is not
+ # working with perlex.
+ if ( $ENV{'GATEWAY_INTERFACE'} && $ENV{'GATEWAY_INTERFACE'} =~ /^CGI-PerlEx/ ) {
+ return;
+ }
+
+ return if !$Self->{Query}->cgi_error();
+ ## no critic
+ return $Self->{Query}->cgi_error() . ' - POST_MAX=' . ( $CGI::POST_MAX / 1024 ) . 'KB';
+ ## use critic
+}
+
+=head2 GetParam()
+
+to get single request parameters. By default, trimming is performed on the data.
+
+ my $Param = $ParamObject->GetParam(
+ Param => 'ID',
+ Raw => 1, # optional, input data is not changed
+ );
+
+=cut
+
+sub GetParam {
+ my ( $Self, %Param ) = @_;
+
+ my $Value = $Self->{Query}->param( $Param{Param} );
+
+ # Fallback to query string for mixed requests.
+ my $RequestMethod = $Self->{Query}->request_method() // '';
+ if ( $RequestMethod eq 'POST' && !defined $Value ) {
+ $Value = $Self->{Query}->url_param( $Param{Param} );
+ }
+
+ $Kernel::OM->Get('Kernel::System::Encode')->EncodeInput( \$Value );
+
+ my $Raw = defined $Param{Raw} ? $Param{Raw} : 0;
+
+ if ( !$Raw ) {
+
+ # If it is a plain string, perform trimming
+ if ( ref \$Value eq 'SCALAR' ) {
+ $Kernel::OM->Get('Kernel::System::CheckItem')->StringClean(
+ StringRef => \$Value,
+ TrimLeft => 1,
+ TrimRight => 1,
+ );
+ }
+ }
+
+ return $Value;
+}
+
+=head2 GetParamNames()
+
+to get names of all parameters passed to the script.
+
+ my @ParamNames = $ParamObject->GetParamNames();
+
+Example:
+
+Called URL: index.pl?Action=AdminSystemConfiguration;Subaction=Save;Name=Config::Option::Valid
+
+ my @ParamNames = $ParamObject->GetParamNames();
+ print join " :: ", @ParamNames;
+ #prints Action :: Subaction :: Name
+
+=cut
+
+sub GetParamNames {
+ my $Self = shift;
+
+ # fetch all names
+ my @ParamNames = $Self->{Query}->param();
+
+ # Fallback to query string for mixed requests.
+ my $RequestMethod = $Self->{Query}->request_method() // '';
+ if ( $RequestMethod eq 'POST' ) {
+ my %POSTNames;
+ @POSTNames{@ParamNames} = @ParamNames;
+ my @GetNames = $Self->{Query}->url_param();
+ GETNAME:
+ for my $GetName (@GetNames) {
+ next GETNAME if !defined $GetName;
+ push @ParamNames, $GetName if !exists $POSTNames{$GetName};
+ }
+ }
+
+ for my $Name (@ParamNames) {
+ $Kernel::OM->Get('Kernel::System::Encode')->EncodeInput( \$Name );
+ }
+
+ return @ParamNames;
+}
+
+=head2 GetArray()
+
+to get array request parameters.
+By default, trimming is performed on the data.
+
+ my @Param = $ParamObject->GetArray(
+ Param => 'ID',
+ Raw => 1, # optional, input data is not changed
+ );
+
+=cut
+
+sub GetArray {
+ my ( $Self, %Param ) = @_;
+
+ my @Values = $Self->{Query}->multi_param( $Param{Param} );
+
+ # Fallback to query string for mixed requests.
+ my $RequestMethod = $Self->{Query}->request_method() // '';
+ if ( $RequestMethod eq 'POST' && !@Values ) {
+ @Values = $Self->{Query}->url_param( $Param{Param} );
+ }
+
+ $Kernel::OM->Get('Kernel::System::Encode')->EncodeInput( \@Values );
+
+ my $Raw = defined $Param{Raw} ? $Param{Raw} : 0;
+
+ if ( !$Raw ) {
+
+ # get check item object
+ my $CheckItemObject = $Kernel::OM->Get('Kernel::System::CheckItem');
+
+ VALUE:
+ for my $Value (@Values) {
+
+ # don't validate CGI::File::Temp objects from file uploads
+ next VALUE if !$Value || ref \$Value ne 'SCALAR';
+
+ $CheckItemObject->StringClean(
+ StringRef => \$Value,
+ TrimLeft => 1,
+ TrimRight => 1,
+ );
+ }
+ }
+
+ return @Values;
+}
+
+=head2 GetUploadAll()
+
+gets file upload data.
+
+ my %File = $ParamObject->GetUploadAll(
+ Param => 'FileParam', # the name of the request parameter containing the file data
+ );
+
+ returns (
+ Filename => 'abc.txt',
+ ContentType => 'text/plain',
+ Content => 'Some text',
+ );
+
+=cut
+
+sub GetUploadAll {
+ my ( $Self, %Param ) = @_;
+
+ # get upload
+ my $Upload = $Self->{Query}->upload( $Param{Param} );
+ return if !$Upload;
+
+ # get real file name
+ my $UploadFilenameOrig = $Self->GetParam( Param => $Param{Param} ) || 'unknown';
+
+ my $NewFileName = "$UploadFilenameOrig"; # use "" to get filename of anony. object
+ $Kernel::OM->Get('Kernel::System::Encode')->EncodeInput( \$NewFileName );
+
+ # replace all devices like c: or d: and dirs for IE!
+ $NewFileName =~ s/.:\\(.*)/$1/g;
+ $NewFileName =~ s/.*\\(.+?)/$1/g;
+
+ # return a string
+ my $Content = '';
+ while (<$Upload>) {
+ $Content .= $_;
+ }
+ close $Upload;
+
+ my $ContentType = $Self->_GetUploadInfo(
+ Filename => $UploadFilenameOrig,
+ Header => 'Content-Type',
+ );
+
+ return (
+ Filename => $NewFileName,
+ Content => $Content,
+ ContentType => $ContentType,
+ );
+}
+
+sub _GetUploadInfo {
+ my ( $Self, %Param ) = @_;
+
+ # get file upload info
+ my $FileInfo = $Self->{Query}->uploadInfo( $Param{Filename} );
+
+ # return if no upload info exists
+ return 'application/octet-stream' if !$FileInfo;
+
+ # return if no content type of upload info exists
+ return 'application/octet-stream' if !$FileInfo->{ $Param{Header} };
+
+ # return content type of upload info
+ return $FileInfo->{ $Param{Header} };
+}
+
+=head2 SetCookie()
+
+set a cookie
+
+ $ParamObject->SetCookie(
+ Key => ID,
+ Value => 123456,
+ Expires => '+3660s',
+ Path => 'otrs/', # optional, only allow cookie for given path
+ Secure => 1, # optional, set secure attribute to disable cookie on HTTP (HTTPS only)
+ HTTPOnly => 1, # optional, sets HttpOnly attribute of cookie to prevent access via JavaScript
+ );
+
+=cut
+
+sub SetCookie {
+ my ( $Self, %Param ) = @_;
+
+ $Param{Path} ||= '';
+
+ return $Self->{Query}->cookie(
+ -name => $Param{Key},
+ -value => $Param{Value},
+ -expires => $Param{Expires},
+ -secure => $Param{Secure} || '',
+ -httponly => $Param{HTTPOnly} || '',
+ -path => '/' . $Param{Path},
+ );
+}
+
+=head2 GetCookie()
+
+get a cookie
+
+ my $String = $ParamObject->GetCookie(
+ Key => ID,
+ );
+
+=cut
+
+sub GetCookie {
+ my ( $Self, %Param ) = @_;
+
+ return $Self->{Query}->cookie( $Param{Key} );
+}
+
+=head2 IsAJAXRequest()
+
+checks if the current request was sent by AJAX
+
+ my $IsAJAXRequest = $ParamObject->IsAJAXRequest();
+
+=cut
+
+sub IsAJAXRequest {
+ my ( $Self, %Param ) = @_;
+
+ return ( $Self->{Query}->http('X-Requested-With') // '' ) eq 'XMLHttpRequest' ? 1 : 0;
+}
+
+=head2 LoadFormDraft()
+
+Load specified draft.
+This will read stored draft data and inject it into the param object
+for transparent use by frontend module.
+
+ my $FormDraftID = $ParamObject->LoadFormDraft(
+ FormDraftID => 123,
+ UserID => 1,
+ );
+
+=cut
+
+sub LoadFormDraft {
+ my ( $Self, %Param ) = @_;
+
+ return if !$Param{FormDraftID} || !$Param{UserID};
+
+ # get draft data
+ my $FormDraft = $Kernel::OM->Get('Kernel::System::FormDraft')->FormDraftGet(
+ FormDraftID => $Param{FormDraftID},
+ UserID => $Param{UserID},
+ );
+ return if !IsHashRefWithData($FormDraft);
+
+ # Verify action.
+ my $Action = $Self->GetParam( Param => 'Action' );
+ return if $FormDraft->{Action} ne $Action;
+
+ # add draft name to form data
+ $FormDraft->{FormData}->{FormDraftTitle} = $FormDraft->{Title};
+
+ # create FormID and add to form data
+ my $FormID = $Kernel::OM->Get('Kernel::System::Web::UploadCache')->FormIDCreate();
+ $FormDraft->{FormData}->{FormID} = $FormID;
+
+ # set form data to param object, depending on type
+ KEY:
+ for my $Key ( sort keys %{ $FormDraft->{FormData} } ) {
+ my $Value = $FormDraft->{FormData}->{$Key} // '';
+
+ # array value
+ if ( IsArrayRefWithData($Value) ) {
+ $Self->{Query}->param(
+ -name => $Key,
+ -values => $Value,
+ );
+ next KEY;
+ }
+
+ # scalar value
+ $Self->{Query}->param(
+ -name => $Key,
+ -value => $Value,
+ );
+ }
+
+ # add UploadCache data
+ my $UploadCacheObject = $Kernel::OM->Get('Kernel::System::Web::UploadCache');
+ for my $File ( @{ $FormDraft->{FileData} } ) {
+ return if !$UploadCacheObject->FormIDAddFile(
+ %{$File},
+ FormID => $FormID,
+ );
+ }
+
+ return $Param{FormDraftID};
+}
+
+=head2 SaveFormDraft()
+
+Create or replace draft using data from param object and upload cache.
+Specified params can be overwritten if necessary.
+
+ my $FormDraftID = $ParamObject->SaveFormDraft(
+ UserID => 1
+ ObjectType => 'Ticket',
+ ObjectID => 123,
+ OverrideParams => { # optional, can contain strings and array references
+ Subaction => undef,
+ UserID => 1,
+ CustomParam => [ 1, 2, 3, ],
+ ...
+ },
+ );
+
+=cut
+
+sub SaveFormDraft {
+ my ( $Self, %Param ) = @_;
+
+ # check params
+ return if !$Param{UserID} || !$Param{ObjectType} || !IsInteger( $Param{ObjectID} );
+
+ # gather necessary data for backend
+ my %MetaParams;
+ for my $Param (qw(Action FormDraftID FormDraftTitle FormID)) {
+ $MetaParams{$Param} = $Self->GetParam(
+ Param => $Param,
+ );
+ }
+ return if !$MetaParams{Action};
+
+ # determine session name param (SessionUseCookie = 0) for exclusion
+ my $SessionName = $Kernel::OM->Get('Kernel::Config')->Get('SessionName') || 'SessionID';
+
+ # compile override list
+ my %OverrideParams = IsHashRefWithData( $Param{OverrideParams} ) ? %{ $Param{OverrideParams} } : ();
+
+ # these params must always be excluded for safety, they take precedence
+ for my $Name (
+ qw(Action ChallengeToken FormID FormDraftID FormDraftTitle FormDraftAction LoadFormDraftID),
+ $SessionName
+ )
+ {
+ $OverrideParams{$Name} = undef;
+ }
+
+ # Gather all params.
+ # Exclude, add or override by using OverrideParams if necessary.
+ my @ParamNames = $Self->GetParamNames();
+ my %ParamSeen;
+ my %FormData;
+ PARAM:
+ for my $Param ( @ParamNames, sort keys %OverrideParams ) {
+ next PARAM if $ParamSeen{$Param}++;
+ my $Value;
+
+ # check for overrides first
+ if ( exists $OverrideParams{$Param} ) {
+
+ # allow only strings and array references as value
+ if (
+ IsStringWithData( $OverrideParams{$Param} )
+ || IsArrayRefWithData( $OverrideParams{$Param} )
+ )
+ {
+ $Value = $OverrideParams{$Param};
+ }
+
+ # skip all other parameters (including those specified to be excluded by using 'undef')
+ else {
+ next PARAM;
+ }
+ }
+
+ # get other values from param object
+ if ( !defined $Value ) {
+ my @Values = $Self->GetArray( Param => $Param );
+ next PARAM if !IsArrayRefWithData( \@Values );
+
+ # store single occurances as string
+ if ( scalar @Values == 1 ) {
+ $Value = $Values[0];
+ }
+
+ # store multiple occurances as array reference
+ else {
+ $Value = \@Values;
+ }
+ }
+
+ $FormData{$Param} = $Value;
+ }
+
+ # get files from upload cache
+ my @FileData = $Kernel::OM->Get('Kernel::System::Web::UploadCache')->FormIDGetAllFilesData(
+ FormID => $MetaParams{FormID},
+ );
+
+ # prepare data to add or update draft
+ my %FormDraft = (
+ FormData => \%FormData,
+ FileData => \@FileData,
+ FormDraftID => $MetaParams{FormDraftID},
+ ObjectType => $Param{ObjectType},
+ ObjectID => $Param{ObjectID},
+ Action => $MetaParams{Action},
+ Title => $MetaParams{FormDraftTitle},
+ UserID => $Param{UserID},
+ );
+
+ # update draft
+ if ( $MetaParams{FormDraftID} ) {
+ return if !$Kernel::OM->Get('Kernel::System::FormDraft')->FormDraftUpdate(%FormDraft);
+ return 1;
+ }
+
+ # create new draft
+ return if !$Kernel::OM->Get('Kernel::System::FormDraft')->FormDraftAdd(%FormDraft);
+ return 1;
+}
+
+# CAS Custom
+sub GetMethod {
+ my ( $Self, %Param ) = @_;
+ return $Self->{Query}->request_method();
+}
+# CAS Custom
+
+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 (AGPL). If you
+did not receive this file, see L.
+
+=cut
diff --git a/Kernel/System/Auth/CAS.pm b/Kernel/System/Auth/CAS.pm
new file mode 100644
index 0000000..2bfec97
--- /dev/null
+++ b/Kernel/System/Auth/CAS.pm
@@ -0,0 +1,154 @@
+# --
+# Kernel/System/Auth/CAS.pm - provides the CAS authentication through Jasig
+#
+# Copyright (C) 2015-2017 - Rodrigo Gonçalves - rodrigo@goncalves.pro.br
+# --
+# $Id: CAS.pm,v 2.0 2015/01/05 15:16:05 mb Exp $
+#
+# Version 2015/01/15 - RG - Adjusts for OTRS4
+# Version 2016-01-18 - RG - Fixes for OTRS 5.0.6
+# Version 2017-12-07 - RG - Fixes for OTRS 6.0.1
+#
+#
+# --
+# 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.
+# --
+# Note:
+#
+# If you use this module, you should use as fallback the following config settings:
+#
+# If use isn't login through apache ($ENV{REMOTE_USER} or $ENV{HTTP_REMOTE_USER})
+# $Self->{CustomerPanelLoginURL} = 'http://host.example.com/not-authorised-for-otrs.html';
+#
+# $Self->{CustomerPanelLogoutURL} = 'http://host.example.com/thanks-for-using-otrs.html';
+#
+# --
+package Kernel::System::Auth::CAS;
+
+use strict;
+use warnings;
+use CGI;
+use AuthCAS;
+use Data::Dumper;
+use CGI::Carp qw( fatalsToBrowser );
+use URI::Escape;
+
+our @ObjectDependencies = ( "Kernel::Config", "Kernel::System::Log", "Kernel::System::DB" );
+
+sub new {
+ my ( $Type, %Param ) = @_;
+
+ # allocate new hash for object
+ my $Self = {};
+ bless( $Self, $Type );
+
+ # Debug 0=off 1=on
+ $Self->{Debug} = 1;
+ $Self->{Count} = $Param{Count} || '';
+
+ return $Self;
+}
+
+sub GetOption {
+ my ( $Self, %Param ) = @_;
+
+ # check needed stuff
+ if ( !$Param{What} ) {
+ $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need What!" );
+ return;
+ }
+
+ # module options
+ my %Option = ( PreAuth => 1, );
+
+ # return option
+ return $Option{ $Param{What} };
+}
+
+sub Auth {
+ my ( $Self, %Param ) = @_;
+
+ my $QueryString = $ENV{"HTTP_REFERER"} || '';
+
+ my $ConfigObject = $Kernel::OM->Get("Kernel::Config");
+
+ my $cas = new AuthCAS( casUrl => $ConfigObject->Get('AuthModule::CAS::CASUrl') );
+ my $app_url = $ConfigObject->Get('AuthModule::CAS::ServiceUrl');
+ my $Gateway = $ConfigObject->Get('AuthModule::CAS::Gateway');
+ my $User = '';
+
+ if ( $Gateway == 1 ) {
+
+ # TEST MODE
+ if ( $QueryString =~ /ticket/ ) {
+ $QueryString =~ /ticket%3D([^&]+)/;
+ my $ST = $1;
+ my $User = $cas->validateST( $app_url, $ST );
+ return $User;
+ }
+
+ if ( $QueryString =~ /checked_cas/ ) {
+ return '';
+ }
+
+ my $login_url = $cas->getServerLoginGatewayURL( $app_url . '?checked_cas=1' );
+ my $q = CGI->new();
+ print $q->redirect( -URL => $login_url );
+ }
+ else {
+ $Self->Debug("Autenticando: " . $QueryString);
+
+ # If no ticket passed, redirect to CAS to authenticate/get token
+ unless ( $QueryString =~ /ticket=/ || $QueryString =~ /ticket%3D/ ) {
+ my $redurl = $app_url . "?" . $Param{RequestedURL};
+ $redurl = uri_escape($redurl);
+ my $login_url = $cas->getServerLoginURL( $redurl );
+ my $q = CGI->new();
+ print $q->redirect( -URL => $login_url );
+ }
+ else {
+ $Self->Debug("Recebida URL com ticket: " . $QueryString);
+
+ # CAS session created - record id
+ $QueryString =~ /ticket=([^&]+)/;
+ my $ST = $1;
+ if (! $ST) {
+ $QueryString =~ /ticket%3D([^&]+)/;
+ $ST = $1;
+ }
+
+ my $requrl = $Param{RequestedURL};
+ my $substring = substr($requrl, 0, index($requrl, "&ticket=ST"));
+
+ my $redurl = $app_url . "?" . $substring;
+ $redurl = uri_escape($redurl);
+
+ $Self->Debug("Validando URL $redurl com ticket $ST");
+ $User = $cas->validateST( $redurl, $ST );
+
+ $Self->Debug("Autenticou... $User");
+ if ($User) {
+ $Kernel::OM->Get("Kernel::System::DB")->Do(
+ SQL => 'DELETE FROM cas_session WHERE UserLogin=?',
+ Bind => [ \$User ],
+ );
+
+ $Kernel::OM->Get("Kernel::System::DB")->Do(
+ SQL => 'INSERT INTO cas_session (UserLogin,Ticket) VALUES (?, ?)',
+ Bind => [ \$User, \$ST, ],
+ );
+ }
+ }
+ }
+ return $User;
+}
+
+sub Debug {
+ my $Self = shift;
+ my $msg = shift;
+ $Kernel::OM->Get("Kernel::System::Log")->Log( Priority => 'debug', Message => $msg );
+}
+
+1;
diff --git a/Kernel/System/CustomerAuth/CAS.pm b/Kernel/System/CustomerAuth/CAS.pm
new file mode 100755
index 0000000..e03beff
--- /dev/null
+++ b/Kernel/System/CustomerAuth/CAS.pm
@@ -0,0 +1,154 @@
+# --
+# Kernel/System/CustomerAuth/CAS.pm - provides the CAS authentication through Jasig
+#
+# Copyright (C) 2015-2017 - Rodrigo Gonçalves - rodrigo@goncalves.pro.br
+# --
+# $Id: CAS.pm,v 2.0 2015/01/05 15:16:05 mb Exp $
+#
+# Version 2015/01/15 - RG - Adjusts for OTRS4
+# Version 2016-01-18 - RG - Fixes for OTRS 5.0.6
+# Version 2017-12-07 - RG - Fixes for OTRS 6.0.1
+#
+# --
+# 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.
+# --
+# Note:
+#
+# If you use this module, you should use as fallback the following config settings:
+#
+# If use isn't login through apache ($ENV{REMOTE_USER} or $ENV{HTTP_REMOTE_USER})
+# $Self->{CustomerPanelLoginURL} = 'http://host.example.com/not-authorised-for-otrs.html';
+#
+# $Self->{CustomerPanelLogoutURL} = 'http://host.example.com/thanks-for-using-otrs.html';
+#
+# --
+package Kernel::System::CustomerAuth::CAS;
+
+use strict;
+use warnings;
+use CGI;
+use AuthCAS;
+use Data::Dumper;
+use CGI::Carp qw( fatalsToBrowser );
+use URI::Escape;
+
+our @ObjectDependencies = ( "Kernel::Config", "Kernel::System::Log", "Kernel::System::DB" );
+
+sub new {
+ my ( $Type, %Param ) = @_;
+
+ # allocate new hash for object
+ my $Self = {};
+ bless( $Self, $Type );
+
+ # Debug 0=off 1=on
+ $Self->{Debug} = 0;
+ $Self->{Count} = $Param{Count} || '';
+
+ return $Self;
+}
+
+sub GetOption {
+ my ( $Self, %Param ) = @_;
+
+ # check needed stuff
+ if ( !$Param{What} ) {
+ $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need What!" );
+ return;
+ }
+
+ # module options
+ my %Option = ( PreAuth => 1, );
+
+ # return option
+ return $Option{ $Param{What} };
+}
+
+sub Auth {
+ my ( $Self, %Param ) = @_;
+
+ my $QueryString = $ENV{"HTTP_REFERER"} || '';
+
+ my $ConfigObject = $Kernel::OM->Get("Kernel::Config");
+
+ my $cas = new AuthCAS( casUrl => $ConfigObject->Get('Customer::AuthModule::CAS::CASUrl') );
+ my $app_url = $ConfigObject->Get('Customer::AuthModule::CAS::ServiceUrl');
+ my $Gateway = $ConfigObject->Get('Customer::AuthModule::CAS::Gateway');
+ my $User = '';
+
+ if ( $Gateway == 1 ) {
+
+ # TEST MODE
+ if ( $QueryString =~ /ticket/ ) {
+ $QueryString =~ /ticket%3D([^&]+)/;
+ my $ST = $1;
+ my $User = $cas->validateST( $app_url, $ST );
+ return $User;
+ }
+
+ if ( $QueryString =~ /checked_cas/ ) {
+ return '';
+ }
+
+ my $login_url = $cas->getServerLoginGatewayURL( $app_url . '?checked_cas=1' );
+ my $q = CGI->new();
+ print $q->redirect( -URL => $login_url );
+ }
+ else {
+ $Self->Debug("Autenticando: " . $QueryString);
+
+ # If no ticket passed, redirect to CAS to authenticate/get token
+ unless ( $QueryString =~ /ticket=/ || $QueryString =~ /ticket%3D/ ) {
+ my $redurl = $app_url . "?" . $Param{RequestedURL};
+ $redurl = uri_escape($redurl);
+ my $login_url = $cas->getServerLoginURL( $redurl );
+ my $q = CGI->new();
+ print $q->redirect( -URL => $login_url );
+ }
+ else {
+ $Self->Debug("Recebida URL com ticket: " . $QueryString);
+
+ # CAS session created - record id
+ $QueryString =~ /ticket=([^&]+)/;
+ my $ST = $1;
+ if (! $ST) {
+ $QueryString =~ /ticket%3D([^&]+)/;
+ $ST = $1;
+ }
+
+ my $requrl = $Param{RequestedURL};
+ my $substring = substr($requrl, 0, index($requrl, "&ticket=ST"));
+
+ my $redurl = $app_url . "?" . $substring;
+ $redurl = uri_escape($redurl);
+
+ $Self->Debug("Validando URL $redurl com ticket $ST");
+ $User = $cas->validateST( $redurl, $ST );
+
+ $Self->Debug("Autenticou... $User");
+ if ($User) {
+ $Kernel::OM->Get("Kernel::System::DB")->Do(
+ SQL => 'DELETE FROM cas_session WHERE UserLogin=?',
+ Bind => [ \$User ],
+ );
+
+ $Kernel::OM->Get("Kernel::System::DB")->Do(
+ SQL => 'INSERT INTO cas_session (UserLogin,Ticket) VALUES (?, ?)',
+ Bind => [ \$User, \$ST, ],
+ );
+ }
+ }
+ }
+
+ return $User;
+}
+
+sub Debug {
+ my $Self = shift;
+ my $msg = shift;
+ $Kernel::OM->Get("Kernel::System::Log")->Log( Priority => 'debug', Message => $msg );
+}
+
+1;
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..043351b
--- /dev/null
+++ b/README.md
@@ -0,0 +1,41 @@
+CAS Authentication (Jasig-based) for OTRS
+=========================================
+
+
+Required PERL Packages:
+-----------------------
+
+* AuthCAS (`apt install libauthcas-perl` on Ubuntu)
+
+
+Config required:
+----------------
+
+*Kernel/Config.pm:*
+
+ $Self->{'AuthModule'} = 'Kernel::System::Auth::CAS';
+ $Self->{'AuthModule::CAS::Gateway'} = 0;
+ $Self->{'AuthModule::CAS::ServiceUrl'} = 'URL FOR OTRS AGENT INDEX (ex: https://host.com/otrs/index.pl)';
+ $Self->{'AuthModule::CAS::CASUrl'} = 'URL FOR CAS SERVICE (WITHOUT TRAILING /) - ex: https://cas.systems.com';
+
+ $Self->{'Customer::AuthModule'} = 'Kernel::System::CustomerAuth::CAS';
+ $Self->{'Customer::AuthModule::CAS::Gateway'} = 0;
+ $Self->{'Customer::AuthModule::CAS::ServiceUrl'} = 'URL FOR OTRS CUSTOMER INDEX (ex: https://host.com/otrs/customer.pl)';
+ $Self->{'Customer::AuthModule::CAS::CASUrl'} = 'URL FOR CAS SERVICE (WITHOUT TRAILING /) - ex: https://cas.systems.com';
+
+
+Package building:
+-----------------
+
+To build the package, do the following:
+
+ cd dist
+ ./CreateOpm.sh
+
+The generated package will be on the same `dist` directory
+
+
+Issues:
+-------
+
+This module was developed in-house and thus is provided without warranty or support. If you have a problem, please open an issue on github.
\ No newline at end of file
diff --git a/dist/CreateOpm.sh b/dist/CreateOpm.sh
new file mode 100755
index 0000000..b427e07
--- /dev/null
+++ b/dist/CreateOpm.sh
@@ -0,0 +1,8 @@
+#!/bin/bash
+LOCAL="$PWD"
+
+echo Build package otrs-cas-authentication;
+echo Package will be generated on the current path...
+cd /opt/otrs
+bin/otrs.Console.pl Dev::Package::Build "$LOCAL"/../CASAuthentication.sopm "$LOCAL"/
+cd $LOCAL
\ No newline at end of file
--
libgit2 0.21.2