From 59511d5e62fa54487f39050d86b48e0da5c60a2b Mon Sep 17 00:00:00 2001 From: Dalibor Bogicevic Date: Mon, 20 Jan 2020 08:29:00 +0100 Subject: [PATCH 1/6] Check for cli environment --- src/Auth.php | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/Auth.php b/src/Auth.php index 62c9097..f0a0108 100644 --- a/src/Auth.php +++ b/src/Auth.php @@ -49,13 +49,21 @@ public function __construct($databaseConnection, $ipAddress = null, $dbTablePref $this->sessionResyncInterval = isset($sessionResyncInterval) ? ((int) $sessionResyncInterval) : (60 * 5); $this->rememberCookieName = self::createRememberCookieName(); - $this->initSessionIfNecessary(); - $this->enhanceHttpSecurity(); + if(!$this->isCli()) { + $this->initSessionIfNecessary(); + $this->enhanceHttpSecurity(); + } $this->processRememberDirective(); $this->resyncSessionIfNecessary(); } + /** Check if current environment is a cli s script */ + private function isCli() + { + return PHP_SAPI === 'cli'; + } + /** Initializes the session and sets the correct configuration */ private function initSessionIfNecessary() { if (\session_status() === \PHP_SESSION_NONE) { From 1d4794642f793d1b90d928c681d8fa6707803452 Mon Sep 17 00:00:00 2001 From: Dalibor Bogicevic Date: Tue, 3 Mar 2020 10:13:06 +0100 Subject: [PATCH 2/6] Refine same site settings --- src/Auth.php | 23 +++++++++++++++-------- src/UserManager.php | 4 ++-- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/Auth.php b/src/Auth.php index f0a0108..ac2adf8 100644 --- a/src/Auth.php +++ b/src/Auth.php @@ -32,6 +32,9 @@ final class Auth extends UserManager { private $sessionResyncInterval; /** @var string the name of the cookie used for the 'remember me' feature */ private $rememberCookieName; + /** @var string the name of the cookie used for the 'remember me' feature */ + private $sameSite; + /** * @param PdoDatabase|PdoDsn|\PDO $databaseConnection the database connection to operate on @@ -41,13 +44,14 @@ final class Auth extends UserManager { * @param int|null $sessionResyncInterval (optional) the interval in seconds after which to resynchronize the session data with its authoritative source in the database * @param string|null $dbSchema (optional) the schema name for all database tables used by this component */ - public function __construct($databaseConnection, $ipAddress = null, $dbTablePrefix = null, $throttling = null, $sessionResyncInterval = null, $dbSchema = null) { + public function __construct($databaseConnection, $ipAddress = null, $dbTablePrefix = null, $throttling = null, $sessionResyncInterval = null, $dbSchema = null, $sameSite = 'Strict') { parent::__construct($databaseConnection, $dbTablePrefix, $dbSchema); $this->ipAddress = !empty($ipAddress) ? $ipAddress : (isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : null); $this->throttling = isset($throttling) ? (bool) $throttling : true; $this->sessionResyncInterval = isset($sessionResyncInterval) ? ((int) $sessionResyncInterval) : (60 * 5); $this->rememberCookieName = self::createRememberCookieName(); + $this->sameSite = $sameSite; if(!$this->isCli()) { $this->initSessionIfNecessary(); @@ -75,7 +79,7 @@ private function initSessionIfNecessary() { \ini_set('session.use_trans_sid', 0); // start the session (requests a cookie to be written on the client) - @Session::start(); + @Session::start($this->sameSite); } } @@ -137,7 +141,7 @@ private function processRememberDirective() { // the cookie and its contents have now been proven to be valid $valid = true; - $this->onLoginSuccessful($rememberData['user'], $rememberData['email'], $rememberData['username'], $rememberData['status'], $rememberData['roles_mask'], $rememberData['force_logout'], true); + $this->onLoginSuccessful($rememberData['user'], $rememberData['email'], $rememberData['username'], $rememberData['status'], $rememberData['roles_mask'], $rememberData['force_logout'], true, $this->sameSite); } } } @@ -447,7 +451,7 @@ public function logOutEverywhereElse() { $_SESSION[self::SESSION_FIELD_FORCE_LOGOUT]++; // re-generate the session ID to prevent session fixation attacks (requests a cookie to be written on the client) - Session::regenerate(true); + Session::regenerate(true, $this->sameSite); // if there had been an existing remember directive previously if (isset($previousRememberDirectiveExpiry)) { @@ -553,6 +557,7 @@ private function setRememberCookie($selector, $token, $expires) { $cookie->setDomain($params['domain']); $cookie->setHttpOnly($params['httponly']); $cookie->setSecureOnly($params['secure']); + $cookie->setSameSiteRestriction($this->sameSite); $result = $cookie->save(); if ($result === false) { @@ -567,11 +572,12 @@ private function setRememberCookie($selector, $token, $expires) { $cookie->setDomain($params['domain']); $cookie->setHttpOnly($params['httponly']); $cookie->setSecureOnly($params['secure']); + $cookie->setSameSiteRestriction($this->sameSite); $cookie->delete(); } } - protected function onLoginSuccessful($userId, $email, $username, $status, $roles, $forceLogout, $remembered) { + protected function onLoginSuccessful($userId, $email, $username, $status, $roles, $forceLogout, $remembered, $sameSite = 'Strict') { // update the timestamp of the user's last login try { $this->db->update( @@ -584,7 +590,7 @@ protected function onLoginSuccessful($userId, $email, $username, $status, $roles throw new DatabaseError($e->getMessage()); } - parent::onLoginSuccessful($userId, $email, $username, $status, $roles, $forceLogout, $remembered); + parent::onLoginSuccessful($userId, $email, $username, $status, $roles, $forceLogout, $remembered, $sameSite); } /** @@ -601,6 +607,7 @@ private function deleteSessionCookie() { $cookie->setDomain($params['domain']); $cookie->setHttpOnly($params['httponly']); $cookie->setSecureOnly($params['secure']); + $cookie->setSameSiteRestriction($this->sameSite); $result = $cookie->delete(); if ($result === false) { @@ -742,7 +749,7 @@ public function confirmEmailAndSignIn($selector, $token, $rememberDuration = nul [ 'id', 'email', 'username', 'status', 'roles_mask', 'force_logout' ] ); - $this->onLoginSuccessful($userData['id'], $userData['email'], $userData['username'], $userData['status'], $userData['roles_mask'], $userData['force_logout'], true); + $this->onLoginSuccessful($userData['id'], $userData['email'], $userData['username'], $userData['status'], $userData['roles_mask'], $userData['force_logout'], true, $this->sameSite); if ($rememberDuration !== null) { $this->createRememberDirective($userData['id'], $rememberDuration); @@ -1078,7 +1085,7 @@ private function authenticateUserInternal($password, $email = null, $username = if ((int) $userData['verified'] === 1) { if (!isset($onBeforeSuccess) || (\is_callable($onBeforeSuccess) && $onBeforeSuccess($userData['id']) === true)) { - $this->onLoginSuccessful($userData['id'], $userData['email'], $userData['username'], $userData['status'], $userData['roles_mask'], $userData['force_logout'], false); + $this->onLoginSuccessful($userData['id'], $userData['email'], $userData['username'], $userData['status'], $userData['roles_mask'], $userData['force_logout'], false, $this->sameSite); // continue to support the old parameter format if ($rememberDuration === true) { diff --git a/src/UserManager.php b/src/UserManager.php index fa31381..83c009f 100644 --- a/src/UserManager.php +++ b/src/UserManager.php @@ -229,9 +229,9 @@ protected function updatePasswordInternal($userId, $newPassword) { * @param bool $remembered whether the user has been remembered (instead of them having authenticated actively) * @throws AuthError if an internal problem occurred (do *not* catch) */ - protected function onLoginSuccessful($userId, $email, $username, $status, $roles, $forceLogout, $remembered) { + protected function onLoginSuccessful($userId, $email, $username, $status, $roles, $forceLogout, $remembered, $sameSite = 'Strict') { // re-generate the session ID to prevent session fixation attacks (requests a cookie to be written on the client) - Session::regenerate(true); + Session::regenerate(true, $sameSite); // save the user data in the session variables maintained by this library $_SESSION[self::SESSION_FIELD_LOGGED_IN] = true; From 44ba3c2d524d3b74b230c68c477f38a432bd57d7 Mon Sep 17 00:00:00 2001 From: Dalibor Bogicevic Date: Sat, 25 Apr 2020 12:00:54 +0200 Subject: [PATCH 3/6] Update packages --- composer.lock | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/composer.lock b/composer.lock index 88ec086..80f54d1 100644 --- a/composer.lock +++ b/composer.lock @@ -1,7 +1,7 @@ { "_readme": [ "This file locks the dependencies of your project to a known state", - "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], "content-hash": "e4acd9e4ba13c4d0692f07a03a454859", @@ -49,16 +49,16 @@ }, { "name": "delight-im/cookie", - "version": "v3.1.0", + "version": "v3.4.0", "source": { "type": "git", "url": "https://github.com/delight-im/PHP-Cookie.git", - "reference": "76ef2a21817cf7a034f85fc3f4d4bfc60f873947" + "reference": "67065d34272377d63bab0bd58f984f9b228c803f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/delight-im/PHP-Cookie/zipball/76ef2a21817cf7a034f85fc3f4d4bfc60f873947", - "reference": "76ef2a21817cf7a034f85fc3f4d4bfc60f873947", + "url": "https://api.github.com/repos/delight-im/PHP-Cookie/zipball/67065d34272377d63bab0bd58f984f9b228c803f", + "reference": "67065d34272377d63bab0bd58f984f9b228c803f", "shasum": "" }, "require": { @@ -86,20 +86,20 @@ "samesite", "xss" ], - "time": "2017-10-18T19:48:59+00:00" + "time": "2020-04-16T11:01:26+00:00" }, { "name": "delight-im/db", - "version": "v1.3.0", + "version": "v1.3.1", "source": { "type": "git", "url": "https://github.com/delight-im/PHP-DB.git", - "reference": "7a03da20b5592fa445c10cd6c7245d51037292c4" + "reference": "7d6f4c7a7e8ba6a297bfc30d65702479fd0b5f7c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/delight-im/PHP-DB/zipball/7a03da20b5592fa445c10cd6c7245d51037292c4", - "reference": "7a03da20b5592fa445c10cd6c7245d51037292c4", + "url": "https://api.github.com/repos/delight-im/PHP-DB/zipball/7d6f4c7a7e8ba6a297bfc30d65702479fd0b5f7c", + "reference": "7d6f4c7a7e8ba6a297bfc30d65702479fd0b5f7c", "shasum": "" }, "require": { @@ -127,7 +127,7 @@ "sql", "sqlite" ], - "time": "2018-08-28T18:23:01+00:00" + "time": "2020-02-21T10:46:03+00:00" }, { "name": "delight-im/http", From d12a2deb6f5f55fcec1d0d1ff5c8f9623c7a2dd7 Mon Sep 17 00:00:00 2001 From: Dalibor Bogicevic Date: Mon, 27 Apr 2020 08:16:33 +0200 Subject: [PATCH 4/6] Disable session start --- src/Auth.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Auth.php b/src/Auth.php index ac2adf8..d5f9f61 100644 --- a/src/Auth.php +++ b/src/Auth.php @@ -79,7 +79,7 @@ private function initSessionIfNecessary() { \ini_set('session.use_trans_sid', 0); // start the session (requests a cookie to be written on the client) - @Session::start($this->sameSite); + //@Session::start($this->sameSite); } } From 6685ceb2ae1b3cd6357bcbe02e92d5dabaad2dc4 Mon Sep 17 00:00:00 2001 From: Dalibor Bogicevic Date: Mon, 27 Apr 2020 09:23:02 +0200 Subject: [PATCH 5/6] Use custom fork for cookie lib --- composer.json | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index da0d9c0..e4c58b2 100644 --- a/composer.json +++ b/composer.json @@ -1,11 +1,17 @@ { "name": "delight-im/auth", "description": "Authentication for PHP. Simple, lightweight and secure.", - "require": { + "repositories": [ + { + "type": "vcs", + "url": "https://github.com/cewlbird/PHP-Cookie.git" + } + ], + "require": { "php": ">=5.6.0", "ext-openssl": "*", "delight-im/base64": "^1.0", - "delight-im/cookie": "^3.1", + "delight-im/cookie": "dev-custom", "delight-im/db": "^1.3" }, "type": "library", From 2d9637eefe2854e17818b66a160cdbb8e9505032 Mon Sep 17 00:00:00 2001 From: Dalibor Bogicevic Date: Mon, 27 Apr 2020 09:45:46 +0200 Subject: [PATCH 6/6] Add minimum stability dev --- composer.json | 3 ++- composer.lock | 22 +++++++++++++--------- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/composer.json b/composer.json index e4c58b2..89825a1 100644 --- a/composer.json +++ b/composer.json @@ -22,5 +22,6 @@ "psr-4": { "Delight\\Auth\\": "src/" } - } + }, + "minimum-stability": "dev" } diff --git a/composer.lock b/composer.lock index 80f54d1..d8d2fe8 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "e4acd9e4ba13c4d0692f07a03a454859", + "content-hash": "72ddc6aaeebd7637318b8432f2daff0a", "packages": [ { "name": "delight-im/base64", @@ -49,16 +49,16 @@ }, { "name": "delight-im/cookie", - "version": "v3.4.0", + "version": "dev-custom", "source": { "type": "git", - "url": "https://github.com/delight-im/PHP-Cookie.git", - "reference": "67065d34272377d63bab0bd58f984f9b228c803f" + "url": "https://github.com/cewlbird/PHP-Cookie.git", + "reference": "f43512ee91d857afcb40c464e1c2b9073312bcc5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/delight-im/PHP-Cookie/zipball/67065d34272377d63bab0bd58f984f9b228c803f", - "reference": "67065d34272377d63bab0bd58f984f9b228c803f", + "url": "https://api.github.com/repos/cewlbird/PHP-Cookie/zipball/f43512ee91d857afcb40c464e1c2b9073312bcc5", + "reference": "f43512ee91d857afcb40c464e1c2b9073312bcc5", "shasum": "" }, "require": { @@ -71,7 +71,6 @@ "Delight\\Cookie\\": "src/" } }, - "notification-url": "https://packagist.org/downloads/", "license": [ "MIT" ], @@ -86,7 +85,10 @@ "samesite", "xss" ], - "time": "2020-04-16T11:01:26+00:00" + "support": { + "source": "https://github.com/cewlbird/PHP-Cookie/tree/custom" + }, + "time": "2020-04-27T07:18:43+00:00" }, { "name": "delight-im/db", @@ -169,7 +171,9 @@ "packages-dev": [], "aliases": [], "minimum-stability": "stable", - "stability-flags": [], + "stability-flags": { + "delight-im/cookie": 20 + }, "prefer-stable": false, "prefer-lowest": false, "platform": {