Skip to content

Commit 5f42091

Browse files
Indrani SonawaneIndrani Sonawane
authored andcommitted
Merge remote-tracking branch '30699/ip-range-for-maintenance-mode' into community_prs_march
2 parents 18ffc1d + 7b70808 commit 5f42091

File tree

5 files changed

+484
-36
lines changed

5 files changed

+484
-36
lines changed

app/code/Magento/Backend/Model/Validator/IpValidator.php

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
<?php
2+
23
/**
34
* Copyright © Magento, Inc. All rights reserved.
45
* See COPYING.txt for license details.
56
*/
7+
68
namespace Magento\Backend\Model\Validator;
79

10+
use Magento\Framework\App\Utility\IPAddress;
11+
812
/**
913
* Class to validate list of IPs for maintenance commands
1014
*/
@@ -25,12 +29,22 @@ class IpValidator
2529
*/
2630
private $invalidIps;
2731

32+
/**
33+
* @param IPAddress $ipAddress
34+
*/
35+
public function __construct(
36+
private readonly IPAddress $ipAddress,
37+
) {
38+
}
39+
2840
/**
2941
* Validates list of ips
3042
*
3143
* @param string[] $ips
3244
* @param bool $noneAllowed
45+
*
3346
* @return string[]
47+
*
3448
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
3549
*/
3650
public function validateIps(array $ips, $noneAllowed)
@@ -55,22 +69,26 @@ public function validateIps(array $ips, $noneAllowed)
5569
$messages[] = "Invalid IP $invalidIp";
5670
}
5771
}
72+
5873
return $messages;
5974
}
6075

6176
/**
6277
* Filter ips into 'none', valid and invalid ips
6378
*
6479
* @param string[] $ips
80+
*
6581
* @return void
6682
*/
6783
private function filterIps(array $ips)
6884
{
6985
foreach ($ips as $ip) {
70-
if (filter_var($ip, FILTER_VALIDATE_IP)) {
71-
$this->validIps[] = $ip;
72-
} elseif ($ip == 'none') {
86+
if ($ip === 'none') {
7387
$this->none[] = $ip;
88+
} elseif ($this->ipAddress->isValidAddress($ip)) {
89+
$this->validIps[] = $ip;
90+
} elseif ($this->ipAddress->isValidRange($ip)) {
91+
$this->validIps[] = $ip;
7492
} else {
7593
$this->invalidIps[] = $ip;
7694
}

app/code/Magento/Backend/Test/Unit/Model/Validator/IpValidatorTest.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
namespace Magento\Backend\Test\Unit\Model\Validator;
99

1010
use Magento\Backend\Model\Validator\IpValidator;
11+
use Magento\Framework\App\Utility\IPAddress;
1112
use PHPUnit\Framework\TestCase;
1213

1314
/**
@@ -25,7 +26,9 @@ class IpValidatorTest extends TestCase
2526
*/
2627
protected function setUp(): void
2728
{
28-
$this->ipValidator = new IpValidator();
29+
$this->ipValidator = new IpValidator(
30+
new IPAddress()
31+
);
2932
}
3033

3134
/**
@@ -45,6 +48,7 @@ public function validateIpsNoneAllowedDataProvider(): array
4548
{
4649
return [
4750
[['127.0.0.1', '127.0.0.2'], []],
51+
[['127.0.0.0/24'], []],
4852
[['none'], []],
4953
[['none', '127.0.0.1'], ["Multiple values are not allowed when 'none' is used"]],
5054
[['127.0.0.1', 'none'], ["Multiple values are not allowed when 'none' is used"]],
@@ -72,6 +76,7 @@ public function validateIpsNoneNotAllowedDataProvider()
7276
{
7377
return [
7478
[['127.0.0.1', '127.0.0.2'], []],
79+
[['127.0.0.0/24'], []],
7580
[['none'], ["'none' is not allowed"]],
7681
[['none', '127.0.0.1'], ["'none' is not allowed"]],
7782
[['127.0.0.1', 'none'], ["'none' is not allowed"]],

lib/internal/Magento/Framework/App/MaintenanceMode.php

Lines changed: 43 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
<?php
2+
23
/**
34
* Copyright © Magento, Inc. All rights reserved.
45
* See COPYING.txt for license details.
56
*/
7+
68
namespace Magento\Framework\App;
79

810
use Magento\Framework\App\Filesystem\DirectoryList;
9-
use Magento\Framework\Filesystem;
1011
use Magento\Framework\Event\Manager;
12+
use Magento\Framework\Filesystem;
1113

1214
/**
1315
* Application Maintenance Mode
@@ -17,20 +19,20 @@ class MaintenanceMode
1719
/**
1820
* Maintenance flag file name
1921
*
20-
* DO NOT consolidate this file and the IP white list into one.
22+
* DO NOT consolidate this file and the IP allow list into one.
2123
* It is going to work much faster in 99% of cases: the isOn() will return false whenever file doesn't exist.
2224
*/
23-
const FLAG_FILENAME = '.maintenance.flag';
25+
public const FLAG_FILENAME = '.maintenance.flag';
2426

2527
/**
2628
* IP-addresses file name
2729
*/
28-
const IP_FILENAME = '.maintenance.ip';
30+
public const IP_FILENAME = '.maintenance.ip';
2931

3032
/**
3133
* Maintenance flag dir
3234
*/
33-
const FLAG_DIR = DirectoryList::VAR_DIR;
35+
public const FLAG_DIR = DirectoryList::VAR_DIR;
3436

3537
/**
3638
* Path to store files
@@ -45,36 +47,59 @@ class MaintenanceMode
4547
private $eventManager;
4648

4749
/**
48-
* @param \Magento\Framework\Filesystem $filesystem
50+
* @param Filesystem $filesystem
51+
* @param Utility\IPAddress $ipAddress
4952
* @param Manager|null $eventManager
5053
*/
51-
public function __construct(Filesystem $filesystem, ?Manager $eventManager = null)
52-
{
54+
public function __construct(
55+
Filesystem $filesystem,
56+
private readonly Utility\IPAddress $ipAddress,
57+
Manager $eventManager = null,
58+
) {
5359
$this->flagDir = $filesystem->getDirectoryWrite(self::FLAG_DIR);
5460
$this->eventManager = $eventManager ?: ObjectManager::getInstance()->get(Manager::class);
5561
}
5662

5763
/**
5864
* Checks whether mode is on
5965
*
60-
* Optionally specify an IP-address to compare against the white list
66+
* Optionally specify an IP-address to compare against the allow list
6167
*
6268
* @param string $remoteAddr
69+
*
6370
* @return bool
6471
*/
6572
public function isOn($remoteAddr = '')
6673
{
6774
if (!$this->flagDir->isExist(self::FLAG_FILENAME)) {
6875
return false;
6976
}
70-
$info = $this->getAddressInfo();
71-
return !in_array($remoteAddr, $info);
77+
78+
if ($remoteAddr) {
79+
$allowedAddresses = $this->getAddressInfo();
80+
foreach ($allowedAddresses as $allowed) {
81+
if ($allowed === $remoteAddr) {
82+
return false;
83+
}
84+
85+
if (!$this->ipAddress->isValidRange($allowed)) {
86+
continue;
87+
}
88+
89+
if ($this->ipAddress->rangeContainsAddress($allowed, $remoteAddr)) {
90+
return false;
91+
}
92+
}
93+
}
94+
95+
return true;
7296
}
7397

7498
/**
7599
* Sets maintenance mode "on" or "off"
76100
*
77101
* @param bool $isOn
102+
*
78103
* @return bool
79104
*/
80105
public function set($isOn)
@@ -84,17 +109,21 @@ public function set($isOn)
84109
if ($isOn) {
85110
return $this->flagDir->touch(self::FLAG_FILENAME);
86111
}
112+
87113
if ($this->flagDir->isExist(self::FLAG_FILENAME)) {
88114
return $this->flagDir->delete(self::FLAG_FILENAME);
89115
}
116+
90117
return true;
91118
}
92119

93120
/**
94121
* Sets list of allowed IP addresses
95122
*
96123
* @param string $addresses
124+
*
97125
* @return bool
126+
*
98127
* @throws \InvalidArgumentException
99128
*/
100129
public function setAddresses($addresses)
@@ -104,11 +133,14 @@ public function setAddresses($addresses)
104133
if ($this->flagDir->isExist(self::IP_FILENAME)) {
105134
return $this->flagDir->delete(self::IP_FILENAME);
106135
}
136+
107137
return true;
108138
}
139+
109140
if (!preg_match('/^[^\s,]+(,[^\s,]+)*$/', $addresses)) {
110141
throw new \InvalidArgumentException("One or more IP-addresses is expected (comma-separated)\n");
111142
}
143+
112144
$result = $this->flagDir->writeFile(self::IP_FILENAME, $addresses);
113145
return false !== $result;
114146
}

0 commit comments

Comments
 (0)