Converts a SAML2 timestamp on the form yyyy-mm-ddThh:mm:ss(\.s+)?Z
to a UNIX timestamp. The sub-second part is ignored.
public static parseSAML2Time ( string $time ) : integer | ||
$time | string | The time we should convert (SAML Timestamp). |
Résultat | integer | $timestamp Converted to a unix timestamp. |
/** * 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; } }
/** * Validates an XML SP Metadata. * * @param string $xml Metadata's XML that will be validate * * @return Array The list of found errors */ public function validateMetadata($xml) { assert('is_string($xml)'); $errors = array(); $res = OneLogin_Saml2_Utils::validateXML($xml, 'saml-schema-metadata-2.0.xsd', $this->_debug); if (!$res instanceof DOMDocument) { $errors[] = $res; } else { $dom = $res; $element = $dom->documentElement; if ($element->tagName !== 'md:EntityDescriptor') { $errors[] = 'noEntityDescriptor_xml'; } else { $validUntil = $cacheDuration = $expireTime = null; if ($element->hasAttribute('validUntil')) { $validUntil = OneLogin_Saml2_Utils::parseSAML2Time($element->getAttribute('validUntil')); } if ($element->hasAttribute('cacheDuration')) { $cacheDuration = $element->getAttribute('cacheDuration'); } $expireTime = OneLogin_Saml2_Utils::getExpireTime($cacheDuration, $validUntil); if (isset($expireTime) && time() > $expireTime) { $errors[] = 'expired_xml'; } } } // TODO: Support Metadata Sign Validation return $errors; }
/** * Tests the parseSAML2Time method of the OneLogin_Saml2_Utils * * @covers OneLogin_Saml2_Utils::parseSAML2Time */ public function testParseSAML2Time() { $time = 1386650371; $SAMLTime = '2013-12-10T04:39:31Z'; $this->assertEquals($time, OneLogin_Saml2_Utils::parseSAML2Time($SAMLTime)); try { OneLogin_Saml2_Utils::parseSAML2Time('invalidSAMLTime'); $this->assertFalse(true); } catch (Exception $e) { $this->assertContains('Invalid SAML2 timestamp passed', $e->getMessage()); } // Now test if toolkit supports miliseconds $SAMLTime2 = '2013-12-10T04:39:31.120Z'; $this->assertEquals($time, OneLogin_Saml2_Utils::parseSAML2Time($SAMLTime2)); }
/** * Gets the SessionNotOnOrAfter from the AuthnStatement. * Could be used to set the local session expiration * * @return DateTime|null The SessionNotOnOrAfter value */ public function getSessionNotOnOrAfter() { $notOnOrAfter = null; $entries = $this->_queryAssertion('/saml:AuthnStatement[@SessionNotOnOrAfter]'); if ($entries->length !== 0) { $notOnOrAfter = OneLogin_Saml2_Utils::parseSAML2Time($entries->item(0)->getAttribute('SessionNotOnOrAfter')); } return $notOnOrAfter; }