Skip to content

Commit 30b6a7b

Browse files
authored
Merge pull request from GHSA-ccvh-jh5x-mpg4
Improper authentication
2 parents 35ef7e9 + 31b896d commit 30b6a7b

File tree

11 files changed

+404
-6
lines changed

11 files changed

+404
-6
lines changed

Diff for: classes/Context.php

+2
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,8 @@ public function updateCustomer(Customer $customer)
359359
$this->cookie->id_cart = (int) $this->cart->id;
360360
$this->cookie->write();
361361
$this->cart->autosetProductAddress();
362+
363+
$this->cookie->registerSession(new CustomerSession());
362364
}
363365

364366
/**

Diff for: classes/Cookie.php

+91-1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
* International Registered Trademark & Property of PrestaShop SA
2525
*/
2626
use Defuse\Crypto\Key;
27+
use PrestaShop\PrestaShop\Core\Exception\CoreException;
28+
use PrestaShop\PrestaShop\Core\Session\SessionInterface;
2729

2830
class CookieCore
2931
{
@@ -246,7 +248,8 @@ public function isLoggedBack()
246248
*/
247249
public function logout()
248250
{
249-
$this->_content = array();
251+
$this->deleteSession();
252+
$this->_content = [];
250253
$this->encryptAndSetCookie();
251254
unset($_COOKIE[$this->_name]);
252255
$this->_modified = true;
@@ -453,4 +456,91 @@ public function exists()
453456
{
454457
return isset($_COOKIE[$this->_name]);
455458
}
459+
460+
/**
461+
* Register a new session
462+
*
463+
* @param SessionInterface $session
464+
*/
465+
public function registerSession(SessionInterface $session)
466+
{
467+
if (isset($this->id_employee)) {
468+
$session->setUserId((int) $this->id_employee);
469+
} elseif (isset($this->id_customer)) {
470+
$session->setUserId((int) $this->id_customer);
471+
} else {
472+
throw new CoreException('Invalid user id');
473+
}
474+
475+
$session->setToken(sha1(time() . uniqid()));
476+
$session->add();
477+
478+
$this->session_id = $session->getId();
479+
$this->session_token = $session->getToken();
480+
}
481+
482+
/**
483+
* Delete session
484+
*
485+
* @return bool
486+
*/
487+
public function deleteSession()
488+
{
489+
if (!isset($this->session_id)) {
490+
return false;
491+
}
492+
493+
$session = $this->getSession($this->session_id);
494+
if ($session !== null) {
495+
$session->delete();
496+
497+
return true;
498+
}
499+
500+
return false;
501+
}
502+
503+
/**
504+
* Check if this session is still alive
505+
*
506+
* @return bool
507+
*/
508+
public function isSessionAlive()
509+
{
510+
if (!isset($this->session_id, $this->session_token)) {
511+
return false;
512+
}
513+
514+
$session = $this->getSession($this->session_id);
515+
516+
return
517+
$session !== null
518+
&& $session->getToken() === $this->session_token
519+
&& (
520+
(int) $this->id_employee === $session->getUserId()
521+
|| (int) $this->id_customer === $session->getUserId()
522+
)
523+
;
524+
}
525+
526+
/**
527+
* Retrieve session based on a session id and the employee or
528+
* customer id
529+
*
530+
* @return SessionInterface|null
531+
*/
532+
public function getSession($sessionId)
533+
{
534+
if (isset($this->id_employee)) {
535+
$session = new EmployeeSession($sessionId);
536+
} elseif (isset($this->id_customer)) {
537+
$session = new CustomerSession($sessionId);
538+
}
539+
540+
if (!empty($session->getId())) {
541+
return $session;
542+
}
543+
544+
return null;
545+
}
456546
}

Diff for: classes/Customer.php

+7-1
Original file line numberDiff line numberDiff line change
@@ -1187,7 +1187,13 @@ public function isLogged($withGuest = false)
11871187
}
11881188

11891189
/* Customer is valid only if it can be load and if object password is the same as database one */
1190-
return $this->logged == 1 && $this->id && Validate::isUnsignedId($this->id) && Customer::checkPassword($this->id, $this->passwd);
1190+
return
1191+
$this->logged == 1
1192+
&& $this->id
1193+
&& Validate::isUnsignedId($this->id)
1194+
&& Customer::checkPassword($this->id, $this->passwd)
1195+
&& Context::getContext()->cookie->isSessionAlive()
1196+
;
11911197
}
11921198

11931199
/**

Diff for: classes/CustomerSession.php

+89
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
<?php
2+
/**
3+
* 2007-2020 PrestaShop SA and Contributors
4+
*
5+
* NOTICE OF LICENSE
6+
*
7+
* This source file is subject to the Open Software License (OSL 3.0)
8+
* that is bundled with this package in the file LICENSE.txt.
9+
* It is also available through the world-wide-web at this URL:
10+
* https://opensource.org/licenses/OSL-3.0
11+
* If you did not receive a copy of the license and are unable to
12+
* obtain it through the world-wide-web, please send an email
13+
* to license@prestashop.com so we can send you a copy immediately.
14+
*
15+
* DISCLAIMER
16+
*
17+
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
18+
* versions in the future. If you wish to customize PrestaShop for your
19+
* needs please refer to https://www.prestashop.com for more information.
20+
*
21+
* @author PrestaShop SA <contact@prestashop.com>
22+
* @copyright 2007-2020 PrestaShop SA and Contributors
23+
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
24+
* International Registered Trademark & Property of PrestaShop SA
25+
*/
26+
use PrestaShop\PrestaShop\Core\Session\SessionInterface;
27+
28+
class CustomerSessionCore extends ObjectModel implements SessionInterface
29+
{
30+
public $id;
31+
32+
/** @var Id Customer */
33+
public $id_customer;
34+
35+
/** @var string Token */
36+
public $token;
37+
38+
/**
39+
* @see ObjectModel::$definition
40+
*/
41+
public static $definition = [
42+
'table' => 'customer_session',
43+
'primary' => 'id_customer_session',
44+
'fields' => [
45+
'id_customer' => ['type' => self::TYPE_INT, 'validate' => 'isUnsignedId', 'required' => true],
46+
'token' => ['type' => self::TYPE_STRING, 'validate' => 'isSha1', 'size' => 40, 'copy_post' => false],
47+
],
48+
];
49+
50+
/**
51+
* {@inheritdoc}
52+
*/
53+
public function getId()
54+
{
55+
return $this->id;
56+
}
57+
58+
/**
59+
* {@inheritdoc}
60+
*/
61+
public function setUserId($idCustomer)
62+
{
63+
$this->id_customer = (int) $idCustomer;
64+
}
65+
66+
/**
67+
* {@inheritdoc}
68+
*/
69+
public function getUserId()
70+
{
71+
return (int) $this->id_customer;
72+
}
73+
74+
/**
75+
* {@inheritdoc}
76+
*/
77+
public function setToken($token)
78+
{
79+
$this->token = (string) $token;
80+
}
81+
82+
/**
83+
* {@inheritdoc}
84+
*/
85+
public function getToken()
86+
{
87+
return $this->token;
88+
}
89+
}

Diff for: classes/Employee.php

+11-2
Original file line numberDiff line numberDiff line change
@@ -480,8 +480,16 @@ public function isLoggedBack()
480480
if (!Cache::isStored('isLoggedBack' . $this->id)) {
481481
/* Employee is valid only if it can be load and if cookie password is the same as database one */
482482
$result = (
483-
$this->id && Validate::isUnsignedId($this->id) && Context::getContext()->cookie && Employee::checkPassword($this->id, Context::getContext()->cookie->passwd)
484-
&& (!isset(Context::getContext()->cookie->remote_addr) || Context::getContext()->cookie->remote_addr == ip2long(Tools::getRemoteAddr()) || !Configuration::get('PS_COOKIE_CHECKIP'))
483+
$this->id
484+
&& Validate::isUnsignedId($this->id)
485+
&& Context::getContext()->cookie
486+
&& Context::getContext()->cookie->isSessionAlive()
487+
&& Employee::checkPassword($this->id, Context::getContext()->cookie->passwd)
488+
&& (
489+
!isset(Context::getContext()->cookie->remote_addr)
490+
|| Context::getContext()->cookie->remote_addr == ip2long(Tools::getRemoteAddr())
491+
|| !Configuration::get('PS_COOKIE_CHECKIP')
492+
)
485493
);
486494
Cache::store('isLoggedBack' . $this->id, $result);
487495

@@ -500,6 +508,7 @@ public function logout()
500508
Context::getContext()->cookie->logout();
501509
Context::getContext()->cookie->write();
502510
}
511+
503512
$this->id = null;
504513
}
505514

Diff for: classes/EmployeeSession.php

+89
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
<?php
2+
/**
3+
* 2007-2020 PrestaShop SA and Contributors
4+
*
5+
* NOTICE OF LICENSE
6+
*
7+
* This source file is subject to the Open Software License (OSL 3.0)
8+
* that is bundled with this package in the file LICENSE.txt.
9+
* It is also available through the world-wide-web at this URL:
10+
* https://opensource.org/licenses/OSL-3.0
11+
* If you did not receive a copy of the license and are unable to
12+
* obtain it through the world-wide-web, please send an email
13+
* to license@prestashop.com so we can send you a copy immediately.
14+
*
15+
* DISCLAIMER
16+
*
17+
* Do not edit or add to this file if you wish to upgrade PrestaShop to newer
18+
* versions in the future. If you wish to customize PrestaShop for your
19+
* needs please refer to https://www.prestashop.com for more information.
20+
*
21+
* @author PrestaShop SA <contact@prestashop.com>
22+
* @copyright 2007-2020 PrestaShop SA and Contributors
23+
* @license https://opensource.org/licenses/OSL-3.0 Open Software License (OSL 3.0)
24+
* International Registered Trademark & Property of PrestaShop SA
25+
*/
26+
use PrestaShop\PrestaShop\Core\Session\SessionInterface;
27+
28+
class EmployeeSessionCore extends ObjectModel implements SessionInterface
29+
{
30+
public $id;
31+
32+
/** @var int Id Employee */
33+
public $id_employee;
34+
35+
/** @var string Token */
36+
public $token;
37+
38+
/**
39+
* @see ObjectModel::$definition
40+
*/
41+
public static $definition = [
42+
'table' => 'employee_session',
43+
'primary' => 'id_employee_session',
44+
'fields' => [
45+
'id_employee' => ['type' => self::TYPE_INT, 'validate' => 'isUnsignedId', 'required' => true],
46+
'token' => ['type' => self::TYPE_STRING, 'validate' => 'isSha1', 'size' => 40, 'copy_post' => false],
47+
],
48+
];
49+
50+
/**
51+
* {@inheritdoc}
52+
*/
53+
public function getId()
54+
{
55+
return $this->id;
56+
}
57+
58+
/**
59+
* {@inheritdoc}
60+
*/
61+
public function setUserId($idEmployee)
62+
{
63+
$this->id_employee = (int) $idEmployee;
64+
}
65+
66+
/**
67+
* {@inheritdoc}
68+
*/
69+
public function getUserId()
70+
{
71+
return (int) $this->id_employee;
72+
}
73+
74+
/**
75+
* {@inheritdoc}
76+
*/
77+
public function setToken($token)
78+
{
79+
$this->token = (string) $token;
80+
}
81+
82+
/**
83+
* {@inheritdoc}
84+
*/
85+
public function getToken()
86+
{
87+
return $this->token;
88+
}
89+
}

Diff for: classes/form/CustomerPersister.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,9 @@ public function save(Customer $customer, $clearTextPassword, $newPassword = '',
5555
{
5656
if ($customer->id) {
5757
return $this->update($customer, $clearTextPassword, $newPassword, $passwordRequired);
58-
} else {
59-
return $this->create($customer, $clearTextPassword);
6058
}
59+
60+
return $this->create($customer, $clearTextPassword);
6161
}
6262

6363
private function update(Customer $customer, $clearTextPassword, $newPassword, $passwordRequired = true)

Diff for: controllers/admin/AdminLoginController.php

+1
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,7 @@ public function processLogin()
213213
$cookie->profile = $this->context->employee->id_profile;
214214
$cookie->passwd = $this->context->employee->passwd;
215215
$cookie->remote_addr = $this->context->employee->remote_addr;
216+
$cookie->registerSession(new EmployeeSession());
216217

217218
if (!Tools::getValue('stay_logged_in')) {
218219
$cookie->last_activity = time();

Diff for: install-dev/data/db_structure.sql

+14
Original file line numberDiff line numberDiff line change
@@ -2829,3 +2829,17 @@ CREATE TABLE IF NOT EXISTS `PREFIX_cms_role_lang` (
28292829
`id_cms_role`, `id_lang`, id_shop
28302830
)
28312831
) ENGINE=ENGINE_TYPE DEFAULT CHARSET=utf8;
2832+
2833+
CREATE TABLE `PREFIX_employee_session` (
2834+
`id_employee_session` int(11) unsigned NOT NULL auto_increment,
2835+
`id_employee` int(10) unsigned DEFAULT NULL,
2836+
`token` varchar(40) DEFAULT NULL,
2837+
PRIMARY KEY `id_employee_session` (`id_employee_session`)
2838+
) ENGINE=ENGINE_TYPE DEFAULT CHARSET=utf8 COLLATION;
2839+
2840+
CREATE TABLE `PREFIX_customer_session` (
2841+
`id_customer_session` int(11) unsigned NOT NULL auto_increment,
2842+
`id_customer` int(10) unsigned DEFAULT NULL,
2843+
`token` varchar(40) DEFAULT NULL,
2844+
PRIMARY KEY `id_customer_session` (`id_customer_session`)
2845+
) ENGINE=ENGINE_TYPE DEFAULT CHARSET=utf8 COLLATION;

Diff for: install-dev/upgrade/sql/1.7.6.6.sql

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
SET SESSION sql_mode='';
2+
SET NAMES 'utf8';
3+
4+
CREATE TABLE `PREFIX_employee_session` (
5+
`id_employee_session` int(11) unsigned NOT NULL auto_increment,
6+
`id_employee` int(10) unsigned DEFAULT NULL,
7+
`token` varchar(40) DEFAULT NULL,
8+
PRIMARY KEY `id_employee_session` (`id_employee_session`)
9+
) ENGINE=ENGINE_TYPE DEFAULT CHARSET=utf8 COLLATION;
10+
11+
CREATE TABLE `PREFIX_customer_session` (
12+
`id_customer_session` int(11) unsigned NOT NULL auto_increment,
13+
`id_customer` int(10) unsigned DEFAULT NULL,
14+
`token` varchar(40) DEFAULT NULL,
15+
PRIMARY KEY `id_customer_session` (`id_customer_session`)
16+
) ENGINE=ENGINE_TYPE DEFAULT CHARSET=utf8 COLLATION;

0 commit comments

Comments
 (0)