From ecdbf006284fa4907b54f58ac6ba59f54b9738a5 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Thu, 14 Aug 2014 14:24:10 +0200 Subject: [PATCH] Move certificate management code to core --- .../ajax/addRootCertificate.php | 34 ++--- .../ajax/removeRootCertificate.php | 10 +- apps/files_external/lib/config.php | 47 ------- apps/files_external/personal.php | 3 +- lib/private/certificatemanager.php | 116 ++++++++++++++++++ lib/private/server.php | 17 +++ lib/public/icertificatemanager.php | 40 ++++++ lib/public/iservercontainer.php | 7 ++ 8 files changed, 193 insertions(+), 81 deletions(-) create mode 100644 lib/private/certificatemanager.php create mode 100644 lib/public/icertificatemanager.php diff --git a/apps/files_external/ajax/addRootCertificate.php b/apps/files_external/ajax/addRootCertificate.php index fcd3a617ad..38b1860594 100644 --- a/apps/files_external/ajax/addRootCertificate.php +++ b/apps/files_external/ajax/addRootCertificate.php @@ -3,8 +3,8 @@ OCP\JSON::checkAppEnabled('files_external'); OCP\JSON::callCheck(); -if ( ! ($filename = $_FILES['rootcert_import']['name']) ) { - header('Location:' . OCP\Util::linkToRoute( "settings_personal" )); +if (!($filename = $_FILES['rootcert_import']['name'])) { + header('Location:' . OCP\Util::linkToRoute("settings_personal")); exit; } @@ -13,33 +13,13 @@ $data = fread($fh, filesize($_FILES['rootcert_import']['tmp_name'])); fclose($fh); $filename = $_FILES['rootcert_import']['name']; -$view = new \OC\Files\View('/'.\OCP\User::getUser().'/files_external/uploads'); -if (!$view->file_exists('')) { - $view->mkdir(''); -} +$certificateManager = \OC::$server->getCertificateManager(); -$isValid = openssl_pkey_get_public($data); - -//maybe it was just the wrong file format, try to convert it... -if ($isValid == false) { - $data = chunk_split(base64_encode($data), 64, "\n"); - $data = "-----BEGIN CERTIFICATE-----\n".$data."-----END CERTIFICATE-----\n"; - $isValid = openssl_pkey_get_public($data); -} - -// add the certificate if it could be verified -if ( $isValid ) { - // disable proxy to prevent multiple fopen calls - $proxyStatus = \OC_FileProxy::$enabled; - \OC_FileProxy::$enabled = false; - $view->file_put_contents($filename, $data); - OC_Mount_Config::createCertificateBundle(); - \OC_FileProxy::$enabled = $proxyStatus; -} else { +if (!$certificateManager->addCertificate($data, $filename)) { OCP\Util::writeLog('files_external', - 'Couldn\'t import SSL root certificate ('.$filename.'), allowed formats: PEM and DER', - OCP\Util::WARN); + 'Couldn\'t import SSL root certificate (' . $filename . '), allowed formats: PEM and DER', + OCP\Util::WARN); } -header('Location:' . OCP\Util::linkToRoute( "settings_personal" )); +header('Location:' . OCP\Util::linkToRoute("settings_personal")); exit; diff --git a/apps/files_external/ajax/removeRootCertificate.php b/apps/files_external/ajax/removeRootCertificate.php index 664b3937e9..e6795800e0 100644 --- a/apps/files_external/ajax/removeRootCertificate.php +++ b/apps/files_external/ajax/removeRootCertificate.php @@ -4,10 +4,8 @@ OCP\JSON::checkAppEnabled('files_external'); OCP\JSON::checkLoggedIn(); OCP\JSON::callCheck(); -$view = \OCP\Files::getStorage("files_external"); -$file = 'uploads/'.ltrim($_POST['cert'], "/\\."); - -if ( $view->file_exists($file) ) { - $view->unlink($file); - OC_Mount_Config::createCertificateBundle(); +$name = $_POST['cert']; +$certificateManager = \OC::$server->getCertificateManager(); +if (\OC\Files\Filesystem::isValidPath($name)) { + $certificateManager->removeCertificate($name); } diff --git a/apps/files_external/lib/config.php b/apps/files_external/lib/config.php index 85e36fd904..952463b801 100755 --- a/apps/files_external/lib/config.php +++ b/apps/files_external/lib/config.php @@ -619,53 +619,6 @@ class OC_Mount_Config { @chmod($file, 0640); } - /** - * Returns all user uploaded ssl root certificates - * @return array - */ - public static function getCertificates() { - $path=OC_User::getHome(OC_User::getUser()) . '/files_external/uploads/'; - \OCP\Util::writeLog('files_external', 'checking path '.$path, \OCP\Util::INFO); - if ( ! is_dir($path)) { - //path might not exist (e.g. non-standard OC_User::getHome() value) - //in this case create full path using 3rd (recursive=true) parameter. - mkdir($path, 0777, true); - } - $result = array(); - $handle = opendir($path); - if(!is_resource($handle)) { - return array(); - } - while (false !== ($file = readdir($handle))) { - if ($file != '.' && $file != '..') $result[] = $file; - } - return $result; - } - - /** - * creates certificate bundle - */ - public static function createCertificateBundle() { - $path=OC_User::getHome(OC_User::getUser()) . '/files_external'; - - $certs = OC_Mount_Config::getCertificates(); - $fh_certs = fopen($path."/rootcerts.crt", 'w'); - foreach ($certs as $cert) { - $file=$path.'/uploads/'.$cert; - $fh = fopen($file, "r"); - $data = fread($fh, filesize($file)); - fclose($fh); - if (strpos($data, 'BEGIN CERTIFICATE')) { - fwrite($fh_certs, $data); - fwrite($fh_certs, "\r\n"); - } - } - - fclose($fh_certs); - - return true; - } - /** * check dependencies */ diff --git a/apps/files_external/personal.php b/apps/files_external/personal.php index 90d7afed28..9965303f21 100755 --- a/apps/files_external/personal.php +++ b/apps/files_external/personal.php @@ -23,11 +23,12 @@ OCP\Util::addScript('files_external', 'settings'); OCP\Util::addStyle('files_external', 'settings'); $backends = OC_Mount_Config::getPersonalBackends(); +$certificateManager = \OC::$server->getCertificateManager(); $tmpl = new OCP\Template('files_external', 'settings'); $tmpl->assign('isAdminPage', false); $tmpl->assign('mounts', OC_Mount_Config::getPersonalMountPoints()); -$tmpl->assign('certs', OC_Mount_Config::getCertificates()); +$tmpl->assign('certs', $certificateManager->listCertificates()); $tmpl->assign('dependencies', OC_Mount_Config::checkDependencies()); $tmpl->assign('backends', $backends); return $tmpl->fetchPage(); diff --git a/lib/private/certificatemanager.php b/lib/private/certificatemanager.php new file mode 100644 index 0000000000..72e0541fa4 --- /dev/null +++ b/lib/private/certificatemanager.php @@ -0,0 +1,116 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OC; + +/** + * Manage trusted certificates for users + */ +class CertificateManager { + /** + * @var \OCP\IUser + */ + protected $user; + + /** + * @param \OCP\IUser $user + */ + public function __construct($user) { + $this->user = $user; + } + + /** + * Returns all certificates trusted by the user + * + * @return string[] + */ + public function listCertificates() { + $path = $this->user->getHome() . '/files_external/uploads/'; + if (!is_dir($path)) { + //path might not exist (e.g. non-standard OC_User::getHome() value) + //in this case create full path using 3rd (recursive=true) parameter. + //note that we use "normal" php filesystem functions here since the certs need to be local + mkdir($path, 0777, true); + } + $result = array(); + $handle = opendir($path); + if (!is_resource($handle)) { + return array(); + } + while (false !== ($file = readdir($handle))) { + if ($file != '.' && $file != '..') $result[] = $file; + } + return $result; + } + + /** + * create the certificate bundle of all trusted certificated + */ + protected function createCertificateBundle() { + $path = $this->user->getHome() . '/files_external/'; + $certs = $this->listCertificates(); + + $fh_certs = fopen($path . '/rootcerts.crt', 'w'); + foreach ($certs as $cert) { + $file = $path . '/uploads/' . $cert; + $fh = fopen($file, 'r'); + $data = fread($fh, filesize($file)); + fclose($fh); + if (strpos($data, 'BEGIN CERTIFICATE')) { + fwrite($fh_certs, $data); + fwrite($fh_certs, "\r\n"); + } + } + + fclose($fh_certs); + } + + /** + * @param string $certificate the certificate data + * @param string $name the filename for the certificate + * @return bool + */ + public function addCertificate($certificate, $name) { + $isValid = openssl_pkey_get_public($certificate); + + if (!$isValid) { + $data = chunk_split(base64_encode($certificate), 64, "\n"); + $data = "-----BEGIN CERTIFICATE-----\n" . $data . "-----END CERTIFICATE-----\n"; + $isValid = openssl_pkey_get_public($data); + } + + if ($isValid) { + $file = $this->user->getHome() . '/files_external/uploads/' . $name; + file_put_contents($file, $certificate); + $this->createCertificateBundle(); + return true; + } else { + return false; + } + } + + /** + * @param string $name + */ + public function removeCertificate($name) { + $path = $this->user->getHome() . '/files_external/uploads/'; + if (file_exists($path . $name)) { + unlink($path . $name); + $this->createCertificateBundle(); + } + } + + /** + * Get the path to the certificate bundle for this user + * + * @return string + */ + public function getCertificateBundle() { + return $this->user->getHome() . '/files_external/rootcerts.crt'; + } +} diff --git a/lib/private/server.php b/lib/private/server.php index 53aab7a586..a30571c1e1 100644 --- a/lib/private/server.php +++ b/lib/private/server.php @@ -469,4 +469,21 @@ class Server extends SimpleContainer implements IServerContainer { function getDb() { return $this->query('Db'); } + + /** + * Get the certificate manager for the user + * + * @param \OCP\IUser $user (optional) if not specified the current loggedin user is used + * @return \OCP\ICertificateManager + */ + function getCertificateManager($user = null) { + if (is_null($user)) { + $userSession = $this->getUserSession(); + $user = $userSession->getUser(); + if (is_null($user)) { + return null; + } + } + return new CertificateManager($user); + } } diff --git a/lib/public/icertificatemanager.php b/lib/public/icertificatemanager.php new file mode 100644 index 0000000000..9ce7d72117 --- /dev/null +++ b/lib/public/icertificatemanager.php @@ -0,0 +1,40 @@ + + * This file is licensed under the Affero General Public License version 3 or + * later. + * See the COPYING-README file. + */ + +namespace OCP; + +/** + * Manage trusted certificates for users + */ +interface ICertificateManager { + /** + * Returns all certificates trusted by the user + * + * @return string[] + */ + public function listCertificates(); + + /** + * @param string $certificate the certificate data + * @param string $name the filename for the certificate + * @return bool + */ + public function addCertificate($certificate, $name); + + /** + * @param string $name + */ + public function removeCertificate($name); + + /** + * Get the path to the certificate bundle for this user + * + * @return string + */ + public function getCertificateBundle(); +} diff --git a/lib/public/iservercontainer.php b/lib/public/iservercontainer.php index 9c39ac7ae7..215bf92f39 100644 --- a/lib/public/iservercontainer.php +++ b/lib/public/iservercontainer.php @@ -226,4 +226,11 @@ interface IServerContainer { */ function getSearch(); + /** + * Get the certificate manager for the user + * + * @param \OCP\IUser $user (optional) if not specified the current loggedin user is used + * @return \OCP\ICertificateManager + */ + function getCertificateManager($user = null); }