From 171720b9cc4e77c52ab444e8fa36f7b4c8ddb6ba Mon Sep 17 00:00:00 2001
From: Tim van Dijen <tvdijen@gmail.com>
Date: Wed, 23 Mar 2022 19:10:11 +0100
Subject: [PATCH] Add as much tests as we can right now

i3x PSR012
---
 composer.lock                                 |  22 +--
 lib/SimpleSAML/IdP/IFrameLogoutHandler.php    |   1 -
 modules/core/lib/Controller/Logout.php        |  23 ++-
 .../core/lib/Controller/LogoutTest.php        | 168 +++++++++++++++++-
 4 files changed, 196 insertions(+), 18 deletions(-)

diff --git a/composer.lock b/composer.lock
index f2ea7b063..b964c40c6 100644
--- a/composer.lock
+++ b/composer.lock
@@ -601,16 +601,16 @@
         },
         {
             "name": "simplesamlphp/saml2",
-            "version": "v4.5.0",
+            "version": "v4.5.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/simplesamlphp/saml2.git",
-                "reference": "d98020c3d7f7331409959eab286ca3a010e5a868"
+                "reference": "88586eb071476a74cd92d50cb789ad45c0b62f1e"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/simplesamlphp/saml2/zipball/d98020c3d7f7331409959eab286ca3a010e5a868",
-                "reference": "d98020c3d7f7331409959eab286ca3a010e5a868",
+                "url": "https://api.github.com/repos/simplesamlphp/saml2/zipball/88586eb071476a74cd92d50cb789ad45c0b62f1e",
+                "reference": "88586eb071476a74cd92d50cb789ad45c0b62f1e",
                 "shasum": ""
             },
             "require": {
@@ -653,9 +653,9 @@
             "description": "SAML2 PHP library from SimpleSAMLphp",
             "support": {
                 "issues": "https://github.com/simplesamlphp/saml2/issues",
-                "source": "https://github.com/simplesamlphp/saml2/tree/v4.5.0"
+                "source": "https://github.com/simplesamlphp/saml2/tree/v4.5.1"
             },
-            "time": "2022-02-17T15:46:12+00:00"
+            "time": "2022-03-22T12:02:23+00:00"
         },
         {
             "name": "symfony/cache",
@@ -6174,16 +6174,16 @@
         },
         {
             "name": "simplesamlphp/simplesamlphp-test-framework",
-            "version": "v1.1.6",
+            "version": "v1.1.7",
             "source": {
                 "type": "git",
                 "url": "https://github.com/simplesamlphp/simplesamlphp-test-framework.git",
-                "reference": "6e2d9a2eb98365d5c3b4faa66e0ea4a95833abd7"
+                "reference": "ffd6f5d68833482cb4473dfa4c26e8be272cbcbc"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/simplesamlphp/simplesamlphp-test-framework/zipball/6e2d9a2eb98365d5c3b4faa66e0ea4a95833abd7",
-                "reference": "6e2d9a2eb98365d5c3b4faa66e0ea4a95833abd7",
+                "url": "https://api.github.com/repos/simplesamlphp/simplesamlphp-test-framework/zipball/ffd6f5d68833482cb4473dfa4c26e8be272cbcbc",
+                "reference": "ffd6f5d68833482cb4473dfa4c26e8be272cbcbc",
                 "shasum": ""
             },
             "require": {
@@ -6227,7 +6227,7 @@
                 "issues": "https://github.com/simplesamlphp/simplesamlphp-test-framework/issues",
                 "source": "https://github.com/simplesamlphp/simplesamlphp-test-framework"
             },
-            "time": "2022-02-13T14:45:14+00:00"
+            "time": "2022-03-22T12:04:35+00:00"
         },
         {
             "name": "simplesamlphp/xml-common",
diff --git a/lib/SimpleSAML/IdP/IFrameLogoutHandler.php b/lib/SimpleSAML/IdP/IFrameLogoutHandler.php
index 5ed469a0b..7541fa268 100644
--- a/lib/SimpleSAML/IdP/IFrameLogoutHandler.php
+++ b/lib/SimpleSAML/IdP/IFrameLogoutHandler.php
@@ -48,7 +48,6 @@ class IFrameLogoutHandler implements LogoutHandlerInterface
      */
     public function startLogout(array &$state, ?string $assocId): void
     {
-\SimpleSAML\Logger::debug("DEBUG");
         $associations = $this->idp->getAssociations();
 
         if (count($associations) === 0) {
diff --git a/modules/core/lib/Controller/Logout.php b/modules/core/lib/Controller/Logout.php
index 039cf98cc..3e3ab60ff 100644
--- a/modules/core/lib/Controller/Logout.php
+++ b/modules/core/lib/Controller/Logout.php
@@ -41,6 +41,12 @@ class Logout
     /** @var \SimpleSAML\Configuration */
     protected Configuration $config;
 
+    /**
+     * @var \SimpleSAML\Auth\State|string
+     * @psalm-var \SimpleSAML\Auth\State|class-string
+     */
+    protected $authState = Auth\State::class;
+
 
     /**
      * Controller constructor.
@@ -56,6 +62,17 @@ class Logout
     }
 
 
+    /**
+     * Inject the \SimpleSAML\Auth\State dependency.
+     *
+     * @param \SimpleSAML\Auth\State $authState
+     */
+    public function setAuthState(Auth\State $authState): void
+    {
+        $this->authState = $authState;
+    }
+
+
     /**
      * Log the user out of a given authentication source.
      *
@@ -110,7 +127,7 @@ class Logout
         $id = $request->query->get('id');
 
         /** @psalm-var array $state */
-        $state = Auth\State::loadState($id, 'core:Logout-IFrame');
+        $state = $this->authState::loadState($id, 'core:Logout-IFrame');
         $idp = IdP::getByState($state);
 
         $associations = $idp->getAssociations();
@@ -258,7 +275,7 @@ class Logout
         }
 
         /** @psalm-var array $state */
-        $state = Auth\State::loadState($id, 'core:Logout-IFrame');
+        $state = $this->authState::loadState($id, 'core:Logout-IFrame');
         $idp = IdP::getByState($state);
         $mdh = MetaDataStorageHandler::getMetadataHandler();
 
@@ -391,7 +408,7 @@ class Logout
         $id = $request->query->get('id');
 
         /** @psalm-var array $state */
-        $state = Auth\State::loadState($id, 'core:Logout:afterbridge');
+        $state = $this->authState::loadState($id, 'core:Logout:afterbridge');
         $idp = IdP::getByState($state);
 
         $assocId = $state['core:TerminatedAssocId'];
diff --git a/tests/modules/core/lib/Controller/LogoutTest.php b/tests/modules/core/lib/Controller/LogoutTest.php
index 6fb32b175..0877b03a2 100644
--- a/tests/modules/core/lib/Controller/LogoutTest.php
+++ b/tests/modules/core/lib/Controller/LogoutTest.php
@@ -8,11 +8,8 @@ use SimpleSAML\Auth;
 use SimpleSAML\Configuration;
 use SimpleSAML\Error;
 use SimpleSAML\HTTP\RunnableResponse;
-//use SimpleSAML\Locale\Localization;
 use SimpleSAML\Module\core\Controller;
 use SimpleSAML\TestUtils\ClearStateTestCase;
-//use SimpleSAML\XHTML\Template;
-//use Symfony\Component\HttpFoundation\RedirectResponse;
 use Symfony\Component\HttpFoundation\Request;
 
 /**
@@ -43,6 +40,7 @@ class LogoutTest extends ClearStateTestCase
             [
                 'baseurlpath' => 'https://example.org/simplesaml',
                 'module.enable' => ['exampleauth' => true],
+                'enable.saml20-idp' => true,
             ],
             '[ARRAY]',
             'simplesaml'
@@ -105,4 +103,168 @@ class LogoutTest extends ClearStateTestCase
         $this->assertInstanceOf(RunnableResponse::class, $response);
         $this->assertEquals('https://example.org/something', $response->getArguments()[0]);
     }
+
+
+    public function testLogoutIframeDoneUnknownEntityThrowsException(): void
+    {
+        $request = Request::create(
+            '/logout-iframe-done',
+            'GET',
+            ['id' => 'someState'],
+        );
+
+        $c = new Controller\Logout($this->config);
+        $c->setAuthState(new class () extends Auth\State {
+            public static function loadState(string $id, string $stage, bool $allowMissing = false): ?array
+            {
+                return ['core:IdP' => 'saml2:something'];
+            }
+        });
+
+        $this->expectException(Error\MetadataNotFound::class);
+        $c->logoutIframeDone($request);
+    }
+
+
+    public function testLogoutIframeDoneWithoutStateThrowsException(): void
+    {
+        $request = Request::create(
+            '/logout-iframe-done',
+            'GET',
+            ['id' => 'someState'],
+        );
+
+        $c = new Controller\Logout($this->config);
+
+        $this->expectException(Error\NoState::class);
+        $c->logoutIframeDone($request);
+    }
+
+
+    public function testLogoutIframeDoneWithoutIdThrowsException(): void
+    {
+        $request = Request::create(
+            '/logout-iframe-done',
+            'GET',
+        );
+
+        $c = new Controller\Logout($this->config);
+
+        $this->expectException(Error\BadRequest::class);
+        $c->logoutIframeDone($request);
+    }
+
+
+    public function testLogoutIframePostWithoutIdpThrowsException(): void
+    {
+        $request = Request::create(
+            '/logout-iframe-post',
+            'GET',
+        );
+
+        $c = new Controller\Logout($this->config);
+
+        $this->expectException(Error\BadRequest::class);
+        $c->logoutIframePost($request);
+    }
+
+
+    public function testLogoutIframePostUnknownEntityThrowsException(): void
+    {
+        $request = Request::create(
+            '/logout-iframe-post',
+            'GET',
+            ['idp' => 'saml2:something'],
+        );
+
+        $c = new Controller\Logout($this->config);
+
+        $this->expectException(Error\MetadataNotFound::class);
+        $c->logoutIframePost($request);
+    }
+
+
+    public function testLogoutIframeWithoutIdThrowsException(): void
+    {
+        $request = Request::create(
+            '/logout-iframe',
+            'GET',
+        );
+
+        $c = new Controller\Logout($this->config);
+
+        $this->expectException(Error\BadRequest::class);
+        $c->logoutIframe($request);
+    }
+
+
+    public function testLogoutIframeWithUnknownTypeThrowsException(): void
+    {
+        $request = Request::create(
+            '/logout-iframe',
+            'GET',
+            ['id' => 'abc123', 'type' => 'foobar'],
+        );
+
+        $c = new Controller\Logout($this->config);
+
+        $this->expectException(Error\BadRequest::class);
+        $c->logoutIframe($request);
+    }
+
+
+    public function testLogoutIframeUnknownEntityThrowsException(): void
+    {
+        $request = Request::create(
+            '/logout-iframe-post',
+            'GET',
+            ['id' => 'abc123', 'type' => 'nojs'],
+        );
+
+        $c = new Controller\Logout($this->config);
+        $c->setAuthState(new class () extends Auth\State {
+            public static function loadState(string $id, string $stage, bool $allowMissing = false): ?array
+            {
+                return ['core:IdP' => 'saml2:something'];
+            }
+        });
+
+        $this->expectException(Error\MetadataNotFound::class);
+        $c->logoutIframe($request);
+    }
+
+
+    public function testResumeLogoutWithoutIdThrowsException(): void
+    {
+        $request = Request::create(
+            '/logout-resume',
+            'GET',
+        );
+
+        $c = new Controller\Logout($this->config);
+
+        $this->expectException(Error\BadRequest::class);
+        $c->resumeLogout($request);
+    }
+
+
+    public function testResumeLogoutWithUnknownEntityThrowsException(): void
+    {
+        $request = Request::create(
+            '/logout-resume',
+            'GET',
+            ['id' => 'abc123'],
+        );
+
+        $c = new Controller\Logout($this->config);
+        $c->setAuthState(new class () extends Auth\State {
+            public static function loadState(string $id, string $stage, bool $allowMissing = false): ?array
+            {
+                return ['core:IdP' => 'saml2:something'];
+            }
+        });
+
+        $this->expectException(Error\MetadataNotFound::class);
+        $c->resumeLogout($request);
+    }
 }
-- 
GitLab