[TASK] Move LocalConfiguration* files to config folder 17/56517/41
authorBenni Mack <benni@typo3.org>
Sat, 9 Jun 2018 15:04:13 +0000 (17:04 +0200)
committerAndreas Wolf <andreas.wolf@typo3.org>
Sat, 25 Aug 2018 09:25:01 +0000 (11:25 +0200)
With the introduction of the environment API, composer-based
installations have the configuration folder outside of
"public-webroot"/typo3conf/, but in the project
paths folder config/.

All checks on PATH_typo3conf/
- LocalConfiguration.php
- AdditionalConfiguration.php
- AdditionalFactoryConfiguration.php

are now done against Environment::getConfigPath(), resulting in
different locations for projects having the environment variable
"TYPO3_PATH_APP" set to something else than the "PATH_site" constant,
the configuration is now found in "TYPO3_PATH_APP" . /config/.

A migration to move all config files into the new directory
is done when accessing the Install Tool automatically.

Resolves: #84623
Releases: master
Change-Id: I94020b1df4c9ffaec66310a4e1564927dbd8cb67
Reviewed-on: https://review.typo3.org/56517
Reviewed-by: Richard Haeser <richard@maxserv.com>
Tested-by: Richard Haeser <richard@maxserv.com>
Reviewed-by: Stephan GroƟberndt <stephan.grossberndt@typo3.org>
Tested-by: TYPO3com <no-reply@typo3.com>
Reviewed-by: Helmut Hummel <typo3@helhum.io>
Tested-by: Helmut Hummel <typo3@helhum.io>
Reviewed-by: Markus Klein <markus.klein@typo3.org>
Reviewed-by: Andreas Wolf <andreas.wolf@typo3.org>
Tested-by: Andreas Wolf <andreas.wolf@typo3.org>
13 files changed:
typo3/sysext/core/Classes/Configuration/ConfigurationManager.php
typo3/sysext/core/Classes/Core/SystemEnvironmentBuilder.php
typo3/sysext/core/Classes/Package/PackageManager.php
typo3/sysext/core/Configuration/FactoryConfiguration.php
typo3/sysext/core/Documentation/Changelog/master/Important-84623-ConfigurationFilesMovedFromTypo3confToConfigDirectory.rst [new file with mode: 0644]
typo3/sysext/core/Tests/Unit/Configuration/ConfigurationManagerTest.php
typo3/sysext/core/Tests/Unit/Utility/GeneralUtilityTest.php
typo3/sysext/install/Classes/Controller/InstallerController.php
typo3/sysext/install/Classes/Controller/LoginController.php
typo3/sysext/install/Classes/Http/Application.php
typo3/sysext/install/Classes/Service/SilentConfigurationUpgradeService.php
typo3/sysext/install/Resources/Private/Templates/Login/ShowLogin.html
typo3/sysext/install/Tests/Unit/Service/SilentConfigurationUpgradeServiceTest.php

index f444467..4003b59 100644 (file)
@@ -26,8 +26,8 @@ use TYPO3\CMS\Core\Utility\GeneralUtility;
  *
  * This class handles the access to the files
  * - EXT:core/Configuration/DefaultConfiguration.php (default TYPO3_CONF_VARS)
- * - typo3conf/LocalConfiguration.php (overrides of TYPO3_CONF_VARS)
- * - typo3conf/AdditionalConfiguration.php (optional additional local code blocks)
+ * - LocalConfiguration.php (overrides of TYPO3_CONF_VARS)
+ * - AdditionalConfiguration.php (optional additional local code blocks)
  *
  * IMPORTANT:
  *   This class is intended for internal core use ONLY.
@@ -48,14 +48,14 @@ class ConfigurationManager
     protected $defaultConfigurationDescriptionFile = 'typo3/sysext/core/Configuration/DefaultConfigurationDescription.yaml';
 
     /**
-     * @var string Path to local overload TYPO3_CONF_VARS file, relative to the public web folder
+     * @var string Path to local overload TYPO3_CONF_VARS file, relative to Environment::getConfigPath()
      */
-    protected $localConfigurationFile = 'typo3conf/LocalConfiguration.php';
+    protected $localConfigurationFile = 'LocalConfiguration.php';
 
     /**
-     * @var string Path to additional local file, relative to the public web folder
+     * @var string Path to additional local file, relative to Environment::getConfigPath()
      */
-    protected $additionalConfigurationFile = 'typo3conf/AdditionalConfiguration.php';
+    protected $additionalConfigurationFile = 'AdditionalConfiguration.php';
 
     /**
      * @var string Path to factory configuration file used during installation as LocalConfiguration boilerplate
@@ -65,7 +65,7 @@ class ConfigurationManager
     /**
      * @var string Path to possible additional factory configuration file delivered by packages
      */
-    protected $additionalFactoryConfigurationFile = 'typo3conf/AdditionalFactoryConfiguration.php';
+    protected $additionalFactoryConfigurationFile = 'AdditionalFactoryConfiguration.php';
 
     /**
      * Writing to these configuration paths is always allowed,
@@ -117,7 +117,7 @@ class ConfigurationManager
     }
 
     /**
-     * Return local configuration array typo3conf/LocalConfiguration.php
+     * Return local configuration array Environment::getConfigPath() / LocalConfiguration.php
      *
      * @return array Content array of local configuration file
      */
@@ -135,7 +135,7 @@ class ConfigurationManager
      */
     public function getLocalConfigurationFileLocation()
     {
-        return Environment::getPublicPath() . '/' . $this->localConfigurationFile;
+        return Environment::getConfigPath() . '/' . $this->localConfigurationFile;
     }
 
     /**
@@ -159,7 +159,7 @@ class ConfigurationManager
      */
     public function getAdditionalConfigurationFileLocation()
     {
-        return Environment::getPublicPath() . '/' . $this->additionalConfigurationFile;
+        return Environment::getConfigPath() . '/' . $this->additionalConfigurationFile;
     }
 
     /**
@@ -179,7 +179,7 @@ class ConfigurationManager
      */
     protected function getAdditionalFactoryConfigurationFileLocation()
     {
-        return Environment::getPublicPath() . '/' . $this->additionalFactoryConfigurationFile;
+        return Environment::getConfigPath() . '/' . $this->additionalFactoryConfigurationFile;
     }
 
     /**
@@ -321,7 +321,7 @@ class ConfigurationManager
     public function canWriteConfiguration()
     {
         $fileLocation = $this->getLocalConfigurationFileLocation();
-        return @is_writable(file_exists($fileLocation) ? $fileLocation : Environment::getPublicPath() . '/typo3conf/');
+        return @is_writable(file_exists($fileLocation) ? $fileLocation : Environment::getConfigPath());
     }
 
     /**
@@ -351,7 +351,7 @@ class ConfigurationManager
     }
 
     /**
-     * Write local configuration array to typo3conf/LocalConfiguration.php
+     * Write local configuration array to Environment::getConfigPath() . /LocalConfiguration.php
      *
      * @param array $configuration The local configuration to be written
      * @throws \RuntimeException
@@ -383,7 +383,7 @@ class ConfigurationManager
     }
 
     /**
-     * Write additional configuration array to typo3conf/AdditionalConfiguration.php
+     * Write additional configuration array to Environment::getConfigPath() . /AdditionalConfiguration.php
      *
      * @param array $additionalConfigurationLines The configuration lines to be written
      * @throws \RuntimeException
@@ -401,7 +401,7 @@ class ConfigurationManager
 
     /**
      * Uses FactoryConfiguration file and a possible AdditionalFactoryConfiguration
-     * file in typo3conf to create a basic LocalConfiguration.php. This is used
+     * file in Environment::getConfigPath() to create a basic LocalConfiguration.php. This is used
      * by the install tool in an early step.
      *
      * @throws \RuntimeException
index 9638fea..767c608 100644 (file)
@@ -28,7 +28,7 @@ use TYPO3\CMS\Core\Utility\StringUtility;
  *
  * This class does not use any TYPO3 instance specific configuration, it only
  * sets up things based on the server environment and core code. Even with a
- * missing typo3conf/localconf.php this script will be successful.
+ * missing LocalConfiguration.php this script will be successful.
  *
  * The script aborts execution with an error message if
  * some part fails or conditions are not met.
index 4fed66d..a6a3043 100644 (file)
@@ -109,7 +109,7 @@ class PackageManager implements SingletonInterface
     public function __construct(DependencyOrderingService $dependencyOrderingService = null)
     {
         $this->packagesBasePath = Environment::getPublicPath() . '/';
-        $this->packageStatesPathAndFilename = Environment::getPublicPath() . '/typo3conf/PackageStates.php';
+        $this->packageStatesPathAndFilename = Environment::getLegacyConfigPath() . '/PackageStates.php';
         if ($dependencyOrderingService === null) {
             trigger_error(self::class . ' without constructor based dependency injection has been deprecated in v9.2 and will not work in TYPO3 v10.', E_USER_DEPRECATED);
             $dependencyOrderingService = GeneralUtility::makeInstance(DependencyOrderingService::class);
index 23d6ad5..1d9e568 100644 (file)
@@ -1,8 +1,8 @@
 <?php
 /**
- * This is a boilerplate of typo3conf/LocalConfiguration.php. It is
+ * This is a boilerplate of LocalConfiguration.php. It is
  * used as base file during installation and can be overloaded with
- * a package specific file typo3conf/AdditionalFactoryConfiguration.php
+ * a package specific file AdditionalFactoryConfiguration.php
  * from eg. the government or introduction package.
  */
 return [
diff --git a/typo3/sysext/core/Documentation/Changelog/master/Important-84623-ConfigurationFilesMovedFromTypo3confToConfigDirectory.rst b/typo3/sysext/core/Documentation/Changelog/master/Important-84623-ConfigurationFilesMovedFromTypo3confToConfigDirectory.rst
new file mode 100644 (file)
index 0000000..85887c6
--- /dev/null
@@ -0,0 +1,38 @@
+.. include:: ../../Includes.txt
+
+====================================================================================
+Important: #84623 - Configuration files moved from "typo3conf" to "config" directory
+====================================================================================
+
+See :issue:`84623`
+
+Description
+===========
+
+The TYPO3 configuration files for instances running in Composer Mode or having the environment
+variable `TYPO3_PATH_APP` set to a different location than :php:`PATH_site`, have been moved from
+the :file:`<web-dir>/typo3conf` to the :file:`config` directory.
+
+The following files are affected:
+
+- :file:`LocalConfiguration.php`
+- :file:`AdditionalConfiguration.php`
+- :file:`AdditionalFactoryConfiguration.php`
+
+The first access to the TYPO3 frontend or backend will redirect to the Install Tool which
+automatically creates the :file:`config` directory and moves all of the affected files currently
+present in :file:`<web-dir>/typo3conf` to :file:`config`. Afterwards backend and frontend are
+accessible as usual.
+
+Using the environment variable `TYPO3_PATH_APP` allows for storing relevant code like configuration
+outside of the document root / Composer `<web-dir>`. This effectively hardens a TYPO3 instance,
+as less files are accessible in public. All new installations in Composer Mode use this setup by
+default. Installations in Classic Mode (without Composer setup) will continue to use the previous
+setup since it cannot be ensured that they have access outside of the document root.
+
+If you have a setup with a $GLOBALS['TYPO3_CONF_VARS']['SYS']['trustedHostsPattern'] set, please
+go to the install tool first. The migration is done automatically and you can just go to the backend
+afterwards. If you have not set your trustedHostsPattern, you will be redirected automatically and
+you don't have to do anything.
+
+.. index:: LocalConfiguration
index 160aa9c..7b7b6f4 100644 (file)
@@ -378,7 +378,7 @@ class ConfigurationManagerTest extends UnitTestCase
             $this->markTestSkipped('Test skipped if run on linux as root');
         }
         /** @var $subject ConfigurationManager|\PHPUnit_Framework_MockObject_MockObject|\TYPO3\TestingFramework\Core\AccessibleObjectInterface */
-        $subject = $this->getAccessibleMock(ConfigurationManager::class, ['dummy']);
+        $subject = $this->getAccessibleMock(ConfigurationManager::class, ['getLocalConfigurationFileLocation']);
 
         $file = 'typo3temp/var/tests/' . $this->getUniqueId('test_');
         $absoluteFile = Environment::getPublicPath() . '/' . $file;
@@ -387,7 +387,9 @@ class ConfigurationManagerTest extends UnitTestCase
         chmod($absoluteFile, 0444);
         clearstatcache();
 
-        $subject->_set('localConfigurationFile', $file);
+        $subject
+            ->method('getLocalConfigurationFileLocation')
+            ->will($this->returnValue($absoluteFile));
 
         $result = $subject->canWriteConfiguration();
 
@@ -402,7 +404,7 @@ class ConfigurationManagerTest extends UnitTestCase
     public function canWriteConfigurationReturnsTrueIfDirectoryAndFilesAreWritable(): void
     {
         /** @var $subject ConfigurationManager|\PHPUnit_Framework_MockObject_MockObject|\TYPO3\TestingFramework\Core\AccessibleObjectInterface */
-        $subject = $this->getAccessibleMock(ConfigurationManager::class, ['dummy']);
+        $subject = $this->getAccessibleMock(ConfigurationManager::class, ['getLocalConfigurationFileLocation']);
 
         $directory = 'typo3temp/var/tests/' . $this->getUniqueId('test_');
         $absoluteDirectory = Environment::getPublicPath() . '/' . $directory;
@@ -412,10 +414,12 @@ class ConfigurationManagerTest extends UnitTestCase
         $absoluteFile1 = Environment::getPublicPath() . '/' . $file;
         touch($absoluteFile1);
         $this->testFilesToDelete[] = $absoluteFile1;
-        $subject->_set('localConfigurationFile', $absoluteFile1);
-
         clearstatcache();
 
+        $subject
+            ->expects($this->any())
+            ->method('getLocalConfigurationFileLocation')
+            ->will($this->returnValue($absoluteFile1));
         $result = $subject->canWriteConfiguration();
 
         $this->assertTrue($result);
@@ -471,13 +475,16 @@ class ConfigurationManagerTest extends UnitTestCase
         $this->expectException(\RuntimeException::class);
 
         /** @var $subject ConfigurationManager|\PHPUnit_Framework_MockObject_MockObject|\TYPO3\TestingFramework\Core\AccessibleObjectInterface */
-        $subject = $this->getAccessibleMock(ConfigurationManager::class, ['dummy']);
+        $subject = $this->getAccessibleMock(ConfigurationManager::class, ['getLocalConfigurationFileLocation']);
 
         $file = 'typo3temp/var/tests/' . $this->getUniqueId('test_');
         $absoluteFile = Environment::getPublicPath() . '/' . $file;
         touch($absoluteFile);
         $this->testFilesToDelete[] = $absoluteFile;
-        $subject->_set('localConfigurationFile', $file);
+        $subject
+            ->expects($this->any())
+            ->method('getLocalConfigurationFileLocation')
+            ->will($this->returnValue($absoluteFile));
 
         $subject->createLocalConfigurationFromFactoryConfiguration();
     }
@@ -488,8 +495,11 @@ class ConfigurationManagerTest extends UnitTestCase
     public function createLocalConfigurationFromFactoryConfigurationWritesContentFromFactoryFile(): void
     {
         /** @var $subject ConfigurationManager|\PHPUnit_Framework_MockObject_MockObject|\TYPO3\TestingFramework\Core\AccessibleObjectInterface */
-        $subject = $this->getAccessibleMock(ConfigurationManager::class, ['writeLocalConfiguration']);
-        $subject->_set('localConfigurationFile', 'typo3temp/var/tests/' . $this->getUniqueId('dummy_'));
+        $subject = $this->getAccessibleMock(ConfigurationManager::class, ['writeLocalConfiguration', 'getLocalConfigurationFileLocation']);
+        $subject
+            ->expects($this->any())
+            ->method('getLocalConfigurationFileLocation')
+            ->will($this->returnValue(PATH_site . 'typo3temp/var/tests/' . $this->getUniqueId('dummy_')));
 
         $factoryConfigurationFile = 'typo3temp/var/tests/' . $this->getUniqueId('test_') . '.php';
         $factoryConfigurationAbsoluteFile = Environment::getPublicPath() . '/' . $factoryConfigurationFile;
@@ -520,8 +530,11 @@ class ConfigurationManagerTest extends UnitTestCase
     public function createLocalConfigurationFromFactoryConfigurationMergesConfigurationWithAdditionalFactoryFile(): void
     {
         /** @var $subject ConfigurationManager|\PHPUnit_Framework_MockObject_MockObject|\TYPO3\TestingFramework\Core\AccessibleObjectInterface */
-        $subject = $this->getAccessibleMock(ConfigurationManager::class, ['writeLocalConfiguration']);
-        $subject->_set('localConfigurationFile', 'typo3temp/var/tests/' . $this->getUniqueId('dummy_'));
+        $subject = $this->getAccessibleMock(ConfigurationManager::class, ['writeLocalConfiguration', 'getAdditionalFactoryConfigurationFileLocation', 'getLocalConfigurationFileLocation']);
+        $subject
+            ->expects($this->any())
+            ->method('getLocalConfigurationFileLocation')
+            ->will($this->returnValue(PATH_site . 'typo3temp/var/tests/' . $this->getUniqueId('dummy_')));
 
         $factoryConfigurationFile = 'typo3temp/var/tests/' . $this->getUniqueId('test_') . '.php';
         $factoryConfigurationAbsoluteFile = Environment::getPublicPath() . '/' . $factoryConfigurationFile;
@@ -549,6 +562,10 @@ class ConfigurationManagerTest extends UnitTestCase
         );
         $this->testFilesToDelete[] = $additionalFactoryConfigurationAbsoluteFile;
         $subject->_set('additionalFactoryConfigurationFile', $additionalFactoryConfigurationFile);
+        $subject
+            ->expects($this->any())
+            ->method('getAdditionalFactoryConfigurationFileLocation')
+            ->will($this->returnValue($additionalFactoryConfigurationAbsoluteFile));
 
         $subject
             ->expects($this->once())
index 4ecaec0..6a57dba 100644 (file)
@@ -2266,7 +2266,7 @@ class GeneralUtilityTest extends UnitTestCase
      */
     public function getDirsReturnsArrayOfDirectoriesFromGivenDirectory()
     {
-        $directories = GeneralUtility::get_dirs(Environment::getLegacyConfigPath() . '/');
+        $directories = GeneralUtility::get_dirs(Environment::getBackendPath() . '/');
         $this->assertInternalType(\PHPUnit\Framework\Constraint\IsType::TYPE_ARRAY, $directories);
     }
 
index 9707763..e645623 100644 (file)
@@ -113,7 +113,7 @@ class InstallerController
     public function checkEnvironmentAndFoldersAction(): ResponseInterface
     {
         return new JsonResponse([
-            'success' => @is_file(Environment::getLegacyConfigPath() . '/LocalConfiguration.php'),
+            'success' => @is_file(Environment::getConfigPath() . '/LocalConfiguration.php'),
         ]);
     }
 
@@ -158,7 +158,7 @@ class InstallerController
         $structureFixMessageQueue = $structureFacade->fix();
         $errorsFromStructure = $structureFixMessageQueue->getAllMessages(FlashMessage::ERROR);
 
-        if (@is_dir(Environment::getLegacyConfigPath())) {
+        if (@is_dir(Environment::getConfigPath())) {
             $configurationManager = GeneralUtility::makeInstance(ConfigurationManager::class);
             $configurationManager->createLocalConfigurationFromFactoryConfiguration();
 
index 65ad5fd..4d74486 100644 (file)
@@ -17,6 +17,7 @@ namespace TYPO3\CMS\Install\Controller;
 
 use Psr\Http\Message\ResponseInterface;
 use Psr\Http\Message\ServerRequestInterface;
+use TYPO3\CMS\Core\Core\Environment;
 use TYPO3\CMS\Core\FormProtection\FormProtectionFactory;
 use TYPO3\CMS\Core\FormProtection\InstallToolFormProtection;
 use TYPO3\CMS\Core\Http\JsonResponse;
@@ -54,6 +55,7 @@ class LoginController extends AbstractController
         $view->assignMultiple([
             'siteName' => $GLOBALS['TYPO3_CONF_VARS']['SYS']['sitename'],
             'loginToken' => $formProtection->generateToken('installTool', 'login'),
+            'configPath' => str_replace(Environment::getProjectPath(), '<project-path>', Environment::getConfigPath()),
         ]);
         return new JsonResponse([
             'success' => true,
index 5ba6e3e..bbf6a4e 100644 (file)
@@ -24,6 +24,7 @@ use TYPO3\CMS\Core\Context\WorkspaceAspect;
 use TYPO3\CMS\Core\Http\AbstractApplication;
 use TYPO3\CMS\Core\Http\RequestHandlerInterface;
 use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Install\Service\SilentConfigurationUpgradeService;
 
 /**
  * Entry point for the TYPO3 Install Tool
@@ -58,7 +59,12 @@ class Application extends AbstractApplication
      */
     protected function handle(ServerRequestInterface $request): ResponseInterface
     {
+        // Migrate LocalConfiguration.php to a new file location, if TYPO3_PATH_APP is used.
+        // The functionality will be removed in TYPO3 v11.
+        GeneralUtility::makeInstance(SilentConfigurationUpgradeService::class)->migrateConfigurationFiles();
+
         $this->initializeContext();
+
         foreach ($this->availableRequestHandlers as $handler) {
             if ($handler->canHandleRequest($request)) {
                 return $handler->handleRequest($request);
index 501eb07..356b890 100644 (file)
@@ -15,6 +15,7 @@ namespace TYPO3\CMS\Install\Service;
  */
 
 use TYPO3\CMS\Core\Configuration\ConfigurationManager;
+use TYPO3\CMS\Core\Core\Environment;
 use TYPO3\CMS\Core\Crypto\PasswordHashing\Argon2iPasswordHash;
 use TYPO3\CMS\Core\Crypto\PasswordHashing\BcryptPasswordHash;
 use TYPO3\CMS\Core\Crypto\PasswordHashing\PasswordHashInterface;
@@ -143,6 +144,45 @@ class SilentConfigurationUpgradeService
     }
 
     /**
+     * Migration wizard to move configuration files from "<web-dir>/typo3conf/" to "config/"
+     * This applies to the files where all installation-wide configuration resides,
+     * and is called each time when the installer is hit.
+     *
+     * This only applies if the environment variable "TYPO3_PATH_APP" is used and the new configuration
+     * files are not in place yet.
+     *
+     * This functionality will be removed in TYPO3 v11, as all installations should be migrated by then.
+     * @internal
+     */
+    public function migrateConfigurationFiles()
+    {
+        if (Environment::getConfigPath() !== rtrim(PATH_typo3conf, '/')) {
+            if (!file_exists(Environment::getConfigPath())) {
+                GeneralUtility::mkdir(Environment::getConfigPath());
+            }
+
+            $filesToCheck = [
+                'LocalConfiguration.php',
+                'AdditionalConfiguration.php',
+                'AdditionalFactoryConfiguration.php',
+            ];
+            $reloadConfiguration = false;
+            foreach ($filesToCheck as $filename) {
+                $oldFilepath = PATH_typo3conf . $filename;
+                $newFilepath = Environment::getConfigPath() . '/' . $filename;
+
+                if (file_exists($oldFilepath) && !file_exists($newFilepath)) {
+                    $reloadConfiguration = true;
+                    rename($oldFilepath, $newFilepath);
+                }
+            }
+            if ($reloadConfiguration) {
+                $this->configurationManager->exportConfiguration();
+            }
+        }
+    }
+
+    /**
      * Executed configuration upgrades. Single upgrade methods must throw a
      * ConfigurationChangedException if something was written to LocalConfiguration.
      *
index 9e422b1..57339a7 100644 (file)
@@ -37,7 +37,7 @@
                <div class="panel-heading"><h3 class="panel-title">Important</h3></div>
                <div class="panel-body">
                        If you don't know the current password, you can set a new one by setting the value of
-                       <code>$GLOBALS['TYPO3_CONF_VARS']['BE']['installToolPassword']</code> in <code>typo3conf/LocalConfiguration.php</code> to
+                       <code>$GLOBALS['TYPO3_CONF_VARS']['BE']['installToolPassword']</code> in <code>{configPath}/LocalConfiguration.php</code> to
                        the hash value of the password you desire, which will be shown if you enter the desired password
                        in this form and submit it.
                        <br /><br />
index 7fec82e..f4fd0f0 100644 (file)
@@ -18,6 +18,8 @@ namespace TYPO3\CMS\Install\Tests\Unit\Service;
 use Prophecy\Argument;
 use Prophecy\Prophecy\ObjectProphecy;
 use TYPO3\CMS\Core\Configuration\ConfigurationManager;
+use TYPO3\CMS\Core\Core\ApplicationContext;
+use TYPO3\CMS\Core\Core\Environment;
 use TYPO3\CMS\Core\Crypto\PasswordHashing\Argon2iPasswordHash;
 use TYPO3\CMS\Core\Crypto\PasswordHashing\BcryptPasswordHash;
 use TYPO3\CMS\Core\Package\PackageManager;
@@ -35,7 +37,7 @@ use TYPO3\TestingFramework\Core\Unit\UnitTestCase;
 class SilentConfigurationUpgradeServiceTest extends UnitTestCase
 {
     /**
-     * @var ConfigurationManager|\PHPUnit_Framework_MockObject_MockObject
+     * @var ConfigurationManager|\PHPUnit\Framework\MockObject\MockObject
      */
     protected $configurationManager;
 
@@ -45,11 +47,18 @@ class SilentConfigurationUpgradeServiceTest extends UnitTestCase
     protected $backupPackageManager;
 
     /**
+     * restore Environment after each test
+     * @var bool
+     */
+    protected $backupEnvironment = true;
+
+    /**
      * Set up
      */
     protected function setUp()
     {
         $this->backupPackageManager = ExtensionManagementUtilityAccessibleProxy::getPackageManager();
+        parent::setUp();
     }
 
     /**
@@ -72,6 +81,50 @@ class SilentConfigurationUpgradeServiceTest extends UnitTestCase
     }
 
     /**
+     * Moves existing files in PATH_site . typo3conf/ to a different location
+     * @test
+     */
+    public function configurationFilesAreMovedToConfigDirectoryIfEnvironmentVariableIsSet()
+    {
+        Environment::initialize(
+            new ApplicationContext('Development'),
+            true,
+            false,
+            rtrim(PATH_site, '/'),
+            rtrim(PATH_site, '/'),
+            PATH_site . 'var',
+            PATH_site . 'typo3temp/var/tests/' . uniqid('config', true),
+            PATH_thisScript,
+            'WINDOWS'
+        );
+
+        $filesToCreate = [
+            'LocalConfiguration.php',
+            'AdditionalConfiguration.php',
+            'AdditionalFactoryConfiguration.php',
+        ];
+
+        foreach ($filesToCreate as $fileToCreate) {
+            touch(PATH_typo3conf . $fileToCreate);
+        }
+
+        $this->createConfigurationManagerWithMockedMethods(['exportConfiguration']);
+        $this->configurationManager->expects($this->once())->method('exportConfiguration');
+
+        $subject = new SilentConfigurationUpgradeService($this->configurationManager);
+        $subject->migrateConfigurationFiles();
+
+        foreach ($filesToCreate as $file) {
+            $this->testFilesToDelete[] = Environment::getConfigPath() . '/' . $file;
+
+            // Check if the new file is placed
+            $this->assertFileExists(Environment::getConfigPath() . '/' . $file);
+            // Check if the old files do not exist anymore
+            $this->assertFileNotExists(PATH_typo3conf . $file);
+        }
+    }
+
+    /**
      * Dataprovider for configureBackendLoginSecurity
      *
      * @return array