diff --git a/docs/simplesamlphp-reference-idp-hosted.md b/docs/simplesamlphp-reference-idp-hosted.md index 122814f7e52ac7551c4ca1a0f96b8f6b4c5569c2..2730c1178356b3403726114acc1c736541ac75d5 100644 --- a/docs/simplesamlphp-reference-idp-hosted.md +++ b/docs/simplesamlphp-reference-idp-hosted.md @@ -381,6 +381,10 @@ See the documentation for those extensions for more details: * [MDRPI extension](./simplesamlphp-metadata-extensions-rpi) * [EntityAttributes](./simplesamlphp-metadata-extensions-attributes) +For other metadata extensions, you can use the `saml:Extensions` option: + +`saml:Extensions` +: An array of `\SAML2\XML\Chunk`s to include in the IdP metadata extensions, at the same level as `EntityAttributes`. Examples -------- @@ -411,3 +415,40 @@ These are some examples of IdP metadata */ 'auth' => 'example-userpass', ]; + +### A custom metadata extension (eduGAIN republish request) ### + +``` +<?php + +$dom = \SAML2\DOMDocumentFactory::create(); +$republishRequest = $dom->createElementNS('http://eduid.cz/schema/metadata/1.0', 'eduidmd:RepublishRequest'); +$republishTarget = $dom->createElementNS('http://eduid.cz/schema/metadata/1.0', 'eduidmd:RepublishTarget', 'http://edugain.org/'); +$republishRequest->appendChild($republishTarget); +$ext = [new \SAML2\XML\Chunk($republishRequest)]; + +$metadata['__DYNAMIC:1__'] = [ + 'host' => '__DEFAULT__', + 'certificate' => 'example.org.crt', + 'privatekey' => 'example.org.pem', + 'auth' => 'example-userpass', + + /* + * The custom metadata extensions. + */ + 'saml:Extensions' => $ext, +]; +``` + +this generates the following metadata: + +``` +<EntityDescriptor entityID="..."> + <Extensions xmlns="urn:oasis:names:tc:SAML:2.0:metadata"> + <eduidmd:RepublishRequest xmlns:eduidmd="http://eduid.cz/schema/metadata/1.0"> + <eduidmd:RepublishTarget>http://edugain.org/</eduidmd:RepublishTarget> + </eduidmd:RepublishRequest> + </Extensions> + <!-- rest of metadata --> +</EntityDescriptor> +``` diff --git a/lib/SimpleSAML/Metadata/SAMLBuilder.php b/lib/SimpleSAML/Metadata/SAMLBuilder.php index 47d873405f9b1d9dc67e9d3b9a19fb1fdf964a7e..a41931cce655cfa61bb7ce8df54abd35ca026fb8 100644 --- a/lib/SimpleSAML/Metadata/SAMLBuilder.php +++ b/lib/SimpleSAML/Metadata/SAMLBuilder.php @@ -225,6 +225,12 @@ class SAMLBuilder ); } + if ($metadata->hasValue('saml:Extensions')) { + $this->entityDescriptor->setExtensions( + array_merge($this->entityDescriptor->getExtensions(), $metadata->getArray('saml:Extensions')) + ); + } + if ($metadata->hasValue('RegistrationInfo')) { $ri = new RegistrationInfo(); foreach ($metadata->getArray('RegistrationInfo') as $riName => $riValues) { diff --git a/tests/lib/SimpleSAML/Metadata/SAMLBuilderTest.php b/tests/lib/SimpleSAML/Metadata/SAMLBuilderTest.php index 2998a753a8d49a0dd102b3c4d57ca300edbf90bd..42e254619dffbfaee1724750effa8be53e487189 100644 --- a/tests/lib/SimpleSAML/Metadata/SAMLBuilderTest.php +++ b/tests/lib/SimpleSAML/Metadata/SAMLBuilderTest.php @@ -240,4 +240,44 @@ class SAMLBuilderTest extends TestCase $entityDescriptorXml ); } + + /** + * Test custom metadata extension (saml:Extensions). + */ + public function testCustomMetadataExtension(): void + { + $entityId = 'https://entity.example.com/id'; + $set = 'saml20-idp-remote'; + + $dom = \SAML2\DOMDocumentFactory::create(); + $republishRequest = $dom->createElementNS( + 'http://eduid.cz/schema/metadata/1.0', + 'eduidmd:RepublishRequest' + ); + $republishTargetContent = 'http://edugain.org/'; + $republishTarget = $dom->createElementNS( + 'http://eduid.cz/schema/metadata/1.0', + 'eduidmd:RepublishTarget', + $republishTargetContent + ); + $republishRequest->appendChild($republishTarget); + $ext = [new \SAML2\XML\Chunk($republishRequest)]; + + $metadata = [ + 'entityid' => $entityId, + 'name' => ['en' => 'Test IdP'], + 'metadata-set' => $set, + 'saml:Extensions' => $ext, + ]; + + $samlBuilder = new SAMLBuilder($entityId); + $samlBuilder->addMetadata($set, $metadata); + + $idpDesc = $samlBuilder->getEntityDescriptor(); + $rt = $idpDesc->getElementsByTagNameNS('http://eduid.cz/schema/metadata/1.0', 'RepublishTarget'); + + /** @var \DOMElement $rt1 */ + $rt1 = $rt->item(0); + $this->assertEquals($republishTargetContent, $rt1->textContent); + } } diff --git a/www/saml2/idp/metadata.php b/www/saml2/idp/metadata.php index 2f6807e8ecf6d5d66722c58367c0215e949b0dcd..68404390f2b213293753c5cb7c0d1e3e415aad23 100644 --- a/www/saml2/idp/metadata.php +++ b/www/saml2/idp/metadata.php @@ -173,6 +173,10 @@ try { } } + if ($idpmeta->hasValue('saml:Extensions')) { + $metaArray['saml:Extensions'] = $idpmeta->getArray('saml:Extensions'); + } + if ($idpmeta->hasValue('UIInfo')) { $metaArray['UIInfo'] = $idpmeta->getArray('UIInfo'); }