Quellcode durchsuchen

exchange shared secret

tags/v9.0beta1
Björn Schießle vor 8 Jahren
Ursprung
Commit
698100d279

+ 136
- 0
apps/federation/api/ocsauthapi.php Datei anzeigen

@@ -0,0 +1,136 @@
<?php
/**
* @author Björn Schießle <schiessle@owncloud.com>
*
* @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 <http://www.gnu.org/licenses/>
*
*/


namespace OCA\Federation\API;

use OC\BackgroundJob\JobList;
use OCA\Federation\DbHandler;
use OCA\Federation\TrustedServers;
use OCP\AppFramework\Http;
use OCP\IRequest;
use OCP\Security\ISecureRandom;
use OCP\Security\StringUtils;

/**
* Class OCSAuthAPI
*
* OCS API end-points to exchange shared secret between two connected ownClouds
*
* @package OCA\Federation\API
*/
class OCSAuthAPI {

/** @var IRequest */
private $request;

/** @var ISecureRandom */
private $secureRandom;

/** @var JobList */
private $jobList;

/** @var TrustedServers */
private $trustedServers;

/** @var DbHandler */
private $dbHandler;

/**
* AuthController constructor.
*
* @param IRequest $request
* @param ISecureRandom $secureRandom
* @param JobList $jobList
* @param TrustedServers $trustedServers
* @param DbHandler $dbHandler
*/
public function __construct(
IRequest $request,
ISecureRandom $secureRandom,
JobList $jobList,
TrustedServers $trustedServers,
DbHandler $dbHandler
) {
$this->request = $request;
$this->secureRandom = $secureRandom;
$this->jobList = $jobList;
$this->trustedServers = $trustedServers;
$this->dbHandler = $dbHandler;
}

/**
* request received to ask remote server for a shared secret
*
* @return \OC_OCS_Result
*/
public function requestSharedSecret() {

$url = $this->request->getParam('url');
$token = $this->request->getParam('token');

if ($this->trustedServers->isTrustedServer($url) === false) {
return new \OC_OCS_Result(null, HTTP::STATUS_FORBIDDEN);
}

$this->jobList->add(
'OCA\Federation\BackgroundJob\GetSharedSecret',
[
'url' => $url,
'token' => $token,
]
);

return new \OC_OCS_Result(null, Http::STATUS_OK);

}

/**
* create shared secret and return it
*
* @return \OC_OCS_Result
*/
public function getSharedSecret() {

$url = $this->request->getParam('url');
$token = $this->request->getParam('token');

if (
$this->trustedServers->isTrustedServer($url) === false
|| $this->isValidToken($url, $token) === false
) {
return new \OC_OCS_Result(null, HTTP::STATUS_FORBIDDEN);
}

$sharedSecret = $this->secureRandom->getMediumStrengthGenerator()->generate(32);

$this->trustedServers->addSharedSecret($url, $sharedSecret);

return new \OC_OCS_Result(['sharedSecret' => $sharedSecret], Http::STATUS_OK);

}

protected function isValidToken($url, $token) {
$storedToken = $this->dbHandler->getToken($url);
return StringUtils::equals($storedToken, $token);
}

}

+ 53
- 3
apps/federation/appinfo/application.php Datei anzeigen

@@ -21,13 +21,15 @@

namespace OCA\Federation\AppInfo;

use OCA\Federation\API\OCSAuthAPI;
use OCA\Federation\Controller\AuthController;
use OCA\Federation\Controller\SettingsController;
use OCA\Federation\DbHandler;
use OCA\Federation\Middleware\AddServerMiddleware;
use OCA\Federation\TrustedServers;
use OCP\API;
use OCP\App;
use OCP\AppFramework\IAppContainer;
use OCP\IAppConfig;

class Application extends \OCP\AppFramework\App {

@@ -38,7 +40,6 @@ class Application extends \OCP\AppFramework\App {
parent::__construct('federation', $urlParams);
$this->registerService();
$this->registerMiddleware();

}

/**
@@ -70,7 +71,9 @@ class Application extends \OCP\AppFramework\App {
return new TrustedServers(
$c->query('DbHandler'),
\OC::$server->getHTTPClientService(),
\OC::$server->getLogger()
\OC::$server->getLogger(),
\OC::$server->getJobList(),
\OC::$server->getSecureRandom()
);
});

@@ -83,10 +86,57 @@ class Application extends \OCP\AppFramework\App {
$c->query('TrustedServers')
);
});


$container->registerService('AuthController', function (IAppContainer $c) {
$server = $c->getServer();
return new AuthController(
$c->getAppName(),
$server->getRequest(),
$server->getSecureRandom(),
$server->getJobList(),
$c->query('TrustedServers'),
$c->query('DbHandler')
);
});
}

private function registerMiddleware() {
$container = $this->getContainer();
$container->registerMiddleware('addServerMiddleware');
}

/**
* register OCS API Calls
*/
public function registerOCSApi() {

$container = $this->getContainer();
$server = $container->getServer();

$auth = new OCSAuthAPI(
$server->getRequest(),
$server->getSecureRandom(),
$server->getJobList(),
$container->query('TrustedServers'),
$container->query('DbHandler')

);

API::register('get',
'/apps/federation/api/v1/shared-secret',
array($auth, 'getSharedSecret'),
'federation',
API::GUEST_AUTH
);

API::register('post',
'/apps/federation/api/v1/request-shared-secret',
array($auth, 'requestSharedSecret'),
'federation',
API::GUEST_AUTH
);

}

}

+ 21
- 1
apps/federation/appinfo/database.xml Datei anzeigen

@@ -28,7 +28,27 @@
<default></default>
<notnull>true</notnull>
<length>32</length>
<comments>md5 hash of the url</comments>
<comments>md5 hash of the url without the protocol</comments>
</field>
<field>
<name>token</name>
<type>text</type>
<length>128</length>
<comments>toke used to exchange the shared secret</comments>
</field>
<field>
<name>shared_secret</name>
<type>text</type>
<length>256</length>
<comments>shared secret used to authenticate</comments>
</field>
<field>
<name>status</name>
<type>integer</type>
<length>4</length>
<notnull>true</notnull>
<default>2</default>
<comments>current status of the connection</comments>
</field>
<index>
<name>url_hash</name>

+ 21
- 14
apps/federation/appinfo/routes.php Datei anzeigen

@@ -19,17 +19,24 @@
*
*/

return [
'routes' => [
[
'name' => 'Settings#addServer',
'url' => '/trusted-servers',
'verb' => 'POST'
],
[
'name' => 'Settings#removeServer',
'url' => '/trusted-servers/{id}',
'verb' => 'DELETE'
],
]
];
$application = new \OCA\Federation\AppInfo\Application();

$application->registerRoutes(
$this,
[
'routes' => [
[
'name' => 'Settings#addServer',
'url' => '/trusted-servers',
'verb' => 'POST'
],
[
'name' => 'Settings#removeServer',
'url' => '/trusted-servers/{id}',
'verb' => 'DELETE'
],
]
]
);

$application->registerOCSApi();

+ 155
- 0
apps/federation/backgroundjob/getsharedsecret.php Datei anzeigen

@@ -0,0 +1,155 @@
<?php
/**
* @author Björn Schießle <schiessle@owncloud.com>
*
* @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 <http://www.gnu.org/licenses/>
*
*/


namespace OCA\Federation\BackgroundJob;

use OC\BackgroundJob\QueuedJob;
use OCA\Federation\DbHandler;
use OCA\Federation\TrustedServers;
use OCP\AppFramework\Http;
use OCP\BackgroundJob\IJobList;
use OCP\Http\Client\IClient;
use OCP\ILogger;
use OCP\IURLGenerator;

/**
* Class GetSharedSecret
*
* request shared secret from remote ownCloud
*
* @package OCA\Federation\Backgroundjob
*/
class GetSharedSecret extends QueuedJob{

/** @var IClient */
private $httpClient;

/** @var IJobList */
private $jobList;

/** @var IURLGenerator */
private $urlGenerator;

/** @var TrustedServers */
private $trustedServers;

/** @var ILogger */
private $logger;

private $endPoint = '/ocs/v2.php/apps/federation/api/v1/shared-secret?format=json';

/**
* RequestSharedSecret constructor.
*
* @param IClient $httpClient
* @param IURLGenerator $urlGenerator
* @param IJobList $jobList
* @param TrustedServers $trustedServers
* @param ILogger $logger
*/
public function __construct(
IClient $httpClient = null,
IURLGenerator $urlGenerator = null,
IJobList $jobList = null,
TrustedServers $trustedServers = null,
ILogger $logger = null
) {
$this->logger = $logger ? $logger : \OC::$server->getLogger();
$this->httpClient = $httpClient ? $httpClient : \OC::$server->getHTTPClientService()->newClient();
$this->jobList = $jobList ? $jobList : \OC::$server->getJobList();
$this->urlGenerator = $urlGenerator ? $urlGenerator : \OC::$server->getURLGenerator();
if ($trustedServers) {
$this->trustedServers = $trustedServers;
} else {
$this->trustedServers = new TrustedServers(
new DbHandler(\OC::$server->getDatabaseConnection(), \OC::$server->getL10N('federation')),
\OC::$server->getHTTPClientService(),
\OC::$server->getLogger(),
$this->jobList,
\OC::$server->getSecureRandom()
);
}
}

/**
* run the job, then remove it from the joblist
*
* @param JobList $jobList
* @param ILogger $logger
*/
public function execute($jobList, ILogger $logger = null) {
$jobList->remove($this, $this->argument);
$target = $this->argument['url'];
// only execute if target is still in the list of trusted domains
if ($this->trustedServers->isTrustedServer($target)) {
parent::execute($jobList, $logger);
}
}

protected function run($argument) {
$target = $argument['url'];
$source = $this->urlGenerator->getAbsoluteURL('/');
$source = rtrim($source, '/');
$token = $argument['token'];

$result = $this->httpClient->get(
$target . $this->endPoint,
[
'query' =>
[
'url' => $source,
'token' => $token
],
'timeout' => 3,
'connect_timeout' => 3,
]
);

$status = $result->getStatusCode();

// if we received a unexpected response we try again later
if (
$status !== Http::STATUS_OK
&& $status !== Http::STATUS_FORBIDDEN
) {
$this->jobList->add(
'OCA\Federation\Backgroundjob\RequestSharedSecret',
$argument
);
} elseif ($status === Http::STATUS_OK) {
$body = $result->getBody();
$result = json_decode($body, true);
if (isset($result['ocs']['data']['sharedSecret'])) {
$this->trustedServers->addSharedSecret(
$target,
$result['ocs']['data']['sharedSecret']
);
} else {
$this->logger->error(
'remote server "' . $target . '"" does not return a valid shared secret',
['app' => 'federation']
);
$this->trustedServers->setServerStatus($target, TrustedServers::STATUS_FAILURE);
}
}
}
}

+ 134
- 0
apps/federation/backgroundjob/requestsharedsecret.php Datei anzeigen

@@ -0,0 +1,134 @@
<?php
/**
* @author Björn Schießle <schiessle@owncloud.com>
*
* @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 <http://www.gnu.org/licenses/>
*
*/


namespace OCA\Federation\BackgroundJob;


use OC\BackgroundJob\QueuedJob;
use OCA\Federation\DbHandler;
use OCA\Federation\TrustedServers;
use OCP\AppFramework\Http;
use OCP\BackgroundJob\IJobList;
use OCP\Http\Client\IClient;
use OCP\ILogger;
use OCP\IURLGenerator;

/**
* Class RequestSharedSecret
*
* Ask remote ownCloud to request a sharedSecret from this server
*
* @package OCA\Federation\Backgroundjob
*/
class RequestSharedSecret extends QueuedJob {

/** @var IClient */
private $httpClient;

/** @var IJobList */
private $jobList;

/** @var IURLGenerator */
private $urlGenerator;

private $endPoint = '/ocs/v2.php/apps/federation/api/v1/request-shared-secret?format=json';

/**
* RequestSharedSecret constructor.
*
* @param IClient $httpClient
* @param IURLGenerator $urlGenerator
* @param IJobList $jobList
* @param TrustedServers $trustedServers
*/
public function __construct(
IClient $httpClient = null,
IURLGenerator $urlGenerator = null,
IJobList $jobList = null,
TrustedServers $trustedServers = null
) {
$this->httpClient = $httpClient ? $httpClient : \OC::$server->getHTTPClientService()->newClient();
$this->jobList = $jobList ? $jobList : \OC::$server->getJobList();
$this->urlGenerator = $urlGenerator ? $urlGenerator : \OC::$server->getURLGenerator();
if ($trustedServers) {
$this->trustedServers = $trustedServers;
} else {
$this->trustedServers = new TrustedServers(
new DbHandler(\OC::$server->getDatabaseConnection(), \OC::$server->getL10N('federation')),
\OC::$server->getHTTPClientService(),
\OC::$server->getLogger(),
$this->jobList,
\OC::$server->getSecureRandom()
);
}
}


/**
* run the job, then remove it from the joblist
*
* @param JobList $jobList
* @param ILogger $logger
*/
public function execute($jobList, ILogger $logger = null) {
$jobList->remove($this, $this->argument);
$target = $this->argument['url'];
// only execute if target is still in the list of trusted domains
if ($this->trustedServers->isTrustedServer($target)) {
parent::execute($jobList, $logger);
}
}

protected function run($argument) {

$target = $argument['url'];
$source = $this->urlGenerator->getAbsoluteURL('/');
$source = rtrim($source, '/');
$token = $argument['token'];

$result = $this->httpClient->post(
$target . $this->endPoint,
[
'body' => [
'url' => $source,
'token' => $token,
],
'timeout' => 3,
'connect_timeout' => 3,
]
);

$status = $result->getStatusCode();

// if we received a unexpected response we try again later
if (
$status !== Http::STATUS_OK
&& $status !== Http::STATUS_FORBIDDEN
) {
$this->jobList->add(
'OCA\Federation\BackgroundJob\RequestSharedSecret',
$argument
);
}

}
}

+ 152
- 30
apps/federation/lib/dbhandler.php Datei anzeigen

@@ -23,10 +23,19 @@
namespace OCA\Federation;


use OC\Files\Filesystem;
use OC\HintException;
use OCP\IDBConnection;
use OCP\IL10N;

/**
* Class DbHandler
*
* handles all database calls for the federation app
*
* @group DB
* @package OCA\Federation
*/
class DbHandler {

/** @var IDBConnection */
@@ -53,12 +62,12 @@ class DbHandler {
/**
* add server to the list of trusted ownCloud servers
*
* @param $url
* @param string $url
* @return int
* @throws HintException
*/
public function add($url) {
$hash = md5($url);
public function addServer($url) {
$hash = $this->hash($url);
$query = $this->connection->getQueryBuilder();
$query->insert($this->dbTable)
->values(
@@ -73,14 +82,7 @@ class DbHandler {
$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;
return $this->connection->lastInsertId($this->dbTable);
} else {
$message = 'Internal failure, Could not add ownCloud as trusted server: ' . $url;
$message_t = $this->l->t('Could not add server');
@@ -93,7 +95,7 @@ class DbHandler {
*
* @param int $id
*/
public function remove($id) {
public function removeServer($id) {
$query = $this->connection->getQueryBuilder();
$query->delete($this->dbTable)
->where($query->expr()->eq('id', $query->createParameter('id')))
@@ -101,27 +103,12 @@ class DbHandler {
$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() {
public function getAllServer() {
$query = $this->connection->getQueryBuilder();
$query->select('url', 'id')->from($this->dbTable);
$result = $query->execute()->fetchAll();
@@ -134,14 +121,149 @@ class DbHandler {
* @param string $url
* @return bool
*/
public function exists($url) {
public function serverExists($url) {
$hash = $this->hash($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));
->setParameter('url_hash', $hash);
$result = $query->execute()->fetchAll();

return !empty($result);
}

/**
* write token to database. Token is used to exchange the secret
*
* @param string $url
* @param string $token
*/
public function addToken($url, $token) {
$hash = $this->hash($url);
$query = $this->connection->getQueryBuilder();
$query->update($this->dbTable)
->set('token', $query->createParameter('token'))
->where($query->expr()->eq('url_hash', $query->createParameter('url_hash')))
->setParameter('url_hash', $hash)
->setParameter('token', $token);
$query->execute();
}

/**
* get token stored in database
*
* @param string $url
* @return string
*/
public function getToken($url) {
$hash = $this->hash($url);
$query = $this->connection->getQueryBuilder();
$query->select('token')->from($this->dbTable)
->where($query->expr()->eq('url_hash', $query->createParameter('url_hash')))
->setParameter('url_hash', $hash);

$result = $query->execute()->fetch();
return $result['token'];
}

/**
* add shared Secret to database
*
* @param string $url
* @param string $sharedSecret
*/
public function addSharedSecret($url, $sharedSecret) {
$hash = $this->hash($url);
$query = $this->connection->getQueryBuilder();
$query->update($this->dbTable)
->set('shared_secret', $query->createParameter('sharedSecret'))
->where($query->expr()->eq('url_hash', $query->createParameter('url_hash')))
->setParameter('url_hash', $hash)
->setParameter('sharedSecret', $sharedSecret);
$query->execute();
}

/**
* get shared secret from database
*
* @param string $url
* @return string
*/
public function getSharedSecret($url) {
$hash = $this->hash($url);
$query = $this->connection->getQueryBuilder();
$query->select('shared_secret')->from($this->dbTable)
->where($query->expr()->eq('url_hash', $query->createParameter('url_hash')))
->setParameter('url_hash', $hash);

$result = $query->execute()->fetch();
return $result['shared_secret'];
}

/**
* set server status
*
* @param string $url
* @param int $status
*/
public function setServerStatus($url, $status) {
$hash = $this->hash($url);
$query = $this->connection->getQueryBuilder();
$query->update($this->dbTable)
->set('status', $query->createParameter('status'))
->where($query->expr()->eq('url_hash', $query->createParameter('url_hash')))
->setParameter('url_hash', $hash)
->setParameter('status', $status);
$query->execute();
}

/**
* get server status
*
* @param string $url
* @return int
*/
public function getServerStatus($url) {
$hash = $this->hash($url);
$query = $this->connection->getQueryBuilder();
$query->select('status')->from($this->dbTable)
->where($query->expr()->eq('url_hash', $query->createParameter('url_hash')))
->setParameter('url_hash', $hash);

$result = $query->execute()->fetch();
return $result['status'];
}

/**
* create hash from URL
*
* @param string $url
* @return string
*/
protected function hash($url) {
$normalized = $this->normalizeUrl($url);
return md5($normalized);
}

/**
* normalize URL, used to create the md5 hash
*
* @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;
}

}

+ 85
- 20
apps/federation/lib/trustedservers.php Datei anzeigen

@@ -22,15 +22,21 @@

namespace OCA\Federation;


use OC\Files\Filesystem;
use OCP\AppFramework\Http;
use OCP\BackgroundJob\IJobList;
use OCP\Http\Client\IClientService;
use OCP\IDBConnection;
use OCP\ILogger;
use OCP\Security\ISecureRandom;

class TrustedServers {

/** after a user list was exchanged at least once successfully */
const STATUS_OK = 1;
/** waiting for shared secret or initial user list exchange */
const STATUS_PENDING = 2;
/** something went wrong, misconfigured server, software bug,... user interaction needed */
const STATUS_FAILURE = 3;

/** @var dbHandler */
private $dbHandler;

@@ -40,21 +46,31 @@ class TrustedServers {
/** @var ILogger */
private $logger;

private $dbTable = 'trusted_servers';
/** @var IJobList */
private $jobList;

/** @var ISecureRandom */
private $secureRandom;

/**
* @param DbHandler $dbHandler
* @param IClientService $httpClientService
* @param ILogger $logger
* @param IJobList $jobList
* @param ISecureRandom $secureRandom
*/
public function __construct(
DbHandler $dbHandler,
IClientService $httpClientService,
ILogger $logger
ILogger $logger,
IJobList $jobList,
ISecureRandom $secureRandom
) {
$this->dbHandler = $dbHandler;
$this->httpClientService = $httpClientService;
$this->logger = $logger;
$this->jobList = $jobList;
$this->secureRandom = $secureRandom;
}

/**
@@ -64,7 +80,41 @@ class TrustedServers {
* @return int server id
*/
public function addServer($url) {
return $this->dbHandler->add($this->normalizeUrl($url));
$url = $this->updateProtocol($url);
$result = $this->dbHandler->addServer($url);
if ($result) {
$token = $this->secureRandom->getMediumStrengthGenerator()->generate(16);
$this->dbHandler->addToken($url, $token);
$this->jobList->add(
'OCA\Federation\BackgroundJob\RequestSharedSecret',
[
'url' => $url,
'token' => $token
]
);
}

return $result;
}

/**
* get shared secret for the given server
*
* @param string $url
* @return string
*/
public function getSharedSecret($url) {
return $this->dbHandler->getSharedSecret($url);
}

/**
* add shared secret for the given server
*
* @param string $url
* @param $sharedSecret
*/
public function addSharedSecret($url, $sharedSecret) {
$this->dbHandler->addSharedSecret($url, $sharedSecret);
}

/**
@@ -73,7 +123,7 @@ class TrustedServers {
* @param int $id
*/
public function removeServer($id) {
$this->dbHandler->remove($id);
$this->dbHandler->removeServer($id);
}

/**
@@ -82,7 +132,7 @@ class TrustedServers {
* @return array
*/
public function getServers() {
return $this->dbHandler->getAll();
return $this->dbHandler->getAllServer();
}

/**
@@ -92,7 +142,25 @@ class TrustedServers {
* @return bool
*/
public function isTrustedServer($url) {
return $this->dbHandler->exists($this->normalizeUrl($url));
return $this->dbHandler->serverExists($url);
}

/**
* set server status
*
* @param string $url
* @param int $status
*/
public function setServerStatus($url, $status) {
$this->dbHandler->setServerStatus($url, $status);
}

/**
* @param string $url
* @return int
*/
public function getServerStatus($url) {
return $this->dbHandler->getServerStatus($url);
}

/**
@@ -137,24 +205,21 @@ class TrustedServers {
}

/**
* normalize URL
* check if the URL contain a protocol, if not add https
*
* @param string $url
* @return string
*/
protected function normalizeUrl($url) {
protected function updateProtocol($url) {
if (
strpos($url, 'https://') === 0
|| strpos($url, 'http://') === 0
) {

$normalized = $url;
return $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;
return 'https://' . $url;
}
}

+ 3
- 1
apps/federation/settings/settings-admin.php Datei anzeigen

@@ -31,7 +31,9 @@ $dbHandler = new \OCA\Federation\DbHandler(
$trustedServers = new \OCA\Federation\TrustedServers(
$dbHandler,
\OC::$server->getHTTPClientService(),
\OC::$server->getLogger()
\OC::$server->getLogger(),
\OC::$server->getJobList(),
\OC::$server->getSecureRandom()
);

$template->assign('trustedServers', $trustedServers->getServers());

+ 184
- 0
apps/federation/tests/api/ocsauthapitest.php Datei anzeigen

@@ -0,0 +1,184 @@
<?php
/**
* @author Björn Schießle <schiessle@owncloud.com>
*
* @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 <http://www.gnu.org/licenses/>
*
*/


namespace OCA\Federation\Tests\API;


use OC\BackgroundJob\JobList;
use OCA\Federation\API\OCSAuthAPI;
use OCA\Federation\DbHandler;
use OCA\Federation\TrustedServers;
use OCP\AppFramework\Http;
use OCP\IRequest;
use OCP\Security\ISecureRandom;
use Test\TestCase;

class OCSAuthAPITest extends TestCase {

/** @var \PHPUnit_Framework_MockObject_MockObject | IRequest */
private $request;

/** @var \PHPUnit_Framework_MockObject_MockObject | ISecureRandom */
private $secureRandom;

/** @var \PHPUnit_Framework_MockObject_MockObject | JobList */
private $jobList;

/** @var \PHPUnit_Framework_MockObject_MockObject | TrustedServers */
private $trustedServers;

/** @var \PHPUnit_Framework_MockObject_MockObject | DbHandler */
private $dbHandler;

/** @var OCSAuthApi */
private $ocsAuthApi;

public function setUp() {
parent::setUp();

$this->request = $this->getMock('OCP\IRequest');
$this->secureRandom = $this->getMock('OCP\Security\ISecureRandom');
$this->trustedServers = $this->getMockBuilder('OCA\Federation\TrustedServers')
->disableOriginalConstructor()->getMock();
$this->dbHandler = $this->getMockBuilder('OCA\Federation\DbHandler')
->disableOriginalConstructor()->getMock();
$this->jobList = $this->getMockBuilder('OC\BackgroundJob\JobList')
->disableOriginalConstructor()->getMock();

$this->ocsAuthApi = new OCSAuthAPI(
$this->request,
$this->secureRandom,
$this->jobList,
$this->trustedServers,
$this->dbHandler
);

}

/**
* @dataProvider dataTestRequestSharedSecret
*
* @param string $token
* @param string $localToken
* @param bool $isTrustedServer
* @param int $expected
*/
public function testRequestSharedSecret($token, $localToken, $isTrustedServer, $expected) {

$url = 'url';

$this->request->expects($this->at(0))->method('getParam')->with('url')->willReturn($url);
$this->request->expects($this->at(1))->method('getParam')->with('token')->willReturn($token);
$this->trustedServers
->expects($this->once())
->method('isTrustedServer')->with($url)->willReturn($isTrustedServer);
$this->dbHandler->expects($this->any())
->method('getToken')->with($url)->willReturn($localToken);

if ($expected === Http::STATUS_OK) {
$this->jobList->expects($this->once())->method('add')
->with('OCA\Federation\BackgroundJob\GetSharedSecret', ['url' => $url, 'token' => $token]);
} else {
$this->jobList->expects($this->never())->method('add');
}

$result = $this->ocsAuthApi->requestSharedSecret();
$this->assertSame($expected, $result->getStatusCode());
}

public function dataTestRequestSharedSecret() {
return [
['token2', 'token1', true, Http::STATUS_OK],
['token1', 'token2', false, Http::STATUS_FORBIDDEN],
['token1', 'token2', true, Http::STATUS_FORBIDDEN],
];
}

/**
* @dataProvider dataTestGetSharedSecret
*
* @param bool $isTrustedServer
* @param bool $isValidToken
* @param int $expected
*/
public function testGetSharedSecret($isTrustedServer, $isValidToken, $expected) {

$url = 'url';
$token = 'token';

$this->request->expects($this->at(0))->method('getParam')->with('url')->willReturn($url);
$this->request->expects($this->at(1))->method('getParam')->with('token')->willReturn($token);

/** @var OCSAuthAPI | \PHPUnit_Framework_MockObject_MockObject $ocsAuthApi */
$ocsAuthApi = $this->getMockBuilder('OCA\Federation\API\OCSAuthAPI')
->setConstructorArgs(
[
$this->request,
$this->secureRandom,
$this->jobList,
$this->trustedServers,
$this->dbHandler
]
)->setMethods(['isValidToken'])->getMock();

$this->trustedServers
->expects($this->any())
->method('isTrustedServer')->with($url)->willReturn($isTrustedServer);
$ocsAuthApi->expects($this->any())
->method('isValidToken')->with($url, $token)->willReturn($isValidToken);

if($expected === Http::STATUS_OK) {
$this->secureRandom->expects($this->once())->method('getMediumStrengthGenerator')
->willReturn($this->secureRandom);
$this->secureRandom->expects($this->once())->method('generate')->with(32)
->willReturn('secret');
$this->trustedServers->expects($this->once())
->method('addSharedSecret')->willReturn($url, 'secret');
$this->dbHandler->expects($this->once())
->method('addToken')->with($url, '');
} else {
$this->secureRandom->expects($this->never())->method('getMediumStrengthGenerator');
$this->secureRandom->expects($this->never())->method('generate');
$this->trustedServers->expects($this->never())->method('addSharedSecret');
$this->dbHandler->expects($this->never())->method('addToken');
}

$result = $ocsAuthApi->getSharedSecret();

$this->assertSame($expected, $result->getStatusCode());

if ($expected === Http::STATUS_OK) {
$data = $result->getData();
$this->assertSame('secret', $data['sharedSecret']);
}
}

public function dataTestGetSharedSecret() {
return [
[true, true, Http::STATUS_OK],
[false, true, Http::STATUS_FORBIDDEN],
[true, false, Http::STATUS_FORBIDDEN],
[false, false, Http::STATUS_FORBIDDEN],
];
}

}

+ 35
- 10
apps/federation/tests/lib/dbhandlertest.php Datei anzeigen

@@ -27,6 +27,9 @@ use OCA\Federation\DbHandler;
use OCP\IDBConnection;
use Test\TestCase;

/**
* @group DB
*/
class DbHandlerTest extends TestCase {

/** @var DbHandler */
@@ -63,8 +66,8 @@ class DbHandlerTest extends TestCase {
$query->execute();
}

public function testAdd() {
$id = $this->dbHandler->add('server1');
public function testAddServer() {
$id = $this->dbHandler->addServer('server1');

$query = $this->connection->getQueryBuilder()->select('*')->from($this->dbTable);
$result = $query->execute()->fetchAll();
@@ -74,8 +77,8 @@ class DbHandlerTest extends TestCase {
}

public function testRemove() {
$id1 = $this->dbHandler->add('server1');
$id2 = $this->dbHandler->add('server2');
$id1 = $this->dbHandler->addServer('server1');
$id2 = $this->dbHandler->addServer('server2');

$query = $this->connection->getQueryBuilder()->select('*')->from($this->dbTable);
$result = $query->execute()->fetchAll();
@@ -85,7 +88,7 @@ class DbHandlerTest extends TestCase {
$this->assertSame($id1, $result[0]['id']);
$this->assertSame($id2, $result[1]['id']);

$this->dbHandler->remove($id2);
$this->dbHandler->removeServer($id2);
$query = $this->connection->getQueryBuilder()->select('*')->from($this->dbTable);
$result = $query->execute()->fetchAll();
$this->assertSame(1, count($result));
@@ -94,10 +97,10 @@ class DbHandlerTest extends TestCase {
}

public function testGetAll() {
$id1 = $this->dbHandler->add('server1');
$id2 = $this->dbHandler->add('server2');
$id1 = $this->dbHandler->addServer('server1');
$id2 = $this->dbHandler->addServer('server2');

$result = $this->dbHandler->getAll();
$result = $this->dbHandler->getAllServer();
$this->assertSame(2, count($result));
$this->assertSame('server1', $result[0]['url']);
$this->assertSame('server2', $result[1]['url']);
@@ -113,9 +116,9 @@ class DbHandlerTest extends TestCase {
* @param bool $expected
*/
public function testExists($serverInTable, $checkForServer, $expected) {
$this->dbHandler->add($serverInTable);
$this->dbHandler->addServer($serverInTable);
$this->assertSame($expected,
$this->dbHandler->exists($checkForServer)
$this->dbHandler->serverExists($checkForServer)
);
}

@@ -127,4 +130,26 @@ class DbHandlerTest extends TestCase {
];
}

/**
* @dataProvider dataTestNormalizeUrl
*
* @param string $url
* @param string $expected
*/
public function testNormalizeUrl($url, $expected) {
$this->assertSame($expected,
$this->invokePrivate($this->dbHandler, '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'],
];
}

}

+ 73
- 40
apps/federation/tests/lib/trustedserverstest.php Datei anzeigen

@@ -25,11 +25,13 @@ namespace OCA\Federation\Tests\lib;

use OCA\Federation\DbHandler;
use OCA\Federation\TrustedServers;
use OCP\BackgroundJob\IJobList;
use OCP\Http\Client\IClient;
use OCP\Http\Client\IClientService;
use OCP\Http\Client\IResponse;
use OCP\IDBConnection;
use OCP\IConfig;
use OCP\ILogger;
use OCP\Security\ISecureRandom;
use Test\TestCase;

class TrustedServersTest extends TestCase {
@@ -52,6 +54,15 @@ class TrustedServersTest extends TestCase {
/** @var \PHPUnit_Framework_MockObject_MockObject | ILogger */
private $logger;

/** @var \PHPUnit_Framework_MockObject_MockObject | IJobList */
private $jobList;

/** @var \PHPUnit_Framework_MockObject_MockObject | ISecureRandom */
private $secureRandom;

/** @var \PHPUnit_Framework_MockObject_MockObject | IConfig */
private $config;

public function setUp() {
parent::setUp();

@@ -61,45 +72,79 @@ class TrustedServersTest extends TestCase {
$this->httpClient = $this->getMock('OCP\Http\Client\IClient');
$this->response = $this->getMock('OCP\Http\Client\IResponse');
$this->logger = $this->getMock('OCP\ILogger');
$this->jobList = $this->getMock('OCP\BackgroundJob\IJobList');
$this->secureRandom = $this->getMock('OCP\Security\ISecureRandom');
$this->config = $this->getMock('OCP\IConfig');

$this->trustedServers = new TrustedServers(
$this->dbHandler,
$this->httpClientService,
$this->logger
$this->logger,
$this->jobList,
$this->secureRandom,
$this->config
);

}

public function testAddServer() {
/**
* @dataProvider dataTestAddServer
*
* @param bool $success
*/
public function testAddServer($success) {
/** @var \PHPUnit_Framework_MockObject_MockObject | TrustedServers $trustedServer */
$trustedServers = $this->getMockBuilder('OCA\Federation\TrustedServers')
->setConstructorArgs(
[
$this->dbHandler,
$this->httpClientService,
$this->logger
$this->logger,
$this->jobList,
$this->secureRandom,
$this->config
]
)
->setMethods(['normalizeUrl'])
->setMethods(['normalizeUrl', 'updateProtocol'])
->getMock();
$trustedServers->expects($this->once())->method('normalizeUrl')
->with('url')->willReturn('normalized');
$this->dbHandler->expects($this->once())->method('add')->with('normalized')
->willReturn(true);
$trustedServers->expects($this->once())->method('updateProtocol')
->with('url')->willReturn('https://url');
$this->dbHandler->expects($this->once())->method('addServer')->with('https://url')
->willReturn($success);

if ($success) {
$this->secureRandom->expects($this->once())->method('getMediumStrengthGenerator')
->willReturn($this->secureRandom);
$this->secureRandom->expects($this->once())->method('generate')
->willReturn('token');
$this->dbHandler->expects($this->once())->method('addToken')->with('https://url', 'token');
$this->jobList->expects($this->once())->method('add')
->with('OCA\Federation\BackgroundJob\RequestSharedSecret',
['url' => 'https://url', 'token' => 'token']);
} else {
$this->jobList->expects($this->never())->method('add');
}

$this->assertTrue(
$this->assertSame($success,
$trustedServers->addServer('url')
);
}

public function dataTestAddServer() {
return [
[true],
[false]
];
}

public function testRemoveServer() {
$id = 42;
$this->dbHandler->expects($this->once())->method('remove')->with($id);
$this->dbHandler->expects($this->once())->method('removeServer')->with($id);
$this->trustedServers->removeServer($id);
}

public function testGetServers() {
$this->dbHandler->expects($this->once())->method('getAll')->willReturn(true);
$this->dbHandler->expects($this->once())->method('getAllServer')->willReturn(true);

$this->assertTrue(
$this->trustedServers->getServers()
@@ -108,24 +153,11 @@ class TrustedServersTest extends TestCase {


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->dbHandler->expects($this->once())->method('serverExists')->with('url')
->willReturn(true);

$this->assertTrue(
$trustedServers->isTrustedServer('url')
$this->trustedServers->isTrustedServer('url')
);
}

@@ -146,7 +178,10 @@ class TrustedServersTest extends TestCase {
[
$this->dbHandler,
$this->httpClientService,
$this->logger
$this->logger,
$this->jobList,
$this->secureRandom,
$this->config
]
)
->setMethods(['checkOwnCloudVersion'])
@@ -192,7 +227,7 @@ class TrustedServersTest extends TestCase {
->with('simulated exception', ['app' => 'federation']);

$this->httpClient->expects($this->once())->method('get')->with($server . '/status.php')
->willReturnCallback(function() {
->willReturnCallback(function () {
throw new \Exception('simulated exception');
});

@@ -221,24 +256,22 @@ class TrustedServersTest extends TestCase {
}

/**
* @dataProvider dataTestNormalizeUrl
*
* @dataProvider dataTestUpdateProtocol
* @param string $url
* @param string $expected
*/
public function testNormalizeUrl($url, $expected) {
public function testUpdateProtocol($url, $expected) {
$this->assertSame($expected,
$this->invokePrivate($this->trustedServers, 'normalizeUrl', [$url])
$this->invokePrivate($this->trustedServers, 'updateProtocol', [$url])
);
}

public function dataTestNormalizeUrl() {
public function dataTestUpdateProtocol() {
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'],
['http://owncloud.org', 'http://owncloud.org'],
['https://owncloud.org', 'https://owncloud.org'],
['owncloud.org', 'https://owncloud.org'],
['httpserver', 'https://httpserver'],
];
}
}

Laden…
Abbrechen
Speichern