From d4108a3ff6a6e982d90521e43116488abe5f5e87 Mon Sep 17 00:00:00 2001
From: Olav Morken <olav.morken@uninett.no>
Date: Mon, 7 Sep 2009 09:25:30 +0000
Subject: [PATCH] SAML: Work around namespace prefix limitation/bug in
 DOMXPath.

If a message contains a namespace prefix on the root node that conflicts
with the prefix used by simpleSAMLphp, XPath will use the original prefix.

This can be a problem if we receive a message with a namespace prefix
of 'saml' instead of 'samlp'.

See: http://bugs.php.net/bug.php?id=49490

git-svn-id: https://simplesamlphp.googlecode.com/svn/trunk@1747 44740490-163a-0410-bde0-09ae8108e29a
---
 lib/SAML2/Assertion.php      | 26 +++++++++++++-------------
 lib/SAML2/AttributeQuery.php |  4 ++--
 lib/SAML2/AuthnRequest.php   |  2 +-
 lib/SAML2/LogoutRequest.php  |  4 ++--
 lib/SAML2/Message.php        |  2 +-
 lib/SAML2/StatusResponse.php |  8 ++++----
 lib/SAML2/SubjectQuery.php   |  4 ++--
 lib/SAML2/Utils.php          |  6 +++---
 8 files changed, 28 insertions(+), 28 deletions(-)

diff --git a/lib/SAML2/Assertion.php b/lib/SAML2/Assertion.php
index 43c6f3139..076000fd0 100644
--- a/lib/SAML2/Assertion.php
+++ b/lib/SAML2/Assertion.php
@@ -190,7 +190,7 @@ class SAML2_Assertion implements SAML2_SignedElement {
 
 		$this->issueInstant = SimpleSAML_Utilities::parseSAML2Time($xml->getAttribute('IssueInstant'));
 
-		$issuer = SAML2_Utils::xpQuery($xml, './saml:Issuer');
+		$issuer = SAML2_Utils::xpQuery($xml, './saml_assertion:Issuer');
 		if (empty($issuer)) {
 			throw new Exception('Missing <saml:Issuer> in assertion.');
 		}
@@ -211,7 +211,7 @@ class SAML2_Assertion implements SAML2_SignedElement {
 	 */
 	private function parseSubject(DOMElement $xml) {
 
-		$subject = SAML2_Utils::xpQuery($xml, './saml:Subject');
+		$subject = SAML2_Utils::xpQuery($xml, './saml_assertion:Subject');
 		if (empty($subject)) {
 			/* No Subject node. */
 			return;
@@ -220,7 +220,7 @@ class SAML2_Assertion implements SAML2_SignedElement {
 		}
 		$subject = $subject[0];
 
-		$nameId = SAML2_Utils::xpQuery($subject, './saml:NameID');
+		$nameId = SAML2_Utils::xpQuery($subject, './saml_assertion:NameID');
 		if (empty($nameId)) {
 			throw new Exception('Missing <saml:NameID> in <saml:Subject>.');
 		} elseif (count($nameId) > 1) {
@@ -229,7 +229,7 @@ class SAML2_Assertion implements SAML2_SignedElement {
 		$nameId = $nameId[0];
 		$this->nameId = SAML2_Utils::parseNameId($nameId);
 
-		$subjectConfirmation = SAML2_Utils::xpQuery($subject, './saml:SubjectConfirmation');
+		$subjectConfirmation = SAML2_Utils::xpQuery($subject, './saml_assertion:SubjectConfirmation');
 		if (empty($subjectConfirmation)) {
 			throw new Exception('Missing <saml:SubjectConfirmation> in <saml:Subject>.');
 		} elseif (count($subjectConfirmation) > 1) {
@@ -246,7 +246,7 @@ class SAML2_Assertion implements SAML2_SignedElement {
 			throw new Exception('Unsupported subject confirmation method: ' . var_export($method, TRUE));
 		}
 
-		$confirmationData = SAML2_Utils::xpQuery($subjectConfirmation, './saml:SubjectConfirmationData');
+		$confirmationData = SAML2_Utils::xpQuery($subjectConfirmation, './saml_assertion:SubjectConfirmationData');
 		if (empty($confirmationData)) {
 			return;
 		} elseif (count($confirmationData) > 1) {
@@ -282,7 +282,7 @@ class SAML2_Assertion implements SAML2_SignedElement {
 	 */
 	private function parseConditions(DOMElement $xml) {
 
-		$conditions = SAML2_Utils::xpQuery($xml, './saml:Conditions');
+		$conditions = SAML2_Utils::xpQuery($xml, './saml_assertion:Conditions');
 		if (empty($conditions)) {
 			/* No <saml:Conditions> node. */
 			return;
@@ -314,7 +314,7 @@ class SAML2_Assertion implements SAML2_SignedElement {
 			}
 			switch ($node->localName) {
 			case 'AudienceRestriction':
-				$audiences = SAML2_Utils::xpQuery($node, './saml:Audience');
+				$audiences = SAML2_Utils::xpQuery($node, './saml_assertion:Audience');
 				foreach ($audiences as &$audience) {
 					$audience = trim($audience->textContent);
 				}
@@ -351,7 +351,7 @@ class SAML2_Assertion implements SAML2_SignedElement {
 	 */
 	private function parseAuthnStatement(DOMElement $xml) {
 
-		$as = SAML2_Utils::xpQuery($xml, './saml:AuthnStatement');
+		$as = SAML2_Utils::xpQuery($xml, './saml_assertion:AuthnStatement');
 		if (empty($as)) {
 			return;
 		} elseif (count($as) > 1) {
@@ -372,7 +372,7 @@ class SAML2_Assertion implements SAML2_SignedElement {
 			$this->sessionIndex = $as->getAttribute('SessionIndex');
 		}
 
-		$ac = SAML2_Utils::xpQuery($as, './saml:AuthnContext');
+		$ac = SAML2_Utils::xpQuery($as, './saml_assertion:AuthnContext');
 		if (empty($ac)) {
 			throw new Exception('Missing required <saml:AuthnContext> in <saml:AuthnStatement>.');
 		} elseif (count($ac) > 1) {
@@ -380,9 +380,9 @@ class SAML2_Assertion implements SAML2_SignedElement {
 		}
 		$ac = $ac[0];
 
-		$accr = SAML2_Utils::xpQuery($ac, './saml:AuthnContextClassRef');
+		$accr = SAML2_Utils::xpQuery($ac, './saml_assertion:AuthnContextClassRef');
 		if (empty($accr)) {
-			$acdr = SAML2_Utils::xpQuery($ac, './saml:AuthnContextDeclRef');
+			$acdr = SAML2_Utils::xpQuery($ac, './saml_assertion:AuthnContextDeclRef');
 			if (empty($acdr)) {
 				throw new Exception('Neither <saml:AuthnContextClassRef> nor <saml:AuthnContextDeclRef> found in <saml:AuthnContext>.');
 			} elseif (count($accr) > 1) {
@@ -405,7 +405,7 @@ class SAML2_Assertion implements SAML2_SignedElement {
 	private function parseAttributes(DOMElement $xml) {
 
 		$firstAttribute = TRUE;
-		$attributes = SAML2_Utils::xpQuery($xml, './saml:AttributeStatement/saml:Attribute');
+		$attributes = SAML2_Utils::xpQuery($xml, './saml_assertion:AttributeStatement/saml_assertion:Attribute');
 		foreach ($attributes as $attribute) {
 			if (!$attribute->hasAttribute('Name')) {
 				throw new Exception('Missing name on <saml:Attribute> element.');
@@ -431,7 +431,7 @@ class SAML2_Assertion implements SAML2_SignedElement {
 				$this->attributes[$name] = array();
 			}
 
-			$values = SAML2_Utils::xpQuery($attribute, './saml:AttributeValue');
+			$values = SAML2_Utils::xpQuery($attribute, './saml_assertion:AttributeValue');
 			foreach ($values as $value) {
 				$this->attributes[$name][] = trim($value->textContent);
 			}
diff --git a/lib/SAML2/AttributeQuery.php b/lib/SAML2/AttributeQuery.php
index 3be052bd3..85e617455 100644
--- a/lib/SAML2/AttributeQuery.php
+++ b/lib/SAML2/AttributeQuery.php
@@ -54,7 +54,7 @@ class SAML2_AttributeQuery extends SAML2_SubjectQuery {
 		}
 
 		$firstAttribute = TRUE;
-		$attributes = SAML2_Utils::xpQuery($xml, './saml:Attribute');
+		$attributes = SAML2_Utils::xpQuery($xml, './saml_assertion:Attribute');
 		foreach ($attributes as $attribute) {
 			if (!$attribute->hasAttribute('Name')) {
 				throw new Exception('Missing name on <saml:Attribute> element.');
@@ -80,7 +80,7 @@ class SAML2_AttributeQuery extends SAML2_SubjectQuery {
 				$this->attributes[$name] = array();
 			}
 
-			$values = SAML2_Utils::xpQuery($attribute, './saml:AttributeValue');
+			$values = SAML2_Utils::xpQuery($attribute, './saml_assertion:AttributeValue');
 			foreach ($values as $value) {
 				$this->attributes[$name][] = trim($value->textContent);
 			}
diff --git a/lib/SAML2/AuthnRequest.php b/lib/SAML2/AuthnRequest.php
index ca7bf9d9d..897b08e02 100644
--- a/lib/SAML2/AuthnRequest.php
+++ b/lib/SAML2/AuthnRequest.php
@@ -74,7 +74,7 @@ class SAML2_AuthnRequest extends SAML2_Request {
 			$this->protocolBinding = $xml->getAttribute('ProtocolBinding');
 		}
 
-		$nameIdPolicy = SAML2_Utils::xpQuery($xml, './samlp:NameIDPolicy');
+		$nameIdPolicy = SAML2_Utils::xpQuery($xml, './saml_protocol:NameIDPolicy');
 		if (!empty($nameIdPolicy)) {
 			$nameIdPolicy = $nameIdPolicy[0];
 			if ($nameIdPolicy->hasAttribute('Format')) {
diff --git a/lib/SAML2/LogoutRequest.php b/lib/SAML2/LogoutRequest.php
index c0718e45b..7cfc7204b 100644
--- a/lib/SAML2/LogoutRequest.php
+++ b/lib/SAML2/LogoutRequest.php
@@ -37,13 +37,13 @@ class SAML2_LogoutRequest extends SAML2_Request {
 			return;
 		}
 
-		$nameId = SAML2_Utils::xpQuery($xml, './saml:NameID');
+		$nameId = SAML2_Utils::xpQuery($xml, './saml_assertion:NameID');
 		if (empty($nameId)) {
 			throw new Exception('Missing NameID in logout request.');
 		}
 		$this->nameId = SAML2_Utils::parseNameId($nameId[0]);
 
-		$sessionIndex = SAML2_Utils::xpQuery($xml, './samlp:SessionIndex');
+		$sessionIndex = SAML2_Utils::xpQuery($xml, './saml_protocol:SessionIndex');
 		if (!empty($sessionIndex)) {
 			$this->sessionIndex = trim($sessionIndex[0]->textContent);
 		}
diff --git a/lib/SAML2/Message.php b/lib/SAML2/Message.php
index b135eca87..b54087eca 100644
--- a/lib/SAML2/Message.php
+++ b/lib/SAML2/Message.php
@@ -140,7 +140,7 @@ abstract class SAML2_Message implements SAML2_SignedElement {
 			$this->destination = $xml->getAttribute('Destination');
 		}
 
-		$issuer = SAML2_Utils::xpQuery($xml, './saml:Issuer');
+		$issuer = SAML2_Utils::xpQuery($xml, './saml_assertion:Issuer');
 		if (!empty($issuer)) {
 			$this->issuer = trim($issuer[0]->textContent);
 		}
diff --git a/lib/SAML2/StatusResponse.php b/lib/SAML2/StatusResponse.php
index cb7422136..6b9f7c760 100644
--- a/lib/SAML2/StatusResponse.php
+++ b/lib/SAML2/StatusResponse.php
@@ -62,13 +62,13 @@ abstract class SAML2_StatusResponse extends SAML2_Message {
 			$this->inResponseTo = $xml->getAttribute('InResponseTo');
 		}
 
-		$status = SAML2_Utils::xpQuery($xml, './samlp:Status');
+		$status = SAML2_Utils::xpQuery($xml, './saml_protocol:Status');
 		if (empty($status)) {
 			throw new Exception('Missing status code on response.');
 		}
 		$status = $status[0];
 
-		$statusCode = SAML2_Utils::xpQuery($status, './samlp:StatusCode');
+		$statusCode = SAML2_Utils::xpQuery($status, './saml_protocol:StatusCode');
 		if (empty($statusCode)) {
 			throw new Exception('Missing status code in status element.');
 		}
@@ -76,12 +76,12 @@ abstract class SAML2_StatusResponse extends SAML2_Message {
 
 		$this->status['Code'] = $statusCode->getAttribute('Value');
 
-		$subCode = SAML2_Utils::xpQuery($statusCode, './samlp:StatusCode');
+		$subCode = SAML2_Utils::xpQuery($statusCode, './saml_protocol:StatusCode');
 		if (!empty($subCode)) {
 			$this->status['SubCode'] = $subCode[0]->getAttribute('Value');
 		}
 
-		$message = SAML2_Utils::xpQuery($status, './samlp:StatusMessage');
+		$message = SAML2_Utils::xpQuery($status, './saml_protocol:StatusMessage');
 		if (!empty($message)) {
 			$this->status['Message'] = trim($message[0]->textContent);
 		}
diff --git a/lib/SAML2/SubjectQuery.php b/lib/SAML2/SubjectQuery.php
index 1dab65b4f..6591f7f7b 100644
--- a/lib/SAML2/SubjectQuery.php
+++ b/lib/SAML2/SubjectQuery.php
@@ -48,7 +48,7 @@ abstract class SAML2_SubjectQuery extends SAML2_Request {
 	 */
 	private function parseSubject(DOMElement $xml) {
 
-		$subject = SAML2_Utils::xpQuery($xml, './saml:Subject');
+		$subject = SAML2_Utils::xpQuery($xml, './saml_assertion:Subject');
 		if (empty($subject)) {
 			/* No Subject node. */
 			throw new Exception('Missing subject in subject query.');
@@ -57,7 +57,7 @@ abstract class SAML2_SubjectQuery extends SAML2_Request {
 		}
 		$subject = $subject[0];
 
-		$nameId = SAML2_Utils::xpQuery($subject, './saml:NameID');
+		$nameId = SAML2_Utils::xpQuery($subject, './saml_assertion:NameID');
 		if (empty($nameId)) {
 			throw new Exception('Missing <saml:NameID> in <saml:Subject>.');
 		} elseif (count($nameId) > 1) {
diff --git a/lib/SAML2/Utils.php b/lib/SAML2/Utils.php
index f62a06052..fe83f12ab 100644
--- a/lib/SAML2/Utils.php
+++ b/lib/SAML2/Utils.php
@@ -115,8 +115,8 @@ class SAML2_Utils {
 
 		if ($xpCache === NULL || !$xpCache->document->isSameNode($node->ownerDocument)) {
 			$xpCache = new DOMXPath($node->ownerDocument);
-			$xpCache->registerNamespace('samlp', SAML2_Const::NS_SAMLP);
-			$xpCache->registerNamespace('saml', SAML2_Const::NS_SAML);
+			$xpCache->registerNamespace('saml_protocol', SAML2_Const::NS_SAMLP);
+			$xpCache->registerNamespace('saml_assertion', SAML2_Const::NS_SAML);
 			$xpCache->registerNamespace('ds', XMLSecurityDSig::XMLDSIGNS);
 			$xpCache->registerNamespace('xenc', XMLSecEnc::XMLENCNS);
 		}
@@ -173,7 +173,7 @@ class SAML2_Utils {
 	public static function addNameId(DOMElement $node, array $nameId) {
 		assert('array_key_exists("Value", $nameId)');
 
-		$xml = $node->ownerDocument->createElementNS(SAML2_Const::NS_SAML, 'saml:NameID');
+		$xml = $node->ownerDocument->createElementNS(SAML2_Const::NS_SAML, 'saml_assertion:NameID');
 		$node->appendChild($xml);
 
 		if (array_key_exists('NameQualifier', $nameId) && $nameId['NameQualifier'] !== NULL) {
-- 
GitLab