Skip to content

Commit 2a91445

Browse files
authored
Backport support for IDP Discovery protocol (#373)
1 parent bdf16d1 commit 2a91445

File tree

9 files changed

+133
-9
lines changed

9 files changed

+133
-9
lines changed

composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,8 @@
4747
"config": {
4848
"allow-plugins": {
4949
"composer/package-versions-deprecated": true,
50-
"dealerdirect/phpcodesniffer-composer-installer": true
50+
"dealerdirect/phpcodesniffer-composer-installer": true,
51+
"phpstan/extension-installer": true
5152
}
5253
}
5354
}

src/SAML2/Constants.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,11 @@ class Constants
231231
*/
232232
const NS_ECP = 'urn:oasis:names:tc:SAML:2.0:profiles:SSO:ecp';
233233

234+
/**
235+
* The namespace for the IDP Discovery protocol.
236+
*/
237+
const NS_IDPDISC = 'urn:oasis:names:tc:SAML:profiles:SSO:idp-discovery-protocol';
238+
234239
/**
235240
* The namespace for the SOAP protocol.
236241
*/

src/SAML2/Utils.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ public static function validateSignature(array $info, XMLSecurityKey $key) : voi
172172

173173
/** @var XMLSecurityDSig $objXMLSecDSig */
174174
$objXMLSecDSig = $info['Signature'];
175-
175+
176176
/**
177177
* @var \DOMElement[] $sigMethod
178178
* @var \DOMElement $objXMLSecDSig->sigNode
@@ -221,6 +221,7 @@ public static function xpQuery(DOMNode $node, string $query) : array
221221
$xpCache->registerNamespace('saml_protocol', Constants::NS_SAMLP);
222222
$xpCache->registerNamespace('saml_assertion', Constants::NS_SAML);
223223
$xpCache->registerNamespace('saml_metadata', Constants::NS_MD);
224+
$xpCache->registerNamespace('saml_idpdisc', Constants::NS_IDPDISC);
224225
$xpCache->registerNamespace('ds', XMLSecurityDSig::XMLDSIGNS);
225226
$xpCache->registerNamespace('xenc', XMLSecEnc::XMLENCNS);
226227
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace SAML2\XML\idpdisc;
6+
7+
use DOMElement;
8+
9+
use SAML2\Constants;
10+
use SAML2\XML\md\IndexedEndpointType;
11+
use Webmozart\Assert\Assert;
12+
13+
/**
14+
* Class representing SAML 2 idpdisc:DiscoveryResponse.
15+
*
16+
* @package SimpleSAMLphp
17+
*/
18+
class DiscoveryResponse extends IndexedEndpointType
19+
{
20+
/**
21+
* Initialize an IndexedEndpointType.
22+
*
23+
* @param \DOMElement|null $xml The XML element we should load.
24+
* @throws \Exception
25+
*/
26+
public function __construct(?DOMElement $xml = null)
27+
{
28+
parent::__construct($xml);
29+
}
30+
31+
32+
/**
33+
* Set the value of the Binding property.
34+
*
35+
* @param string $binding
36+
* @return void
37+
*/
38+
public function setBinding(string $binding) : void
39+
{
40+
Assert::same($binding, Constants::NS_IDPDISC);
41+
42+
parent::setBinding($binding);
43+
}
44+
45+
46+
/**
47+
* Add this endpoint to an XML element.
48+
*
49+
* @param \DOMElement $parent The element we should append this endpoint to.
50+
* @param string $name The name of the element we should create.
51+
* @return \DOMElement
52+
*/
53+
public function toXML(DOMElement $parent, string $name) : DOMElement
54+
{
55+
return $this->toXMLInternal($parent, Constants::NS_IDPDISC, 'idpdisc:DiscoveryResponse');
56+
}
57+
}

src/SAML2/XML/md/EndpointType.php

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ public function __construct(?DOMElement $xml = null)
5959
if (!$xml->hasAttribute('Binding')) {
6060
throw new \Exception('Missing Binding on '.$xml->tagName);
6161
}
62-
$this->Binding = $xml->getAttribute('Binding');
62+
$this->setBinding($xml->getAttribute('Binding'));
6363

6464
if (!$xml->hasAttribute('Location')) {
6565
throw new \Exception('Missing Location on '.$xml->tagName);
@@ -230,11 +230,12 @@ public function setResponseLocation(?string $responseLocation = null) : void
230230
*
231231
* @param \DOMElement $parent The element we should append this endpoint to.
232232
* @param string $name The name of the element we should create.
233+
* @param string $namespace The namespace of the element we should create
233234
* @return \DOMElement
234235
*/
235-
public function toXML(DOMElement $parent, string $name) : DOMElement
236+
protected function toXMLInternal(DOMElement $parent, string $namespace, string $name) : DOMElement
236237
{
237-
$e = $parent->ownerDocument->createElementNS(Constants::NS_MD, $name);
238+
$e = $parent->ownerDocument->createElementNS($namespace, $name);
238239
$parent->appendChild($e);
239240

240241
if (empty($this->Binding)) {
@@ -257,4 +258,17 @@ public function toXML(DOMElement $parent, string $name) : DOMElement
257258

258259
return $e;
259260
}
261+
262+
263+
/**
264+
* Convert this Attribute to XML.
265+
*
266+
* @param \DOMElement $parent The element we should append this Attribute to.
267+
* @param string $name
268+
* @return \DOMElement
269+
*/
270+
public function toXML(DOMElement $parent, string $name) : \DOMElement
271+
{
272+
return $this->toXMLInternal($parent, Constants::NS_MD, $name);
273+
}
260274
}

src/SAML2/XML/md/Extensions.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
use SAML2\XML\alg\DigestMethod;
1313
use SAML2\XML\alg\SigningMethod;
1414
use SAML2\XML\Chunk;
15+
use SAML2\XML\idpdisc\DiscoveryResponse;
1516
use SAML2\XML\mdattr\EntityAttributes;
1617
use SAML2\XML\mdrpi\Common as MDRPI;
1718
use SAML2\XML\mdrpi\PublicationInfo;
@@ -32,6 +33,7 @@ class Extensions
3233
*
3334
* @param \DOMElement $parent The element that may contain the md:Extensions element.
3435
* @return (\SAML2\XML\shibmd\Scope|
36+
* \SAML2\XML\idpdisc\DiscoveryResponse|
3537
* \SAML2\XML\mdattr\EntityAttributes|
3638
* \SAML2\XML\mdrpi\RegistrationInfo|
3739
* \SAML2\XML\mdrpi\PublicationInfo|
@@ -45,6 +47,9 @@ public static function getList(DOMElement $parent) : array
4547
{
4648
$ret = [];
4749
$supported = [
50+
Constants::NS_IDPDISC => [
51+
'DiscoveryResponse' => DiscoveryResponse::class,
52+
],
4853
Scope::NS => [
4954
'Scope' => Scope::class,
5055
],

src/SAML2/XML/md/IndexedEndpointType.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,11 +104,12 @@ public function setIsDefault(?bool $flag = null) : void
104104
*
105105
* @param \DOMElement $parent The element we should append this endpoint to.
106106
* @param string $name The name of the element we should create.
107+
* @param string $namespace The namesapce of the element we should create.
107108
* @return \DOMElement
108109
*/
109-
public function toXML(DOMElement $parent, string $name) : DOMElement
110+
protected function toXMLInternal(DOMElement $parent, string $namespace, string $name) : DOMElement
110111
{
111-
$e = parent::toXML($parent, $name);
112+
$e = parent::toXMLInternal($parent, $namespace, $name);
112113
$e->setAttribute('index', strval($this->index));
113114

114115
if (is_bool($this->isDefault)) {

tests/SAML2/XML/md/EndpointTypeTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ public function testMarshalling() : void
2525

2626
$document = DOMDocumentFactory::fromString('<root />');
2727
$endpointTypeElement = $endpointType->toXML($document->firstChild, 'md:Test');
28-
2928
$endpointTypeElements = Utils::xpQuery($endpointTypeElement, '/root/saml_metadata:Test');
29+
3030
$this->assertCount(1, $endpointTypeElements);
3131
$endpointTypeElement = $endpointTypeElements[0];
3232

tests/SAML2/XML/md/IndexedEndpointTypeTest.php

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@
44

55
namespace SAML2\XML\md;
66

7+
use InvalidArgumentException;
8+
use SAML2\Constants;
79
use SAML2\DOMDocumentFactory;
10+
use SAML2\XML\idpdisc\DiscoveryResponse;
811
use SAML2\XML\md\IndexedEndpointType;
912
use SAML2\Utils;
1013

@@ -16,7 +19,7 @@ class IndexedEndpointTypeTest extends \PHPUnit\Framework\TestCase
1619
/**
1720
* @return void
1821
*/
19-
public function testMarshalling() : void
22+
public function testMarshalling(): void
2023
{
2124
$indexedEndpointType = new IndexedEndpointType();
2225
$indexedEndpointType->setBinding('TestBinding');
@@ -50,4 +53,41 @@ public function testMarshalling() : void
5053
$this->assertCount(1, $indexedEndpointTypeElement);
5154
$this->assertTrue(!$indexedEndpointTypeElement[0]->hasAttribute('isDefault'));
5255
}
56+
57+
58+
/**
59+
* @return void
60+
*/
61+
public function testMarshallingDiscoveryResponse(): void
62+
{
63+
$discoResponse = new DiscoveryResponse();
64+
$discoResponse->setBinding(Constants::NS_IDPDISC);
65+
$discoResponse->setLocation('TestLocation');
66+
$discoResponse->setIndex(42);
67+
$discoResponse->setIsDefault(false);
68+
69+
$document = DOMDocumentFactory::fromString('<root />');
70+
$discoResponseElement = $discoResponse->toXML($document->firstChild, 'idpdisc:DiscoverResponse');
71+
72+
$discoResponseElements = Utils::xpQuery($discoResponseElement, '/root/saml_idpdisc:DiscoveryResponse');
73+
$this->assertCount(1, $discoResponseElements);
74+
$discoResponseElement = $discoResponseElements[0];
75+
76+
$this->assertEquals(Constants::NS_IDPDISC, $discoResponseElement->getAttribute('Binding'));
77+
$this->assertEquals('TestLocation', $discoResponseElement->getAttribute('Location'));
78+
$this->assertEquals('42', $discoResponseElement->getAttribute('index'));
79+
$this->assertEquals('false', $discoResponseElement->getAttribute('isDefault'));
80+
}
81+
82+
83+
/**
84+
* @return void
85+
*/
86+
public function testMarshallingDiscoveryResponseWrongBindingFails(): void
87+
{
88+
$discoResponse = new DiscoveryResponse();
89+
90+
$this->expectException(InvalidArgumentException::class);
91+
$discoResponse->setBinding('This is not OK.');
92+
}
5393
}

0 commit comments

Comments
 (0)