From ecdbf006284fa4907b54f58ac6ba59f54b9738a5 Mon Sep 17 00:00:00 2001
From: Robin Appelman
Date: Thu, 14 Aug 2014 14:24:10 +0200
Subject: [PATCH 01/18] 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);
}
From c2ebc192a6a6c7cb9cff958e412e0cc4aff15ead Mon Sep 17 00:00:00 2001
From: Robin Appelman
Date: Thu, 14 Aug 2014 14:24:56 +0200
Subject: [PATCH 02/18] Make external shares work with imported self-signed
certificates
---
apps/files_sharing/lib/external/manager.php | 4 +++-
apps/files_sharing/lib/external/storage.php | 12 +++++++++++-
2 files changed, 14 insertions(+), 2 deletions(-)
diff --git a/apps/files_sharing/lib/external/manager.php b/apps/files_sharing/lib/external/manager.php
index dda283f495..8176302a86 100644
--- a/apps/files_sharing/lib/external/manager.php
+++ b/apps/files_sharing/lib/external/manager.php
@@ -113,9 +113,11 @@ class Manager {
* @return Mount
*/
protected function mountShare($data) {
+ $user = $this->userSession->getUser();
$data['manager'] = $this;
- $mountPoint = '/' . $this->userSession->getUser()->getUID() . '/files' . $data['mountpoint'];
+ $mountPoint = '/' . $user->getUID() . '/files' . $data['mountpoint'];
$data['mountpoint'] = $mountPoint;
+ $data['certificateManager'] = \OC::$server->getCertificateManager($user);
$mount = new Mount(self::STORAGE, $mountPoint, $data, $this, $this->storageLoader);
$this->mountManager->addMount($mount);
return $mount;
diff --git a/apps/files_sharing/lib/external/storage.php b/apps/files_sharing/lib/external/storage.php
index 855be2872b..b3a8bdcc96 100644
--- a/apps/files_sharing/lib/external/storage.php
+++ b/apps/files_sharing/lib/external/storage.php
@@ -37,6 +37,11 @@ class Storage extends DAV implements ISharedStorage {
*/
private $token;
+ /**
+ * @var \OCP\ICertificateManager
+ */
+ private $certificateManager;
+
private $updateChecked = false;
/**
@@ -46,6 +51,7 @@ class Storage extends DAV implements ISharedStorage {
public function __construct($options) {
$this->manager = $options['manager'];
+ $this->certificateManager = $options['certificateManager'];
$this->remote = $options['remote'];
$this->remoteUser = $options['owner'];
list($protocol, $remote) = explode('://', $this->remote);
@@ -190,7 +196,11 @@ class Storage extends DAV implements ISharedStorage {
http_build_query(array('password' => $password)));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
- $result = curl_exec($ch);
+ curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
+ curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
+ curl_setopt($ch, CURLOPT_CAINFO, $this->certificateManager->getCertificateBundle());
+
+ $result = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
From dcc4f96d3e368ee976cd085c18dcb74ada3617ce Mon Sep 17 00:00:00 2001
From: Robin Appelman
Date: Thu, 14 Aug 2014 15:47:23 +0200
Subject: [PATCH 03/18] Verify names of certificates
---
apps/files_external/ajax/removeRootCertificate.php | 4 +---
lib/private/certificatemanager.php | 11 ++++++++++-
2 files changed, 11 insertions(+), 4 deletions(-)
diff --git a/apps/files_external/ajax/removeRootCertificate.php b/apps/files_external/ajax/removeRootCertificate.php
index e6795800e0..0931138ad4 100644
--- a/apps/files_external/ajax/removeRootCertificate.php
+++ b/apps/files_external/ajax/removeRootCertificate.php
@@ -6,6 +6,4 @@ OCP\JSON::callCheck();
$name = $_POST['cert'];
$certificateManager = \OC::$server->getCertificateManager();
-if (\OC\Files\Filesystem::isValidPath($name)) {
- $certificateManager->removeCertificate($name);
-}
+$certificateManager->removeCertificate($name);
diff --git a/lib/private/certificatemanager.php b/lib/private/certificatemanager.php
index 72e0541fa4..e07413c127 100644
--- a/lib/private/certificatemanager.php
+++ b/lib/private/certificatemanager.php
@@ -8,10 +8,12 @@
namespace OC;
+use OCP\ICertificateManager;
+
/**
* Manage trusted certificates for users
*/
-class CertificateManager {
+class CertificateManager implements ICertificateManager {
/**
* @var \OCP\IUser
*/
@@ -76,6 +78,9 @@ class CertificateManager {
* @return bool
*/
public function addCertificate($certificate, $name) {
+ if (!\OC\Files\Filesystem::isValidPath($name)) {
+ return false;
+ }
$isValid = openssl_pkey_get_public($certificate);
if (!$isValid) {
@@ -96,8 +101,12 @@ class CertificateManager {
/**
* @param string $name
+ * @return bool
*/
public function removeCertificate($name) {
+ if (!\OC\Files\Filesystem::isValidPath($name)) {
+ return false;
+ }
$path = $this->user->getHome() . '/files_external/uploads/';
if (file_exists($path . $name)) {
unlink($path . $name);
From 4efdbff6dfe20329db145617ed38aa23391b1860 Mon Sep 17 00:00:00 2001
From: Robin Appelman
Date: Thu, 14 Aug 2014 15:47:58 +0200
Subject: [PATCH 04/18] No need for this folder to be world accessible
---
lib/private/certificatemanager.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/private/certificatemanager.php b/lib/private/certificatemanager.php
index e07413c127..3a93494578 100644
--- a/lib/private/certificatemanager.php
+++ b/lib/private/certificatemanager.php
@@ -37,7 +37,7 @@ class CertificateManager implements ICertificateManager {
//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);
+ mkdir($path, 0700, true);
}
$result = array();
$handle = opendir($path);
From 298011bf296a4eda62b787bb7c8fbfe30644d488 Mon Sep 17 00:00:00 2001
From: Robin Appelman
Date: Thu, 14 Aug 2014 15:49:31 +0200
Subject: [PATCH 05/18] fix indention
---
apps/files_sharing/lib/external/storage.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/apps/files_sharing/lib/external/storage.php b/apps/files_sharing/lib/external/storage.php
index b3a8bdcc96..92d8f92b38 100644
--- a/apps/files_sharing/lib/external/storage.php
+++ b/apps/files_sharing/lib/external/storage.php
@@ -200,7 +200,7 @@ class Storage extends DAV implements ISharedStorage {
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($ch, CURLOPT_CAINFO, $this->certificateManager->getCertificateBundle());
- $result = curl_exec($ch);
+ $result = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
From c1b11571ea53748d57241598dec71750637416cd Mon Sep 17 00:00:00 2001
From: Robin Appelman
Date: Fri, 15 Aug 2014 17:18:46 +0200
Subject: [PATCH 06/18] Move certificate management interface from
files_external to core
---
.../ajax/addRootCertificate.php | 25 --
apps/files_external/personal.php | 2 -
apps/files_external/templates/settings.php | 27 ---
lib/private/certificatemanager.php | 10 +-
lib/private/l10n.php | 2 +-
lib/public/icertificatemanager.php | 4 +-
settings/ajax/addRootCertificate.php | 34 +++
.../ajax/removeRootCertificate.php | 0
settings/css/settings.css | 8 +-
settings/js/personal.js | 215 +++++++++++-------
settings/personal.php | 2 +
settings/routes.php | 4 +
settings/templates/personal.php | 41 +++-
13 files changed, 220 insertions(+), 154 deletions(-)
delete mode 100644 apps/files_external/ajax/addRootCertificate.php
create mode 100644 settings/ajax/addRootCertificate.php
rename {apps/files_external => settings}/ajax/removeRootCertificate.php (100%)
diff --git a/apps/files_external/ajax/addRootCertificate.php b/apps/files_external/ajax/addRootCertificate.php
deleted file mode 100644
index 38b1860594..0000000000
--- a/apps/files_external/ajax/addRootCertificate.php
+++ /dev/null
@@ -1,25 +0,0 @@
-getCertificateManager();
-
-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);
-}
-
-header('Location:' . OCP\Util::linkToRoute("settings_personal"));
-exit;
diff --git a/apps/files_external/personal.php b/apps/files_external/personal.php
index 9965303f21..a279163ff7 100755
--- a/apps/files_external/personal.php
+++ b/apps/files_external/personal.php
@@ -23,12 +23,10 @@
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', $certificateManager->listCertificates());
$tmpl->assign('dependencies', OC_Mount_Config::checkDependencies());
$tmpl->assign('backends', $backends);
return $tmpl->fetchPage();
diff --git a/apps/files_external/templates/settings.php b/apps/files_external/templates/settings.php
index dd283f9ff5..072f856dfb 100644
--- a/apps/files_external/templates/settings.php
+++ b/apps/files_external/templates/settings.php
@@ -119,30 +119,3 @@
-
-
-
-
diff --git a/lib/private/certificatemanager.php b/lib/private/certificatemanager.php
index 3a93494578..90a30182c6 100644
--- a/lib/private/certificatemanager.php
+++ b/lib/private/certificatemanager.php
@@ -29,7 +29,7 @@ class CertificateManager implements ICertificateManager {
/**
* Returns all certificates trusted by the user
*
- * @return string[]
+ * @return \OCP\ICertificate[]
*/
public function listCertificates() {
$path = $this->user->getHome() . '/files_external/uploads/';
@@ -45,7 +45,9 @@ class CertificateManager implements ICertificateManager {
return array();
}
while (false !== ($file = readdir($handle))) {
- if ($file != '.' && $file != '..') $result[] = $file;
+ if ($file != '.' && $file != '..') {
+ $result[] = new Certificate(file_get_contents($path . $file), $file);
+ }
}
return $result;
}
@@ -75,7 +77,7 @@ class CertificateManager implements ICertificateManager {
/**
* @param string $certificate the certificate data
* @param string $name the filename for the certificate
- * @return bool
+ * @return bool | \OCP\ICertificate
*/
public function addCertificate($certificate, $name) {
if (!\OC\Files\Filesystem::isValidPath($name)) {
@@ -93,7 +95,7 @@ class CertificateManager implements ICertificateManager {
$file = $this->user->getHome() . '/files_external/uploads/' . $name;
file_put_contents($file, $certificate);
$this->createCertificateBundle();
- return true;
+ return new Certificate($certificate, $name);
} else {
return false;
}
diff --git a/lib/private/l10n.php b/lib/private/l10n.php
index 28b35e92a2..57886a796c 100644
--- a/lib/private/l10n.php
+++ b/lib/private/l10n.php
@@ -354,7 +354,7 @@ class OC_L10N implements \OCP\IL10N {
case 'datetime':
case 'time':
if($data instanceof DateTime) {
- return $data->format($this->localizations[$type]);
+ $data = $data->getTimestamp();
} elseif(is_string($data) && !is_numeric($data)) {
$data = strtotime($data);
}
diff --git a/lib/public/icertificatemanager.php b/lib/public/icertificatemanager.php
index 9ce7d72117..24b8d12363 100644
--- a/lib/public/icertificatemanager.php
+++ b/lib/public/icertificatemanager.php
@@ -15,14 +15,14 @@ interface ICertificateManager {
/**
* Returns all certificates trusted by the user
*
- * @return string[]
+ * @return \OCP\ICertificate[]
*/
public function listCertificates();
/**
* @param string $certificate the certificate data
* @param string $name the filename for the certificate
- * @return bool
+ * @return bool | \OCP\ICertificate
*/
public function addCertificate($certificate, $name);
diff --git a/settings/ajax/addRootCertificate.php b/settings/ajax/addRootCertificate.php
new file mode 100644
index 0000000000..9be8fd0025
--- /dev/null
+++ b/settings/ajax/addRootCertificate.php
@@ -0,0 +1,34 @@
+getCertificateManager();
+
+if ($cert = $certificateManager->addCertificate($data, $filename)) {
+ OCP\JSON::success(array(
+ 'name' => $cert->getName(),
+ 'commonName' => $cert->getCommonName(),
+ 'organization' => $cert->getOrganization(),
+ 'validFrom' => $cert->getIssueDate()->getTimestamp(),
+ 'validTill' => $cert->getExpireDate()->getTimestamp(),
+ 'validFromString' => $l->l('date', $cert->getIssueDate()),
+ 'validTillString' => $l->l('date', $cert->getExpireDate()),
+ 'issuer' => $cert->getIssuerName(),
+ 'issuerOrganization' => $cert->getIssuerOrganization()
+ ));
+} else {
+ OCP\JSON::error(array('error' => 'Couldn\'t import SSL root certificate, allowed formats: PEM and DER'));
+}
diff --git a/apps/files_external/ajax/removeRootCertificate.php b/settings/ajax/removeRootCertificate.php
similarity index 100%
rename from apps/files_external/ajax/removeRootCertificate.php
rename to settings/ajax/removeRootCertificate.php
diff --git a/settings/css/settings.css b/settings/css/settings.css
index a62a971b83..95fab85df9 100644
--- a/settings/css/settings.css
+++ b/settings/css/settings.css
@@ -6,9 +6,11 @@ select#languageinput, select#timezone { width:15em; }
input#openid, input#webdav { width:20em; }
/* PERSONAL */
-#rootcert_import {
- margin: 0 0 10px 0;
- display: block;
+#sslCertificate tr.expired {
+ background-color: rgba(255, 0, 0, 0.5);
+}
+#sslCertificate td {
+ padding: 5px;
}
/* Sync clients */
diff --git a/settings/js/personal.js b/settings/js/personal.js
index f56dd3425f..d6763cdb29 100644
--- a/settings/js/personal.js
+++ b/settings/js/personal.js
@@ -13,12 +13,12 @@
*
* @param callback
*/
-jQuery.fn.keyUpDelayedOrEnter = function(callback){
+jQuery.fn.keyUpDelayedOrEnter = function (callback) {
var cb = callback;
var that = this;
this.keyup(_.debounce(function (event) {
// enter is already handled in keypress
- if(event.keyCode === 13) {
+ if (event.keyCode === 13) {
return;
}
if (that.val() !== '') {
@@ -27,7 +27,7 @@ jQuery.fn.keyUpDelayedOrEnter = function(callback){
}, 1000));
this.keypress(function (event) {
- if (event.keyCode === 13 && that.val() !== '' ){
+ if (event.keyCode === 13 && that.val() !== '') {
event.preventDefault();
cb();
}
@@ -38,48 +38,48 @@ jQuery.fn.keyUpDelayedOrEnter = function(callback){
/**
* Post the email address change to the server.
*/
-function changeEmailAddress(){
- var emailInfo = $('#email');
- if (emailInfo.val() === emailInfo.defaultValue){
- return;
- }
- emailInfo.defaultValue = emailInfo.val();
- OC.msg.startSaving('#lostpassword .msg');
- var post = $( "#lostpassword" ).serialize();
- $.post( 'ajax/lostpassword.php', post, function(data){
- OC.msg.finishedSaving('#lostpassword .msg', data);
- });
+function changeEmailAddress () {
+ var emailInfo = $('#email');
+ if (emailInfo.val() === emailInfo.defaultValue) {
+ return;
+ }
+ emailInfo.defaultValue = emailInfo.val();
+ OC.msg.startSaving('#lostpassword .msg');
+ var post = $("#lostpassword").serialize();
+ $.post('ajax/lostpassword.php', post, function (data) {
+ OC.msg.finishedSaving('#lostpassword .msg', data);
+ });
}
/**
* Post the display name change to the server.
*/
-function changeDisplayName(){
- if ($('#displayName').val() !== '' ) {
- OC.msg.startSaving('#displaynameform .msg');
- // Serialize the data
- var post = $( "#displaynameform" ).serialize();
- // Ajax foo
- $.post( 'ajax/changedisplayname.php', post, function(data){
- if( data.status === "success" ){
- $('#oldDisplayName').val($('#displayName').val());
- // update displayName on the top right expand button
- $('#expandDisplayName').text($('#displayName').val());
- updateAvatar();
- }
- else{
- $('#newdisplayname').val(data.data.displayName);
- }
- OC.msg.finishedSaving('#displaynameform .msg', data);
- });
- }
+function changeDisplayName () {
+ if ($('#displayName').val() !== '') {
+ OC.msg.startSaving('#displaynameform .msg');
+ // Serialize the data
+ var post = $("#displaynameform").serialize();
+ // Ajax foo
+ $.post('ajax/changedisplayname.php', post, function (data) {
+ if (data.status === "success") {
+ $('#oldDisplayName').val($('#displayName').val());
+ // update displayName on the top right expand button
+ $('#expandDisplayName').text($('#displayName').val());
+ updateAvatar();
+ }
+ else {
+ $('#newdisplayname').val(data.data.displayName);
+ }
+ OC.msg.finishedSaving('#displaynameform .msg', data);
+ });
+ }
}
function updateAvatar (hidedefault) {
var $headerdiv = $('#header .avatardiv');
var $displaydiv = $('#displayavatar .avatardiv');
- if(hidedefault) {
+ if (hidedefault) {
$headerdiv.hide();
$('#header .avatardiv').removeClass('avatardiv-shown');
} else {
@@ -93,16 +93,16 @@ function updateAvatar (hidedefault) {
$('#removeavatar').show();
}
-function showAvatarCropper() {
+function showAvatarCropper () {
var $cropper = $('#cropper');
$cropper.prepend("");
var $cropperImage = $('#cropper img');
$cropperImage.attr('src',
- OC.generateUrl('/avatar/tmp')+'?requesttoken='+oc_requesttoken+'#'+Math.floor(Math.random()*1000));
+ OC.generateUrl('/avatar/tmp') + '?requesttoken=' + oc_requesttoken + '#' + Math.floor(Math.random() * 1000));
// Looks weird, but on('load', ...) doesn't work in IE8
- $cropperImage.ready(function(){
+ $cropperImage.ready(function () {
$('#displayavatar').hide();
$cropper.show();
@@ -117,7 +117,7 @@ function showAvatarCropper() {
});
}
-function sendCropData() {
+function sendCropData () {
cleanCropper();
var cropperData = $('#cropper').data();
@@ -130,11 +130,11 @@ function sendCropData() {
$.post(OC.generateUrl('/avatar/cropped'), {crop: data}, avatarResponseHandler);
}
-function saveCoords(c) {
+function saveCoords (c) {
$('#cropper').data(c);
}
-function cleanCropper() {
+function cleanCropper () {
var $cropper = $('#cropper');
$('#displayavatar').show();
$cropper.hide();
@@ -143,7 +143,7 @@ function cleanCropper() {
$('#cropper img').remove();
}
-function avatarResponseHandler(data) {
+function avatarResponseHandler (data) {
var $warning = $('#avatar .warning');
$warning.hide();
if (data.status === "success") {
@@ -156,20 +156,20 @@ function avatarResponseHandler(data) {
}
}
-$(document).ready(function(){
- $("#passwordbutton").click( function(){
+$(document).ready(function () {
+ $("#passwordbutton").click(function () {
if ($('#pass1').val() !== '' && $('#pass2').val() !== '') {
// Serialize the data
- var post = $( "#passwordform" ).serialize();
+ var post = $("#passwordform").serialize();
$('#passwordchanged').hide();
$('#passworderror').hide();
// Ajax foo
- $.post(OC.generateUrl('/settings/personal/changepassword'), post, function(data){
- if( data.status === "success" ){
+ $.post(OC.generateUrl('/settings/personal/changepassword'), post, function (data) {
+ if (data.status === "success") {
$('#pass1').val('');
$('#pass2').val('');
$('#passwordchanged').show();
- } else{
+ } else {
if (typeof(data.data) !== "undefined") {
$('#passworderror').html(data.data.message);
} else {
@@ -190,22 +190,22 @@ $(document).ready(function(){
$('#displayName').keyUpDelayedOrEnter(changeDisplayName);
$('#email').keyUpDelayedOrEnter(changeEmailAddress);
- $("#languageinput").change( function(){
+ $("#languageinput").change(function () {
// Serialize the data
- var post = $( "#languageinput" ).serialize();
+ var post = $("#languageinput").serialize();
// Ajax foo
- $.post( 'ajax/setlanguage.php', post, function(data){
- if( data.status === "success" ){
+ $.post('ajax/setlanguage.php', post, function (data) {
+ if (data.status === "success") {
location.reload();
}
- else{
- $('#passworderror').html( data.data.message );
+ else {
+ $('#passworderror').html(data.data.message);
}
});
return false;
});
- $('button:button[name="submitDecryptAll"]').click(function() {
+ $('button:button[name="submitDecryptAll"]').click(function () {
var privateKeyPassword = $('#decryptAll input:password[id="privateKeyPassword"]').val();
$('#decryptAll button:button[name="submitDecryptAll"]').prop("disabled", true);
$('#decryptAll input:password[name="privateKeyPassword"]').prop("disabled", true);
@@ -213,23 +213,23 @@ $(document).ready(function(){
});
- $('button:button[name="submitRestoreKeys"]').click(function() {
+ $('button:button[name="submitRestoreKeys"]').click(function () {
$('#restoreBackupKeys button:button[name="submitDeleteKeys"]').prop("disabled", true);
$('#restoreBackupKeys button:button[name="submitRestoreKeys"]').prop("disabled", true);
OC.Encryption.restoreKeys();
});
- $('button:button[name="submitDeleteKeys"]').click(function() {
+ $('button:button[name="submitDeleteKeys"]').click(function () {
$('#restoreBackupKeys button:button[name="submitDeleteKeys"]').prop("disabled", true);
$('#restoreBackupKeys button:button[name="submitRestoreKeys"]').prop("disabled", true);
OC.Encryption.deleteKeys();
});
- $('#decryptAll input:password[name="privateKeyPassword"]').keyup(function(event) {
+ $('#decryptAll input:password[name="privateKeyPassword"]').keyup(function (event) {
var privateKeyPassword = $('#decryptAll input:password[id="privateKeyPassword"]').val();
- if (privateKeyPassword !== '' ) {
+ if (privateKeyPassword !== '') {
$('#decryptAll button:button[name="submitDecryptAll"]').prop("disabled", false);
- if(event.which === 13) {
+ if (event.which === 13) {
$('#decryptAll button:button[name="submitDecryptAll"]').prop("disabled", true);
$('#decryptAll input:password[name="privateKeyPassword"]').prop("disabled", true);
OC.Encryption.decryptAll(privateKeyPassword);
@@ -240,21 +240,21 @@ $(document).ready(function(){
});
var uploadparms = {
- done: function(e, data) {
+ done: function (e, data) {
avatarResponseHandler(data.result);
}
};
- $('#uploadavatarbutton').click(function(){
+ $('#uploadavatarbutton').click(function () {
$('#uploadavatar').click();
});
$('#uploadavatar').fileupload(uploadparms);
- $('#selectavatar').click(function(){
+ $('#selectavatar').click(function () {
OC.dialogs.filepicker(
t('settings', "Select a profile picture"),
- function(path){
+ function (path) {
$.post(OC.generateUrl('/avatar/'), {path: path}, avatarResponseHandler);
},
false,
@@ -262,27 +262,27 @@ $(document).ready(function(){
);
});
- $('#removeavatar').click(function(){
+ $('#removeavatar').click(function () {
$.ajax({
- type: 'DELETE',
- url: OC.generateUrl('/avatar/'),
- success: function() {
+ type: 'DELETE',
+ url: OC.generateUrl('/avatar/'),
+ success: function () {
updateAvatar(true);
$('#removeavatar').hide();
}
});
});
- $('#abortcropperbutton').click(function(){
+ $('#abortcropperbutton').click(function () {
cleanCropper();
});
- $('#sendcropperbutton').click(function(){
+ $('#sendcropperbutton').click(function () {
sendCropData();
});
$('#pass2').strengthify({
- zxcvbn: OC.linkTo('3rdparty','zxcvbn/js/zxcvbn.js'),
+ zxcvbn: OC.linkTo('3rdparty', 'zxcvbn/js/zxcvbn.js'),
titles: [
t('core', 'Very weak password'),
t('core', 'Weak password'),
@@ -298,18 +298,59 @@ $(document).ready(function(){
'/avatar/{user}/{size}',
{user: OC.currentUser, size: 1}
) + '?requesttoken=' + oc_requesttoken;
- $.get(url, function(result) {
+ $.get(url, function (result) {
if (typeof(result) === 'object') {
$('#removeavatar').hide();
}
});
-} );
+
+ $('#sslCertificate').on('click', 'td.remove > img', function () {
+ var row = $(this).parent().parent();
+ $.post(OC.filePath('settings', 'ajax', 'removeRootCertificate.php'), {
+ cert: row.data('name')
+ });
+ row.remove();
+ return true;
+ });
+
+ $('#sslCertificate tr > td').tipsy({fade: true, gravity: 'n', live: true});
+
+ $('#rootcert_import').fileupload({
+ done: function (e, data) {
+ console.log(data.result);
+ var issueDate = new Date(data.result.validFrom * 1000);
+ var expireDate = new Date(data.result.validTill * 1000);
+ var now = new Date();
+ var isExpired = !(issueDate <= now && now <= expireDate);
+
+ var row = $('
');
+ row.addClass(isExpired? 'expired': 'valid');
+ row.append($(' | ').attr('title', data.result.organization).text(data.result.commonName));
+ row.append($(' | ').attr('title', t('core,', 'Valid from {date}', {date: data.result.validFromString}))
+ .text(data.result.validTillString));
+ row.append($(' | ').attr('title', data.result.issuerOrganization).text(data.result.issuer));
+ row.append($(' | ').addClass('remove').append(
+ $('').attr({
+ alt: t('core', 'Delete'),
+ title: t('core', 'Delete'),
+ src: OC.imagePath('core', 'actions/delete.svg')
+ }).addClass('action')
+ ));
+
+ $('#sslCertificate tbody').append(row);
+ }
+ });
+
+ $('#rootcert_import_button').click(function () {
+ $('#rootcert_import').click();
+ });
+});
OC.Encryption = {
- decryptAll: function(password) {
+ decryptAll: function (password) {
var message = t('settings', 'Decrypting files... Please wait, this can take some time.');
OC.Encryption.msg.start('#decryptAll .msg', message);
- $.post('ajax/decryptall.php', {password:password}, function(data) {
+ $.post('ajax/decryptall.php', {password: password}, function (data) {
if (data.status === "error") {
OC.Encryption.msg.finished('#decryptAll .msg', data);
$('#decryptAll input:password[name="privateKeyPassword"]').prop("disabled", false);
@@ -320,10 +361,10 @@ OC.Encryption = {
});
},
- deleteKeys: function() {
+ deleteKeys: function () {
var message = t('settings', 'Delete encryption keys permanently.');
OC.Encryption.msg.start('#restoreBackupKeys .msg', message);
- $.post('ajax/deletekeys.php', null, function(data) {
+ $.post('ajax/deletekeys.php', null, function (data) {
if (data.status === "error") {
OC.Encryption.msg.finished('#restoreBackupKeys .msg', data);
$('#restoreBackupKeys button:button[name="submitDeleteKeys"]').prop("disabled", false);
@@ -334,10 +375,10 @@ OC.Encryption = {
});
},
- restoreKeys: function() {
+ restoreKeys: function () {
var message = t('settings', 'Restore encryption keys.');
OC.Encryption.msg.start('#restoreBackupKeys .msg', message);
- $.post('ajax/restorekeys.php', {}, function(data) {
+ $.post('ajax/restorekeys.php', {}, function (data) {
if (data.status === "error") {
OC.Encryption.msg.finished('#restoreBackupKeys .msg', data);
$('#restoreBackupKeys button:button[name="submitDeleteKeys"]').prop("disabled", false);
@@ -349,24 +390,24 @@ OC.Encryption = {
}
};
-OC.Encryption.msg={
- start:function(selector, msg){
- var spinner = '';
+OC.Encryption.msg = {
+ start: function (selector, msg) {
+ var spinner = '';
$(selector)
- .html( msg + ' ' + spinner )
+ .html(msg + ' ' + spinner)
.removeClass('success')
.removeClass('error')
.stop(true, true)
.show();
},
- finished:function(selector, data){
- if( data.status === "success" ){
- $(selector).html( data.data.message )
+ finished: function (selector, data) {
+ if (data.status === "success") {
+ $(selector).html(data.data.message)
.addClass('success')
.stop(true, true)
.delay(3000);
- }else{
- $(selector).html( data.data.message ).addClass('error');
+ } else {
+ $(selector).html(data.data.message).addClass('error');
}
}
};
diff --git a/settings/personal.php b/settings/personal.php
index a72b293413..d426fd7f35 100644
--- a/settings/personal.php
+++ b/settings/personal.php
@@ -8,6 +8,7 @@
OC_Util::checkLoggedIn();
$defaults = new OC_Defaults(); // initialize themable default strings and urls
+$certificateManager = \OC::$server->getCertificateManager();
// Highlight navigation entry
OC_Util::addScript( 'settings', 'personal' );
@@ -98,6 +99,7 @@ $tmpl->assign('backupKeysExists' , $backupKeysExists);
$tmpl->assign('filesStillEncrypted' , $filesStillEncrypted);
$tmpl->assign('enableAvatars', \OC_Config::getValue('enable_avatars', true));
$tmpl->assign('avatarChangeSupported', OC_User::canUserChangeAvatar(OC_User::getUser()));
+$tmpl->assign('certs', $certificateManager->listCertificates());
$forms=OC_App::getForms('personal');
$tmpl->assign('forms', array());
diff --git a/settings/routes.php b/settings/routes.php
index 1c8ad1b3fe..c7bab409d4 100644
--- a/settings/routes.php
+++ b/settings/routes.php
@@ -62,6 +62,10 @@ $this->create('settings_ajax_restorekeys', '/settings/ajax/restorekeys.php')
->actionInclude('settings/ajax/restorekeys.php');
$this->create('settings_ajax_deletekeys', '/settings/ajax/deletekeys.php')
->actionInclude('settings/ajax/deletekeys.php');
+$this->create('core_cert_post', '/settings/ajax/addRootCertificate.php')
+ ->actionInclude('settings/ajax/addRootCertificate.php');
+$this->create('core_cert_remove', '/settings/ajax/removeRootCertificate.php')
+ ->actionInclude('settings/ajax/removeRootCertificate.php');
// apps
$this->create('settings_ajax_apps_ocs', '/settings/ajax/apps/ocs.php')
->actionInclude('settings/ajax/apps/ocs.php');
diff --git a/settings/templates/personal.php b/settings/templates/personal.php
index c1fb20dce0..6d07b89954 100644
--- a/settings/templates/personal.php
+++ b/settings/templates/personal.php
@@ -150,6 +150,44 @@ if($_['passwordChangeSupported']) {
print_unescaped($form);
};?>
+
+
t('SSL root certificates')); ?>
+
+
+ t('Common Name')); ?> |
+ t('Valid until')); ?> |
+ t('Issued By')); ?> |
+ |
+
+
+
+
+
+ getCommonName()) ?>
+ |
+
+ l('date', $rootCert->getExpireDate()) ?>
+ |
+
+ getIssuerName()) ?>
+ |
+ class="remove"
+ style="visibility:hidden;"
+ >
+ |
+
+
+
+
+
+
+
@@ -177,11 +215,8 @@ if($_['passwordChangeSupported']) {
-
-
-
>
t( "Your encryption keys are moved to a backup location. If something went wrong you can restore the keys. Only delete them permanently if you are sure that all files are decrypted correctly." )); ?>
From c158db72000f0d92c0852abad313e254c4b7fc2e Mon Sep 17 00:00:00 2001
From: Robin Appelman
Date: Fri, 15 Aug 2014 19:54:03 +0200
Subject: [PATCH 07/18] Add certificate class
---
lib/private/certificate.php | 116 ++++++++++++++++++++++++++++++++++++
lib/public/icertificate.php | 56 +++++++++++++++++
2 files changed, 172 insertions(+)
create mode 100644 lib/private/certificate.php
create mode 100644 lib/public/icertificate.php
diff --git a/lib/private/certificate.php b/lib/private/certificate.php
new file mode 100644
index 0000000000..294722bc66
--- /dev/null
+++ b/lib/private/certificate.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;
+
+use OCP\ICertificate;
+
+class Certificate implements ICertificate {
+ protected $name;
+
+ protected $commonName;
+
+ protected $organization;
+
+ protected $serial;
+
+ protected $issueDate;
+
+ protected $expireDate;
+
+ protected $issuerName;
+
+ protected $issuerOrganization;
+
+ public function __construct($data, $name) {
+ $this->name = $name;
+ $info = openssl_x509_parse($data);
+ $this->commonName = $info['subject']['CN'];
+ $this->organization = isset($info['subject']['O']) ? $info['subject']['O'] : null;
+ $this->serial = $this->formatSerial($info['serialNumber']);
+ $this->issueDate = new \DateTime('@' . $info['validFrom_time_t']);
+ $this->expireDate = new \DateTime('@' . $info['validTo_time_t']);
+ $this->issuerName = $info['issuer']['CN'];
+ $this->issuerOrganization = isset($info['issuer']['O']) ? $info['issuer']['O'] : null;
+ }
+
+ /**
+ * Format the numeric serial into AA:BB:CC hex format
+ *
+ * @param int $serial
+ * @return string
+ */
+ protected function formatSerial($serial) {
+ $hex = strtoupper(dechex($serial));
+ return trim(chunk_split($hex, 2, ':'), ':');
+ }
+
+ /**
+ * @return string
+ */
+ public function getName() {
+ return $this->name;
+ }
+
+ /**
+ * @return string
+ */
+ public function getCommonName() {
+ return $this->commonName;
+ }
+
+ /**
+ * @return string
+ */
+ public function getOrganization() {
+ return $this->organization;
+ }
+
+ /**
+ * @return string
+ */
+ public function getSerial() {
+ return $this->getSerial();
+ }
+
+ /**
+ * @return \DateTime
+ */
+ public function getIssueDate() {
+ return $this->issueDate;
+ }
+
+ /**
+ * @return \DateTime
+ */
+ public function getExpireDate() {
+ return $this->expireDate;
+ }
+
+ /**
+ * @return bool
+ */
+ public function isExpired() {
+ $now = new \DateTime();
+ return !($this->issueDate <= $now and $now <= $this->expireDate);
+ }
+
+ /**
+ * @return string
+ */
+ public function getIssuerName() {
+ return $this->issuerName;
+ }
+
+ /**
+ * @return string
+ */
+ public function getIssuerOrganization() {
+ return $this->issuerOrganization;
+ }
+}
diff --git a/lib/public/icertificate.php b/lib/public/icertificate.php
new file mode 100644
index 0000000000..013496cb37
--- /dev/null
+++ b/lib/public/icertificate.php
@@ -0,0 +1,56 @@
+
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+namespace OCP;
+
+interface ICertificate {
+ /**
+ * @return string
+ */
+ public function getName();
+
+ /**
+ * @return string
+ */
+ public function getCommonName();
+
+ /**
+ * @return string
+ */
+ public function getOrganization();
+
+ /**
+ * @return string
+ */
+ public function getSerial();
+
+ /**
+ * @return \DateTime
+ */
+ public function getIssueDate();
+
+ /**
+ * @return \DateTime
+ */
+ public function getExpireDate();
+
+ /**
+ * @return bool
+ */
+ public function isExpired();
+
+ /**
+ * @return string
+ */
+ public function getIssuerName();
+
+ /**
+ * @return string
+ */
+ public function getIssuerOrganization();
+}
From f135130a7524e0b035a721aa395a60117494f806 Mon Sep 17 00:00:00 2001
From: Robin Appelman
Date: Fri, 15 Aug 2014 19:56:04 +0200
Subject: [PATCH 08/18] remove outdated checks
---
settings/ajax/addRootCertificate.php | 2 --
settings/ajax/removeRootCertificate.php | 2 --
2 files changed, 4 deletions(-)
diff --git a/settings/ajax/addRootCertificate.php b/settings/ajax/addRootCertificate.php
index 9be8fd0025..f055a4066e 100644
--- a/settings/ajax/addRootCertificate.php
+++ b/settings/ajax/addRootCertificate.php
@@ -1,6 +1,4 @@
Date: Mon, 18 Aug 2014 13:43:25 +0200
Subject: [PATCH 09/18] move certificate classes to their own namespace
---
lib/private/{ => certificate}/certificate.php | 4 ++--
lib/private/{ => certificate}/certificatemanager.php | 2 +-
lib/private/server.php | 1 +
3 files changed, 4 insertions(+), 3 deletions(-)
rename lib/private/{ => certificate}/certificate.php (97%)
rename lib/private/{ => certificate}/certificatemanager.php (99%)
diff --git a/lib/private/certificate.php b/lib/private/certificate/certificate.php
similarity index 97%
rename from lib/private/certificate.php
rename to lib/private/certificate/certificate.php
index 294722bc66..801afa7916 100644
--- a/lib/private/certificate.php
+++ b/lib/private/certificate/certificate.php
@@ -6,7 +6,7 @@
* See the COPYING-README file.
*/
-namespace OC;
+namespace OC\Certificate;
use OCP\ICertificate;
@@ -75,7 +75,7 @@ class Certificate implements ICertificate {
* @return string
*/
public function getSerial() {
- return $this->getSerial();
+ return $this->serial;
}
/**
diff --git a/lib/private/certificatemanager.php b/lib/private/certificate/certificatemanager.php
similarity index 99%
rename from lib/private/certificatemanager.php
rename to lib/private/certificate/certificatemanager.php
index 90a30182c6..c6207f057d 100644
--- a/lib/private/certificatemanager.php
+++ b/lib/private/certificate/certificatemanager.php
@@ -6,7 +6,7 @@
* See the COPYING-README file.
*/
-namespace OC;
+namespace OC\Certificate;
use OCP\ICertificateManager;
diff --git a/lib/private/server.php b/lib/private/server.php
index a30571c1e1..311001ce40 100644
--- a/lib/private/server.php
+++ b/lib/private/server.php
@@ -6,6 +6,7 @@ use OC\AppFramework\Http\Request;
use OC\AppFramework\Db\Db;
use OC\AppFramework\Utility\SimpleContainer;
use OC\Cache\UserCache;
+use OC\Certificate\CertificateManager;
use OC\DB\ConnectionWrapper;
use OC\Files\Node\Root;
use OC\Files\View;
From 6044ad0e174a0d3c9db174115df9c8f61fd43dc3 Mon Sep 17 00:00:00 2001
From: Robin Appelman
Date: Mon, 18 Aug 2014 13:57:38 +0200
Subject: [PATCH 10/18] Cleanup certificate code
---
lib/private/certificate/certificate.php | 6 ++++-
.../certificate/certificatemanager.php | 26 ++++++++++++-------
settings/ajax/addRootCertificate.php | 13 +++++-----
3 files changed, 28 insertions(+), 17 deletions(-)
diff --git a/lib/private/certificate/certificate.php b/lib/private/certificate/certificate.php
index 801afa7916..6b4021cf5e 100644
--- a/lib/private/certificate/certificate.php
+++ b/lib/private/certificate/certificate.php
@@ -27,6 +27,10 @@ class Certificate implements ICertificate {
protected $issuerOrganization;
+ /**
+ * @param string $data base64 encoded certificate
+ * @param string $name
+ */
public function __construct($data, $name) {
$this->name = $name;
$info = openssl_x509_parse($data);
@@ -97,7 +101,7 @@ class Certificate implements ICertificate {
*/
public function isExpired() {
$now = new \DateTime();
- return !($this->issueDate <= $now and $now <= $this->expireDate);
+ return $this->issueDate > $now or $now > $this->expireDate;
}
/**
diff --git a/lib/private/certificate/certificatemanager.php b/lib/private/certificate/certificatemanager.php
index c6207f057d..d7180f7f3f 100644
--- a/lib/private/certificate/certificatemanager.php
+++ b/lib/private/certificate/certificatemanager.php
@@ -8,6 +8,7 @@
namespace OC\Certificate;
+use OC\Files\Filesystem;
use OCP\ICertificateManager;
/**
@@ -34,10 +35,7 @@ class CertificateManager implements ICertificateManager {
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, 0700, true);
+ return array();
}
$result = array();
$handle = opendir($path);
@@ -62,9 +60,7 @@ class CertificateManager implements ICertificateManager {
$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);
+ $data = file_get_contents($file);
if (strpos($data, 'BEGIN CERTIFICATE')) {
fwrite($fh_certs, $data);
fwrite($fh_certs, "\r\n");
@@ -75,6 +71,8 @@ class CertificateManager implements ICertificateManager {
}
/**
+ * Save the certificate and re-generate the certificate bundle
+ *
* @param string $certificate the certificate data
* @param string $name the filename for the certificate
* @return bool | \OCP\ICertificate
@@ -92,7 +90,14 @@ class CertificateManager implements ICertificateManager {
}
if ($isValid) {
- $file = $this->user->getHome() . '/files_external/uploads/' . $name;
+ $dir = $this->user->getHome() . '/files_external/uploads/';
+ if (!file_exists($dir)) {
+ //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($dir, 0700, true);
+ }
+ $file = $dir . $name;
file_put_contents($file, $certificate);
$this->createCertificateBundle();
return new Certificate($certificate, $name);
@@ -102,11 +107,13 @@ class CertificateManager implements ICertificateManager {
}
/**
+ * Remove the certificate and re-generate the certificate bundle
+ *
* @param string $name
* @return bool
*/
public function removeCertificate($name) {
- if (!\OC\Files\Filesystem::isValidPath($name)) {
+ if (!Filesystem::isValidPath($name)) {
return false;
}
$path = $this->user->getHome() . '/files_external/uploads/';
@@ -114,6 +121,7 @@ class CertificateManager implements ICertificateManager {
unlink($path . $name);
$this->createCertificateBundle();
}
+ return true;
}
/**
diff --git a/settings/ajax/addRootCertificate.php b/settings/ajax/addRootCertificate.php
index f055a4066e..87b1460ef1 100644
--- a/settings/ajax/addRootCertificate.php
+++ b/settings/ajax/addRootCertificate.php
@@ -3,19 +3,18 @@ OCP\JSON::callCheck();
$l = new OC_L10N('core');
-if (!($filename = $_FILES['rootcert_import']['name'])) {
- header('Location:' . OCP\Util::linkToRoute("settings_personal"));
+if (!isset($_FILES['rootcert_import'])) {
+ OCP\JSON::error(array('error' => 'No certificate uploaded'));
exit;
}
-$fh = fopen($_FILES['rootcert_import']['tmp_name'], 'r');
-$data = fread($fh, filesize($_FILES['rootcert_import']['tmp_name']));
-fclose($fh);
-$filename = $_FILES['rootcert_import']['name'];
+$data = file_get_contents($_FILES['rootcert_import']['tmp_name']);
+$filename = basename($_FILES['rootcert_import']['name']);
$certificateManager = \OC::$server->getCertificateManager();
-if ($cert = $certificateManager->addCertificate($data, $filename)) {
+$cert = $certificateManager->addCertificate($data, $filename);
+if ($cert) {
OCP\JSON::success(array(
'name' => $cert->getName(),
'commonName' => $cert->getCommonName(),
From 79d896e830d9076593e1e5366a52cd0061061fed Mon Sep 17 00:00:00 2001
From: Robin Appelman
Date: Mon, 18 Aug 2014 16:30:23 +0200
Subject: [PATCH 11/18] Rename namespace
---
lib/private/{certificate => security}/certificate.php | 2 +-
lib/private/{certificate => security}/certificatemanager.php | 2 +-
lib/private/server.php | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
rename lib/private/{certificate => security}/certificate.php (98%)
rename lib/private/{certificate => security}/certificatemanager.php (99%)
diff --git a/lib/private/certificate/certificate.php b/lib/private/security/certificate.php
similarity index 98%
rename from lib/private/certificate/certificate.php
rename to lib/private/security/certificate.php
index 6b4021cf5e..953111f469 100644
--- a/lib/private/certificate/certificate.php
+++ b/lib/private/security/certificate.php
@@ -6,7 +6,7 @@
* See the COPYING-README file.
*/
-namespace OC\Certificate;
+namespace OC\Security;
use OCP\ICertificate;
diff --git a/lib/private/certificate/certificatemanager.php b/lib/private/security/certificatemanager.php
similarity index 99%
rename from lib/private/certificate/certificatemanager.php
rename to lib/private/security/certificatemanager.php
index d7180f7f3f..2888fecd23 100644
--- a/lib/private/certificate/certificatemanager.php
+++ b/lib/private/security/certificatemanager.php
@@ -6,7 +6,7 @@
* See the COPYING-README file.
*/
-namespace OC\Certificate;
+namespace OC\Security;
use OC\Files\Filesystem;
use OCP\ICertificateManager;
diff --git a/lib/private/server.php b/lib/private/server.php
index 311001ce40..62ef9bfb61 100644
--- a/lib/private/server.php
+++ b/lib/private/server.php
@@ -6,7 +6,7 @@ use OC\AppFramework\Http\Request;
use OC\AppFramework\Db\Db;
use OC\AppFramework\Utility\SimpleContainer;
use OC\Cache\UserCache;
-use OC\Certificate\CertificateManager;
+use OC\Security\CertificateManager;
use OC\DB\ConnectionWrapper;
use OC\Files\Node\Root;
use OC\Files\View;
From 2fcedcc50382127492ca0bf071e8e1bbe5736b16 Mon Sep 17 00:00:00 2001
From: Robin Appelman
Date: Tue, 19 Aug 2014 16:03:09 +0200
Subject: [PATCH 12/18] fix test
---
apps/files_sharing/tests/externalstorage.php | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/apps/files_sharing/tests/externalstorage.php b/apps/files_sharing/tests/externalstorage.php
index 1258148af5..2e93afa198 100644
--- a/apps/files_sharing/tests/externalstorage.php
+++ b/apps/files_sharing/tests/externalstorage.php
@@ -65,6 +65,7 @@ class Test_Files_Sharing_External_Storage extends \PHPUnit_Framework_TestCase {
* @dataProvider optionsProvider
*/
public function testStorageMountOptions($inputUri, $baseUri) {
+ $certificateManager = \OC::$server->getCertificateManager();
$storage = new TestSharingExternalStorage(
array(
'remote' => $inputUri,
@@ -72,7 +73,8 @@ class Test_Files_Sharing_External_Storage extends \PHPUnit_Framework_TestCase {
'mountpoint' => 'remoteshare',
'token' => 'abcdef',
'password' => '',
- 'manager' => null
+ 'manager' => null,
+ 'certificateManager' => $certificateManager
)
);
$this->assertEquals($baseUri, $storage->getBaseUri());
From e64aa330fdd6ce6180a0ffcf3634dbcae31abfff Mon Sep 17 00:00:00 2001
From: Robin Appelman
Date: Thu, 21 Aug 2014 14:09:40 +0200
Subject: [PATCH 13/18] check for blacklisted file certificate filenames
---
lib/private/security/certificatemanager.php | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lib/private/security/certificatemanager.php b/lib/private/security/certificatemanager.php
index 2888fecd23..64a1d6431a 100644
--- a/lib/private/security/certificatemanager.php
+++ b/lib/private/security/certificatemanager.php
@@ -78,7 +78,7 @@ class CertificateManager implements ICertificateManager {
* @return bool | \OCP\ICertificate
*/
public function addCertificate($certificate, $name) {
- if (!\OC\Files\Filesystem::isValidPath($name)) {
+ if (!Filesystem::isValidPath($name) or Filesystem::isFileBlacklisted($name)) {
return false;
}
$isValid = openssl_pkey_get_public($certificate);
From 1361bbb1e6a47266cf3a11b2ddba77706522d9e0 Mon Sep 17 00:00:00 2001
From: Robin Appelman
Date: Thu, 21 Aug 2014 14:15:43 +0200
Subject: [PATCH 14/18] Cleanup routes
---
settings/js/personal.js | 3 +--
settings/routes.php | 4 ++--
settings/templates/personal.php | 2 +-
3 files changed, 4 insertions(+), 5 deletions(-)
diff --git a/settings/js/personal.js b/settings/js/personal.js
index d6763cdb29..d6546717d1 100644
--- a/settings/js/personal.js
+++ b/settings/js/personal.js
@@ -306,7 +306,7 @@ $(document).ready(function () {
$('#sslCertificate').on('click', 'td.remove > img', function () {
var row = $(this).parent().parent();
- $.post(OC.filePath('settings', 'ajax', 'removeRootCertificate.php'), {
+ $.post(OC.generateUrl('settings/ajax/removeRootCertificate'), {
cert: row.data('name')
});
row.remove();
@@ -317,7 +317,6 @@ $(document).ready(function () {
$('#rootcert_import').fileupload({
done: function (e, data) {
- console.log(data.result);
var issueDate = new Date(data.result.validFrom * 1000);
var expireDate = new Date(data.result.validTill * 1000);
var now = new Date();
diff --git a/settings/routes.php b/settings/routes.php
index c7bab409d4..191b5febbd 100644
--- a/settings/routes.php
+++ b/settings/routes.php
@@ -62,9 +62,9 @@ $this->create('settings_ajax_restorekeys', '/settings/ajax/restorekeys.php')
->actionInclude('settings/ajax/restorekeys.php');
$this->create('settings_ajax_deletekeys', '/settings/ajax/deletekeys.php')
->actionInclude('settings/ajax/deletekeys.php');
-$this->create('core_cert_post', '/settings/ajax/addRootCertificate.php')
+$this->create('settings_cert_post', '/settings/ajax/addRootCertificate')
->actionInclude('settings/ajax/addRootCertificate.php');
-$this->create('core_cert_remove', '/settings/ajax/removeRootCertificate.php')
+$this->create('settings_cert_remove', '/settings/ajax/removeRootCertificate')
->actionInclude('settings/ajax/removeRootCertificate.php');
// apps
$this->create('settings_ajax_apps_ocs', '/settings/ajax/apps/ocs.php')
diff --git a/settings/templates/personal.php b/settings/templates/personal.php
index 6d07b89954..8cb7be2773 100644
--- a/settings/templates/personal.php
+++ b/settings/templates/personal.php
@@ -182,7 +182,7 @@ if($_['passwordChangeSupported']) {
-
From 4efe6f62402482608cb1b2f4c51b9b3e41603733 Mon Sep 17 00:00:00 2001
From: Lukas Reschke
Date: Wed, 27 Aug 2014 16:28:51 +0200
Subject: [PATCH 15/18] Add unit tests and fix rootcerts creation bug
---
lib/private/security/certificate.php | 27 +++---
lib/private/security/certificatemanager.php | 37 ++++----
settings/ajax/addRootCertificate.php | 7 +-
settings/js/personal.js | 2 +-
settings/templates/personal.php | 9 +-
tests/data/certificates/badCertificate.crt | 13 +++
.../data/certificates/expiredCertificate.crt | 13 +++
tests/data/certificates/goodCertificate.crt | 15 ++++
tests/lib/security/certificate.php | 90 +++++++++++++++++++
tests/lib/security/certificatemanager.php | 87 ++++++++++++++++++
10 files changed, 263 insertions(+), 37 deletions(-)
create mode 100644 tests/data/certificates/badCertificate.crt
create mode 100644 tests/data/certificates/expiredCertificate.crt
create mode 100644 tests/data/certificates/goodCertificate.crt
create mode 100644 tests/lib/security/certificate.php
create mode 100644 tests/lib/security/certificatemanager.php
diff --git a/lib/private/security/certificate.php b/lib/private/security/certificate.php
index 953111f469..63c02a124f 100644
--- a/lib/private/security/certificate.php
+++ b/lib/private/security/certificate.php
@@ -30,17 +30,22 @@ class Certificate implements ICertificate {
/**
* @param string $data base64 encoded certificate
* @param string $name
+ * @throws \Exception If the certificate could not get parsed
*/
public function __construct($data, $name) {
$this->name = $name;
- $info = openssl_x509_parse($data);
- $this->commonName = $info['subject']['CN'];
- $this->organization = isset($info['subject']['O']) ? $info['subject']['O'] : null;
- $this->serial = $this->formatSerial($info['serialNumber']);
- $this->issueDate = new \DateTime('@' . $info['validFrom_time_t']);
- $this->expireDate = new \DateTime('@' . $info['validTo_time_t']);
- $this->issuerName = $info['issuer']['CN'];
- $this->issuerOrganization = isset($info['issuer']['O']) ? $info['issuer']['O'] : null;
+ try {
+ $info = openssl_x509_parse($data);
+ $this->commonName = isset($info['subject']['CN']) ? $info['subject']['CN'] : null;
+ $this->organization = isset($info['subject']['O']) ? $info['subject']['O'] : null;
+ $this->serial = $this->formatSerial($info['serialNumber']);
+ $this->issueDate = new \DateTime('@' . $info['validFrom_time_t']);
+ $this->expireDate = new \DateTime('@' . $info['validTo_time_t']);
+ $this->issuerName = isset($info['issuer']['CN']) ? $info['issuer']['CN'] : null;
+ $this->issuerOrganization = isset($info['issuer']['O']) ? $info['issuer']['O'] : null;
+ } catch (\Exception $e) {
+ throw new \Exception('Certificate could not get parsed.');
+ }
}
/**
@@ -62,7 +67,7 @@ class Certificate implements ICertificate {
}
/**
- * @return string
+ * @return string|null
*/
public function getCommonName() {
return $this->commonName;
@@ -105,14 +110,14 @@ class Certificate implements ICertificate {
}
/**
- * @return string
+ * @return string|null
*/
public function getIssuerName() {
return $this->issuerName;
}
/**
- * @return string
+ * @return string|null
*/
public function getIssuerOrganization() {
return $this->issuerOrganization;
diff --git a/lib/private/security/certificatemanager.php b/lib/private/security/certificatemanager.php
index 64a1d6431a..cae9730eb2 100644
--- a/lib/private/security/certificatemanager.php
+++ b/lib/private/security/certificatemanager.php
@@ -44,7 +44,9 @@ class CertificateManager implements ICertificateManager {
}
while (false !== ($file = readdir($handle))) {
if ($file != '.' && $file != '..') {
- $result[] = new Certificate(file_get_contents($path . $file), $file);
+ try {
+ $result[] = new Certificate(file_get_contents($path . $file), $file);
+ } catch(\Exception $e) {}
}
}
return $result;
@@ -59,7 +61,7 @@ class CertificateManager implements ICertificateManager {
$fh_certs = fopen($path . '/rootcerts.crt', 'w');
foreach ($certs as $cert) {
- $file = $path . '/uploads/' . $cert;
+ $file = $path . '/uploads/' . $cert->getName();
$data = file_get_contents($file);
if (strpos($data, 'BEGIN CERTIFICATE')) {
fwrite($fh_certs, $data);
@@ -75,35 +77,32 @@ class CertificateManager implements ICertificateManager {
*
* @param string $certificate the certificate data
* @param string $name the filename for the certificate
- * @return bool | \OCP\ICertificate
+ * @return \OCP\ICertificate|void|bool
+ * @throws \Exception If the certificate could not get added
*/
public function addCertificate($certificate, $name) {
if (!Filesystem::isValidPath($name) or Filesystem::isFileBlacklisted($name)) {
return false;
}
- $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);
+ $dir = $this->user->getHome() . '/files_external/uploads/';
+ if (!file_exists($dir)) {
+ //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($dir, 0700, true);
}
- if ($isValid) {
- $dir = $this->user->getHome() . '/files_external/uploads/';
- if (!file_exists($dir)) {
- //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($dir, 0700, true);
- }
+ try {
$file = $dir . $name;
+ $certificateObject = new Certificate($certificate, $name);
file_put_contents($file, $certificate);
$this->createCertificateBundle();
- return new Certificate($certificate, $name);
- } else {
- return false;
+ return $certificateObject;
+ } catch (\Exception $e) {
+ throw $e;
}
+
}
/**
diff --git a/settings/ajax/addRootCertificate.php b/settings/ajax/addRootCertificate.php
index 87b1460ef1..378ef39c1e 100644
--- a/settings/ajax/addRootCertificate.php
+++ b/settings/ajax/addRootCertificate.php
@@ -1,4 +1,5 @@
getCertificateManager();
-$cert = $certificateManager->addCertificate($data, $filename);
-if ($cert) {
+try {
+ $cert = $certificateManager->addCertificate($data, $filename);
OCP\JSON::success(array(
'name' => $cert->getName(),
'commonName' => $cert->getCommonName(),
@@ -26,6 +27,6 @@ if ($cert) {
'issuer' => $cert->getIssuerName(),
'issuerOrganization' => $cert->getIssuerOrganization()
));
-} else {
+} catch(\Exception $e) {
OCP\JSON::error(array('error' => 'Couldn\'t import SSL root certificate, allowed formats: PEM and DER'));
}
diff --git a/settings/js/personal.js b/settings/js/personal.js
index d6546717d1..11e9593d74 100644
--- a/settings/js/personal.js
+++ b/settings/js/personal.js
@@ -325,7 +325,7 @@ $(document).ready(function () {
var row = $('
');
row.addClass(isExpired? 'expired': 'valid');
row.append($(' | ').attr('title', data.result.organization).text(data.result.commonName));
- row.append($(' | ').attr('title', t('core,', 'Valid from {date}', {date: data.result.validFromString}))
+ row.append($(' | ').attr('title', t('core,', 'Valid until {date}', {date: data.result.validFromString}))
.text(data.result.validTillString));
row.append($(' | ').attr('title', data.result.issuerOrganization).text(data.result.issuer));
row.append($(' | ').addClass('remove').append(
diff --git a/settings/templates/personal.php b/settings/templates/personal.php
index 8cb7be2773..871a0ec9e3 100644
--- a/settings/templates/personal.php
+++ b/settings/templates/personal.php
@@ -2,7 +2,10 @@
* Copyright (c) 2011, Robin Appelman
* This file is licensed under the Affero General Public License version 3 or later.
* See the COPYING-README file.
- */?>
+ */
+
+/** @var $_ array */
+?>
t('Get the apps to sync your files'));?>
@@ -160,12 +163,12 @@ if($_['passwordChangeSupported']) {
|
-
+
getCommonName()) ?>
|
-
+ |
l('date', $rootCert->getExpireDate()) ?>
|
diff --git a/tests/data/certificates/badCertificate.crt b/tests/data/certificates/badCertificate.crt
new file mode 100644
index 0000000000..dcb1895fba
--- /dev/null
+++ b/tests/data/certificates/badCertificate.crt
@@ -0,0 +1,13 @@
+-----BEGIN CERTIFICATE-----
+MIICATCCAWoCCQDNdmb4pJrUeDANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJB
+VTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0
+cyBQdHkgTHRkMB4XDTE0MDgyNzA4NDg1MVoXDTE1MDgyNzA4NDg1MVowRTELMAkG
+A1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0
+IFdpZGdpdHMgUHR5IEx0ZDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAvrMe
+x5D45HVMV2U4kqTU0mzHAihHT6r+OtO6g7S9yIlJZGGVcEet6An78Ow7aYM141eI
+Jfbvqql7OIblHXSw7mvkw4bOQ1ee5lmJYOYCgaMNJ6mBLJfpK9xwidb0ZvhWOA8P
+DLIiBKA3T5ChXCzilD5GF2+H/BXBE9lL9tuDjM0CAwEAATANBgkqhkiG9w0BAQUF
+AAOBgQCJwfJe7j+aNkopw+P8uxobfOnMWU9XC4Pu+39TVLeakeSqu2Y8vJSHmkjF
+WK3VXAJr33Eul5VP/3SWGwuRPd9X4i4iLh1gJfYvi9MJf1lQNYncGCM+xtdrNu2O
+u0yexkOBRrapDYjcv58BiOaFgvFLquKvtVj9HlcYRfwfM77uKQ==
+-----END CERTIFICATE-----
\ No newline at end of file
diff --git a/tests/data/certificates/expiredCertificate.crt b/tests/data/certificates/expiredCertificate.crt
new file mode 100644
index 0000000000..5e7e5df2cb
--- /dev/null
+++ b/tests/data/certificates/expiredCertificate.crt
@@ -0,0 +1,13 @@
+-----BEGIN CERTIFICATE-----
+MIICATCCAWoCCQCjCIB6tCZ2sDANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJB
+VTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0
+cyBQdHkgTHRkMB4XDTE0MDgyNzA5MTI0M1oXDTE0MDgyODA5MTI0M1owRTELMAkG
+A1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0
+IFdpZGdpdHMgUHR5IEx0ZDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAvrMe
+x5D45HVMV2U4kqTU0mzHAihHT6r+OtO6g7S9yIlJZGGVcEet6An78Ow7aYM141eI
+Jfbvqql7OIblHXSw7mvkw4bOQ1ee5lmJYOYCgaMNJ6mBLJfpK9xwidb0ZvhWOA8P
+DLIiBKA3T5ChXCzilD5GF2+H/BXBE9lL9tuDjM0CAwEAATANBgkqhkiG9w0BAQUF
+AAOBgQBuNClmOj3wudlX86nygcZgQT2+ZS8f1iJgM9lbrrkenT6tgcT1/YjcrN9C
+BZR29Wz7htflpqverLUGZXh72K+gYercyR16Zu7zjt/NWuZldZmzJ3bUGq2HSoCX
+2sDykAEuaDxUlzdJrztlOH4vPlRaGbxUogpC2hB1BQfxA90CIA==
+-----END CERTIFICATE-----
\ No newline at end of file
diff --git a/tests/data/certificates/goodCertificate.crt b/tests/data/certificates/goodCertificate.crt
new file mode 100644
index 0000000000..4a5d7bd32f
--- /dev/null
+++ b/tests/data/certificates/goodCertificate.crt
@@ -0,0 +1,15 @@
+-----BEGIN CERTIFICATE-----
+MIICazCCAdQCCQCySF7HjQD78DANBgkqhkiG9w0BAQUFADB6MQswCQYDVQQGEwJD
+SDEPMA0GA1UECBMGWnVyaWNoMQ8wDQYDVQQHEwZadXJpY2gxFjAUBgNVBAoTDW93
+bkNsb3VkIEluYy4xETAPBgNVBAsTCFNlY3VyaXR5MR4wHAYDVQQDExVzZWN1cml0
+eS5vd25jbG91ZC5jb20wHhcNMTQwODI3MDg0NTUyWhcNMTUwODI3MDg0NTUyWjB6
+MQswCQYDVQQGEwJDSDEPMA0GA1UECBMGWnVyaWNoMQ8wDQYDVQQHEwZadXJpY2gx
+FjAUBgNVBAoTDW93bkNsb3VkIEluYy4xETAPBgNVBAsTCFNlY3VyaXR5MR4wHAYD
+VQQDExVzZWN1cml0eS5vd25jbG91ZC5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0A
+MIGJAoGBAL55lB4RvU0pTyh7YsLCxPBq43xxkRZBxfZENoflCIUsBo7/mXNz2zVO
+476oQ4L47heUOX3j8kemOgPmWEqA34JB8rusijCy5WqFBLnm4HsRLa66i+Jgd+Yl
+QhcKvhGas1K/CVTG4oSLoAmA2coZUL94uxnRtd8aluflHMNGApIlAgMBAAEwDQYJ
+KoZIhvcNAQEFBQADgYEADo08zWdOtIvCKFDnLbzRwIjSYTlAtQtQaULv7KQe3qIn
+iaFAi6fAynHfdC8/2tvmSeniw0OZBkrfVGIVtUbwCSrljNSUY/lWrUR0pE61lb4r
+DpX0JZjlk48XEaErRVDfu3wq6n/2nYg6HnaLOPwt8OSYYrxzvXlFPrKBH3q6R+M=
+-----END CERTIFICATE-----
\ No newline at end of file
diff --git a/tests/lib/security/certificate.php b/tests/lib/security/certificate.php
new file mode 100644
index 0000000000..694d1f2701
--- /dev/null
+++ b/tests/lib/security/certificate.php
@@ -0,0 +1,90 @@
+
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+*/
+
+use \OC\Security\Certificate;
+
+class CertificateTest extends \PHPUnit_Framework_TestCase {
+
+ /** @var Certificate That contains a valid certificate */
+ protected $goodCertificate;
+ /** @var Certificate That contains an invalid certificate */
+ protected $invalidCertificate;
+ /** @var Certificate That contains an expired certificate */
+ protected $expiredCertificate;
+
+ function setUp() {
+ $goodCertificate = file_get_contents(__DIR__.'/../../data/certificates/goodCertificate.crt');
+ $this->goodCertificate = new Certificate($goodCertificate, 'GoodCertificate');
+ $badCertificate = file_get_contents(__DIR__.'/../../data/certificates/badCertificate.crt');
+ $this->invalidCertificate = new Certificate($badCertificate, 'BadCertificate');
+ $expiredCertificate = file_get_contents(__DIR__.'/../../data/certificates/expiredCertificate.crt');
+ $this->expiredCertificate = new Certificate($expiredCertificate, 'ExpiredCertificate');
+ }
+
+ /**
+ * @expectedException \Exception
+ * @expectedExceptionMessage Certificate could not get parsed.
+ */
+ function testBogusData() {
+ new Certificate('foo', 'bar');
+ }
+
+ function testGetName() {
+ $this->assertSame('GoodCertificate', $this->goodCertificate->getName());
+ $this->assertSame('BadCertificate', $this->invalidCertificate->getName());
+ }
+
+ function testGetCommonName() {
+ $this->assertSame('security.owncloud.com', $this->goodCertificate->getCommonName());
+ $this->assertSame(null, $this->invalidCertificate->getCommonName());
+ }
+
+ function testGetOrganization() {
+ $this->assertSame('ownCloud Inc.', $this->goodCertificate->getOrganization());
+ $this->assertSame('Internet Widgits Pty Ltd', $this->invalidCertificate->getOrganization());
+ }
+
+ function testGetSerial() {
+ $this->assertSame('7F:FF:FF:FF:FF:FF:FF:FF', $this->goodCertificate->getSerial());
+ $this->assertSame('7F:FF:FF:FF:FF:FF:FF:FF', $this->invalidCertificate->getSerial());
+ }
+
+ function testGetIssueDate() {
+ $this->assertEquals(new DateTime('2014-08-27 08:45:52'), $this->goodCertificate->getIssueDate());
+ $this->assertEquals(new DateTime('2014-08-27 08:48:51'), $this->invalidCertificate->getIssueDate());
+ }
+
+ function testGetExpireDate() {
+ $this->assertEquals(new DateTime('2015-08-27 08:45:52'), $this->goodCertificate->getExpireDate());
+ $this->assertEquals(new DateTime('2015-08-27 08:48:51'), $this->invalidCertificate->getExpireDate());
+ $this->assertEquals(new DateTime('2014-08-28 09:12:43'), $this->expiredCertificate->getExpireDate());
+ }
+
+ /**
+ * Obviously the following test case might fail after 2015-08-27, just create a new certificate with longer validity then
+ */
+ function testIsExpired() {
+ $this->assertSame(false, $this->goodCertificate->isExpired());
+ $this->assertSame(false, $this->invalidCertificate->isExpired());
+
+ // TODO: Change to false after tomorrow
+ $this->assertSame(false, $this->expiredCertificate->isExpired());
+ }
+
+ function testGetIssuerName() {
+ $this->assertSame('security.owncloud.com', $this->goodCertificate->getIssuerName());
+ $this->assertSame(null, $this->invalidCertificate->getIssuerName());
+ $this->assertSame(null, $this->expiredCertificate->getIssuerName());
+ }
+
+ function testGetIssuerOrganization() {
+ $this->assertSame('ownCloud Inc.', $this->goodCertificate->getIssuerOrganization());
+ $this->assertSame('Internet Widgits Pty Ltd', $this->invalidCertificate->getIssuerOrganization());
+ $this->assertSame('Internet Widgits Pty Ltd', $this->expiredCertificate->getIssuerOrganization());
+ }
+}
\ No newline at end of file
diff --git a/tests/lib/security/certificatemanager.php b/tests/lib/security/certificatemanager.php
new file mode 100644
index 0000000000..5baf9e16e8
--- /dev/null
+++ b/tests/lib/security/certificatemanager.php
@@ -0,0 +1,87 @@
+
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+use \OC\Security\CertificateManager;
+
+class CertificateManagerTest extends \PHPUnit_Framework_TestCase {
+
+ /** @var CertificateManager */
+ private $certificateManager;
+ /** @var String */
+ private $username;
+ /** @var \OC\User\User */
+ private $user;
+
+ function setUp() {
+ $this->username = OC_Util::generateRandomBytes(20);
+ OC_User::createUser($this->username, OC_Util::generateRandomBytes(20));
+
+ \OC_Util::tearDownFS();
+ \OC_User::setUserId('');
+ \OC\Files\Filesystem::tearDown();
+ \OC_Util::setupFS($this->username);
+
+ $this->user = \OC::$server->getUserManager()->get($this->username);
+
+ $this->certificateManager = new CertificateManager($this->user);
+ }
+
+ function tearDown() {
+ \OC_User::deleteUser($this->username);
+ }
+
+ protected function assertEqualsArrays($expected, $actual) {
+ sort($expected);
+ sort($actual);
+
+ $this->assertEquals($expected, $actual);
+ }
+
+ function testListCertificates() {
+ // Test empty certificate bundle
+ $this->assertSame(array(), $this->certificateManager->listCertificates());
+
+ // Add some certificates
+ $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');
+ $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->assertEqualsArrays($certificateStore, $this->certificateManager->listCertificates());
+ }
+
+ /**
+ * @expectedException \Exception
+ * @expectedExceptionMessage Certificate could not get parsed.
+ */
+ function testAddInvalidCertificate() {
+ $this->certificateManager->addCertificate('InvalidCertificate', 'invalidCertificate');
+ }
+
+ function testAddDangerousFile() {
+ $this->assertFalse($this->certificateManager->addCertificate(file_get_contents(__DIR__.'/../../data/certificates/expiredCertificate.crt'), '.htaccess'));
+ $this->assertFalse($this->certificateManager->addCertificate(file_get_contents(__DIR__.'/../../data/certificates/expiredCertificate.crt'), '../../foo.txt'));
+ }
+
+ function testRemoveDangerousFile() {
+ $this->assertFalse($this->certificateManager->removeCertificate('../../foo.txt'));
+ }
+
+ function testRemoveExistingFile() {
+ $this->certificateManager->addCertificate(file_get_contents(__DIR__.'/../../data/certificates/goodCertificate.crt'), 'GoodCertificate');
+ $this->assertTrue($this->certificateManager->removeCertificate('GoodCertificate'));
+ }
+
+ function testGetCertificateBundle() {
+ $this->assertSame($this->user->getHome().'/files_external/rootcerts.crt', $this->certificateManager->getCertificateBundle());
+ }
+
+}
\ No newline at end of file
From 4bc9980f4be1ed9834768b613af6a6e43dc83556 Mon Sep 17 00:00:00 2001
From: Lukas Reschke
Date: Wed, 27 Aug 2014 16:29:42 +0200
Subject: [PATCH 16/18] Add test for expired certificate
Will only work after tomorrow
---
tests/lib/security/certificate.php | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/tests/lib/security/certificate.php b/tests/lib/security/certificate.php
index 694d1f2701..9ae68f2cf1 100644
--- a/tests/lib/security/certificate.php
+++ b/tests/lib/security/certificate.php
@@ -71,9 +71,7 @@ class CertificateTest extends \PHPUnit_Framework_TestCase {
function testIsExpired() {
$this->assertSame(false, $this->goodCertificate->isExpired());
$this->assertSame(false, $this->invalidCertificate->isExpired());
-
- // TODO: Change to false after tomorrow
- $this->assertSame(false, $this->expiredCertificate->isExpired());
+ $this->assertSame(true, $this->expiredCertificate->isExpired());
}
function testGetIssuerName() {
From bfa0c4b78a977726971f7b48e8f921b8adb56e8b Mon Sep 17 00:00:00 2001
From: Robin Appelman
Date: Sun, 31 Aug 2014 11:06:18 +0200
Subject: [PATCH 17/18] Explicitly set the timezones
---
lib/private/security/certificate.php | 5 +++--
tests/lib/security/certificate.php | 12 ++++++------
2 files changed, 9 insertions(+), 8 deletions(-)
diff --git a/lib/private/security/certificate.php b/lib/private/security/certificate.php
index 63c02a124f..778524507e 100644
--- a/lib/private/security/certificate.php
+++ b/lib/private/security/certificate.php
@@ -35,12 +35,13 @@ class Certificate implements ICertificate {
public function __construct($data, $name) {
$this->name = $name;
try {
+ $gmt = new \DateTimeZone('GMT');
$info = openssl_x509_parse($data);
$this->commonName = isset($info['subject']['CN']) ? $info['subject']['CN'] : null;
$this->organization = isset($info['subject']['O']) ? $info['subject']['O'] : null;
$this->serial = $this->formatSerial($info['serialNumber']);
- $this->issueDate = new \DateTime('@' . $info['validFrom_time_t']);
- $this->expireDate = new \DateTime('@' . $info['validTo_time_t']);
+ $this->issueDate = new \DateTime('@' . $info['validFrom_time_t'], $gmt);
+ $this->expireDate = new \DateTime('@' . $info['validTo_time_t'], $gmt);
$this->issuerName = isset($info['issuer']['CN']) ? $info['issuer']['CN'] : null;
$this->issuerOrganization = isset($info['issuer']['O']) ? $info['issuer']['O'] : null;
} catch (\Exception $e) {
diff --git a/tests/lib/security/certificate.php b/tests/lib/security/certificate.php
index 9ae68f2cf1..41c8a74b83 100644
--- a/tests/lib/security/certificate.php
+++ b/tests/lib/security/certificate.php
@@ -55,14 +55,14 @@ class CertificateTest extends \PHPUnit_Framework_TestCase {
}
function testGetIssueDate() {
- $this->assertEquals(new DateTime('2014-08-27 08:45:52'), $this->goodCertificate->getIssueDate());
- $this->assertEquals(new DateTime('2014-08-27 08:48:51'), $this->invalidCertificate->getIssueDate());
+ $this->assertEquals((new DateTime('2014-08-27 08:45:52 GMT'))->getTimestamp(), $this->goodCertificate->getIssueDate()->getTimestamp());
+ $this->assertEquals((new DateTime('2014-08-27 08:48:51 GMT'))->getTimestamp(), $this->invalidCertificate->getIssueDate()->getTimestamp());
}
function testGetExpireDate() {
- $this->assertEquals(new DateTime('2015-08-27 08:45:52'), $this->goodCertificate->getExpireDate());
- $this->assertEquals(new DateTime('2015-08-27 08:48:51'), $this->invalidCertificate->getExpireDate());
- $this->assertEquals(new DateTime('2014-08-28 09:12:43'), $this->expiredCertificate->getExpireDate());
+ $this->assertEquals((new DateTime('2015-08-27 08:45:52 GMT'))->getTimestamp(), $this->goodCertificate->getExpireDate()->getTimestamp());
+ $this->assertEquals((new DateTime('2015-08-27 08:48:51 GMT'))->getTimestamp(), $this->invalidCertificate->getExpireDate()->getTimestamp());
+ $this->assertEquals((new DateTime('2014-08-28 09:12:43 GMT'))->getTimestamp(), $this->expiredCertificate->getExpireDate()->getTimestamp());
}
/**
@@ -85,4 +85,4 @@ class CertificateTest extends \PHPUnit_Framework_TestCase {
$this->assertSame('Internet Widgits Pty Ltd', $this->invalidCertificate->getIssuerOrganization());
$this->assertSame('Internet Widgits Pty Ltd', $this->expiredCertificate->getIssuerOrganization());
}
-}
\ No newline at end of file
+}
From 3a85767182e04ac013f59d82cc3a8c4d08bab151 Mon Sep 17 00:00:00 2001
From: Robin Appelman
Date: Sun, 31 Aug 2014 13:16:28 +0200
Subject: [PATCH 18/18] 5.3 syntax...
---
tests/lib/security/certificate.php | 23 ++++++++++++++---------
1 file changed, 14 insertions(+), 9 deletions(-)
diff --git a/tests/lib/security/certificate.php b/tests/lib/security/certificate.php
index 41c8a74b83..db33dd00d9 100644
--- a/tests/lib/security/certificate.php
+++ b/tests/lib/security/certificate.php
@@ -4,7 +4,7 @@
* This file is licensed under the Affero General Public License version 3 or
* later.
* See the COPYING-README file.
-*/
+ */
use \OC\Security\Certificate;
@@ -18,11 +18,11 @@ class CertificateTest extends \PHPUnit_Framework_TestCase {
protected $expiredCertificate;
function setUp() {
- $goodCertificate = file_get_contents(__DIR__.'/../../data/certificates/goodCertificate.crt');
+ $goodCertificate = file_get_contents(__DIR__ . '/../../data/certificates/goodCertificate.crt');
$this->goodCertificate = new Certificate($goodCertificate, 'GoodCertificate');
- $badCertificate = file_get_contents(__DIR__.'/../../data/certificates/badCertificate.crt');
+ $badCertificate = file_get_contents(__DIR__ . '/../../data/certificates/badCertificate.crt');
$this->invalidCertificate = new Certificate($badCertificate, 'BadCertificate');
- $expiredCertificate = file_get_contents(__DIR__.'/../../data/certificates/expiredCertificate.crt');
+ $expiredCertificate = file_get_contents(__DIR__ . '/../../data/certificates/expiredCertificate.crt');
$this->expiredCertificate = new Certificate($expiredCertificate, 'ExpiredCertificate');
}
@@ -55,14 +55,19 @@ class CertificateTest extends \PHPUnit_Framework_TestCase {
}
function testGetIssueDate() {
- $this->assertEquals((new DateTime('2014-08-27 08:45:52 GMT'))->getTimestamp(), $this->goodCertificate->getIssueDate()->getTimestamp());
- $this->assertEquals((new DateTime('2014-08-27 08:48:51 GMT'))->getTimestamp(), $this->invalidCertificate->getIssueDate()->getTimestamp());
+ $expected = new DateTime('2014-08-27 08:45:52 GMT');
+ $this->assertEquals($expected->getTimestamp(), $this->goodCertificate->getIssueDate()->getTimestamp());
+ $expected = new DateTime('2014-08-27 08:48:51 GMT');
+ $this->assertEquals($expected->getTimestamp(), $this->invalidCertificate->getIssueDate()->getTimestamp());
}
function testGetExpireDate() {
- $this->assertEquals((new DateTime('2015-08-27 08:45:52 GMT'))->getTimestamp(), $this->goodCertificate->getExpireDate()->getTimestamp());
- $this->assertEquals((new DateTime('2015-08-27 08:48:51 GMT'))->getTimestamp(), $this->invalidCertificate->getExpireDate()->getTimestamp());
- $this->assertEquals((new DateTime('2014-08-28 09:12:43 GMT'))->getTimestamp(), $this->expiredCertificate->getExpireDate()->getTimestamp());
+ $expected = new DateTime('2015-08-27 08:45:52 GMT');
+ $this->assertEquals($expected->getTimestamp(), $this->goodCertificate->getExpireDate()->getTimestamp());
+ $expected = new DateTime('2015-08-27 08:48:51 GMT');
+ $this->assertEquals($expected->getTimestamp(), $this->invalidCertificate->getExpireDate()->getTimestamp());
+ $expected = new DateTime('2014-08-28 09:12:43 GMT');
+ $this->assertEquals($expected->getTimestamp(), $this->expiredCertificate->getExpireDate()->getTimestamp());
}
/**
|