diff options
author | Thomas Müller <thomas.mueller@tmit.eu> | 2016-01-12 15:01:46 +0100 |
---|---|---|
committer | Thomas Müller <thomas.mueller@tmit.eu> | 2016-01-12 15:01:46 +0100 |
commit | eac5d9fb3a52932fafdb200a2cf5d50fe9f1c759 (patch) | |
tree | b5ebb8da406d6d667632beb4b764568c8ff954a3 | |
parent | 2493cfede92c472c29cffc098206b8cdb7a2ca30 (diff) | |
parent | 0d0377ebfb123e079822632ae4bc6855a11eb117 (diff) | |
download | nextcloud-server-eac5d9fb3a52932fafdb200a2cf5d50fe9f1c759.tar.gz nextcloud-server-eac5d9fb3a52932fafdb200a2cf5d50fe9f1c759.zip |
Merge pull request #21336 from owncloud/system-root-certs
Allow admins to add system wide root certificates
-rw-r--r-- | apps/files_external/js/settings.js | 7 | ||||
-rw-r--r-- | config/config.sample.php | 5 | ||||
-rw-r--r-- | lib/private/http/client/client.php | 9 | ||||
-rw-r--r-- | lib/private/security/certificatemanager.php | 89 | ||||
-rw-r--r-- | lib/private/server.php | 6 | ||||
-rw-r--r-- | lib/public/icertificatemanager.php | 12 | ||||
-rw-r--r-- | lib/public/iservercontainer.php | 2 | ||||
-rw-r--r-- | settings/admin.php | 16 | ||||
-rw-r--r-- | settings/application.php | 4 | ||||
-rw-r--r-- | settings/controller/certificatecontroller.php | 71 | ||||
-rw-r--r-- | settings/js/certificates.js | 69 | ||||
-rw-r--r-- | settings/js/personal.js | 67 | ||||
-rw-r--r-- | settings/personal.php | 19 | ||||
-rw-r--r-- | settings/routes.php | 2 | ||||
-rw-r--r-- | settings/templates/certificates.php | 44 | ||||
-rw-r--r-- | settings/templates/personal.php | 42 | ||||
-rw-r--r-- | tests/lib/security/certificatemanager.php | 23 | ||||
-rw-r--r-- | tests/settings/controller/CertificateControllerTest.php | 4 |
18 files changed, 323 insertions, 168 deletions
diff --git a/apps/files_external/js/settings.js b/apps/files_external/js/settings.js index 59cf55d6ad5..2f879e1c850 100644 --- a/apps/files_external/js/settings.js +++ b/apps/files_external/js/settings.js @@ -1210,13 +1210,6 @@ $(document).ready(function() { }); mountConfigListView.loadStorages(); - $('#sslCertificate').on('click', 'td.remove>img', function() { - var $tr = $(this).closest('tr'); - $.post(OC.filePath('files_external', 'ajax', 'removeRootCertificate.php'), {cert: $tr.attr('id')}); - $tr.remove(); - return true; - }); - // TODO: move this into its own View class var $allowUserMounting = $('#allowUserMounting'); $allowUserMounting.bind('change', function() { diff --git a/config/config.sample.php b/config/config.sample.php index 525a0895b07..b0ede5cc6de 100644 --- a/config/config.sample.php +++ b/config/config.sample.php @@ -854,6 +854,11 @@ $CONFIG = array( ), /** + * Allow the configuration of system wide trusted certificates + */ +'enable_certificate_management' => false, + +/** * Memory caching backend configuration * * Available cache backends: diff --git a/lib/private/http/client/client.php b/lib/private/http/client/client.php index 5f298e1acd7..8cddfc3ae03 100644 --- a/lib/private/http/client/client.php +++ b/lib/private/http/client/client.php @@ -58,12 +58,11 @@ class Client implements IClient { * Sets the default options to the client */ private function setDefaultOptions() { - // Either use default bundle or the user bundle if nothing is specified - if($this->certificateManager->listCertificates() !== []) { - $dataDir = $this->config->getSystemValue('datadirectory'); - $this->client->setDefaultOption('verify', $dataDir.'/'.$this->certificateManager->getCertificateBundle()); + // Either use user bundle or the system bundle if nothing is specified + if ($this->certificateManager->listCertificates() !== []) { + $this->client->setDefaultOption('verify', $this->certificateManager->getAbsoluteBundlePath()); } else { - $this->client->setDefaultOption('verify', \OC::$SERVERROOT . '/resources/config/ca-bundle.crt'); + $this->client->setDefaultOption('verify', $this->certificateManager->getAbsoluteBundlePath(null)); } $this->client->setDefaultOption('headers/User-Agent', 'ownCloud Server Crawler'); diff --git a/lib/private/security/certificatemanager.php b/lib/private/security/certificatemanager.php index ded81863a73..ce0d330c4b2 100644 --- a/lib/private/security/certificatemanager.php +++ b/lib/private/security/certificatemanager.php @@ -50,7 +50,7 @@ class CertificateManager implements ICertificateManager { /** * @param string $uid - * @param \OC\Files\View $view relative zu data/ + * @param \OC\Files\View $view relative to data/ * @param IConfig $config */ public function __construct($uid, \OC\Files\View $view, IConfig $config) { @@ -83,7 +83,8 @@ class CertificateManager implements ICertificateManager { if ($file != '.' && $file != '..') { try { $result[] = new Certificate($this->view->file_get_contents($path . $file), $file); - } catch(\Exception $e) {} + } catch (\Exception $e) { + } } } closedir($handle); @@ -97,22 +98,34 @@ class CertificateManager implements ICertificateManager { $path = $this->getPathToCertificates(); $certs = $this->listCertificates(); - $fh_certs = $this->view->fopen($path . '/rootcerts.crt', 'w'); + if (!$this->view->file_exists($path)) { + $this->view->mkdir($path); + } + + $fhCerts = $this->view->fopen($path . '/rootcerts.crt', 'w'); // Write user certificates foreach ($certs as $cert) { $file = $path . '/uploads/' . $cert->getName(); $data = $this->view->file_get_contents($file); if (strpos($data, 'BEGIN CERTIFICATE')) { - fwrite($fh_certs, $data); - fwrite($fh_certs, "\r\n"); + fwrite($fhCerts, $data); + fwrite($fhCerts, "\r\n"); } } // Append the default certificates $defaultCertificates = file_get_contents(\OC::$SERVERROOT . '/resources/config/ca-bundle.crt'); - fwrite($fh_certs, $defaultCertificates); - fclose($fh_certs); + fwrite($fhCerts, $defaultCertificates); + + // Append the system certificate bundle + $systemBundle = $this->getCertificateBundle(null); + if ($this->view->file_exists($systemBundle)) { + $systemCertificates = $this->view->file_get_contents($systemBundle); + fwrite($fhCerts, $systemCertificates); + } + + fclose($fhCerts); } /** @@ -166,18 +179,72 @@ class CertificateManager implements ICertificateManager { /** * Get the path to the certificate bundle for this user * + * @param string $uid (optional) user to get the certificate bundle for, use `null` to get the system bundle * @return string */ - public function getCertificateBundle() { - return $this->getPathToCertificates() . 'rootcerts.crt'; + public function getCertificateBundle($uid = '') { + if ($uid === '') { + $uid = $this->uid; + } + return $this->getPathToCertificates($uid) . 'rootcerts.crt'; + } + + /** + * Get the full local path to the certificate bundle for this user + * + * @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); + $manager->createCertificateBundle(); + } else { + $this->createCertificateBundle(); + } + } + return $this->view->getLocalFile($this->getCertificateBundle($uid)); } /** + * @param string $uid (optional) user to get the certificate path for, use `null` to get the system path * @return string */ - private function getPathToCertificates() { - $path = is_null($this->uid) ? '/files_external/' : '/' . $this->uid . '/files_external/'; + private function getPathToCertificates($uid = '') { + if ($uid === '') { + $uid = $this->uid; + } + $path = is_null($uid) ? '/files_external/' : '/' . $uid . '/files_external/'; return $path; } + + /** + * 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 = [filemtime(\OC::$SERVERROOT . '/resources/config/ca-bundle.crt')]; + $targetBundle = $this->getCertificateBundle($uid); + if (!$this->view->file_exists($targetBundle)) { + return true; + } + if (!is_null($uid)) { // also depend on the system bundle + $sourceBundles[] = $this->view->filemtime($this->getCertificateBundle(null)); + } + + $sourceMTime = array_reduce($sourceMTimes, function ($max, $mtime) { + return max($max, $mtime); + }, 0); + return $sourceMTime > $this->view->filemtime($targetBundle); + } } diff --git a/lib/private/server.php b/lib/private/server.php index ead9fa95db8..414f59af612 100644 --- a/lib/private/server.php +++ b/lib/private/server.php @@ -921,11 +921,11 @@ class Server extends ServerContainer implements IServerContainer { /** * Get the certificate manager for the user * - * @param string $userId (optional) if not specified the current loggedin user is used + * @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 */ - public function getCertificateManager($userId = null) { - if (is_null($userId)) { + public function getCertificateManager($userId = '') { + if ($userId === '') { $userSession = $this->getUserSession(); $user = $userSession->getUser(); if (is_null($user)) { diff --git a/lib/public/icertificatemanager.php b/lib/public/icertificatemanager.php index b1a16d8b5ee..3872fdd765d 100644 --- a/lib/public/icertificatemanager.php +++ b/lib/public/icertificatemanager.php @@ -54,8 +54,18 @@ interface ICertificateManager { /** * Get the path to the certificate bundle for this user * + * @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(); + public function getCertificateBundle($uid = ''); + + /** + * Get the full local path to the certificate bundle for this user + * + * @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 = ''); } diff --git a/lib/public/iservercontainer.php b/lib/public/iservercontainer.php index 267e5dc4d31..e706750bb21 100644 --- a/lib/public/iservercontainer.php +++ b/lib/public/iservercontainer.php @@ -326,7 +326,7 @@ interface IServerContainer { /** * Get the certificate manager for the user * - * @param string $userId (optional) if not specified the current loggedin user is used + * @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 * @since 8.0.0 */ diff --git a/settings/admin.php b/settings/admin.php index 25db05d99ac..112b9d38c90 100644 --- a/settings/admin.php +++ b/settings/admin.php @@ -38,6 +38,10 @@ OC_Util::checkAdminUser(); $template = new OC_Template('settings', 'admin', 'user'); $l = \OC::$server->getL10N('settings'); +OC_Util::addScript('settings', 'certificates'); +OC_Util::addScript('files', 'jquery.iframe-transport'); +OC_Util::addScript('files', 'jquery.fileupload'); + $showLog = (\OC::$server->getConfig()->getSystemValue('log_type', 'owncloud') === 'owncloud'); $numEntriesToLoad = 3; $entries = OC_Log_Owncloud::getEntries($numEntriesToLoad + 1); @@ -52,6 +56,8 @@ if($doesLogFileExist) { $config = \OC::$server->getConfig(); $appConfig = \OC::$server->getAppConfig(); $request = \OC::$server->getRequest(); +$certificateManager = \OC::$server->getCertificateManager(null); +$urlGenerator = \OC::$server->getURLGenerator(); // Should we display sendmail as an option? $template->assign('sendmail_is_available', (bool) \OC_Helper::findBinaryPath('sendmail')); @@ -152,6 +158,16 @@ $template->assign('OutdatedCacheWarning', $outdatedCaches); // add hardcoded forms from the template $forms = OC_App::getForms('admin'); + +if ($config->getSystemValue('enable_certificate_management', false)) { + $certificatesTemplate = new OC_Template('settings', 'certificates'); + $certificatesTemplate->assign('type', 'admin'); + $certificatesTemplate->assign('uploadRoute', 'settings.Certificate.addSystemRootCertificate'); + $certificatesTemplate->assign('certs', $certificateManager->listCertificates()); + $certificatesTemplate->assign('urlGenerator', $urlGenerator); + $forms[] = $certificatesTemplate->fetchPage(); +} + $formsAndMore = array(); if ($request->getServerProtocol() !== 'https' || !OC_Util::isAnnotationsWorking() || $suggestedOverwriteCliUrl || !OC_Util::isSetLocaleWorking() || diff --git a/settings/application.php b/settings/application.php index 729e61b5925..1c562c62a84 100644 --- a/settings/application.php +++ b/settings/application.php @@ -107,6 +107,7 @@ class Application extends App { $c->query('AppName'), $c->query('Request'), $c->query('CertificateManager'), + $c->query('SystemCertificateManager'), $c->query('L10N'), $c->query('IAppManager') ); @@ -243,6 +244,9 @@ class Application extends App { $container->registerService('CertificateManager', function(IContainer $c){ return $c->query('ServerContainer')->getCertificateManager(); }); + $container->registerService('SystemCertificateManager', function (IContainer $c) { + return $c->query('ServerContainer')->getCertificateManager(null); + }); $container->registerService('Checker', function(IContainer $c) { /** @var Server $server */ $server = $c->query('ServerContainer'); diff --git a/settings/controller/certificatecontroller.php b/settings/controller/certificatecontroller.php index e360a1053c3..1c8dfe35556 100644 --- a/settings/controller/certificatecontroller.php +++ b/settings/controller/certificatecontroller.php @@ -36,7 +36,9 @@ use OCP\IRequest; */ class CertificateController extends Controller { /** @var ICertificateManager */ - private $certificateManager; + private $userCertificateManager; + /** @var ICertificateManager */ + private $systemCertificateManager; /** @var IL10N */ private $l10n; /** @var IAppManager */ @@ -45,17 +47,20 @@ class CertificateController extends Controller { /** * @param string $appName * @param IRequest $request - * @param ICertificateManager $certificateManager + * @param ICertificateManager $userCertificateManager + * @param ICertificateManager $systemCertificateManager * @param IL10N $l10n * @param IAppManager $appManager */ public function __construct($appName, IRequest $request, - ICertificateManager $certificateManager, + ICertificateManager $userCertificateManager, + ICertificateManager $systemCertificateManager, IL10N $l10n, IAppManager $appManager) { parent::__construct($appName, $request); - $this->certificateManager = $certificateManager; + $this->userCertificateManager = $userCertificateManager; + $this->systemCertificateManager = $systemCertificateManager; $this->l10n = $l10n; $this->appManager = $appManager; } @@ -68,6 +73,16 @@ class CertificateController extends Controller { * @return array */ public function addPersonalRootCertificate() { + return $this->addCertificate($this->userCertificateManager); + } + + /** + * Add a new root certificate to a trust store + * + * @param ICertificateManager $certificateManager + * @return array + */ + private function addCertificate(ICertificateManager $certificateManager) { $headers = []; if ($this->request->isUserAgent([\OC\AppFramework\Http\Request::USER_AGENT_IE_8])) { // due to upload iframe workaround, need to set content-type to text/plain @@ -79,23 +94,23 @@ class CertificateController extends Controller { } $file = $this->request->getUploadedFile('rootcert_import'); - if(empty($file)) { + if (empty($file)) { return new DataResponse(['message' => 'No file uploaded'], Http::STATUS_UNPROCESSABLE_ENTITY, $headers); } try { - $certificate = $this->certificateManager->addCertificate(file_get_contents($file['tmp_name']), $file['name']); + $certificate = $certificateManager->addCertificate(file_get_contents($file['tmp_name']), $file['name']); return new DataResponse( [ - 'name' => $certificate->getName(), - 'commonName' => $certificate->getCommonName(), - 'organization' => $certificate->getOrganization(), - 'validFrom' => $certificate->getIssueDate()->getTimestamp(), - 'validTill' => $certificate->getExpireDate()->getTimestamp(), - 'validFromString' => $this->l10n->l('date', $certificate->getIssueDate()), - 'validTillString' => $this->l10n->l('date', $certificate->getExpireDate()), - 'issuer' => $certificate->getIssuerName(), - 'issuerOrganization' => $certificate->getIssuerOrganization(), + 'name' => $certificate->getName(), + 'commonName' => $certificate->getCommonName(), + 'organization' => $certificate->getOrganization(), + 'validFrom' => $certificate->getIssueDate()->getTimestamp(), + 'validTill' => $certificate->getExpireDate()->getTimestamp(), + 'validFromString' => $this->l10n->l('date', $certificate->getIssueDate()), + 'validTillString' => $this->l10n->l('date', $certificate->getExpireDate()), + 'issuer' => $certificate->getIssuerName(), + 'issuerOrganization' => $certificate->getIssuerOrganization(), ], Http::STATUS_OK, $headers @@ -119,7 +134,7 @@ class CertificateController extends Controller { return new DataResponse('Individual certificate management disabled', Http::STATUS_FORBIDDEN); } - $this->certificateManager->removeCertificate($certificateIdentifier); + $this->userCertificateManager->removeCertificate($certificateIdentifier); return new DataResponse(); } @@ -140,4 +155,28 @@ class CertificateController extends Controller { return false; } + /** + * Add a new personal root certificate to the system's trust store + * + * @return array + */ + public function addSystemRootCertificate() { + return $this->addCertificate($this->systemCertificateManager); + } + + /** + * Removes a personal root certificate from the users' trust store + * + * @param string $certificateIdentifier + * @return DataResponse + */ + public function removeSystemRootCertificate($certificateIdentifier) { + + if ($this->isCertificateImportAllowed() === false) { + return new DataResponse('Individual certificate management disabled', Http::STATUS_FORBIDDEN); + } + + $this->systemCertificateManager->removeCertificate($certificateIdentifier); + return new DataResponse(); + } } diff --git a/settings/js/certificates.js b/settings/js/certificates.js new file mode 100644 index 00000000000..9ce9f9aa8d8 --- /dev/null +++ b/settings/js/certificates.js @@ -0,0 +1,69 @@ +$(document).ready(function () { + var type = $('#sslCertificate').data('type'); + $('#sslCertificate').on('click', 'td.remove', function () { + var row = $(this).parent(); + $.ajax(OC.generateUrl('settings/' + type + '/certificate/{certificate}', {certificate: row.data('name')}), { + type: 'DELETE' + }); + row.remove(); + + if ($('#sslCertificate > tbody > tr').length === 0) { + $('#sslCertificate').hide(); + } + return true; + }); + + $('#sslCertificate tr > td').tipsy({gravity: 'n', live: true}); + + $('#rootcert_import').fileupload({ + submit: function (e, data) { + data.formData = _.extend(data.formData || {}, { + requesttoken: OC.requestToken + }); + }, + success: function (data) { + if (typeof data === 'string') { + data = $.parseJSON(data); + } else if (data && data.length) { + // fetch response from iframe + data = $.parseJSON(data[0].body.innerText); + } + if (!data || typeof(data) === 'string') { + // IE8 iframe workaround comes here instead of fail() + OC.Notification.showTemporary( + t('settings', 'An error occurred. Please upload an ASCII-encoded PEM certificate.')); + return; + } + var issueDate = new Date(data.validFrom * 1000); + var expireDate = new Date(data.validTill * 1000); + var now = new Date(); + var isExpired = !(issueDate <= now && now <= expireDate); + + var row = $('<tr/>'); + row.data('name', data.name); + row.addClass(isExpired ? 'expired' : 'valid'); + row.append($('<td/>').attr('title', data.organization).text(data.commonName)); + row.append($('<td/>').attr('title', t('core,', 'Valid until {date}', {date: data.validTillString})) + .text(data.validTillString)); + row.append($('<td/>').attr('title', data.issuerOrganization).text(data.issuer)); + row.append($('<td/>').addClass('remove').append( + $('<img/>').attr({ + alt: t('core', 'Delete'), + title: t('core', 'Delete'), + src: OC.imagePath('core', 'actions/delete.svg') + }).addClass('action') + )); + + $('#sslCertificate tbody').append(row); + $('#sslCertificate').show(); + }, + fail: function () { + OC.Notification.showTemporary( + t('settings', 'An error occurred. Please upload an ASCII-encoded PEM certificate.')); + } + }); + + if ($('#sslCertificate > tbody > tr').length === 0) { + $('#sslCertificate').hide(); + } +}); diff --git a/settings/js/personal.js b/settings/js/personal.js index da74f28d70c..3e1a0d7497b 100644 --- a/settings/js/personal.js +++ b/settings/js/personal.js @@ -339,73 +339,6 @@ $(document).ready(function () { } }); - $('#sslCertificate').on('click', 'td.remove > img', function () { - var row = $(this).parent().parent(); - $.ajax(OC.generateUrl('settings/personal/certificate/{certificate}', {certificate: row.data('name')}), { - type: 'DELETE' - }); - row.remove(); - - if ($('#sslCertificate > tbody > tr').length === 0) { - $('#sslCertificate').hide(); - } - return true; - }); - - $('#sslCertificate tr > td').tipsy({gravity: 'n', live: true}); - - $('#rootcert_import').fileupload({ - submit: function(e, data) { - data.formData = _.extend(data.formData || {}, { - requesttoken: OC.requestToken - }); - }, - success: function (data) { - if (typeof data === 'string') { - data = $.parseJSON(data); - } else if (data && data.length) { - // fetch response from iframe - data = $.parseJSON(data[0].body.innerText); - } - if (!data || typeof(data) === 'string') { - // IE8 iframe workaround comes here instead of fail() - OC.Notification.showTemporary( - t('settings', 'An error occurred. Please upload an ASCII-encoded PEM certificate.')); - return; - } - var issueDate = new Date(data.validFrom * 1000); - var expireDate = new Date(data.validTill * 1000); - var now = new Date(); - var isExpired = !(issueDate <= now && now <= expireDate); - - var row = $('<tr/>'); - row.data('name', data.name); - row.addClass(isExpired? 'expired': 'valid'); - row.append($('<td/>').attr('title', data.organization).text(data.commonName)); - row.append($('<td/>').attr('title', t('core,', 'Valid until {date}', {date: data.validTillString})) - .text(data.validTillString)); - row.append($('<td/>').attr('title', data.issuerOrganization).text(data.issuer)); - row.append($('<td/>').addClass('remove').append( - $('<img/>').attr({ - alt: t('core', 'Delete'), - title: t('core', 'Delete'), - src: OC.imagePath('core', 'actions/delete.svg') - }).addClass('action') - )); - - $('#sslCertificate tbody').append(row); - $('#sslCertificate').show(); - }, - fail: function () { - OC.Notification.showTemporary( - t('settings', 'An error occurred. Please upload an ASCII-encoded PEM certificate.')); - } - }); - - if ($('#sslCertificate > tbody > tr').length === 0) { - $('#sslCertificate').hide(); - } - // Load the big avatar if (oc_config.enable_avatars) { $('#avatar .avatardiv').avatar(OC.currentUser, 145); diff --git a/settings/personal.php b/settings/personal.php index c4e1c057bf3..54698fd6d54 100644 --- a/settings/personal.php +++ b/settings/personal.php @@ -43,6 +43,7 @@ $urlGenerator = \OC::$server->getURLGenerator(); // Highlight navigation entry OC_Util::addScript( 'settings', 'personal' ); +OC_Util::addScript('settings', 'certificates'); OC_Util::addStyle( 'settings', 'settings' ); \OC_Util::addVendorScript('strengthify/jquery.strengthify'); \OC_Util::addVendorStyle('strengthify/strengthify'); @@ -168,6 +169,17 @@ $formsAndMore[]= ['anchor' => 'clientsbox', 'section-name' => $l->t('Sync client $forms=OC_App::getForms('personal'); + +// add bottom hardcoded forms from the template +if ($enableCertImport) { + $certificatesTemplate = new OC_Template('settings', 'certificates'); + $certificatesTemplate->assign('type', 'personal'); + $certificatesTemplate->assign('uploadRoute', 'settings.Certificate.addPersonalRootCertificate'); + $certificatesTemplate->assign('certs', $certificateManager->listCertificates()); + $certificatesTemplate->assign('urlGenerator', $urlGenerator); + $forms[] = $certificatesTemplate->fetchPage(); +} + $formsMap = array_map(function($form){ if (preg_match('%(<h2(?P<class>[^>]*)>.*?</h2>)%i', $form, $regs)) { $sectionName = str_replace('<h2'.$regs['class'].'>', '', $regs[0]); @@ -188,12 +200,5 @@ $formsMap = array_map(function($form){ $formsAndMore = array_merge($formsAndMore, $formsMap); -// add bottom hardcoded forms from the template -if($enableCertImport) { - $formsAndMore[]= array( 'anchor' => 'ssl-root-certificates', 'section-name' => $l->t('SSL root certificates') ); -} - - - $tmpl->assign('forms', $formsAndMore); $tmpl->printPage(); diff --git a/settings/routes.php b/settings/routes.php index 6b6b0150168..0cc5e1eccab 100644 --- a/settings/routes.php +++ b/settings/routes.php @@ -57,6 +57,8 @@ $application->registerRoutes($this, [ ['name' => 'CheckSetup#rescanFailedIntegrityCheck', 'url' => '/settings/integrity/rescan', 'verb' => 'GET'], ['name' => 'Certificate#addPersonalRootCertificate', 'url' => '/settings/personal/certificate', 'verb' => 'POST'], ['name' => 'Certificate#removePersonalRootCertificate', 'url' => '/settings/personal/certificate/{certificateIdentifier}', 'verb' => 'DELETE'], + ['name' => 'Certificate#addSystemRootCertificate', 'url' => '/settings/admin/certificate', 'verb' => 'POST'], + ['name' => 'Certificate#removeSystemRootCertificate', 'url' => '/settings/admin/certificate/{certificateIdentifier}', 'verb' => 'DELETE'], ] ]); diff --git a/settings/templates/certificates.php b/settings/templates/certificates.php new file mode 100644 index 00000000000..c1ccdcaef95 --- /dev/null +++ b/settings/templates/certificates.php @@ -0,0 +1,44 @@ +<div class="section"> + <h2><?php p($l->t('SSL Root Certificates')); ?></h2> + <table id="sslCertificate" class="grid" data-type="<?php p($_['type']); ?>"> + <thead> + <tr> + <th><?php p($l->t('Common Name')); ?></th> + <th><?php p($l->t('Valid until')); ?></th> + <th><?php p($l->t('Issued By')); ?></th> + </tr> + </thead> + <tbody> + <?php foreach ($_['certs'] as $rootCert): /**@var \OCP\ICertificate $rootCert */ ?> + <tr class="<?php echo ($rootCert->isExpired()) ? 'expired' : 'valid' ?>" + data-name="<?php p($rootCert->getName()) ?>"> + <td class="rootCert" + title="<?php p($rootCert->getOrganization()) ?>"> + <?php p($rootCert->getCommonName()) ?> + </td> + <td title="<?php p($l->t('Valid until %s', $l->l('date', $rootCert->getExpireDate()))) ?>"> + <?php echo $l->l('date', $rootCert->getExpireDate()) ?> + </td> + <td title="<?php p($rootCert->getIssuerOrganization()) ?>"> + <?php p($rootCert->getIssuerName()) ?> + </td> + <td <?php if ($rootCert != ''): ?>class="remove" + <?php else: ?>style="visibility:hidden;" + <?php endif; ?>><img alt="<?php p($l->t('Delete')); ?>" + title="<?php p($l->t('Delete')); ?>" + class="svg action" + src="<?php print_unescaped(image_path('core', 'actions/delete.svg')); ?>"/> + </td> + </tr> + <?php endforeach; ?> + </tbody> + </table> + <form class="uploadButton" method="post" + action="<?php p($_['urlGenerator']->linkToRoute($_['uploadRoute'])); ?>" + target="certUploadFrame"> + <label for="rootcert_import" class="inlineblock button" + id="rootcert_import_button"><?php p($l->t('Import root certificate')); ?></label> + <input type="file" id="rootcert_import" name="rootcert_import" + class="hiddenuploadfield"> + </form> +</div> diff --git a/settings/templates/personal.php b/settings/templates/personal.php index ce179ca8788..5bae01742b6 100644 --- a/settings/templates/personal.php +++ b/settings/templates/personal.php @@ -204,48 +204,6 @@ if($_['passwordChangeSupported']) { <?php } };?> -<?php if($_['showCertificates']) : ?> -<div id="ssl-root-certificates" class="section"> - <h2><?php p($l->t('SSL root certificates')); ?></h2> - <table id="sslCertificate" class="grid"> - <thead> - <tr> - <th><?php p($l->t('Common Name')); ?></th> - <th><?php p($l->t('Valid until')); ?></th> - <th><?php p($l->t('Issued By')); ?></th> - <th></th> - </tr> - </thead> - <tbody> - <?php foreach ($_['certs'] as $rootCert): /**@var \OCP\ICertificate $rootCert*/ ?> - <tr class="<?php echo ($rootCert->isExpired()) ? 'expired' : 'valid' ?>" data-name="<?php p($rootCert->getName()) ?>"> - <td class="rootCert" title="<?php p($rootCert->getOrganization())?>"> - <?php p($rootCert->getCommonName()) ?> - </td> - <td title="<?php p($l->t('Valid until %s', $l->l('date', $rootCert->getExpireDate()))) ?>"> - <?php echo $l->l('date', $rootCert->getExpireDate()) ?> - </td> - <td title="<?php p($rootCert->getIssuerOrganization()) ?>"> - <?php p($rootCert->getIssuerName()) ?> - </td> - <td <?php if ($rootCert != ''): ?>class="remove" - <?php else: ?>style="visibility:hidden;" - <?php endif; ?>><img alt="<?php p($l->t('Delete')); ?>" - title="<?php p($l->t('Delete')); ?>" - class="svg action" - src="<?php print_unescaped(image_path('core', 'actions/delete.svg')); ?>"/> - </td> - </tr> - <?php endforeach; ?> - </tbody> - </table> - <form class="uploadButton" method="post" action="<?php p($_['urlGenerator']->linkToRoute('settings.Certificate.addPersonalRootCertificate')); ?>" target="certUploadFrame"> - <label for="rootcert_import" class="inlineblock button" id="rootcert_import_button"><?php p($l->t('Import root certificate')); ?></label> - <input type="file" id="rootcert_import" name="rootcert_import" class="hiddenuploadfield"> - </form> -</div> -<?php endif; ?> - <div class="section"> <h2><?php p($l->t('Version'));?></h2> <p><a href="<?php print_unescaped($theme->getBaseUrl()); ?>" target="_blank"><?php p($theme->getTitle()); ?></a> <?php p(OC_Util::getHumanVersion()) ?></p> diff --git a/tests/lib/security/certificatemanager.php b/tests/lib/security/certificatemanager.php index f2e29cab18e..e9ccea39efe 100644 --- a/tests/lib/security/certificatemanager.php +++ b/tests/lib/security/certificatemanager.php @@ -14,6 +14,8 @@ use \OC\Security\CertificateManager; * @group DB */ class CertificateManagerTest extends \Test\TestCase { + use \Test\Traits\UserTrait; + use \Test\Traits\MountProviderTrait; /** @var CertificateManager */ private $certificateManager; @@ -24,7 +26,10 @@ class CertificateManagerTest extends \Test\TestCase { parent::setUp(); $this->username = $this->getUniqueID('', 20); - \OC::$server->getUserManager()->createUser($this->username, $this->getUniqueID('', 20)); + $this->createUser($this->username, ''); + + $storage = new \OC\Files\Storage\Temporary(); + $this->registerMount($this->username, $storage, '/' . $this->username . '/'); \OC_Util::tearDownFS(); \OC_User::setUserId(''); @@ -40,7 +45,9 @@ class CertificateManagerTest extends \Test\TestCase { protected function tearDown() { $user = \OC::$server->getUserManager()->get($this->username); - if ($user !== null) { $user->delete(); } + if ($user !== null) { + $user->delete(); + } parent::tearDown(); } @@ -56,14 +63,14 @@ class CertificateManagerTest extends \Test\TestCase { $this->assertSame(array(), $this->certificateManager->listCertificates()); // Add some certificates - $this->certificateManager->addCertificate(file_get_contents(__DIR__.'/../../data/certificates/goodCertificate.crt'), 'GoodCertificate'); + $this->certificateManager->addCertificate(file_get_contents(__DIR__ . '/../../data/certificates/goodCertificate.crt'), 'GoodCertificate'); $certificateStore = array(); - $certificateStore[] = new \OC\Security\Certificate(file_get_contents(__DIR__.'/../../data/certificates/goodCertificate.crt'), 'GoodCertificate'); + $certificateStore[] = new \OC\Security\Certificate(file_get_contents(__DIR__ . '/../../data/certificates/goodCertificate.crt'), 'GoodCertificate'); $this->assertEqualsArrays($certificateStore, $this->certificateManager->listCertificates()); // Add another certificates - $this->certificateManager->addCertificate(file_get_contents(__DIR__.'/../../data/certificates/expiredCertificate.crt'), 'ExpiredCertificate'); - $certificateStore[] = new \OC\Security\Certificate(file_get_contents(__DIR__.'/../../data/certificates/expiredCertificate.crt'), 'ExpiredCertificate'); + $this->certificateManager->addCertificate(file_get_contents(__DIR__ . '/../../data/certificates/expiredCertificate.crt'), 'ExpiredCertificate'); + $certificateStore[] = new \OC\Security\Certificate(file_get_contents(__DIR__ . '/../../data/certificates/expiredCertificate.crt'), 'ExpiredCertificate'); $this->assertEqualsArrays($certificateStore, $this->certificateManager->listCertificates()); } @@ -93,7 +100,7 @@ class CertificateManagerTest extends \Test\TestCase { * @param string $filename */ function testAddDangerousFile($filename) { - $this->certificateManager->addCertificate(file_get_contents(__DIR__.'/../../data/certificates/expiredCertificate.crt'), $filename); + $this->certificateManager->addCertificate(file_get_contents(__DIR__ . '/../../data/certificates/expiredCertificate.crt'), $filename); } function testRemoveDangerousFile() { @@ -101,7 +108,7 @@ class CertificateManagerTest extends \Test\TestCase { } function testRemoveExistingFile() { - $this->certificateManager->addCertificate(file_get_contents(__DIR__.'/../../data/certificates/goodCertificate.crt'), 'GoodCertificate'); + $this->certificateManager->addCertificate(file_get_contents(__DIR__ . '/../../data/certificates/goodCertificate.crt'), 'GoodCertificate'); $this->assertTrue($this->certificateManager->removeCertificate('GoodCertificate')); } diff --git a/tests/settings/controller/CertificateControllerTest.php b/tests/settings/controller/CertificateControllerTest.php index 023d7753cca..2fdbbb8b0ac 100644 --- a/tests/settings/controller/CertificateControllerTest.php +++ b/tests/settings/controller/CertificateControllerTest.php @@ -44,12 +44,15 @@ class CertificateControllerTest extends \Test\TestCase { private $l10n; /** @var IAppManager */ private $appManager; + /** @var ICertificateManager */ + private $systemCertificateManager; public function setUp() { parent::setUp(); $this->request = $this->getMock('\OCP\IRequest'); $this->certificateManager = $this->getMock('\OCP\ICertificateManager'); + $this->systemCertificateManager = $this->getMock('\OCP\ICertificateManager'); $this->l10n = $this->getMock('\OCP\IL10N'); $this->appManager = $this->getMock('OCP\App\IAppManager'); @@ -59,6 +62,7 @@ class CertificateControllerTest extends \Test\TestCase { 'settings', $this->request, $this->certificateManager, + $this->systemCertificateManager, $this->l10n, $this->appManager ] |