1<?php 2/** 3 * This file is part of php-saml. 4 * 5 * (c) OneLogin Inc 6 * 7 * For the full copyright and license information, please view the LICENSE 8 * file that was distributed with this source code. 9 * 10 * @package OneLogin 11 * @author OneLogin Inc <saml-info@onelogin.com> 12 * @license MIT https://github.com/onelogin/php-saml/blob/master/LICENSE 13 * @link https://github.com/onelogin/php-saml 14 */ 15 16namespace OneLogin\Saml2; 17 18use RobRichards\XMLSecLibs\XMLSecurityKey; 19 20use Exception; 21 22/** 23 * Main class of OneLogin's PHP Toolkit 24 */ 25class Auth 26{ 27 /** 28 * Settings data. 29 * 30 * @var Settings 31 */ 32 private $_settings; 33 34 /** 35 * User attributes data. 36 * 37 * @var array 38 */ 39 private $_attributes = array(); 40 41 /** 42 * User attributes data with FriendlyName index. 43 * 44 * @var array 45 */ 46 private $_attributesWithFriendlyName = array(); 47 48 /** 49 * NameID 50 * 51 * @var string 52 */ 53 private $_nameid; 54 55 /** 56 * NameID Format 57 * 58 * @var string 59 */ 60 private $_nameidFormat; 61 62 /** 63 * NameID NameQualifier 64 * 65 * @var string 66 */ 67 private $_nameidNameQualifier; 68 69 /** 70 * NameID SP NameQualifier 71 * 72 * @var string 73 */ 74 private $_nameidSPNameQualifier; 75 76 /** 77 * If user is authenticated. 78 * 79 * @var bool 80 */ 81 private $_authenticated = false; 82 83 84 /** 85 * SessionIndex. When the user is logged, this stored it 86 * from the AuthnStatement of the SAML Response 87 * 88 * @var string 89 */ 90 private $_sessionIndex; 91 92 /** 93 * SessionNotOnOrAfter. When the user is logged, this stored it 94 * from the AuthnStatement of the SAML Response 95 * 96 * @var int|null 97 */ 98 private $_sessionExpiration; 99 100 /** 101 * The ID of the last message processed 102 * 103 * @var string 104 */ 105 private $_lastMessageId; 106 107 /** 108 * The ID of the last assertion processed 109 * 110 * @var string 111 */ 112 private $_lastAssertionId; 113 114 /** 115 * The NotOnOrAfter value of the valid SubjectConfirmationData 116 * node (if any) of the last assertion processed 117 * 118 * @var int 119 */ 120 private $_lastAssertionNotOnOrAfter; 121 122 /** 123 * If any error. 124 * 125 * @var array 126 */ 127 private $_errors = array(); 128 129 /** 130 * Last error object. 131 * 132 * @var Error|null 133 */ 134 private $_lastErrorException; 135 136 /** 137 * Last error. 138 * 139 * @var string|null 140 */ 141 private $_lastError; 142 143 /** 144 * Last AuthNRequest ID or LogoutRequest ID generated by this Service Provider 145 * 146 * @var string 147 */ 148 private $_lastRequestID; 149 150 /** 151 * The most recently-constructed/processed XML SAML request 152 * (AuthNRequest, LogoutRequest) 153 * 154 * @var string 155 */ 156 private $_lastRequest; 157 158 /** 159 * The most recently-constructed/processed XML SAML response 160 * (SAMLResponse, LogoutResponse). If the SAMLResponse was 161 * encrypted, by default tries to return the decrypted XML 162 * 163 * @var string|\DomDocument|null 164 */ 165 private $_lastResponse; 166 167 /** 168 * Initializes the SP SAML instance. 169 * 170 * @param array|null $settings Setting data 171 * 172 * @throws Exception 173 * @throws Error 174 */ 175 public function __construct(array $settings = null) 176 { 177 $this->_settings = new Settings($settings); 178 } 179 180 /** 181 * Returns the settings info 182 * 183 * @return Settings The settings data. 184 */ 185 public function getSettings() 186 { 187 return $this->_settings; 188 } 189 190 /** 191 * Set the strict mode active/disable 192 * 193 * @param bool $value Strict parameter 194 * 195 * @throws Error 196 */ 197 public function setStrict($value) 198 { 199 if (!is_bool($value)) { 200 throw new Error( 201 'Invalid value passed to setStrict()', 202 Error::SETTINGS_INVALID_SYNTAX 203 ); 204 } 205 206 $this->_settings->setStrict($value); 207 } 208 209 /** 210 * Set schemas path 211 * 212 * @param string $path 213 * @return $this 214 */ 215 public function setSchemasPath($path) 216 { 217 $this->_paths['schemas'] = $path; 218 } 219 220 /** 221 * Process the SAML Response sent by the IdP. 222 * 223 * @param string|null $requestId The ID of the AuthNRequest sent by this SP to the IdP 224 * 225 * @throws Error 226 * @throws ValidationError 227 */ 228 public function processResponse($requestId = null) 229 { 230 $this->_errors = array(); 231 $this->_lastError = $this->_lastErrorException = null; 232 if (isset($_POST['SAMLResponse'])) { 233 // AuthnResponse -- HTTP_POST Binding 234 $response = new Response($this->_settings, $_POST['SAMLResponse']); 235 $this->_lastResponse = $response->getXMLDocument(); 236 237 if ($response->isValid($requestId)) { 238 $this->_attributes = $response->getAttributes(); 239 $this->_attributesWithFriendlyName = $response->getAttributesWithFriendlyName(); 240 $this->_nameid = $response->getNameId(); 241 $this->_nameidFormat = $response->getNameIdFormat(); 242 $this->_nameidNameQualifier = $response->getNameIdNameQualifier(); 243 $this->_nameidSPNameQualifier = $response->getNameIdSPNameQualifier(); 244 $this->_authenticated = true; 245 $this->_sessionIndex = $response->getSessionIndex(); 246 $this->_sessionExpiration = $response->getSessionNotOnOrAfter(); 247 $this->_lastMessageId = $response->getId(); 248 $this->_lastAssertionId = $response->getAssertionId(); 249 $this->_lastAssertionNotOnOrAfter = $response->getAssertionNotOnOrAfter(); 250 } else { 251 $this->_errors[] = 'invalid_response'; 252 $this->_lastErrorException = $response->getErrorException(); 253 $this->_lastError = $response->getError(); 254 } 255 } else { 256 $this->_errors[] = 'invalid_binding'; 257 throw new Error( 258 'SAML Response not found, Only supported HTTP_POST Binding', 259 Error::SAML_RESPONSE_NOT_FOUND 260 ); 261 } 262 } 263 264 /** 265 * Process the SAML Logout Response / Logout Request sent by the IdP. 266 * 267 * @param bool $keepLocalSession When false will destroy the local session, otherwise will keep it 268 * @param string|null $requestId The ID of the LogoutRequest sent by this SP to the IdP 269 * @param bool $retrieveParametersFromServer True if we want to use parameters from $_SERVER to validate the signature 270 * @param callable $cbDeleteSession Callback to be executed to delete session 271 * @param bool $stay True if we want to stay (returns the url string) False to redirect 272 * 273 * @return string|null 274 * 275 * @throws Error 276 */ 277 public function processSLO($keepLocalSession = false, $requestId = null, $retrieveParametersFromServer = false, $cbDeleteSession = null, $stay = false) 278 { 279 $this->_errors = array(); 280 $this->_lastError = $this->_lastErrorException = null; 281 if (isset($_GET['SAMLResponse'])) { 282 $logoutResponse = new LogoutResponse($this->_settings, $_GET['SAMLResponse']); 283 $this->_lastResponse = $logoutResponse->getXML(); 284 if (!$logoutResponse->isValid($requestId, $retrieveParametersFromServer)) { 285 $this->_errors[] = 'invalid_logout_response'; 286 $this->_lastErrorException = $logoutResponse->getErrorException(); 287 $this->_lastError = $logoutResponse->getError(); 288 289 } else if ($logoutResponse->getStatus() !== Constants::STATUS_SUCCESS) { 290 $this->_errors[] = 'logout_not_success'; 291 } else { 292 $this->_lastMessageId = $logoutResponse->id; 293 if (!$keepLocalSession) { 294 if ($cbDeleteSession === null) { 295 Utils::deleteLocalSession(); 296 } else { 297 call_user_func($cbDeleteSession); 298 } 299 } 300 } 301 } else if (isset($_GET['SAMLRequest'])) { 302 $logoutRequest = new LogoutRequest($this->_settings, $_GET['SAMLRequest']); 303 $this->_lastRequest = $logoutRequest->getXML(); 304 if (!$logoutRequest->isValid($retrieveParametersFromServer)) { 305 $this->_errors[] = 'invalid_logout_request'; 306 $this->_lastErrorException = $logoutRequest->getErrorException(); 307 $this->_lastError = $logoutRequest->getError(); 308 } else { 309 if (!$keepLocalSession) { 310 if ($cbDeleteSession === null) { 311 Utils::deleteLocalSession(); 312 } else { 313 call_user_func($cbDeleteSession); 314 } 315 } 316 $inResponseTo = $logoutRequest->id; 317 $this->_lastMessageId = $logoutRequest->id; 318 $responseBuilder = new LogoutResponse($this->_settings); 319 $responseBuilder->build($inResponseTo); 320 $this->_lastResponse = $responseBuilder->getXML(); 321 322 $logoutResponse = $responseBuilder->getResponse(); 323 324 $parameters = array('SAMLResponse' => $logoutResponse); 325 if (isset($_GET['RelayState'])) { 326 $parameters['RelayState'] = $_GET['RelayState']; 327 } 328 329 $security = $this->_settings->getSecurityData(); 330 if (isset($security['logoutResponseSigned']) && $security['logoutResponseSigned']) { 331 $signature = $this->buildResponseSignature($logoutResponse, isset($parameters['RelayState'])? $parameters['RelayState']: null, $security['signatureAlgorithm']); 332 $parameters['SigAlg'] = $security['signatureAlgorithm']; 333 $parameters['Signature'] = $signature; 334 } 335 336 return $this->redirectTo($this->getSLOResponseUrl(), $parameters, $stay); 337 } 338 } else { 339 $this->_errors[] = 'invalid_binding'; 340 throw new Error( 341 'SAML LogoutRequest/LogoutResponse not found. Only supported HTTP_REDIRECT Binding', 342 Error::SAML_LOGOUTMESSAGE_NOT_FOUND 343 ); 344 } 345 } 346 347 /** 348 * Redirects the user to the url past by parameter 349 * or to the url that we defined in our SSO Request. 350 * 351 * @param string $url The target URL to redirect the user. 352 * @param array $parameters Extra parameters to be passed as part of the url 353 * @param bool $stay True if we want to stay (returns the url string) False to redirect 354 * 355 * @return string|null 356 */ 357 public function redirectTo($url = '', array $parameters = array(), $stay = false) 358 { 359 assert(is_string($url)); 360 361 if (empty($url) && isset($_REQUEST['RelayState'])) { 362 $url = $_REQUEST['RelayState']; 363 } 364 365 return Utils::redirect($url, $parameters, $stay); 366 } 367 368 /** 369 * Checks if the user is authenticated or not. 370 * 371 * @return bool True if the user is authenticated 372 */ 373 public function isAuthenticated() 374 { 375 return $this->_authenticated; 376 } 377 378 /** 379 * Returns the set of SAML attributes. 380 * 381 * @return array Attributes of the user. 382 */ 383 public function getAttributes() 384 { 385 return $this->_attributes; 386 } 387 388 389 /** 390 * Returns the set of SAML attributes indexed by FriendlyName 391 * 392 * @return array Attributes of the user. 393 */ 394 public function getAttributesWithFriendlyName() 395 { 396 return $this->_attributesWithFriendlyName; 397 } 398 399 /** 400 * Returns the nameID 401 * 402 * @return string The nameID of the assertion 403 */ 404 public function getNameId() 405 { 406 return $this->_nameid; 407 } 408 409 /** 410 * Returns the nameID Format 411 * 412 * @return string The nameID Format of the assertion 413 */ 414 public function getNameIdFormat() 415 { 416 return $this->_nameidFormat; 417 } 418 419 /** 420 * Returns the nameID NameQualifier 421 * 422 * @return string The nameID NameQualifier of the assertion 423 */ 424 public function getNameIdNameQualifier() 425 { 426 return $this->_nameidNameQualifier; 427 } 428 429 /** 430 * Returns the nameID SP NameQualifier 431 * 432 * @return string The nameID SP NameQualifier of the assertion 433 */ 434 public function getNameIdSPNameQualifier() 435 { 436 return $this->_nameidSPNameQualifier; 437 } 438 439 /** 440 * Returns the SessionIndex 441 * 442 * @return string|null The SessionIndex of the assertion 443 */ 444 public function getSessionIndex() 445 { 446 return $this->_sessionIndex; 447 } 448 449 /** 450 * Returns the SessionNotOnOrAfter 451 * 452 * @return int|null The SessionNotOnOrAfter of the assertion 453 */ 454 public function getSessionExpiration() 455 { 456 return $this->_sessionExpiration; 457 } 458 459 /** 460 * Returns if there were any error 461 * 462 * @return array Errors 463 */ 464 public function getErrors() 465 { 466 return $this->_errors; 467 } 468 469 /** 470 * Returns the reason for the last error 471 * 472 * @return string|null Error reason 473 */ 474 public function getLastErrorReason() 475 { 476 return $this->_lastError; 477 } 478 479 480 /** 481 * Returns the last error 482 * 483 * @return Exception|null Error 484 */ 485 public function getLastErrorException() 486 { 487 return $this->_lastErrorException; 488 } 489 490 /** 491 * Returns the requested SAML attribute 492 * 493 * @param string $name The requested attribute of the user. 494 * 495 * @return array|null Requested SAML attribute ($name). 496 */ 497 public function getAttribute($name) 498 { 499 assert(is_string($name)); 500 501 $value = null; 502 if (isset($this->_attributes[$name])) { 503 return $this->_attributes[$name]; 504 } 505 return $value; 506 } 507 508 /** 509 * Returns the requested SAML attribute indexed by FriendlyName 510 * 511 * @param string $friendlyName The requested attribute of the user. 512 * 513 * @return array|null Requested SAML attribute ($friendlyName). 514 */ 515 public function getAttributeWithFriendlyName($friendlyName) 516 { 517 assert(is_string($friendlyName)); 518 $value = null; 519 if (isset($this->_attributesWithFriendlyName[$friendlyName])) { 520 return $this->_attributesWithFriendlyName[$friendlyName]; 521 } 522 return $value; 523 } 524 525 /** 526 * Initiates the SSO process. 527 * 528 * @param string|null $returnTo The target URL the user should be returned to after login. 529 * @param array $parameters Extra parameters to be added to the GET 530 * @param bool $forceAuthn When true the AuthNRequest will set the ForceAuthn='true' 531 * @param bool $isPassive When true the AuthNRequest will set the Ispassive='true' 532 * @param bool $stay True if we want to stay (returns the url string) False to redirect 533 * @param bool $setNameIdPolicy When true the AuthNRequest will set a nameIdPolicy element 534 * @param string $nameIdValueReq Indicates to the IdP the subject that should be authenticated 535 * 536 * @return string|null If $stay is True, it return a string with the SLO URL + LogoutRequest + parameters 537 * 538 * @throws Error 539 */ 540 public function login($returnTo = null, array $parameters = array(), $forceAuthn = false, $isPassive = false, $stay = false, $setNameIdPolicy = true, $nameIdValueReq = null) 541 { 542 $authnRequest = $this->buildAuthnRequest($this->_settings, $forceAuthn, $isPassive, $setNameIdPolicy, $nameIdValueReq); 543 544 $this->_lastRequest = $authnRequest->getXML(); 545 $this->_lastRequestID = $authnRequest->getId(); 546 547 $samlRequest = $authnRequest->getRequest(); 548 $parameters['SAMLRequest'] = $samlRequest; 549 550 if (!empty($returnTo)) { 551 $parameters['RelayState'] = $returnTo; 552 } else { 553 $parameters['RelayState'] = Utils::getSelfRoutedURLNoQuery(); 554 } 555 556 $security = $this->_settings->getSecurityData(); 557 if (isset($security['authnRequestsSigned']) && $security['authnRequestsSigned']) { 558 $signature = $this->buildRequestSignature($samlRequest, $parameters['RelayState'], $security['signatureAlgorithm']); 559 $parameters['SigAlg'] = $security['signatureAlgorithm']; 560 $parameters['Signature'] = $signature; 561 } 562 return $this->redirectTo($this->getSSOurl(), $parameters, $stay); 563 } 564 565 /** 566 * Initiates the SLO process. 567 * 568 * @param string|null $returnTo The target URL the user should be returned to after logout. 569 * @param array $parameters Extra parameters to be added to the GET 570 * @param string|null $nameId The NameID that will be set in the LogoutRequest. 571 * @param string|null $sessionIndex The SessionIndex (taken from the SAML Response in the SSO process). 572 * @param bool $stay True if we want to stay (returns the url string) False to redirect 573 * @param string|null $nameIdFormat The NameID Format will be set in the LogoutRequest. 574 * @param string|null $nameIdNameQualifier The NameID NameQualifier will be set in the LogoutRequest. 575 * 576 * @return string|null If $stay is True, it return a string with the SLO URL + LogoutRequest + parameters 577 * 578 * @throws Error 579 */ 580 public function logout($returnTo = null, array $parameters = array(), $nameId = null, $sessionIndex = null, $stay = false, $nameIdFormat = null, $nameIdNameQualifier = null, $nameIdSPNameQualifier = null) 581 { 582 $sloUrl = $this->getSLOurl(); 583 if (empty($sloUrl)) { 584 throw new Error( 585 'The IdP does not support Single Log Out', 586 Error::SAML_SINGLE_LOGOUT_NOT_SUPPORTED 587 ); 588 } 589 590 if (empty($nameId) && !empty($this->_nameid)) { 591 $nameId = $this->_nameid; 592 } 593 if (empty($nameIdFormat) && !empty($this->_nameidFormat)) { 594 $nameIdFormat = $this->_nameidFormat; 595 } 596 597 $logoutRequest = new LogoutRequest($this->_settings, null, $nameId, $sessionIndex, $nameIdFormat, $nameIdNameQualifier, $nameIdSPNameQualifier); 598 599 $this->_lastRequest = $logoutRequest->getXML(); 600 $this->_lastRequestID = $logoutRequest->id; 601 602 $samlRequest = $logoutRequest->getRequest(); 603 604 $parameters['SAMLRequest'] = $samlRequest; 605 if (!empty($returnTo)) { 606 $parameters['RelayState'] = $returnTo; 607 } else { 608 $parameters['RelayState'] = Utils::getSelfRoutedURLNoQuery(); 609 } 610 611 $security = $this->_settings->getSecurityData(); 612 if (isset($security['logoutRequestSigned']) && $security['logoutRequestSigned']) { 613 $signature = $this->buildRequestSignature($samlRequest, $parameters['RelayState'], $security['signatureAlgorithm']); 614 $parameters['SigAlg'] = $security['signatureAlgorithm']; 615 $parameters['Signature'] = $signature; 616 } 617 618 return $this->redirectTo($sloUrl, $parameters, $stay); 619 } 620 621 /** 622 * Gets the SSO url. 623 * 624 * @return string The url of the Single Sign On Service 625 */ 626 public function getSSOurl() 627 { 628 $idpData = $this->_settings->getIdPData(); 629 return $idpData['singleSignOnService']['url']; 630 } 631 632 /** 633 * Gets the SLO url. 634 * 635 * @return string|null The url of the Single Logout Service 636 */ 637 public function getSLOurl() 638 { 639 $url = null; 640 $idpData = $this->_settings->getIdPData(); 641 if (isset($idpData['singleLogoutService']) && isset($idpData['singleLogoutService']['url'])) { 642 $url = $idpData['singleLogoutService']['url']; 643 } 644 return $url; 645 } 646 647 /** 648 * Gets the SLO response url. 649 * 650 * @return string|null The response url of the Single Logout Service 651 */ 652 public function getSLOResponseUrl() 653 { 654 $idpData = $this->_settings->getIdPData(); 655 if (isset($idpData['singleLogoutService']) && isset($idpData['singleLogoutService']['responseUrl'])) { 656 return $idpData['singleLogoutService']['responseUrl']; 657 } 658 return $this->getSLOurl(); 659 } 660 661 /** 662 * Gets the ID of the last AuthNRequest or LogoutRequest generated by the Service Provider. 663 * 664 * @return string The ID of the Request SAML message. 665 */ 666 public function getLastRequestID() 667 { 668 return $this->_lastRequestID; 669 } 670 671 /** 672 * Creates an AuthnRequest 673 * 674 * @param Settings $settings Setting data 675 * @param bool $forceAuthn When true the AuthNRequest will set the ForceAuthn='true' 676 * @param bool $isPassive When true the AuthNRequest will set the Ispassive='true' 677 * @param bool $setNameIdPolicy When true the AuthNRequest will set a nameIdPolicy element 678 * @param string $nameIdValueReq Indicates to the IdP the subject that should be authenticated 679 * 680 * @return AuthnRequest The AuthnRequest object 681 */ 682 public function buildAuthnRequest($settings, $forceAuthn, $isPassive, $setNameIdPolicy, $nameIdValueReq = null) 683 { 684 return new AuthnRequest($settings, $forceAuthn, $isPassive, $setNameIdPolicy, $nameIdValueReq); 685 } 686 687 /** 688 * Generates the Signature for a SAML Request 689 * 690 * @param string $samlRequest The SAML Request 691 * @param string $relayState The RelayState 692 * @param string $signAlgorithm Signature algorithm method 693 * 694 * @return string A base64 encoded signature 695 * 696 * @throws Exception 697 * @throws Error 698 */ 699 public function buildRequestSignature($samlRequest, $relayState, $signAlgorithm = XMLSecurityKey::RSA_SHA256) 700 { 701 return $this->buildMessageSignature($samlRequest, $relayState, $signAlgorithm, "SAMLRequest"); 702 } 703 704 /** 705 * Generates the Signature for a SAML Response 706 * 707 * @param string $samlResponse The SAML Response 708 * @param string $relayState The RelayState 709 * @param string $signAlgorithm Signature algorithm method 710 * 711 * @return string A base64 encoded signature 712 * 713 * @throws Exception 714 * @throws Error 715 */ 716 public function buildResponseSignature($samlResponse, $relayState, $signAlgorithm = XMLSecurityKey::RSA_SHA256) 717 { 718 return $this->buildMessageSignature($samlResponse, $relayState, $signAlgorithm, "SAMLResponse"); 719 } 720 721 /** 722 * Generates the Signature for a SAML Message 723 * 724 * @param string $samlMessage The SAML Message 725 * @param string $relayState The RelayState 726 * @param string $signAlgorithm Signature algorithm method 727 * @param string $type "SAMLRequest" or "SAMLResponse" 728 * 729 * @return string A base64 encoded signature 730 * 731 * @throws Exception 732 * @throws Error 733 */ 734 private function buildMessageSignature($samlMessage, $relayState, $signAlgorithm = XMLSecurityKey::RSA_SHA256, $type = "SAMLRequest") 735 { 736 $key = $this->_settings->getSPkey(); 737 if (empty($key)) { 738 if ($type == "SAMLRequest") { 739 $errorMsg = "Trying to sign the SAML Request but can't load the SP private key"; 740 } else { 741 $errorMsg = "Trying to sign the SAML Response but can't load the SP private key"; 742 } 743 744 throw new Error($errorMsg, Error::PRIVATE_KEY_NOT_FOUND); 745 } 746 747 $objKey = new XMLSecurityKey($signAlgorithm, array('type' => 'private')); 748 $objKey->loadKey($key, false); 749 750 $security = $this->_settings->getSecurityData(); 751 if ($security['lowercaseUrlencoding']) { 752 $msg = $type.'='.rawurlencode($samlMessage); 753 if (isset($relayState)) { 754 $msg .= '&RelayState='.rawurlencode($relayState); 755 } 756 $msg .= '&SigAlg=' . rawurlencode($signAlgorithm); 757 } else { 758 $msg = $type.'='.urlencode($samlMessage); 759 if (isset($relayState)) { 760 $msg .= '&RelayState='.urlencode($relayState); 761 } 762 $msg .= '&SigAlg=' . urlencode($signAlgorithm); 763 } 764 $signature = $objKey->signData($msg); 765 return base64_encode($signature); 766 } 767 768 /** 769 * @return string The ID of the last message processed 770 */ 771 public function getLastMessageId() 772 { 773 return $this->_lastMessageId; 774 } 775 776 /** 777 * @return string The ID of the last assertion processed 778 */ 779 public function getLastAssertionId() 780 { 781 return $this->_lastAssertionId; 782 } 783 784 /** 785 * @return int The NotOnOrAfter value of the valid 786 * SubjectConfirmationData node (if any) 787 * of the last assertion processed 788 */ 789 public function getLastAssertionNotOnOrAfter() 790 { 791 return $this->_lastAssertionNotOnOrAfter; 792 } 793 794 /** 795 * Returns the most recently-constructed/processed 796 * XML SAML request (AuthNRequest, LogoutRequest) 797 * 798 * @return string|null The Request XML 799 */ 800 public function getLastRequestXML() 801 { 802 return $this->_lastRequest; 803 } 804 805 /** 806 * Returns the most recently-constructed/processed 807 * XML SAML response (SAMLResponse, LogoutResponse). 808 * If the SAMLResponse was encrypted, by default tries 809 * to return the decrypted XML. 810 * 811 * @return string|null The Response XML 812 */ 813 public function getLastResponseXML() 814 { 815 $response = null; 816 if (isset($this->_lastResponse)) { 817 if (is_string($this->_lastResponse)) { 818 $response = $this->_lastResponse; 819 } else { 820 $response = $this->_lastResponse->saveXML(); 821 } 822 } 823 824 return $response; 825 } 826} 827