File: /home/posscale/subdomains/xibo/vendor/onelogin/php-saml/lib/Saml2/LogoutResponse.php
<?php
/**
* SAML 2 Logout Response
*
*/
class OneLogin_Saml2_LogoutResponse
{
/**
* Object that represents the setting info
* @var OneLogin_Saml2_Settings
*/
protected $_settings;
/**
* The decoded, unprocessed XML response provided to the constructor.
* @var string
*/
protected $_logoutResponse;
/**
* A DOMDocument class loaded from the SAML LogoutResponse.
* @var DomDocument
*/
public $document;
/**
* After execute a validation process, if it fails, this var contains the cause
* @var string
*/
private $_error;
/**
* Constructs a Logout Response object (Initialize params from settings and if provided
* load the Logout Response.
*
* @param OneLogin_Saml2_Settings $settings Settings.
* @param string|null $response An UUEncoded SAML Logout response from the IdP.
*/
public function __construct(OneLogin_Saml2_Settings $settings, $response = null)
{
$this->_settings = $settings;
$baseURL = $this->_settings->getBaseURL();
if (!empty($baseURL)) {
OneLogin_Saml2_Utils::setBaseURL($baseURL);
}
if ($response) {
$decoded = base64_decode($response);
$inflated = @gzinflate($decoded);
if ($inflated != false) {
$this->_logoutResponse = $inflated;
} else {
$this->_logoutResponse = $decoded;
}
$this->document = new DOMDocument();
$this->document = OneLogin_Saml2_Utils::loadXML($this->document, $this->_logoutResponse);
}
}
/**
* Gets the Issuer of the Logout Response.
*
* @return string|null $issuer The Issuer
*/
public function getIssuer()
{
$issuer = null;
$issuerNodes = $this->_query('/samlp:LogoutResponse/saml:Issuer');
if ($issuerNodes->length == 1) {
$issuer = $issuerNodes->item(0)->textContent;
}
return $issuer;
}
/**
* Gets the Status of the Logout Response.
*
* @return string The Status
*/
public function getStatus()
{
$entries = $this->_query('/samlp:LogoutResponse/samlp:Status/samlp:StatusCode');
if ($entries->length != 1) {
return null;
}
$status = $entries->item(0)->getAttribute('Value');
return $status;
}
/**
* Determines if the SAML LogoutResponse is valid
*
* @param string|null $requestId The ID of the LogoutRequest sent by this SP to the IdP
* @param bool $retrieveParametersFromServer
*
* @return bool Returns if the SAML LogoutResponse is or not valid
*
* @throws Exception
*/
public function isValid($requestId = null, $retrieveParametersFromServer=false)
{
$this->_error = null;
try {
$idpData = $this->_settings->getIdPData();
$idPEntityId = $idpData['entityId'];
if ($this->_settings->isStrict()) {
$security = $this->_settings->getSecurityData();
if ($security['wantXMLValidation']) {
$res = OneLogin_Saml2_Utils::validateXML($this->document, 'saml-schema-protocol-2.0.xsd', $this->_settings->isDebugActive());
if (!$res instanceof DOMDocument) {
throw new Exception("Invalid SAML Logout Response. Not match the saml-schema-protocol-2.0.xsd");
}
}
// Check if the InResponseTo of the Logout Response matchs the ID of the Logout Request (requestId) if provided
if (isset($requestId) && $this->document->documentElement->hasAttribute('InResponseTo')) {
$inResponseTo = $this->document->documentElement->getAttribute('InResponseTo');
if ($requestId != $inResponseTo) {
throw new Exception("The InResponseTo of the Logout Response: $inResponseTo, does not match the ID of the Logout request sent by the SP: $requestId");
}
}
// Check issuer
$issuer = $this->getIssuer();
if (!empty($issuer) && $issuer != $idPEntityId) {
throw new Exception("Invalid issuer in the Logout Response");
}
$currentURL = OneLogin_Saml2_Utils::getSelfRoutedURLNoQuery();
// Check destination
if ($this->document->documentElement->hasAttribute('Destination')) {
$destination = $this->document->documentElement->getAttribute('Destination');
if (!empty($destination)) {
if (strpos($destination, $currentURL) === false) {
throw new Exception("The LogoutResponse was received at $currentURL instead of $destination");
}
}
}
if ($security['wantMessagesSigned']) {
if (!isset($_GET['Signature'])) {
throw new Exception("The Message of the Logout Response is not signed and the SP requires it");
}
}
}
if (isset($_GET['Signature'])) {
if (!isset($_GET['SigAlg'])) {
$signAlg = XMLSecurityKey::RSA_SHA1;
} else {
$signAlg = $_GET['SigAlg'];
}
if ($retrieveParametersFromServer) {
$signedQuery = 'SAMLResponse='.OneLogin_Saml2_Utils::extractOriginalQueryParam('SAMLResponse');
if (isset($_GET['RelayState'])) {
$signedQuery .= '&RelayState='.OneLogin_Saml2_Utils::extractOriginalQueryParam('RelayState');
}
$signedQuery .= '&SigAlg='.OneLogin_Saml2_Utils::extractOriginalQueryParam('SigAlg');
} else {
$signedQuery = 'SAMLResponse='.urlencode($_GET['SAMLResponse']);
if (isset($_GET['RelayState'])) {
$signedQuery .= '&RelayState='.urlencode($_GET['RelayState']);
}
$signedQuery .= '&SigAlg='.urlencode($signAlg);
}
if (!isset($idpData['x509cert']) || empty($idpData['x509cert'])) {
throw new Exception('In order to validate the sign on the Logout Response, the x509cert of the IdP is required');
}
$cert = $idpData['x509cert'];
$objKey = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1, array('type' => 'public'));
$objKey->loadKey($cert, false, true);
if ($signAlg != XMLSecurityKey::RSA_SHA1) {
try {
$objKey = OneLogin_Saml2_Utils::castKey($objKey, $signAlg, 'public');
} catch (Exception $e) {
throw new Exception('Invalid signAlg in the recieved Logout Response');
}
}
if (!$objKey->verifySignature($signedQuery, base64_decode($_GET['Signature']))) {
throw new Exception('Signature validation failed. Logout Response rejected');
}
}
return true;
} catch (Exception $e) {
$this->_error = $e->getMessage();
$debug = $this->_settings->isDebugActive();
if ($debug) {
echo $this->_error;
}
return false;
}
}
/**
* Extracts a node from the DOMDocument (Logout Response Menssage)
*
* @param string $query Xpath Expresion
*
* @return DOMNodeList The queried node
*/
private function _query($query)
{
return OneLogin_Saml2_Utils::query($this->document, $query);
}
/**
* Generates a Logout Response object.
*
* @param string $inResponseTo InResponseTo value for the Logout Response.
*/
public function build($inResponseTo)
{
$spData = $this->_settings->getSPData();
$idpData = $this->_settings->getIdPData();
$id = OneLogin_Saml2_Utils::generateUniqueID();
$issueInstant = OneLogin_Saml2_Utils::parseTime2SAML(time());
$logoutResponse = <<<LOGOUTRESPONSE
<samlp:LogoutResponse xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
ID="{$id}"
Version="2.0"
IssueInstant="{$issueInstant}"
Destination="{$idpData['singleLogoutService']['url']}"
InResponseTo="{$inResponseTo}"
>
<saml:Issuer>{$spData['entityId']}</saml:Issuer>
<samlp:Status>
<samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success" />
</samlp:Status>
</samlp:LogoutResponse>
LOGOUTRESPONSE;
$this->_logoutResponse = $logoutResponse;
}
/**
* Returns a Logout Response object.
*
* @param bool|null $deflate Whether or not we should 'gzdeflate' the response body before we return it.
*
* @return string Logout Response deflated and base64 encoded
*/
public function getResponse($deflate = null)
{
$subject = $this->_logoutResponse;
if (is_null($deflate)) {
$deflate = $this->_settings->shouldCompressResponses();
}
if ($deflate) {
$subject = gzdeflate($this->_logoutResponse);
}
return base64_encode($subject);
}
/* After execute a validation process, if fails this method returns the cause.
*
* @return string Cause
*/
public function getError()
{
return $this->_error;
}
}