diff --git a/modules/saml/lib/Auth/Source/SP.php b/modules/saml/lib/Auth/Source/SP.php index 95ac6c55f3c47ee54eaa80f7c1ef2d84831d8764..e82405c4fa9a4dcf8620a7c5f1c525f158c9891d 100644 --- a/modules/saml/lib/Auth/Source/SP.php +++ b/modules/saml/lib/Auth/Source/SP.php @@ -7,6 +7,7 @@ namespace SimpleSAML\Module\saml\Auth\Source; use SAML2\AuthnRequest; use SAML2\Binding; use SAML2\Constants; +use SAML2\LogoutRequest; use SAML2\XML\saml\NameID; use SimpleSAML\Assert\Assert; use SimpleSAML\Auth; @@ -614,7 +615,7 @@ class SP extends \SimpleSAML\Auth\Source $b = Binding::getBinding($dst['Binding']); - $this->sendSAML2AuthnRequest($state, $b, $ar); + $this->sendSAML2AuthnRequest($b, $ar); Assert::true(false); } @@ -625,17 +626,31 @@ class SP extends \SimpleSAML\Auth\Source * * This function does not return. * - * @param array &$state The state array. * @param \SAML2\Binding $binding The binding. * @param \SAML2\AuthnRequest $ar The authentication request. */ - public function sendSAML2AuthnRequest(array &$state, Binding $binding, AuthnRequest $ar): void + public function sendSAML2AuthnRequest(Binding $binding, AuthnRequest $ar): void { $binding->send($ar); Assert::true(false); } + /** + * Function to actually send the logout request. + * + * This function does not return. + * + * @param \SAML2\Binding $binding The binding. + * @param \SAML2\LogoutRequest $ar The logout request. + */ + public function sendSAML2LogoutRequest(Binding $binding, LogoutRequest $lr): void + { + $binding->send($lr); + Assert::true(false); + } + + /** * Send a SSO request to an IdP. * @@ -992,9 +1007,8 @@ class SP extends \SimpleSAML\Auth\Source } $b = Binding::getBinding($endpoint['Binding']); - $b->send($lr); - Assert::true(false); + $this->sendSAML2LogoutRequest($b, $lr); } diff --git a/tests/Utils/SpTester.php b/tests/Utils/SpTester.php index a83396bbca22b987380e19c35e5c435e69d2e01f..7f8d01884b53188f2b09149d3ca8963d07a21848 100644 --- a/tests/Utils/SpTester.php +++ b/tests/Utils/SpTester.php @@ -7,6 +7,7 @@ namespace SimpleSAML\Test\Utils; use ReflectionObject; use SAML2\AuthnRequest; use SAML2\Binding; +use SAML2\LogoutRequest; use SimpleSAML\Configuration; use SimpleSAML\Module\saml\Auth\Source\SP; @@ -41,15 +42,29 @@ class SpTester extends SP /** * override the method that sends the request to avoid sending anything */ - public function sendSAML2AuthnRequest(array &$state, Binding $binding, AuthnRequest $ar): void + public function sendSAML2AuthnRequest(Binding $binding, AuthnRequest $ar): void { // Exit test. Continuing would mean running into a assert(FALSE) throw new ExitTestException( [ - 'state' => $state, 'binding' => $binding, 'ar' => $ar, ] ); } + + + /** + * override the method that sends the request to avoid sending anything + */ + public function sendSAML2LogoutRequest(Binding $binding, LogoutRequest $lr): void + { + // Exit test. Continuing would mean running into a assert(FALSE) + throw new ExitTestException( + [ + 'binding' => $binding, + 'lr' => $lr, + ] + ); + } } diff --git a/tests/modules/saml/lib/Auth/Source/Auth_Source_SP_Test.php b/tests/modules/saml/lib/Auth/Source/Auth_Source_SP_Test.php index 9c697ea1b753b6688440f522f2b7e73dc9717051..d748b61f6d22947b256aa95824eb71c30436cec4 100644 --- a/tests/modules/saml/lib/Auth/Source/Auth_Source_SP_Test.php +++ b/tests/modules/saml/lib/Auth/Source/Auth_Source_SP_Test.php @@ -120,6 +120,33 @@ class SPTest extends ClearStateTestCase } + /** + * Create a SAML LogoutRequest using \SimpleSAML\Module\saml\Auth\Source\SP + * + * @param array $state The state array to use in the test. This is an array of the parameters described in section + * 2 of https://simplesamlphp.org/docs/development/saml:sp + * + * @return \SAML2\LogoutRequest The LogoutRequest generated. + */ + private function createLogoutRequest(array $state = []): LogoutRequest + { + $info = ['AuthId' => 'default-sp']; + $config = ['entityID' => 'https://engine.surfconext.nl/authentication/idp/metadata']; + $as = new SpTester($info, $config); + + /** @var \SAML2\LogoutRequest $lr */ + $lr = null; + try { + $as->startSLO2($state); + $this->assertTrue(false, 'Expected ExitTestException'); + } catch (ExitTestException $e) { + $r = $e->getTestResult(); + $lr = $r['lr']; + } + return $lr; + } + + /** * Test generating an AuthnRequest * @test @@ -394,4 +421,41 @@ class SPTest extends ClearStateTestCase $as = new SpTester($info, $config); $as->authenticate($state); } + + + /** + * Test setting a logout-extension + */ + public function testLogoutExtensions(): void + { + $entityId = "https://example.com"; + $xml = MetaDataStorageSourceTest::generateIdpMetadataXml($entityId); + $c = [ + 'metadata.sources' => [ + ["type" => "xml", "xml" => $xml], + ], + ]; + Configuration::loadFromArray($c, '', 'simplesaml'); + + $state = [ + 'saml:logout:IdP' => 'https://engine.surfconext.nl/authentication/idp/metadata', + 'saml:logout:NameID' => 'someone@example.com', + 'saml:logout:SessionIndex' => 'abc123', + 'saml:logout:Extensions' => [ + 'some extention' + ] + ]; + + $lr = $this->createLogoutRequest($state); + + /** @var \SAML2\XML\samlp\Extensions $extentions */ + $extensions = $lr->getExtensions(); + $this->assertcount(1, $state['saml:logout:Extionsions']); + + $xml = $lr->toSignedXML(); + + /** @var \DOMNode[] $q */ + $q = Utils::xpQuery($xml, '/samlp:AuthnRequest/samlp:Extentions'); + $this->assertCount(1, $q); + } }