Commit 9c6523ef39f49340ca3efd6bd5ddd868473baed3

Authored by Rodrigo Goncalves
1 parent 023f8cd9
Exists in master

Support for OTRS 6.0.1

.gitignore 0 → 100644
... ... @@ -0,0 +1 @@
  1 +dist/*.opm
... ...
.includepath 0 → 100644
... ... @@ -0,0 +1,6 @@
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<includepath>
  3 + <includepathentry path="/opt/otrs/" />
  4 + <includepathentry path="/opt/otrs/Kernel/cpan-lib/" />
  5 +</includepath>
  6 +
... ...
.project 0 → 100644
... ... @@ -0,0 +1,18 @@
  1 +<?xml version="1.0" encoding="UTF-8"?>
  2 +<projectDescription>
  3 + <name>otrs-cas</name>
  4 + <comment></comment>
  5 + <projects>
  6 + <project>otrs</project>
  7 + </projects>
  8 + <buildSpec>
  9 + <buildCommand>
  10 + <name>org.epic.perleditor.perlbuilder</name>
  11 + <arguments>
  12 + </arguments>
  13 + </buildCommand>
  14 + </buildSpec>
  15 + <natures>
  16 + <nature>org.epic.perleditor.perlnature</nature>
  17 + </natures>
  18 +</projectDescription>
... ...
CASAuthentication.sopm 0 → 100755
... ... @@ -0,0 +1,56 @@
  1 +<?xml version="1.0" encoding="utf-8" ?>
  2 +<otrs_package version="1.0">
  3 + <Name>CASAuthentication</Name>
  4 + <Version>1.3.0</Version>
  5 + <Framework>6.0.1</Framework>
  6 + <Vendor>Rodrigo Gonçalves (rodrigo@goncalves.pro.br)</Vendor>
  7 + <URL>http://www.goncalves.pro.br/</URL>
  8 + <License>AGPL</License>
  9 +
  10 + <ChangeLog Version="1.0.0" Date="2014-06-01">First Version</ChangeLog>
  11 + <ChangeLog Version="1.1.0" Date="2014-01-05">Support for OTRS 4</ChangeLog>
  12 + <ChangeLog Version="1.1.0" Date="2014-01-05">Bug in customer authentication for OTRS 4</ChangeLog>
  13 + <ChangeLog Version="1.1.8" Date="2014-02-03">Support for users not in database (custom redirect)</ChangeLog>
  14 + <ChangeLog Version="1.1.9" Date="2015-11-16">Fix for authentication with redirect URL</ChangeLog>
  15 + <ChangeLog Version="1.2.0" Date="2016-01-18">Support for OTRS 5.0.x and fix for agent redirection on first link</ChangeLog>
  16 + <ChangeLog Version="1.2.0" Date="2017-12-14">Support for OTRS 6.0.1</ChangeLog>
  17 +
  18 + <Description>CAS Authentication (Jasig) Module</Description>
  19 +
  20 + <BuildDate>?</BuildDate>
  21 + <BuildHost>?</BuildHost>
  22 +
  23 + <IntroInstall Type="post" Title="Thank you"><![CDATA[
  24 + Module installed successfully!<BR/><BR/>
  25 +
  26 + In order to active the module, the following lines should be included/changed in Kernel/Config.pm:<BR/><BR/>
  27 +
  28 + $Self->{'AuthModule'} = 'Kernel::System::Auth::CAS';<BR/>
  29 + $Self->{'AuthModule::CAS::Gateway'} = 0;<BR/>
  30 + $Self->{'AuthModule::CAS::ServiceUrl'} = 'URL FOR OTRS AGENT INDEX (ex: https://host.com/otrs/index.pl)';<BR/>
  31 + $Self->{'AuthModule::CAS::CASUrl'} = 'URL FOR CAS SERVICE (WITHOUT TRAILING /) - ex: https://cas.systems.com';<BR/>
  32 +<BR/>
  33 + $Self->{'Customer::AuthModule'} = 'Kernel::System::CustomerAuth::CAS';<BR/>
  34 + $Self->{'Customer::AuthModule::CAS::Gateway'} = 0;<BR/>
  35 + $Self->{'Customer::AuthModule::CAS::ServiceUrl'} = 'URL FOR OTRS CUSTOMER INDEX (ex: https://host.com/otrs/customer.pl)';<BR/>
  36 + $Self->{'Customer::AuthModule::CAS::CASUrl'} = 'URL FOR CAS SERVICE (WITHOUT TRAILING /) - ex: https://cas.systems.com';<BR/>
  37 +
  38 + ]]></IntroInstall>
  39 +
  40 + <ModuleRequired>AuthCAS</ModuleRequired>
  41 +
  42 + <Filelist>
  43 + <File Permission="644" Location="Kernel/System/Auth/CAS.pm"></File>
  44 + <File Permission="644" Location="Kernel/System/CustomerAuth/CAS.pm"></File>
  45 + <File Permission="644" Location="Custom/Kernel/System/Web/InterfaceAgent.pm"></File>
  46 + <File Permission="644" Location="Custom/Kernel/System/Web/InterfaceCustomer.pm"></File>
  47 + <File Permission="644" Location="Custom/Kernel/System/Web/Request.pm"></File>
  48 + </Filelist>
  49 +
  50 + <DatabaseInstall>
  51 + <TableCreate Name="cas_session">
  52 + <Column Name="UserLogin" Required="true" Size="100" Type="VARCHAR" />
  53 + <Column Name="Ticket" Required="true" Size="250" Type="VARCHAR" />
  54 + </TableCreate>
  55 + </DatabaseInstall>
  56 +</otrs_package>
... ...
Custom/Kernel/System/Web/InterfaceAgent.pm 0 → 100644
... ... @@ -0,0 +1,1242 @@
  1 +# --
  2 +# Copyright (C) 2001-2017 OTRS AG, http://otrs.com/
  3 +# --
  4 +# This software comes with ABSOLUTELY NO WARRANTY. For details, see
  5 +# the enclosed file COPYING for license information (AGPL). If you
  6 +# did not receive this file, see http://www.gnu.org/licenses/agpl.txt.
  7 +#
  8 +#
  9 +# Custom version for CAS authentication - rodrigo@goncalves.pro.br
  10 +#
  11 +# Version 18/01/2016 - RG - Version for OTRS 5.0.6
  12 +# Version 2017-12-07 - RG - Version for OTRS 6.0.1
  13 +#
  14 +# --
  15 +
  16 +package Kernel::System::Web::InterfaceAgent;
  17 +
  18 +use strict;
  19 +use warnings;
  20 +
  21 +# CAS Custom
  22 +use CGI;
  23 +use URI::Escape;
  24 +# CAS Custom
  25 +
  26 +use Kernel::Language qw(Translatable);
  27 +use Kernel::System::DateTime;
  28 +
  29 +our @ObjectDependencies = (
  30 + 'Kernel::Config',
  31 + 'Kernel::Output::HTML::Layout',
  32 + 'Kernel::System::Auth',
  33 + 'Kernel::System::AuthSession',
  34 + 'Kernel::System::DB',
  35 + 'Kernel::System::Email',
  36 + 'Kernel::System::Group',
  37 + 'Kernel::System::Log',
  38 + 'Kernel::System::Main',
  39 + 'Kernel::System::Scheduler',
  40 + 'Kernel::System::DateTime',
  41 + 'Kernel::System::User',
  42 + 'Kernel::System::Web::Request',
  43 + 'Kernel::System::Valid',
  44 +);
  45 +
  46 +=head1 NAME
  47 +
  48 +Kernel::System::Web::InterfaceAgent - the agent web interface
  49 +
  50 +=head1 DESCRIPTION
  51 +
  52 +the global agent web interface (authentication, session handling, ...)
  53 +
  54 +=head1 PUBLIC INTERFACE
  55 +
  56 +=head2 new()
  57 +
  58 +create agent web interface object. Do not use it directly, instead use:
  59 +
  60 + use Kernel::System::ObjectManager;
  61 + my $Debug = 0,
  62 + local $Kernel::OM = Kernel::System::ObjectManager->new(
  63 + 'Kernel::System::Web::InterfaceAgent' => {
  64 + Debug => 0,
  65 + WebRequest => CGI::Fast->new(), # optional, e. g. if fast cgi is used,
  66 + # the CGI object is already provided
  67 + }
  68 + );
  69 + my $InterfaceAgent = $Kernel::OM->Get('Kernel::System::Web::InterfaceAgent');
  70 +
  71 +=cut
  72 +
  73 +sub new {
  74 + my ( $Type, %Param ) = @_;
  75 + my $Self = {};
  76 + bless( $Self, $Type );
  77 +
  78 + # Performance log
  79 + $Self->{PerformanceLogStart} = time();
  80 +
  81 + # get debug level
  82 + $Self->{Debug} = $Param{Debug} || 0;
  83 +
  84 + $Kernel::OM->ObjectParamAdd(
  85 + 'Kernel::System::Log' => {
  86 + LogPrefix => $Kernel::OM->Get('Kernel::Config')->Get('CGILogPrefix'),
  87 + },
  88 + 'Kernel::System::Web::Request' => {
  89 + WebRequest => $Param{WebRequest} || 0,
  90 + },
  91 + );
  92 +
  93 + # debug info
  94 + if ( $Self->{Debug} ) {
  95 + $Kernel::OM->Get('Kernel::System::Log')->Log(
  96 + Priority => 'debug',
  97 + Message => 'Global handle started...',
  98 + );
  99 + }
  100 +
  101 + return $Self;
  102 +}
  103 +
  104 +=head2 Run()
  105 +
  106 +execute the object
  107 +
  108 + $InterfaceAgent->Run();
  109 +
  110 +=cut
  111 +
  112 +sub Run {
  113 + my $Self = shift;
  114 +
  115 + # CAS Custom
  116 + if ($Self->CASLogout()) {
  117 + return;
  118 + }
  119 + # CAS Custom
  120 +
  121 + my $ConfigObject = $Kernel::OM->Get('Kernel::Config');
  122 +
  123 + my $QueryString = $ENV{QUERY_STRING} || '';
  124 +
  125 + # Check if https forcing is active, and redirect if needed.
  126 + if ( $ConfigObject->Get('HTTPSForceRedirect') ) {
  127 +
  128 + # Some web servers do not set HTTPS environment variable, so it's not possible to easily know if we are using
  129 + # https protocol. Look also for similarly named keys in environment hash, since this should prevent loops in
  130 + # certain cases.
  131 + if (
  132 + (
  133 + !defined $ENV{HTTPS}
  134 + && !grep {/^HTTPS(?:_|$)/} keys %ENV
  135 + )
  136 + || $ENV{HTTPS} ne 'on'
  137 + )
  138 + {
  139 + my $Host = $ENV{HTTP_HOST} || $ConfigObject->Get('FQDN');
  140 +
  141 + # Redirect with 301 code. Add two new lines at the end, so HTTP headers are validated correctly.
  142 + print "Status: 301 Moved Permanently\nLocation: https://$Host$ENV{REQUEST_URI}\n\n";
  143 + return;
  144 + }
  145 + }
  146 +
  147 + my $ParamObject = $Kernel::OM->Get('Kernel::System::Web::Request');
  148 +
  149 + my %Param;
  150 +
  151 + # get session id
  152 + $Param{SessionName} = $ConfigObject->Get('SessionName') || 'SessionID';
  153 + $Param{SessionID} = $ParamObject->GetParam( Param => $Param{SessionName} ) || '';
  154 +
  155 + # drop old session id (if exists)
  156 + $QueryString =~ s/(\?|&|;|)$Param{SessionName}(=&|=;|=.+?&|=.+?$)/;/g;
  157 +
  158 + # define framework params
  159 + my $FrameworkParams = {
  160 + Lang => '',
  161 + Action => '',
  162 + Subaction => '',
  163 + RequestedURL => $QueryString,
  164 + };
  165 + for my $Key ( sort keys %{$FrameworkParams} ) {
  166 + $Param{$Key} = $ParamObject->GetParam( Param => $Key )
  167 + || $FrameworkParams->{$Key};
  168 + }
  169 +
  170 + # validate language
  171 + if ( $Param{Lang} && $Param{Lang} !~ m{\A[a-z]{2}(?:_[A-Z]{2})?\z}xms ) {
  172 + delete $Param{Lang};
  173 + }
  174 +
  175 + # check if the browser sends the SessionID cookie and set the SessionID-cookie
  176 + # as SessionID! GET or POST SessionID have the lowest priority.
  177 + my $BrowserHasCookie = 0;
  178 + if ( $ConfigObject->Get('SessionUseCookie') ) {
  179 + $Param{SessionIDCookie} = $ParamObject->GetCookie( Key => $Param{SessionName} );
  180 + if ( $Param{SessionIDCookie} ) {
  181 + $Param{SessionID} = $Param{SessionIDCookie};
  182 + }
  183 + }
  184 +
  185 + $Kernel::OM->ObjectParamAdd(
  186 + 'Kernel::Output::HTML::Layout' => {
  187 + Lang => $Param{Lang},
  188 + UserLanguage => $Param{Lang},
  189 + },
  190 + 'Kernel::Language' => {
  191 + UserLanguage => $Param{Lang}
  192 + },
  193 + );
  194 +
  195 + my $CookieSecureAttribute;
  196 + if ( $ConfigObject->Get('HttpType') eq 'https' ) {
  197 +
  198 + # Restrict Cookie to HTTPS if it is used.
  199 + $CookieSecureAttribute = 1;
  200 + }
  201 +
  202 + my $DBCanConnect = $Kernel::OM->Get('Kernel::System::DB')->Connect();
  203 +
  204 + if ( !$DBCanConnect || $ParamObject->Error() ) {
  205 + my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
  206 + if ( !$DBCanConnect ) {
  207 + $LayoutObject->FatalError(
  208 + Comment => Translatable('Please contact the administrator.'),
  209 + );
  210 + return;
  211 + }
  212 + if ( $ParamObject->Error() ) {
  213 + $LayoutObject->FatalError(
  214 + Message => $ParamObject->Error(),
  215 + Comment => Translatable('Please contact the administrator.'),
  216 + );
  217 + return;
  218 + }
  219 + }
  220 +
  221 + # get common application and add-on application params
  222 + my %CommonObjectParam = %{ $ConfigObject->Get('Frontend::CommonParam') };
  223 + for my $Key ( sort keys %CommonObjectParam ) {
  224 + $Param{$Key} = $ParamObject->GetParam( Param => $Key ) || $CommonObjectParam{$Key};
  225 + }
  226 +
  227 + # security check Action Param (replace non word chars)
  228 + $Param{Action} =~ s/\W//g;
  229 +
  230 + my $SessionObject = $Kernel::OM->Get('Kernel::System::AuthSession');
  231 + my $UserObject = $Kernel::OM->Get('Kernel::System::User');
  232 +
  233 + # check request type
  234 + if ( $Param{Action} eq 'PreLogin' ) {
  235 + my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
  236 + $Param{RequestedURL} = $Param{RequestedURL} || "Action=AgentDashboard";
  237 +
  238 + # login screen
  239 + $LayoutObject->Print(
  240 + Output => \$LayoutObject->Login(
  241 + Title => 'Login',
  242 + Mode => 'PreLogin',
  243 + %Param,
  244 + ),
  245 + );
  246 +
  247 + return;
  248 + }
  249 + elsif ( $Param{Action} eq 'Login' ) {
  250 +
  251 + # get params
  252 + my $PostUser = $ParamObject->GetParam( Param => 'User' ) || '';
  253 + my $PostPw = $ParamObject->GetParam(
  254 + Param => 'Password',
  255 + Raw => 1
  256 + ) || '';
  257 + my $PostTwoFactorToken = $ParamObject->GetParam(
  258 + Param => 'TwoFactorToken',
  259 + Raw => 1
  260 + ) || '';
  261 +
  262 + # create AuthObject
  263 + my $AuthObject = $Kernel::OM->Get('Kernel::System::Auth');
  264 +
  265 + # check submitted data
  266 + my $User = $AuthObject->Auth(
  267 + User => $PostUser,
  268 + Pw => $PostPw,
  269 + TwoFactorToken => $PostTwoFactorToken,
  270 + RequestedURL => $Param{RequestedURL},
  271 + );
  272 +
  273 + # login is invalid
  274 + if ( !$User ) {
  275 +
  276 + # CAS Custom
  277 + # Fixes OTRS Layout bug when redirecting
  278 + my $cgi = new CGI();
  279 + print $cgi->redirect( -URL => $ConfigObject->Get("AuthModule::CAS::CASUrl") . "/login?service=" . $ConfigObject->Get("AuthModule::CAS::ServiceUrl") . "?" . $Param{RequestedURL});
  280 + return;
  281 + # CAS Custom
  282 +
  283 + my $Expires = '+' . $ConfigObject->Get('SessionMaxTime') . 's';
  284 + if ( !$ConfigObject->Get('SessionUseCookieAfterBrowserClose') ) {
  285 + $Expires = '';
  286 + }
  287 +
  288 + $Kernel::OM->ObjectParamAdd(
  289 + 'Kernel::Output::HTML::Layout' => {
  290 + SetCookies => {
  291 + OTRSBrowserHasCookie => $ParamObject->SetCookie(
  292 + Key => 'OTRSBrowserHasCookie',
  293 + Value => 1,
  294 + Expires => $Expires,
  295 + Path => $ConfigObject->Get('ScriptAlias'),
  296 + Secure => $CookieSecureAttribute,
  297 + HTTPOnly => 1,
  298 + ),
  299 + },
  300 + }
  301 + );
  302 + my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
  303 +
  304 + # redirect to alternate login
  305 + if ( $ConfigObject->Get('LoginURL') ) {
  306 + $Param{RequestedURL} = $LayoutObject->LinkEncode( $Param{RequestedURL} );
  307 + print $LayoutObject->Redirect(
  308 + ExtURL => $ConfigObject->Get('LoginURL')
  309 + . "?Reason=LoginFailed&RequestedURL=$Param{RequestedURL}",
  310 + );
  311 + return;
  312 + }
  313 +
  314 + # show normal login
  315 + $LayoutObject->Print(
  316 + Output => \$LayoutObject->Login(
  317 + Title => 'Login',
  318 + Message => $Kernel::OM->Get('Kernel::System::Log')->GetLogEntry(
  319 + Type => 'Info',
  320 + What => 'Message',
  321 + )
  322 + || $LayoutObject->{LanguageObject}->Translate( $AuthObject->GetLastErrorMessage() )
  323 + || Translatable('Login failed! Your user name or password was entered incorrectly.'),
  324 + LoginFailed => 1,
  325 + MessageType => 'Error',
  326 + User => $User,
  327 + %Param,
  328 + ),
  329 + );
  330 + return;
  331 + }
  332 +
  333 + # login is successful
  334 + my %UserData = $UserObject->GetUserData(
  335 + User => $User,
  336 + Valid => 1
  337 + );
  338 +
  339 + # check if the browser supports cookies
  340 + if ( $ParamObject->GetCookie( Key => 'OTRSBrowserHasCookie' ) ) {
  341 + $Kernel::OM->ObjectParamAdd(
  342 + 'Kernel::Output::HTML::Layout' => {
  343 + BrowserHasCookie => 1,
  344 + },
  345 + );
  346 + }
  347 +
  348 + # check needed data
  349 + if ( !$UserData{UserID} || !$UserData{UserLogin} ) {
  350 +
  351 + # redirect to alternate login
  352 + if ( $ConfigObject->Get('LoginURL') ) {
  353 + print $Kernel::OM->Get('Kernel::Output::HTML::Layout')->Redirect(
  354 + ExtURL => $ConfigObject->Get('LoginURL') . '?Reason=SystemError',
  355 + );
  356 + return;
  357 + }
  358 +
  359 + my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
  360 +
  361 + # show need user data error message
  362 + $LayoutObject->Print(
  363 + Output => \$LayoutObject->Login(
  364 + Title => 'Error',
  365 + Message =>
  366 + Translatable(
  367 + 'Authentication succeeded, but no user data record is found in the database. Please contact the administrator.'
  368 + ),
  369 + %Param,
  370 + MessageType => 'Error',
  371 + ),
  372 + );
  373 + return;
  374 + }
  375 +
  376 + my $DateTimeObj = $Kernel::OM->Create('Kernel::System::DateTime');
  377 +
  378 + # create new session id
  379 + my $NewSessionID = $SessionObject->CreateSessionID(
  380 + %UserData,
  381 + UserLastRequest => $DateTimeObj->ToEpoch(),
  382 + UserType => 'User',
  383 + SessionSource => 'AgentInterface',
  384 + );
  385 +
  386 + # show error message if no session id has been created
  387 + if ( !$NewSessionID ) {
  388 +
  389 + # get error message
  390 + my $Error = $SessionObject->SessionIDErrorMessage() || '';
  391 +
  392 + # output error message
  393 + my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
  394 + $LayoutObject->Print(
  395 + Output => \$LayoutObject->Login(
  396 + Title => 'Login',
  397 + Message => $Error,
  398 + MessageType => 'Error',
  399 + %Param,
  400 + ),
  401 + );
  402 + return;
  403 + }
  404 +
  405 + # execution in 20 seconds
  406 + my $ExecutionTimeObj = $DateTimeObj->Clone();
  407 + $ExecutionTimeObj->Add( Seconds => 20 );
  408 + my $ExecutionTime = $ExecutionTimeObj->ToString();
  409 +
  410 + # add a asychronous executor scheduler task to count the concurrent user
  411 + $Kernel::OM->Get('Kernel::System::Scheduler')->TaskAdd(
  412 + ExecutionTime => $ExecutionTime,
  413 + Type => 'AsynchronousExecutor',
  414 + Name => 'PluginAsynchronous::ConcurrentUser',
  415 + MaximumParallelInstances => 1,
  416 + Data => {
  417 + Object => 'Kernel::System::SupportDataCollector::PluginAsynchronous::OTRS::ConcurrentUsers',
  418 + Function => 'RunAsynchronous',
  419 + },
  420 + );
  421 +
  422 + # get time zone
  423 + my $UserTimeZone = $UserData{UserTimeZone} || Kernel::System::DateTime->UserDefaultTimeZoneGet();
  424 + $SessionObject->UpdateSessionID(
  425 + SessionID => $NewSessionID,
  426 + Key => 'UserTimeZone',
  427 + Value => $UserTimeZone,
  428 + );
  429 +
  430 + # check if the time zone offset reported by the user's browser differs from that
  431 + # of the OTRS user's time zone offset
  432 + my $DateTimeObject = $Kernel::OM->Create(
  433 + 'Kernel::System::DateTime',
  434 + ObjectParams => {
  435 + TimeZone => $UserTimeZone,
  436 + },
  437 + );
  438 + my $OTRSUserTimeZoneOffset = $DateTimeObject->Format( Format => '%{offset}' ) / 60;
  439 + my $BrowserTimeZoneOffset = ( $ParamObject->GetParam( Param => 'TimeZoneOffset' ) || 0 ) * -1;
  440 +
  441 + # TimeZoneOffsetDifference contains the difference of the time zone offset between
  442 + # the user's OTRS time zone setting and the one reported by the user's browser.
  443 + # If there is a difference it can be evaluated later to e. g. show a message
  444 + # for the user to check his OTRS time zone setting.
  445 + my $UserTimeZoneOffsetDifference = abs( $OTRSUserTimeZoneOffset - $BrowserTimeZoneOffset );
  446 + $SessionObject->UpdateSessionID(
  447 + SessionID => $NewSessionID,
  448 + Key => 'UserTimeZoneOffsetDifference',
  449 + Value => $UserTimeZoneOffsetDifference,
  450 + );
  451 +
  452 + # create a new LayoutObject with SessionIDCookie
  453 + my $Expires = '+' . $ConfigObject->Get('SessionMaxTime') . 's';
  454 + if ( !$ConfigObject->Get('SessionUseCookieAfterBrowserClose') ) {
  455 + $Expires = '';
  456 + }
  457 +
  458 + my $SecureAttribute;
  459 + if ( $ConfigObject->Get('HttpType') eq 'https' ) {
  460 +
  461 + # Restrict Cookie to HTTPS if it is used.
  462 + $SecureAttribute = 1;
  463 + }
  464 +
  465 + $Kernel::OM->ObjectParamAdd(
  466 + 'Kernel::Output::HTML::Layout' => {
  467 + SetCookies => {
  468 + SessionIDCookie => $ParamObject->SetCookie(
  469 + Key => $Param{SessionName},
  470 + Value => $NewSessionID,
  471 + Expires => $Expires,
  472 + Path => $ConfigObject->Get('ScriptAlias'),
  473 + Secure => scalar $CookieSecureAttribute,
  474 + HTTPOnly => 1,
  475 + ),
  476 + OTRSBrowserHasCookie => $ParamObject->SetCookie(
  477 + Key => 'OTRSBrowserHasCookie',
  478 + Value => '',
  479 + Expires => '-1y',
  480 + Path => $ConfigObject->Get('ScriptAlias'),
  481 + Secure => $CookieSecureAttribute,
  482 + HTTPOnly => 1,
  483 + ),
  484 + },
  485 + SessionID => $NewSessionID,
  486 + SessionName => $Param{SessionName},
  487 + },
  488 + );
  489 +
  490 + # Check if Chat is active
  491 + if ( $Kernel::OM->Get('Kernel::Config')->Get('ChatEngine::Active') ) {
  492 + my $ChatReceivingAgentsGroup
  493 + = $Kernel::OM->Get('Kernel::Config')->Get('ChatEngine::PermissionGroup::ChatReceivingAgents');
  494 +
  495 + my $ChatReceivingAgentsGroupPermission = $Kernel::OM->Get('Kernel::System::Group')->PermissionCheck(
  496 + UserID => $UserData{UserID},
  497 + GroupName => $ChatReceivingAgentsGroup,
  498 + Type => 'rw',
  499 + );
  500 +
  501 + if (
  502 + $UserData{UserID} != -1
  503 + && $ChatReceivingAgentsGroup
  504 + && $ChatReceivingAgentsGroupPermission
  505 + && $Kernel::OM->Get('Kernel::Config')->Get('Ticket::Agent::UnavailableForExternalChatsOnLogin')
  506 + )
  507 + {
  508 + # Get user preferences
  509 + my %Preferences = $Kernel::OM->Get('Kernel::System::User')->GetPreferences(
  510 + UserID => $UserData{UserID},
  511 + );
  512 +
  513 + if ( $Preferences{ChatAvailability} && $Preferences{ChatAvailability} == 2 ) {
  514 +
  515 + # User is available for external chats. Set his availability to internal only.
  516 + $Kernel::OM->Get('Kernel::System::User')->SetPreferences(
  517 + Key => 'ChatAvailability',
  518 + Value => '1',
  519 + UserID => $UserData{UserID},
  520 + );
  521 +
  522 + # Set ChatAvailabilityNotification to display notification in agent interface (only once)
  523 + $Kernel::OM->Get('Kernel::System::User')->SetPreferences(
  524 + Key => 'ChatAvailabilityNotification',
  525 + Value => '1',
  526 + UserID => $UserData{UserID},
  527 + );
  528 + }
  529 + }
  530 + }
  531 +
  532 + # redirect with new session id and old params
  533 + # prepare old redirect URL -- do not redirect to Login or Logout (loop)!
  534 + if ( $Param{RequestedURL} =~ /Action=(Logout|Login|LostPassword|PreLogin)/ ) {
  535 + $Param{RequestedURL} = '';
  536 + }
  537 +
  538 + # redirect with new session id
  539 + print $Kernel::OM->Get('Kernel::Output::HTML::Layout')->Redirect(
  540 + OP => $Param{RequestedURL},
  541 + Login => 1,
  542 + );
  543 + return 1;
  544 + }
  545 +
  546 + # logout
  547 + elsif ( $Param{Action} eq 'Logout' ) {
  548 +
  549 + my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
  550 +
  551 + # check session id
  552 + if ( !$SessionObject->CheckSessionID( SessionID => $Param{SessionID} ) ) {
  553 +
  554 + # redirect to alternate login
  555 + if ( $ConfigObject->Get('LoginURL') ) {
  556 + $Param{RequestedURL} = $LayoutObject->LinkEncode( $Param{RequestedURL} );
  557 + print $LayoutObject->Redirect(
  558 + ExtURL => $ConfigObject->Get('LoginURL')
  559 + . "?Reason=InvalidSessionID&RequestedURL=$Param{RequestedURL}",
  560 + );
  561 + return;
  562 + }
  563 +
  564 + # show login screen
  565 + $LayoutObject->Print(
  566 + Output => \$LayoutObject->Login(
  567 + Title => 'Logout',
  568 + %Param,
  569 + ),
  570 + );
  571 + return;
  572 + }
  573 +
  574 + # get session data
  575 + my %UserData = $SessionObject->GetSessionIDData(
  576 + SessionID => $Param{SessionID},
  577 + );
  578 +
  579 + # create a new LayoutObject with %UserData
  580 + $Kernel::OM->ObjectParamAdd(
  581 + 'Kernel::Output::HTML::Layout' => {
  582 + SetCookies => {
  583 + SessionIDCookie => $ParamObject->SetCookie(
  584 + Key => $Param{SessionName},
  585 + Value => '',
  586 + Expires => '-1y',
  587 + Path => $ConfigObject->Get('ScriptAlias'),
  588 + Secure => scalar $CookieSecureAttribute,
  589 + HTTPOnly => 1,
  590 + ),
  591 + },
  592 + %UserData,
  593 + },
  594 + );
  595 + $Kernel::OM->ObjectsDiscard( Objects => ['Kernel::Output::HTML::Layout'] );
  596 + $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
  597 +
  598 + # Prevent CSRF attacks
  599 + $LayoutObject->ChallengeTokenCheck();
  600 +
  601 + # remove session id
  602 + if ( !$SessionObject->RemoveSessionID( SessionID => $Param{SessionID} ) ) {
  603 + $LayoutObject->FatalError(
  604 + Message => Translatable('Can`t remove SessionID.'),
  605 + Comment => Translatable('Please contact the administrator.'),
  606 + );
  607 + return;
  608 + }
  609 +
  610 + # redirect to alternate login
  611 + if ( $ConfigObject->Get('LogoutURL') ) {
  612 + print $LayoutObject->Redirect(
  613 + ExtURL => $ConfigObject->Get('LogoutURL') . "?Reason=Logout",
  614 + );
  615 + return 1;
  616 + }
  617 +
  618 + # show logout screen
  619 + my $LogoutMessage = $LayoutObject->{LanguageObject}->Translate('Logout successful.');
  620 +
  621 + $LayoutObject->Print(
  622 + Output => \$LayoutObject->Login(
  623 + Title => 'Logout',
  624 + Message => $LogoutMessage,
  625 + MessageType => 'Success',
  626 + %Param,
  627 + ),
  628 + );
  629 + return 1;
  630 + }
  631 +
  632 + # user lost password
  633 + elsif ( $Param{Action} eq 'LostPassword' ) {
  634 +
  635 + my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
  636 +
  637 + # check feature
  638 + if ( !$ConfigObject->Get('LostPassword') ) {
  639 +
  640 + # show normal login
  641 + $LayoutObject->Print(
  642 + Output => \$LayoutObject->Login(
  643 + Title => 'Login',
  644 + Message => Translatable('Feature not active!'),
  645 + MessageType => 'Error',
  646 + ),
  647 + );
  648 + return;
  649 + }
  650 +
  651 + # get params
  652 + my $User = $ParamObject->GetParam( Param => 'User' ) || '';
  653 + my $Token = $ParamObject->GetParam( Param => 'Token' ) || '';
  654 +
  655 + # get user login by token
  656 + if ( !$User && $Token ) {
  657 + my %UserList = $UserObject->SearchPreferences(
  658 + Key => 'UserToken',
  659 + Value => $Token,
  660 + );
  661 + USERS:
  662 + for my $UserID ( sort keys %UserList ) {
  663 + my %UserData = $UserObject->GetUserData(
  664 + UserID => $UserID,
  665 + Valid => 1,
  666 + );
  667 + if (%UserData) {
  668 + $User = $UserData{UserLogin};
  669 + last USERS;
  670 + }
  671 + }
  672 + }
  673 +
  674 + # get user data
  675 + my %UserData = $UserObject->GetUserData(
  676 + User => $User,
  677 + Valid => 1
  678 + );
  679 +
  680 + # verify user is valid when requesting password reset
  681 + my @ValidIDs = $Kernel::OM->Get('Kernel::System::Valid')->ValidIDsGet();
  682 + my $UserIsValid = grep { $UserData{ValidID} && $UserData{ValidID} == $_ } @ValidIDs;
  683 + if ( !$UserData{UserID} || !$UserIsValid ) {
  684 +
  685 + # Security: pretend that password reset instructions were actually sent to
  686 + # make sure that users cannot find out valid usernames by
  687 + # just trying and checking the result message.
  688 + $LayoutObject->Print(
  689 + Output => \$LayoutObject->Login(
  690 + Title => 'Login',
  691 + Message => Translatable('Sent password reset instructions. Please check your email.'),
  692 + MessageType => 'Success',
  693 + %Param,
  694 + ),
  695 + );
  696 + return;
  697 + }
  698 +
  699 + # create email object
  700 + my $EmailObject = $Kernel::OM->Get('Kernel::System::Email');
  701 +
  702 + # send password reset token
  703 + if ( !$Token ) {
  704 +
  705 + # generate token
  706 + $UserData{Token} = $UserObject->TokenGenerate(
  707 + UserID => $UserData{UserID},
  708 + );
  709 +
  710 + # send token notify email with link
  711 + my $Body = $ConfigObject->Get('NotificationBodyLostPasswordToken')
  712 + || 'ERROR: NotificationBodyLostPasswordToken is missing!';
  713 + my $Subject = $ConfigObject->Get('NotificationSubjectLostPasswordToken')
  714 + || 'ERROR: NotificationSubjectLostPasswordToken is missing!';
  715 + for ( sort keys %UserData ) {
  716 + $Body =~ s/<OTRS_$_>/$UserData{$_}/gi;
  717 + }
  718 + my $Sent = $EmailObject->Send(
  719 + To => $UserData{UserEmail},
  720 + Subject => $Subject,
  721 + Charset => $LayoutObject->{UserCharset},
  722 + MimeType => 'text/plain',
  723 + Body => $Body
  724 + );
  725 + if ( !$Sent->{Success} ) {
  726 + $LayoutObject->FatalError(
  727 + Comment => Translatable('Please contact the administrator.'),
  728 + );
  729 + return;
  730 + }
  731 + $LayoutObject->Print(
  732 + Output => \$LayoutObject->Login(
  733 + Title => 'Login',
  734 + Message => Translatable('Sent password reset instructions. Please check your email.'),
  735 + MessageType => 'Success',
  736 + %Param,
  737 + ),
  738 + );
  739 + return 1;
  740 + }
  741 +
  742 + # reset password
  743 + # check if token is valid
  744 + my $TokenValid = $UserObject->TokenCheck(
  745 + Token => $Token,
  746 + UserID => $UserData{UserID},
  747 + );
  748 + if ( !$TokenValid ) {
  749 + $LayoutObject->Print(
  750 + Output => \$LayoutObject->Login(
  751 + Title => 'Login',
  752 + Message => Translatable('Invalid Token!'),
  753 + MessageType => 'Error',
  754 + %Param,
  755 + ),
  756 + );
  757 + return;
  758 + }
  759 +
  760 + # get new password
  761 + $UserData{NewPW} = $UserObject->GenerateRandomPassword();
  762 +
  763 + # update new password
  764 + $UserObject->SetPassword(
  765 + UserLogin => $User,
  766 + PW => $UserData{NewPW}
  767 + );
  768 +
  769 + # send notify email
  770 + my $Body = $ConfigObject->Get('NotificationBodyLostPassword')
  771 + || 'New Password is: <OTRS_NEWPW>';
  772 + my $Subject = $ConfigObject->Get('NotificationSubjectLostPassword')
  773 + || 'New Password!';
  774 + for ( sort keys %UserData ) {
  775 + $Body =~ s/<OTRS_$_>/$UserData{$_}/gi;
  776 + }
  777 + my $Sent = $EmailObject->Send(
  778 + To => $UserData{UserEmail},
  779 + Subject => $Subject,
  780 + Charset => $LayoutObject->{UserCharset},
  781 + MimeType => 'text/plain',
  782 + Body => $Body
  783 + );
  784 +
  785 + if ( !$Sent->{Success} ) {
  786 + $LayoutObject->FatalError(
  787 + Comment => Translatable('Please contact the administrator.'),
  788 + );
  789 + return;
  790 + }
  791 + my $Message = $LayoutObject->{LanguageObject}->Translate(
  792 + 'Sent new password to %s. Please check your email.',
  793 + $UserData{UserEmail},
  794 + );
  795 + $LayoutObject->Print(
  796 + Output => \$LayoutObject->Login(
  797 + Title => 'Login',
  798 + Message => $Message,
  799 + User => $User,
  800 + MessageType => 'Success',
  801 + %Param,
  802 + ),
  803 + );
  804 + return 1;
  805 + }
  806 +
  807 + # show login site
  808 + elsif ( !$Param{SessionID} ) {
  809 +
  810 + # create AuthObject
  811 + my $AuthObject = $Kernel::OM->Get('Kernel::System::Auth');
  812 + my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
  813 + if ( $AuthObject->GetOption( What => 'PreAuth' ) ) {
  814 +
  815 + # automatic login
  816 + $Param{RequestedURL} = $LayoutObject->LinkEncode( $Param{RequestedURL} );
  817 + print $LayoutObject->Redirect(
  818 + OP => "Action=PreLogin&RequestedURL=$Param{RequestedURL}",
  819 + );
  820 + return;
  821 + }
  822 + elsif ( $ConfigObject->Get('LoginURL') ) {
  823 +
  824 + # redirect to alternate login
  825 + $Param{RequestedURL} = $LayoutObject->LinkEncode( $Param{RequestedURL} );
  826 + print $LayoutObject->Redirect(
  827 + ExtURL => $ConfigObject->Get('LoginURL')
  828 + . "?RequestedURL=$Param{RequestedURL}",
  829 + );
  830 + return;
  831 + }
  832 +
  833 + # login screen
  834 + $LayoutObject->Print(
  835 + Output => \$LayoutObject->Login(
  836 + Title => 'Login',
  837 + %Param,
  838 + ),
  839 + );
  840 + return;
  841 + }
  842 +
  843 + # run modules if a version value exists
  844 + elsif ( $Kernel::OM->Get('Kernel::System::Main')->Require("Kernel::Modules::$Param{Action}") ) {
  845 +
  846 + # check session id
  847 + if ( !$SessionObject->CheckSessionID( SessionID => $Param{SessionID} ) ) {
  848 +
  849 + # put '%Param' into LayoutObject
  850 + $Kernel::OM->ObjectParamAdd(
  851 + 'Kernel::Output::HTML::Layout' => {
  852 + SetCookies => {
  853 + SessionIDCookie => $ParamObject->SetCookie(
  854 + Key => $Param{SessionName},
  855 + Value => '',
  856 + Expires => '-1y',
  857 + Path => $ConfigObject->Get('ScriptAlias'),
  858 + Secure => scalar $CookieSecureAttribute,
  859 + HTTPOnly => 1,
  860 + ),
  861 + },
  862 + %Param,
  863 + },
  864 + );
  865 +
  866 + $Kernel::OM->ObjectsDiscard( Objects => ['Kernel::Output::HTML::Layout'] );
  867 + my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
  868 +
  869 + # create AuthObject
  870 + my $AuthObject = $Kernel::OM->Get('Kernel::System::Auth');
  871 + if ( $AuthObject->GetOption( What => 'PreAuth' ) ) {
  872 +
  873 + # automatic re-login
  874 + $Param{RequestedURL} = $LayoutObject->LinkEncode( $Param{RequestedURL} );
  875 + print $LayoutObject->Redirect(
  876 + OP => "?Action=PreLogin&RequestedURL=$Param{RequestedURL}",
  877 + );
  878 + return;
  879 + }
  880 + elsif ( $ConfigObject->Get('LoginURL') ) {
  881 +
  882 + # redirect to alternate login
  883 + $Param{RequestedURL} = $LayoutObject->LinkEncode( $Param{RequestedURL} );
  884 + print $LayoutObject->Redirect(
  885 + ExtURL => $ConfigObject->Get('LoginURL')
  886 + . "?Reason=InvalidSessionID&RequestedURL=$Param{RequestedURL}",
  887 + );
  888 + return;
  889 + }
  890 +
  891 + # show login
  892 + $LayoutObject->Print(
  893 + Output => \$LayoutObject->Login(
  894 + Title => 'Login',
  895 + Message =>
  896 + $LayoutObject->{LanguageObject}->Translate( $SessionObject->SessionIDErrorMessage() ),
  897 + MessageType => 'Error',
  898 + %Param,
  899 + ),
  900 + );
  901 + return;
  902 + }
  903 +
  904 + # get session data
  905 + my %UserData = $SessionObject->GetSessionIDData(
  906 + SessionID => $Param{SessionID},
  907 + );
  908 +
  909 + # check needed data
  910 + if ( !$UserData{UserID} || !$UserData{UserLogin} || $UserData{UserType} ne 'User' ) {
  911 +
  912 + my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
  913 +
  914 + # redirect to alternate login
  915 + if ( $ConfigObject->Get('LoginURL') ) {
  916 + print $LayoutObject->Redirect(
  917 + ExtURL => $ConfigObject->Get('LoginURL') . '?Reason=SystemError',
  918 + );
  919 + return;
  920 + }
  921 +
  922 + # show login screen
  923 + $LayoutObject->Print(
  924 + Output => \$LayoutObject->Login(
  925 + Title => 'Error',
  926 + Message => Translatable('Error: invalid session.'),
  927 + MessageType => 'Error',
  928 + %Param,
  929 + ),
  930 + );
  931 + return;
  932 + }
  933 +
  934 + # check module registry
  935 + my $ModuleReg = $ConfigObject->Get('Frontend::Module')->{ $Param{Action} };
  936 + if ( !$ModuleReg ) {
  937 +
  938 + $Kernel::OM->Get('Kernel::System::Log')->Log(
  939 + Priority => 'error',
  940 + Message =>
  941 + "Module Kernel::Modules::$Param{Action} not registered in Kernel/Config.pm!",
  942 + );
  943 + $Kernel::OM->Get('Kernel::Output::HTML::Layout')->FatalError(
  944 + Comment => Translatable('Please contact the administrator.'),
  945 + );
  946 + return;
  947 + }
  948 +
  949 + # module permisson check
  950 + if (
  951 + ref $ModuleReg->{GroupRo} eq 'ARRAY'
  952 + && !scalar @{ $ModuleReg->{GroupRo} }
  953 + && ref $ModuleReg->{Group} eq 'ARRAY'
  954 + && !scalar @{ $ModuleReg->{Group} }
  955 + )
  956 + {
  957 + $Param{AccessRo} = 1;
  958 + $Param{AccessRw} = 1;
  959 + }
  960 + else {
  961 + my $GroupObject = $Kernel::OM->Get('Kernel::System::Group');
  962 +
  963 + PERMISSION:
  964 + for my $Permission (qw(GroupRo Group)) {
  965 + my $AccessOk = 0;
  966 + my $Group = $ModuleReg->{$Permission};
  967 + next PERMISSION if !$Group;
  968 + if ( ref $Group eq 'ARRAY' ) {
  969 + INNER:
  970 + for my $GroupName ( @{$Group} ) {
  971 + next INNER if !$GroupName;
  972 + next INNER if !$GroupObject->PermissionCheck(
  973 + UserID => $UserData{UserID},
  974 + GroupName => $GroupName,
  975 + Type => $Permission eq 'GroupRo' ? 'ro' : 'rw',
  976 +
  977 + );
  978 + $AccessOk = 1;
  979 + last INNER;
  980 + }
  981 + }
  982 + else {
  983 + my $HasPermission = $GroupObject->PermissionCheck(
  984 + UserID => $UserData{UserID},
  985 + GroupName => $Group,
  986 + Type => $Permission eq 'GroupRo' ? 'ro' : 'rw',
  987 +
  988 + );
  989 + if ($HasPermission) {
  990 + $AccessOk = 1;
  991 + }
  992 + }
  993 + if ( $Permission eq 'Group' && $AccessOk ) {
  994 + $Param{AccessRo} = 1;
  995 + $Param{AccessRw} = 1;
  996 + }
  997 + elsif ( $Permission eq 'GroupRo' && $AccessOk ) {
  998 + $Param{AccessRo} = 1;
  999 + }
  1000 + }
  1001 + if ( !$Param{AccessRo} && !$Param{AccessRw} || !$Param{AccessRo} && $Param{AccessRw} ) {
  1002 +
  1003 + print $Kernel::OM->Get('Kernel::Output::HTML::Layout')->NoPermission(
  1004 + Message => Translatable('No Permission to use this frontend module!')
  1005 + );
  1006 + return;
  1007 + }
  1008 + }
  1009 +
  1010 + # put '%Param' and '%UserData' into LayoutObject
  1011 + $Kernel::OM->ObjectParamAdd(
  1012 + 'Kernel::Output::HTML::Layout' => {
  1013 + %Param,
  1014 + %UserData,
  1015 + ModuleReg => $ModuleReg,
  1016 + },
  1017 + );
  1018 + $Kernel::OM->ObjectsDiscard( Objects => ['Kernel::Output::HTML::Layout'] );
  1019 +
  1020 + # update last request time
  1021 + if (
  1022 + !$ParamObject->IsAJAXRequest()
  1023 + || $Param{Action} eq 'AgentVideoChat'
  1024 + ||
  1025 + (
  1026 + $Param{Action} eq 'AgentChat'
  1027 + &&
  1028 + $Param{Subaction} ne 'ChatGetOpenRequests' &&
  1029 + $Param{Subaction} ne 'ChatMonitorCheck'
  1030 + )
  1031 + )
  1032 + {
  1033 + my $DateTimeObject = $Kernel::OM->Create('Kernel::System::DateTime');
  1034 +
  1035 + $SessionObject->UpdateSessionID(
  1036 + SessionID => $Param{SessionID},
  1037 + Key => 'UserLastRequest',
  1038 + Value => $DateTimeObject->ToEpoch(),
  1039 + );
  1040 + }
  1041 +
  1042 + # Override user settings.
  1043 + my $Home = $ConfigObject->Get('Home');
  1044 + my $File = "$Home/Kernel/Config/Files/User/$UserData{UserID}.pm";
  1045 + if ( -e $File ) {
  1046 + if ( !require $File ) {
  1047 + die "ERROR: $!\n";
  1048 + }
  1049 +
  1050 + # prepare file
  1051 + $File =~ s/\Q$Home\E//g;
  1052 + $File =~ s/^\///g;
  1053 + $File =~ s/\/\//\//g;
  1054 + $File =~ s/\//::/g;
  1055 + $File =~ s/\.pm$//g;
  1056 + $File->Load($ConfigObject);
  1057 + }
  1058 +
  1059 + # pre application module
  1060 + my $PreModule = $ConfigObject->Get('PreApplicationModule');
  1061 + if ($PreModule) {
  1062 + my %PreModuleList;
  1063 + if ( ref $PreModule eq 'HASH' ) {
  1064 + %PreModuleList = %{$PreModule};
  1065 + }
  1066 + else {
  1067 + $PreModuleList{Init} = $PreModule;
  1068 + }
  1069 +
  1070 + MODULE:
  1071 + for my $PreModuleKey ( sort keys %PreModuleList ) {
  1072 + my $PreModule = $PreModuleList{$PreModuleKey};
  1073 + next MODULE if !$PreModule;
  1074 + next MODULE if !$Kernel::OM->Get('Kernel::System::Main')->Require($PreModule);
  1075 +
  1076 + # debug info
  1077 + if ( $Self->{Debug} ) {
  1078 + $Kernel::OM->Get('Kernel::System::Log')->Log(
  1079 + Priority => 'debug',
  1080 + Message => "PreApplication module $PreModule is used.",
  1081 + );
  1082 + }
  1083 +
  1084 + my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
  1085 +
  1086 + # use module
  1087 + my $PreModuleObject = $PreModule->new(
  1088 + %Param,
  1089 + %UserData,
  1090 + ModuleReg => $ModuleReg,
  1091 + );
  1092 + my $Output = $PreModuleObject->PreRun();
  1093 + if ($Output) {
  1094 + $LayoutObject->Print( Output => \$Output );
  1095 + return 1;
  1096 + }
  1097 + }
  1098 + }
  1099 +
  1100 + # debug info
  1101 + if ( $Self->{Debug} ) {
  1102 + $Kernel::OM->Get('Kernel::System::Log')->Log(
  1103 + Priority => 'debug',
  1104 + Message => 'Kernel::Modules::' . $Param{Action} . '->new',
  1105 + );
  1106 + }
  1107 +
  1108 + my $FrontendObject = ( 'Kernel::Modules::' . $Param{Action} )->new(
  1109 + %Param,
  1110 + %UserData,
  1111 + ModuleReg => $ModuleReg,
  1112 + Debug => $Self->{Debug},
  1113 + );
  1114 +
  1115 + # debug info
  1116 + if ( $Self->{Debug} ) {
  1117 + $Kernel::OM->Get('Kernel::System::Log')->Log(
  1118 + Priority => 'debug',
  1119 + Message => 'Kernel::Modules::' . $Param{Action} . '->run',
  1120 + );
  1121 + }
  1122 +
  1123 + # ->Run $Action with $FrontendObject
  1124 + $Kernel::OM->Get('Kernel::Output::HTML::Layout')->Print( Output => \$FrontendObject->Run() );
  1125 +
  1126 + # log request time
  1127 + if ( $ConfigObject->Get('PerformanceLog') ) {
  1128 + if ( ( !$QueryString && $Param{Action} ) || $QueryString !~ /Action=/ ) {
  1129 + $QueryString = 'Action=' . $Param{Action} . '&Subaction=' . $Param{Subaction};
  1130 + }
  1131 + my $File = $ConfigObject->Get('PerformanceLog::File');
  1132 + ## no critic
  1133 + if ( open my $Out, '>>', $File ) {
  1134 + ## use critic
  1135 + print $Out time()
  1136 + . '::Agent::'
  1137 + . ( time() - $Self->{PerformanceLogStart} )
  1138 + . "::$UserData{UserLogin}::$QueryString\n";
  1139 + close $Out;
  1140 +
  1141 + $Kernel::OM->Get('Kernel::System::Log')->Log(
  1142 + Priority => 'debug',
  1143 + Message => "Response::Agent: "
  1144 + . ( time() - $Self->{PerformanceLogStart} )
  1145 + . "s taken (URL:$QueryString:$UserData{UserLogin})",
  1146 + );
  1147 + }
  1148 + else {
  1149 + $Kernel::OM->Get('Kernel::System::Log')->Log(
  1150 + Priority => 'error',
  1151 + Message => "Can't write $File: $!",
  1152 + );
  1153 + }
  1154 + }
  1155 + return 1;
  1156 + }
  1157 +
  1158 + # print an error screen
  1159 + my %Data = $SessionObject->GetSessionIDData(
  1160 + SessionID => $Param{SessionID},
  1161 + );
  1162 + $Kernel::OM->ObjectParamAdd(
  1163 + 'Kernel::Output::HTML::Layout' => {
  1164 + %Param,
  1165 + %Data,
  1166 + },
  1167 + );
  1168 + $Kernel::OM->Get('Kernel::Output::HTML::Layout')->FatalError(
  1169 + Comment => Translatable('Please contact the administrator.'),
  1170 + );
  1171 + return;
  1172 +}
  1173 +
  1174 +sub DESTROY {
  1175 + my $Self = shift;
  1176 +
  1177 + # debug info
  1178 + if ( $Self->{Debug} ) {
  1179 + $Kernel::OM->Get('Kernel::System::Log')->Log(
  1180 + Priority => 'debug',
  1181 + Message => 'Global handle stopped.',
  1182 + );
  1183 + }
  1184 +
  1185 + return 1;
  1186 +}
  1187 +
  1188 +# CAS Custom
  1189 +=item
  1190 + Check if it is a CAS logout - if true, logs out user for the session ticket
  1191 +=cut
  1192 +sub CASLogout {
  1193 + my $Self = shift;
  1194 +
  1195 + # get post data
  1196 + my $cgi = new CGI;
  1197 + my $request = uri_unescape($cgi->query_string());
  1198 +
  1199 + # check if it is CAS logout
  1200 + if ($request =~ /(logoutRequest=<samlp:LogoutRequest)/) {
  1201 +
  1202 + (my $ticket) = ($request =~ /<samlp:SessionIndex>([^<]+)/);
  1203 + if (! $ticket) {
  1204 + return 1;
  1205 + }
  1206 +
  1207 + my $DBObject = $Kernel::OM->Get("Kernel::System::DB");
  1208 +
  1209 + # get login for session
  1210 + my $sqlLogin = 'SELECT UserLogin from cas_session where Ticket=?';
  1211 + $DBObject->Prepare(SQL => $sqlLogin, Bind => [\$ticket]);
  1212 +
  1213 + my $login;
  1214 + while (my @Row = $DBObject->FetchrowArray()) {
  1215 + $login = $Row[0];
  1216 + }
  1217 +
  1218 + # if a login was found, kill the user session
  1219 + if ($login) {
  1220 + $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)",
  1221 + Bind => [\$login]);
  1222 + } else {
  1223 + }
  1224 + return 1;
  1225 + } else {
  1226 + return 0;
  1227 + }
  1228 +
  1229 +}
  1230 +# CAS Custom
  1231 +
  1232 +1;
  1233 +
  1234 +=head1 TERMS AND CONDITIONS
  1235 +
  1236 +This software is part of the OTRS project (L<http://otrs.org/>).
  1237 +
  1238 +This software comes with ABSOLUTELY NO WARRANTY. For details, see
  1239 +the enclosed file COPYING for license information (AGPL). If you
  1240 +did not receive this file, see L<http://www.gnu.org/licenses/agpl.txt>.
  1241 +
  1242 +=cut
... ...
Custom/Kernel/System/Web/InterfaceCustomer.pm 0 → 100644
... ... @@ -0,0 +1,1512 @@
  1 +# --
  2 +# Copyright (C) 2001-2017 OTRS AG, http://otrs.com/
  3 +# --
  4 +# This software comes with ABSOLUTELY NO WARRANTY. For details, see
  5 +# the enclosed file COPYING for license information (AGPL). If you
  6 +# did not receive this file, see http://www.gnu.org/licenses/agpl.txt.
  7 +#
  8 +#
  9 +# Custom version for CAS authentication - rodrigo@goncalves.pro.br
  10 +#
  11 +# Version 2016-01-18 - RG - Version for OTRS 5.0.6
  12 +# Version 2017-12-07 - RG - Version for OTRS 6.0.1
  13 +#
  14 +# --
  15 +
  16 +package Kernel::System::Web::InterfaceCustomer;
  17 +
  18 +use strict;
  19 +use warnings;
  20 +
  21 +# CAS Custom
  22 +use CGI;
  23 +use URI::Escape;
  24 +# CAS Custom
  25 +
  26 +use Kernel::System::DateTime;
  27 +use Kernel::System::Email;
  28 +use Kernel::System::VariableCheck qw(IsArrayRefWithData IsHashRefWithData);
  29 +use Kernel::Language qw(Translatable);
  30 +
  31 +our @ObjectDependencies = (
  32 + 'Kernel::Config',
  33 + 'Kernel::Output::HTML::Layout',
  34 + 'Kernel::System::AuthSession',
  35 + 'Kernel::System::CustomerAuth',
  36 + 'Kernel::System::CustomerGroup',
  37 + 'Kernel::System::CustomerUser',
  38 + 'Kernel::System::DB',
  39 + 'Kernel::System::Group',
  40 + 'Kernel::System::Log',
  41 + 'Kernel::System::Main',
  42 + 'Kernel::System::Scheduler',
  43 + 'Kernel::System::DateTime',
  44 + 'Kernel::System::Web::Request',
  45 + 'Kernel::System::Valid',
  46 +);
  47 +
  48 +=head1 NAME
  49 +
  50 +Kernel::System::Web::InterfaceCustomer - the customer web interface
  51 +
  52 +=head1 DESCRIPTION
  53 +
  54 +the global customer web interface (authentication, session handling, ...)
  55 +
  56 +=head1 PUBLIC INTERFACE
  57 +
  58 +=head2 new()
  59 +
  60 +create customer web interface object
  61 +
  62 + use Kernel::System::Web::InterfaceCustomer;
  63 +
  64 + my $Debug = 0;
  65 + my $InterfaceCustomer = Kernel::System::Web::InterfaceCustomer->new(
  66 + Debug => $Debug,
  67 + WebRequest => CGI::Fast->new(), # optional, e. g. if fast cgi is used, the CGI object is already provided
  68 + );
  69 +
  70 +=cut
  71 +
  72 +sub new {
  73 + my ( $Type, %Param ) = @_;
  74 +
  75 + # allocate new hash for object
  76 + my $Self = {};
  77 + bless( $Self, $Type );
  78 +
  79 + # get debug level
  80 + $Self->{Debug} = $Param{Debug} || 0;
  81 +
  82 + # performance log
  83 + $Self->{PerformanceLogStart} = time();
  84 +
  85 + $Kernel::OM->ObjectParamAdd(
  86 + 'Kernel::System::Log' => {
  87 + LogPrefix => $Kernel::OM->Get('Kernel::Config')->Get('CGILogPrefix'),
  88 + },
  89 + 'Kernel::System::Web::Request' => {
  90 + WebRequest => $Param{WebRequest} || 0,
  91 + },
  92 + );
  93 +
  94 + # debug info
  95 + if ( $Self->{Debug} ) {
  96 + $Kernel::OM->Get('Kernel::System::Log')->Log(
  97 + Priority => 'debug',
  98 + Message => 'Global handle started...',
  99 + );
  100 + }
  101 +
  102 + return $Self;
  103 +}
  104 +
  105 +=head2 Run()
  106 +
  107 +execute the object
  108 +
  109 + $InterfaceCustomer->Run();
  110 +
  111 +=cut
  112 +
  113 +sub Run {
  114 + my $Self = shift;
  115 +
  116 + # CAS Custom
  117 + if ($Self->CASLogout()) {
  118 + return;
  119 + }
  120 + # CAS Custom
  121 +
  122 + my $ConfigObject = $Kernel::OM->Get('Kernel::Config');
  123 +
  124 + my $QueryString = $ENV{QUERY_STRING} || '';
  125 +
  126 + # Check if https forcing is active, and redirect if needed.
  127 + if ( $ConfigObject->Get('HTTPSForceRedirect') ) {
  128 +
  129 + # Some web servers do not set HTTPS environment variable, so it's not possible to easily know if we are using
  130 + # https protocol. Look also for similarly named keys in environment hash, since this should prevent loops in
  131 + # certain cases.
  132 + if (
  133 + (
  134 + !defined $ENV{HTTPS}
  135 + && !grep {/^HTTPS(?:_|$)/} keys %ENV
  136 + )
  137 + || $ENV{HTTPS} ne 'on'
  138 + )
  139 + {
  140 + my $Host = $ENV{HTTP_HOST} || $ConfigObject->Get('FQDN');
  141 +
  142 + # Redirect with 301 code. Add two new lines at the end, so HTTP headers are validated correctly.
  143 + print "Status: 301 Moved Permanently\nLocation: https://$Host$ENV{REQUEST_URI}\n\n";
  144 + return;
  145 + }
  146 + }
  147 +
  148 + my $ParamObject = $Kernel::OM->Get('Kernel::System::Web::Request');
  149 +
  150 + my %Param;
  151 +
  152 + # get session id
  153 + $Param{SessionName} = $ConfigObject->Get('CustomerPanelSessionName') || 'CSID';
  154 + $Param{SessionID} = $ParamObject->GetParam( Param => $Param{SessionName} ) || '';
  155 +
  156 + # drop old session id (if exists)
  157 + $QueryString =~ s/(\?|&|;|)$Param{SessionName}(=&|=;|=.+?&|=.+?$)/;/g;
  158 +
  159 + # define framework params
  160 + my $FrameworkParams = {
  161 + Lang => '',
  162 + Action => '',
  163 + Subaction => '',
  164 + RequestedURL => $QueryString,
  165 + };
  166 + for my $Key ( sort keys %{$FrameworkParams} ) {
  167 + $Param{$Key} = $ParamObject->GetParam( Param => $Key )
  168 + || $FrameworkParams->{$Key};
  169 + }
  170 +
  171 + # validate language
  172 + if ( $Param{Lang} && $Param{Lang} !~ m{\A[a-z]{2}(?:_[A-Z]{2})?\z}xms ) {
  173 + delete $Param{Lang};
  174 + }
  175 +
  176 + my $BrowserHasCookie = 0;
  177 +
  178 + # Check if the browser sends the SessionID cookie and set the SessionID-cookie
  179 + # as SessionID! GET or POST SessionID have the lowest priority.
  180 + if ( $ConfigObject->Get('SessionUseCookie') ) {
  181 + $Param{SessionIDCookie} = $ParamObject->GetCookie( Key => $Param{SessionName} );
  182 + if ( $Param{SessionIDCookie} ) {
  183 + $Param{SessionID} = $Param{SessionIDCookie};
  184 + }
  185 + }
  186 +
  187 + my $CookieSecureAttribute;
  188 + if ( $ConfigObject->Get('HttpType') eq 'https' ) {
  189 +
  190 + # Restrict Cookie to HTTPS if it is used.
  191 + $CookieSecureAttribute = 1;
  192 + }
  193 +
  194 + $Kernel::OM->ObjectParamAdd(
  195 + 'Kernel::Output::HTML::Layout' => {
  196 + Lang => $Param{Lang},
  197 + },
  198 + 'Kernel::Language' => {
  199 + UserLanguage => $Param{Lang},
  200 + },
  201 + );
  202 +
  203 + my $DBCanConnect = $Kernel::OM->Get('Kernel::System::DB')->Connect();
  204 +
  205 + if ( !$DBCanConnect || $ParamObject->Error() ) {
  206 + my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
  207 + if ( !$DBCanConnect ) {
  208 + $LayoutObject->CustomerFatalError(
  209 + Comment => Translatable('Please contact the administrator.'),
  210 + );
  211 + return;
  212 + }
  213 + if ( $ParamObject->Error() ) {
  214 + $LayoutObject->CustomerFatalError(
  215 + Message => $ParamObject->Error(),
  216 + Comment => Translatable('Please contact the administrator.'),
  217 + );
  218 + return;
  219 + }
  220 + }
  221 +
  222 + my $UserObject = $Kernel::OM->Get('Kernel::System::CustomerUser');
  223 + my $SessionObject = $Kernel::OM->Get('Kernel::System::AuthSession');
  224 +
  225 + # get common application and add on application params
  226 + my %CommonObjectParam = %{ $ConfigObject->Get('CustomerFrontend::CommonParam') };
  227 + for my $Key ( sort keys %CommonObjectParam ) {
  228 + $Param{$Key} = $ParamObject->GetParam( Param => $Key ) || $CommonObjectParam{$Key};
  229 + }
  230 +
  231 + # security check Action Param (replace non-word chars)
  232 + $Param{Action} =~ s/\W//g;
  233 +
  234 + # check request type
  235 + if ( $Param{Action} eq 'PreLogin' ) {
  236 + my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
  237 +
  238 + # login screen
  239 + $LayoutObject->Print(
  240 + Output => \$LayoutObject->CustomerLogin(
  241 + Title => 'Login',
  242 + Mode => 'PreLogin',
  243 + %Param,
  244 + ),
  245 + );
  246 +
  247 + return;
  248 + }
  249 + elsif ( $Param{Action} eq 'Login' ) {
  250 +
  251 + # get params
  252 + my $PostUser = $ParamObject->GetParam( Param => 'User' ) || '';
  253 + my $PostPw = $ParamObject->GetParam(
  254 + Param => 'Password',
  255 + Raw => 1
  256 + ) || '';
  257 + my $PostTwoFactorToken = $ParamObject->GetParam(
  258 + Param => 'TwoFactorToken',
  259 + Raw => 1
  260 + ) || '';
  261 +
  262 + # create AuthObject
  263 + my $AuthObject = $Kernel::OM->Get('Kernel::System::CustomerAuth');
  264 +
  265 + # check submitted data
  266 + my $User = $AuthObject->Auth(
  267 + User => $PostUser,
  268 + Pw => $PostPw,
  269 + TwoFactorToken => $PostTwoFactorToken,
  270 + RequestedURL => $Param{RequestedURL},
  271 + );
  272 +
  273 + my $Expires = '+' . $ConfigObject->Get('SessionMaxTime') . 's';
  274 + if ( !$ConfigObject->Get('SessionUseCookieAfterBrowserClose') ) {
  275 + $Expires = '';
  276 + }
  277 +
  278 + # login is invalid
  279 + if ( !$User ) {
  280 +
  281 + # CAS Custom
  282 + # Fixes OTRS Layout bug when redirecting
  283 + my $cgi = new CGI();
  284 + print $cgi->redirect( -URL => $ConfigObject->Get("Customer::AuthModule::CAS::CASUrl") . "/login?service=" . $ConfigObject->Get("Customer::AuthModule::CAS::ServiceUrl") . "?" . $Param{RequestedURL});
  285 + return;
  286 + # CAS Custom
  287 +
  288 + $Kernel::OM->ObjectParamAdd(
  289 + 'Kernel::Output::HTML::Layout' => {
  290 + SetCookies => {
  291 + OTRSBrowserHasCookie => $ParamObject->SetCookie(
  292 + Key => 'OTRSBrowserHasCookie',
  293 + Value => 1,
  294 + Expires => $Expires,
  295 + Path => $ConfigObject->Get('ScriptAlias'),
  296 + Secure => $CookieSecureAttribute,
  297 + HTTPOnly => 1,
  298 + ),
  299 + },
  300 + },
  301 + );
  302 +
  303 + my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
  304 +
  305 + # redirect to alternate login
  306 + if ( $ConfigObject->Get('CustomerPanelLoginURL') ) {
  307 + $Param{RequestedURL} = $LayoutObject->LinkEncode( $Param{RequestedURL} );
  308 + print $LayoutObject->Redirect(
  309 + ExtURL => $ConfigObject->Get('CustomerPanelLoginURL')
  310 + . "?Reason=LoginFailed;RequestedURL=$Param{RequestedURL}",
  311 + );
  312 + return;
  313 + }
  314 +
  315 + # show normal login
  316 + $LayoutObject->Print(
  317 + Output => \$LayoutObject->CustomerLogin(
  318 + Title => 'Login',
  319 + Message => $Kernel::OM->Get('Kernel::System::Log')->GetLogEntry(
  320 + Type => 'Info',
  321 + What => 'Message',
  322 + )
  323 + || $AuthObject->GetLastErrorMessage()
  324 + || Translatable('Login failed! Your user name or password was entered incorrectly.'),
  325 + User => $PostUser,
  326 + LoginFailed => 1,
  327 + %Param,
  328 + ),
  329 + );
  330 + return;
  331 + }
  332 +
  333 + # login is successful
  334 + my %UserData = $UserObject->CustomerUserDataGet(
  335 + User => $User,
  336 + Valid => 1
  337 + );
  338 +
  339 + # check if the browser supports cookies
  340 + if ( $ParamObject->GetCookie( Key => 'OTRSBrowserHasCookie' ) ) {
  341 + $Kernel::OM->ObjectParamAdd(
  342 + 'Kernel::Output::HTML::Layout' => {
  343 + BrowserHasCookie => 1,
  344 + },
  345 + );
  346 + }
  347 +
  348 + # check needed data
  349 + if ( !$UserData{UserID} || !$UserData{UserLogin} ) {
  350 +
  351 + my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
  352 +
  353 + # CAS Custom
  354 + my $url = $Kernel::OM->Get("Kernel::Config")->Get('Customer::AuthModule::CAS::InvalidUserURL');
  355 +
  356 + if ($url) {
  357 + print $LayoutObject->Redirect( ExtURL => $url, );
  358 + return;
  359 + }
  360 + # CAS Custom
  361 +
  362 + # redirect to alternate login
  363 + if ( $ConfigObject->Get('CustomerPanelLoginURL') ) {
  364 + print $LayoutObject->Redirect(
  365 + ExtURL => $ConfigObject->Get('CustomerPanelLoginURL')
  366 + . '?Reason=SystemError',
  367 + );
  368 + return;
  369 + }
  370 +
  371 + # show need user data error message
  372 + $LayoutObject->Print(
  373 + Output => \$LayoutObject->CustomerLogin(
  374 + Title => 'Error',
  375 + Message => Translatable(
  376 + 'Authentication succeeded, but no customer record is found in the customer backend. Please contact the administrator.'
  377 + ),
  378 + %Param,
  379 + ),
  380 + );
  381 + return;
  382 + }
  383 +
  384 + # create datetime object
  385 + my $SessionDTObject = $Kernel::OM->Create('Kernel::System::DateTime');
  386 +
  387 + # create new session id
  388 + my $NewSessionID = $SessionObject->CreateSessionID(
  389 + %UserData,
  390 + UserLastRequest => $SessionDTObject->ToEpoch(),
  391 + UserType => 'Customer',
  392 + SessionSource => 'CustomerInterface',
  393 + );
  394 +
  395 + # show error message if no session id has been created
  396 + if ( !$NewSessionID ) {
  397 +
  398 + # get error message
  399 + my $Error = $SessionObject->SessionIDErrorMessage() || '';
  400 +
  401 + my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
  402 +
  403 + # output error message
  404 + $LayoutObject->Print(
  405 + Output => \$LayoutObject->CustomerLogin(
  406 + Title => 'Login',
  407 + Message => $Error,
  408 + %Param,
  409 + ),
  410 + );
  411 + return;
  412 + }
  413 +
  414 + # execution in 20 seconds
  415 + my $ExecutionTimeObj = $Kernel::OM->Create('Kernel::System::DateTime');
  416 + $ExecutionTimeObj->Add( Seconds => 20 );
  417 +
  418 + # add a asynchronous executor scheduler task to count the concurrent user
  419 + $Kernel::OM->Get('Kernel::System::Scheduler')->TaskAdd(
  420 + ExecutionTime => $ExecutionTimeObj->ToString(),
  421 + Type => 'AsynchronousExecutor',
  422 + Name => 'PluginAsynchronous::ConcurrentUser',
  423 + MaximumParallelInstances => 1,
  424 + Data => {
  425 + Object => 'Kernel::System::SupportDataCollector::PluginAsynchronous::OTRS::ConcurrentUsers',
  426 + Function => 'RunAsynchronous',
  427 + },
  428 + );
  429 +
  430 + # get time zone
  431 + my $UserTimeZone = $UserData{UserTimeZone} || Kernel::System::DateTime->UserDefaultTimeZoneGet();
  432 + $SessionObject->UpdateSessionID(
  433 + SessionID => $NewSessionID,
  434 + Key => 'UserTimeZone',
  435 + Value => $UserTimeZone,
  436 + );
  437 +
  438 + # check if the time zone offset reported by the user's browser differs from that
  439 + # of the OTRS user's time zone offset
  440 + my $DateTimeObject = $Kernel::OM->Create(
  441 + 'Kernel::System::DateTime',
  442 + ObjectParams => {
  443 + TimeZone => $UserTimeZone,
  444 + },
  445 + );
  446 + my $OTRSUserTimeZoneOffset = $DateTimeObject->Format( Format => '%{offset}' ) / 60;
  447 + my $BrowserTimeZoneOffset = ( $ParamObject->GetParam( Param => 'TimeZoneOffset' ) || 0 ) * -1;
  448 +
  449 + # TimeZoneOffsetDifference contains the difference of the time zone offset between
  450 + # the user's OTRS time zone setting and the one reported by the user's browser.
  451 + # If there is a difference it can be evaluated later to e. g. show a message
  452 + # for the user to check his OTRS time zone setting.
  453 + my $UserTimeZoneOffsetDifference = abs( $OTRSUserTimeZoneOffset - $BrowserTimeZoneOffset );
  454 + $SessionObject->UpdateSessionID(
  455 + SessionID => $NewSessionID,
  456 + Key => 'UserTimeZoneOffsetDifference',
  457 + Value => $UserTimeZoneOffsetDifference,
  458 + );
  459 +
  460 + $Kernel::OM->ObjectParamAdd(
  461 + 'Kernel::Output::HTML::Layout' => {
  462 + SetCookies => {
  463 + SessionIDCookie => $ParamObject->SetCookie(
  464 + Key => $Param{SessionName},
  465 + Value => $NewSessionID,
  466 + Expires => $Expires,
  467 + Path => $ConfigObject->Get('ScriptAlias'),
  468 + Secure => scalar $CookieSecureAttribute,
  469 + HTTPOnly => 1,
  470 + ),
  471 + OTRSBrowserHasCookie => $ParamObject->SetCookie(
  472 + Key => 'OTRSBrowserHasCookie',
  473 + Value => '',
  474 + Expires => '-1y',
  475 + Path => $ConfigObject->Get('ScriptAlias'),
  476 + Secure => $CookieSecureAttribute,
  477 + HTTPOnly => 1,
  478 + ),
  479 +
  480 + },
  481 + SessionID => $NewSessionID,
  482 + SessionName => $Param{SessionName},
  483 + },
  484 + );
  485 +
  486 + # redirect with new session id and old params
  487 + # prepare old redirect URL -- do not redirect to Login or Logout (loop)!
  488 + if ( $Param{RequestedURL} =~ /Action=(Logout|Login|LostPassword|PreLogin)/ ) {
  489 + $Param{RequestedURL} = '';
  490 + }
  491 +
  492 + # redirect with new session id
  493 + print $Kernel::OM->Get('Kernel::Output::HTML::Layout')->Redirect(
  494 + OP => $Param{RequestedURL},
  495 + Login => 1,
  496 + );
  497 + return 1;
  498 + }
  499 +
  500 + # logout
  501 + elsif ( $Param{Action} eq 'Logout' ) {
  502 +
  503 + # check session id
  504 + if ( !$SessionObject->CheckSessionID( SessionID => $Param{SessionID} ) ) {
  505 +
  506 + # new layout object
  507 + my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
  508 +
  509 + # redirect to alternate login
  510 + if ( $ConfigObject->Get('CustomerPanelLoginURL') ) {
  511 + $Param{RequestedURL} = $LayoutObject->LinkEncode( $Param{RequestedURL} );
  512 + print $LayoutObject->Redirect(
  513 + ExtURL => $ConfigObject->Get('CustomerPanelLoginURL')
  514 + . "?Reason=InvalidSessionID;RequestedURL=$Param{RequestedURL}",
  515 + );
  516 + }
  517 +
  518 + # show login screen
  519 + print $LayoutObject->CustomerLogin(
  520 + Title => 'Logout',
  521 + Message => Translatable('Session invalid. Please log in again.'),
  522 + %Param,
  523 + );
  524 + return;
  525 + }
  526 +
  527 + # get session data
  528 + my %UserData = $SessionObject->GetSessionIDData(
  529 + SessionID => $Param{SessionID},
  530 + );
  531 +
  532 + # create new LayoutObject with new '%Param' and '%UserData'
  533 + $Kernel::OM->ObjectParamAdd(
  534 + 'Kernel::Output::HTML::Layout' => {
  535 + SetCookies => {
  536 + SessionIDCookie => $ParamObject->SetCookie(
  537 + Key => $Param{SessionName},
  538 + Value => '',
  539 + Expires => '-1y',
  540 + Path => $ConfigObject->Get('ScriptAlias'),
  541 + Secure => scalar $CookieSecureAttribute,
  542 + HTTPOnly => 1,
  543 + ),
  544 + },
  545 + %Param,
  546 + %UserData,
  547 + },
  548 + );
  549 +
  550 + $Kernel::OM->ObjectsDiscard( Objects => ['Kernel::Output::HTML::Layout'] );
  551 + my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
  552 +
  553 + # remove session id
  554 + if ( !$SessionObject->RemoveSessionID( SessionID => $Param{SessionID} ) ) {
  555 + $LayoutObject->CustomerFatalError(
  556 + Comment => Translatable('Please contact the administrator.')
  557 + );
  558 + return;
  559 + }
  560 +
  561 + # redirect to alternate login
  562 + if ( $ConfigObject->Get('CustomerPanelLogoutURL') ) {
  563 + print $LayoutObject->Redirect(
  564 + ExtURL => $ConfigObject->Get('CustomerPanelLogoutURL')
  565 + . "?Reason=Logout",
  566 + );
  567 + }
  568 +
  569 + # show logout screen
  570 + my $LogoutMessage = $LayoutObject->{LanguageObject}->Translate('Logout successful.');
  571 +
  572 + $LayoutObject->Print(
  573 + Output => \$LayoutObject->CustomerLogin(
  574 + Title => 'Logout',
  575 + Message => $LogoutMessage,
  576 + MessageType => 'Success',
  577 + %Param,
  578 + ),
  579 + );
  580 + return 1;
  581 + }
  582 +
  583 + # CustomerLostPassword
  584 + elsif ( $Param{Action} eq 'CustomerLostPassword' ) {
  585 +
  586 + # new layout object
  587 + my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
  588 +
  589 + # check feature
  590 + if ( !$ConfigObject->Get('CustomerPanelLostPassword') ) {
  591 +
  592 + # show normal login
  593 + $LayoutObject->Print(
  594 + Output => \$LayoutObject->CustomerLogin(
  595 + Title => 'Login',
  596 + Message => Translatable('Feature not active!'),
  597 + ),
  598 + );
  599 + return;
  600 + }
  601 +
  602 + # get params
  603 + my $User = $ParamObject->GetParam( Param => 'User' ) || '';
  604 + my $Token = $ParamObject->GetParam( Param => 'Token' ) || '';
  605 +
  606 + # get user login by token
  607 + if ( !$User && $Token ) {
  608 + my %UserList = $UserObject->SearchPreferences(
  609 + Key => 'UserToken',
  610 + Value => $Token,
  611 + );
  612 + USER_ID:
  613 + for my $UserID ( sort keys %UserList ) {
  614 + my %UserData = $UserObject->CustomerUserDataGet(
  615 + User => $UserID,
  616 + Valid => 1,
  617 + );
  618 + if (%UserData) {
  619 + $User = $UserData{UserLogin};
  620 + last USER_ID;
  621 + }
  622 + }
  623 + }
  624 +
  625 + # get user data
  626 + my %UserData = $UserObject->CustomerUserDataGet( User => $User );
  627 +
  628 + # verify customer user is valid when requesting password reset
  629 + my @ValidIDs = $Kernel::OM->Get('Kernel::System::Valid')->ValidIDsGet();
  630 + my $UserIsValid = grep { $UserData{ValidID} && $UserData{ValidID} == $_ } @ValidIDs;
  631 + if ( !$UserData{UserID} || !$UserIsValid ) {
  632 +
  633 + # Security: pretend that password reset instructions were actually sent to
  634 + # make sure that users cannot find out valid usernames by
  635 + # just trying and checking the result message.
  636 + $LayoutObject->Print(
  637 + Output => \$LayoutObject->CustomerLogin(
  638 + Title => 'Login',
  639 + Message => Translatable('Sent password reset instructions. Please check your email.'),
  640 + MessageType => 'Success',
  641 + ),
  642 + );
  643 + return;
  644 + }
  645 +
  646 + # create email object
  647 + my $EmailObject = Kernel::System::Email->new( %{$Self} );
  648 +
  649 + # send password reset token
  650 + if ( !$Token ) {
  651 +
  652 + # generate token
  653 + $UserData{Token} = $UserObject->TokenGenerate(
  654 + UserID => $UserData{UserID},
  655 + );
  656 +
  657 + # send token notify email with link
  658 + my $Body = $ConfigObject->Get('CustomerPanelBodyLostPasswordToken')
  659 + || 'ERROR: CustomerPanelBodyLostPasswordToken is missing!';
  660 + my $Subject = $ConfigObject->Get('CustomerPanelSubjectLostPasswordToken')
  661 + || 'ERROR: CustomerPanelSubjectLostPasswordToken is missing!';
  662 + for ( sort keys %UserData ) {
  663 + $Body =~ s/<OTRS_$_>/$UserData{$_}/gi;
  664 + }
  665 + my $Sent = $EmailObject->Send(
  666 + To => $UserData{UserEmail},
  667 + Subject => $Subject,
  668 + Charset => $LayoutObject->{UserCharset},
  669 + MimeType => 'text/plain',
  670 + Body => $Body
  671 + );
  672 + if ( !$Sent->{Success} ) {
  673 + $LayoutObject->FatalError(
  674 + Comment => Translatable('Please contact the administrator.'),
  675 + );
  676 + return;
  677 + }
  678 + $LayoutObject->Print(
  679 + Output => \$LayoutObject->CustomerLogin(
  680 + Title => 'Login',
  681 + Message => Translatable('Sent password reset instructions. Please check your email.'),
  682 + %Param,
  683 + MessageType => 'Success',
  684 + ),
  685 + );
  686 + return 1;
  687 +
  688 + }
  689 +
  690 + # reset password
  691 + # check if token is valid
  692 + my $TokenValid = $UserObject->TokenCheck(
  693 + Token => $Token,
  694 + UserID => $UserData{UserID},
  695 + );
  696 + if ( !$TokenValid ) {
  697 + $LayoutObject->Print(
  698 + Output => \$LayoutObject->CustomerLogin(
  699 + Title => 'Login',
  700 + Message => Translatable('Invalid Token!'),
  701 + %Param,
  702 + ),
  703 + );
  704 + return;
  705 + }
  706 +
  707 + # get new password
  708 + $UserData{NewPW} = $UserObject->GenerateRandomPassword();
  709 +
  710 + # update new password
  711 + my $Success = $UserObject->SetPassword(
  712 + UserLogin => $User,
  713 + PW => $UserData{NewPW}
  714 + );
  715 +
  716 + if ( !$Success ) {
  717 + $LayoutObject->Print(
  718 + Output => \$LayoutObject->CustomerLogin(
  719 + Title => 'Login',
  720 + Message => Translatable('Reset password unsuccessful. Please contact the administrator.'),
  721 + User => $User,
  722 + ),
  723 + );
  724 + return;
  725 + }
  726 +
  727 + # send notify email
  728 + my $Body = $ConfigObject->Get('CustomerPanelBodyLostPassword')
  729 + || 'New Password is: <OTRS_NEWPW>';
  730 + my $Subject = $ConfigObject->Get('CustomerPanelSubjectLostPassword')
  731 + || 'New Password!';
  732 + for ( sort keys %UserData ) {
  733 + $Body =~ s/<OTRS_$_>/$UserData{$_}/gi;
  734 + }
  735 + my $Sent = $EmailObject->Send(
  736 + To => $UserData{UserEmail},
  737 + Subject => $Subject,
  738 + Charset => $LayoutObject->{UserCharset},
  739 + MimeType => 'text/plain',
  740 + Body => $Body
  741 + );
  742 + if ( !$Sent->{Success} ) {
  743 + $LayoutObject->CustomerFatalError(
  744 + Comment => Translatable('Please contact the administrator.')
  745 + );
  746 + return;
  747 + }
  748 + my $Message = $LayoutObject->{LanguageObject}->Translate(
  749 + 'Sent new password to %s. Please check your email.',
  750 + $UserData{UserEmail},
  751 + );
  752 + $LayoutObject->Print(
  753 + Output => \$LayoutObject->CustomerLogin(
  754 + Title => 'Login',
  755 + Message => $Message,
  756 + User => $User,
  757 + MessageType => 'Success',
  758 + ),
  759 + );
  760 + return 1;
  761 + }
  762 +
  763 + # create new customer account
  764 + elsif ( $Param{Action} eq 'CustomerCreateAccount' ) {
  765 +
  766 + # new layout object
  767 + my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
  768 +
  769 + # check feature
  770 + if ( !$ConfigObject->Get('CustomerPanelCreateAccount') ) {
  771 +
  772 + # show normal login
  773 + $LayoutObject->Print(
  774 + Output => \$LayoutObject->CustomerLogin(
  775 + Title => 'Login',
  776 + Message => Translatable('Feature not active!'),
  777 + ),
  778 + );
  779 + return;
  780 + }
  781 +
  782 + # get params
  783 + my %GetParams;
  784 + for my $Entry ( @{ $ConfigObject->Get('CustomerUser')->{Map} } ) {
  785 + $GetParams{ $Entry->[0] } = $ParamObject->GetParam( Param => $Entry->[1] )
  786 + || '';
  787 + }
  788 + $GetParams{ValidID} = 1;
  789 +
  790 + # check needed params
  791 + if ( !$GetParams{UserCustomerID} ) {
  792 + $GetParams{UserCustomerID} = $GetParams{UserEmail};
  793 + }
  794 + if ( !$GetParams{UserLogin} ) {
  795 + $GetParams{UserLogin} = $GetParams{UserEmail};
  796 + }
  797 +
  798 + # get new password
  799 + $GetParams{UserPassword} = $UserObject->GenerateRandomPassword();
  800 +
  801 + # get user data
  802 + my %UserData = $UserObject->CustomerUserDataGet( User => $GetParams{UserLogin} );
  803 + if ( $UserData{UserID} || !$GetParams{UserLogin} ) {
  804 +
  805 + # send data to JS
  806 + $LayoutObject->AddJSData(
  807 + Key => 'SignupError',
  808 + Value => 1,
  809 + );
  810 +
  811 + $LayoutObject->Print(
  812 + Output => \$LayoutObject->CustomerLogin(
  813 + Title => 'Login',
  814 + Message =>
  815 + Translatable('This e-mail address already exists. Please log in or reset your password.'),
  816 + UserTitle => $GetParams{UserTitle},
  817 + UserFirstname => $GetParams{UserFirstname},
  818 + UserLastname => $GetParams{UserLastname},
  819 + UserEmail => $GetParams{UserEmail},
  820 + ),
  821 + );
  822 + return;
  823 + }
  824 +
  825 + # check for mail address restrictions
  826 + my @Whitelist = @{
  827 + $ConfigObject->Get('CustomerPanelCreateAccount::MailRestrictions::Whitelist') // []
  828 + };
  829 + my @Blacklist = @{
  830 + $ConfigObject->Get('CustomerPanelCreateAccount::MailRestrictions::Blacklist') // []
  831 + };
  832 +
  833 + my $WhitelistMatched;
  834 + for my $WhitelistEntry (@Whitelist) {
  835 + my $Regex = eval {qr/$WhitelistEntry/i};
  836 + if ($@) {
  837 + $Kernel::OM->Get('Kernel::System::Log')->Log(
  838 + Priority => 'error',
  839 + Message =>
  840 + $LayoutObject->{LanguageObject}->Translate(
  841 + 'The customer panel mail address whitelist contains the invalid regular expression $WhitelistEntry, please check and correct it.'
  842 + ),
  843 + );
  844 + }
  845 + elsif ( $GetParams{UserEmail} =~ $Regex ) {
  846 + $WhitelistMatched++;
  847 + }
  848 + }
  849 + my $BlacklistMatched;
  850 + for my $BlacklistEntry (@Blacklist) {
  851 + my $Regex = eval {qr/$BlacklistEntry/i};
  852 + if ($@) {
  853 + $Kernel::OM->Get('Kernel::System::Log')->Log(
  854 + Priority => 'error',
  855 + Message =>
  856 + $LayoutObject->{LanguageObject}->Translate(
  857 + 'The customer panel mail address blacklist contains the invalid regular expression $BlacklistEntry, please check and correct it.'
  858 + ),
  859 + );
  860 + }
  861 + elsif ( $GetParams{UserEmail} =~ $Regex ) {
  862 + $BlacklistMatched++;
  863 + }
  864 + }
  865 +
  866 + if ( ( @Whitelist && !$WhitelistMatched ) || ( @Blacklist && $BlacklistMatched ) ) {
  867 +
  868 + # send data to JS
  869 + $LayoutObject->AddJSData(
  870 + Key => 'SignupError',
  871 + Value => 1,
  872 + );
  873 +
  874 + $LayoutObject->Print(
  875 + Output => \$LayoutObject->CustomerLogin(
  876 + Title => 'Login',
  877 + Message =>
  878 + Translatable('This email address is not allowed to register. Please contact support staff.'),
  879 + UserTitle => $GetParams{UserTitle},
  880 + UserFirstname => $GetParams{UserFirstname},
  881 + UserLastname => $GetParams{UserLastname},
  882 + UserEmail => $GetParams{UserEmail},
  883 + ),
  884 + );
  885 +
  886 + return;
  887 + }
  888 +
  889 + # create account
  890 + my $DateTimeObject = $Kernel::OM->Create('Kernel::System::DateTime');
  891 +
  892 + my $Now = $DateTimeObject->ToString();
  893 +
  894 + my $Add = $UserObject->CustomerUserAdd(
  895 + %GetParams,
  896 + Comment => $LayoutObject->{LanguageObject}->Translate( 'Added via Customer Panel (%s)', $Now ),
  897 + ValidID => 1,
  898 + UserID => $ConfigObject->Get('CustomerPanelUserID'),
  899 + );
  900 + if ( !$Add ) {
  901 +
  902 + # send data to JS
  903 + $LayoutObject->AddJSData(
  904 + Key => 'SignupError',
  905 + Value => 1,
  906 + );
  907 +
  908 + $LayoutObject->Print(
  909 + Output => \$LayoutObject->CustomerLogin(
  910 + Title => 'Login',
  911 + Message => Translatable('Customer user can\'t be added!'),
  912 + UserTitle => $GetParams{UserTitle},
  913 + UserFirstname => $GetParams{UserFirstname},
  914 + UserLastname => $GetParams{UserLastname},
  915 + UserEmail => $GetParams{UserEmail},
  916 + ),
  917 + );
  918 + return;
  919 + }
  920 +
  921 + # send notify email
  922 + my $EmailObject = Kernel::System::Email->new( %{$Self} );
  923 + my $Body = $ConfigObject->Get('CustomerPanelBodyNewAccount')
  924 + || 'No Config Option found!';
  925 + my $Subject = $ConfigObject->Get('CustomerPanelSubjectNewAccount')
  926 + || 'New OTRS Account!';
  927 + for ( sort keys %GetParams ) {
  928 + $Body =~ s/<OTRS_$_>/$GetParams{$_}/gi;
  929 + }
  930 +
  931 + # send account info
  932 + my $Sent = $EmailObject->Send(
  933 + To => $GetParams{UserEmail},
  934 + Subject => $Subject,
  935 + Charset => $LayoutObject->{UserCharset},
  936 + MimeType => 'text/plain',
  937 + Body => $Body
  938 + );
  939 + if ( !$Sent->{Success} ) {
  940 + my $Output = $LayoutObject->CustomerHeader(
  941 + Area => 'Core',
  942 + Title => 'Error'
  943 + );
  944 + $Output .= $LayoutObject->CustomerWarning(
  945 + Comment => Translatable('Can\'t send account info!')
  946 + );
  947 + $Output .= $LayoutObject->CustomerFooter();
  948 + $LayoutObject->Print( Output => \$Output );
  949 + return;
  950 + }
  951 +
  952 + # show sent account info
  953 + if ( $ConfigObject->Get('CustomerPanelLoginURL') ) {
  954 +
  955 + # redirect to alternate login
  956 + $Param{RequestedURL} = $LayoutObject->LinkEncode( $Param{RequestedURL} );
  957 + print $LayoutObject->Redirect(
  958 + ExtURL => $ConfigObject->Get('CustomerPanelLoginURL')
  959 + . "?RequestedURL=$Param{RequestedURL};User=$GetParams{UserLogin};"
  960 + . "Email=$GetParams{UserEmail};Reason=NewAccountCreated",
  961 + );
  962 + return 1;
  963 + }
  964 +
  965 + my $AccountCreatedMessage = $LayoutObject->{LanguageObject}->Translate(
  966 + 'New account created. Sent login information to %s. Please check your email.',
  967 + $GetParams{UserEmail},
  968 + );
  969 +
  970 + # login screen
  971 + $LayoutObject->Print(
  972 + Output => \$LayoutObject->CustomerLogin(
  973 + Title => 'Login',
  974 + Message => $AccountCreatedMessage,
  975 + User => $GetParams{UserLogin},
  976 + MessageType => 'Success',
  977 + ),
  978 + );
  979 + return 1;
  980 + }
  981 +
  982 + # show login site
  983 + elsif ( !$Param{SessionID} ) {
  984 +
  985 + # new layout object
  986 + my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
  987 +
  988 + # create AuthObject
  989 + my $AuthObject = $Kernel::OM->Get('Kernel::System::CustomerAuth');
  990 + if ( $AuthObject->GetOption( What => 'PreAuth' ) ) {
  991 +
  992 + # automatic login
  993 + $Param{RequestedURL} = $LayoutObject->LinkEncode( $Param{RequestedURL} );
  994 + print $LayoutObject->Redirect(
  995 + OP => "Action=PreLogin;RequestedURL=$Param{RequestedURL}",
  996 + );
  997 + return;
  998 + }
  999 + elsif ( $ConfigObject->Get('CustomerPanelLoginURL') ) {
  1000 +
  1001 + # redirect to alternate login
  1002 + $Param{RequestedURL} = $LayoutObject->LinkEncode( $Param{RequestedURL} );
  1003 + print $LayoutObject->Redirect(
  1004 + ExtURL => $ConfigObject->Get('CustomerPanelLoginURL')
  1005 + . "?RequestedURL=$Param{RequestedURL}",
  1006 + );
  1007 + return;
  1008 + }
  1009 +
  1010 + # login screen
  1011 + $LayoutObject->Print(
  1012 + Output => \$LayoutObject->CustomerLogin(
  1013 + Title => 'Login',
  1014 + %Param,
  1015 + ),
  1016 + );
  1017 + return 1;
  1018 + }
  1019 +
  1020 + # run modules if a version value exists
  1021 + elsif ( $Kernel::OM->Get('Kernel::System::Main')->Require("Kernel::Modules::$Param{Action}") ) {
  1022 +
  1023 + # check session id
  1024 + if ( !$SessionObject->CheckSessionID( SessionID => $Param{SessionID} ) ) {
  1025 +
  1026 + # create new LayoutObject with new '%Param'
  1027 + $Kernel::OM->ObjectParamAdd(
  1028 + 'Kernel::Output::HTML::Layout' => {
  1029 + SetCookies => {
  1030 + SessionIDCookie => $ParamObject->SetCookie(
  1031 + Key => $Param{SessionName},
  1032 + Value => '',
  1033 + Expires => '-1y',
  1034 + Path => $ConfigObject->Get('ScriptAlias'),
  1035 + Secure => scalar $CookieSecureAttribute,
  1036 + HTTPOnly => 1,
  1037 + ),
  1038 + },
  1039 + %Param,
  1040 + }
  1041 + );
  1042 +
  1043 + $Kernel::OM->ObjectsDiscard( Objects => ['Kernel::Output::HTML::Layout'] );
  1044 + my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
  1045 +
  1046 + # create AuthObject
  1047 + my $AuthObject = $Kernel::OM->Get('Kernel::System::CustomerAuth');
  1048 + if ( $AuthObject->GetOption( What => 'PreAuth' ) ) {
  1049 +
  1050 + # automatic re-login
  1051 + $Param{RequestedURL} = $LayoutObject->LinkEncode( $Param{RequestedURL} );
  1052 + print $LayoutObject->Redirect(
  1053 + OP => "?Action=PreLogin&RequestedURL=$Param{RequestedURL}",
  1054 + );
  1055 + return;
  1056 + }
  1057 +
  1058 + # redirect to alternate login
  1059 + elsif ( $ConfigObject->Get('CustomerPanelLoginURL') ) {
  1060 +
  1061 + # redirect to alternate login
  1062 + $Param{RequestedURL} = $LayoutObject->LinkEncode( $Param{RequestedURL} );
  1063 + print $LayoutObject->Redirect(
  1064 + ExtURL => $ConfigObject->Get('CustomerPanelLoginURL')
  1065 + . "?Reason=InvalidSessionID;RequestedURL=$Param{RequestedURL}",
  1066 + );
  1067 + return;
  1068 + }
  1069 +
  1070 + # show login
  1071 + $LayoutObject->Print(
  1072 + Output => \$LayoutObject->CustomerLogin(
  1073 + Title => 'Login',
  1074 + Message =>
  1075 + $LayoutObject->{LanguageObject}->Translate( $SessionObject->SessionIDErrorMessage() ),
  1076 + %Param,
  1077 + ),
  1078 + );
  1079 + return;
  1080 + }
  1081 +
  1082 + # get session data
  1083 + my %UserData = $SessionObject->GetSessionIDData(
  1084 + SessionID => $Param{SessionID},
  1085 + );
  1086 +
  1087 + # check needed data
  1088 + if ( !$UserData{UserID} || !$UserData{UserLogin} || $UserData{UserType} ne 'Customer' ) {
  1089 + my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
  1090 +
  1091 + # redirect to alternate login
  1092 + if ( $ConfigObject->Get('CustomerPanelLoginURL') ) {
  1093 + print $LayoutObject->Redirect(
  1094 + ExtURL => $ConfigObject->Get('CustomerPanelLoginURL')
  1095 + . "?Reason=SystemError",
  1096 + );
  1097 + return;
  1098 + }
  1099 +
  1100 + # show login screen
  1101 + $LayoutObject->Print(
  1102 + Output => \$LayoutObject->CustomerLogin(
  1103 + Title => 'Error',
  1104 + Message => Translatable('Error: invalid session.'),
  1105 + %Param,
  1106 + ),
  1107 + );
  1108 + return;
  1109 + }
  1110 +
  1111 + # module registry
  1112 + my $ModuleReg = $ConfigObject->Get('CustomerFrontend::Module')->{ $Param{Action} };
  1113 + if ( !$ModuleReg ) {
  1114 +
  1115 + # new layout object
  1116 + my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
  1117 + $Kernel::OM->Get('Kernel::System::Log')->Log(
  1118 + Priority => 'error',
  1119 + Message =>
  1120 + "Module Kernel::Modules::$Param{Action} not registered in Kernel/Config.pm!",
  1121 + );
  1122 + $LayoutObject->CustomerFatalError(
  1123 + Comment => Translatable('Please contact the administrator.'),
  1124 + );
  1125 + return;
  1126 + }
  1127 +
  1128 + # module permission check for action
  1129 + if (
  1130 + ref $ModuleReg->{GroupRo} eq 'ARRAY'
  1131 + && !scalar @{ $ModuleReg->{GroupRo} }
  1132 + && ref $ModuleReg->{Group} eq 'ARRAY'
  1133 + && !scalar @{ $ModuleReg->{Group} }
  1134 + )
  1135 + {
  1136 + $Param{AccessRo} = 1;
  1137 + $Param{AccessRw} = 1;
  1138 + }
  1139 + else {
  1140 +
  1141 + ( $Param{AccessRo}, $Param{AccessRw} ) = $Self->_CheckModulePermission(
  1142 + ModuleReg => $ModuleReg,
  1143 + %UserData,
  1144 + );
  1145 +
  1146 + if ( !$Param{AccessRo} ) {
  1147 +
  1148 + # new layout object
  1149 + my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
  1150 + $Kernel::OM->Get('Kernel::System::Log')->Log(
  1151 + Priority => 'error',
  1152 + Message => 'No Permission to use this frontend action module!'
  1153 + );
  1154 + $LayoutObject->CustomerFatalError(
  1155 + Comment => Translatable('Please contact the administrator.'),
  1156 + );
  1157 + return;
  1158 + }
  1159 +
  1160 + }
  1161 +
  1162 + my $NavigationConfig = $ConfigObject->Get('CustomerFrontend::Navigation')->{ $Param{Action} };
  1163 +
  1164 + # module permission check for submenu item
  1165 + if ( IsHashRefWithData($NavigationConfig) ) {
  1166 +
  1167 + KEY:
  1168 + for my $Key ( sort keys %{$NavigationConfig} ) {
  1169 + next KEY if $Key !~ m/^\d+/i;
  1170 + next KEY if $Param{RequestedURL} !~ m/Subaction/i;
  1171 +
  1172 + my @ModuleNavigationConfigs;
  1173 +
  1174 + # FIXME: Support both old (HASH) and new (ARRAY of HASH) navigation configurations, for reasons of
  1175 + # backwards compatibility. Once we are sure everything has been migrated correctly, support for
  1176 + # HASH-only configuration can be dropped in future major release.
  1177 + if ( IsHashRefWithData( $NavigationConfig->{$Key} ) ) {
  1178 + push @ModuleNavigationConfigs, $NavigationConfig->{$Key};
  1179 + }
  1180 + elsif ( IsArrayRefWithData( $NavigationConfig->{$Key} ) ) {
  1181 + push @ModuleNavigationConfigs, @{ $NavigationConfig->{$Key} };
  1182 + }
  1183 +
  1184 + # Skip incompatible configuration.
  1185 + else {
  1186 + next KEY;
  1187 + }
  1188 +
  1189 + ITEM:
  1190 + for my $Item (@ModuleNavigationConfigs) {
  1191 + if (
  1192 + $Item->{Link} =~ m/Subaction=/i
  1193 + && $Item->{Link} !~ m/$Param{Subaction}/i
  1194 + )
  1195 + {
  1196 + next ITEM;
  1197 + }
  1198 + $Param{AccessRo} = 0;
  1199 + $Param{AccessRw} = 0;
  1200 +
  1201 + # module permission check for submenu item
  1202 + if (
  1203 + ref $Item->{GroupRo} eq 'ARRAY'
  1204 + && !scalar @{ $Item->{GroupRo} }
  1205 + && ref $Item->{Group} eq 'ARRAY'
  1206 + && !scalar @{ $Item->{Group} }
  1207 + )
  1208 + {
  1209 + $Param{AccessRo} = 1;
  1210 + $Param{AccessRw} = 1;
  1211 + }
  1212 + else {
  1213 +
  1214 + ( $Param{AccessRo}, $Param{AccessRw} ) = $Self->_CheckModulePermission(
  1215 + ModuleReg => $Item,
  1216 + %UserData,
  1217 + );
  1218 +
  1219 + if ( !$Param{AccessRo} ) {
  1220 +
  1221 + # new layout object
  1222 + my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
  1223 + $Kernel::OM->Get('Kernel::System::Log')->Log(
  1224 + Priority => 'error',
  1225 + Message => 'No Permission to use this frontend subaction module!'
  1226 + );
  1227 + $LayoutObject->CustomerFatalError(
  1228 + Comment => Translatable('Please contact the administrator.')
  1229 + );
  1230 + return;
  1231 + }
  1232 + }
  1233 + }
  1234 + }
  1235 + }
  1236 +
  1237 + # create new LayoutObject with new '%Param' and '%UserData'
  1238 + $Kernel::OM->ObjectParamAdd(
  1239 + 'Kernel::Output::HTML::Layout' => {
  1240 + %Param,
  1241 + %UserData,
  1242 + ModuleReg => $ModuleReg,
  1243 + },
  1244 + );
  1245 +
  1246 + $Kernel::OM->ObjectsDiscard( Objects => ['Kernel::Output::HTML::Layout'] );
  1247 + my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
  1248 +
  1249 + # update last request time
  1250 + if (
  1251 + !$ParamObject->IsAJAXRequest()
  1252 + || $Param{Action} eq 'CustomerVideoChat'
  1253 + )
  1254 + {
  1255 + my $DateTimeObject = $Kernel::OM->Create('Kernel::System::DateTime');
  1256 +
  1257 + $SessionObject->UpdateSessionID(
  1258 + SessionID => $Param{SessionID},
  1259 + Key => 'UserLastRequest',
  1260 + Value => $DateTimeObject->ToEpoch(),
  1261 + );
  1262 + }
  1263 +
  1264 + # pre application module
  1265 + my $PreModule = $ConfigObject->Get('CustomerPanelPreApplicationModule');
  1266 + if ($PreModule) {
  1267 + my %PreModuleList;
  1268 + if ( ref $PreModule eq 'HASH' ) {
  1269 + %PreModuleList = %{$PreModule};
  1270 + }
  1271 + else {
  1272 + $PreModuleList{Init} = $PreModule;
  1273 + }
  1274 +
  1275 + MODULE:
  1276 + for my $PreModuleKey ( sort keys %PreModuleList ) {
  1277 + my $PreModule = $PreModuleList{$PreModuleKey};
  1278 + next MODULE if !$PreModule;
  1279 + next MODULE if !$Kernel::OM->Get('Kernel::System::Main')->Require($PreModule);
  1280 +
  1281 + # debug info
  1282 + if ( $Self->{Debug} ) {
  1283 + $Kernel::OM->Get('Kernel::System::Log')->Log(
  1284 + Priority => 'debug',
  1285 + Message => "CustomerPanelPreApplication module $PreModule is used.",
  1286 + );
  1287 + }
  1288 +
  1289 + # use module
  1290 + my $PreModuleObject = $PreModule->new(
  1291 + %Param,
  1292 + %UserData,
  1293 +
  1294 + );
  1295 + my $Output = $PreModuleObject->PreRun();
  1296 + if ($Output) {
  1297 + $LayoutObject->Print( Output => \$Output );
  1298 + return 1;
  1299 + }
  1300 + }
  1301 + }
  1302 +
  1303 + # debug info
  1304 + if ( $Self->{Debug} ) {
  1305 + $Kernel::OM->Get('Kernel::System::Log')->Log(
  1306 + Priority => 'debug',
  1307 + Message => 'Kernel::Modules::' . $Param{Action} . '->new',
  1308 + );
  1309 + }
  1310 +
  1311 + my $FrontendObject = ( 'Kernel::Modules::' . $Param{Action} )->new(
  1312 + %Param,
  1313 + %UserData,
  1314 + ModuleReg => $ModuleReg,
  1315 + Debug => $Self->{Debug},
  1316 + );
  1317 +
  1318 + # debug info
  1319 + if ( $Self->{Debug} ) {
  1320 + $Kernel::OM->Get('Kernel::System::Log')->Log(
  1321 + Priority => 'debug',
  1322 + Message => 'Kernel::Modules::' . $Param{Action} . '->run',
  1323 + );
  1324 + }
  1325 +
  1326 + # ->Run $Action with $FrontendObject
  1327 + $LayoutObject->Print( Output => \$FrontendObject->Run() );
  1328 +
  1329 + # log request time
  1330 + if ( $ConfigObject->Get('PerformanceLog') ) {
  1331 + if ( ( !$QueryString && $Param{Action} ) || $QueryString !~ /Action=/ ) {
  1332 + $QueryString = 'Action=' . $Param{Action} . ';Subaction=' . $Param{Subaction};
  1333 + }
  1334 + my $File = $ConfigObject->Get('PerformanceLog::File');
  1335 + ## no critic
  1336 + if ( open my $Out, '>>', $File ) {
  1337 + ## use critic
  1338 + print $Out time()
  1339 + . '::Customer::'
  1340 + . ( time() - $Self->{PerformanceLogStart} )
  1341 + . "::$UserData{UserLogin}::$QueryString\n";
  1342 + close $Out;
  1343 + $Kernel::OM->Get('Kernel::System::Log')->Log(
  1344 + Priority => 'debug',
  1345 + Message => 'Response::Customer: '
  1346 + . ( time() - $Self->{PerformanceLogStart} )
  1347 + . "s taken (URL:$QueryString:$UserData{UserLogin})",
  1348 + );
  1349 + }
  1350 + else {
  1351 + $Kernel::OM->Get('Kernel::System::Log')->Log(
  1352 + Priority => 'error',
  1353 + Message => "Can't write $File: $!",
  1354 + );
  1355 + }
  1356 + }
  1357 + return 1;
  1358 + }
  1359 +
  1360 + # print an error screen
  1361 + my %Data = $SessionObject->GetSessionIDData(
  1362 + SessionID => $Param{SessionID},
  1363 + );
  1364 + $Kernel::OM->ObjectParamAdd(
  1365 + 'Kernel::Output::HTML::Layout' => {
  1366 + %Param,
  1367 + %Data,
  1368 + },
  1369 + );
  1370 + my $LayoutObject = $Kernel::OM->Get('Kernel::Output::HTML::Layout');
  1371 + $LayoutObject->CustomerFatalError(
  1372 + Comment => Translatable('Please contact the administrator.'),
  1373 + );
  1374 + return;
  1375 +}
  1376 +
  1377 +=begin Internal:
  1378 +
  1379 +=head2 _CheckModulePermission()
  1380 +
  1381 +module permission check
  1382 +
  1383 + ($AccessRo, $AccessRw = $AutoResponseObject->_CheckModulePermission(
  1384 + ModuleReg => $ModuleReg,
  1385 + %UserData,
  1386 + );
  1387 +
  1388 +=cut
  1389 +
  1390 +sub _CheckModulePermission {
  1391 + my ( $Self, %Param ) = @_;
  1392 +
  1393 + my $AccessRo = 0;
  1394 + my $AccessRw = 0;
  1395 +
  1396 + PERMISSION:
  1397 + for my $Permission (qw(GroupRo Group)) {
  1398 + my $AccessOk = 0;
  1399 + my $Group = $Param{ModuleReg}->{$Permission};
  1400 +
  1401 + next PERMISSION if !$Group;
  1402 +
  1403 + my $GroupObject = $Kernel::OM->Get('Kernel::System::CustomerGroup');
  1404 +
  1405 + if ( IsArrayRefWithData($Group) ) {
  1406 + GROUP:
  1407 + for my $Item ( @{$Group} ) {
  1408 + next GROUP if !$Item;
  1409 + next GROUP if !$GroupObject->PermissionCheck(
  1410 + UserID => $Param{UserID},
  1411 + GroupName => $Item,
  1412 + Type => $Permission eq 'GroupRo' ? 'ro' : 'rw',
  1413 + );
  1414 +
  1415 + $AccessOk = 1;
  1416 + last GROUP;
  1417 + }
  1418 + }
  1419 + else {
  1420 + my $HasPermission = $GroupObject->PermissionCheck(
  1421 + UserID => $Param{UserID},
  1422 + GroupName => $Group,
  1423 + Type => $Permission eq 'GroupRo' ? 'ro' : 'rw',
  1424 + );
  1425 + if ($HasPermission) {
  1426 + $AccessOk = 1;
  1427 + }
  1428 + }
  1429 + if ( $Permission eq 'Group' && $AccessOk ) {
  1430 + $AccessRo = 1;
  1431 + $AccessRw = 1;
  1432 + }
  1433 + elsif ( $Permission eq 'GroupRo' && $AccessOk ) {
  1434 + $AccessRo = 1;
  1435 + }
  1436 + }
  1437 +
  1438 + return ( $AccessRo, $AccessRw );
  1439 +}
  1440 +
  1441 +=end Internal:
  1442 +
  1443 +=cut
  1444 +
  1445 +sub DESTROY {
  1446 + my $Self = shift;
  1447 +
  1448 + # debug info
  1449 + if ( $Self->{Debug} ) {
  1450 + $Kernel::OM->Get('Kernel::System::Log')->Log(
  1451 + Priority => 'debug',
  1452 + Message => 'Global handle stopped.',
  1453 + );
  1454 + }
  1455 +
  1456 + return 1;
  1457 +}
  1458 +
  1459 +# CAS Custom
  1460 +=item
  1461 + Check if it is a CAS logout - if true, logs out user for the session ticket
  1462 +=cut
  1463 +sub CASLogout {
  1464 + my $Self = shift;
  1465 +
  1466 + # get post data
  1467 + my $cgi = new CGI;
  1468 + my $request = uri_unescape($cgi->query_string());
  1469 +
  1470 + # check if it is CAS logout
  1471 + if ($request =~ /(logoutRequest=<samlp:LogoutRequest)/) {
  1472 +
  1473 + (my $ticket) = ($request =~ /<samlp:SessionIndex>([^<]+)/);
  1474 + if (! $ticket) {
  1475 + return 1;
  1476 + } else {
  1477 + }
  1478 +
  1479 + my $DBObject = $Kernel::OM->Get("Kernel::System::DB");
  1480 +
  1481 + # get login for session
  1482 + my $sqlLogin = 'SELECT UserLogin from cas_session where Ticket=?';
  1483 + $DBObject->Prepare(SQL => $sqlLogin, Bind => [\$ticket]);
  1484 + my $login;
  1485 + while (my @Row = $DBObject->FetchrowArray()) {
  1486 + $login = $Row[0];
  1487 + }
  1488 +
  1489 + # if a login was found, kill the user session
  1490 + if ($login) {
  1491 + $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)",
  1492 + Bind => [\$login]);
  1493 + } else {
  1494 + }
  1495 + return 1;
  1496 + } else {
  1497 + return 0;
  1498 + }
  1499 +}
  1500 +# CAS Custom
  1501 +
  1502 +1;
  1503 +
  1504 +=head1 TERMS AND CONDITIONS
  1505 +
  1506 +This software is part of the OTRS project (L<http://otrs.org/>).
  1507 +
  1508 +This software comes with ABSOLUTELY NO WARRANTY. For details, see
  1509 +the enclosed file COPYING for license information (AGPL). If you
  1510 +did not receive this file, see L<http://www.gnu.org/licenses/agpl.txt>.
  1511 +
  1512 +=cut
... ...
Custom/Kernel/System/Web/Request.pm 0 → 100644
... ... @@ -0,0 +1,582 @@
  1 +# --
  2 +# Copyright (C) 2001-2017 OTRS AG, http://otrs.com/
  3 +# --
  4 +# This software comes with ABSOLUTELY NO WARRANTY. For details, see
  5 +# the enclosed file COPYING for license information (AGPL). If you
  6 +# did not receive this file, see http://www.gnu.org/licenses/agpl.txt.
  7 +#
  8 +# Custom version for CAS authentication - rodrigo@goncalves.pro.br
  9 +#
  10 +# Version 2016-01-18 - RG - Version for OTRS 5.0.6
  11 +# Version 2017-12-07 - RG - Version for OTRS 6.0.1
  12 +#
  13 +# --
  14 +
  15 +package Kernel::System::Web::Request;
  16 +
  17 +use strict;
  18 +use warnings;
  19 +
  20 +use CGI ();
  21 +use CGI::Carp;
  22 +use File::Path qw();
  23 +
  24 +use Kernel::System::VariableCheck qw(:all);
  25 +
  26 +our @ObjectDependencies = (
  27 + 'Kernel::Config',
  28 + 'Kernel::System::CheckItem',
  29 + 'Kernel::System::Encode',
  30 + 'Kernel::System::Web::UploadCache',
  31 + 'Kernel::System::FormDraft',
  32 +);
  33 +
  34 +=head1 NAME
  35 +
  36 +Kernel::System::Web::Request - global CGI interface
  37 +
  38 +=head1 DESCRIPTION
  39 +
  40 +All cgi param functions.
  41 +
  42 +=head1 PUBLIC INTERFACE
  43 +
  44 +=head2 new()
  45 +
  46 +create param object. Do not use it directly, instead use:
  47 +
  48 + use Kernel::System::ObjectManager;
  49 + local $Kernel::OM = Kernel::System::ObjectManager->new(
  50 + 'Kernel::System::Web::Request' => {
  51 + WebRequest => CGI::Fast->new(), # optional, e. g. if fast cgi is used
  52 + }
  53 + );
  54 + my $ParamObject = $Kernel::OM->Get('Kernel::System::Web::Request');
  55 +
  56 +If Kernel::System::Web::Request is instantiated several times, they will share the
  57 +same CGI data (this can be helpful in filters which do not have access to the
  58 +ParamObject, for example.
  59 +
  60 +If you need to reset the CGI data before creating a new instance, use
  61 +
  62 + CGI::initialize_globals();
  63 +
  64 +before calling Kernel::System::Web::Request->new();
  65 +
  66 +=cut
  67 +
  68 +sub new {
  69 + my ( $Type, %Param ) = @_;
  70 +
  71 + # allocate new hash for object
  72 + my $Self = {};
  73 + bless( $Self, $Type );
  74 +
  75 + # get config object
  76 + my $ConfigObject = $Kernel::OM->Get('Kernel::Config');
  77 +
  78 + # max 5 MB posts
  79 + $CGI::POST_MAX = $ConfigObject->Get('WebMaxFileUpload') || 1024 * 1024 * 5; ## no critic
  80 +
  81 + # query object (in case use already existing WebRequest, e. g. fast cgi)
  82 + $Self->{Query} = $Param{WebRequest} || CGI->new();
  83 +
  84 + return $Self;
  85 +}
  86 +
  87 +=head2 Error()
  88 +
  89 +to get the error back
  90 +
  91 + if ( $ParamObject->Error() ) {
  92 + print STDERR $ParamObject->Error() . "\n";
  93 + }
  94 +
  95 +=cut
  96 +
  97 +sub Error {
  98 + my ( $Self, %Param ) = @_;
  99 +
  100 + # Workaround, do not check cgi_error() with perlex, CGI module is not
  101 + # working with perlex.
  102 + if ( $ENV{'GATEWAY_INTERFACE'} && $ENV{'GATEWAY_INTERFACE'} =~ /^CGI-PerlEx/ ) {
  103 + return;
  104 + }
  105 +
  106 + return if !$Self->{Query}->cgi_error();
  107 + ## no critic
  108 + return $Self->{Query}->cgi_error() . ' - POST_MAX=' . ( $CGI::POST_MAX / 1024 ) . 'KB';
  109 + ## use critic
  110 +}
  111 +
  112 +=head2 GetParam()
  113 +
  114 +to get single request parameters. By default, trimming is performed on the data.
  115 +
  116 + my $Param = $ParamObject->GetParam(
  117 + Param => 'ID',
  118 + Raw => 1, # optional, input data is not changed
  119 + );
  120 +
  121 +=cut
  122 +
  123 +sub GetParam {
  124 + my ( $Self, %Param ) = @_;
  125 +
  126 + my $Value = $Self->{Query}->param( $Param{Param} );
  127 +
  128 + # Fallback to query string for mixed requests.
  129 + my $RequestMethod = $Self->{Query}->request_method() // '';
  130 + if ( $RequestMethod eq 'POST' && !defined $Value ) {
  131 + $Value = $Self->{Query}->url_param( $Param{Param} );
  132 + }
  133 +
  134 + $Kernel::OM->Get('Kernel::System::Encode')->EncodeInput( \$Value );
  135 +
  136 + my $Raw = defined $Param{Raw} ? $Param{Raw} : 0;
  137 +
  138 + if ( !$Raw ) {
  139 +
  140 + # If it is a plain string, perform trimming
  141 + if ( ref \$Value eq 'SCALAR' ) {
  142 + $Kernel::OM->Get('Kernel::System::CheckItem')->StringClean(
  143 + StringRef => \$Value,
  144 + TrimLeft => 1,
  145 + TrimRight => 1,
  146 + );
  147 + }
  148 + }
  149 +
  150 + return $Value;
  151 +}
  152 +
  153 +=head2 GetParamNames()
  154 +
  155 +to get names of all parameters passed to the script.
  156 +
  157 + my @ParamNames = $ParamObject->GetParamNames();
  158 +
  159 +Example:
  160 +
  161 +Called URL: index.pl?Action=AdminSystemConfiguration;Subaction=Save;Name=Config::Option::Valid
  162 +
  163 + my @ParamNames = $ParamObject->GetParamNames();
  164 + print join " :: ", @ParamNames;
  165 + #prints Action :: Subaction :: Name
  166 +
  167 +=cut
  168 +
  169 +sub GetParamNames {
  170 + my $Self = shift;
  171 +
  172 + # fetch all names
  173 + my @ParamNames = $Self->{Query}->param();
  174 +
  175 + # Fallback to query string for mixed requests.
  176 + my $RequestMethod = $Self->{Query}->request_method() // '';
  177 + if ( $RequestMethod eq 'POST' ) {
  178 + my %POSTNames;
  179 + @POSTNames{@ParamNames} = @ParamNames;
  180 + my @GetNames = $Self->{Query}->url_param();
  181 + GETNAME:
  182 + for my $GetName (@GetNames) {
  183 + next GETNAME if !defined $GetName;
  184 + push @ParamNames, $GetName if !exists $POSTNames{$GetName};
  185 + }
  186 + }
  187 +
  188 + for my $Name (@ParamNames) {
  189 + $Kernel::OM->Get('Kernel::System::Encode')->EncodeInput( \$Name );
  190 + }
  191 +
  192 + return @ParamNames;
  193 +}
  194 +
  195 +=head2 GetArray()
  196 +
  197 +to get array request parameters.
  198 +By default, trimming is performed on the data.
  199 +
  200 + my @Param = $ParamObject->GetArray(
  201 + Param => 'ID',
  202 + Raw => 1, # optional, input data is not changed
  203 + );
  204 +
  205 +=cut
  206 +
  207 +sub GetArray {
  208 + my ( $Self, %Param ) = @_;
  209 +
  210 + my @Values = $Self->{Query}->multi_param( $Param{Param} );
  211 +
  212 + # Fallback to query string for mixed requests.
  213 + my $RequestMethod = $Self->{Query}->request_method() // '';
  214 + if ( $RequestMethod eq 'POST' && !@Values ) {
  215 + @Values = $Self->{Query}->url_param( $Param{Param} );
  216 + }
  217 +
  218 + $Kernel::OM->Get('Kernel::System::Encode')->EncodeInput( \@Values );
  219 +
  220 + my $Raw = defined $Param{Raw} ? $Param{Raw} : 0;
  221 +
  222 + if ( !$Raw ) {
  223 +
  224 + # get check item object
  225 + my $CheckItemObject = $Kernel::OM->Get('Kernel::System::CheckItem');
  226 +
  227 + VALUE:
  228 + for my $Value (@Values) {
  229 +
  230 + # don't validate CGI::File::Temp objects from file uploads
  231 + next VALUE if !$Value || ref \$Value ne 'SCALAR';
  232 +
  233 + $CheckItemObject->StringClean(
  234 + StringRef => \$Value,
  235 + TrimLeft => 1,
  236 + TrimRight => 1,
  237 + );
  238 + }
  239 + }
  240 +
  241 + return @Values;
  242 +}
  243 +
  244 +=head2 GetUploadAll()
  245 +
  246 +gets file upload data.
  247 +
  248 + my %File = $ParamObject->GetUploadAll(
  249 + Param => 'FileParam', # the name of the request parameter containing the file data
  250 + );
  251 +
  252 + returns (
  253 + Filename => 'abc.txt',
  254 + ContentType => 'text/plain',
  255 + Content => 'Some text',
  256 + );
  257 +
  258 +=cut
  259 +
  260 +sub GetUploadAll {
  261 + my ( $Self, %Param ) = @_;
  262 +
  263 + # get upload
  264 + my $Upload = $Self->{Query}->upload( $Param{Param} );
  265 + return if !$Upload;
  266 +
  267 + # get real file name
  268 + my $UploadFilenameOrig = $Self->GetParam( Param => $Param{Param} ) || 'unknown';
  269 +
  270 + my $NewFileName = "$UploadFilenameOrig"; # use "" to get filename of anony. object
  271 + $Kernel::OM->Get('Kernel::System::Encode')->EncodeInput( \$NewFileName );
  272 +
  273 + # replace all devices like c: or d: and dirs for IE!
  274 + $NewFileName =~ s/.:\\(.*)/$1/g;
  275 + $NewFileName =~ s/.*\\(.+?)/$1/g;
  276 +
  277 + # return a string
  278 + my $Content = '';
  279 + while (<$Upload>) {
  280 + $Content .= $_;
  281 + }
  282 + close $Upload;
  283 +
  284 + my $ContentType = $Self->_GetUploadInfo(
  285 + Filename => $UploadFilenameOrig,
  286 + Header => 'Content-Type',
  287 + );
  288 +
  289 + return (
  290 + Filename => $NewFileName,
  291 + Content => $Content,
  292 + ContentType => $ContentType,
  293 + );
  294 +}
  295 +
  296 +sub _GetUploadInfo {
  297 + my ( $Self, %Param ) = @_;
  298 +
  299 + # get file upload info
  300 + my $FileInfo = $Self->{Query}->uploadInfo( $Param{Filename} );
  301 +
  302 + # return if no upload info exists
  303 + return 'application/octet-stream' if !$FileInfo;
  304 +
  305 + # return if no content type of upload info exists
  306 + return 'application/octet-stream' if !$FileInfo->{ $Param{Header} };
  307 +
  308 + # return content type of upload info
  309 + return $FileInfo->{ $Param{Header} };
  310 +}
  311 +
  312 +=head2 SetCookie()
  313 +
  314 +set a cookie
  315 +
  316 + $ParamObject->SetCookie(
  317 + Key => ID,
  318 + Value => 123456,
  319 + Expires => '+3660s',
  320 + Path => 'otrs/', # optional, only allow cookie for given path
  321 + Secure => 1, # optional, set secure attribute to disable cookie on HTTP (HTTPS only)
  322 + HTTPOnly => 1, # optional, sets HttpOnly attribute of cookie to prevent access via JavaScript
  323 + );
  324 +
  325 +=cut
  326 +
  327 +sub SetCookie {
  328 + my ( $Self, %Param ) = @_;
  329 +
  330 + $Param{Path} ||= '';
  331 +
  332 + return $Self->{Query}->cookie(
  333 + -name => $Param{Key},
  334 + -value => $Param{Value},
  335 + -expires => $Param{Expires},
  336 + -secure => $Param{Secure} || '',
  337 + -httponly => $Param{HTTPOnly} || '',
  338 + -path => '/' . $Param{Path},
  339 + );
  340 +}
  341 +
  342 +=head2 GetCookie()
  343 +
  344 +get a cookie
  345 +
  346 + my $String = $ParamObject->GetCookie(
  347 + Key => ID,
  348 + );
  349 +
  350 +=cut
  351 +
  352 +sub GetCookie {
  353 + my ( $Self, %Param ) = @_;
  354 +
  355 + return $Self->{Query}->cookie( $Param{Key} );
  356 +}
  357 +
  358 +=head2 IsAJAXRequest()
  359 +
  360 +checks if the current request was sent by AJAX
  361 +
  362 + my $IsAJAXRequest = $ParamObject->IsAJAXRequest();
  363 +
  364 +=cut
  365 +
  366 +sub IsAJAXRequest {
  367 + my ( $Self, %Param ) = @_;
  368 +
  369 + return ( $Self->{Query}->http('X-Requested-With') // '' ) eq 'XMLHttpRequest' ? 1 : 0;
  370 +}
  371 +
  372 +=head2 LoadFormDraft()
  373 +
  374 +Load specified draft.
  375 +This will read stored draft data and inject it into the param object
  376 +for transparent use by frontend module.
  377 +
  378 + my $FormDraftID = $ParamObject->LoadFormDraft(
  379 + FormDraftID => 123,
  380 + UserID => 1,
  381 + );
  382 +
  383 +=cut
  384 +
  385 +sub LoadFormDraft {
  386 + my ( $Self, %Param ) = @_;
  387 +
  388 + return if !$Param{FormDraftID} || !$Param{UserID};
  389 +
  390 + # get draft data
  391 + my $FormDraft = $Kernel::OM->Get('Kernel::System::FormDraft')->FormDraftGet(
  392 + FormDraftID => $Param{FormDraftID},
  393 + UserID => $Param{UserID},
  394 + );
  395 + return if !IsHashRefWithData($FormDraft);
  396 +
  397 + # Verify action.
  398 + my $Action = $Self->GetParam( Param => 'Action' );
  399 + return if $FormDraft->{Action} ne $Action;
  400 +
  401 + # add draft name to form data
  402 + $FormDraft->{FormData}->{FormDraftTitle} = $FormDraft->{Title};
  403 +
  404 + # create FormID and add to form data
  405 + my $FormID = $Kernel::OM->Get('Kernel::System::Web::UploadCache')->FormIDCreate();
  406 + $FormDraft->{FormData}->{FormID} = $FormID;
  407 +
  408 + # set form data to param object, depending on type
  409 + KEY:
  410 + for my $Key ( sort keys %{ $FormDraft->{FormData} } ) {
  411 + my $Value = $FormDraft->{FormData}->{$Key} // '';
  412 +
  413 + # array value
  414 + if ( IsArrayRefWithData($Value) ) {
  415 + $Self->{Query}->param(
  416 + -name => $Key,
  417 + -values => $Value,
  418 + );
  419 + next KEY;
  420 + }
  421 +
  422 + # scalar value
  423 + $Self->{Query}->param(
  424 + -name => $Key,
  425 + -value => $Value,
  426 + );
  427 + }
  428 +
  429 + # add UploadCache data
  430 + my $UploadCacheObject = $Kernel::OM->Get('Kernel::System::Web::UploadCache');
  431 + for my $File ( @{ $FormDraft->{FileData} } ) {
  432 + return if !$UploadCacheObject->FormIDAddFile(
  433 + %{$File},
  434 + FormID => $FormID,
  435 + );
  436 + }
  437 +
  438 + return $Param{FormDraftID};
  439 +}
  440 +
  441 +=head2 SaveFormDraft()
  442 +
  443 +Create or replace draft using data from param object and upload cache.
  444 +Specified params can be overwritten if necessary.
  445 +
  446 + my $FormDraftID = $ParamObject->SaveFormDraft(
  447 + UserID => 1
  448 + ObjectType => 'Ticket',
  449 + ObjectID => 123,
  450 + OverrideParams => { # optional, can contain strings and array references
  451 + Subaction => undef,
  452 + UserID => 1,
  453 + CustomParam => [ 1, 2, 3, ],
  454 + ...
  455 + },
  456 + );
  457 +
  458 +=cut
  459 +
  460 +sub SaveFormDraft {
  461 + my ( $Self, %Param ) = @_;
  462 +
  463 + # check params
  464 + return if !$Param{UserID} || !$Param{ObjectType} || !IsInteger( $Param{ObjectID} );
  465 +
  466 + # gather necessary data for backend
  467 + my %MetaParams;
  468 + for my $Param (qw(Action FormDraftID FormDraftTitle FormID)) {
  469 + $MetaParams{$Param} = $Self->GetParam(
  470 + Param => $Param,
  471 + );
  472 + }
  473 + return if !$MetaParams{Action};
  474 +
  475 + # determine session name param (SessionUseCookie = 0) for exclusion
  476 + my $SessionName = $Kernel::OM->Get('Kernel::Config')->Get('SessionName') || 'SessionID';
  477 +
  478 + # compile override list
  479 + my %OverrideParams = IsHashRefWithData( $Param{OverrideParams} ) ? %{ $Param{OverrideParams} } : ();
  480 +
  481 + # these params must always be excluded for safety, they take precedence
  482 + for my $Name (
  483 + qw(Action ChallengeToken FormID FormDraftID FormDraftTitle FormDraftAction LoadFormDraftID),
  484 + $SessionName
  485 + )
  486 + {
  487 + $OverrideParams{$Name} = undef;
  488 + }
  489 +
  490 + # Gather all params.
  491 + # Exclude, add or override by using OverrideParams if necessary.
  492 + my @ParamNames = $Self->GetParamNames();
  493 + my %ParamSeen;
  494 + my %FormData;
  495 + PARAM:
  496 + for my $Param ( @ParamNames, sort keys %OverrideParams ) {
  497 + next PARAM if $ParamSeen{$Param}++;
  498 + my $Value;
  499 +
  500 + # check for overrides first
  501 + if ( exists $OverrideParams{$Param} ) {
  502 +
  503 + # allow only strings and array references as value
  504 + if (
  505 + IsStringWithData( $OverrideParams{$Param} )
  506 + || IsArrayRefWithData( $OverrideParams{$Param} )
  507 + )
  508 + {
  509 + $Value = $OverrideParams{$Param};
  510 + }
  511 +
  512 + # skip all other parameters (including those specified to be excluded by using 'undef')
  513 + else {
  514 + next PARAM;
  515 + }
  516 + }
  517 +
  518 + # get other values from param object
  519 + if ( !defined $Value ) {
  520 + my @Values = $Self->GetArray( Param => $Param );
  521 + next PARAM if !IsArrayRefWithData( \@Values );
  522 +
  523 + # store single occurances as string
  524 + if ( scalar @Values == 1 ) {
  525 + $Value = $Values[0];
  526 + }
  527 +
  528 + # store multiple occurances as array reference
  529 + else {
  530 + $Value = \@Values;
  531 + }
  532 + }
  533 +
  534 + $FormData{$Param} = $Value;
  535 + }
  536 +
  537 + # get files from upload cache
  538 + my @FileData = $Kernel::OM->Get('Kernel::System::Web::UploadCache')->FormIDGetAllFilesData(
  539 + FormID => $MetaParams{FormID},
  540 + );
  541 +
  542 + # prepare data to add or update draft
  543 + my %FormDraft = (
  544 + FormData => \%FormData,
  545 + FileData => \@FileData,
  546 + FormDraftID => $MetaParams{FormDraftID},
  547 + ObjectType => $Param{ObjectType},
  548 + ObjectID => $Param{ObjectID},
  549 + Action => $MetaParams{Action},
  550 + Title => $MetaParams{FormDraftTitle},
  551 + UserID => $Param{UserID},
  552 + );
  553 +
  554 + # update draft
  555 + if ( $MetaParams{FormDraftID} ) {
  556 + return if !$Kernel::OM->Get('Kernel::System::FormDraft')->FormDraftUpdate(%FormDraft);
  557 + return 1;
  558 + }
  559 +
  560 + # create new draft
  561 + return if !$Kernel::OM->Get('Kernel::System::FormDraft')->FormDraftAdd(%FormDraft);
  562 + return 1;
  563 +}
  564 +
  565 +# CAS Custom
  566 +sub GetMethod {
  567 + my ( $Self, %Param ) = @_;
  568 + return $Self->{Query}->request_method();
  569 +}
  570 +# CAS Custom
  571 +
  572 +1;
  573 +
  574 +=head1 TERMS AND CONDITIONS
  575 +
  576 +This software is part of the OTRS project (L<http://otrs.org/>).
  577 +
  578 +This software comes with ABSOLUTELY NO WARRANTY. For details, see
  579 +the enclosed file COPYING for license information (AGPL). If you
  580 +did not receive this file, see L<http://www.gnu.org/licenses/agpl.txt>.
  581 +
  582 +=cut
... ...
Kernel/System/Auth/CAS.pm 0 → 100644
... ... @@ -0,0 +1,154 @@
  1 +# --
  2 +# Kernel/System/Auth/CAS.pm - provides the CAS authentication through Jasig
  3 +#
  4 +# Copyright (C) 2015-2017 - Rodrigo Gonçalves - rodrigo@goncalves.pro.br
  5 +# --
  6 +# $Id: CAS.pm,v 2.0 2015/01/05 15:16:05 mb Exp $
  7 +#
  8 +# Version 2015/01/15 - RG - Adjusts for OTRS4
  9 +# Version 2016-01-18 - RG - Fixes for OTRS 5.0.6
  10 +# Version 2017-12-07 - RG - Fixes for OTRS 6.0.1
  11 +#
  12 +#
  13 +# --
  14 +# This software comes with ABSOLUTELY NO WARRANTY. For details, see
  15 +# the enclosed file COPYING for license information (AGPL). If you
  16 +# did not receive this file, see http://www.gnu.org/licenses/agpl.txt.
  17 +# --
  18 +# Note:
  19 +#
  20 +# If you use this module, you should use as fallback the following config settings:
  21 +#
  22 +# If use isn't login through apache ($ENV{REMOTE_USER} or $ENV{HTTP_REMOTE_USER})
  23 +# $Self->{CustomerPanelLoginURL} = 'http://host.example.com/not-authorised-for-otrs.html';
  24 +#
  25 +# $Self->{CustomerPanelLogoutURL} = 'http://host.example.com/thanks-for-using-otrs.html';
  26 +#
  27 +# --
  28 +package Kernel::System::Auth::CAS;
  29 +
  30 +use strict;
  31 +use warnings;
  32 +use CGI;
  33 +use AuthCAS;
  34 +use Data::Dumper;
  35 +use CGI::Carp qw( fatalsToBrowser );
  36 +use URI::Escape;
  37 +
  38 +our @ObjectDependencies = ( "Kernel::Config", "Kernel::System::Log", "Kernel::System::DB" );
  39 +
  40 +sub new {
  41 + my ( $Type, %Param ) = @_;
  42 +
  43 + # allocate new hash for object
  44 + my $Self = {};
  45 + bless( $Self, $Type );
  46 +
  47 + # Debug 0=off 1=on
  48 + $Self->{Debug} = 1;
  49 + $Self->{Count} = $Param{Count} || '';
  50 +
  51 + return $Self;
  52 +}
  53 +
  54 +sub GetOption {
  55 + my ( $Self, %Param ) = @_;
  56 +
  57 + # check needed stuff
  58 + if ( !$Param{What} ) {
  59 + $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need What!" );
  60 + return;
  61 + }
  62 +
  63 + # module options
  64 + my %Option = ( PreAuth => 1, );
  65 +
  66 + # return option
  67 + return $Option{ $Param{What} };
  68 +}
  69 +
  70 +sub Auth {
  71 + my ( $Self, %Param ) = @_;
  72 +
  73 + my $QueryString = $ENV{"HTTP_REFERER"} || '';
  74 +
  75 + my $ConfigObject = $Kernel::OM->Get("Kernel::Config");
  76 +
  77 + my $cas = new AuthCAS( casUrl => $ConfigObject->Get('AuthModule::CAS::CASUrl') );
  78 + my $app_url = $ConfigObject->Get('AuthModule::CAS::ServiceUrl');
  79 + my $Gateway = $ConfigObject->Get('AuthModule::CAS::Gateway');
  80 + my $User = '';
  81 +
  82 + if ( $Gateway == 1 ) {
  83 +
  84 + # TEST MODE
  85 + if ( $QueryString =~ /ticket/ ) {
  86 + $QueryString =~ /ticket%3D([^&]+)/;
  87 + my $ST = $1;
  88 + my $User = $cas->validateST( $app_url, $ST );
  89 + return $User;
  90 + }
  91 +
  92 + if ( $QueryString =~ /checked_cas/ ) {
  93 + return '';
  94 + }
  95 +
  96 + my $login_url = $cas->getServerLoginGatewayURL( $app_url . '?checked_cas=1' );
  97 + my $q = CGI->new();
  98 + print $q->redirect( -URL => $login_url );
  99 + }
  100 + else {
  101 + $Self->Debug("Autenticando: " . $QueryString);
  102 +
  103 + # If no ticket passed, redirect to CAS to authenticate/get token
  104 + unless ( $QueryString =~ /ticket=/ || $QueryString =~ /ticket%3D/ ) {
  105 + my $redurl = $app_url . "?" . $Param{RequestedURL};
  106 + $redurl = uri_escape($redurl);
  107 + my $login_url = $cas->getServerLoginURL( $redurl );
  108 + my $q = CGI->new();
  109 + print $q->redirect( -URL => $login_url );
  110 + }
  111 + else {
  112 + $Self->Debug("Recebida URL com ticket: " . $QueryString);
  113 +
  114 + # CAS session created - record id
  115 + $QueryString =~ /ticket=([^&]+)/;
  116 + my $ST = $1;
  117 + if (! $ST) {
  118 + $QueryString =~ /ticket%3D([^&]+)/;
  119 + $ST = $1;
  120 + }
  121 +
  122 + my $requrl = $Param{RequestedURL};
  123 + my $substring = substr($requrl, 0, index($requrl, "&ticket=ST"));
  124 +
  125 + my $redurl = $app_url . "?" . $substring;
  126 + $redurl = uri_escape($redurl);
  127 +
  128 + $Self->Debug("Validando URL $redurl com ticket $ST");
  129 + $User = $cas->validateST( $redurl, $ST );
  130 +
  131 + $Self->Debug("Autenticou... $User");
  132 + if ($User) {
  133 + $Kernel::OM->Get("Kernel::System::DB")->Do(
  134 + SQL => 'DELETE FROM cas_session WHERE UserLogin=?',
  135 + Bind => [ \$User ],
  136 + );
  137 +
  138 + $Kernel::OM->Get("Kernel::System::DB")->Do(
  139 + SQL => 'INSERT INTO cas_session (UserLogin,Ticket) VALUES (?, ?)',
  140 + Bind => [ \$User, \$ST, ],
  141 + );
  142 + }
  143 + }
  144 + }
  145 + return $User;
  146 +}
  147 +
  148 +sub Debug {
  149 + my $Self = shift;
  150 + my $msg = shift;
  151 + $Kernel::OM->Get("Kernel::System::Log")->Log( Priority => 'debug', Message => $msg );
  152 +}
  153 +
  154 +1;
... ...
Kernel/System/CustomerAuth/CAS.pm 0 → 100755
... ... @@ -0,0 +1,154 @@
  1 +# --
  2 +# Kernel/System/CustomerAuth/CAS.pm - provides the CAS authentication through Jasig
  3 +#
  4 +# Copyright (C) 2015-2017 - Rodrigo Gonçalves - rodrigo@goncalves.pro.br
  5 +# --
  6 +# $Id: CAS.pm,v 2.0 2015/01/05 15:16:05 mb Exp $
  7 +#
  8 +# Version 2015/01/15 - RG - Adjusts for OTRS4
  9 +# Version 2016-01-18 - RG - Fixes for OTRS 5.0.6
  10 +# Version 2017-12-07 - RG - Fixes for OTRS 6.0.1
  11 +#
  12 +# --
  13 +# This software comes with ABSOLUTELY NO WARRANTY. For details, see
  14 +# the enclosed file COPYING for license information (AGPL). If you
  15 +# did not receive this file, see http://www.gnu.org/licenses/agpl.txt.
  16 +# --
  17 +# Note:
  18 +#
  19 +# If you use this module, you should use as fallback the following config settings:
  20 +#
  21 +# If use isn't login through apache ($ENV{REMOTE_USER} or $ENV{HTTP_REMOTE_USER})
  22 +# $Self->{CustomerPanelLoginURL} = 'http://host.example.com/not-authorised-for-otrs.html';
  23 +#
  24 +# $Self->{CustomerPanelLogoutURL} = 'http://host.example.com/thanks-for-using-otrs.html';
  25 +#
  26 +# --
  27 +package Kernel::System::CustomerAuth::CAS;
  28 +
  29 +use strict;
  30 +use warnings;
  31 +use CGI;
  32 +use AuthCAS;
  33 +use Data::Dumper;
  34 +use CGI::Carp qw( fatalsToBrowser );
  35 +use URI::Escape;
  36 +
  37 +our @ObjectDependencies = ( "Kernel::Config", "Kernel::System::Log", "Kernel::System::DB" );
  38 +
  39 +sub new {
  40 + my ( $Type, %Param ) = @_;
  41 +
  42 + # allocate new hash for object
  43 + my $Self = {};
  44 + bless( $Self, $Type );
  45 +
  46 + # Debug 0=off 1=on
  47 + $Self->{Debug} = 0;
  48 + $Self->{Count} = $Param{Count} || '';
  49 +
  50 + return $Self;
  51 +}
  52 +
  53 +sub GetOption {
  54 + my ( $Self, %Param ) = @_;
  55 +
  56 + # check needed stuff
  57 + if ( !$Param{What} ) {
  58 + $Kernel::OM->Get('Kernel::System::Log')->Log( Priority => 'error', Message => "Need What!" );
  59 + return;
  60 + }
  61 +
  62 + # module options
  63 + my %Option = ( PreAuth => 1, );
  64 +
  65 + # return option
  66 + return $Option{ $Param{What} };
  67 +}
  68 +
  69 +sub Auth {
  70 + my ( $Self, %Param ) = @_;
  71 +
  72 + my $QueryString = $ENV{"HTTP_REFERER"} || '';
  73 +
  74 + my $ConfigObject = $Kernel::OM->Get("Kernel::Config");
  75 +
  76 + my $cas = new AuthCAS( casUrl => $ConfigObject->Get('Customer::AuthModule::CAS::CASUrl') );
  77 + my $app_url = $ConfigObject->Get('Customer::AuthModule::CAS::ServiceUrl');
  78 + my $Gateway = $ConfigObject->Get('Customer::AuthModule::CAS::Gateway');
  79 + my $User = '';
  80 +
  81 + if ( $Gateway == 1 ) {
  82 +
  83 + # TEST MODE
  84 + if ( $QueryString =~ /ticket/ ) {
  85 + $QueryString =~ /ticket%3D([^&]+)/;
  86 + my $ST = $1;
  87 + my $User = $cas->validateST( $app_url, $ST );
  88 + return $User;
  89 + }
  90 +
  91 + if ( $QueryString =~ /checked_cas/ ) {
  92 + return '';
  93 + }
  94 +
  95 + my $login_url = $cas->getServerLoginGatewayURL( $app_url . '?checked_cas=1' );
  96 + my $q = CGI->new();
  97 + print $q->redirect( -URL => $login_url );
  98 + }
  99 + else {
  100 + $Self->Debug("Autenticando: " . $QueryString);
  101 +
  102 + # If no ticket passed, redirect to CAS to authenticate/get token
  103 + unless ( $QueryString =~ /ticket=/ || $QueryString =~ /ticket%3D/ ) {
  104 + my $redurl = $app_url . "?" . $Param{RequestedURL};
  105 + $redurl = uri_escape($redurl);
  106 + my $login_url = $cas->getServerLoginURL( $redurl );
  107 + my $q = CGI->new();
  108 + print $q->redirect( -URL => $login_url );
  109 + }
  110 + else {
  111 + $Self->Debug("Recebida URL com ticket: " . $QueryString);
  112 +
  113 + # CAS session created - record id
  114 + $QueryString =~ /ticket=([^&]+)/;
  115 + my $ST = $1;
  116 + if (! $ST) {
  117 + $QueryString =~ /ticket%3D([^&]+)/;
  118 + $ST = $1;
  119 + }
  120 +
  121 + my $requrl = $Param{RequestedURL};
  122 + my $substring = substr($requrl, 0, index($requrl, "&ticket=ST"));
  123 +
  124 + my $redurl = $app_url . "?" . $substring;
  125 + $redurl = uri_escape($redurl);
  126 +
  127 + $Self->Debug("Validando URL $redurl com ticket $ST");
  128 + $User = $cas->validateST( $redurl, $ST );
  129 +
  130 + $Self->Debug("Autenticou... $User");
  131 + if ($User) {
  132 + $Kernel::OM->Get("Kernel::System::DB")->Do(
  133 + SQL => 'DELETE FROM cas_session WHERE UserLogin=?',
  134 + Bind => [ \$User ],
  135 + );
  136 +
  137 + $Kernel::OM->Get("Kernel::System::DB")->Do(
  138 + SQL => 'INSERT INTO cas_session (UserLogin,Ticket) VALUES (?, ?)',
  139 + Bind => [ \$User, \$ST, ],
  140 + );
  141 + }
  142 + }
  143 + }
  144 +
  145 + return $User;
  146 +}
  147 +
  148 +sub Debug {
  149 + my $Self = shift;
  150 + my $msg = shift;
  151 + $Kernel::OM->Get("Kernel::System::Log")->Log( Priority => 'debug', Message => $msg );
  152 +}
  153 +
  154 +1;
... ...
README.md 0 → 100644
... ... @@ -0,0 +1,41 @@
  1 +CAS Authentication (Jasig-based) for OTRS
  2 +=========================================
  3 +
  4 +
  5 +Required PERL Packages:
  6 +-----------------------
  7 +
  8 +* AuthCAS (`apt install libauthcas-perl` on Ubuntu)
  9 +
  10 +
  11 +Config required:
  12 +----------------
  13 +
  14 +*Kernel/Config.pm:*
  15 +
  16 + $Self->{'AuthModule'} = 'Kernel::System::Auth::CAS';
  17 + $Self->{'AuthModule::CAS::Gateway'} = 0;
  18 + $Self->{'AuthModule::CAS::ServiceUrl'} = 'URL FOR OTRS AGENT INDEX (ex: https://host.com/otrs/index.pl)';
  19 + $Self->{'AuthModule::CAS::CASUrl'} = 'URL FOR CAS SERVICE (WITHOUT TRAILING /) - ex: https://cas.systems.com';
  20 +
  21 + $Self->{'Customer::AuthModule'} = 'Kernel::System::CustomerAuth::CAS';
  22 + $Self->{'Customer::AuthModule::CAS::Gateway'} = 0;
  23 + $Self->{'Customer::AuthModule::CAS::ServiceUrl'} = 'URL FOR OTRS CUSTOMER INDEX (ex: https://host.com/otrs/customer.pl)';
  24 + $Self->{'Customer::AuthModule::CAS::CASUrl'} = 'URL FOR CAS SERVICE (WITHOUT TRAILING /) - ex: https://cas.systems.com';
  25 +
  26 +
  27 +Package building:
  28 +-----------------
  29 +
  30 +To build the package, do the following:
  31 +
  32 + cd dist
  33 + ./CreateOpm.sh
  34 +
  35 +The generated package will be on the same `dist` directory
  36 +
  37 +
  38 +Issues:
  39 +-------
  40 +
  41 +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.
0 42 \ No newline at end of file
... ...
dist/CreateOpm.sh 0 → 100755
... ... @@ -0,0 +1,8 @@
  1 +#!/bin/bash
  2 +LOCAL="$PWD"
  3 +
  4 +echo Build package otrs-cas-authentication;
  5 +echo Package will be generated on the current path...
  6 +cd /opt/otrs
  7 +bin/otrs.Console.pl Dev::Package::Build "$LOCAL"/../CASAuthentication.sopm "$LOCAL"/
  8 +cd $LOCAL
0 9 \ No newline at end of file
... ...