From fbd8a7875dbe6a1f672ecc3bfceba8993cf44cea Mon Sep 17 00:00:00 2001
From: Olav Morken <olav.morken@uninett.no>
Date: Mon, 9 Aug 2010 08:52:40 +0000
Subject: [PATCH] SAML2_LogoutRequest: Add support for encrypted NameID.

git-svn-id: https://simplesamlphp.googlecode.com/svn/trunk@2502 44740490-163a-0410-bde0-09ae8108e29a
---
 lib/SAML2/LogoutRequest.php | 103 +++++++++++++++++++++++++++++++++---
 1 file changed, 96 insertions(+), 7 deletions(-)

diff --git a/lib/SAML2/LogoutRequest.php b/lib/SAML2/LogoutRequest.php
index 710c58f77..ea3790d69 100644
--- a/lib/SAML2/LogoutRequest.php
+++ b/lib/SAML2/LogoutRequest.php
@@ -9,6 +9,16 @@
 class SAML2_LogoutRequest extends SAML2_Request {
 
 
+	/**
+	 * 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.
 	 *
@@ -39,11 +49,19 @@ class SAML2_LogoutRequest extends SAML2_Request {
 			return;
 		}
 
-		$nameId = SAML2_Utils::xpQuery($xml, './saml_assertion:NameID');
+		$nameId = SAML2_Utils::xpQuery($xml, './saml_assertion:NameID | ./saml_assertion:EncryptedID/xenc:EncryptedData');
 		if (empty($nameId)) {
-			throw new Exception('Missing NameID in logout request.');
+			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);
 		}
-		$this->nameId = SAML2_Utils::parseNameId($nameId[0]);
 
 		$sessionIndexes = SAML2_Utils::xpQuery($xml, './saml_protocol:SessionIndex');
 		foreach ($sessionIndexes as $sessionIndex) {
@@ -52,12 +70,80 @@ class SAML2_LogoutRequest extends SAML2_Request {
 	}
 
 
+	/**
+	 * 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;
+
+
+		/* 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.
+	 */
+	public function decryptNameId(XMLSecurityKey $key) {
+
+		if ($this->encryptedNameId === NULL) {
+			/* No NameID to decrypt. */
+			return;
+		}
+
+		$nameId = SAML2_Utils::decryptElement($this->encryptedNameId, $key);
+		$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;
 	}
 
@@ -137,7 +223,13 @@ class SAML2_LogoutRequest extends SAML2_Request {
 
 		$root = parent::toUnsignedXML();
 
-		SAML2_Utils::addNameId($root, $this->nameId);
+		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);
@@ -147,6 +239,3 @@ class SAML2_LogoutRequest extends SAML2_Request {
 	}
 
 }
-
-
-?>
\ No newline at end of file
-- 
GitLab