/** * Validate the signature on a HTTP-Redirect message. * * Throws an exception if we are unable to validate the signature. * * @param array $data The data we need to validate the query string. * @param XMLSecurityKey $key The key we should validate the query against. */ public static function validateSignature(array $data, XMLSecurityKey $key) { assert('array_key_exists("Query", $data)'); assert('array_key_exists("SigAlg", $data)'); assert('array_key_exists("Signature", $data)'); $query = $data['Query']; $sigAlg = $data['SigAlg']; $signature = $data['Signature']; $signature = base64_decode($signature); switch ($sigAlg) { case XMLSecurityKey::RSA_SHA1: if ($key->type !== XMLSecurityKey::RSA_SHA1) { throw new Exception('Invalid key type for validating signature on query string.'); } if (!$key->verifySignature($query, $signature)) { throw new Exception('Unable to validate signature on query string.'); } break; default: throw new Exception('Unknown signature algorithm: ' . var_export($sigAlg, TRUE)); } }
public function validateQuery($issuer, $mode = 'SP', $request = 'SAMLRequest') { $metadataset = 'saml20-idp-remote'; if ($mode == 'IdP') { $metadataset = 'saml20-sp-remote'; } SimpleSAML_Logger::debug('Library - HTTPRedirect validateQuery(): Looking up metadata issuer:' . $issuer . ' in set ' . $metadataset); $md = $this->metadata->getMetaData($issuer, $metadataset); // check whether to validate or not if (!array_key_exists('request.signing', $md) || !$md['request.signing']) { return false; } if (!isset($_GET['Signature'])) { throw new Exception('No Signature on the request, required by configuration'); } SimpleSAML_Logger::debug('Library - HTTPRedirect validateQuery(): All required paramaters received.'); // building query string $query = $request . '=' . urlencode($_GET[$request]); if ($_GET['RelayState']) { $relaystate = $_GET['RelayState']; $query .= "&RelayState=" . urlencode($relaystate); } $algURI = 'http://www.w3.org/2000/09/xmldsig#rsa-sha1'; if (isset($_GET['SigAlg']) && $_GET['SigAlg'] != $algURI) { throw new Exception('Signature must be rsa-sha1 based'); } $query = $query . "&" . "SigAlg=" . urlencode($algURI); SimpleSAML_Logger::debug('Library - HTTPRedirect validateQuery(): Built query: ' . $query); SimpleSAML_Logger::debug('Library - HTTPRedirect validateQuery(): Sig Alg: ' . $algURI); if (empty($md['certificate'])) { throw new Exception('SAML: If you set request.signing to be true in the metadata, you also have to add the certificate parameter.'); } // getting signature from get arguments $signature = @base64_decode($_GET['Signature']); if (!$signature) { throw new Exception('Error base64 decoding signature parameter.'); } // verify signature using xmlseclibs $xmlseckey = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1, array('type' => 'public')); $xmlseckey->loadKey($publickey); if (!$xmlseckey->verifySignature($query, $signature)) { throw new Exception("Unable to validate Signature"); } //signature ok return true; }
/** * Determines if the SAML LogoutResponse is valid * * @param string $requestId The ID of the LogoutRequest sent by this SP to the IdP * * @throws Exception * @return bool Returns if the SAML LogoutResponse is or not valid */ public function isValid($requestId = null) { try { $idpData = $this->_settings->getIdPData(); $idPEntityId = $idpData['entityId']; if ($this->_settings->isStrict()) { $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"); } $security = $this->_settings->getSecurityData(); // 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 Request"); } $currentURL = OneLogin_Saml2_Utils::getSelfURLNoQuery(); // 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 LogoutRequest 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 ($signAlg != XMLSecurityKey::RSA_SHA1) { throw new Exception('Invalid signAlg in the recieved Logout Response'); } $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 (!$objKey->verifySignature($signedQuery, base64_decode($_GET['Signature']))) { throw new Exception('Signature validation failed. Logout Response rejected'); } } return true; } catch (Exception $e) { $debug = $this->_settings->isDebugActive(); if ($debug) { echo $e->getMessage(); } return false; } }
/** * Checks if the Logout Request recieved is valid. * * @param OneLogin_Saml2_Settings $settings Settings * @param string|DOMDocument $request Logout Request decoded * * @return boolean If the Logout Request is or not valid */ public static function isValid(OneLogin_Saml2_Settings $settings, $request, $debug = false) { try { if ($request instanceof DOMDocument) { $dom = $request; } else { $dom = new DOMDocument(); $dom = OneLogin_Saml2_Utils::loadXML($dom, $request); } $idpData = $settings->getIdPData(); $idPEntityId = $idpData['entityId']; if ($settings->isStrict()) { $res = OneLogin_Saml2_Utils::validateXML($dom, 'saml-schema-protocol-2.0.xsd', $debug); if (!$res instanceof DOMDocument) { throw new Exception("Invalid SAML Logout Request. Not match the saml-schema-protocol-2.0.xsd"); } $security = $settings->getSecurityData(); $currentURL = OneLogin_Saml2_Utils::getSelfURLNoQuery(); // Check NotOnOrAfter if ($dom->documentElement->hasAttribute('NotOnOrAfter')) { $na = OneLogin_Saml2_Utils::parseSAML2Time($dom->documentElement->getAttribute('NotOnOrAfter')); if ($na <= time()) { throw new Exception('Timing issues (please check your clock settings)'); } } // Check destination if ($dom->documentElement->hasAttribute('Destination')) { $destination = $dom->documentElement->getAttribute('Destination'); if (!empty($destination)) { if (strpos($destination, $currentURL) === false) { throw new Exception("The LogoutRequest was received at {$currentURL} instead of {$destination}"); } } } $nameId = self::getNameId($dom); // Check issuer $issuer = self::getIssuer($dom); if (empty($issuer) || $issuer != $idPEntityId) { throw new Exception("Invalid issuer in the Logout Request"); } if ($security['wantMessagesSigned']) { if (!isset($_GET['Signature'])) { throw new Exception("The Message of the Logout Request is not signed and the SP require it"); } } } if (isset($_GET['Signature'])) { if (!isset($_GET['SigAlg'])) { $signAlg = XMLSecurityKey::RSA_SHA1; } else { $signAlg = $_GET['SigAlg']; } if ($signAlg != XMLSecurityKey::RSA_SHA1) { throw new Exception('Invalid signAlg in the recieved Logout Request'); } $signedQuery = 'SAMLRequest=' . urlencode($_GET['SAMLRequest']); 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 Request, 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 (!$objKey->verifySignature($signedQuery, base64_decode($_GET['Signature']))) { throw new Exception('Signature validation failed. Logout Request rejected'); } } return true; } catch (Exception $e) { $debug = $settings->isDebugActive(); if ($debug) { echo $e->getMessage(); } return false; } }