diff --git a/.gitignore b/.gitignore
index 531e372e6074013d352aabf8db545c5501672dd5..3fb848dbb44f6ae718eda6d1f9851750fcbab965 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 0000000000000000000000000000000000000000..9ed00f23866330f02474e64395426f86c74c33fb
--- /dev/null
+++ b/apps/federation/appinfo/app.php
@@ -0,0 +1,25 @@
+<?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\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 0000000000000000000000000000000000000000..46a791c25d07251ae3da71f50b7608d3bafa4ff2
--- /dev/null
+++ b/apps/federation/appinfo/application.php
@@ -0,0 +1,92 @@
+<?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\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 0000000000000000000000000000000000000000..da16212ca1976444704d950ae571724cd6564288
--- /dev/null
+++ b/apps/federation/appinfo/database.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<database>
+	<name>*dbname*</name>
+	<create>true</create>
+	<overwrite>false</overwrite>
+	<charset>utf8</charset>
+	<table>
+		<name>*dbprefix*trusted_servers</name>
+		<declaration>
+			<field>
+				<name>id</name>
+				<type>integer</type>
+				<default>0</default>
+				<notnull>true</notnull>
+				<autoincrement>1</autoincrement>
+				<length>4</length>
+			</field>
+			<field>
+				<name>url</name>
+				<type>text</type>
+				<notnull>true</notnull>
+				<length>512</length>
+				<comments>Url of trusted server</comments>
+			</field>
+			<field>
+				<name>url_hash</name>
+				<type>text</type>
+				<default></default>
+				<notnull>true</notnull>
+				<length>32</length>
+				<comments>md5 hash of the url</comments>
+			</field>
+			<index>
+				<name>url_hash</name>
+				<unique>true</unique>
+				<field>
+					<name>url_hash</name>
+					<sorting>ascending</sorting>
+				</field>
+			</index>
+		</declaration>
+	</table>
+</database>
diff --git a/apps/federation/appinfo/info.xml b/apps/federation/appinfo/info.xml
new file mode 100644
index 0000000000000000000000000000000000000000..53b2926ba539886299b42f193d5964d63cd9f04b
--- /dev/null
+++ b/apps/federation/appinfo/info.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0"?>
+<info>
+    <id>federation</id>
+    <name>Federation</name>
+    <description>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.</description>
+    <licence>AGPL</licence>
+    <author>Bjoern Schiessle</author>
+    <version>0.0.1</version>
+    <namespace>Federation</namespace>
+    <category>other</category>
+    <dependencies>
+        <owncloud min-version="9.0" />
+    </dependencies>
+</info>
diff --git a/apps/federation/appinfo/routes.php b/apps/federation/appinfo/routes.php
new file mode 100644
index 0000000000000000000000000000000000000000..43ccc4ed504d0644ea60db7c5454fc1568988a8a
--- /dev/null
+++ b/apps/federation/appinfo/routes.php
@@ -0,0 +1,35 @@
+<?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/>
+ *
+ */
+
+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 0000000000000000000000000000000000000000..8d522328120951ca0aa1790af3183e3cbaf06224
--- /dev/null
+++ b/apps/federation/controller/settingscontroller.php
@@ -0,0 +1,112 @@
+<?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\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 0000000000000000000000000000000000000000..7dbc949270f73864f1583b40d18ab944a779823f
--- /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 0000000000000000000000000000000000000000..a1f02a09efe29e76443f4c127533351de5e0adca
--- /dev/null
+++ b/apps/federation/js/settings-admin.js
@@ -0,0 +1,70 @@
+/**
+ * @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/>
+ *
+ */
+
+$(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(
+						$('<li>').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 0000000000000000000000000000000000000000..1100875cc2392e98151416089c9c2626715e7825
--- /dev/null
+++ b/apps/federation/lib/dbhandler.php
@@ -0,0 +1,147 @@
+<?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;
+
+
+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 0000000000000000000000000000000000000000..bf31277b2a8bcaa48661a94c5643610d25ac1e92
--- /dev/null
+++ b/apps/federation/lib/trustedservers.php
@@ -0,0 +1,160 @@
+<?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;
+
+
+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 0000000000000000000000000000000000000000..56552021dc268ff5393771181c8305c6b32d2bfb
--- /dev/null
+++ b/apps/federation/middleware/addservermiddleware.php
@@ -0,0 +1,71 @@
+<?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\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 0000000000000000000000000000000000000000..ea71475d619a78de4736d0be55bb00149e4c5058
--- /dev/null
+++ b/apps/federation/settings/settings-admin.php
@@ -0,0 +1,39 @@
+<?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/>
+ *
+ */
+
+\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 0000000000000000000000000000000000000000..faa1e3931580d475d62cf092719344d1af0374a3
--- /dev/null
+++ b/apps/federation/templates/settings-admin.php
@@ -0,0 +1,31 @@
+<?php
+/** @var array $_ */
+/** @var OC_L10N $l */
+script('federation', 'settings-admin');
+style('federation', 'settings-admin')
+?>
+<div id="ocFederationSettings" class="section">
+	<h2><?php p($l->t('Federation')); ?></h2>
+	<em><?php p($l->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.')); ?></em>
+
+	<p id="ocFederationShareUsers">
+		<input type="checkbox" class="checkbox" id="shareUsers" />
+		<label for="shareUsers">Share internal user list with other ownClouds</label>
+	</p>
+
+	<h3>Trusted ownCloud Servers</h3>
+	<p id="ocFederationAddServer">
+		<button id="ocFederationAddServerButton" class="">+ Add ownCloud server</button>
+		<input id="serverUrl" class="hidden" type="text" value="" placeholder="ownCloud Server" name="server_url"/>
+		<span class="msg"></span>
+	</p>
+	<ul id="listOfTrustedServers">
+		<?php foreach($_['trustedServers'] as $trustedServer) { ?>
+			<li id="<?php p($trustedServer['id']); ?>">
+				<?php p($trustedServer['url']); ?>
+			</li>
+		<?php } ?>
+	</ul>
+
+</div>
+
diff --git a/apps/federation/tests/controller/settingscontrollertest.php b/apps/federation/tests/controller/settingscontrollertest.php
new file mode 100644
index 0000000000000000000000000000000000000000..efbc6911c52acbd3ed95f0a6c439802a82cab41e
--- /dev/null
+++ b/apps/federation/tests/controller/settingscontrollertest.php
@@ -0,0 +1,166 @@
+<?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\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 0000000000000000000000000000000000000000..202199d2b5b4d53a8ef98dbfaacc218cc6755616
--- /dev/null
+++ b/apps/federation/tests/lib/dbhandlertest.php
@@ -0,0 +1,130 @@
+<?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\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 0000000000000000000000000000000000000000..07aa75312749052ef267137e9e6abbdd0130106c
--- /dev/null
+++ b/apps/federation/tests/lib/trustedserverstest.php
@@ -0,0 +1,244 @@
+<?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\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 0000000000000000000000000000000000000000..1be5a34228563e8f8f21217a6594c834de02c379
--- /dev/null
+++ b/apps/federation/tests/middleware/addservermiddlewaretest.php
@@ -0,0 +1,100 @@
+<?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\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 464155b1f39abe79e5319cee501ae9d7e4c36158..6f2d1fa87173cb1d06491b56c69fbfccd231e5e1 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');