/** * Constructs the Logout Request object. * * @param OneLogin_Saml2_Settings $settings Settings */ public function __construct(OneLogin_Saml2_Settings $settings) { $this->_settings = $settings; $spData = $this->_settings->getSPData(); $idpData = $this->_settings->getIdPData(); $security = $this->_settings->getSecurityData(); $id = OneLogin_Saml2_Utils::generateUniqueID(); $nameIdValue = OneLogin_Saml2_Utils::generateUniqueID(); $issueInstant = OneLogin_Saml2_Utils::parseTime2SAML(time()); $key = null; if (isset($security['nameIdEncrypted']) && $security['nameIdEncrypted']) { $key = $idpData['x509cert']; } $nameId = OneLogin_Saml2_Utils::generateNameId($nameIdValue, $spData['entityId'], $spData['NameIDFormat'], $key); $logoutRequest = <<<LOGOUTREQUEST <samlp:LogoutRequest 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']}"> <saml:Issuer>{$spData['entityId']}</saml:Issuer> {$nameId} </samlp:LogoutRequest> LOGOUTREQUEST; $this->_logoutRequest = $logoutRequest; }
/** * Constructs the Logout Request object. * * @param OneLogin_Saml2_Settings $settings Settings * @param string|null $request A UUEncoded Logout Request. * @param string|null $nameId The NameID that will be set in the LogoutRequest. * @param string|null $sessionIndex The SessionIndex (taken from the SAML Response in the SSO process). * @param string|null $nameIdFormat The NameID Format will be set in the LogoutRequest. */ public function __construct(OneLogin_Saml2_Settings $settings, $request = null, $nameId = null, $sessionIndex = null, $nameIdFormat = null) { $this->_settings = $settings; $baseURL = $this->_settings->getBaseURL(); if (!empty($baseURL)) { OneLogin_Saml2_Utils::setBaseURL($baseURL); } if (!isset($request) || empty($request)) { $spData = $this->_settings->getSPData(); $idpData = $this->_settings->getIdPData(); $security = $this->_settings->getSecurityData(); $id = OneLogin_Saml2_Utils::generateUniqueID(); $this->id = $id; $nameIdValue = OneLogin_Saml2_Utils::generateUniqueID(); $issueInstant = OneLogin_Saml2_Utils::parseTime2SAML(time()); $cert = null; if (isset($security['nameIdEncrypted']) && $security['nameIdEncrypted']) { $cert = $idpData['x509cert']; } if (!empty($nameId)) { if (empty($nameIdFormat)) { $nameIdFormat = $spData['NameIDFormat']; } $spNameQualifier = null; } else { $nameId = $idpData['entityId']; $nameIdFormat = OneLogin_Saml2_Constants::NAMEID_ENTITY; $spNameQualifier = $spData['entityId']; } $nameIdObj = OneLogin_Saml2_Utils::generateNameId($nameId, $spNameQualifier, $nameIdFormat, $cert); $sessionIndexStr = isset($sessionIndex) ? "<samlp:SessionIndex>{$sessionIndex}</samlp:SessionIndex>" : ""; $logoutRequest = <<<LOGOUTREQUEST <samlp:LogoutRequest 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']}"> <saml:Issuer>{$spData['entityId']}</saml:Issuer> {$nameIdObj} {$sessionIndexStr} </samlp:LogoutRequest> LOGOUTREQUEST; } else { $decoded = base64_decode($request); // We try to inflate $inflated = @gzinflate($decoded); if ($inflated != false) { $logoutRequest = $inflated; } else { $logoutRequest = $decoded; } $this->id = self::getID($logoutRequest); } $this->_logoutRequest = $logoutRequest; }
/** * Constructs the AuthnRequest object. * * @param OneLogin_Saml2_Settings $settings Settings */ public function __construct(OneLogin_Saml2_Settings $settings) { $this->_settings = $settings; $spData = $this->_settings->getSPData(); $idpData = $this->_settings->getIdPData(); $security = $this->_settings->getSecurityData(); $id = OneLogin_Saml2_Utils::generateUniqueID(); $issueInstant = OneLogin_Saml2_Utils::parseTime2SAML(time()); $nameIDPolicyFormat = $spData['NameIDFormat']; if (isset($security['wantNameIdEncrypted']) && $security['wantNameIdEncrypted']) { $nameIDPolicyFormat = OneLogin_Saml2_Constants::NAMEID_ENCRYPTED; } $providerNameStr = ''; $organizationData = $settings->getOrganization(); if (!empty($organizationData)) { $langs = array_keys($organizationData); if (in_array('en-US', $langs)) { $lang = 'en-US'; } else { $lang = $langs[0]; } if (isset($organizationData[$lang]['displayname']) && !empty($organizationData[$lang]['displayname'])) { $providerNameStr = <<<PROVIDERNAME ProviderName="{$organizationData[$lang]['displayname']}" PROVIDERNAME; } } $request = <<<AUTHNREQUEST <samlp:AuthnRequest 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" {$providerNameStr} IssueInstant="{$issueInstant}" Destination="{$idpData['singleSignOnService']['url']}" ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" AssertionConsumerServiceURL="{$spData['assertionConsumerService']['url']}"> <saml:Issuer>{$spData['entityId']}</saml:Issuer> <samlp:NameIDPolicy Format="{$nameIDPolicyFormat}" AllowCreate="true" /> AUTHNREQUEST; if (!isset($security['allowedAuthContexts'])) { $security['allowedAuthContexts'] = array('urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport'); } if ($security['allowedAuthContexts'] && is_array($security['allowedAuthContexts'])) { $request .= '<samlp:RequestedAuthnContext Comparison="exact">' . "\n"; foreach ($security['allowedAuthContexts'] as $authCtx) { $request .= '<saml:AuthnContextClassRef>' . $authCtx . "</saml:AuthnContextClassRef>\n"; } $request .= '</samlp:RequestedAuthnContext> ' . "\n"; } $request .= '</samlp:AuthnRequest>'; $this->_id = $id; $this->_authnRequest = $request; }
/** * Gets the NameID Data provided by the SAML response from the IdP. * * @return array Name ID Data (Value, Format, NameQualifier, SPNameQualifier) */ public function getNameIdData() { $encryptedIdDataEntries = $this->_queryAssertion('/saml:Subject/saml:EncryptedID/xenc:EncryptedData'); if ($encryptedIdDataEntries->length == 1) { $encryptedData = $encryptedIdDataEntries->item(0); $key = $this->_settings->getSPkey(); $seckey = new XMLSecurityKey(XMLSecurityKey::RSA_1_5, array('type' => 'private')); $seckey->loadKey($key); $nameId = OneLogin_Saml2_Utils::decryptElement($encryptedData, $seckey); } else { $entries = $this->_queryAssertion('/saml:Subject/saml:NameID'); if ($entries->length == 1) { $nameId = $entries->item(0); } } $nameIdData = array(); if (!isset($nameId)) { $security = $this->_settings->getSecurityData(); if ($security['wantNameId']) { throw new Exception("Not NameID found in the assertion of the Response"); } } else { if ($this->_settings->isStrict() && empty($nameId->nodeValue)) { throw new Exception("An empty NameID value found"); } $nameIdData['Value'] = $nameId->nodeValue; foreach (array('Format', 'SPNameQualifier', 'NameQualifier') as $attr) { if ($nameId->hasAttribute($attr)) { if ($this->_settings->isStrict() && $attr == 'SPNameQualifier') { $spData = $this->_settings->getSPData(); $spEntityId = $spData['entityId']; if ($spEntityId != $nameId->getAttribute($attr)) { throw new Exception("The SPNameQualifier value mistmatch the SP entityID value."); } } $nameIdData[$attr] = $nameId->getAttribute($attr); } } } return $nameIdData; }
/** * 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; }
<?php /** * SAMPLE Code to demonstrate how to handle a SAML assertion response. * * Your IdP will usually want your metadata, you can use this code to generate it once, * or expose it on a URL so your IdP can check it periodically. */ error_reporting(E_ALL); require_once '../_toolkit_loader.php'; header('Content-Type: text/xml'); $samlSettings = new OneLogin_Saml2_Settings(); $sp = $samlSettings->getSPData(); $samlMetadata = OneLogin_Saml2_Metadata::builder($sp); echo $samlMetadata;
/** * Tests the getSPData method of the OneLogin_Saml2_Settings * * @covers OneLogin_Saml2_Settings::getSPData */ public function testGetSPData() { $settingsDir = TEST_ROOT . '/settings/'; include $settingsDir . 'settings1.php'; $settings = new OneLogin_Saml2_Settings($settingsInfo); $spData = $settings->getSPData(); $this->assertNotEmpty($spData); $this->assertArrayHasKey('entityId', $spData); $this->assertArrayHasKey('assertionConsumerService', $spData); $this->assertArrayHasKey('singleLogoutService', $spData); $this->assertArrayHasKey('NameIDFormat', $spData); $this->assertEquals('http://stuff.com/endpoints/metadata.php', $spData['entityId']); $this->assertEquals('http://stuff.com/endpoints/endpoints/acs.php', $spData['assertionConsumerService']['url']); $this->assertEquals('http://stuff.com/endpoints/endpoints/sls.php', $spData['singleLogoutService']['url']); $this->assertEquals('urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified', $spData['NameIDFormat']); }
/** * Determines if the SAML Response is valid using the certificate. * * @param string $requestId The ID of the AuthNRequest sent by this SP to the IdP * * @throws Exception * @return bool Validate the document */ public function isValid($requestId = null) { $this->_error = null; try { // Check SAML version if ($this->document->documentElement->getAttribute('Version') != '2.0') { throw new Exception('Unsupported SAML version'); } if (!$this->document->documentElement->hasAttribute('ID')) { throw new Exception('Missing ID attribute on SAML Response'); } $status = $this->checkStatus(); $singleAssertion = $this->validateNumAssertions(); if (!$singleAssertion) { throw new Exception('SAML Response must contain 1 assertion'); } $idpData = $this->_settings->getIdPData(); $idPEntityId = $idpData['entityId']; $spData = $this->_settings->getSPData(); $spEntityId = $spData['entityId']; $signedElements = array(); if ($this->encrypted) { $signNodes = $this->decryptedDocument->getElementsByTagName('Signature'); } else { $signNodes = $this->document->getElementsByTagName('Signature'); } foreach ($signNodes as $signNode) { $signedElements[] = $signNode->parentNode->localName; } if (!empty($signedElements)) { // Check SignedElements if (!$this->validateSignedElements($signedElements)) { throw new Exception('Found an unexpected Signature Element. SAML Response rejected'); } } 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 Response. Not match the saml-schema-protocol-2.0.xsd"); } } $currentURL = OneLogin_Saml2_Utils::getSelfRoutedURLNoQuery(); if ($this->document->documentElement->hasAttribute('InResponseTo')) { $responseInResponseTo = $this->document->documentElement->getAttribute('InResponseTo'); } // Check if the InResponseTo of the Response matchs the ID of the AuthNRequest (requestId) if provided if (isset($requestId) && isset($responseInResponseTo)) { if ($requestId != $responseInResponseTo) { throw new Exception("The InResponseTo of the Response: {$responseInResponseTo}, does not match the ID of the AuthNRequest sent by the SP: {$requestId}"); } } if (!$this->encrypted && $security['wantAssertionsEncrypted']) { throw new Exception("The assertion of the Response is not encrypted and the SP requires it"); } if ($security['wantNameIdEncrypted']) { $encryptedIdNodes = $this->_queryAssertion('/saml:Subject/saml:EncryptedID/xenc:EncryptedData'); if ($encryptedIdNodes->length == 0) { throw new Exception("The NameID of the Response is not encrypted and the SP requires it"); } } // Validate Asserion timestamps $validTimestamps = $this->validateTimestamps(); if (!$validTimestamps) { throw new Exception('Timing issues (please check your clock settings)'); } // EncryptedAttributes are not supported $encryptedAttributeNodes = $this->_queryAssertion('/saml:AttributeStatement/saml:EncryptedAttribute'); if ($encryptedAttributeNodes->length > 0) { throw new Exception("There is an EncryptedAttribute in the Response and this SP not support them"); } // Check destination if ($this->document->documentElement->hasAttribute('Destination')) { $destination = $this->document->documentElement->getAttribute('Destination'); if (!empty($destination)) { if (strpos($destination, $currentURL) !== 0) { $currentURLrouted = OneLogin_Saml2_Utils::getSelfRoutedURLNoQuery(); if (strpos($destination, $currentURLrouted) !== 0) { throw new Exception("The response was received at {$currentURL} instead of {$destination}"); } } } } // Check audience $validAudiences = $this->getAudiences(); if (!empty($validAudiences) && !in_array($spEntityId, $validAudiences)) { throw new Exception("{$spEntityId} is not a valid audience for this Response"); } // Check the issuers $issuers = $this->getIssuers(); foreach ($issuers as $issuer) { if (empty($issuer) || $issuer != $idPEntityId) { throw new Exception("Invalid issuer in the Assertion/Response"); } } // Check the session Expiration $sessionExpiration = $this->getSessionNotOnOrAfter(); if (!empty($sessionExpiration) && $sessionExpiration <= time()) { throw new Exception("The attributes have expired, based on the SessionNotOnOrAfter of the AttributeStatement of this Response"); } // Check the SubjectConfirmation, at least one SubjectConfirmation must be valid $anySubjectConfirmation = false; $subjectConfirmationNodes = $this->_queryAssertion('/saml:Subject/saml:SubjectConfirmation'); foreach ($subjectConfirmationNodes as $scn) { if ($scn->hasAttribute('Method') && $scn->getAttribute('Method') != OneLogin_Saml2_Constants::CM_BEARER) { continue; } $subjectConfirmationDataNodes = $scn->getElementsByTagName('SubjectConfirmationData'); if ($subjectConfirmationDataNodes->length == 0) { continue; } else { $scnData = $subjectConfirmationDataNodes->item(0); if ($scnData->hasAttribute('InResponseTo')) { $inResponseTo = $scnData->getAttribute('InResponseTo'); if ($responseInResponseTo != $inResponseTo) { continue; } } if ($scnData->hasAttribute('Recipient')) { $recipient = $scnData->getAttribute('Recipient'); if (!empty($recipient) && strpos($recipient, $currentURL) === false) { continue; } } if ($scnData->hasAttribute('NotOnOrAfter')) { $noa = OneLogin_Saml2_Utils::parseSAML2Time($scnData->getAttribute('NotOnOrAfter')); if ($noa <= time()) { continue; } } if ($scnData->hasAttribute('NotBefore')) { $nb = OneLogin_Saml2_Utils::parseSAML2Time($scnData->getAttribute('NotBefore')); if ($nb > time()) { continue; } } $anySubjectConfirmation = true; break; } } if (!$anySubjectConfirmation) { throw new Exception("A valid SubjectConfirmation was not found on this Response"); } if ($security['wantAssertionsSigned'] && !in_array('Assertion', $signedElements)) { throw new Exception("The Assertion of the Response is not signed and the SP requires it"); } if ($security['wantMessagesSigned'] && !in_array('Response', $signedElements)) { throw new Exception("The Message of the Response is not signed and the SP requires it"); } } if (!empty($signedElements)) { $cert = $idpData['x509cert']; $fingerprint = $idpData['certFingerprint']; $fingerprintalg = $idpData['certFingerprintAlgorithm']; // Only validates the first signed element if (in_array('Response', $signedElements)) { $documentToValidate = $this->document; } else { $documentToValidate = $signNodes->item(0)->parentNode; if ($this->encrypted) { $encryptedIDNodes = OneLogin_Saml2_Utils::query($this->decryptedDocument, '/samlp:Response/saml:EncryptedAssertion/saml:Assertion/saml:Subject/saml:EncryptedID'); if ($encryptedIDNodes->length > 0) { throw new Exception('Unsigned SAML Response that contains a signed and encrypted Assertion with encrypted nameId is not supported.'); } } } if (!OneLogin_Saml2_Utils::validateSign($documentToValidate, $cert, $fingerprint, $fingerprintalg)) { throw new Exception('Signature validation failed. SAML Response rejected'); } } else { throw new Exception('No Signature found. SAML Response rejected'); } return true; } catch (Exception $e) { $this->_error = $e->getMessage(); $debug = $this->_settings->isDebugActive(); if ($debug) { echo $this->_error; } return false; } }
/** * Constructs the AuthnRequest object. * * @param OneLogin_Saml2_Settings $settings Settings * @param bool $forceAuthn When true the AuthNReuqest will set the ForceAuthn='true' * @param bool $isPassive When true the AuthNReuqest will set the Ispassive='true' */ public function __construct(OneLogin_Saml2_Settings $settings, $forceAuthn = false, $isPassive = false) { $this->_settings = $settings; $spData = $this->_settings->getSPData(); $idpData = $this->_settings->getIdPData(); $security = $this->_settings->getSecurityData(); $id = OneLogin_Saml2_Utils::generateUniqueID(); $issueInstant = OneLogin_Saml2_Utils::parseTime2SAML(time()); $nameIDPolicyFormat = $spData['NameIDFormat']; echo "1@@@@@@@@@@@@<br /> nameIDPolicyFormat: "; print_r($nameIDPolicyFormat); echo "<br /> OneLogin_Saml2_Constants::NAMEID_ENCRYPTED: "; print_r(OneLogin_Saml2_Constants::NAMEID_ENCRYPTED); echo "2@@@@@@@@@@@@<br />"; //$nameIDPolicyFormat = "urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"; if (isset($security['wantNameIdEncrypted']) && $security['wantNameIdEncrypted']) { $nameIDPolicyFormat = OneLogin_Saml2_Constants::NAMEID_ENCRYPTED; } $providerNameStr = ''; $organizationData = $settings->getOrganization(); if (!empty($organizationData)) { $langs = array_keys($organizationData); if (in_array('en-US', $langs)) { $lang = 'en-US'; } else { $lang = $langs[0]; } if (isset($organizationData[$lang]['displayname']) && !empty($organizationData[$lang]['displayname'])) { $providerNameStr = <<<PROVIDERNAME ProviderName="{$organizationData[$lang]['displayname']}" PROVIDERNAME; } } $forceAuthnStr = ''; if ($forceAuthn) { $forceAuthnStr = <<<FORCEAUTHN ForceAuthn="true" FORCEAUTHN; } $isPassiveStr = ''; if ($isPassive) { $isPassiveStr = <<<ISPASSIVE IsPassive="true" ISPASSIVE; } $requestedAuthnStr = ''; if (isset($security['requestedAuthnContext']) && $security['requestedAuthnContext'] !== false) { if ($security['requestedAuthnContext'] === true) { $requestedAuthnStr = <<<REQUESTEDAUTHN <samlp:RequestedAuthnContext Comparison="exact"> <saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml:AuthnContextClassRef> </samlp:RequestedAuthnContext> REQUESTEDAUTHN; } else { $requestedAuthnStr .= " <samlp:RequestedAuthnContext Comparison=\"exact\">\n"; foreach ($security['requestedAuthnContext'] as $contextValue) { $requestedAuthnStr .= " <saml:AuthnContextClassRef>" . $contextValue . "</saml:AuthnContextClassRef>\n"; } $requestedAuthnStr .= ' </samlp:RequestedAuthnContext>'; } } $request = <<<AUTHNREQUEST <samlp:AuthnRequest 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" {$providerNameStr}{$forceAuthnStr}{$isPassiveStr} IssueInstant="{$issueInstant}" Destination="{$idpData['singleSignOnService']['url']}" ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" AssertionConsumerServiceURL="{$spData['assertionConsumerService']['url']}"> <saml:Issuer>{$spData['entityId']}</saml:Issuer> <samlp:NameIDPolicy Format="{$nameIDPolicyFormat}" AllowCreate="true" /> {$requestedAuthnStr} </samlp:AuthnRequest> AUTHNREQUEST; $this->_id = $id; $this->_authnRequest = $request; }
/** * Tests the addX509KeyDescriptors method of the OneLogin_Saml2_Metadata * * @covers OneLogin_Saml2_Metadata::addX509KeyDescriptors */ public function testAddX509KeyDescriptors() { $settingsDir = TEST_ROOT . '/settings/'; include $settingsDir . 'settings1.php'; $settings = new OneLogin_Saml2_Settings($settingsInfo); $spData = $settings->getSPData(); $metadata = OneLogin_Saml2_Metadata::builder($spData); $this->assertNotContains('<md:KeyDescriptor use="signing"', $metadata); $this->assertNotContains('<md:KeyDescriptor use="encryption"', $metadata); $certPath = $settings->getCertPath(); $cert = file_get_contents($certPath . 'sp.crt'); $metadataWithDescriptors = OneLogin_Saml2_Metadata::addX509KeyDescriptors($metadata, $cert); $this->assertContains('<md:KeyDescriptor use="signing"', $metadataWithDescriptors); $this->assertContains('<md:KeyDescriptor use="encryption"', $metadataWithDescriptors); try { $signedMetadata2 = OneLogin_Saml2_Metadata::addX509KeyDescriptors('', $cert); $this->assertFalse(true); } catch (Exception $e) { $this->assertContains('Error parsing metadata', $e->getMessage()); } libxml_use_internal_errors(true); $unparsedMetadata = file_get_contents(TEST_ROOT . '/data/metadata/unparsed_metadata.xml'); try { $metadataWithDescriptors = OneLogin_Saml2_Metadata::addX509KeyDescriptors($unparsedMetadata, $cert); $this->assertFalse(true); } catch (Exception $e) { $this->assertContains('Error parsing metadata', $e->getMessage()); } }
/** * Constructs the AuthnRequest object. * * @param OneLogin_Saml2_Settings $settings Settings * @param bool $forceAuthn When true the AuthNReuqest will set the ForceAuthn='true' * @param bool $isPassive When true the AuthNReuqest will set the Ispassive='true' */ public function __construct(OneLogin_Saml2_Settings $settings, $forceAuthn = false, $isPassive = false) { $this->_settings = $settings; $spData = $this->_settings->getSPData(); $idpData = $this->_settings->getIdPData(); $security = $this->_settings->getSecurityData(); $id = OneLogin_Saml2_Utils::generateUniqueID(); $issueInstant = OneLogin_Saml2_Utils::parseTime2SAML(time()); $nameIDPolicyFormat = $spData['NameIDFormat']; if (isset($security['wantNameIdEncrypted']) && $security['wantNameIdEncrypted']) { $nameIDPolicyFormat = OneLogin_Saml2_Constants::NAMEID_ENCRYPTED; } $providerNameStr = ''; $organizationData = $settings->getOrganization(); if (!empty($organizationData)) { $langs = array_keys($organizationData); if (in_array('en-US', $langs)) { $lang = 'en-US'; } else { $lang = $langs[0]; } if (isset($organizationData[$lang]['displayname']) && !empty($organizationData[$lang]['displayname'])) { $providerNameStr = <<<PROVIDERNAME ProviderName="{$organizationData[$lang]['displayname']}" PROVIDERNAME; } } $forceAuthnStr = ''; if ($forceAuthn) { $forceAuthnStr = <<<FORCEAUTHN ForceAuthn="true" FORCEAUTHN; } $isPassiveStr = ''; if ($isPassive) { $isPassiveStr = <<<ISPASSIVE IsPassive="true" ISPASSIVE; } $requestedAuthnStr = ''; if (isset($security['requestedAuthnContext']) && $security['requestedAuthnContext'] !== false) { if ($security['requestedAuthnContext'] === true) { $requestedAuthnStr = <<<REQUESTEDAUTHN <samlp:RequestedAuthnContext Comparison="exact"> <saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml:AuthnContextClassRef> </samlp:RequestedAuthnContext> REQUESTEDAUTHN; } else { $requestedAuthnStr .= " <samlp:RequestedAuthnContext Comparison=\"exact\">\n"; foreach ($security['requestedAuthnContext'] as $contextValue) { $requestedAuthnStr .= " <saml:AuthnContextClassRef>" . $contextValue . "</saml:AuthnContextClassRef>\n"; } $requestedAuthnStr .= ' </samlp:RequestedAuthnContext>'; } } $signature = ''; if (isset($security['authnRequestsSigned']) && $security['authnRequestsSigned']) { $key = $this->_settings->getSPkey(); $objKey = new XMLSecurityKey($security['signatureAlgorithm'], array('type' => 'private')); $objKey->loadKey($key, false); $signatureValue = $objKey->signData(time()); $signatureValue = base64_encode($signatureValue); $digestValue = base64_encode(sha1(time())); $x509Cert = $this->_settings->getSPcert(); $x509Cert = OneLogin_Saml2_Utils::formatCert($x509Cert, false); $signature = <<<SIGNATURE <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> <ds:SignedInfo> <ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" /> <ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" /> <ds:Reference> <ds:Transforms> <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" /> <ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" /> </ds:Transforms> <ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" /> <ds:DigestValue>{$digestValue}</ds:DigestValue> </ds:Reference> </ds:SignedInfo> <ds:SignatureValue>asd{$signatureValue}</ds:SignatureValue> <ds:KeyInfo> <ds:X509Data> <ds:X509Certificate>{$x509Cert}</ds:X509Certificate> </ds:X509Data> </ds:KeyInfo> </ds:Signature> SIGNATURE; } $request = <<<AUTHNREQUEST <samlp:AuthnRequest 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" {$providerNameStr}{$forceAuthnStr}{$isPassiveStr} IssueInstant="{$issueInstant}" Destination="{$idpData['singleSignOnService']['url']}" ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" AssertionConsumerServiceURL="{$spData['assertionConsumerService']['url']}"> <saml:Issuer>{$spData['entityId']}</saml:Issuer> {$signature} <samlp:NameIDPolicy Format="{$nameIDPolicyFormat}" AllowCreate="true" /> {$requestedAuthnStr} </samlp:AuthnRequest> AUTHNREQUEST; $this->_id = $id; $this->_authnRequest = $request; }