From 5db874920e3e577434aa5669bcf3ca03dbf0cd37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Pablo=20Villaf=C3=A1=C3=B1ez?= Date: Wed, 9 Mar 2022 15:25:35 +0100 Subject: [PATCH 1/7] Improved RSA key handling for the SFTP storage --- apps/files_external/js/public_key.js | 18 ++- .../lib/Controller/AjaxController.php | 10 +- .../lib/Lib/Auth/PublicKey/RSA.php | 42 +++---- apps/files_external/lib/Lib/RSAStore.php | 109 ++++++++++++++++++ apps/files_external/lib/Lib/Storage/SFTP.php | 6 +- .../External/FrontendDefinitionTrait.php | 6 +- lib/private/Files/External/StorageConfig.php | 16 --- 7 files changed, 148 insertions(+), 59 deletions(-) create mode 100644 apps/files_external/lib/Lib/RSAStore.php diff --git a/apps/files_external/js/public_key.js b/apps/files_external/js/public_key.js index 5f9658381f0d..a80b9a06504a 100644 --- a/apps/files_external/js/public_key.js +++ b/apps/files_external/js/public_key.js @@ -3,11 +3,14 @@ $(document).ready(function() { OCA.External.Settings.mountConfig.whenSelectAuthMechanism(function($tr, authMechanism, scheme, onCompletion) { if (scheme === 'publickey') { var config = $tr.find('.configuration'); - if ($(config).find('[name="public_key_generate"]').length === 0) { + if (config.find('[name="public_key_generate"]').length === 0) { setupTableRow($tr, config); onCompletion.then(function() { // If there's no private key, build one - if (0 === $(config).find('[data-parameter="private_key"]').val().length) { + var $privateKeyElem = config.find('[data-parameter="private_key"]'); + if ($privateKeyElem.length !== 0 && $privateKeyElem.val().length === 0) { + // the private_key element might be removed in some scenarios such as + // global mount showing in the personal mounts generateKeys($tr); } }); @@ -33,7 +36,16 @@ $(document).ready(function() { function generateKeys(tr) { var config = $(tr).find('.configuration'); - $.post(OC.filePath('files_external', 'ajax', 'public_key.php'), {}, function(result) { + var $table = $(tr).parentsUntil('#files_external', '#externalStorage'); + var isAdmin = $table.data('admin'); + + var postData = {}; + if (!isAdmin) { + postData = { + 'userId': OC.currentUser + }; + } + $.post(OC.filePath('files_external', 'ajax', 'public_key.php'), postData, function(result) { if (result && result.status === 'success') { $(config).find('[data-parameter="public_key"]').val(result.data.public_key).keyup(); $(config).find('[data-parameter="private_key"]').val(result.data.private_key); diff --git a/apps/files_external/lib/Controller/AjaxController.php b/apps/files_external/lib/Controller/AjaxController.php index e41e8782189d..48a7d412b45e 100644 --- a/apps/files_external/lib/Controller/AjaxController.php +++ b/apps/files_external/lib/Controller/AjaxController.php @@ -39,8 +39,8 @@ public function __construct($appName, IRequest $request, RSA $rsaMechanism) { $this->rsaMechanism = $rsaMechanism; } - private function generateSshKeys() { - $key = $this->rsaMechanism->createKey(); + private function generateSshKeys($userId) { + $key = $this->rsaMechanism->createKey($userId); // Replace the placeholder label with a more meaningful one $key['publickey'] = \str_replace('phpseclib-generated-key', \gethostname(), $key['publickey']); @@ -49,11 +49,11 @@ private function generateSshKeys() { /** * Generates an SSH public/private key pair. - * + * @param string $userId * @NoAdminRequired */ - public function getSshKeys() { - $key = $this->generateSshKeys(); + public function getSshKeys($userId = '') { + $key = $this->generateSshKeys($userId); return new JSONResponse( ['data' => [ 'private_key' => $key['privatekey'], diff --git a/apps/files_external/lib/Lib/Auth/PublicKey/RSA.php b/apps/files_external/lib/Lib/Auth/PublicKey/RSA.php index aaf1dd5b5b96..e37f47359557 100644 --- a/apps/files_external/lib/Lib/Auth/PublicKey/RSA.php +++ b/apps/files_external/lib/Lib/Auth/PublicKey/RSA.php @@ -24,10 +24,8 @@ use OCP\Files\External\Auth\AuthMechanism; use OCP\Files\External\DefinitionParameter; -use OCP\Files\External\IStorageConfig; -use OCP\IConfig; use OCP\IL10N; -use OCP\IUser; +use OCA\Files_External\Lib\RSAStore; use phpseclib3\Crypt\RSA as RSACrypt; /** @@ -36,12 +34,7 @@ class RSA extends AuthMechanism { public const CREATE_KEY_BITS = 1024; - /** @var IConfig */ - private $config; - - public function __construct(IL10N $l, IConfig $config) { - $this->config = $config; - + public function __construct(IL10N $l) { $this ->setIdentifier('publickey::rsa') ->setScheme(self::SCHEME_PUBLICKEY) @@ -56,33 +49,26 @@ public function __construct(IL10N $l, IConfig $config) { ; } - public function manipulateStorageConfig(IStorageConfig &$storage, IUser $user = null) { - $privateKey = $storage->getBackendOption('private_key'); - $password = $this->config->getSystemValue('secret', ''); - - try { - $rsaKey = RSACrypt::load($privateKey, $password)->withHash('sha1'); - } catch (\phpseclib3\Exception\NoKeyLoadedException $e) { - throw new \RuntimeException('unable to load private key'); - } - - $storage->setBackendOption('private_key', \base64_encode($privateKey)); - $storage->setBackendOption('public_key_auth', $rsaKey); - } - /** - * Generate a keypair - * + * Generate a keypair. + * The public key will be returned without any modification. + * The private key will be stored using the RSAStore, and a token will + * be returned instead. The token can be used to retrieve the private key + * from the RSAStore later. + * @params string $userId the userId holding the keys, or empty string if the keys are global + * (for system-wide mount points, for example) * @return array ['privatekey' => $privateKey, 'publickey' => $publicKey] */ - public function createKey() { + public function createKey($userId = '') { /** @var RSACrypt\PrivateKey $rsaKey */ $rsaKey = RSACrypt::createKey(self::CREATE_KEY_BITS) ->withHash('sha1') ->withMGFHash('sha1'); - $password = $this->config->getSystemValue('secret', ''); + + $rsaStore = RSAStore::getGlobalInstance(); + $token = $rsaStore->storeData($rsaKey, $userId); return [ - 'privatekey' => $rsaKey->withPassword($password)->toString('PKCS1'), + 'privatekey' => $token, 'publickey' => $rsaKey->getPublicKey()->toString('OpenSSH') ]; } diff --git a/apps/files_external/lib/Lib/RSAStore.php b/apps/files_external/lib/Lib/RSAStore.php new file mode 100644 index 000000000000..3755dd4e59f0 --- /dev/null +++ b/apps/files_external/lib/Lib/RSAStore.php @@ -0,0 +1,109 @@ + + * + * @copyright Copyright (c) 2022, ownCloud GmbH + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see + * + */ + +namespace OCA\Files_External\Lib; + +use OCP\Security\ICredentialsManager; +use OCP\IConfig; +use phpseclib3\Crypt\RSA; +use phpseclib3\Crypt\RSA\PrivateKey; + +/** + * Store and retrieve phpseclib3 RSA private keys + */ +class RSAStore { + private static $rsaStore = null; + + /** @var ICredentialsManager */ + private $credentialsManager; + /** @var IConfig */ + private $config; + + /** + * Get the global instance of the RSAStore. If no one is set yet, a new + * one will be created using real server components. + * @return RSAStore + */ + public static function getGlobalInstance(): RSAStore { + if (self::$rsaStore === null) { + self::$rsaStore = new RSAStore( + \OC::$server->getCredentialsManager(), + \OC::$server->getConfig() + ); + } + return self::$rsaStore; + } + + /** + * Set a new RSAStore instance as a global instance overwriting whatever + * instance was there. + * This shouldn't be needed outside of unit tests + */ + public static function setGlobalInstance(RSAStore $rsaStore) { + self::$rsaStore = $rsaStore; + } + + /** + * @param ICredentialsManager $credentialsManager + * @param IConfig $config + */ + public function __construct(ICredentialsManager $credentialsManager, IConfig $config) { + $this->credentialsManager = $credentialsManager; + $this->config = $config; + } + + /** + * Store the $rsaKey inside the $userId's space. A token will be returned + * in order to retrieve the stored key + * @param PrivateKey $rsaKey the private key to be stored + * @param string $userId the user under which the token will be stored + * @return string an opaque token to be used to retrieve the stored key later + */ + public function storeData(PrivateKey $rsaKey, string $userId): string { + $password = $this->config->getSystemValue('secret', ''); + $privatekey = $rsaKey->withPassword($password)->toString('PKCS1'); + + $keyId = \uniqid('rsaid:', true); + + $this->credentialsManager->store($userId, $keyId, $privatekey); + + $keyData = [ + 'rsaId' => $keyId, + 'userId' => $userId, + ]; + return \base64_encode(\json_encode($keyData)); + } + + /** + * Retrieve a previously stored private key using the token that was returned + * when the key was stored + * @param string $token the token returned previously by the "storeData" + * method when the key was stored. + * @return PrivateKey the stored private key + */ + public function retrieveData(string $token): PrivateKey { + $keyData = \json_decode(\base64_decode($token), true); + $privateKey = $this->credentialsManager->retrieve($keyData['userId'], $keyData['rsaId']); + $password = $this->config->getSystemValue('secret', ''); + + return RSA::load($privateKey, $password)->withHash('sha1'); + } +} diff --git a/apps/files_external/lib/Lib/Storage/SFTP.php b/apps/files_external/lib/Lib/Storage/SFTP.php index a18c8b0cc044..c6f71fe2b156 100644 --- a/apps/files_external/lib/Lib/Storage/SFTP.php +++ b/apps/files_external/lib/Lib/Storage/SFTP.php @@ -35,6 +35,7 @@ use Icewind\Streams\IteratorDirectory; use Icewind\Streams\RetryWrapper; use phpseclib3\Net\SFTP\Stream; +use OCA\Files_External\Lib\RSAStore; /** * Uses phpseclib's Net\SFTP class and the Net\SFTP\Stream stream wrapper to @@ -92,8 +93,9 @@ public function __construct($params) { } $this->user = $params['user']; - if (isset($params['public_key_auth'])) { - $this->auth = $params['public_key_auth']; + if (isset($params['private_key'])) { + $rsaStore = RSAStore::getGlobalInstance(); + $this->auth = $rsaStore->retrieveData($params['private_key']); } elseif (isset($params['password'])) { $this->auth = $params['password']; } else { diff --git a/lib/private/Files/External/FrontendDefinitionTrait.php b/lib/private/Files/External/FrontendDefinitionTrait.php index f972d2a89b84..0b99ab86354b 100644 --- a/lib/private/Files/External/FrontendDefinitionTrait.php +++ b/lib/private/Files/External/FrontendDefinitionTrait.php @@ -141,11 +141,7 @@ public function validateStorageDefinition(IStorageConfig $storage) { if (!$parameter->validateValue($value)) { return false; } - if (($name === 'public_key') || ($name === 'private_key')) { - $storage->setBackendOption($name, \base64_encode($value)); - } else { - $storage->setBackendOption($name, $value); - } + $storage->setBackendOption($name, $value); } } return true; diff --git a/lib/private/Files/External/StorageConfig.php b/lib/private/Files/External/StorageConfig.php index b5452c569ca7..936f5628ef0c 100644 --- a/lib/private/Files/External/StorageConfig.php +++ b/lib/private/Files/External/StorageConfig.php @@ -221,15 +221,6 @@ public function setBackendOptions($backendOptions) { } $backendOptions[$key] = $value; } - if (\is_string($backendOptions[$key])) { - if (($key === 'public_key') || ($key === 'private_key')) { - if (\base64_decode($backendOptions[$key], true) === false) { - $backendOptions[$key] = \base64_encode($backendOptions[$key]); - } - } - - $backendOptions[$key] = \str_replace(["\n", "\r"], "", $backendOptions[$key]); - } } } @@ -242,13 +233,6 @@ public function setBackendOptions($backendOptions) { */ public function getBackendOption($key) { if (isset($this->backendOptions[$key])) { - if (($key === 'private_key') || ($key === 'public_key')) { - $decodedString = \base64_decode($this->backendOptions[$key], true); - if ($decodedString !== false) { - return $decodedString; - } - } - return $this->backendOptions[$key]; } return null; From f0b9cf0cb411932031771c37818159e0916461bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Pablo=20Villaf=C3=A1=C3=B1ez?= Date: Tue, 29 Mar 2022 17:53:52 +0200 Subject: [PATCH 2/7] Include migration for the SFTP keys --- .../Migrations/Version20220329110116.php | 105 ++++++++++++++++++ apps/files_external/appinfo/info.xml | 2 +- 2 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 apps/files_external/appinfo/Migrations/Version20220329110116.php diff --git a/apps/files_external/appinfo/Migrations/Version20220329110116.php b/apps/files_external/appinfo/Migrations/Version20220329110116.php new file mode 100644 index 000000000000..935a280427b8 --- /dev/null +++ b/apps/files_external/appinfo/Migrations/Version20220329110116.php @@ -0,0 +1,105 @@ +storageService = $storageService; + $this->logger = $logger; + $this->config = $config; + } + /** + * @param IOutput $out + */ + public function run(IOutput $out) { + if (!$this->config->getSystemValue('installed', false)) { + // Skip the migration for new installations -> nothing to migrate + return; + } + + $this->loadFSApps(); + \OC_Util::setupFS(); // this should load additional backends and auth mechanisms + $storageConfigs = $this->storageService->getStorageForAllUsers(); + $pass = $this->config->getSystemValue('secret', ''); + + $rsaStore = RSAStore::getGlobalInstance(); + foreach ($storageConfigs as $storageConfig) { + if ($storageConfig->getBackend() instanceof SFTP && $storageConfig->getAuthMechanism() instanceof RSA) { + $encPubKey = $storageConfig->getBackendOption('public_key'); + $encPrivKey = $storageConfig->getBackendOption('private_key'); + + $pubKey = \base64_decode($encPubKey, true); + $privKey = \base64_decode($encPrivKey, true); + + $configId = $storageConfig->getId(); + if ($pubKey === false || $privKey === false) { + $out->warning("Storage configuration with id = {$configId}: Cannot decode either public or private key, skipping"); + continue; + } + + try { + $rsaKey = RSACrypt::load($privKey, $pass)->withHash('sha1'); + } catch (\phpseclib3\Exception\NoKeyLoadedException $e) { + $out->warning("Storage configuration with id = {$configId}: Cannot load private key, skipping"); + continue; + } + + $targetUserId = ''; + if ($storageConfig->getType() === IStorageConfig::MOUNT_TYPE_PERSONAl) { + $applicableUsers = $storageConfig->getApplicableUsers(); + $targetUserId = $applicableUsers[0]; // it must have one user. + } + + $token = $rsaStore->storeData($rsaKey, $targetUserId); + $storageConfig->setBackendOption('public_key', $pubKey); + $storageConfig->setBackendOption('private_key', $token); + + $this->storageService->updateStorage($storageConfig); + $out->info("Storage configuration with id = {$configId}: keys migrated successfully"); + } + } + } + + /** + * Load the FS apps. This is required because the FS apps might not be loaded during the + * migration. + */ + private function loadFSApps() { + $enabledApps = \OC_App::getEnabledApps(); + foreach ($enabledApps as $enabledApp) { + if ($enabledApp !== 'files_external' && \OC_App::isType($enabledApp, ['filesystem'])) { + try { + \OC_App::loadApp($enabledApp); + } catch (NeedsUpdateException $ex) { + if (\OC_App::updateApp($enabledApp)) { + // update successful. + // We can load the app without checking if the should upgrade or not. + \OC_App::loadApp($enabledApp, false); + } else { + $this->logger->error("Error during files_external migration. $enabledApp couldn't be loaded nor updated.", ['app' => 'files_external']); + $this->logger->logException($ex, ['app' => 'files_external']); + $this->logger->error("Mount points using $enabledApp might not be migrated properly. You might need to re-enter the passwords for those mount points", ['app' => 'files_external']); + } + } + } + } + } +} diff --git a/apps/files_external/appinfo/info.xml b/apps/files_external/appinfo/info.xml index 7c665584c636..4939bf2d7a53 100644 --- a/apps/files_external/appinfo/info.xml +++ b/apps/files_external/appinfo/info.xml @@ -13,7 +13,7 @@ admin-external-storage false - 0.8.0 + 0.9.0 From 87754e6a281250b3c7c3095d289902a41b955f4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Pablo=20Villaf=C3=A1=C3=B1ez?= Date: Thu, 31 Mar 2022 14:40:59 +0200 Subject: [PATCH 3/7] Add unit tests --- apps/files_external/lib/Lib/RSAStore.php | 2 +- apps/files_external/tests/RSAStoreTest.php | 86 ++++++++++++++++++++++ 2 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 apps/files_external/tests/RSAStoreTest.php diff --git a/apps/files_external/lib/Lib/RSAStore.php b/apps/files_external/lib/Lib/RSAStore.php index 3755dd4e59f0..1401378e47fd 100644 --- a/apps/files_external/lib/Lib/RSAStore.php +++ b/apps/files_external/lib/Lib/RSAStore.php @@ -57,7 +57,7 @@ public static function getGlobalInstance(): RSAStore { * instance was there. * This shouldn't be needed outside of unit tests */ - public static function setGlobalInstance(RSAStore $rsaStore) { + public static function setGlobalInstance(?RSAStore $rsaStore) { self::$rsaStore = $rsaStore; } diff --git a/apps/files_external/tests/RSAStoreTest.php b/apps/files_external/tests/RSAStoreTest.php new file mode 100644 index 000000000000..b63c4fc0fae1 --- /dev/null +++ b/apps/files_external/tests/RSAStoreTest.php @@ -0,0 +1,86 @@ + + * + * @copyright Copyright (c) 2022, ownCloud GmbH + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see + * + */ + +namespace OCA\Files_External\Tests; + +use OCP\Security\ICredentialsManager; +use OCP\IConfig; +use OCA\Files_External\Lib\RSAStore; +use phpseclib3\Crypt\RSA; + +class RSAStoreTest extends \Test\TestCase { + /** @var ICredentialsManager */ + private $credentialsManager; + /** @var IConfig */ + private $config; + /** @var RSAStore */ + private $rsaStore; + + protected function setUp(): void { + $this->credentialsManager = $this->createMock(ICredentialsManager::class); + $this->config = $this->createMock(IConfig::class); + $this->rsaStore = new RSAStore($this->credentialsManager, $this->config); + } + + protected function tearDown(): void { + RSAStore::setGlobalInstance(null); // reset global instance + } + + public function testGlobalInstanceNotMocked() { + $this->assertNotSame($this->rsaStore, RSAStore::getGlobalInstance()); + } + + public function testGlobalInstance() { + RSAStore::setGlobalInstance($this->rsaStore); + $this->assertSame($this->rsaStore, RSAStore::getGlobalInstance()); + } + + public function testStoreAndRetrieve() { + $credentialsHolder = []; + + $userId = ''; + $this->config->method('getSystemValue') + ->will($this->returnValueMap([ + 'secret', '', 'itsASecret', + ])); + + $this->credentialsManager->expects($this->once()) + ->method('store') + ->with($userId, $this->anything(), $this->anything()) + ->will($this->returnCallback(function ($uid, $key, $value) use (&$credentialsHolder) { + if (!isset($credentialsHolder[$uid])) { + $credentialsHolder[$uid] = []; + } + $credentialsHolder[$uid][$key] = $value; + })); + + $this->credentialsManager->expects($this->once()) + ->method('retrieve') + ->with($userId, $this->anything()) + ->will($this->returnCallback(function ($uid, $key) use (&$credentialsHolder) { + return $credentialsHolder[$uid][$key]; + })); + $privKey = RSA::createKey(); + + $token = $this->rsaStore->storeData($privKey, $userId); + $this->assertEquals($privKey->toString('PKCS1'), $this->rsaStore->retrieveData($token)->toString('PKCS1')); + } +} From 42712c01371c90b50c0b6591c7107e0762e3e767 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Pablo=20Villaf=C3=A1=C3=B1ez?= Date: Thu, 31 Mar 2022 15:28:46 +0200 Subject: [PATCH 4/7] Fix missing import --- apps/files_external/appinfo/Migrations/Version20220329110116.php | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/files_external/appinfo/Migrations/Version20220329110116.php b/apps/files_external/appinfo/Migrations/Version20220329110116.php index 935a280427b8..03c3eae1f7c2 100644 --- a/apps/files_external/appinfo/Migrations/Version20220329110116.php +++ b/apps/files_external/appinfo/Migrations/Version20220329110116.php @@ -1,6 +1,7 @@ Date: Thu, 7 Apr 2022 14:46:46 +0200 Subject: [PATCH 5/7] Fix CI, keys won't be modified in any way --- tests/lib/Files/External/StorageConfigTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/lib/Files/External/StorageConfigTest.php b/tests/lib/Files/External/StorageConfigTest.php index fa0521122cda..226fee4884e0 100644 --- a/tests/lib/Files/External/StorageConfigTest.php +++ b/tests/lib/Files/External/StorageConfigTest.php @@ -55,7 +55,7 @@ public function testJsonSerialization() { $storageConfig->setMountPoint('test'); $storageConfig->setBackend($backend); $storageConfig->setAuthMechanism($authMech); - $storageConfig->setBackendOptions(['user' => 'test', 'password' => 'password123', 'secure' => true, 'key' => "12345\r\n"]); + $storageConfig->setBackendOptions(['user' => 'test', 'password' => 'password123', 'secure' => true, 'key' => "12345"]); $storageConfig->setPriority(128); $storageConfig->setApplicableUsers(['user1', 'user2']); $storageConfig->setApplicableGroups(['group1', 'group2']); From baf7b9852ae830f3f312c695c69ff1a3eb9710f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Pablo=20Villaf=C3=A1=C3=B1ez?= Date: Tue, 12 Apr 2022 15:25:03 +0200 Subject: [PATCH 6/7] Add changelog entry --- changelog/unreleased/39935 | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 changelog/unreleased/39935 diff --git a/changelog/unreleased/39935 b/changelog/unreleased/39935 new file mode 100644 index 000000000000..19f2d6f64ece --- /dev/null +++ b/changelog/unreleased/39935 @@ -0,0 +1,17 @@ +Change: Private keys for SFTP storage will be stored in credentials table + +Previously, both private and public keys were part of the configuration of +the SFTP mount point. Although encrypted, there were some scenarios where +the private key could be visible. + +The following changes have been implemented: +* The private key will never leave the ownCloud server. +* The private key will be stored encrypted inside the oc_credentials table. +* A random token will be created to refer to the private key. This token +will be part of the SFTP mount point configuration. +* The public key will be treated as a normal configuration parameter. This +means that it won't be neither encrypted nor encoded in any way. + +The overall behavior remains the same. ownCloud will generate a key pair, whose public key will need to be placed in the SFTP server. + +https://github.com/owncloud/core/pull/39935 From 80bff00e93a216fad337783d8edbe7eb4b719fca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Pablo=20Villaf=C3=A1=C3=B1ez?= Date: Mon, 25 Apr 2022 09:38:56 +0200 Subject: [PATCH 7/7] Add comments and missing docs --- apps/files_external/lib/Lib/RSAStore.php | 3 +++ apps/files_external/lib/Lib/Storage/SFTP.php | 2 ++ 2 files changed, 5 insertions(+) diff --git a/apps/files_external/lib/Lib/RSAStore.php b/apps/files_external/lib/Lib/RSAStore.php index 1401378e47fd..56e02af151e9 100644 --- a/apps/files_external/lib/Lib/RSAStore.php +++ b/apps/files_external/lib/Lib/RSAStore.php @@ -56,6 +56,9 @@ public static function getGlobalInstance(): RSAStore { * Set a new RSAStore instance as a global instance overwriting whatever * instance was there. * This shouldn't be needed outside of unit tests + * @param RSAStore|null The RSAStore to be set as global instance, or null + * to destroy the global instance (destroying the global instance will allow + * getting the default one again) */ public static function setGlobalInstance(?RSAStore $rsaStore) { self::$rsaStore = $rsaStore; diff --git a/apps/files_external/lib/Lib/Storage/SFTP.php b/apps/files_external/lib/Lib/Storage/SFTP.php index c6f71fe2b156..03cde982d7e1 100644 --- a/apps/files_external/lib/Lib/Storage/SFTP.php +++ b/apps/files_external/lib/Lib/Storage/SFTP.php @@ -94,6 +94,8 @@ public function __construct($params) { $this->user = $params['user']; if (isset($params['private_key'])) { + // The $params['private_key'] contains the token to get the private key, not the key. + // The actual private key is fetched from the RSAStore using that token. $rsaStore = RSAStore::getGlobalInstance(); $this->auth = $rsaStore->retrieveData($params['private_key']); } elseif (isset($params['password'])) {