From ed039ee5ebdba6778b245f249fe206d2423a6a36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Schie=C3=9Fle?= Date: Thu, 29 Oct 2015 17:27:14 +0100 Subject: [PATCH] added app "federation", allows you to connect ownClouds and exchange user lists --- .gitignore | 1 + apps/federation/appinfo/app.php | 25 ++ apps/federation/appinfo/application.php | 92 +++++++ apps/federation/appinfo/database.xml | 43 +++ apps/federation/appinfo/info.xml | 14 + apps/federation/appinfo/routes.php | 35 +++ .../controller/settingscontroller.php | 112 ++++++++ apps/federation/css/settings-admin.css | 24 ++ apps/federation/js/settings-admin.js | 70 +++++ apps/federation/lib/dbhandler.php | 147 +++++++++++ apps/federation/lib/trustedservers.php | 160 ++++++++++++ .../middleware/addservermiddleware.php | 71 +++++ apps/federation/settings/settings-admin.php | 39 +++ apps/federation/templates/settings-admin.php | 31 +++ .../controller/settingscontrollertest.php | 166 ++++++++++++ apps/federation/tests/lib/dbhandlertest.php | 130 ++++++++++ .../tests/lib/trustedserverstest.php | 244 ++++++++++++++++++ .../middleware/addservermiddlewaretest.php | 100 +++++++ tests/enable_all.php | 2 +- 19 files changed, 1505 insertions(+), 1 deletion(-) create mode 100644 apps/federation/appinfo/app.php create mode 100644 apps/federation/appinfo/application.php create mode 100644 apps/federation/appinfo/database.xml create mode 100644 apps/federation/appinfo/info.xml create mode 100644 apps/federation/appinfo/routes.php create mode 100644 apps/federation/controller/settingscontroller.php create mode 100644 apps/federation/css/settings-admin.css create mode 100644 apps/federation/js/settings-admin.js create mode 100644 apps/federation/lib/dbhandler.php create mode 100644 apps/federation/lib/trustedservers.php create mode 100644 apps/federation/middleware/addservermiddleware.php create mode 100644 apps/federation/settings/settings-admin.php create mode 100644 apps/federation/templates/settings-admin.php create mode 100644 apps/federation/tests/controller/settingscontrollertest.php create mode 100644 apps/federation/tests/lib/dbhandlertest.php create mode 100644 apps/federation/tests/lib/trustedserverstest.php create mode 100644 apps/federation/tests/middleware/addservermiddlewaretest.php diff --git a/.gitignore b/.gitignore index 531e372e607..3fb848dbb44 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,7 @@ !/apps/dav !/apps/files !/apps/files_encryption +!/apps/federation !/apps/encryption !/apps/encryption_dummy !/apps/files_external diff --git a/apps/federation/appinfo/app.php b/apps/federation/appinfo/app.php new file mode 100644 index 00000000000..9ed00f23866 --- /dev/null +++ b/apps/federation/appinfo/app.php @@ -0,0 +1,25 @@ + + * + * @copyright Copyright (c) 2015, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see + * + */ + +namespace OCA\Federation\AppInfo; + +$app = new Application(); +$app->registerSettings(); diff --git a/apps/federation/appinfo/application.php b/apps/federation/appinfo/application.php new file mode 100644 index 00000000000..46a791c25d0 --- /dev/null +++ b/apps/federation/appinfo/application.php @@ -0,0 +1,92 @@ + + * + * @copyright Copyright (c) 2015, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see + * + */ + +namespace OCA\Federation\AppInfo; + +use OCA\Federation\Controller\SettingsController; +use OCA\Federation\DbHandler; +use OCA\Federation\Middleware\AddServerMiddleware; +use OCA\Federation\TrustedServers; +use OCP\App; +use OCP\AppFramework\IAppContainer; +use OCP\IAppConfig; + +class Application extends \OCP\AppFramework\App { + + /** + * @param array $urlParams + */ + public function __construct($urlParams = array()) { + parent::__construct('federation', $urlParams); + $this->registerService(); + $this->registerMiddleware(); + + } + + /** + * register setting scripts + */ + public function registerSettings() { + App::registerAdmin('federation', 'settings/settings-admin'); + } + + private function registerService() { + $container = $this->getContainer(); + + $container->registerService('addServerMiddleware', function(IAppContainer $c) { + return new AddServerMiddleware( + $c->getAppName(), + \OC::$server->getL10N($c->getAppName()), + \OC::$server->getLogger() + ); + }); + + $container->registerService('DbHandler', function(IAppContainer $c) { + return new DbHandler( + \OC::$server->getDatabaseConnection(), + \OC::$server->getL10N($c->getAppName()) + ); + }); + + $container->registerService('TrustedServers', function(IAppContainer $c) { + return new TrustedServers( + $c->query('DbHandler'), + \OC::$server->getHTTPClientService(), + \OC::$server->getLogger() + ); + }); + + $container->registerService('SettingsController', function (IAppContainer $c) { + $server = $c->getServer(); + return new SettingsController( + $c->getAppName(), + $server->getRequest(), + $server->getL10N($c->getAppName()), + $c->query('TrustedServers') + ); + }); + } + + private function registerMiddleware() { + $container = $this->getContainer(); + $container->registerMiddleware('addServerMiddleware'); + } +} diff --git a/apps/federation/appinfo/database.xml b/apps/federation/appinfo/database.xml new file mode 100644 index 00000000000..da16212ca19 --- /dev/null +++ b/apps/federation/appinfo/database.xml @@ -0,0 +1,43 @@ + + + *dbname* + true + false + utf8 + + *dbprefix*trusted_servers + + + id + integer + 0 + true + 1 + 4 + + + url + text + true + 512 + Url of trusted server + + + url_hash + text + + true + 32 + md5 hash of the url + + + url_hash + true + + url_hash + ascending + + + +
+
diff --git a/apps/federation/appinfo/info.xml b/apps/federation/appinfo/info.xml new file mode 100644 index 00000000000..53b2926ba53 --- /dev/null +++ b/apps/federation/appinfo/info.xml @@ -0,0 +1,14 @@ + + + federation + Federation + ownCloud Federation allows you to connect with other trusted ownClouds to exchange the user directory. For example this will be used to auto-complete external users for federated sharing. + AGPL + Bjoern Schiessle + 0.0.1 + Federation + other + + + + diff --git a/apps/federation/appinfo/routes.php b/apps/federation/appinfo/routes.php new file mode 100644 index 00000000000..43ccc4ed504 --- /dev/null +++ b/apps/federation/appinfo/routes.php @@ -0,0 +1,35 @@ + + * + * @copyright Copyright (c) 2015, ownCloud, Inc. + * @license AGPL-3.0 +* + * This code is free software: you can redistribute it and/or modify +* it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see + * + */ + +return [ + 'routes' => [ + [ + 'name' => 'Settings#addServer', + 'url' => '/trusted-servers', + 'verb' => 'POST' + ], + [ + 'name' => 'Settings#removeServer', + 'url' => '/trusted-servers/{id}', + 'verb' => 'DELETE' + ], + ] +]; diff --git a/apps/federation/controller/settingscontroller.php b/apps/federation/controller/settingscontroller.php new file mode 100644 index 00000000000..8d522328120 --- /dev/null +++ b/apps/federation/controller/settingscontroller.php @@ -0,0 +1,112 @@ + + * + * @copyright Copyright (c) 2015, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see + * + */ + +namespace OCA\Federation\Controller; + +use OC\HintException; +use OCA\Federation\TrustedServers; +use OCP\AppFramework\Controller; +use OCP\AppFramework\Http; +use OCP\AppFramework\Http\DataResponse; +use OCP\IL10N; +use OCP\IRequest; + + +class SettingsController extends Controller { + + /** @var IL10N */ + private $l; + + /** @var TrustedServers */ + private $trustedServers; + + /** + * @param string $AppName + * @param IRequest $request + * @param IL10N $l10n + * @param TrustedServers $trustedServers + */ + public function __construct($AppName, + IRequest $request, + IL10N $l10n, + TrustedServers $trustedServers + ) { + parent::__construct($AppName, $request); + $this->l = $l10n; + $this->trustedServers = $trustedServers; + } + + + /** + * add server to the list of trusted ownClouds + * + * @param string $url + * @return DataResponse + * @throws HintException + */ + public function addServer($url) { + $this->checkServer($url); + $id = $this->trustedServers->addServer($url); + + return new DataResponse( + [ + 'url' => $url, + 'id' => $id, + 'message' => (string) $this->l->t('Server added to the list of trusted ownClouds') + ] + ); + } + + /** + * add server to the list of trusted ownClouds + * + * @param int $id + * @return DataResponse + */ + public function removeServer($id) { + $this->trustedServers->removeServer($id); + return new DataResponse(); + } + + /** + * check if the server should be added to the list of trusted servers or not + * + * @param string $url + * @return bool + * @throws HintException + */ + protected function checkServer($url) { + if ($this->trustedServers->isTrustedServer($url) === true) { + $message = 'Server is already in the list of trusted servers.'; + $hint = $this->l->t('Server is already in the list of trusted servers.'); + throw new HintException($message, $hint); + } + + if ($this->trustedServers->isOwnCloudServer($url) === false) { + $message = 'No ownCloud server found'; + $hint = $this->l->t('No ownCloud server found'); + throw new HintException($message, $hint); + } + + return true; + } + +} diff --git a/apps/federation/css/settings-admin.css b/apps/federation/css/settings-admin.css new file mode 100644 index 00000000000..7dbc949270f --- /dev/null +++ b/apps/federation/css/settings-admin.css @@ -0,0 +1,24 @@ +#ocFederationSettings p { + padding-top: 10px; +} + +#listOfTrustedServers li { + padding-top: 10px; + padding-left: 20px; +} + +.removeTrustedServer { + display: none; + vertical-align:middle; + padding-left: 10px; +} + +#ocFederationAddServerButton { + cursor: pointer; +} + +#listOfTrustedServers li:hover { + cursor: pointer; + background: url(../../../core/img/actions/delete.svg) no-repeat left center; + padding-left: 20px; +} diff --git a/apps/federation/js/settings-admin.js b/apps/federation/js/settings-admin.js new file mode 100644 index 00000000000..a1f02a09efe --- /dev/null +++ b/apps/federation/js/settings-admin.js @@ -0,0 +1,70 @@ +/** + * @author Björn Schießle + * + * @copyright Copyright (c) 2015, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see + * + */ + +$(document).ready(function () { + + // show input field to add a new trusted server + $("#ocFederationAddServer").on('click', function() { + $('#ocFederationAddServerButton').addClass('hidden'); + $("#serverUrl").removeClass('hidden'); + $("#serverUrl").focus(); + }); + + // add new trusted server + $("#serverUrl").keyup(function (e) { + if (e.keyCode === 13) { // add server on "enter" + var url = $('#serverUrl').val(); + OC.msg.startSaving('#ocFederationAddServer .msg'); + $.post( + OC.generateUrl('/apps/federation/trusted-servers'), + { + url: url + } + ).done(function (data) { + $('#serverUrl').attr('value', ''); + $('ul#listOfTrustedServers').prepend( + $('
  • ').attr('id', data.id).text(data.url) + ); + OC.msg.finishedSuccess('#ocFederationAddServer .msg', data.message); + }) + .fail(function (jqXHR) { + OC.msg.finishedError('#ocFederationAddServer .msg', JSON.parse(jqXHR.responseText).message); + }); + } else if (e.keyCode === 27) { // hide input filed again in ESC + $('#ocFederationAddServerButton').toggleClass('hidden'); + $("#serverUrl").toggleClass('hidden'); + } + }); + + // remove trusted server from list + $( "#listOfTrustedServers" ).on('click', 'li', function() { + var id = $(this).attr('id'); + var $this = $(this); + $.ajax({ + url: OC.generateUrl('/apps/federation/trusted-servers/' + id), + type: 'DELETE', + success: function(response) { + $this.remove(); + } + }); + + }); + +}); diff --git a/apps/federation/lib/dbhandler.php b/apps/federation/lib/dbhandler.php new file mode 100644 index 00000000000..1100875cc23 --- /dev/null +++ b/apps/federation/lib/dbhandler.php @@ -0,0 +1,147 @@ + + * + * @copyright Copyright (c) 2015, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see + * + */ + + +namespace OCA\Federation; + + +use OC\HintException; +use OCP\IDBConnection; +use OCP\IL10N; + +class DbHandler { + + /** @var IDBConnection */ + private $connection; + + /** @var IL10N */ + private $l; + + /** @var string */ + private $dbTable = 'trusted_servers'; + + /** + * @param IDBConnection $connection + * @param IL10N $il10n + */ + public function __construct( + IDBConnection $connection, + IL10N $il10n + ) { + $this->connection = $connection; + $this->IL10N = $il10n; + } + + /** + * add server to the list of trusted ownCloud servers + * + * @param $url + * @return int + * @throws HintException + */ + public function add($url) { + $hash = md5($url); + $query = $this->connection->getQueryBuilder(); + $query->insert($this->dbTable) + ->values( + [ + 'url' => $query->createParameter('url'), + 'url_hash' => $query->createParameter('url_hash'), + ] + ) + ->setParameter('url', $url) + ->setParameter('url_hash', $hash); + + $result = $query->execute(); + + if ($result) { + $id = $this->connection->lastInsertId(); + // Fallback, if lastInterId() doesn't work we need to perform a select + // to get the ID (seems to happen sometimes on Oracle) + if (!$id) { + $server = $this->get($url); + $id = $server['id']; + } + return $id; + } else { + $message = 'Internal failure, Could not add ownCloud as trusted server: ' . $url; + $message_t = $this->l->t('Could not add server'); + throw new HintException($message, $message_t); + } + } + + /** + * remove server from the list of trusted ownCloud servers + * + * @param int $id + */ + public function remove($id) { + $query = $this->connection->getQueryBuilder(); + $query->delete($this->dbTable) + ->where($query->expr()->eq('id', $query->createParameter('id'))) + ->setParameter('id', $id); + $query->execute(); + } + + /** + * get trusted server from database + * + * @param $url + * @return mixed + */ + public function get($url) { + $query = $this->connection->getQueryBuilder(); + $query->select('url', 'id')->from($this->dbTable) + ->where($query->expr()->eq('url_hash', $query->createParameter('url_hash'))) + ->setParameter('url_hash', md5($url)); + + return $query->execute()->fetch(); + } + + /** + * get all trusted servers + * + * @return array + */ + public function getAll() { + $query = $this->connection->getQueryBuilder(); + $query->select('url', 'id')->from($this->dbTable); + $result = $query->execute()->fetchAll(); + return $result; + } + + /** + * check if server already exists in the database table + * + * @param string $url + * @return bool + */ + public function exists($url) { + $query = $this->connection->getQueryBuilder(); + $query->select('url')->from($this->dbTable) + ->where($query->expr()->eq('url_hash', $query->createParameter('url_hash'))) + ->setParameter('url_hash', md5($url)); + $result = $query->execute()->fetchAll(); + + return !empty($result); + } + +} diff --git a/apps/federation/lib/trustedservers.php b/apps/federation/lib/trustedservers.php new file mode 100644 index 00000000000..bf31277b2a8 --- /dev/null +++ b/apps/federation/lib/trustedservers.php @@ -0,0 +1,160 @@ + + * + * @copyright Copyright (c) 2015, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see + * + */ + + +namespace OCA\Federation; + + +use OC\Files\Filesystem; +use OCP\AppFramework\Http; +use OCP\Http\Client\IClientService; +use OCP\IDBConnection; +use OCP\ILogger; + +class TrustedServers { + + /** @var dbHandler */ + private $dbHandler; + + /** @var IClientService */ + private $httpClientService; + + /** @var ILogger */ + private $logger; + + private $dbTable = 'trusted_servers'; + + /** + * @param DbHandler $dbHandler + * @param IClientService $httpClientService + * @param ILogger $logger + */ + public function __construct( + DbHandler $dbHandler, + IClientService $httpClientService, + ILogger $logger + ) { + $this->dbHandler = $dbHandler; + $this->httpClientService = $httpClientService; + $this->logger = $logger; + } + + /** + * add server to the list of trusted ownCloud servers + * + * @param $url + * @return int server id + */ + public function addServer($url) { + return $this->dbHandler->add($this->normalizeUrl($url)); + } + + /** + * remove server from the list of trusted ownCloud servers + * + * @param int $id + */ + public function removeServer($id) { + $this->dbHandler->remove($id); + } + + /** + * get all trusted servers + * + * @return array + */ + public function getServers() { + return $this->dbHandler->getAll(); + } + + /** + * check if given server is a trusted ownCloud server + * + * @param string $url + * @return bool + */ + public function isTrustedServer($url) { + return $this->dbHandler->exists($this->normalizeUrl($url)); + } + + /** + * check if URL point to a ownCloud server + * + * @param string $url + * @return bool + */ + public function isOwnCloudServer($url) { + $isValidOwnCloud = false; + $client = $this->httpClientService->newClient(); + try { + $result = $client->get( + $url . '/status.php', + [ + 'timeout' => 3, + 'connect_timeout' => 3, + ] + ); + if ($result->getStatusCode() === Http::STATUS_OK) { + $isValidOwnCloud = $this->checkOwnCloudVersion($result->getBody()); + } + } catch (\Exception $e) { + $this->logger->error($e->getMessage(), ['app' => 'federation']); + return false; + } + return $isValidOwnCloud; + } + + /** + * check if ownCloud version is >= 9.0 + * + * @param $statusphp + * @return bool + */ + protected function checkOwnCloudVersion($statusphp) { + $decoded = json_decode($statusphp, true); + if (!empty($decoded) && isset($decoded['version'])) { + return version_compare($decoded['version'], '9.0.0', '>='); + } + return false; + } + + /** + * normalize URL + * + * @param string $url + * @return string + */ + protected function normalizeUrl($url) { + + $normalized = $url; + + if (strpos($url, 'https://') === 0) { + $normalized = substr($url, strlen('https://')); + } else if (strpos($url, 'http://') === 0) { + $normalized = substr($url, strlen('http://')); + } + + $normalized = Filesystem::normalizePath($normalized); + $normalized = trim($normalized, '/'); + + return $normalized; + } +} diff --git a/apps/federation/middleware/addservermiddleware.php b/apps/federation/middleware/addservermiddleware.php new file mode 100644 index 00000000000..56552021dc2 --- /dev/null +++ b/apps/federation/middleware/addservermiddleware.php @@ -0,0 +1,71 @@ + + * + * @copyright Copyright (c) 2015, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see + * + */ + +namespace OCA\Federation\Middleware ; + +use OC\HintException; +use OCP\AppFramework\Http; +use OCP\AppFramework\Http\JSONResponse; +use OCP\AppFramework\Middleware; +use OCP\IL10N; +use OCP\ILogger; + +class AddServerMiddleware extends Middleware { + + /** @var string */ + protected $appName; + + /** @var IL10N */ + protected $l; + + /** @var ILogger */ + protected $logger; + + public function __construct($appName, IL10N $l, ILogger $logger) { + $this->appName = $appName; + $this->l = $l; + $this->logger = $logger; + } + + /** + * Log error message and return a response which can be displayed to the user + * + * @param \OCP\AppFramework\Controller $controller + * @param string $methodName + * @param \Exception $exception + * @return JSONResponse + */ + public function afterException($controller, $methodName, \Exception $exception) { + $this->logger->error($exception->getMessage(), ['app' => $this->appName]); + if ($exception instanceof HintException) { + $message = $exception->getHint(); + } else { + $message = $this->l->t('Unknown error'); + } + + return new JSONResponse( + ['message' => $message], + Http::STATUS_BAD_REQUEST + ); + + } + +} diff --git a/apps/federation/settings/settings-admin.php b/apps/federation/settings/settings-admin.php new file mode 100644 index 00000000000..ea71475d619 --- /dev/null +++ b/apps/federation/settings/settings-admin.php @@ -0,0 +1,39 @@ + + * + * @copyright Copyright (c) 2015, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see + * + */ + +\OC_Util::checkAdminUser(); + +$template = new OCP\Template('federation', 'settings-admin'); + +$dbHandler = new \OCA\Federation\DbHandler( + \OC::$server->getDatabaseConnection(), + \OC::$server->getL10N('federation') +); + +$trustedServers = new \OCA\Federation\TrustedServers( + $dbHandler, + \OC::$server->getHTTPClientService(), + \OC::$server->getLogger() +); + +$template->assign('trustedServers', $trustedServers->getServers()); + +return $template->fetchPage(); diff --git a/apps/federation/templates/settings-admin.php b/apps/federation/templates/settings-admin.php new file mode 100644 index 00000000000..faa1e393158 --- /dev/null +++ b/apps/federation/templates/settings-admin.php @@ -0,0 +1,31 @@ + +
    +

    t('Federation')); ?>

    + t('ownCloud Federation allows you to connect with other trusted ownClouds to exchange the user directory. For example this will be used to auto-complete external users for federated sharing.')); ?> + +

    + + +

    + +

    Trusted ownCloud Servers

    +

    + + + +

    +
      + +
    • + +
    • + +
    + +
    + diff --git a/apps/federation/tests/controller/settingscontrollertest.php b/apps/federation/tests/controller/settingscontrollertest.php new file mode 100644 index 00000000000..efbc6911c52 --- /dev/null +++ b/apps/federation/tests/controller/settingscontrollertest.php @@ -0,0 +1,166 @@ + + * + * @copyright Copyright (c) 2015, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see + * + */ + + +namespace OCA\Federation\Tests\Controller; + + +use OCA\Federation\Controller\SettingsController; +use OCP\AppFramework\Http\DataResponse; +use Test\TestCase; + +class SettingsControllerTest extends TestCase { + + /** @var SettingsController */ + private $controller; + + /** @var \PHPUnit_Framework_MockObject_MockObject | \OCP\IRequest */ + private $request; + + /** @var \PHPUnit_Framework_MockObject_MockObject | \OCP\IL10N */ + private $l10n; + + /** @var \PHPUnit_Framework_MockObject_MockObject | \OCA\Federation\TrustedServers */ + private $trustedServers; + + public function setUp() { + parent::setUp(); + + $this->request = $this->getMock('OCP\IRequest'); + $this->l10n = $this->getMock('OCP\IL10N'); + $this->trustedServers = $this->getMockBuilder('OCA\Federation\TrustedServers') + ->disableOriginalConstructor()->getMock(); + + $this->controller = new SettingsController( + 'SettingsControllerTest', + $this->request, + $this->l10n, + $this->trustedServers + ); + } + + public function testAddServer() { + $this->trustedServers + ->expects($this->once()) + ->method('isTrustedServer') + ->with('url') + ->willReturn(false); + $this->trustedServers + ->expects($this->once()) + ->method('isOwnCloudServer') + ->with('url') + ->willReturn(true); + + $result = $this->controller->addServer('url'); + $this->assertTrue($result instanceof DataResponse); + + $data = $result->getData(); + $this->assertSame(200, $result->getStatus()); + $this->assertSame('url', $data['url']); + $this->assertArrayHasKey('id', $data); + } + + /** + * @dataProvider checkServerFails + * @expectedException \OC\HintException + * + * @param bool $isTrustedServer + * @param bool $isOwnCloud + */ + public function testAddServerFail($isTrustedServer, $isOwnCloud) { + $this->trustedServers + ->expects($this->any()) + ->method('isTrustedServer') + ->with('url') + ->willReturn($isTrustedServer); + $this->trustedServers + ->expects($this->any()) + ->method('isOwnCloudServer') + ->with('url') + ->willReturn($isOwnCloud); + + $this->controller->addServer('url'); + } + + public function testRemoveServer() { + $this->trustedServers->expects($this->once())->method('removeServer') + ->with('url'); + $result = $this->controller->removeServer('url'); + $this->assertTrue($result instanceof DataResponse); + $this->assertSame(200, $result->getStatus()); + } + + public function testCheckServer() { + $this->trustedServers + ->expects($this->once()) + ->method('isTrustedServer') + ->with('url') + ->willReturn(false); + $this->trustedServers + ->expects($this->once()) + ->method('isOwnCloudServer') + ->with('url') + ->willReturn(true); + + $this->assertTrue( + $this->invokePrivate($this->controller, 'checkServer', ['url']) + ); + + } + + /** + * @dataProvider checkServerFails + * @expectedException \OC\HintException + * + * @param bool $isTrustedServer + * @param bool $isOwnCloud + */ + public function testCheckServerFail($isTrustedServer, $isOwnCloud) { + $this->trustedServers + ->expects($this->any()) + ->method('isTrustedServer') + ->with('url') + ->willReturn($isTrustedServer); + $this->trustedServers + ->expects($this->any()) + ->method('isOwnCloudServer') + ->with('url') + ->willReturn($isOwnCloud); + + $this->assertTrue( + $this->invokePrivate($this->controller, 'checkServer', ['url']) + ); + + } + + /** + * data to simulate checkServer fails + * + * @return array + */ + public function checkServerFails() { + return [ + [true, true], + [false, false] + ]; + } + +} diff --git a/apps/federation/tests/lib/dbhandlertest.php b/apps/federation/tests/lib/dbhandlertest.php new file mode 100644 index 00000000000..202199d2b5b --- /dev/null +++ b/apps/federation/tests/lib/dbhandlertest.php @@ -0,0 +1,130 @@ + + * + * @copyright Copyright (c) 2015, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see + * + */ + + +namespace OCA\Federation\Tests\lib; + + +use OCA\Federation\DbHandler; +use OCP\IDBConnection; +use Test\TestCase; + +class DbHandlerTest extends TestCase { + + /** @var DbHandler */ + private $dbHandler; + + /** @var \PHPUnit_Framework_MockObject_MockObject */ + private $il10n; + + /** @var IDBConnection */ + private $connection; + + /** @var string */ + private $dbTable = 'trusted_servers'; + + public function setUp() { + parent::setUp(); + + $this->connection = \OC::$server->getDatabaseConnection(); + $this->il10n = $this->getMock('OCP\IL10N'); + + $this->dbHandler = new DbHandler( + $this->connection, + $this->il10n + ); + + $query = $this->connection->getQueryBuilder()->select('*')->from($this->dbTable); + $result = $query->execute()->fetchAll(); + $this->assertEmpty($result, 'we need to start with a empty trusted_servers table'); + } + + public function tearDown() { + parent::tearDown(); + $query = $this->connection->getQueryBuilder()->delete($this->dbTable); + $query->execute(); + } + + public function testAdd() { + $id = $this->dbHandler->add('server1'); + + $query = $this->connection->getQueryBuilder()->select('*')->from($this->dbTable); + $result = $query->execute()->fetchAll(); + $this->assertSame(1, count($result)); + $this->assertSame('server1', $result[0]['url']); + $this->assertSame($id, $result[0]['id']); + } + + public function testRemove() { + $id1 = $this->dbHandler->add('server1'); + $id2 = $this->dbHandler->add('server2'); + + $query = $this->connection->getQueryBuilder()->select('*')->from($this->dbTable); + $result = $query->execute()->fetchAll(); + $this->assertSame(2, count($result)); + $this->assertSame('server1', $result[0]['url']); + $this->assertSame('server2', $result[1]['url']); + $this->assertSame($id1, $result[0]['id']); + $this->assertSame($id2, $result[1]['id']); + + $this->dbHandler->remove($id2); + $query = $this->connection->getQueryBuilder()->select('*')->from($this->dbTable); + $result = $query->execute()->fetchAll(); + $this->assertSame(1, count($result)); + $this->assertSame('server1', $result[0]['url']); + $this->assertSame($id1, $result[0]['id']); + } + + public function testGetAll() { + $id1 = $this->dbHandler->add('server1'); + $id2 = $this->dbHandler->add('server2'); + + $result = $this->dbHandler->getAll(); + $this->assertSame(2, count($result)); + $this->assertSame('server1', $result[0]['url']); + $this->assertSame('server2', $result[1]['url']); + $this->assertSame($id1, $result[0]['id']); + $this->assertSame($id2, $result[1]['id']); + } + + /** + * @dataProvider dataTestExists + * + * @param string $serverInTable + * @param string $checkForServer + * @param bool $expected + */ + public function testExists($serverInTable, $checkForServer, $expected) { + $this->dbHandler->add($serverInTable); + $this->assertSame($expected, + $this->dbHandler->exists($checkForServer) + ); + } + + public function dataTestExists() { + return [ + ['server1', 'server1', true], + ['server1', 'server1', true], + ['server1', 'server2', false] + ]; + } + +} diff --git a/apps/federation/tests/lib/trustedserverstest.php b/apps/federation/tests/lib/trustedserverstest.php new file mode 100644 index 00000000000..07aa7531274 --- /dev/null +++ b/apps/federation/tests/lib/trustedserverstest.php @@ -0,0 +1,244 @@ + + * + * @copyright Copyright (c) 2015, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see + * + */ + + +namespace OCA\Federation\Tests\lib; + + +use OCA\Federation\DbHandler; +use OCA\Federation\TrustedServers; +use OCP\Http\Client\IClient; +use OCP\Http\Client\IClientService; +use OCP\Http\Client\IResponse; +use OCP\IDBConnection; +use OCP\ILogger; +use Test\TestCase; + +class TrustedServersTest extends TestCase { + + /** @var TrustedServers */ + private $trustedServers; + + /** @var \PHPUnit_Framework_MockObject_MockObject | DbHandler */ + private $dbHandler; + + /** @var \PHPUnit_Framework_MockObject_MockObject | IClientService */ + private $httpClientService; + + /** @var \PHPUnit_Framework_MockObject_MockObject | IClient */ + private $httpClient; + + /** @var \PHPUnit_Framework_MockObject_MockObject | IResponse */ + private $response; + + /** @var \PHPUnit_Framework_MockObject_MockObject | ILogger */ + private $logger; + + public function setUp() { + parent::setUp(); + + $this->dbHandler = $this->getMockBuilder('\OCA\Federation\DbHandler') + ->disableOriginalConstructor()->getMock(); + $this->httpClientService = $this->getMock('OCP\Http\Client\IClientService'); + $this->httpClient = $this->getMock('OCP\Http\Client\IClient'); + $this->response = $this->getMock('OCP\Http\Client\IResponse'); + $this->logger = $this->getMock('OCP\ILogger'); + + $this->trustedServers = new TrustedServers( + $this->dbHandler, + $this->httpClientService, + $this->logger + ); + + } + + public function testAddServer() { + /** @var \PHPUnit_Framework_MockObject_MockObject | TrustedServers $trustedServer */ + $trustedServers = $this->getMockBuilder('OCA\Federation\TrustedServers') + ->setConstructorArgs( + [ + $this->dbHandler, + $this->httpClientService, + $this->logger + ] + ) + ->setMethods(['normalizeUrl']) + ->getMock(); + $trustedServers->expects($this->once())->method('normalizeUrl') + ->with('url')->willReturn('normalized'); + $this->dbHandler->expects($this->once())->method('add')->with('normalized') + ->willReturn(true); + + $this->assertTrue( + $trustedServers->addServer('url') + ); + } + + public function testRemoveServer() { + $id = 42; + $this->dbHandler->expects($this->once())->method('remove')->with($id); + $this->trustedServers->removeServer($id); + } + + public function testGetServers() { + $this->dbHandler->expects($this->once())->method('getAll')->willReturn(true); + + $this->assertTrue( + $this->trustedServers->getServers() + ); + } + + + public function testIsTrustedServer() { + /** @var \PHPUnit_Framework_MockObject_MockObject | TrustedServers $trustedServer */ + $trustedServers = $this->getMockBuilder('OCA\Federation\TrustedServers') + ->setConstructorArgs( + [ + $this->dbHandler, + $this->httpClientService, + $this->logger + ] + ) + ->setMethods(['normalizeUrl']) + ->getMock(); + $trustedServers->expects($this->once())->method('normalizeUrl') + ->with('url')->willReturn('normalized'); + $this->dbHandler->expects($this->once())->method('exists')->with('normalized') + ->willReturn(true); + + $this->assertTrue( + $trustedServers->isTrustedServer('url') + ); + } + + /** + * @dataProvider dataTestIsOwnCloudServer + * + * @param int $statusCode + * @param bool $isValidOwnCloudVersion + * @param bool $expected + */ + public function testIsOwnCloudServer($statusCode, $isValidOwnCloudVersion, $expected) { + + $server = 'server1'; + + /** @var \PHPUnit_Framework_MockObject_MockObject | TrustedServers $trustedServer */ + $trustedServers = $this->getMockBuilder('OCA\Federation\TrustedServers') + ->setConstructorArgs( + [ + $this->dbHandler, + $this->httpClientService, + $this->logger + ] + ) + ->setMethods(['checkOwnCloudVersion']) + ->getMock(); + + $this->httpClientService->expects($this->once())->method('newClient') + ->willReturn($this->httpClient); + + $this->httpClient->expects($this->once())->method('get')->with($server . '/status.php') + ->willReturn($this->response); + + $this->response->expects($this->once())->method('getStatusCode') + ->willReturn($statusCode); + + if ($statusCode === 200) { + $trustedServers->expects($this->once())->method('checkOwnCloudVersion') + ->willReturn($isValidOwnCloudVersion); + } else { + $trustedServers->expects($this->never())->method('checkOwnCloudVersion'); + } + + $this->assertSame($expected, + $trustedServers->isOwnCloudServer($server) + ); + + } + + public function dataTestIsOwnCloudServer() { + return [ + [200, true, true], + [200, false, false], + [404, true, false], + ]; + } + + public function testIsOwnCloudServerFail() { + $server = 'server1'; + + $this->httpClientService->expects($this->once())->method('newClient') + ->willReturn($this->httpClient); + + $this->logger->expects($this->once())->method('error') + ->with('simulated exception', ['app' => 'federation']); + + $this->httpClient->expects($this->once())->method('get')->with($server . '/status.php') + ->willReturnCallback(function() { + throw new \Exception('simulated exception'); + }); + + $this->assertFalse($this->trustedServers->isOwnCloudServer($server)); + + } + + /** + * @dataProvider dataTestCheckOwnCloudVersion + * + * @param $statusphp + * @param $expected + */ + public function testCheckOwnCloudVersion($statusphp, $expected) { + $this->assertSame($expected, + $this->invokePrivate($this->trustedServers, 'checkOwnCloudVersion', [$statusphp]) + ); + } + + public function dataTestCheckOwnCloudVersion() { + return [ + ['{"version":"8.4.0"}', false], + ['{"version":"9.0.0"}', true], + ['{"version":"9.1.0"}', true] + ]; + } + + /** + * @dataProvider dataTestNormalizeUrl + * + * @param string $url + * @param string $expected + */ + public function testNormalizeUrl($url, $expected) { + $this->assertSame($expected, + $this->invokePrivate($this->trustedServers, 'normalizeUrl', [$url]) + ); + } + + public function dataTestNormalizeUrl() { + return [ + ['owncloud.org', 'owncloud.org'], + ['http://owncloud.org', 'owncloud.org'], + ['https://owncloud.org', 'owncloud.org'], + ['https://owncloud.org//mycloud', 'owncloud.org/mycloud'], + ['https://owncloud.org/mycloud/', 'owncloud.org/mycloud'], + ]; + } +} diff --git a/apps/federation/tests/middleware/addservermiddlewaretest.php b/apps/federation/tests/middleware/addservermiddlewaretest.php new file mode 100644 index 00000000000..1be5a342285 --- /dev/null +++ b/apps/federation/tests/middleware/addservermiddlewaretest.php @@ -0,0 +1,100 @@ + + * + * @copyright Copyright (c) 2015, ownCloud, Inc. + * @license AGPL-3.0 + * + * This code is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License, version 3, + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License, version 3, + * along with this program. If not, see + * + */ + + +namespace OCA\Federation\Tests\Middleware; + + +use OC\HintException; +use OCA\Federation\Middleware\AddServerMiddleware; +use OCP\AppFramework\Controller; +use OCP\AppFramework\Http; +use Test\TestCase; + +class AddServerMiddlewareTest extends TestCase { + + /** @var \PHPUnit_Framework_MockObject_MockObject | ILogger */ + private $logger; + + /** @var \PHPUnit_Framework_MockObject_MockObject | \OCP\IL10N */ + private $l10n; + + /** @var AddServerMiddleware */ + private $middleware; + + /** @var \PHPUnit_Framework_MockObject_MockObject | Controller */ + private $controller; + + public function setUp() { + parent::setUp(); + + $this->logger = $this->getMock('OCP\ILogger'); + $this->l10n = $this->getMock('OCP\IL10N'); + $this->controller = $this->getMockBuilder('OCP\AppFramework\Controller') + ->disableOriginalConstructor()->getMock(); + + $this->middleware = new AddServerMiddleware( + 'AddServerMiddlewareTest', + $this->l10n, + $this->logger + ); + } + + /** + * @dataProvider dataTestAfterException + * + * @param \Exception $exception + * @param string $message + * @param string $hint + */ + public function testAfterException($exception, $message, $hint) { + + $this->logger->expects($this->once())->method('error') + ->with($message, ['app' => 'AddServerMiddlewareTest']); + + $this->l10n->expects($this->any())->method('t') + ->willReturnCallback( + function($message) { + return $message; + } + ); + + $result = $this->middleware->afterException($this->controller, 'method', $exception); + + $this->assertSame(Http::STATUS_BAD_REQUEST, + $result->getStatus() + ); + + $data = $result->getData(); + + $this->assertSame($hint, + $data['message'] + ); + } + + public function dataTestAfterException() { + return [ + [new HintException('message', 'hint'), 'message', 'hint'], + [new \Exception('message'), 'message', 'Unknown error'], + ]; + } + +} diff --git a/tests/enable_all.php b/tests/enable_all.php index 464155b1f39..6f2d1fa8717 100644 --- a/tests/enable_all.php +++ b/tests/enable_all.php @@ -22,4 +22,4 @@ enableApp('encryption'); enableApp('user_ldap'); enableApp('files_versions'); enableApp('provisioning_api'); - +enableApp('federation');