283 lines
6.8 KiB
PHP
283 lines
6.8 KiB
PHP
<?php
|
|
|
|
/**
|
|
* Class for SAML 2 logout request messages.
|
|
*
|
|
* @package simpleSAMLphp
|
|
* @version $Id$
|
|
*/
|
|
class SAML2_LogoutRequest extends SAML2_Request {
|
|
|
|
/**
|
|
* The expiration time of this request.
|
|
*
|
|
* @var int|NULL
|
|
*/
|
|
private $notOnOrAfter;
|
|
|
|
|
|
/**
|
|
* The encrypted NameID in the request.
|
|
*
|
|
* If this is not NULL, the NameID needs decryption before it can be accessed.
|
|
*
|
|
* @var DOMElement|NULL
|
|
*/
|
|
private $encryptedNameId;
|
|
|
|
|
|
/**
|
|
* The name identifier of the session that should be terminated.
|
|
*
|
|
* @var array
|
|
*/
|
|
private $nameId;
|
|
|
|
|
|
/**
|
|
* The SessionIndexes of the sessions that should be terminated.
|
|
*
|
|
* @var array
|
|
*/
|
|
private $sessionIndexes;
|
|
|
|
|
|
/**
|
|
* Constructor for SAML 2 logout request messages.
|
|
*
|
|
* @param DOMElement|NULL $xml The input message.
|
|
*/
|
|
public function __construct(DOMElement $xml = NULL) {
|
|
parent::__construct('LogoutRequest', $xml);
|
|
|
|
$this->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 <saml:NameID> or <saml:EncryptedID> in <samlp:LogoutRequest>.');
|
|
} elseif (count($nameId) > 1) {
|
|
throw new Exception('More than one <saml:NameID> or <saml:EncryptedD> in <samlp:LogoutRequest>.');
|
|
}
|
|
$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;
|
|
}
|
|
|
|
}
|