/** * Test unmarshalling / marshalling of XML with Extensions element */ public function testExtensionOrdering() { $xml = <<<AUTHNREQUEST <samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="_306f8ec5b618f361c70b6ffb1480eade" Version="2.0" IssueInstant="2004-12-05T09:21:59Z" Destination="https://idp.example.org/SAML2/SSO/Artifact" ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact" AssertionConsumerServiceURL="https://sp.example.com/SAML2/SSO/Artifact"> <saml:Issuer>https://sp.example.com/SAML2</saml:Issuer> <samlp:Extensions> <myns:AttributeList xmlns:myns="urn:mynamespace"> <myns:Attribute name="UserName" value=""/> </myns:AttributeList> </samlp:Extensions> <saml:Subject> <saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">user@example.org</saml:NameID> </saml:Subject> <samlp:NameIDPolicy AllowCreate="true" Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"/> </samlp:AuthnRequest> AUTHNREQUEST; $document = SAML2_DOMDocumentFactory::fromString($xml); $authnRequest = new SAML2_AuthnRequest($document->documentElement); $this->assertXmlStringEqualsXmlString($document->C14N(), $authnRequest->toUnsignedXML()->C14N()); }
/** * Load a fixture. */ public function setUp() { $xml = <<<XML <samlp:LogoutRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="SomeIDValue" Version="2.0" IssueInstant="2010-07-22T11:30:19Z"> <saml:Issuer>TheIssuer</saml:Issuer> <saml:EncryptedID> <xenc:EncryptedData xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" xmlns:dsig="http://www.w3.org/2000/09/xmldsig#" Type="http://www.w3.org/2001/04/xmlenc#Element"> <xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes128-cbc"/> <dsig:KeyInfo xmlns:dsig="http://www.w3.org/2000/09/xmldsig#"> <xenc:EncryptedKey> <xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p"/> <xenc:CipherData> <xenc:CipherValue>j7t37UjyQ9zgu+zcCDH8v0IaXP2aRSm/XuAW5p5dzeFKf9PZnh7n8977cmex6SCl9SQrJOlqw/GRa342MKFVEl2VmEY9Q+br0ypAZueLwe/z1x3NWzN1ZKwNteWrM7jMdoesjV55PWIWmnuBoDBebuKB7+zS83WN2plV/geSLDg=</xenc:CipherValue> </xenc:CipherData> </xenc:EncryptedKey> </dsig:KeyInfo> <xenc:CipherData> <xenc:CipherValue>rwUZFd0oNzJnvqliCntg8IBx1rulZD4Dopz1LNzx2GbqMln4vxtHi+tzmM9iZ/70zO3n83YXk61JwRzEwvmu7OEZERkjL3cQAEDEws/s4Ibc16pR0irorZy1FYqi9DR1dzDLI2Hbfdrg5oHviyPXtw==</xenc:CipherValue> </xenc:CipherData> </xenc:EncryptedData> </saml:EncryptedID> <samlp:SessionIndex>SomeSessionIndex1</samlp:SessionIndex> <samlp:SessionIndex>SomeSessionIndex2</samlp:SessionIndex> </samlp:LogoutRequest> XML; $document = SAML2_DOMDocumentFactory::fromString($xml); $this->logoutRequestElement = $document->firstChild; }
/** * Convert this NameID to XML. * * @param DOMElement|NULL $parent The element we should append to. * @return DOMElement This AdditionalMetadataLocation-element. */ public function toXML(DOMElement $parent = NULL) { assert('is_string($this->NameQualifier) || is_null($this->NameQualifier)'); assert('is_string($this->SPNameQualifier) || is_null($this->SPNameQualifier)'); assert('is_string($this->Format) || is_null($this->Format)'); assert('is_string($this->SPProvidedID) || is_null($this->SPProvidedID)'); assert('is_string($this->value)'); if ($parent === NULL) { $parent = SAML2_DOMDocumentFactory::create(); $doc = $parent; } else { $doc = $parent->ownerDocument; } $e = $doc->createElementNS(SAML2_Const::NS_SAML, 'saml:NameID'); $parent->appendChild($e); if ($this->NameQualifier !== NULL) { $e->setAttribute('NameQualifier', $this->NameQualifier); } if ($this->SPNameQualifier !== NULL) { $e->setAttribute('SPNameQualifier', $this->SPNameQualifier); } if ($this->Format !== NULL) { $e->setAttribute('Format', $this->Format); } if ($this->SPProvidedID !== NULL) { $e->setAttribute('SPProvidedID', $this->SPProvidedID); } $t = $doc->createTextNode($this->value); $e->appendChild($t); return $e; }
public function testMarshalling() { $indexedEndpointType = new SAML2_XML_md_IndexedEndpointType(); $indexedEndpointType->Binding = 'TestBinding'; $indexedEndpointType->Location = 'TestLocation'; $indexedEndpointType->index = 42; $indexedEndpointType->isDefault = FALSE; $document = SAML2_DOMDocumentFactory::fromString('<root />'); $indexedEndpointTypeElement = $indexedEndpointType->toXML($document->firstChild, 'md:Test'); $indexedEndpointElements = SAML2_Utils::xpQuery($indexedEndpointTypeElement, '/root/saml_metadata:Test'); $this->assertCount(1, $indexedEndpointElements); $indexedEndpointElement = $indexedEndpointElements[0]; $this->assertEquals('TestBinding', $indexedEndpointElement->getAttribute('Binding')); $this->assertEquals('TestLocation', $indexedEndpointElement->getAttribute('Location')); $this->assertEquals('42', $indexedEndpointElement->getAttribute('index')); $this->assertEquals('false', $indexedEndpointElement->getAttribute('isDefault')); $indexedEndpointType->isDefault = TRUE; $document->loadXML('<root />'); $indexedEndpointTypeElement = $indexedEndpointType->toXML($document->firstChild, 'md:Test'); $indexedEndpointTypeElement = SAML2_Utils::xpQuery($indexedEndpointTypeElement, '/root/saml_metadata:Test'); $this->assertCount(1, $indexedEndpointTypeElement); $this->assertEquals('true', $indexedEndpointTypeElement[0]->getAttribute('isDefault')); $indexedEndpointType->isDefault = NULL; $document->loadXML('<root />'); $indexedEndpointTypeElement = $indexedEndpointType->toXML($document->firstChild, 'md:Test'); $indexedEndpointTypeElement = SAML2_Utils::xpQuery($indexedEndpointTypeElement, '/root/saml_metadata:Test'); $this->assertCount(1, $indexedEndpointTypeElement); $this->assertTrue(!$indexedEndpointTypeElement[0]->hasAttribute('isDefault')); }
public function testUnmarshalling() { $mdNamespace = SAML2_Const::NS_MD; $document = SAML2_DOMDocumentFactory::fromString(<<<XML <md:Test xmlns:md="{$mdNamespace}" Binding="urn:something" Location="https://whatever/" xmlns:test="urn:test" test:attr="value" /> XML ); $endpointType = new SAML2_XML_md_EndpointType($document->firstChild); $this->assertEquals(TRUE, $endpointType->hasAttributeNS('urn:test', 'attr')); $this->assertEquals('value', $endpointType->getAttributeNS('urn:test', 'attr')); $this->assertEquals(FALSE, $endpointType->hasAttributeNS('urn:test', 'invalid')); $this->assertEquals('', $endpointType->getAttributeNS('urn:test', 'invalid')); $endpointType->removeAttributeNS('urn:test', 'attr'); $this->assertEquals(FALSE, $endpointType->hasAttributeNS('urn:test', 'attr')); $this->assertEquals('', $endpointType->getAttributeNS('urn:test', 'attr')); $endpointType->setAttributeNS('urn:test2', 'test2:attr2', 'value2'); $this->assertEquals('value2', $endpointType->getAttributeNS('urn:test2', 'attr2')); $document->loadXML('<root />'); $endpointTypeElement = $endpointType->toXML($document->firstChild, 'md:Test'); $endpointTypeElements = SAML2_Utils::xpQuery($endpointTypeElement, '/root/saml_metadata:Test'); $this->assertCount(1, $endpointTypeElements); $endpointTypeElement = $endpointTypeElements[0]; $this->assertEquals('value2', $endpointTypeElement->getAttributeNS('urn:test2', 'attr2')); $this->assertEquals(FALSE, $endpointTypeElement->hasAttributeNS('urn:test', 'attr')); }
/** * Extract the response element from the SOAP response. * * @param string $soapResponse The SOAP response. * @return string The <saml1p:Response> element, as a string. */ private static function extractResponse($soapResponse) { assert('is_string($soapResponse)'); try { $doc = SAML2_DOMDocumentFactory::fromString($soapResponse); } catch (\Exception $e) { throw new SimpleSAML_Error_Exception('Error parsing SAML 1 artifact response.'); } $soapEnvelope = $doc->firstChild; if (!SimpleSAML\Utils\XML::isDOMElementOfType($soapEnvelope, 'Envelope', 'http://schemas.xmlsoap.org/soap/envelope/')) { throw new SimpleSAML_Error_Exception('Expected artifact response to contain a <soap:Envelope> element.'); } $soapBody = SimpleSAML\Utils\XML::getDOMChildren($soapEnvelope, 'Body', 'http://schemas.xmlsoap.org/soap/envelope/'); if (count($soapBody) === 0) { throw new SimpleSAML_Error_Exception('Couldn\'t find <soap:Body> in <soap:Envelope>.'); } $soapBody = $soapBody[0]; $responseElement = SimpleSAML\Utils\XML::getDOMChildren($soapBody, 'Response', 'urn:oasis:names:tc:SAML:1.0:protocol'); if (count($responseElement) === 0) { throw new SimpleSAML_Error_Exception('Couldn\'t find <saml1p:Response> in <soap:Body>.'); } $responseElement = $responseElement[0]; /* * Save the <saml1p:Response> element. Note that we need to import it * into a new document, in order to preserve namespace declarations. */ $newDoc = SAML2_DOMDocumentFactory::create(); $newDoc->appendChild($newDoc->importNode($responseElement, TRUE)); $responseXML = $newDoc->saveXML(); return $responseXML; }
/** * Un-serialize this XML chunk. * * @param string $serialized The serialized chunk. * @return SAML2_XML_Chunk The chunk object represented by the serialized string. */ public function unserialize($serialized) { $doc = SAML2_DOMDocumentFactory::fromString(unserialize($serialized)); $this->xml = $doc->documentElement; $this->localName = $this->xml->localName; $this->namespaceURI = $this->xml->namespaceURI; }
/** * Test retrieval of a localized string for a given node. */ public function testExtractLocalizedString() { $document = SAML2_DOMDocumentFactory::fromString('<root xmlns="' . SAML2_Const::NS_MD . '">' . '<somenode xml:lang="en">value (en)</somenode>' . '<somenode xml:lang="no">value (no)</somenode>' . '</root>'); $localizedStringValues = SAML2_Utils::extractLocalizedStrings($document->firstChild, SAML2_Const::NS_MD, 'somenode'); $this->assertTrue(count($localizedStringValues) === 2); $this->assertEquals('value (en)', $localizedStringValues["en"]); $this->assertEquals('value (no)', $localizedStringValues["no"]); }
public function setXML($xml) { assert('is_string($xml)'); try { $this->dom = SAML2_DOMDocumentFactory::fromString(str_replace("\r", "", $xml)); } catch (\Exception $e) { throw new Exception('Unable to parse AuthnResponse XML.'); } }
/** * @param string $saml_response Base64 Encoded SAML * * @throws Exception When no assertions are found or signature in invalid */ public function load_saml_response($saml_response) { $response_element = SAML2_DOMDocumentFactory::fromString(base64_decode($saml_response))->documentElement; $signature_info = SAML2_Utils::validateElement($response_element); SAML2_Utils::validateSignature($signature_info, $this->security_key); $response = SAML2_StatusResponse::fromXML($response_element); $this->destination = $response->getDestination(); $assertions = $response->getAssertions(); $this->assertions = $assertions; }
public function testUnmarshalling() { $document = SAML2_DOMDocumentFactory::fromString('<md:AdditionalMetadataLocation xmlns:md="' . SAML2_Const::NS_MD . '"' . ' namespace="TheNamespaceAttribute">LocationText</md:AdditionalMetadataLocation>'); $additionalMetadataLocation = new SAML2_XML_md_AdditionalMetadataLocation($document->firstChild); $this->assertEquals('TheNamespaceAttribute', $additionalMetadataLocation->namespace); $this->assertEquals('LocationText', $additionalMetadataLocation->location); $document->loadXML('<md:AdditionalMetadataLocation xmlns:md="' . SAML2_Const::NS_MD . '"' . '>LocationText</md:AdditionalMetadataLocation>'); $this->setExpectedException('Exception', 'Missing namespace attribute on AdditionalMetadataLocation element.'); new SAML2_XML_md_AdditionalMetadataLocation($document->firstChild); }
/** * Receive a SAML 2 message sent using the HTTP-POST binding. * * Throws an exception if it is unable receive the message. * * @return SAML2_Message The received message. * @throws Exception */ public function receive() { $postText = file_get_contents('php://input'); if (empty($postText)) { throw new Exception('Invalid message received to AssertionConsumerService endpoint.'); } $document = SAML2_DOMDocumentFactory::fromString($postText); $xml = $document->firstChild; SAML2_Utils::getContainer()->debugMessage($xml, 'in'); $results = SAML2_Utils::xpQuery($xml, '/soap-env:Envelope/soap-env:Body/*[1]'); return SAML2_Message::fromXML($results[0]); }
/** * @return DOMElement */ public function toSignedXML() { $doc = SAML2_DOMDocumentFactory::create(); $root = $doc->createElement('root'); $doc->appendChild($root); $child = $doc->createElement('child'); $root->appendChild($child); $txt = $doc->createTextNode('sometext'); $child->appendChild($txt); $this->signElement($root, $child); return $root; }
function __construct($metaxml) { $template = ''; if (strpos("\n", $metaxml) === FALSE) { foreach (explode("\n", self::template) as $line) { $template .= trim($line); } } else { $template = self::template; } $sigdoc = SAML2_DOMDocumentFactory::fromString($template); $this->sigNode = $sigdoc->documentElement; }
public function testUnmarshallingFailure() { $samlNamespace = SAML2_Const::NS_SAML; $document = SAML2_DOMDocumentFactory::fromString(<<<XML <saml:Attribute xmlns:saml="{$samlNamespace}" NameFormat="TheNameFormat" FriendlyName="TheFriendlyName"> <saml:AttributeValue>FirstValue</saml:AttributeValue> <saml:AttributeValue>SecondValue</saml:AttributeValue> </saml:Attribute> XML ); $this->setExpectedException('Exception', 'Missing Name on Attribute.'); new SAML2_XML_saml_Attribute($document->firstChild); }
public function testUnmarshallingWithoutOwner() { $mdNamespace = SAML2_Const::NS_MD; $document = SAML2_DOMDocumentFactory::fromString(<<<XML <md:AffiliationDescriptor xmlns:md="{$mdNamespace}" ID="TheID" validUntil="2009-02-13T23:31:30Z" cacheDuration="PT5000S"> <md:AffiliateMember>Member</md:AffiliateMember> <md:AffiliateMember>OtherMember</md:AffiliateMember> </md:AffiliationDescriptor> XML ); $this->setExpectedException('Exception', 'Missing affiliationOwnerID on AffiliationDescriptor.'); new SAML2_XML_md_AffiliationDescriptor($document->firstChild); }
/** * @param string $saml_request Base64 Encoded SAML * * @throws Exception When signature in invalid */ public function load_saml_request($saml_request) { $request_element = SAML2_DOMDocumentFactory::fromString(base64_decode($saml_request))->documentElement; $signature_info = SAML2_Utils::validateElement($request_element); SAML2_Utils::validateSignature($signature_info, $this->security_key); /** @var SAML2_LogoutRequest $request */ $request = SAML2_LogoutRequest::fromXML($request_element); $request->decryptNameId($this->security_key); $name_id = $request->getNameId(); $this->notOnOrAfter = $request->getNotOnOrAfter(); $this->name = $name_id ? $name_id['Value'] : null; $this->session_index = $request->getSessionIndex(); $this->destination = $request->getDestination(); }
public function testUnmarshalling() { $samlNamespace = SAML2_Const::NS_SAML; $document = SAML2_DOMDocumentFactory::fromString(<<<XML <saml:NameID xmlns:saml="{$samlNamespace}" NameQualifier="TheNameQualifier" SPNameQualifier="TheSPNameQualifier" Format="TheFormat" SPProvidedID="TheSPProvidedID">TheNameIDValue</saml:NameID> XML ); $nameId = new SAML2_XML_saml_NameID($document->firstChild); $this->assertEquals('TheNameQualifier', $nameId->NameQualifier); $this->assertEquals('TheSPNameQualifier', $nameId->SPNameQualifier); $this->assertEquals('TheFormat', $nameId->Format); $this->assertEquals('TheSPProvidedID', $nameId->SPProvidedID); $this->assertEquals('TheNameIDValue', $nameId->value); }
/** * @test * @group signature */ public function signed_message_with_valid_signature_is_validated_correctly() { $pattern = SAML2_Utilities_Certificate::CERTIFICATE_PATTERN; preg_match($pattern, SAML2_CertificatesMock::PUBLIC_KEY_PEM, $matches); $config = new SAML2_Configuration_IdentityProvider(array('certificateData' => $matches[1])); $validator = new SAML2_Signature_PublicKeyValidator(new SAML2_SimpleTestLogger(), new SAML2_Certificate_KeyLoader()); $doc = SAML2_DOMDocumentFactory::fromFile(__DIR__ . '/response.xml'); $response = new SAML2_Response($doc->firstChild); $response->setSignatureKey(SAML2_CertificatesMock::getPrivateKey()); $response->setCertificates(array(SAML2_CertificatesMock::PUBLIC_KEY_PEM)); // convert to signed response $response = new SAML2_Response($response->toSignedXML()); $this->assertTrue($validator->canValidate($response, $config), 'Cannot validate the element'); $this->assertTrue($validator->hasValidSignature($response, $config), 'The signature is not valid'); }
public function testUnmarshalling() { $samlNamespace = SAML2_Const::NS_SAML; $document = SAML2_DOMDocumentFactory::fromString(<<<XML <saml:SubjectConfirmation xmlns:saml="{$samlNamespace}" Method="SomeMethod"> <saml:NameID>SomeNameIDValue</saml:NameID> <saml:SubjectConfirmationData/> </saml:SubjectConfirmation> XML ); $subjectConfirmation = new SAML2_XML_saml_SubjectConfirmation($document->firstChild); $this->assertEquals('SomeMethod', $subjectConfirmation->Method); $this->assertTrue($subjectConfirmation->NameID instanceof SAML2_XML_saml_NameID); $this->assertEquals('SomeNameIDValue', $subjectConfirmation->NameID->value); $this->assertTrue($subjectConfirmation->SubjectConfirmationData instanceof SAML2_XML_saml_SubjectConfirmationData); }
public function testECPRequest() { $xml = <<<XML <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"> <S:Header> <ecp:Request xmlns:ecp="urn:oasis:names:tc:SAML:2.0:profiles:SSO:ecp" IsPassive="0" S:actor="http://schemas.xmlsoap.org/soap/actor/next" S:mustUnderstand="1"> <saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"> https://sp.example.org/shibboleth</saml:Issuer> <samlp:IDPList xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"> <samlp:IDPEntry ProviderID="https://idp.example.org/idp/shibboleth" /> </samlp:IDPList> </ecp:Request> <ecp:RelayState xmlns:ecp="urn:oasis:names:tc:SAML:2.0:profiles:SSO:ecp" S:actor="http://schemas.xmlsoap.org/soap/actor/next" S:mustUnderstand="1"> ss:mem:cca27ceabb8b0035ead1d99c0e343fa9234d6d559d5da43d4efb9d6cb592c0cf</ecp:RelayState> </S:Header> <S:Body> <samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" AssertionConsumerServiceURL="https://sp.example.org/Shibboleth.sso/SAML2/ECP" ID="_c4c85dda436c8d0512ddc6bc21be3a45" IssueInstant="2012-11-12T09:33:26Z" ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:PAOS" Version="2.0"> <saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"> https://sp.example.org/shibboleth</saml:Issuer> <samlp:NameIDPolicy AllowCreate="1" /> <samlp:Scoping> <samlp:IDPList> <samlp:IDPEntry ProviderID="https://idp.example.org/idp/shibboleth" /> </samlp:IDPList> </samlp:Scoping> </samlp:AuthnRequest> </S:Body> </S:Envelope> XML; $fixtureResponseDom = SAML2_DOMDocumentFactory::fromString($xml); $request = new SAML2_XML_ecp_Request($fixtureResponseDom->getElementsByTagNameNS('urn:oasis:names:tc:SAML:2.0:profiles:SSO:ecp', 'Request')->item(0)); $requestXml = $request->toXML($fixtureResponseDom->firstChild)->ownerDocument->C14N(); $fixtureXml = $fixtureResponseDom->C14N(); $this->assertXmlStringEqualsXmlString($fixtureXml, $requestXml, 'PAOS Request after Unmarshalling and re-marshalling remains the same'); }
/** * @test * @group signature */ public function signed_message_with_valid_signature_is_validated_correctly() { $pattern = SAML2_Utilities_Certificate::CERTIFICATE_PATTERN; preg_match($pattern, SAML2_CertificatesMock::PUBLIC_KEY_PEM, $matches); $certdata = SAML2_Certificate_X509::createFromCertificateData($matches[1]); $fingerprint = $certdata->getFingerprint(); $fingerprint_retry = $certdata->getFingerprint(); $this->assertTrue($fingerprint->equals($fingerprint_retry), 'Cached fingerprint does not match original'); $config = new SAML2_Configuration_IdentityProvider(array('certificateFingerprints' => array($fingerprint->getRaw()))); $validator = new SAML2_Signature_FingerprintValidator(new SAML2_SimpleTestLogger(), new SAML2_Certificate_FingerprintLoader()); $doc = SAML2_DOMDocumentFactory::fromFile(__DIR__ . '/response.xml'); $response = new SAML2_Response($doc->firstChild); $response->setSignatureKey(SAML2_CertificatesMock::getPrivateKey()); $response->setCertificates(array(SAML2_CertificatesMock::PUBLIC_KEY_PEM)); // convert to signed response $response = new SAML2_Response($response->toSignedXML()); $this->assertTrue($validator->canValidate($response, $config), 'Cannot validate the element'); $this->assertTrue($validator->hasValidSignature($response, $config), 'The signature is not valid'); }
/** * Receive a SAML 2 message sent using the HTTP-POST binding. * * Throws an exception if it is unable receive the message. * * @return SAML2_Message The received message. * @throws Exception */ public function receive() { if (array_key_exists('SAMLRequest', $_POST)) { $msg = $_POST['SAMLRequest']; } elseif (array_key_exists('SAMLResponse', $_POST)) { $msg = $_POST['SAMLResponse']; } else { throw new Exception('Missing SAMLRequest or SAMLResponse parameter.'); } $msg = base64_decode($msg); SAML2_Utils::getContainer()->debugMessage($msg, 'in'); $document = SAML2_DOMDocumentFactory::fromString($msg); $xml = $document->firstChild; $msg = SAML2_Message::fromXML($xml); if (array_key_exists('RelayState', $_POST)) { $msg->setRelayState($_POST['RelayState']); } return $msg; }
/** * Store a NameID to attribute. * * @param array &$state The request state. */ public function process(&$state) { assert('is_array($state)'); if (!isset($state['saml:NameID'][SAML2_Const::NAMEID_PERSISTENT])) { SimpleSAML\Logger::warning('Unable to generate eduPersonTargetedID because no persistent NameID was available.'); return; } $nameID = $state['saml:NameID'][SAML2_Const::NAMEID_PERSISTENT]; if ($this->nameId) { $doc = SAML2_DOMDocumentFactory::create(); $root = $doc->createElement('root'); $doc->appendChild($root); SAML2_Utils::addNameId($root, $nameID); $value = $doc->saveXML($root->firstChild); } else { $value = $nameID['Value']; } $state['Attributes'][$this->attribute] = array($value); }
public function testUnmarshalling() { $document = SAML2_DOMDocumentFactory::fromString(<<<XML <mdrpi:PublicationInfo xmlns:mdrpi="urn:oasis:names:tc:SAML:metadata:rpi" publisher="SomePublisher" creationInstant="2011-01-01T00:00:00Z" publicationId="SomePublicationId"> <mdrpi:UsagePolicy xml:lang="en">http://TheEnglishUsagePolicy</mdrpi:UsagePolicy> <mdrpi:UsagePolicy xml:lang="no">http://TheNorwegianUsagePolicy</mdrpi:UsagePolicy> </mdrpi:PublicationInfo> XML ); $publicationInfo = new SAML2_XML_mdrpi_PublicationInfo($document->firstChild); $this->assertEquals('SomePublisher', $publicationInfo->publisher); $this->assertEquals(1293840000, $publicationInfo->creationInstant); $this->assertEquals('SomePublicationId', $publicationInfo->publicationId); $this->assertCount(2, $publicationInfo->UsagePolicy); $this->assertEquals('http://TheEnglishUsagePolicy', $publicationInfo->UsagePolicy["en"]); $this->assertEquals('http://TheNorwegianUsagePolicy', $publicationInfo->UsagePolicy["no"]); }
public function testMarshalling() { $roleDescriptor = new SAML2_XML_md_RoleDescriptorMock(); $roleDescriptor->ID = 'SomeID'; $roleDescriptor->validUntil = 1234567890; $roleDescriptor->cacheDuration = 'PT5000S'; $roleDescriptor->protocolSupportEnumeration = array('protocol1', 'protocol2'); $roleDescriptor->errorURL = 'https://example.org/error'; $document = SAML2_DOMDocumentFactory::fromString('<root />'); $roleDescriptorElement = $roleDescriptor->toXML($document->firstChild); $roleDescriptorElement = SAML2_Utils::xpQuery($roleDescriptorElement, '/root/md:RoleDescriptor'); $this->assertCount(1, $roleDescriptorElement); $roleDescriptorElement = $roleDescriptorElement[0]; $this->assertEquals('SomeID', $roleDescriptorElement->getAttribute("ID")); $this->assertEquals('2009-02-13T23:31:30Z', $roleDescriptorElement->getAttribute("validUntil")); $this->assertEquals('PT5000S', $roleDescriptorElement->getAttribute("cacheDuration")); $this->assertEquals('protocol1 protocol2', $roleDescriptorElement->getAttribute("protocolSupportEnumeration")); $this->assertEquals('myns:MyElement', $roleDescriptorElement->getAttributeNS(SAML2_Const::NS_XSI, "type")); $this->assertEquals('http://example.org/mynsdefinition', $roleDescriptorElement->lookupNamespaceURI("myns")); }
/** * Send an authenticationResponse using HTTP-POST. * * @param string $response The response which should be sent. * @param SimpleSAML_Configuration $idpmd The metadata of the IdP which is sending the response. * @param SimpleSAML_Configuration $spmd The metadata of the SP which is receiving the response. * @param string|null $relayState The relaystate for the SP. * @param string $shire The shire which should receive the response. */ public function sendResponse($response, SimpleSAML_Configuration $idpmd, SimpleSAML_Configuration $spmd, $relayState, $shire) { \SimpleSAML\Utils\XML::checkSAMLMessage($response, 'saml11'); $privatekey = SimpleSAML\Utils\Crypto::loadPrivateKey($idpmd, true); $publickey = SimpleSAML\Utils\Crypto::loadPublicKey($idpmd, true); $responsedom = SAML2_DOMDocumentFactory::fromString(str_replace("\r", "", $response)); $responseroot = $responsedom->getElementsByTagName('Response')->item(0); $firstassertionroot = $responsedom->getElementsByTagName('Assertion')->item(0); /* Determine what we should sign - either the Response element or the Assertion. The default is to sign the * Assertion, but that can be overridden by the 'signresponse' option in the SP metadata or * 'saml20.signresponse' in the global configuration. * * TODO: neither 'signresponse' nor 'shib13.signresponse' are valid options any longer. Remove! */ if ($spmd->hasValue('signresponse')) { $signResponse = $spmd->getBoolean('signresponse'); } else { $signResponse = $this->configuration->getBoolean('shib13.signresponse', true); } // check if we have an assertion to sign. Force to sign the response if not if ($firstassertionroot === null) { $signResponse = true; } $signer = new SimpleSAML_XML_Signer(array('privatekey_array' => $privatekey, 'publickey_array' => $publickey, 'id' => $signResponse ? 'ResponseID' : 'AssertionID')); if ($idpmd->hasValue('certificatechain')) { $signer->addCertificate($idpmd->getString('certificatechain')); } if ($signResponse) { // sign the response - this must be done after encrypting the assertion // we insert the signature before the saml2p:Status element $statusElements = SimpleSAML\Utils\XML::getDOMChildren($responseroot, 'Status', '@saml1p'); assert('count($statusElements) === 1'); $signer->sign($responseroot, $responseroot, $statusElements[0]); } else { // Sign the assertion $signer->sign($firstassertionroot, $firstassertionroot); } $response = $responsedom->saveXML(); \SimpleSAML\Utils\XML::debugSAMLMessage($response, 'out'); \SimpleSAML\Utils\HTTP::submitPOSTData($shire, array('TARGET' => $relayState, 'SAMLResponse' => base64_encode($response))); }
public function testUnmarshalling() { $samlNamespace = SAML2_Const::NS_SAML; $document = SAML2_DOMDocumentFactory::fromString(<<<XML <saml:SubjectConfirmationData xmlns:saml="{$samlNamespace}" NotBefore="2001-04-19T04:25:21Z" NotOnOrAfter="2009-02-13T23:31:30Z" Recipient="https://sp.example.org/asdf" InResponseTo="SomeRequestID" Address="127.0.0.1" /> XML ); $subjectConfirmationData = new SAML2_XML_saml_SubjectConfirmationData($document->firstChild); $this->assertEquals(987654321, $subjectConfirmationData->NotBefore); $this->assertEquals(1234567890, $subjectConfirmationData->NotOnOrAfter); $this->assertEquals('https://sp.example.org/asdf', $subjectConfirmationData->Recipient); $this->assertEquals('SomeRequestID', $subjectConfirmationData->InResponseTo); $this->assertEquals('127.0.0.1', $subjectConfirmationData->Address); }
/** * Tests that AuthnContextDeclRef is not mistaken for AuthnContextClassRef. * * This tests against reintroduction of removed behavior. */ public function testNoAuthnContextDeclRefFallback() { $authnContextDeclRef = 'relative/url/to/authcontext.xml'; // Unmarshall an assertion $document = SAML2_DOMDocumentFactory::fromString(<<<XML <saml:Assertion xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" ID="_593e33ddf86449ce4d4c22b60ac48e067d98a0b2bf" Version="2.0" IssueInstant="2010-03-05T13:34:28Z" > <saml:Issuer>testIssuer</saml:Issuer> <saml:AuthnStatement AuthnInstant="2010-03-05T13:34:28Z"> <saml:AuthnContext> <saml:AuthnContextDeclRef>{$authnContextDeclRef}</saml:AuthnContextDeclRef> </saml:AuthnContext> </saml:AuthnStatement> </saml:Assertion> XML ); $assertion = new \SAML2_Assertion($document->firstChild); $this->assertEmpty($assertion->getAuthnContextClassRef()); $this->assertEquals($authnContextDeclRef, $assertion->getAuthnContextDeclRef()); }
/** * Helper function for encoding attributes. * * @param SimpleSAML_Configuration $idpMetadata The metadata of the IdP. * @param SimpleSAML_Configuration $spMetadata The metadata of the SP. * @param array $attributes The attributes of the user * @return array The encoded attributes. */ private static function encodeAttributes(SimpleSAML_Configuration $idpMetadata, SimpleSAML_Configuration $spMetadata, array $attributes) { $base64Attributes = $spMetadata->getBoolean('base64attributes', NULL); if ($base64Attributes === NULL) { $base64Attributes = $idpMetadata->getBoolean('base64attributes', FALSE); } if ($base64Attributes) { $defaultEncoding = 'base64'; } else { $defaultEncoding = 'string'; } $srcEncodings = $idpMetadata->getArray('attributeencodings', array()); $dstEncodings = $spMetadata->getArray('attributeencodings', array()); /* * Merge the two encoding arrays. Encodings specified in the target metadata * takes precedence over the source metadata. */ $encodings = array_merge($srcEncodings, $dstEncodings); $ret = array(); foreach ($attributes as $name => $values) { $ret[$name] = array(); if (array_key_exists($name, $encodings)) { $encoding = $encodings[$name]; } else { $encoding = $defaultEncoding; } foreach ($values as $value) { // allow null values if ($value === null) { $ret[$name][] = $value; continue; } switch ($encoding) { case 'string': $value = (string) $value; break; case 'base64': $value = base64_encode((string) $value); break; case 'raw': if (is_string($value)) { $doc = SAML2_DOMDocumentFactory::fromString('<root>' . $value . '</root>'); $value = $doc->firstChild->childNodes; } assert('$value instanceof DOMNodeList'); break; default: throw new SimpleSAML_Error_Exception('Invalid encoding for attribute ' . var_export($name, TRUE) . ': ' . var_export($encoding, TRUE)); } $ret[$name][] = $value; } } return $ret; }