From 19540701b622a439dfbcc81b35a2a44174cf8dca Mon Sep 17 00:00:00 2001 From: DualFroz Date: Fri, 11 Sep 2026 23:09:02 +0200 Subject: [PATCH] fix(session): scope the session cookie to the directory without a trailing slash UrlHelper::dir() always returns a trailing slash, so the session cookie was scoped to "/kanboard/". That cookie is not sent back for "/kanboard", which is exactly the url the bundled web.config and .htaccess serve the application on: both rewrite to index.php whenever the request is not a file, so the directory url is never redirected to its trailing-slash form. The first login then stores redirectAfterLogin="/kanboard", redirects there after a successful check, arrives without the session cookie and bounces back to the login form with no error message. Use the directory without the trailing slash, which is what the browser would have picked as the default cookie path anyway and still matches every url below it. --- app/Core/Session/SessionManager.php | 14 ++++++- .../units/Core/Session/SessionManagerTest.php | 38 +++++++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 tests/units/Core/Session/SessionManagerTest.php diff --git a/app/Core/Session/SessionManager.php b/app/Core/Session/SessionManager.php index 0ce0254..7628992 100644 --- a/app/Core/Session/SessionManager.php +++ b/app/Core/Session/SessionManager.php @@ -79,6 +79,18 @@ class SessionManager extends Base session_destroy(); } + /** + * Get the session cookie path, without the trailing slash + * + * @access public + * @return string + */ + public function getCookiePath() + { + $path = rtrim((string) $this->helper->url->dir(), '/'); + return $path === '' ? '/' : $path; + } + /** * Define session settings * @@ -89,7 +101,7 @@ class SessionManager extends Base // Session cookie: HttpOnly and secure flags session_set_cookie_params( SESSION_DURATION, - $this->helper->url->dir() ?: '/', + $this->getCookiePath(), null, $this->request->isHTTPS(), true diff --git a/tests/units/Core/Session/SessionManagerTest.php b/tests/units/Core/Session/SessionManagerTest.php new file mode 100644 index 0000000..f2dbb0a --- /dev/null +++ b/tests/units/Core/Session/SessionManagerTest.php @@ -0,0 +1,38 @@ +assertEquals('/', $this->buildSessionManager('/index.php')->getCookiePath()); + } + + public function testCookiePathInSubDirectoryHasNoTrailingSlash() + { + $this->assertEquals('/kanboard', $this->buildSessionManager('/kanboard/index.php')->getCookiePath()); + } + + public function testCookiePathInNestedSubDirectoryHasNoTrailingSlash() + { + $this->assertEquals('/apps/kanboard', $this->buildSessionManager('/apps/kanboard/index.php')->getCookiePath()); + } + + private function buildSessionManager($phpSelf) + { + $this->container['request'] = new Request( + $this->container, + array( + 'PHP_SELF' => $phpSelf, + 'REQUEST_METHOD' => 'GET', + ) + ); + + return new SessionManager($this->container); + } +}