sessionIndexes = array(); if ($xml === NULL) { return; } if ($xml->hasAttribute('NotOnOrAfter')) { $this->notOnOrAfter = SimpleSAML_Utilities::parseSAML2Time($xml->getAttribute('NotOnOrAfter')); } $nameId = SAML2_Utils::xpQuery($xml, './saml_assertion:NameID | ./saml_assertion:EncryptedID/xenc:EncryptedData'); if (empty($nameId)) { throw new Exception('Missing or in .'); } elseif (count($nameId) > 1) { throw new Exception('More than one or in .'); } $nameId = $nameId[0]; if ($nameId->localName === 'EncryptedData') { /* The NameID element is encrypted. */ $this->encryptedNameId = $nameId; } else { $this->nameId = SAML2_Utils::parseNameId($nameId); } $sessionIndexes = SAML2_Utils::xpQuery($xml, './saml_protocol:SessionIndex'); foreach ($sessionIndexes as $sessionIndex) { $this->sessionIndexes[] = trim($sessionIndex->textContent); } } /** * Retrieve the expiration time of this request. * * @return int|NULL The expiration time of this request. */ public function getNotOnOrAfter() { return $this->notOnOrAfter; } /** * Set the expiration time of this request. * * @param int|NULL $notOnOrAfter The expiration time of this request. */ public function setNotOnOrAfter($notOnOrAfter) { assert('is_int($notOnOrAfter) || is_null($notOnOrAfter)'); $this->notOnOrAfter = $notOnOrAfter; } /** * Check whether the NameId is encrypted. * * @return TRUE if the NameId is encrypted, FALSE if not. */ public function isNameIdEncrypted() { if ($this->encryptedNameId !== NULL) { return TRUE; } return FALSE; } /** * 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 = new DOMDocument(); $root = $doc->createElement('root'); $doc->appendChild($root); SAML2_Utils::addNameId($root, $this->nameId); $nameId = $root->firstChild; SimpleSAML_Utilities::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; } /** * Decrypt the NameID in the LogoutRequest. * * @param XMLSecurityKey $key The decryption key. * @param array $blacklist Blacklisted decryption algorithms. */ public function decryptNameId(XMLSecurityKey $key, array $blacklist = array()) { if ($this->encryptedNameId === NULL) { /* No NameID to decrypt. */ return; } $nameId = SAML2_Utils::decryptElement($this->encryptedNameId, $key, $blacklist); SimpleSAML_Utilities::debugMessage($nameId, 'decrypt'); $this->nameId = SAML2_Utils::parseNameId($nameId); $this->encryptedNameId = NULL; } /** * Retrieve the name identifier of the session that should be terminated. * * @return array The name identifier of the session that should be terminated. */ public function getNameId() { if ($this->encryptedNameId !== NULL) { throw new Exception('Attempted to retrieve encrypted NameID without decrypting it first.'); } return $this->nameId; } /** * Set the name identifier of the session that should be terminated. * * The name identifier must be in the format accepted by SAML2_message::buildNameId(). * * @see SAML2_message::buildNameId() * @param array $nameId The name identifier of the session that should be terminated. */ public function setNameId($nameId) { assert('is_array($nameId)'); $this->nameId = $nameId; } /** * Retrieve the SessionIndexes of the sessions that should be terminated. * * @return array The SessionIndexes, or an empty array if all sessions should be terminated. */ public function getSessionIndexes() { return $this->sessionIndexes; } /** * Set the SessionIndexes of the sessions that should be terminated. * * @param array $sessionIndexes The SessionIndexes, or an empty array if all sessions should be terminated. */ public function setSessionIndexes(array $sessionIndexes) { $this->sessionIndexes = $sessionIndexes; } /** * Retrieve the sesion index of the session that should be terminated. * * @return string|NULL The sesion index of the session that should be terminated. */ public function getSessionIndex() { if (empty($this->sessionIndexes)) { return NULL; } return $this->sessionIndexes[0]; } /** * Set the sesion index of the session that should be terminated. * * @param string|NULL $sessionIndex The sesion index of the session that should be terminated. */ public function setSessionIndex($sessionIndex) { assert('is_string($sessionIndex) || is_null($sessionIndex)'); if (is_null($sessionIndex)) { $this->sessionIndexes = array(); } else { $this->sessionIndexes = array($sessionIndex); } } /** * Convert this logout request message to an XML element. * * @return DOMElement This logout request. */ public function toUnsignedXML() { $root = parent::toUnsignedXML(); if ($this->notOnOrAfter !== NULL) { $root->setAttribute('NotOnOrAfter', gmdate('Y-m-d\TH:i:s\Z', $this->notOnOrAfter)); } if ($this->encryptedNameId === NULL) { SAML2_Utils::addNameId($root, $this->nameId); } else { $eid = $root->ownerDocument->createElementNS(SAML2_Const::NS_SAML, 'saml:' . 'EncryptedID'); $root->appendChild($eid); $eid->appendChild($root->ownerDocument->importNode($this->encryptedNameId, TRUE)); } foreach ($this->sessionIndexes as $sessionIndex) { SAML2_Utils::addString($root, SAML2_Const::NS_SAMLP, 'SessionIndex', $sessionIndex); } return $root; } }