/** * 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; }
/** * 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; }
/** * @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; }
/** * 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); }
/** * Create an AttributeValue. * * @param mixed $value The value of this element. Can be one of: * - string Create an attribute value with a simple string. * - DOMElement(AttributeValue) Create an attribute value of the given DOMElement. * - DOMElement Create an attribute value with the given DOMElement as a child. */ public function __construct($value) { assert('is_string($value) || $value instanceof DOMElement'); if (is_string($value)) { $doc = SAML2_DOMDocumentFactory::create(); $this->element = $doc->createElementNS(SAML2_Const::NS_SAML, 'saml:AttributeValue'); $this->element->setAttributeNS(SAML2_Const::NS_XSI, 'xsi:type', 'xs:string'); $this->element->appendChild($doc->createTextNode($value)); /* Make sure that the xs-namespace is available in the AttributeValue (for xs:string). */ $this->element->setAttributeNS(SAML2_Const::NS_XS, 'xs:tmp', 'tmp'); $this->element->removeAttributeNS(SAML2_Const::NS_XS, 'tmp'); return; } if ($value->namespaceURI === SAML2_Const::NS_SAML && $value->localName === 'AttributeValue') { $this->element = SAML2_Utils::copyElement($value); return; } $doc = SAML2_DOMDocumentFactory::create(); $this->element = $doc->createElementNS(SAML2_Const::NS_SAML, 'saml:AttributeValue'); SAML2_Utils::copyElement($value, $this->element); }
/** * Make an exact copy the specific DOMElement. * * @param DOMElement $element The element we should copy. * @param DOMElement|NULL $parent The target parent element. * @return DOMElement The copied element. */ public static function copyElement(DOMElement $element, DOMElement $parent = NULL) { if ($parent === NULL) { $document = SAML2_DOMDocumentFactory::create(); } else { $document = $parent->ownerDocument; } $namespaces = array(); for ($e = $element; $e !== NULL; $e = $e->parentNode) { foreach (SAML2_Utils::xpQuery($e, './namespace::*') as $ns) { $prefix = $ns->localName; if ($prefix === 'xml' || $prefix === 'xmlns') { continue; } $uri = $ns->nodeValue; if (!isset($namespaces[$prefix])) { $namespaces[$prefix] = $uri; } } } /** @var DOMElement $newElement */ $newElement = $document->importNode($element, TRUE); if ($parent !== NULL) { /* We need to append the child to the parent before we add the namespaces. */ $parent->appendChild($newElement); } foreach ($namespaces as $prefix => $uri) { $newElement->setAttributeNS($uri, $prefix . ':__ns_workaround__', 'tmp'); $newElement->removeAttributeNS($uri, '__ns_workaround__'); } return $newElement; }
/** * Apply filter to add the targeted ID. * * @param array &$state The current state. */ public function process(&$state) { assert('is_array($state)'); assert('array_key_exists("Attributes", $state)'); if ($this->attribute === NULL) { if (!array_key_exists('UserID', $state)) { throw new Exception('core:TargetedID: Missing UserID for this user. Please' . ' check the \'userid.attribute\' option in the metadata against the' . ' attributes provided by the authentication source.'); } $userID = $state['UserID']; } else { if (!array_key_exists($this->attribute, $state['Attributes'])) { throw new Exception('core:TargetedID: Missing attribute \'' . $this->attribute . '\', which is needed to generate the targeted ID.'); } $userID = $state['Attributes'][$this->attribute][0]; } $secretSalt = SimpleSAML\Utils\Config::getSecretSalt(); if (array_key_exists('Source', $state)) { $srcID = self::getEntityId($state['Source']); } else { $srcID = ''; } if (array_key_exists('Destination', $state)) { $dstID = self::getEntityId($state['Destination']); } else { $dstID = ''; } $uidData = 'uidhashbase' . $secretSalt; $uidData .= strlen($srcID) . ':' . $srcID; $uidData .= strlen($dstID) . ':' . $dstID; $uidData .= strlen($userID) . ':' . $userID; $uidData .= $secretSalt; $uid = hash('sha1', $uidData); if ($this->generateNameId) { /* Convert the targeted ID to a SAML 2.0 name identifier element. */ $nameId = array('Format' => SAML2_Const::NAMEID_PERSISTENT, 'Value' => $uid); if (isset($state['Source']['entityid'])) { $nameId['NameQualifier'] = $state['Source']['entityid']; } if (isset($state['Destination']['entityid'])) { $nameId['SPNameQualifier'] = $state['Destination']['entityid']; } $doc = SAML2_DOMDocumentFactory::create(); $root = $doc->createElement('root'); $doc->appendChild($root); SAML2_Utils::addNameId($root, $nameId); $uid = $doc->saveXML($root->firstChild); } $state['Attributes']['eduPersonTargetedID'] = array($uid); }
/** * Convert this encrypted assertion to an XML element. * * @param DOMNode|NULL $parentElement The DOM node the assertion should be created in. * @return DOMElement This encrypted assertion. */ public function toXML(DOMNode $parentElement = NULL) { if ($parentElement === NULL) { $document = SAML2_DOMDocumentFactory::create(); $parentElement = $document; } else { $document = $parentElement->ownerDocument; } $root = $document->createElementNS(SAML2_Const::NS_SAML, 'saml:' . 'EncryptedAssertion'); $parentElement->appendChild($root); $root->appendChild($document->importNode($this->encryptedData, TRUE)); return $root; }
/** * Create this EntityDescriptor. * * @param DOMElement|NULL $parent The EntitiesDescriptor we should append this EntityDescriptor to. * @return DOMElement */ public function toXML(DOMElement $parent = NULL) { assert('is_string($this->entityID)'); assert('is_null($this->ID) || is_string($this->ID)'); assert('is_null($this->validUntil) || is_int($this->validUntil)'); assert('is_null($this->cacheDuration) || is_string($this->cacheDuration)'); assert('is_array($this->Extensions)'); assert('is_array($this->RoleDescriptor)'); assert('is_null($this->AffiliationDescriptor) || $this->AffiliationDescriptor instanceof SAML2_XML_md_AffiliationDescriptor'); assert('is_null($this->Organization) || $this->Organization instanceof SAML2_XML_md_Organization'); assert('is_array($this->ContactPerson)'); assert('is_array($this->AdditionalMetadataLocation)'); if ($parent === NULL) { $doc = SAML2_DOMDocumentFactory::create(); $e = $doc->createElementNS(SAML2_Const::NS_MD, 'md:EntityDescriptor'); $doc->appendChild($e); } else { $e = $parent->ownerDocument->createElementNS(SAML2_Const::NS_MD, 'md:EntityDescriptor'); $parent->appendChild($e); } $e->setAttribute('entityID', $this->entityID); if (isset($this->ID)) { $e->setAttribute('ID', $this->ID); } if (isset($this->validUntil)) { $e->setAttribute('validUntil', gmdate('Y-m-d\\TH:i:s\\Z', $this->validUntil)); } if (isset($this->cacheDuration)) { $e->setAttribute('cacheDuration', $this->cacheDuration); } SAML2_XML_md_Extensions::addList($e, $this->Extensions); /** @var SAML2_XML_md_UnknownRoleDescriptor|SAML2_XML_md_IDPSSODescriptor|SAML2_XML_md_SPSSODescriptor|SAML2_XML_md_AuthnAuthorityDescriptor|SAML2_XML_md_AttributeAuthorityDescriptor|SAML2_XML_md_PDPDescriptor $n */ foreach ($this->RoleDescriptor as $n) { $n->toXML($e); } if (isset($this->AffiliationDescriptor)) { $this->AffiliationDescriptor->toXML($e); } if (isset($this->Organization)) { $this->Organization->toXML($e); } foreach ($this->ContactPerson as $cp) { $cp->toXML($e); } foreach ($this->AdditionalMetadataLocation as $n) { $n->toXML($e); } $this->signElement($e, $e->firstChild); return $e; }
/** * Add an EncryptedAttribute Statement-node to the assertion. * * @param DOMElement $root The assertion element we should add the Encrypted Attribute Statement to. */ private function addEncryptedAttributeStatement(DOMElement $root) { if ($this->requiredEncAttributes == FALSE) { return; } $document = $root->ownerDocument; $attributeStatement = $document->createElementNS(SAML2_Const::NS_SAML, 'saml:AttributeStatement'); $root->appendChild($attributeStatement); foreach ($this->attributes as $name => $values) { $document2 = SAML2_DOMDocumentFactory::create(); $attribute = $document2->createElementNS(SAML2_Const::NS_SAML, 'saml:Attribute'); $attribute->setAttribute('Name', $name); $document2->appendChild($attribute); if ($this->nameFormat !== SAML2_Const::NAMEFORMAT_UNSPECIFIED) { $attribute->setAttribute('NameFormat', $this->nameFormat); } foreach ($values as $value) { if (is_string($value)) { $type = 'xs:string'; } elseif (is_int($value)) { $type = 'xs:integer'; } else { $type = NULL; } $attributeValue = $document2->createElementNS(SAML2_Const::NS_SAML, 'saml:AttributeValue'); $attribute->appendChild($attributeValue); if ($type !== NULL) { $attributeValue->setAttributeNS(SAML2_Const::NS_XSI, 'xsi:type', $type); } if ($value instanceof DOMNodeList) { for ($i = 0; $i < $value->length; $i++) { $node = $document2->importNode($value->item($i), TRUE); $attributeValue->appendChild($node); } } else { $attributeValue->appendChild($document2->createTextNode($value)); } } /*Once the attribute nodes are built, the are encrypted*/ $EncAssert = new XMLSecEnc(); $EncAssert->setNode($document2->documentElement); $EncAssert->type = 'http://www.w3.org/2001/04/xmlenc#Element'; /* * Attributes are encrypted with a session key and this one with * $EncryptionKey */ $symmetricKey = new XMLSecurityKey(XMLSecurityKey::AES256_CBC); $symmetricKey->generateSessionKey(); $EncAssert->encryptKey($this->encryptionKey, $symmetricKey); $EncrNode = $EncAssert->encryptNode($symmetricKey); $EncAttribute = $document->createElementNS(SAML2_Const::NS_SAML, 'saml:EncryptedAttribute'); $attributeStatement->appendChild($EncAttribute); $n = $document->importNode($EncrNode, TRUE); $EncAttribute->appendChild($n); } }
/** * Convert the targeted ID to a SAML 2.0 name identifier element * * @param string $value The value of the attribute. * @param string $source Identifier of the IdP. * @param string $destination Identifier of the SP. * @return string The XML representing the element */ private static function toNameId($value, $source, $destination) { $nameId = array('Format' => SAML2_Const::NAMEID_PERSISTENT, 'Value' => $value); if (!empty($source)) { $nameId['NameQualifier'] = $source; } if (!empty($destination)) { $nameId['SPNameQualifier'] = $destination; } $doc = SAML2_DOMDocumentFactory::create(); $root = $doc->createElement('root'); $doc->appendChild($root); SAML2_Utils::addNameId($root, $nameId); return $doc->saveXML($root->firstChild); }
/** * Convert this message to an unsigned XML document. * * This method does not sign the resulting XML document. * * @return DOMElement The root element of the DOM tree. */ public function toUnsignedXML() { $this->document = SAML2_DOMDocumentFactory::create(); $root = $this->document->createElementNS(SAML2_Const::NS_SAMLP, 'samlp:' . $this->tagName); $this->document->appendChild($root); /* Ugly hack to add another namespace declaration to the root element. */ $root->setAttributeNS(SAML2_Const::NS_SAML, 'saml:tmp', 'tmp'); $root->removeAttributeNS(SAML2_Const::NS_SAML, 'tmp'); $root->setAttribute('ID', $this->id); $root->setAttribute('Version', '2.0'); $root->setAttribute('IssueInstant', gmdate('Y-m-d\\TH:i:s\\Z', $this->issueInstant)); if ($this->destination !== NULL) { $root->setAttribute('Destination', $this->destination); } if ($this->consent !== NULL && $this->consent !== SAML2_Const::CONSENT_UNSPECIFIED) { $root->setAttribute('Consent', $this->consent); } if ($this->issuer !== NULL) { SAML2_Utils::addString($root, SAML2_Const::NS_SAML, 'saml:Issuer', $this->issuer); } if (!empty($this->extensions)) { SAML2_XML_samlp_Extensions::addList($root, $this->extensions); } return $root; }
/** * Encrypt the NameID in the LogoutRequest. * * @param XMLSecurityKey $key The encryption key. */ public function encryptNameId(XMLSecurityKey $key) { /* First create a XML representation of the NameID. */ $doc = SAML2_DOMDocumentFactory::create(); $root = $doc->createElement('root'); $doc->appendChild($root); SAML2_Utils::addNameId($root, $this->nameId); $nameId = $root->firstChild; SAML2_Utils::getContainer()->debugMessage($nameId, 'encrypt'); /* Encrypt the NameID. */ $enc = new XMLSecEnc(); $enc->setNode($nameId); $enc->type = XMLSecEnc::Element; $symmetricKey = new XMLSecurityKey(XMLSecurityKey::AES128_CBC); $symmetricKey->generateSessionKey(); $enc->encryptKey($key, $symmetricKey); $this->encryptedNameId = $enc->encryptNode($symmetricKey); $this->nameId = NULL; }
/** * Convert this EntitiesDescriptor to XML. * * @param DOMElement|NULL $parent The EntitiesDescriptor we should append this EntitiesDescriptor to. * @return DOMElement */ public function toXML(DOMElement $parent = NULL) { assert('is_null($this->ID) || is_string($this->ID)'); assert('is_null($this->validUntil) || is_int($this->validUntil)'); assert('is_null($this->cacheDuration) || is_string($this->cacheDuration)'); assert('is_null($this->Name) || is_string($this->Name)'); assert('is_array($this->Extensions)'); assert('is_array($this->children)'); if ($parent === NULL) { $doc = SAML2_DOMDocumentFactory::create(); $e = $doc->createElementNS(SAML2_Const::NS_MD, 'md:EntitiesDescriptor'); $doc->appendChild($e); } else { $e = $parent->ownerDocument->createElementNS(SAML2_Const::NS_MD, 'md:EntitiesDescriptor'); $parent->appendChild($e); } if (isset($this->ID)) { $e->setAttribute('ID', $this->ID); } if (isset($this->validUntil)) { $e->setAttribute('validUntil', gmdate('Y-m-d\\TH:i:s\\Z', $this->validUntil)); } if (isset($this->cacheDuration)) { $e->setAttribute('cacheDuration', $this->cacheDuration); } if (isset($this->Name)) { $e->setAttribute('Name', $this->Name); } SAML2_XML_md_Extensions::addList($e, $this->Extensions); /** @var SAML2_XML_md_EntityDescriptor|SAML2_XML_md_EntitiesDescriptor $node */ foreach ($this->children as $node) { $node->toXML($e); } $this->signElement($e, $e->firstChild); return $e; }