1# -- 2# Copyright (C) 2001-2020 OTRS AG, https://otrs.com/ 3# -- 4# This software comes with ABSOLUTELY NO WARRANTY. For details, see 5# the enclosed file COPYING for license information (GPL). If you 6# did not receive this file, see https://www.gnu.org/licenses/gpl-3.0.txt. 7# -- 8 9package Kernel::System::GenericInterface::Webservice; 10 11use strict; 12use warnings; 13 14use Kernel::System::VariableCheck qw(:all); 15 16our @ObjectDependencies = ( 17 'Kernel::Config', 18 'Kernel::System::Cache', 19 'Kernel::System::DB', 20 'Kernel::System::GenericInterface::DebugLog', 21 'Kernel::System::GenericInterface::WebserviceHistory', 22 'Kernel::System::Log', 23 'Kernel::System::Main', 24 'Kernel::System::Valid', 25 'Kernel::System::YAML', 26); 27 28=head1 NAME 29 30Kernel::System::GenericInterface::Webservice 31 32=head1 DESCRIPTION 33 34Web service configuration backend. 35 36=head1 PUBLIC INTERFACE 37 38=head2 new() 39 40Don't use the constructor directly, use the ObjectManager instead: 41 42 my $WebserviceObject = $Kernel::OM->Get('Kernel::System::GenericInterface::Webservice'); 43 44=cut 45 46sub new { 47 my ( $Webservice, %Param ) = @_; 48 49 # allocate new hash for object 50 my $Self = {}; 51 bless( $Self, $Webservice ); 52 53 return $Self; 54} 55 56=head2 WebserviceAdd() 57 58add new Webservices 59 60returns id of new web service if successful or undef otherwise 61 62 my $ID = $WebserviceObject->WebserviceAdd( 63 Name => 'some name', 64 Config => $ConfigHashRef, 65 ValidID => 1, 66 UserID => 123, 67 ); 68 69=cut 70 71sub WebserviceAdd { 72 my ( $Self, %Param ) = @_; 73 74 # check needed stuff 75 for my $Key (qw(Name Config ValidID UserID)) { 76 if ( !$Param{$Key} ) { 77 $Kernel::OM->Get('Kernel::System::Log')->Log( 78 Priority => 'error', 79 Message => "Need $Key!" 80 ); 81 return; 82 } 83 } 84 85 # check config 86 if ( !IsHashRefWithData( $Param{Config} ) ) { 87 $Kernel::OM->Get('Kernel::System::Log')->Log( 88 Priority => 'error', 89 Message => "Web service Config should be a non empty hash reference!", 90 ); 91 return; 92 } 93 94 # check config internals 95 if ( !IsHashRefWithData( $Param{Config}->{Debugger} ) ) { 96 $Kernel::OM->Get('Kernel::System::Log')->Log( 97 Priority => 'error', 98 Message => "Web service Config Debugger should be a non empty hash reference!", 99 ); 100 return; 101 } 102 if ( !IsStringWithData( $Param{Config}->{Debugger}->{DebugThreshold} ) ) { 103 $Kernel::OM->Get('Kernel::System::Log')->Log( 104 Priority => 'error', 105 Message => "Web service Config Debugger DebugThreshold should be a non empty string!", 106 ); 107 return; 108 } 109 if ( !defined $Param{Config}->{Provider} && !defined $Param{Config}->{Requester} ) { 110 $Kernel::OM->Get('Kernel::System::Log')->Log( 111 Priority => 'error', 112 Message => "Web service Config Provider or Requester should be defined!", 113 ); 114 return; 115 } 116 for my $CommunicationType (qw(Provider Requester)) { 117 if ( defined $Param{Config}->{$CommunicationType} ) { 118 if ( !IsHashRefWithData( $Param{Config}->{$CommunicationType} ) ) { 119 $Kernel::OM->Get('Kernel::System::Log')->Log( 120 Priority => 'error', 121 Message => "Web service Config $CommunicationType should be a non empty hash" 122 . " reference!", 123 ); 124 return; 125 } 126 if ( !IsHashRefWithData( $Param{Config}->{$CommunicationType}->{Transport} ) ) { 127 $Kernel::OM->Get('Kernel::System::Log')->Log( 128 Priority => 'error', 129 Message => "Web service Config $CommunicationType Transport should be a" 130 . " non empty hash reference!", 131 ); 132 return; 133 } 134 } 135 } 136 137 # Check if web service is using an old configuration type and upgrade if necessary. 138 $Self->_WebserviceConfigUpgrade(%Param); 139 140 # dump config as string 141 my $Config = $Kernel::OM->Get('Kernel::System::YAML')->Dump( Data => $Param{Config} ); 142 143 # get database object 144 my $DBObject = $Kernel::OM->Get('Kernel::System::DB'); 145 146 # sql 147 return if !$DBObject->Do( 148 SQL => 149 'INSERT INTO gi_webservice_config (name, config, valid_id, ' 150 . ' create_time, create_by, change_time, change_by)' 151 . ' VALUES (?, ?, ?, current_timestamp, ?, current_timestamp, ?)', 152 Bind => [ 153 \$Param{Name}, \$Config, \$Param{ValidID}, 154 \$Param{UserID}, \$Param{UserID}, 155 ], 156 ); 157 158 return if !$DBObject->Prepare( 159 SQL => 'SELECT id FROM gi_webservice_config WHERE name = ?', 160 Bind => [ \$Param{Name} ], 161 ); 162 163 my $ID; 164 while ( my @Row = $DBObject->FetchrowArray() ) { 165 $ID = $Row[0]; 166 } 167 168 # delete cache 169 $Kernel::OM->Get('Kernel::System::Cache')->CleanUp( 170 Type => 'Webservice', 171 ); 172 173 # get web service history object 174 my $WebserviceHistoryObject = $Kernel::OM->Get('Kernel::System::GenericInterface::WebserviceHistory'); 175 176 # add history 177 return if !$WebserviceHistoryObject->WebserviceHistoryAdd( 178 WebserviceID => $ID, 179 Config => $Param{Config}, 180 UserID => $Param{UserID}, 181 ); 182 183 return $ID; 184} 185 186=head2 WebserviceGet() 187 188get Webservices attributes 189 190 my $Webservice = $WebserviceObject->WebserviceGet( 191 ID => 123, # ID or Name must be provided 192 Name => 'MyWebservice', 193 ); 194 195Returns: 196 197 $Webservice = { 198 ID => 123, 199 Name => 'some name', 200 Config => $ConfigHashRef, 201 ValidID => 123, 202 CreateTime => '2011-02-08 15:08:00', 203 ChangeTime => '2011-02-08 15:08:00', 204 }; 205 206=cut 207 208sub WebserviceGet { 209 my ( $Self, %Param ) = @_; 210 211 # check needed stuff 212 if ( !$Param{ID} && !$Param{Name} ) { 213 $Kernel::OM->Get('Kernel::System::Log')->Log( 214 Priority => 'error', 215 Message => 'Need ID or Name!' 216 ); 217 return; 218 } 219 220 # get cache object 221 my $CacheObject = $Kernel::OM->Get('Kernel::System::Cache'); 222 223 # check cache 224 my $CacheKey; 225 if ( $Param{ID} ) { 226 $CacheKey = 'WebserviceGet::ID::' . $Param{ID}; 227 } 228 else { 229 $CacheKey = 'WebserviceGet::Name::' . $Param{Name}; 230 231 } 232 my $Cache = $CacheObject->Get( 233 Type => 'Webservice', 234 Key => $CacheKey, 235 ); 236 return $Cache if $Cache; 237 238 # get database object 239 my $DBObject = $Kernel::OM->Get('Kernel::System::DB'); 240 241 # sql 242 if ( $Param{ID} ) { 243 return if !$DBObject->Prepare( 244 SQL => 'SELECT id, name, config, valid_id, create_time, change_time ' 245 . 'FROM gi_webservice_config WHERE id = ?', 246 Bind => [ \$Param{ID} ], 247 Limit => 1, 248 ); 249 } 250 else { 251 return if !$DBObject->Prepare( 252 SQL => 'SELECT id, name, config, valid_id, create_time, change_time ' 253 . 'FROM gi_webservice_config WHERE name = ?', 254 Bind => [ \$Param{Name} ], 255 Limit => 1, 256 ); 257 } 258 259 # get yaml object 260 my $YAMLObject = $Kernel::OM->Get('Kernel::System::YAML'); 261 262 my %Data; 263 while ( my @Data = $DBObject->FetchrowArray() ) { 264 265 my $Config = $YAMLObject->Load( Data => $Data[2] ); 266 267 %Data = ( 268 ID => $Data[0], 269 Name => $Data[1], 270 Config => $Config, 271 ValidID => $Data[3], 272 CreateTime => $Data[4], 273 ChangeTime => $Data[5], 274 ); 275 } 276 277 # get the cache TTL (in seconds) 278 my $CacheTTL = int( 279 $Kernel::OM->Get('Kernel::Config')->Get('GenericInterface::WebserviceConfig::CacheTTL') 280 || 3600 281 ); 282 283 # set cache 284 $CacheObject->Set( 285 Type => 'Webservice', 286 Key => $CacheKey, 287 Value => \%Data, 288 TTL => $CacheTTL, 289 ); 290 291 return \%Data; 292} 293 294=head2 WebserviceUpdate() 295 296update web service attributes 297 298returns 1 if successful or undef otherwise 299 300 my $Success = $WebserviceObject->WebserviceUpdate( 301 ID => 123, 302 Name => 'some name', 303 Config => $ConfigHashRef, 304 ValidID => 1, 305 UserID => 123, 306 ); 307 308=cut 309 310sub WebserviceUpdate { 311 my ( $Self, %Param ) = @_; 312 313 # check needed stuff 314 for my $Key (qw(ID Name Config ValidID UserID)) { 315 if ( !$Param{$Key} ) { 316 $Kernel::OM->Get('Kernel::System::Log')->Log( 317 Priority => 'error', 318 Message => "Need $Key!" 319 ); 320 return; 321 } 322 } 323 324 # check config 325 if ( !IsHashRefWithData( $Param{Config} ) ) { 326 $Kernel::OM->Get('Kernel::System::Log')->Log( 327 Priority => 'error', 328 Message => "Web service Config should be a non empty hash reference!", 329 ); 330 return; 331 } 332 333 # check config internals 334 if ( !IsHashRefWithData( $Param{Config}->{Debugger} ) ) { 335 $Kernel::OM->Get('Kernel::System::Log')->Log( 336 Priority => 'error', 337 Message => "Web service Config Debugger should be a non empty hash reference!", 338 ); 339 return; 340 } 341 if ( !IsStringWithData( $Param{Config}->{Debugger}->{DebugThreshold} ) ) { 342 $Kernel::OM->Get('Kernel::System::Log')->Log( 343 Priority => 'error', 344 Message => "Web service Config Debugger DebugThreshold should be a non empty string!", 345 ); 346 return; 347 } 348 if ( !defined $Param{Config}->{Provider} && !defined $Param{Config}->{Requester} ) { 349 $Kernel::OM->Get('Kernel::System::Log')->Log( 350 Priority => 'error', 351 Message => "Web service Config Provider or Requester should be defined!", 352 ); 353 return; 354 } 355 for my $CommunicationType (qw(Provider Requester)) { 356 if ( defined $Param{Config}->{$CommunicationType} ) { 357 if ( !IsHashRefWithData( $Param{Config}->{$CommunicationType} ) ) { 358 $Kernel::OM->Get('Kernel::System::Log')->Log( 359 Priority => 'error', 360 Message => "Web service Config $CommunicationType should be a non empty hash" 361 . " reference!", 362 ); 363 return; 364 } 365 if ( !IsHashRefWithData( $Param{Config}->{$CommunicationType}->{Transport} ) ) { 366 $Kernel::OM->Get('Kernel::System::Log')->Log( 367 Priority => 'error', 368 Message => "Web service Config $CommunicationType Transport should be a" 369 . " non empty hash reference!", 370 ); 371 return; 372 } 373 } 374 } 375 376 # Check if web service is using an old configuration type and upgrade if necessary. 377 $Self->_WebserviceConfigUpgrade(%Param); 378 379 # dump config as string 380 my $Config = $Kernel::OM->Get('Kernel::System::YAML')->Dump( Data => $Param{Config} ); 381 382 # get database object 383 my $DBObject = $Kernel::OM->Get('Kernel::System::DB'); 384 385 # check if config and valid_id is the same 386 return if !$DBObject->Prepare( 387 SQL => 'SELECT config, valid_id, name FROM gi_webservice_config WHERE id = ?', 388 Bind => [ \$Param{ID} ], 389 Limit => 1, 390 ); 391 392 my $ConfigCurrent; 393 my $ValidIDCurrent; 394 my $NameCurrent; 395 while ( my @Data = $DBObject->FetchrowArray() ) { 396 $ConfigCurrent = $Data[0]; 397 $ValidIDCurrent = $Data[1]; 398 $NameCurrent = $Data[2]; 399 } 400 401 return 1 if $ValidIDCurrent eq $Param{ValidID} 402 && $Config eq $ConfigCurrent 403 && $NameCurrent eq $Param{Name}; 404 405 # sql 406 return if !$DBObject->Do( 407 SQL => 'UPDATE gi_webservice_config SET name = ?, config = ?, ' 408 . ' valid_id = ?, change_time = current_timestamp, ' 409 . ' change_by = ? WHERE id = ?', 410 Bind => [ 411 \$Param{Name}, \$Config, \$Param{ValidID}, \$Param{UserID}, 412 \$Param{ID}, 413 ], 414 ); 415 416 # delete cache 417 $Kernel::OM->Get('Kernel::System::Cache')->CleanUp( 418 Type => 'Webservice', 419 ); 420 421 # get web service history object 422 my $WebserviceHistoryObject = $Kernel::OM->Get('Kernel::System::GenericInterface::WebserviceHistory'); 423 424 # add history 425 return if !$WebserviceHistoryObject->WebserviceHistoryAdd( 426 WebserviceID => $Param{ID}, 427 Config => $Param{Config}, 428 UserID => $Param{UserID}, 429 ); 430 431 return 1; 432} 433 434=head2 WebserviceDelete() 435 436delete a Webservice 437 438returns 1 if successful or undef otherwise 439 440 my $Success = $WebserviceObject->WebserviceDelete( 441 ID => 123, 442 UserID => 123, 443 ); 444 445=cut 446 447sub WebserviceDelete { 448 my ( $Self, %Param ) = @_; 449 450 # check needed stuff 451 for my $Key (qw(ID UserID)) { 452 if ( !$Param{$Key} ) { 453 $Kernel::OM->Get('Kernel::System::Log')->Log( 454 Priority => 'error', 455 Message => "Need $Key!" 456 ); 457 return; 458 } 459 } 460 461 # check if exists 462 my $Webservice = $Self->WebserviceGet( 463 ID => $Param{ID}, 464 ); 465 return if !IsHashRefWithData($Webservice); 466 467 # get web service history object 468 my $WebserviceHistoryObject = $Kernel::OM->Get('Kernel::System::GenericInterface::WebserviceHistory'); 469 470 # delete history 471 return if !$WebserviceHistoryObject->WebserviceHistoryDelete( 472 WebserviceID => $Param{ID}, 473 UserID => $Param{UserID}, 474 ); 475 476 # get debug log object 477 my $DebugLogObject = $Kernel::OM->Get('Kernel::System::GenericInterface::DebugLog'); 478 479 # delete debugging data for web service 480 return if !$DebugLogObject->LogDelete( 481 WebserviceID => $Param{ID}, 482 NoErrorIfEmpty => 1, 483 ); 484 485 # delete web service 486 return if !$Kernel::OM->Get('Kernel::System::DB')->Do( 487 SQL => 'DELETE FROM gi_webservice_config WHERE id = ?', 488 Bind => [ \$Param{ID} ], 489 ); 490 491 # delete cache 492 $Kernel::OM->Get('Kernel::System::Cache')->CleanUp( 493 Type => 'Webservice', 494 ); 495 496 return 1; 497} 498 499=head2 WebserviceList() 500 501get web service list 502 503 my $List = $WebserviceObject->WebserviceList(); 504 505 or 506 507 my $List = $WebserviceObject->WebserviceList( 508 Valid => 0, # optional, defaults to 1 509 ); 510 511=cut 512 513sub WebserviceList { 514 my ( $Self, %Param ) = @_; 515 516 # get cache object 517 my $CacheObject = $Kernel::OM->Get('Kernel::System::Cache'); 518 519 # check Valid param 520 my $Valid = ( IsStringWithData( $Param{Valid} ) && $Param{Valid} eq 0 ) ? 0 : 1; 521 522 # check cache 523 my $CacheKey = 'WebserviceList::Valid::' . $Valid; 524 my $Cache = $CacheObject->Get( 525 Type => 'Webservice', 526 Key => $CacheKey, 527 ); 528 return $Cache if ref $Cache; 529 530 my $SQL = 'SELECT id, name FROM gi_webservice_config'; 531 532 if ($Valid) { 533 534 # get valid object 535 my $ValidObject = $Kernel::OM->Get('Kernel::System::Valid'); 536 537 $SQL .= ' WHERE valid_id IN (' . join ', ', $ValidObject->ValidIDsGet() . ')'; 538 } 539 540 # get database object 541 my $DBObject = $Kernel::OM->Get('Kernel::System::DB'); 542 543 return if !$DBObject->Prepare( SQL => $SQL ); 544 545 my %Data; 546 while ( my @Row = $DBObject->FetchrowArray() ) { 547 $Data{ $Row[0] } = $Row[1]; 548 } 549 550 # get the cache TTL (in seconds) 551 my $CacheTTL = int( 552 $Kernel::OM->Get('Kernel::Config')->Get('GenericInterface::WebserviceConfig::CacheTTL') 553 || 3600 554 ); 555 556 # set cache 557 $CacheObject->Set( 558 Type => 'Webservice', 559 Key => $CacheKey, 560 Value => \%Data, 561 TTL => $CacheTTL, 562 ); 563 564 return \%Data; 565} 566 567=begin Internal: 568 569=head2 _WebserviceConfigUpgrade() 570 571Update version if webservice config (e.g. for API changes). 572 573 my $Config = $WebserviceObject->_WebserviceConfigUpgrade( Config => $Config ); 574 575=cut 576 577sub _WebserviceConfigUpgrade { 578 my ( $Self, %Param ) = @_; 579 580 return if !IsHashRefWithData( $Param{Config} ); 581 582 # Updates of SOAP and REST transport in OTRS 6: 583 # Authentication, SSL and Proxy option changes, introduction of timeout param. 584 # Upgrade is considered necessary if the new (and now mandatory) parameter 'Timeout' isn't set. 585 if ( 586 IsHashRefWithData( $Param{Config}->{Requester} ) # prevent creation of dummy elements 587 && IsStringWithData( $Param{Config}->{Requester}->{Transport}->{Type} ) 588 && ( 589 $Param{Config}->{Requester}->{Transport}->{Type} eq 'HTTP::REST' 590 || $Param{Config}->{Requester}->{Transport}->{Type} eq 'HTTP::SOAP' 591 ) 592 && IsHashRefWithData( $Param{Config}->{Requester}->{Transport}->{Config} ) 593 && !IsStringWithData( $Param{Config}->{Requester}->{Transport}->{Config}->{Timeout} ) 594 ) 595 { 596 my $RequesterTransportConfig = $Param{Config}->{Requester}->{Transport}->{Config}; 597 my $RequesterTransportType = $Param{Config}->{Requester}->{Transport}->{Type}; 598 599 # set default timeout 600 if ( $RequesterTransportType eq 'HTTP::SOAP' ) { 601 $RequesterTransportConfig->{Timeout} = 60; 602 } 603 else { 604 $RequesterTransportConfig->{Timeout} = 300; 605 } 606 607 # set default SOAPAction scheme for SOAP 608 if ( 609 $RequesterTransportType eq 'HTTP::SOAP' 610 && IsStringWithData( $RequesterTransportConfig->{SOAPAction} ) 611 && $RequesterTransportConfig->{SOAPAction} eq 'Yes' 612 ) 613 { 614 $RequesterTransportConfig->{SOAPActionScheme} = 'NameSpaceSeparatorOperation'; 615 } 616 617 # convert auth settings 618 my $Authentication = delete $RequesterTransportConfig->{Authentication}; 619 if ( 620 IsHashRefWithData($Authentication) 621 && $Authentication->{Type} 622 && $Authentication->{Type} eq 'BasicAuth' 623 ) 624 { 625 $RequesterTransportConfig->{Authentication} = { 626 AuthType => $Authentication->{Type}, 627 BasicAuthUser => $Authentication->{User}, 628 BasicAuthPassword => $Authentication->{Password}, 629 }; 630 } 631 632 # convert ssl settings 633 my $SSL = delete $RequesterTransportConfig->{SSL}; 634 my $X509 = delete $RequesterTransportConfig->{X509}; 635 if ( 636 $RequesterTransportType eq 'HTTP::SOAP' 637 && IsHashRefWithData($SSL) 638 && $SSL->{UseSSL} 639 && $SSL->{UseSSL} eq 'Yes' 640 ) 641 { 642 $RequesterTransportConfig->{SSL} = { 643 UseSSL => 'Yes', 644 SSLPassword => $SSL->{SSLP12Password}, 645 SSLCertificate => $SSL->{SSLP12Certificate}, 646 SSLCADir => $SSL->{SSLCADir}, 647 SSLCAFile => $SSL->{SSLCAFile}, 648 }; 649 } 650 elsif ( 651 IsHashRefWithData($X509) 652 && $X509->{UseX509} 653 && $X509->{UseX509} eq 'Yes' 654 ) 655 { 656 $RequesterTransportConfig->{SSL} = { 657 UseSSL => 'Yes', 658 SSLKey => $X509->{X509KeyFile}, 659 SSLCertificate => $X509->{X509CertFile}, 660 SSLCAFile => $X509->{X509CAFile}, 661 }; 662 } 663 else { 664 $RequesterTransportConfig->{SSL}->{UseSSL} = 'No'; 665 } 666 667 # convert proxy settings 668 if ( 669 IsHashRefWithData($SSL) 670 && $SSL->{SSLProxy} 671 ) 672 { 673 $RequesterTransportConfig->{Proxy} = { 674 UseProxy => 'Yes', 675 ProxyHost => $SSL->{SSLProxy}, 676 ProxyUser => $SSL->{SSLProxyUser}, 677 ProxyPassword => $SSL->{SSLProxyPassword}, 678 ProxyExclude => 'No', 679 }; 680 } 681 else { 682 $RequesterTransportConfig->{Proxy}->{UseProxy} = 'No'; 683 } 684 685 # set updated config 686 $Param{Config}->{Requester}->{Transport}->{Config} = $RequesterTransportConfig; 687 } 688 689 return 1; 690} 691 6921; 693 694=end Internal: 695 696=head1 TERMS AND CONDITIONS 697 698This software is part of the OTRS project (L<https://otrs.org/>). 699 700This software comes with ABSOLUTELY NO WARRANTY. For details, see 701the enclosed file COPYING for license information (GPL). If you 702did not receive this file, see L<https://www.gnu.org/licenses/gpl-3.0.txt>. 703 704=cut 705