Skip to content
Snippets Groups Projects
Commit 8bc1cbc2 authored by Patrick Radtke's avatar Patrick Radtke
Browse files

RegistrationInfo can be inherited from EntitiesDescriptor

parent d1208f56
No related branches found
No related tags found
No related merge requests found
......@@ -159,11 +159,13 @@ class SimpleSAML_Metadata_SAMLParser
* @param int|NULL $maxExpireTime The unix timestamp for when this entity should expire, or
* NULL if unknown.
* @param array $validators An array of parent elements that may validate this element.
* @param array $parentExtensions An optional array of extensions from the parent element.
*/
private function __construct(
SAML2_XML_md_EntityDescriptor $entityElement,
$maxExpireTime,
array $validators = array()
array $validators = array(),
array $parentExtensions = null
) {
assert('is_null($maxExpireTime) || is_int($maxExpireTime)');
......@@ -181,7 +183,7 @@ class SimpleSAML_Metadata_SAMLParser
$this->validators[] = $entityElement;
// process Extensions element, if it exists
$ext = self::processExtensions($entityElement);
$ext = self::processExtensions($entityElement, $parentExtensions);
$this->scopes = $ext['scope'];
$this->tags = $ext['tags'];
$this->entityAttributes = $ext['EntityAttributes'];
......@@ -379,15 +381,21 @@ class SimpleSAML_Metadata_SAMLParser
* of the entities.
* @param array $validators The parent-elements that may be
* signed.
* @param array $parentExtensions An optional array of
* extensions from the parent element.
*
* @return SimpleSAML_Metadata_SAMLParser[] Array of SAMLParser instances.
*/
private static function processDescriptorsElement($element, $maxExpireTime = null, array $validators = array())
{
private static function processDescriptorsElement(
$element,
$maxExpireTime = null,
array $validators = array(),
array $parentExtensions = array()
) {
assert('is_null($maxExpireTime) || is_int($maxExpireTime)');
if ($element instanceof SAML2_XML_md_EntityDescriptor) {
$ret = new SimpleSAML_Metadata_SAMLParser($element, $maxExpireTime, $validators);
$ret = new SimpleSAML_Metadata_SAMLParser($element, $maxExpireTime, $validators, $parentExtensions);
$ret = array($ret->getEntityId() => $ret);
/** @var SimpleSAML_Metadata_SAMLParser[] $ret */
return $ret;
......@@ -395,13 +403,14 @@ class SimpleSAML_Metadata_SAMLParser
assert('$element instanceof SAML2_XML_md_EntitiesDescriptor');
$extensions = self::processExtensions($element, $parentExtensions);
$expTime = self::getExpireTime($element, $maxExpireTime);
$validators[] = $element;
$ret = array();
foreach ($element->children as $child) {
$ret += self::processDescriptorsElement($child, $expTime, $validators);
$ret += self::processDescriptorsElement($child, $expTime, $validators, $extensions);
}
return $ret;
......@@ -992,13 +1001,15 @@ class SimpleSAML_Metadata_SAMLParser
/**
* Parse an Extensions element.
* Parse an Extensions element. Extensions may appear in multiple elements and certain extension may get inherited
* from a parent element.
*
* @param mixed $element The element which contains the Extensions element.
* @param array $parentExtensions An optional array of extensions from the parent element.
*
* @return array An associative array with the extensions parsed.
*/
private static function processExtensions($element)
private static function processExtensions($element, $parentExtensions = array())
{
$ret = array(
'scope' => array(),
......@@ -1009,6 +1020,12 @@ class SimpleSAML_Metadata_SAMLParser
'DiscoHints' => array(),
);
// Some extensions may get inherited from a parent element
if (($element instanceof SAML2_XML_md_EntityDescriptor || $element instanceof SAML2_XML_md_EntitiesDescriptor)
&& !empty($parentExtensions['RegistrationInfo'])) {
$ret['RegistrationInfo'] = $parentExtensions['RegistrationInfo'];
}
foreach ($element->Extensions as $e) {
if ($e instanceof SAML2_XML_shibmd_Scope) {
......@@ -1017,9 +1034,18 @@ class SimpleSAML_Metadata_SAMLParser
}
// Entity Attributes are only allowed at entity level extensions and not at RoleDescriptor level
if ($element instanceof SAML2_XML_md_EntityDescriptor) {
if ($element instanceof SAML2_XML_md_EntityDescriptor ||
$element instanceof SAML2_XML_md_EntitiesDescriptor) {
if ($e instanceof SAML2_XML_mdrpi_RegistrationInfo) {
$ret['RegistrationInfo']['registrationAuthority'] = $e->registrationAuthority;
// Registration Authority cannot be overridden
if (isset($ret['RegistrationInfo']['registrationAuthority'])) {
SimpleSAML_Logger::debug('Invalid attempt to override registrationAuthority '
. $ret['RegistrationInfo']['registrationAuthority'] . " with {$e->registrationAuthority}");
} else {
$ret['RegistrationInfo']['registrationAuthority'] = $e->registrationAuthority;
}
}
if ($e instanceof SAML2_XML_mdattr_EntityAttributes && !empty($e->children)) {
foreach ($e->children as $attr) {
......
......@@ -18,23 +18,71 @@ class SAMLParserTest extends \PHPUnit_Framework_TestCase
$document = \SAML2_DOMDocumentFactory::fromString(
<<<XML
<EntityDescriptor entityID="theEntityID"
xmlns="urn:oasis:names:tc:SAML:2.0:metadata" xmlns:mdrpi="urn:oasis:names:tc:SAML:metadata:rpi">
<EntitiesDescriptor xmlns="urn:oasis:names:tc:SAML:2.0:metadata" xmlns:mdrpi="urn:oasis:names:tc:SAML:metadata:rpi">
<EntityDescriptor entityID="theEntityID">
<Extensions>
<mdrpi:RegistrationInfo registrationAuthority="https://incommon.org"/>
</Extensions>
<SPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol"/>
</EntityDescriptor>
</EntitiesDescriptor>
XML
);
$entities = \SimpleSAML_Metadata_SAMLParser::parseDescriptorsElement($document->documentElement);
$this->assertArrayHasKey('theEntityID', $entities);
// RegistrationInfo is accessible in the SP or IDP metadata accessors
$metadata = $entities['theEntityID']->getMetadata20SP();
$this->assertEquals($expected, $metadata['RegistrationInfo']);
}
/**
* Test RegistrationInfo is inherited correctly from parent EntitiesDescriptor.
* According to the spec overriding RegistrationInfo is not valid. We ignore attempts to override
*/
public function testRegistrationInfoInheritance()
{
$expected = array(
'registrationAuthority' => 'https://incommon.org',
);
$document = \SAML2_DOMDocumentFactory::fromString(
<<<XML
<EntitiesDescriptor xmlns="urn:oasis:names:tc:SAML:2.0:metadata" xmlns:mdrpi="urn:oasis:names:tc:SAML:metadata:rpi">
<Extensions>
<mdrpi:RegistrationInfo registrationAuthority="https://incommon.org"/>
</Extensions>
<SPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
</SPSSODescriptor>
</EntityDescriptor>
</Extensions>
<EntityDescriptor entityID="theEntityID">
<SPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol"/>
</EntityDescriptor>
<EntitiesDescriptor>
<EntityDescriptor entityID="subEntityId">
<SPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol"/>
</EntityDescriptor>
<EntityDescriptor entityID="subEntityIdOverride">
<Extensions>
<mdrpi:RegistrationInfo registrationAuthority="overrides-are-ignored"/>
</Extensions>
<SPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol"/>
</EntityDescriptor>
</EntitiesDescriptor>
</EntitiesDescriptor>
XML
);
$entities = \SimpleSAML_Metadata_SAMLParser::parseDescriptorsElement($document->documentElement);
$this->assertArrayHasKey('theEntityID', $entities);
$this->assertArrayHasKey('subEntityId', $entities);
// RegistrationInfo is accessible in the SP or IDP metadata accessors
$metadata = $entities['theEntityID']->getMetadata20SP();
$this->assertEquals($expected, $metadata['RegistrationInfo']);
$metadata = $entities['subEntityId']->getMetadata20SP();
$this->assertEquals($expected, $metadata['RegistrationInfo']);
$metadata = $entities['subEntityIdOverride']->getMetadata20SP();
$this->assertEquals($expected, $metadata['RegistrationInfo']);
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment