Skip to content

Commit de7f72a

Browse files
committed
New method of importing a decrypted assertion into the XML document to replace the EncryptedAssertion. Fix signature issues on Signed Encrypted Assertions with default namespace
1 parent 3adb517 commit de7f72a

2 files changed

Lines changed: 57 additions & 8 deletions

File tree

src/Saml2/Response.php

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -745,7 +745,7 @@ public function getAttributesWithFriendlyName()
745745
return $this->_getAttributesByKeyName('FriendlyName');
746746
}
747747

748-
private function _getAttributesByKeyName($keyName="Name")
748+
private function _getAttributesByKeyName($keyName = "Name")
749749
{
750750
$attributes = array();
751751
$entries = $this->_queryAssertion('/saml:AttributeStatement/saml:Attribute');
@@ -1090,12 +1090,17 @@ protected function decryptAssertion(\DomNode $dom)
10901090
$objKey->loadKey($key);
10911091
}
10921092

1093-
$decrypted = $objenc->decryptNode($objKey, true);
1094-
1095-
if ($decrypted instanceof DOMDocument) {
1093+
$decryptedXML = $objenc->decryptNode($objKey, false);
1094+
$decrypted = new DOMDocument();
1095+
$check = Utils::loadXML($decrypted, $decryptedXML);
1096+
if ($check === false) {
1097+
throw new Exception('Error: string from decrypted assertion could not be loaded into a XML document');
1098+
}
1099+
if ($encData->parentNode instanceof DOMDocument) {
10961100
return $decrypted;
10971101
} else {
1098-
$encryptedAssertion = $decrypted->parentNode;
1102+
$decrypted = $decrypted->documentElement;
1103+
$encryptedAssertion = $encData->parentNode;
10991104
$container = $encryptedAssertion->parentNode;
11001105

11011106
// Fix possible issue with saml namespace
@@ -1112,13 +1117,14 @@ protected function decryptAssertion(\DomNode $dom)
11121117
} else {
11131118
$ns = 'xmlns';
11141119
}
1115-
11161120
$decrypted->setAttributeNS('http://www.w3.org/2000/xmlns/', $ns, Constants::NS_SAML);
11171121
}
11181122

1119-
$container->replaceChild($decrypted, $encryptedAssertion);
1123+
Utils::treeCopyReplace($encryptedAssertion, $decrypted);
11201124

1121-
return $decrypted->ownerDocument;
1125+
// Rebuild the DOM will fix issues with namespaces as well
1126+
$dom = new DOMDocument();
1127+
return Utils::loadXML($dom, $container->ownerDocument->saveXML());
11221128
}
11231129
}
11241130

src/Saml2/Utils.php

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
use DOMDocument;
2323
use DOMElement;
2424
use DOMNodeList;
25+
use DomNode;
2526
use DOMXPath;
2627
use Exception;
2728

@@ -138,6 +139,48 @@ public static function validateXML($xml, $schema, $debug = false)
138139
return $dom;
139140
}
140141

142+
/**
143+
* Import a node tree into a target document
144+
* Copy it before a reference node as a sibling
145+
* and at the end of the copy remove
146+
* the reference node in the target document
147+
* As it were 'replacing' it
148+
* Leaving nested default namespaces alone
149+
* (Standard importNode with deep copy
150+
* mangles nested default namespaces)
151+
*
152+
* The reference node must not be a DomDocument
153+
* It CAN be the top element of a document
154+
* Returns the copied node in the target document
155+
*
156+
* @param DomNode $targetNode
157+
* @param DomNode $sourceNode
158+
* @param bool $recurse
159+
* @return DOMNode
160+
* @throws Exception
161+
*/
162+
public static function treeCopyReplace(DomNode $targetNode, DomNode $sourceNode, $recurse = false)
163+
{
164+
if ($targetNode->parentNode === null) {
165+
throw new Exception('Illegal argument targetNode. It has no parentNode.');
166+
}
167+
$clonedNode = $targetNode->ownerDocument->importNode($sourceNode, false);
168+
if ($recurse) {
169+
$resultNode = $targetNode->appendChild($clonedNode);
170+
} else {
171+
$resultNode = $targetNode->parentNode->insertBefore($clonedNode, $targetNode);
172+
}
173+
if ($sourceNode->childNodes !== null) {
174+
foreach ($sourceNode->childNodes as $child) {
175+
self::treeCopyReplace($resultNode, $child, true);
176+
}
177+
}
178+
if (!$recurse) {
179+
$targetNode->parentNode->removeChild($targetNode);
180+
}
181+
return $resultNode;
182+
}
183+
141184
/**
142185
* Returns a x509 cert (adding header & footer if required).
143186
*

0 commit comments

Comments
 (0)