Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Improve CertificateManager to not be user context dependent
* removes the ability for users to import their own certificates (for external storage)
* reliably returns the same certificate bundles system wide (and not depending on the user context and available sessions)

The user specific certificates were broken in some cases anyways, as they are only loaded if the specific user is logged in and thus causing unexpected behavior for background jobs and other non-user triggered code paths.

Signed-off-by: Morris Jobke <hey@morrisjobke.de>
  • Loading branch information
MorrisJobke committed Nov 2, 2020
commit dc479aae2d055dafddb250a382eb801a68d42afb
4 changes: 1 addition & 3 deletions apps/dav/lib/CardDAV/SyncService.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@

use OC\Accounts\AccountManager;
use OCP\AppFramework\Http;
use OCP\ICertificateManager;
use OCP\ILogger;
use OCP\IUser;
use OCP\IUserManager;
Expand Down Expand Up @@ -155,8 +154,7 @@ protected function getCertPath() {
return $this->certPath;
}

/** @var ICertificateManager $certManager */
$certManager = \OC::$server->getCertificateManager(null);
$certManager = \OC::$server->getCertificateManager();
$certPath = $certManager->getAbsoluteBundlePath();
if (file_exists($certPath)) {
$this->certPath = $certPath;
Expand Down
2 changes: 1 addition & 1 deletion apps/files_sharing/lib/External/Manager.php
Original file line number Diff line number Diff line change
Expand Up @@ -441,7 +441,7 @@ public function getMount($data) {
$data['manager'] = $this;
$mountPoint = '/' . $this->uid . '/files' . $data['mountpoint'];
$data['mountpoint'] = $mountPoint;
$data['certificateManager'] = \OC::$server->getCertificateManager($this->uid);
$data['certificateManager'] = \OC::$server->getCertificateManager();
return new Mount(self::STORAGE, $mountPoint, $data, $this, $this->storageLoader);
}

Expand Down
2 changes: 1 addition & 1 deletion apps/files_sharing/lib/External/MountProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public function getMount(IUser $user, $data, IStorageFactory $storageFactory) {
$mountPoint = '/' . $user->getUID() . '/files/' . ltrim($data['mountpoint'], '/');
$data['mountpoint'] = $mountPoint;
$data['cloudId'] = $this->cloudIdManager->getCloudId($data['owner'], $data['remote']);
$data['certificateManager'] = \OC::$server->getCertificateManager($user->getUID());
$data['certificateManager'] = \OC::$server->getCertificateManager();
$data['HttpClientService'] = \OC::$server->getHTTPClientService();
return new Mount(self::STORAGE, $mountPoint, $data, $manager, $storageFactory);
}
Expand Down
6 changes: 3 additions & 3 deletions core/register_command.php
Original file line number Diff line number Diff line change
Expand Up @@ -183,9 +183,9 @@
$application->add(new OC\Core\Command\Group\AddUser(\OC::$server->getUserManager(), \OC::$server->getGroupManager()));
$application->add(new OC\Core\Command\Group\RemoveUser(\OC::$server->getUserManager(), \OC::$server->getGroupManager()));

$application->add(new OC\Core\Command\Security\ListCertificates(\OC::$server->getCertificateManager(null), \OC::$server->getL10N('core')));
$application->add(new OC\Core\Command\Security\ImportCertificate(\OC::$server->getCertificateManager(null)));
$application->add(new OC\Core\Command\Security\RemoveCertificate(\OC::$server->getCertificateManager(null)));
$application->add(new OC\Core\Command\Security\ListCertificates(\OC::$server->getCertificateManager(), \OC::$server->getL10N('core')));
$application->add(new OC\Core\Command\Security\ImportCertificate(\OC::$server->getCertificateManager()));
$application->add(new OC\Core\Command\Security\RemoveCertificate(\OC::$server->getCertificateManager()));
$application->add(new OC\Core\Command\Security\ResetBruteforceAttempts(\OC::$server->getBruteForceThrottler()));
} else {
$application->add(\OC::$server->get(\OC\Core\Command\Maintenance\Install::class));
Expand Down
3 changes: 0 additions & 3 deletions lib/private/Files/Storage/DAV.php
Original file line number Diff line number Diff line change
Expand Up @@ -122,9 +122,6 @@ public function __construct($params) {
if ($this->secure === true) {
// inject mock for testing
$this->certManager = \OC::$server->getCertificateManager();
if (is_null($this->certManager)) { //no user
$this->certManager = \OC::$server->getCertificateManager(null);
}
}
$this->root = $params['root'] ?? '/';
$this->root = '/' . ltrim($this->root, '/');
Expand Down
66 changes: 15 additions & 51 deletions lib/private/Security/CertificateManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,6 @@
* Manage trusted certificates for users
*/
class CertificateManager implements ICertificateManager {
/**
* @var string
*/
protected $uid;

/**
* @var \OC\Files\View
*/
Expand All @@ -63,18 +58,15 @@ class CertificateManager implements ICertificateManager {
protected $random;

/**
* @param string $uid
* @param \OC\Files\View $view relative to data/
* @param IConfig $config
* @param ILogger $logger
* @param ISecureRandom $random
*/
public function __construct($uid,
\OC\Files\View $view,
public function __construct(\OC\Files\View $view,
IConfig $config,
ILogger $logger,
ISecureRandom $random) {
$this->uid = $uid;
$this->view = $view;
$this->config = $config;
$this->logger = $logger;
Expand Down Expand Up @@ -148,7 +140,7 @@ public function createCertificateBundle() {
fwrite($fhCerts, $defaultCertificates);

// Append the system certificate bundle
$systemBundle = $this->getCertificateBundle(null);
$systemBundle = $this->getCertificateBundle();
if ($systemBundle !== $certPath && $this->view->file_exists($systemBundle)) {
$systemCertificates = $this->view->file_get_contents($systemBundle);
fwrite($fhCerts, $systemCertificates);
Expand Down Expand Up @@ -207,73 +199,45 @@ public function removeCertificate($name) {
}

/**
* Get the path to the certificate bundle for this user
* Get the path to the certificate bundle
*
* @param string|null $uid (optional) user to get the certificate bundle for, use `null` to get the system bundle
* @return string
*/
public function getCertificateBundle($uid = '') {
if ($uid === '') {
$uid = $this->uid;
}
return $this->getPathToCertificates($uid) . 'rootcerts.crt';
public function getCertificateBundle() {
return $this->getPathToCertificates() . 'rootcerts.crt';
}

/**
* Get the full local path to the certificate bundle for this user
* Get the full local path to the certificate bundle
*
* @param string $uid (optional) user to get the certificate bundle for, use `null` to get the system bundle
* @return string
*/
public function getAbsoluteBundlePath($uid = '') {
if ($uid === '') {
$uid = $this->uid;
}
if ($this->needsRebundling($uid)) {
if (is_null($uid)) {
$manager = new CertificateManager(null, $this->view, $this->config, $this->logger, $this->random);
$manager->createCertificateBundle();
} else {
$this->createCertificateBundle();
}
public function getAbsoluteBundlePath() {
if ($this->needsRebundling()) {
$this->createCertificateBundle();
}
return $this->view->getLocalFile($this->getCertificateBundle($uid));
return $this->view->getLocalFile($this->getCertificateBundle());
}

/**
* @param string|null $uid (optional) user to get the certificate path for, use `null` to get the system path
* @return string
*/
private function getPathToCertificates($uid = '') {
if ($uid === '') {
$uid = $this->uid;
}
return is_null($uid) ? '/files_external/' : '/' . $uid . '/files_external/';
private function getPathToCertificates() {
return '/files_external/';
}

/**
* Check if we need to re-bundle the certificates because one of the sources has updated
*
* @param string $uid (optional) user to get the certificate path for, use `null` to get the system path
* @return bool
*/
private function needsRebundling($uid = '') {
if ($uid === '') {
$uid = $this->uid;
}
$sourceMTimes = [$this->getFilemtimeOfCaBundle()];
$targetBundle = $this->getCertificateBundle($uid);
private function needsRebundling() {
$targetBundle = $this->getCertificateBundle();
if (!$this->view->file_exists($targetBundle)) {
return true;
}

if (!is_null($uid)) { // also depend on the system bundle
$sourceMTimes[] = $this->view->filemtime($this->getCertificateBundle(null));
}

$sourceMTime = array_reduce($sourceMTimes, function ($max, $mtime) {
return max($max, $mtime);
}, 0);
$sourceMTime = $this->getFilemtimeOfCaBundle();
return $sourceMTime > $this->view->filemtime($targetBundle);
}

Expand Down
44 changes: 7 additions & 37 deletions lib/private/Server.php
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@
use OCP\IAvatarManager;
use OCP\ICache;
use OCP\ICacheFactory;
use OCP\ICertificateManager;
use OCP\IDateTimeFormatter;
use OCP\IDateTimeZone;
use OCP\IDBConnection;
Expand Down Expand Up @@ -823,23 +824,8 @@ public function __construct($webRoot, \OC\Config $config) {
/** @deprecated 19.0.0 */
$this->registerDeprecatedAlias('DatabaseConnection', IDBConnection::class);


$this->registerService(IClientService::class, function (ContainerInterface $c) {
$user = \OC_User::getUser();
$uid = $user ? $user : null;
return new ClientService(
$c->get(\OCP\IConfig::class),
$c->get(ILogger::class),
new \OC\Security\CertificateManager(
$uid,
new View(),
$c->get(\OCP\IConfig::class),
$c->get(ILogger::class),
$c->get(ISecureRandom::class)
)
);
});
/** @deprecated 19.0.0 */
$this->registerAlias(ICertificateManager::class, CertificateManager::class);
$this->registerAlias(IClientService::class, ClientService::class);
$this->registerDeprecatedAlias('HttpClientService', IClientService::class);
$this->registerService(IEventLogger::class, function (ContainerInterface $c) {
$eventLogger = new EventLogger();
Expand Down Expand Up @@ -1840,28 +1826,12 @@ public function getCredentialsManager() {
}

/**
* Get the certificate manager for the user
* Get the certificate manager
*
* @param string $userId (optional) if not specified the current loggedin user is used, use null to get the system certificate manager
* @return \OCP\ICertificateManager | null if $uid is null and no user is logged in
* @deprecated 20.0.0
* @return \OCP\ICertificateManager
*/
public function getCertificateManager($userId = '') {
if ($userId === '') {
$userSession = $this->get(IUserSession::class);
$user = $userSession->getUser();
if (is_null($user)) {
return null;
}
$userId = $user->getUID();
}
return new CertificateManager(
$userId,
new View(),
$this->get(\OCP\IConfig::class),
$this->get(ILogger::class),
$this->get(ISecureRandom::class)
);
public function getCertificateManager() {
return $this->get(ICertificateManager::class);
}

/**
Expand Down
14 changes: 6 additions & 8 deletions lib/public/ICertificateManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,12 @@
namespace OCP;

/**
* Manage trusted certificates for users
* Manage trusted certificates
* @since 8.0.0
*/
interface ICertificateManager {
/**
* Returns all certificates trusted by the user
* Returns all certificates trusted by the system
*
* @return \OCP\ICertificate[]
* @since 8.0.0
Expand All @@ -53,20 +53,18 @@ public function addCertificate($certificate, $name);
public function removeCertificate($name);

/**
* Get the path to the certificate bundle for this user
* Get the path to the certificate bundle
*
* @param string $uid (optional) user to get the certificate bundle for, use `null` to get the system bundle (since 9.0.0)
* @return string
* @since 8.0.0
*/
public function getCertificateBundle($uid = '');
public function getCertificateBundle();

/**
* Get the full local path to the certificate bundle for this user
* Get the full local path to the certificate bundle
*
* @param string $uid (optional) user to get the certificate bundle for, use `null` to get the system bundle
* @return string
* @since 9.0.0
*/
public function getAbsoluteBundlePath($uid = '');
public function getAbsoluteBundlePath();
}
7 changes: 3 additions & 4 deletions lib/public/IServerContainer.php
Original file line number Diff line number Diff line change
Expand Up @@ -387,14 +387,13 @@ public function getRouter();
public function getSearch();

/**
* Get the certificate manager for the user
* Get the certificate manager
*
* @param string $userId (optional) if not specified the current loggedin user is used, use null to get the system certificate manager
* @return \OCP\ICertificateManager | null if $userId is null and no user is logged in
* @return \OCP\ICertificateManager
* @since 8.0.0
* @deprecated 20.0.0 have it injected or fetch it through \Psr\Container\ContainerInterface::get
*/
public function getCertificateManager($userId = null);
public function getCertificateManager();

/**
* Create a new event source
Expand Down
6 changes: 3 additions & 3 deletions tests/lib/Http/Client/ClientTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ private function setUpDefaultRequestOptions(): void {
$this->certificateManager
->expects($this->once())
->method('getAbsoluteBundlePath')
->with(null)
->with()
->willReturn('/my/path.crt');

$this->defaultRequestOptions = [
Expand Down Expand Up @@ -493,7 +493,7 @@ public function testSetDefaultOptionsWithProxy(): void {
$this->certificateManager
->expects($this->once())
->method('getAbsoluteBundlePath')
->with(null)
->with()
->willReturn('/my/path.crt');

$this->assertEquals([
Expand Down Expand Up @@ -529,7 +529,7 @@ public function testSetDefaultOptionsWithProxyAndExclude(): void {
$this->certificateManager
->expects($this->once())
->method('getAbsoluteBundlePath')
->with(null)
->with()
->willReturn('/my/path.crt');

$this->assertEquals([
Expand Down
Loading