Skip to content

Commit

Permalink
Use updated Attribute Value parsing for encrypted attributes
Browse files Browse the repository at this point in the history
  • Loading branch information
DRvanR committed Jan 22, 2016
1 parent dc74049 commit d3b8bb0
Show file tree
Hide file tree
Showing 2 changed files with 124 additions and 23 deletions.
52 changes: 29 additions & 23 deletions src/SAML2/Assertion.php
Original file line number Diff line number Diff line change
Expand Up @@ -501,28 +501,37 @@ private function parseAttributes(\DOMElement $xml)
$this->attributes[$name] = array();
}

$values = Utils::xpQuery($attribute, './saml_assertion:AttributeValue');
foreach ($values as $value) {
$hasNonTextChildElements = false;
foreach ($value->childNodes as $childNode) {
/** @var \DOMNode $childNode */
if ($childNode->nodeType !== XML_TEXT_NODE) {
$hasNonTextChildElements = true;
break;
}
}
$this->parseAttributeValue($attribute, $name);
}
}

if ($hasNonTextChildElements) {
$this->attributes[$name][] = $value->childNodes;
continue;
/**
* @param \DOMNode $attribute
* @param string $attributeName
*/
private function parseAttributeValue($attribute, $attributeName)
{
$values = Utils::xpQuery($attribute, './saml_assertion:AttributeValue');
foreach ($values as $value) {
$hasNonTextChildElements = false;
foreach ($value->childNodes as $childNode) {
/** @var \DOMNode $childNode */
if ($childNode->nodeType !== XML_TEXT_NODE) {
$hasNonTextChildElements = true;
break;
}
}

$type = $value->getAttribute('xsi:type');
if ($type === 'xs:integer') {
$this->attributes[$name][] = (int) $value->textContent;
} else {
$this->attributes[$name][] = trim($value->textContent);
}
if ($hasNonTextChildElements) {
$this->attributes[$attributeName][] = $value->childNodes;
continue;
}

$type = $value->getAttribute('xsi:type');
if ($type === 'xs:integer') {
$this->attributes[$attributeName][] = (int)$value->textContent;
} else {
$this->attributes[$attributeName][] = trim($value->textContent);
}
}
}
Expand Down Expand Up @@ -800,10 +809,7 @@ public function decryptAttributes(XMLSecurityKey $key, array $blacklist = array(
$this->attributes[$name] = array();
}

$values = Utils::xpQuery($attribute, './saml_assertion:AttributeValue');
foreach ($values as $value) {
$this->attributes[$name][] = trim($value->textContent);
}
$this->parseAttributeValue($attribute, $name);
}
}

Expand Down
95 changes: 95 additions & 0 deletions tests/SAML2/AssertionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -456,4 +456,99 @@ public function testTypedAttributeValuesAreParsedCorrectly()
$this->assertInternalType('string', $attributes['urn:some:string'][0]);
$this->assertXmlStringEqualsXmlString($xml, $assertion->toXML()->ownerDocument->saveXML());
}

public function testEncryptedAttributeValuesWithComplexTypeValuesAreParsedCorrectly()
{
$xml = <<<XML
<saml:Assertion
xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
Version="2.0"
ID="_93af655219464fb403b34436cfb0c5cb1d9a5502"
IssueInstant="1970-01-01T01:33:31Z">
<saml:Issuer>Provider</saml:Issuer>
<saml:Conditions/>
<saml:AttributeStatement>
<saml:Attribute Name="urn:oid:1.3.6.1.4.1.5923.1.1.1.10" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri">
<saml:AttributeValue>
<saml:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent">abcd-some-value-xyz</saml:NameID>
</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="urn:mace:dir:attribute-def:eduPersonTargetedID" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri">
<saml:AttributeValue>
<saml:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent">abcd-some-value-xyz</saml:NameID>
</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="urn:EntityConcernedSubID" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri">
<saml:AttributeValue xsi:type="xs:string">string</saml:AttributeValue>
</saml:Attribute>
</saml:AttributeStatement>
</saml:Assertion>
XML;

$privateKey = CertificatesMock::getPublicKey();

$assertion = new Assertion(DOMDocumentFactory::fromString($xml)->firstChild);
$assertion->setEncryptionKey($privateKey);
$assertion->setEncryptedAttributes(true);
$encryptedAssertion = $assertion->toXML()->ownerDocument->saveXML();

$assertionToVerify = new Assertion(DOMDocumentFactory::fromString($encryptedAssertion)->firstChild);

$this->assertTrue($assertionToVerify->hasEncryptedAttributes());

$assertionToVerify->decryptAttributes(CertificatesMock::getPrivateKey());

$attributes = $assertionToVerify->getAttributes();
$this->assertInstanceOf(
'\DOMNodeList',
$attributes['urn:mace:dir:attribute-def:eduPersonTargetedID'][0]
);
$this->assertXmlStringEqualsXmlString($xml, $assertionToVerify->toXML()->ownerDocument->saveXML());
}

public function testTypedEncryptedAttributeValuesAreParsedCorrectly()
{
$xml = <<<XML
<saml:Assertion
xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
Version="2.0"
ID="_93af655219464fb403b34436cfb0c5cb1d9a5502"
IssueInstant="1970-01-01T01:33:31Z">
<saml:Issuer>Provider</saml:Issuer>
<saml:Conditions/>
<saml:AttributeStatement>
<saml:Attribute Name="urn:some:string">
<saml:AttributeValue xsi:type="xs:string">string</saml:AttributeValue>
</saml:Attribute>
<saml:Attribute Name="urn:some:integer">
<saml:AttributeValue xsi:type="xs:integer">42</saml:AttributeValue>
</saml:Attribute>
</saml:AttributeStatement>
</saml:Assertion>
XML;

$privateKey = CertificatesMock::getPublicKey();

$assertion = new Assertion(DOMDocumentFactory::fromString($xml)->firstChild);
$assertion->setEncryptionKey($privateKey);
$assertion->setEncryptedAttributes(true);
$encryptedAssertion = $assertion->toXML()->ownerDocument->saveXML();

$assertionToVerify = new Assertion(DOMDocumentFactory::fromString($encryptedAssertion)->firstChild);

$this->assertTrue($assertionToVerify->hasEncryptedAttributes());

$assertionToVerify->decryptAttributes(CertificatesMock::getPrivateKey());
$attributes = $assertionToVerify->getAttributes();

$this->assertInternalType('int', $attributes['urn:some:integer'][0]);
$this->assertInternalType('string', $attributes['urn:some:string'][0]);
$this->assertXmlStringEqualsXmlString($xml, $assertionToVerify->toXML()->ownerDocument->saveXML());
}
}

0 comments on commit d3b8bb0

Please sign in to comment.