Skip to content

Commit c3834c5

Browse files
committed
MAGETWO-67736: Secure environment variables does not apply properly
1 parent 07f4e70 commit c3834c5

File tree

3 files changed

+187
-55
lines changed

3 files changed

+187
-55
lines changed

app/code/Magento/Config/App/Config/Source/EnvironmentConfigSource.php

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,13 @@ class EnvironmentConfigSource implements ConfigSourceInterface
3030
*/
3131
private $placeholder;
3232

33+
/**
34+
* Variable for caching loaded environment config.
35+
*
36+
* @var DataObject
37+
*/
38+
private $data;
39+
3340
/**
3441
* @param ArrayManager $arrayManager
3542
* @param PlaceholderFactory $placeholderFactory
@@ -47,8 +54,11 @@ public function __construct(
4754
*/
4855
public function get($path = '')
4956
{
50-
$data = new DataObject($this->loadConfig());
51-
return $data->getData($path) ?: [];
57+
if ($this->data === null) {
58+
$this->data = new DataObject($this->loadConfig());
59+
}
60+
61+
return $this->data->getData($path) ?: [];
5262
}
5363

5464
/**

lib/internal/Magento/Framework/App/Config/MetadataConfigTypeProcessor.php

Lines changed: 47 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,15 @@
77
*/
88
namespace Magento\Framework\App\Config;
99

10+
use Magento\Config\App\Config\Source\EnvironmentConfigSource;
11+
use Magento\Framework\App\Config\Data\ProcessorFactory;
1012
use Magento\Framework\App\Config\Spi\PostProcessorInterface;
13+
use Magento\Framework\App\ObjectManager;
1114

1215
class MetadataConfigTypeProcessor implements PostProcessorInterface
1316
{
1417
/**
15-
* @var \Magento\Framework\App\Config\Data\ProcessorFactory
18+
* @var ProcessorFactory
1619
*/
1720
protected $_processorFactory;
1821

@@ -22,15 +25,37 @@ class MetadataConfigTypeProcessor implements PostProcessorInterface
2225
protected $_metadata = [];
2326

2427
/**
25-
* @param \Magento\Framework\App\Config\Data\ProcessorFactory $processorFactory
28+
* The environment configuration
29+
*
30+
* @var EnvironmentConfigSource
31+
*/
32+
private $environmentConfigSource;
33+
34+
/**
35+
* The resolver for configuration paths
36+
*
37+
* @var ConfigPathResolver
38+
*/
39+
private $configPathResolver;
40+
41+
/**
42+
* @param ProcessorFactory $processorFactory
2643
* @param Initial $initialConfig
44+
* @param EnvironmentConfigSource $environmentConfigSource The environment configuration
45+
* @param ConfigPathResolver $configPathResolver The resolver for configuration paths
2746
*/
2847
public function __construct(
29-
\Magento\Framework\App\Config\Data\ProcessorFactory $processorFactory,
30-
Initial $initialConfig
48+
ProcessorFactory $processorFactory,
49+
Initial $initialConfig,
50+
EnvironmentConfigSource $environmentConfigSource = null,
51+
ConfigPathResolver $configPathResolver = null
3152
) {
3253
$this->_processorFactory = $processorFactory;
3354
$this->_metadata = $initialConfig->getMetadata();
55+
$this->environmentConfigSource = $environmentConfigSource
56+
?: ObjectManager::getInstance()->get(EnvironmentConfigSource::class);
57+
$this->configPathResolver = $configPathResolver
58+
?: ObjectManager::getInstance()->get(ConfigPathResolver::class);
3459
}
3560

3661
/**
@@ -75,14 +100,25 @@ protected function _setValue(array &$container, $path, $value)
75100
}
76101

77102
/**
78-
* Process data by sections: stores, default, websites and by scope codes
103+
* Process data by sections: stores, default, websites and by scope codes.
79104
*
80-
* @param array $data
81-
* @return array
105+
* Doesn't processes configuration values that present in $_ENV variables.
106+
*
107+
* @param array $data An array of scope configuration
108+
* @param string $scope The configuration scope
109+
* @param string|null $scopeCode The configuration scope code
110+
* @return array An array of processed configuration
82111
*/
83-
private function processScopeData(array $data)
84-
{
112+
private function processScopeData(
113+
array $data,
114+
$scope = ScopeConfigInterface::SCOPE_TYPE_DEFAULT,
115+
$scopeCode = null
116+
) {
85117
foreach ($this->_metadata as $path => $metadata) {
118+
$configPath = $this->configPathResolver->resolve($path, $scope, $scopeCode);
119+
if (!empty($this->environmentConfigSource->get($configPath))) {
120+
continue;
121+
}
86122
/** @var \Magento\Framework\App\Config\Data\ProcessorInterface $processor */
87123
$processor = $this->_processorFactory->get($metadata['backendModel']);
88124
$value = $processor->processValue($this->_getValue($data, $path));
@@ -95,7 +131,7 @@ private function processScopeData(array $data)
95131
/**
96132
* Process config data
97133
*
98-
* @param array $data
134+
* @param array $rawData An array of configuration
99135
* @return array
100136
*/
101137
public function process(array $rawData)
@@ -106,7 +142,7 @@ public function process(array $rawData)
106142
$processedData[ScopeConfigInterface::SCOPE_TYPE_DEFAULT] = $this->processScopeData($scopeData);
107143
} else {
108144
foreach ($scopeData as $scopeCode => $data) {
109-
$processedData[$scope][$scopeCode] = $this->processScopeData($data);
145+
$processedData[$scope][$scopeCode] = $this->processScopeData($data, $scope, $scopeCode);
110146
}
111147
}
112148
}

lib/internal/Magento/Framework/App/Test/Unit/Config/MetadataConfigTypeProcessorTest.php

Lines changed: 128 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -5,75 +5,161 @@
55
*/
66
namespace Magento\Framework\App\Test\Unit\Config;
77

8+
use Magento\Config\App\Config\Source\EnvironmentConfigSource;
9+
use Magento\Framework\App\Config\ConfigPathResolver;
10+
use Magento\Framework\App\Config\Data\ProcessorFactory;
11+
use Magento\Framework\App\Config\Data\ProcessorInterface;
12+
use Magento\Framework\App\Config\Initial;
13+
use Magento\Framework\App\Config\MetadataConfigTypeProcessor;
14+
use PHPUnit_Framework_MockObject_MockObject as MockObject;
15+
816
class MetadataConfigTypeProcessorTest extends \PHPUnit_Framework_TestCase
917
{
1018
/**
11-
* @var \Magento\Framework\App\Config\MetadataProcessor
19+
* @var MetadataConfigTypeProcessor
1220
*/
1321
protected $_model;
1422

1523
/**
16-
* @var \PHPUnit_Framework_MockObject_MockObject
24+
* @var Initial|MockObject
1725
*/
1826
protected $_initialConfigMock;
1927

2028
/**
21-
* @var \PHPUnit_Framework_MockObject_MockObject
29+
* @var ProcessorFactory|MockObject
2230
*/
2331
protected $_modelPoolMock;
2432

2533
/**
26-
* @var \PHPUnit_Framework_MockObject_MockObject
34+
* @var ProcessorInterface|MockObject
2735
*/
2836
protected $_backendModelMock;
2937

38+
/**
39+
* @var EnvironmentConfigSource|MockObject
40+
*/
41+
private $environmentConfigSourceMock;
42+
43+
/**
44+
* @var ConfigPathResolver|MockObject
45+
*/
46+
private $configPathResolverMock;
47+
3048
protected function setUp()
3149
{
32-
$this->_modelPoolMock = $this->getMock(
33-
\Magento\Framework\App\Config\Data\ProcessorFactory::class,
34-
[],
35-
[],
36-
'',
37-
false
38-
);
39-
$this->_initialConfigMock = $this->getMock(\Magento\Framework\App\Config\Initial::class, [], [], '', false);
40-
$this->_backendModelMock = $this->getMock(\Magento\Framework\App\Config\Data\ProcessorInterface::class);
41-
$this->_initialConfigMock->expects(
42-
$this->any()
43-
)->method(
44-
'getMetadata'
45-
)->will(
46-
$this->returnValue(['some/config/path' => ['backendModel' => 'Custom_Backend_Model']])
47-
);
48-
$this->_model = new \Magento\Framework\App\Config\MetadataConfigTypeProcessor(
50+
$this->_modelPoolMock = $this->getMockBuilder(ProcessorFactory::class)
51+
->disableOriginalConstructor()
52+
->getMock();
53+
$this->_initialConfigMock = $this->getMockBuilder(Initial::class)
54+
->disableOriginalConstructor()
55+
->getMock();
56+
$this->_backendModelMock= $this->getMockBuilder(ProcessorInterface::class)
57+
->getMockForAbstractClass();
58+
$this->environmentConfigSourceMock = $this->getMockBuilder(EnvironmentConfigSource::class)
59+
->disableOriginalConstructor()
60+
->getMock();
61+
$this->configPathResolverMock = $this->getMockBuilder(ConfigPathResolver::class)
62+
->disableOriginalConstructor()
63+
->getMock();
64+
$this->_initialConfigMock->expects($this->once())
65+
->method('getMetadata')
66+
->willReturn([
67+
'some/config/path1' => ['backendModel' => 'Custom_Backend_Model'],
68+
'some/config/path2' => ['backendModel' => 'Custom_Backend_Model'],
69+
'some/config/path3' => ['backendModel' => 'Custom_Backend_Model']
70+
]);
71+
72+
$this->_model = new MetadataConfigTypeProcessor(
4973
$this->_modelPoolMock,
50-
$this->_initialConfigMock
74+
$this->_initialConfigMock,
75+
$this->environmentConfigSourceMock,
76+
$this->configPathResolverMock
5177
);
5278
}
5379

5480
public function testProcess()
5581
{
56-
$this->_modelPoolMock->expects(
57-
$this->once()
58-
)->method(
59-
'get'
60-
)->with(
61-
'Custom_Backend_Model'
62-
)->will(
63-
$this->returnValue($this->_backendModelMock)
64-
);
65-
$this->_backendModelMock->expects(
66-
$this->once()
67-
)->method(
68-
'processValue'
69-
)->with(
70-
'value'
71-
)->will(
72-
$this->returnValue('processed_value')
73-
);
74-
$data = ['default' => [ 'some' => ['config' => ['path' => 'value']], 'active' => 1]];
82+
$this->configPathResolverMock->expects($this->exactly(6))
83+
->method('resolve')
84+
->withConsecutive(
85+
['some/config/path1', 'default'],
86+
['some/config/path2', 'default'],
87+
['some/config/path3', 'default'],
88+
['some/config/path1', 'websites', 'website_one'],
89+
['some/config/path2', 'websites', 'website_one'],
90+
['some/config/path3', 'websites', 'website_one']
91+
)
92+
->willReturnOnConsecutiveCalls(
93+
'default/some/config/path1',
94+
'default/some/config/path2',
95+
'default/some/config/path3',
96+
'websites/website_one/some/config/path1',
97+
'websites/website_one/some/config/path2',
98+
'websites/website_one/some/config/path3'
99+
);
100+
$this->environmentConfigSourceMock->expects($this->exactly(6))
101+
->method('get')
102+
->withConsecutive(
103+
['default/some/config/path1'],
104+
['default/some/config/path2'],
105+
['default/some/config/path3'],
106+
['websites/website_one/some/config/path1'],
107+
['websites/website_one/some/config/path2'],
108+
['websites/website_one/some/config/path3']
109+
)
110+
->willReturnOnConsecutiveCalls(
111+
'someValue',
112+
[],
113+
'someValue',
114+
[],
115+
'someValue',
116+
[]
117+
);
118+
$this->_modelPoolMock->expects($this->exactly(3))
119+
->method('get')
120+
->with('Custom_Backend_Model')
121+
->willReturn($this->_backendModelMock);
122+
$this->_backendModelMock->expects($this->exactly(3))
123+
->method('processValue')
124+
->withConsecutive(
125+
['value2'],
126+
['value1'],
127+
['value3']
128+
)
129+
->willReturnOnConsecutiveCalls(
130+
'default_processed_value_path2',
131+
'website_one_processed_value_path1',
132+
'website_one_processed_value_path3'
133+
);
134+
135+
$data = [
136+
'default' => [
137+
'some' => [
138+
'config' => [
139+
'path1' => 'value1',
140+
'path2' => 'value2',
141+
'path3' => 'value3'
142+
]
143+
]
144+
],
145+
'websites' => [
146+
'website_one' => [
147+
'some' => [
148+
'config' => [
149+
'path1' => 'value1',
150+
'path2' => 'value2',
151+
'path3' => 'value3',
152+
]
153+
]
154+
]
155+
]
156+
];
157+
75158
$expectedResult = $data;
76-
$expectedResult['default']['some']['config']['path'] = 'processed_value';
159+
$expectedResult['default']['some']['config']['path2'] = 'default_processed_value_path2';
160+
$expectedResult['websites']['website_one']['some']['config']['path1'] = 'website_one_processed_value_path1';
161+
$expectedResult['websites']['website_one']['some']['config']['path3'] = 'website_one_processed_value_path3';
162+
77163
$this->assertEquals($expectedResult, $this->_model->process($data));
78164
}
79165
}

0 commit comments

Comments
 (0)