loadXML() public static method

Prevent XEE/XXE Attacks
public static loadXML ( DOMDocument $dom, string $xml ) : DOMDocument
$dom DOMDocument The document where load the xml.
$xml string The XML string to be loaded.
return DOMDocument $dom The result of load the XML at the DomDocument
Example #1
0
 /**
  * Tests the loadXML method of the OneLogin_Saml2_Utils
  *
  * @covers OneLogin_Saml2_Utils::loadXML
  */
 public function testXMLAttacks()
 {
     $dom = new DOMDocument();
     $attackXXE = '<?xml version="1.0" encoding="ISO-8859-1"?>
                   <!DOCTYPE foo [  
                   <!ELEMENT foo ANY >
                   <!ENTITY xxe SYSTEM "file:///etc/passwd" >]><foo>&xxe;</foo>';
     try {
         $res = OneLogin_Saml2_Utils::loadXML($dom, $attackXXE);
         $this->assertTrue(false);
     } catch (Exception $e) {
         $this->assertEquals('Detected use of ENTITY in XML, disabled to prevent XXE/XEE attacks', $e->getMessage());
     }
     $xmlWithDTD = '<?xml version="1.0"?>
                       <!DOCTYPE results [
                         <!ELEMENT results (result+)>
                         <!ELEMENT result (#PCDATA)>
                       ]>
                       <results>
                         <result>test</result>
                       </results>';
     $res2 = OneLogin_Saml2_Utils::loadXML($dom, $xmlWithDTD);
     $this->assertTrue($res2 instanceof DOMDocument);
     $attackXEE = '<?xml version="1.0"?>
                   <!DOCTYPE results [<!ENTITY harmless "completely harmless">]>
                   <results>
                     <result>This result is &harmless;</result>
                   </results>';
     try {
         $res3 = OneLogin_Saml2_Utils::loadXML($dom, $attackXEE);
         $this->assertTrue(false);
     } catch (Exception $e) {
         $this->assertEquals('Detected use of ENTITY in XML, disabled to prevent XXE/XEE attacks', $e->getMessage());
     }
 }
Example #2
0
 /**
  * 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;
     if ($response) {
         $decoded = base64_decode($response);
         $this->_logoutResponse = gzinflate($decoded);
         $this->document = new DOMDocument();
         $this->document = OneLogin_Saml2_Utils::loadXML($this->document, $this->_logoutResponse);
     }
 }
Example #3
0
 /**
  * Constructs the SAML Response object.
  *
  * @param OneLogin_Saml2_Settings $settings Settings.
  * @param string                  $response A UUEncoded SAML response from the IdP.
  */
 public function __construct(OneLogin_Saml2_Settings $settings, $response)
 {
     $this->_settings = $settings;
     $this->response = base64_decode($response);
     $this->document = new DOMDocument();
     $this->document = OneLogin_Saml2_Utils::loadXML($this->document, $this->response);
     // Quick check for the presence of EncryptedAssertion
     $encryptedAssertionNodes = $this->document->getElementsByTagName('EncryptedAssertion');
     if ($encryptedAssertionNodes->length !== 0) {
         $this->decryptedDocument = clone $this->document;
         $this->encrypted = true;
         $this->_decryptAssertion($this->decryptedDocument);
     }
 }
Example #4
0
 /**
  * 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);
     }
 }
Example #5
0
 /**
  * Constructs the SAML Response object.
  *
  * @param OneLogin_Saml2_Settings $settings Settings.
  * @param string                  $response A UUEncoded SAML response from the IdP.
  */
 public function __construct(OneLogin_Saml2_Settings $settings, $response)
 {
     $this->_settings = $settings;
     $this->response = base64_decode($response);
     $this->document = new DOMDocument();
     echo "1********<br />";
     print_r($this->document);
     echo "2********<br />";
     $this->document = OneLogin_Saml2_Utils::loadXML($this->document, $this->response);
     if (!$this->document) {
         throw new Exception('SAML Response could not be processed');
     }
     // Quick check for the presence of EncryptedAssertion
     $encryptedAssertionNodes = $this->document->getElementsByTagName('EncryptedAssertion');
     if ($encryptedAssertionNodes->length !== 0) {
         $this->decryptedDocument = clone $this->document;
         $this->encrypted = true;
         $this->_decryptAssertion($this->decryptedDocument);
     }
 }
Example #6
0
 /**
  * Checks if the Logout Request recieved is valid.
  *
  * @return boolean If the Logout Request is or not valid
  */
 public function isValid($retrieveParametersFromServer = false)
 {
     $this->_error = null;
     try {
         $dom = new DOMDocument();
         $dom = OneLogin_Saml2_Utils::loadXML($dom, $this->_logoutRequest);
         $idpData = $this->_settings->getIdPData();
         $idPEntityId = $idpData['entityId'];
         if ($this->_settings->isStrict()) {
             $security = $this->_settings->getSecurityData();
             if ($security['wantXMLValidation']) {
                 $res = OneLogin_Saml2_Utils::validateXML($dom, 'saml-schema-protocol-2.0.xsd', $this->_settings->isDebugActive());
                 if (!$res instanceof DOMDocument) {
                     throw new Exception("Invalid SAML Logout Request. Not match the saml-schema-protocol-2.0.xsd");
                 }
             }
             $currentURL = OneLogin_Saml2_Utils::getSelfRoutedURLNoQuery();
             // 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 = $this->getNameId($dom, $this->_settings->getSPkey());
             // Check issuer
             $issuer = $this->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 ($retrieveParametersFromServer) {
                 $signedQuery = 'SAMLRequest=' . OneLogin_Saml2_Utils::extractOriginalQueryParam('SAMLRequest');
                 if (isset($_GET['RelayState'])) {
                     $signedQuery .= '&RelayState=' . OneLogin_Saml2_Utils::extractOriginalQueryParam('RelayState');
                 }
                 $signedQuery .= '&SigAlg=' . OneLogin_Saml2_Utils::extractOriginalQueryParam('SigAlg');
             } else {
                 $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 ($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 Request');
                 }
             }
             if (!$objKey->verifySignature($signedQuery, base64_decode($_GET['Signature']))) {
                 throw new Exception('Signature validation failed. Logout Request rejected');
             }
         }
         return true;
     } catch (Exception $e) {
         $this->_error = $e->getMessage();
         $debug = $this->_settings->isDebugActive();
         if ($debug) {
             echo $this->_error;
         }
         return false;
     }
 }
Example #7
0
 /**
  * Tests the validateXML method of the OneLogin_Saml2_Utils
  *
  * @covers OneLogin_Saml2_Utils::validateXML
  */
 public function testValidateXML()
 {
     $metadataUnloaded = '<xml><EntityDescriptor>';
     $this->assertEquals(OneLogin_Saml2_Utils::validateXML($metadataUnloaded, 'saml-schema-metadata-2.0.xsd'), 'unloaded_xml');
     $metadataInvalid = file_get_contents(TEST_ROOT . '/data/metadata/noentity_metadata_settings1.xml');
     $this->assertEquals(OneLogin_Saml2_Utils::validateXML($metadataInvalid, 'saml-schema-metadata-2.0.xsd'), 'invalid_xml');
     $metadataExpired = file_get_contents(TEST_ROOT . '/data/metadata/expired_metadata_settings1.xml');
     $res = OneLogin_Saml2_Utils::validateXML($metadataExpired, 'saml-schema-metadata-2.0.xsd');
     $this->assertTrue($res instanceof DOMDocument);
     $metadataOk = file_get_contents(TEST_ROOT . '/data/metadata/metadata_settings1.xml');
     $res2 = OneLogin_Saml2_Utils::validateXML($metadataOk, 'saml-schema-metadata-2.0.xsd');
     $this->assertTrue($res2 instanceof DOMDocument);
     $metadataBadOrder = file_get_contents(TEST_ROOT . '/data/metadata/metadata_bad_order_settings1.xml');
     $res3 = OneLogin_Saml2_Utils::validateXML($metadataBadOrder, 'saml-schema-metadata-2.0.xsd');
     $this->assertFalse($res3 instanceof DOMDocument);
     $metadataSigned = file_get_contents(TEST_ROOT . '/data/metadata/signed_metadata_settings1.xml');
     $res4 = OneLogin_Saml2_Utils::validateXML($metadataSigned, 'saml-schema-metadata-2.0.xsd');
     $this->assertTrue($res4 instanceof DOMDocument);
     $dom = new DOMDocument();
     OneLogin_Saml2_Utils::loadXML($dom, $metadataOk);
     $res5 = OneLogin_Saml2_Utils::validateXML($dom, 'saml-schema-metadata-2.0.xsd');
     $this->assertTrue($res5 instanceof DOMDocument);
 }
Example #8
0
 /**
  * Adds the x509 descriptors (sign/encriptation) to the metadata
  * The same cert will be used for sign/encrypt
  *
  * @param string $metadata SAML Metadata XML
  * @param string $cert     x509 cert
  *
  * @return string Metadata with KeyDescriptors
  */
 public static function addX509KeyDescriptors($metadata, $cert)
 {
     $xml = new DOMDocument();
     $xml->preserveWhiteSpace = false;
     $xml->formatOutput = true;
     try {
         $xml = OneLogin_Saml2_Utils::loadXML($xml, $metadata);
         if (!$xml) {
             throw new Exception('Error parsing metadata');
         }
     } catch (Exception $e) {
         throw new Exception('Error parsing metadata. ' . $e->getMessage());
     }
     $formatedCert = OneLogin_Saml2_Utils::formatCert($cert, false);
     $x509Certificate = $xml->createElementNS(OneLogin_Saml2_Constants::NS_DS, 'X509Certificate', $formatedCert);
     $keyData = $xml->createElementNS(OneLogin_Saml2_Constants::NS_DS, 'ds:X509Data');
     $keyData->appendChild($x509Certificate);
     $keyInfo = $xml->createElementNS(OneLogin_Saml2_Constants::NS_DS, 'ds:KeyInfo');
     $keyInfo->appendChild($keyData);
     $keyDescriptor = $xml->createElementNS(OneLogin_Saml2_Constants::NS_MD, "md:KeyDescriptor");
     $SPSSODescriptor = $xml->getElementsByTagName('SPSSODescriptor')->item(0);
     $SPSSODescriptor->insertBefore($keyDescriptor->cloneNode(), $SPSSODescriptor->firstChild);
     $SPSSODescriptor->insertBefore($keyDescriptor->cloneNode(), $SPSSODescriptor->firstChild);
     $signing = $xml->getElementsByTagName('KeyDescriptor')->item(0);
     $signing->setAttribute('use', 'signing');
     $encryption = $xml->getElementsByTagName('KeyDescriptor')->item(1);
     $encryption->setAttribute('use', 'encryption');
     $signing->appendChild($keyInfo);
     $encryption->appendChild($keyInfo->cloneNode(true));
     return $xml->saveXML();
 }