From 24993280edcf66f9daa5a5e82428fefef4a3ab56 Mon Sep 17 00:00:00 2001
From: Bjoern Schiessle <schiessle@owncloud.com>
Date: Thu, 4 Dec 2014 19:51:04 +0100
Subject: [PATCH] Next step in server-to-server sharing next generation, see
 #12285

Beside some small improvements and bug fixes this will probably the final state for OC8.

To test this you need to set up two ownCloud instances. Let's say:

URL: myPC/firstOwnCloud user: user1
URL: myPC/secondOwnCloud user: user2
Now user1 can share a file with user2 by entering the username and the URL to the second ownCloud to the share-drop-down, in this case "user2@myPC/secondOwnCloud".

The next time user2 login he will get a notification that he received a server-to-server share with the option to accept/decline it. If he accept it the share will be mounted. In both cases a event will be send back to user1 and add a notification to the activity stream that the share was accepted/declined.

If user1 decides to unshare the file again from user2 the share will automatically be removed from the second ownCloud server and user2 will see a notification in his activity stream that user1@myPC/firstOwnCloud has unshared the file/folder from him.
---
 apps/files_encryption/lib/hooks.php           |  13 +-
 apps/files_encryption/lib/util.php            |   8 +-
 apps/files_encryption/tests/share.php         |  99 +++++-
 apps/files_sharing/ajax/external.php          |  11 +-
 apps/files_sharing/api/server2server.php      |  51 ++-
 apps/files_sharing/appinfo/routes.php         |  22 +-
 apps/files_sharing/application.php            |  21 ++
 apps/files_sharing/js/external.js             |  95 ++++--
 apps/files_sharing/lib/activity.php           |   2 +-
 .../lib/connector/publicauth.php              |   2 +
 .../controllers/externalsharescontroller.php  |  86 +++++
 apps/files_sharing/lib/external/manager.php   | 136 +++++++-
 apps/files_sharing/lib/helper.php             |  28 +-
 apps/files_sharing/lib/share/file.php         |  14 +
 apps/files_sharing/lib/updater.php            |   7 +-
 apps/files_sharing/tests/server2server.php    |  41 ++-
 core/ajax/share.php                           |  17 +-
 core/js/share.js                              |  82 +++--
 lib/private/httphelper.php                    |  55 +++-
 lib/private/security/certificatemanager.php   |  16 +-
 lib/private/server.php                        |   2 +-
 lib/private/share/constants.php               |   4 +
 lib/private/share/helper.php                  |   2 +-
 lib/private/share/share.php                   | 293 ++++++++++++++----
 lib/public/share_backend.php                  |  12 +
 tests/lib/app/infoparser.php                  |   3 +-
 tests/lib/httphelper.php                      |  24 +-
 tests/lib/share/backend.php                   |   4 +
 tests/lib/share/share.php                     |  17 +
 tests/lib/updater.php                         |  28 +-
 30 files changed, 948 insertions(+), 247 deletions(-)
 create mode 100644 apps/files_sharing/lib/controllers/externalsharescontroller.php

diff --git a/apps/files_encryption/lib/hooks.php b/apps/files_encryption/lib/hooks.php
index bddfb7b254..7ddde0a311 100644
--- a/apps/files_encryption/lib/hooks.php
+++ b/apps/files_encryption/lib/hooks.php
@@ -25,8 +25,6 @@
 
 namespace OCA\Files_Encryption;
 
-use OC\Files\Filesystem;
-
 /**
  * Class for hook specific logic
  */
@@ -364,15 +362,16 @@ class Hooks {
 		if ($params['itemType'] === 'file' || $params['itemType'] === 'folder') {
 
 			$view = new \OC\Files\View('/');
-			$userId = \OCP\User::getUser();
+			$userId = $params['uidOwner'];
+			$userView = new \OC\Files\View('/' . $userId . '/files');
 			$util = new Util($view, $userId);
-			$path = \OC\Files\Filesystem::getPath($params['fileSource']);
+			$path = $userView->getPath($params['fileSource']);
 
 			// for group shares get a list of the group members
 			if ($params['shareType'] === \OCP\Share::SHARE_TYPE_GROUP) {
 				$userIds = \OC_Group::usersInGroup($params['shareWith']);
 			} else {
-				if ($params['shareType'] === \OCP\Share::SHARE_TYPE_LINK) {
+				if ($params['shareType'] === \OCP\Share::SHARE_TYPE_LINK || $params['shareType'] === \OCP\Share::SHARE_TYPE_REMOTE) {
 					$userIds = array($util->getPublicShareKeyId());
 				} else {
 					$userIds = array($params['shareWith']);
@@ -619,8 +618,8 @@ class Hooks {
 
 		// check if the user still has access to the file, otherwise delete share key
 		$sharingUsers = \OCP\Share::getUsersSharingFile($path, $user);
-		if (!in_array(\OCP\User::getUser(), $sharingUsers['users'])) {
-			Keymanager::delShareKey($view, array(\OCP\User::getUser()), $keyPath, $owner, $ownerPath);
+		if (!in_array($user, $sharingUsers['users'])) {
+			Keymanager::delShareKey($view, array($user), $keyPath, $owner, $ownerPath);
 		}
 	}
 
diff --git a/apps/files_encryption/lib/util.php b/apps/files_encryption/lib/util.php
index ad6948b95a..4aaf7aa257 100644
--- a/apps/files_encryption/lib/util.php
+++ b/apps/files_encryption/lib/util.php
@@ -1207,13 +1207,7 @@ class Util {
 
 		// handle public access
 		if ($this->isPublic) {
-			$filename = $path;
-			$fileOwnerUid = $this->userId;
-
-			return array(
-				$fileOwnerUid,
-				$filename
-			);
+			return array($this->userId, $path);
 		} else {
 
 			// Check that UID is valid
diff --git a/apps/files_encryption/tests/share.php b/apps/files_encryption/tests/share.php
index 9c53c73aaf..d29e6a191c 100755
--- a/apps/files_encryption/tests/share.php
+++ b/apps/files_encryption/tests/share.php
@@ -115,6 +115,91 @@ class Share extends TestCase {
 		parent::tearDownAfterClass();
 	}
 
+	/**
+	 * @medium
+	 */
+	function testDeclineServer2ServerShare() {
+
+		$config = $this->getMockBuilder('\OCP\IConfig')
+				->disableOriginalConstructor()->getMock();
+		$certificateManager = $this->getMock('\OCP\ICertificateManager');
+		$httpHelperMock = $this->getMockBuilder('\OC\HTTPHelper')
+				->setConstructorArgs(array($config, $certificateManager))
+				->getMock();
+		$httpHelperMock->expects($this->once())->method('post')->with($this->anything())->will($this->returnValue(true));
+
+		self::loginHelper(self::TEST_ENCRYPTION_SHARE_USER1);
+
+		// save file with content
+		$cryptedFile = file_put_contents('crypt:///' . self::TEST_ENCRYPTION_SHARE_USER1 . '/files/'  . $this->filename, $this->dataShort);
+
+		// test that data was successfully written
+		$this->assertTrue(is_int($cryptedFile));
+
+		// get the file info from previous created file
+		$fileInfo = $this->view->getFileInfo(
+			'/' . self::TEST_ENCRYPTION_SHARE_USER1 . '/files/' . $this->filename);
+
+
+		// share the file
+		$token = \OCP\Share::shareItem('file', $fileInfo['fileid'], \OCP\Share::SHARE_TYPE_LINK, '', \OCP\Constants::PERMISSION_ALL);
+		$this->assertTrue(is_string($token));
+
+		$publicShareKeyId = \OC::$server->getConfig()->getAppValue('files_encryption', 'publicShareKeyId');
+
+		// check if share key for public exists
+		$this->assertTrue($this->view->file_exists(
+			'/' . self::TEST_ENCRYPTION_SHARE_USER1 . '/files_encryption/keys/'
+			. $this->filename . '/' . $publicShareKeyId . '.shareKey'));
+
+		// manipulate share
+		$query = \OC::$server->getDatabaseConnection()->prepare('UPDATE `*PREFIX*share` SET `share_type` = ?, `share_with` = ? WHERE `token`=?');
+		$this->assertTrue($query->execute(array(\OCP\Share::SHARE_TYPE_REMOTE, 'foo@bar', $token)));
+
+		// check if share key not exists
+		$this->assertTrue($this->view->file_exists(
+			'/' . self::TEST_ENCRYPTION_SHARE_USER1 . '/files_encryption/keys/'
+			. $this->filename . '/' . $publicShareKeyId . '.shareKey'));
+
+
+		$query = \OC::$server->getDatabaseConnection()->prepare('SELECT * FROM `*PREFIX*share` WHERE `token`=?');
+		$query->execute(array($token));
+
+		$share = $query->fetch();
+
+		$this->registerHttpHelper($httpHelperMock);
+		$_POST['token'] = $token;
+		$s2s = new \OCA\Files_Sharing\API\Server2Server();
+		$s2s->declineShare(array('id' => $share['id']));
+		$this->restoreHttpHelper();
+
+		$this->assertFalse($this->view->file_exists(
+			'/' . self::TEST_ENCRYPTION_SHARE_USER1 . '/files_encryption/keys/'
+			. $this->filename . '/' . $publicShareKeyId . '.shareKey'));
+
+	}
+
+
+	/**
+	 * Register an http helper mock for testing purposes.
+	 * @param $httpHelper http helper mock
+	 */
+	private function registerHttpHelper($httpHelper) {
+		$this->oldHttpHelper = \OC::$server->query('HTTPHelper');
+		\OC::$server->registerService('HTTPHelper', function ($c) use ($httpHelper) {
+			return $httpHelper;
+		});
+	}
+
+	/**
+	 * Restore the original http helper
+	 */
+	private function restoreHttpHelper() {
+		$oldHttpHelper = $this->oldHttpHelper;
+		\OC::$server->registerService('HTTPHelper', function ($c) use ($oldHttpHelper) {
+			return $oldHttpHelper;
+		});
+	}
 
 	/**
 	 * @medium
@@ -285,7 +370,7 @@ class Share extends TestCase {
 
 		// save file with content
 		$cryptedFile = file_put_contents('crypt:///' . self::TEST_ENCRYPTION_SHARE_USER1 . '/files/'  . $this->folder1 . $this->subfolder . $this->subsubfolder . '/'
-										 . $this->filename, $this->dataShort);
+			. $this->filename, $this->dataShort);
 
 		// test that data was successfully written
 		$this->assertTrue(is_int($cryptedFile));
@@ -677,7 +762,7 @@ class Share extends TestCase {
 		// save file with content
 		$cryptedFile1 = file_put_contents('crypt:///' . self::TEST_ENCRYPTION_SHARE_USER1 . '/files/' . $this->filename, $this->dataShort);
 		$cryptedFile2 = file_put_contents('crypt:///' . self::TEST_ENCRYPTION_SHARE_USER1 . '/files/' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/'
-										  . $this->filename, $this->dataShort);
+			. $this->filename, $this->dataShort);
 
 		// test that data was successfully written
 		$this->assertTrue(is_int($cryptedFile1));
@@ -784,7 +869,7 @@ class Share extends TestCase {
 		// save file with content
 		$cryptedFile1 = file_put_contents('crypt:///' . self::TEST_ENCRYPTION_SHARE_USER2. '/files/' . $this->filename, $this->dataShort);
 		$cryptedFile2 = file_put_contents('crypt:///' . self::TEST_ENCRYPTION_SHARE_USER2 . '/files/' . $this->folder1 . $this->subfolder . $this->subsubfolder . '/'
-										  . $this->filename, $this->dataShort);
+			. $this->filename, $this->dataShort);
 
 		// test that data was successfully written
 		$this->assertTrue(is_int($cryptedFile1));
@@ -925,8 +1010,8 @@ class Share extends TestCase {
 
 		// remove share file
 		$this->view->unlink('/' . self::TEST_ENCRYPTION_SHARE_USER1 . '/files_encryption/keys/'
-							. $this->filename . '/' . self::TEST_ENCRYPTION_SHARE_USER3
-							. '.shareKey');
+			. $this->filename . '/' . self::TEST_ENCRYPTION_SHARE_USER3
+			. '.shareKey');
 
 		// re-enable the file proxy
 		\OC_FileProxy::$enabled = $proxyStatus;
@@ -990,7 +1075,7 @@ class Share extends TestCase {
 
 		// move the file to a subfolder
 		$this->view->rename('/' . self::TEST_ENCRYPTION_SHARE_USER2 . '/files/' . $this->filename,
-				'/' . self::TEST_ENCRYPTION_SHARE_USER2 . '/files/' . $this->folder1 . $this->filename);
+			'/' . self::TEST_ENCRYPTION_SHARE_USER2 . '/files/' . $this->folder1 . $this->filename);
 
 		// check if we can read the moved file
 		$retrievedRenamedFile = $this->view->file_get_contents(
@@ -1122,4 +1207,4 @@ class Share extends TestCase {
 		\OC\Files\Filesystem::unlink($folder);
 	}
 
-}
+}
\ No newline at end of file
diff --git a/apps/files_sharing/ajax/external.php b/apps/files_sharing/ajax/external.php
index 6d68b5f7f8..1a709eda07 100644
--- a/apps/files_sharing/ajax/external.php
+++ b/apps/files_sharing/ajax/external.php
@@ -31,10 +31,11 @@ if(!\OCP\Util::isValidFileName($name)) {
 }
 
 $externalManager = new \OCA\Files_Sharing\External\Manager(
-	\OC::$server->getDatabaseConnection(),
-	\OC\Files\Filesystem::getMountManager(),
-	\OC\Files\Filesystem::getLoader(),
-	\OC::$server->getUserSession()
+		\OC::$server->getDatabaseConnection(),
+		\OC\Files\Filesystem::getMountManager(),
+		\OC\Files\Filesystem::getLoader(),
+		\OC::$server->getUserSession(),
+		\OC::$server->getHTTPHelper()
 );
 
 $name = OCP\Files::buildNotExistingFileName('/', $name);
@@ -44,7 +45,7 @@ if (substr($remote, 0, 5) === 'https' and !OC_Util::getUrlContent($remote)) {
 	\OCP\JSON::error(array('data' => array('message' => $l->t("Invalid or untrusted SSL certificate"))));
 	exit;
 } else {
-	$mount = $externalManager->addShare($remote, $token, $password, $name, $owner);
+	$mount = $externalManager->addShare($remote, $token, $password, $name, $owner, true);
 	/**
 	 * @var \OCA\Files_Sharing\External\Storage $storage
 	 */
diff --git a/apps/files_sharing/api/server2server.php b/apps/files_sharing/api/server2server.php
index 2949e2dd09..f78d64caa7 100644
--- a/apps/files_sharing/api/server2server.php
+++ b/apps/files_sharing/api/server2server.php
@@ -34,7 +34,7 @@ class Server2Server {
 	public function createShare($params) {
 
 		if (!$this->isS2SEnabled(true)) {
-			return \OC_OCS_Result(null, 503, 'Server does not support server-to-server sharing');
+			return new \OC_OCS_Result(null, 503, 'Server does not support server-to-server sharing');
 		}
 
 		$remote = isset($_POST['remote']) ? $_POST['remote'] : null;
@@ -42,7 +42,7 @@ class Server2Server {
 		$name = isset($_POST['name']) ? $_POST['name'] : null;
 		$owner = isset($_POST['owner']) ? $_POST['owner'] : null;
 		$shareWith = isset($_POST['shareWith']) ? $_POST['shareWith'] : null;
-		$remoteId = isset($_POST['remote_id']) ? (int)$_POST['remote_id'] : null;
+		$remoteId = isset($_POST['remoteId']) ? (int)$_POST['remoteId'] : null;
 
 		if ($remote && $token && $name && $owner && $remoteId && $shareWith) {
 
@@ -56,19 +56,28 @@ class Server2Server {
 
 			\OC_Util::setupFS($shareWith);
 
-			$mountPoint = \OC\Files\Filesystem::normalizePath('/' . $name);
+			$externalManager = new \OCA\Files_Sharing\External\Manager(
+					\OC::$server->getDatabaseConnection(),
+					\OC\Files\Filesystem::getMountManager(),
+					\OC\Files\Filesystem::getLoader(),
+					\OC::$server->getUserSession(),
+					\OC::$server->getHTTPHelper());
+
 			$name = \OCP\Files::buildNotExistingFileName('/', $name);
 
 			try {
-				\OCA\Files_Sharing\Helper::addServer2ServerShare($remote, $token, $name, $mountPoint, $owner, $shareWith, '', $remoteId);
+				$externalManager->addShare($remote, $token, '', $name, $owner, false, $shareWith, $remoteId);
+
+				$user = $owner . '@' . $this->cleanupRemote($remote);
 
 				\OC::$server->getActivityManager()->publishActivity(
-						'files_sharing', \OCA\Files_Sharing\Activity::SUBJECT_REMOTE_SHARE_RECEIVED, array($owner), '', array(),
-						'', '', $shareWith, \OCA\Files_Sharing\Activity::TYPE_REMOTE_SHARE, \OCA\Files_Sharing\Activity::PRIORITY_LOW);
+					'files_sharing', \OCA\Files_Sharing\Activity::SUBJECT_REMOTE_SHARE_RECEIVED, array($user), '', array(),
+					'', '', $shareWith, \OCA\Files_Sharing\Activity::TYPE_REMOTE_SHARE, \OCA\Files_Sharing\Activity::PRIORITY_LOW);
 
 				return new \OC_OCS_Result();
 			} catch (\Exception $e) {
-				return new \OC_OCS_Result(null, 500, 'server can not add remote share, ' . $e->getMessage());
+				\OCP\Util::writeLog('files_sharing', 'server can not add remote share, ' . $e->getMessage(), \OCP\Util::ERROR);
+				return new \OC_OCS_Result(null, 500, 'internal server error, was not able to add share from ' . $remote);
 			}
 		}
 
@@ -84,7 +93,7 @@ class Server2Server {
 	public function acceptShare($params) {
 
 		if (!$this->isS2SEnabled()) {
-			return \OC_OCS_Result(null, 503, 'Server does not support server-to-server sharing');
+			return new \OC_OCS_Result(null, 503, 'Server does not support server-to-server sharing');
 		}
 
 		$id = $params['id'];
@@ -95,8 +104,8 @@ class Server2Server {
 			list($file, $link) = self::getFile($share['uid_owner'], $share['file_source']);
 
 			\OC::$server->getActivityManager()->publishActivity(
-					'files_sharing', \OCA\Files_Sharing\Activity::SUBJECT_REMOTE_SHARE_ACCEPTED, array($share['share_with'], basename($file)), '', array(),
-					$file, $link, $share['uid_owner'], \OCA\Files_Sharing\Activity::TYPE_REMOTE_SHARE, \OCA\Files_Sharing\Activity::PRIORITY_LOW);
+				'files_sharing', \OCA\Files_Sharing\Activity::SUBJECT_REMOTE_SHARE_ACCEPTED, array($share['share_with'], basename($file)), '', array(),
+				$file, $link, $share['uid_owner'], \OCA\Files_Sharing\Activity::TYPE_REMOTE_SHARE, \OCA\Files_Sharing\Activity::PRIORITY_LOW);
 		}
 
 		return new \OC_OCS_Result();
@@ -111,7 +120,7 @@ class Server2Server {
 	public function declineShare($params) {
 
 		if (!$this->isS2SEnabled()) {
-			return \OC_OCS_Result(null, 503, 'Server does not support server-to-server sharing');
+			return new \OC_OCS_Result(null, 503, 'Server does not support server-to-server sharing');
 		}
 
 		$id = $params['id'];
@@ -126,8 +135,8 @@ class Server2Server {
 			list($file, $link) = $this->getFile($share['uid_owner'], $share['file_source']);
 
 			\OC::$server->getActivityManager()->publishActivity(
-					'files_sharing', \OCA\Files_Sharing\Activity::SUBJECT_REMOTE_SHARE_DECLINED, array($share['share_with'], basename($file)), '', array(),
-					$file, $link, $share['uid_owner'], \OCA\Files_Sharing\Activity::TYPE_REMOTE_SHARE, \OCA\Files_Sharing\Activity::PRIORITY_LOW);
+				'files_sharing', \OCA\Files_Sharing\Activity::SUBJECT_REMOTE_SHARE_DECLINED, array($share['share_with'], basename($file)), '', array(),
+				$file, $link, $share['uid_owner'], \OCA\Files_Sharing\Activity::TYPE_REMOTE_SHARE, \OCA\Files_Sharing\Activity::PRIORITY_LOW);
 		}
 
 		return new \OC_OCS_Result();
@@ -142,7 +151,7 @@ class Server2Server {
 	public function unshare($params) {
 
 		if (!$this->isS2SEnabled()) {
-			return \OC_OCS_Result(null, 503, 'Server does not support server-to-server sharing');
+			return new \OC_OCS_Result(null, 503, 'Server does not support server-to-server sharing');
 		}
 
 		$id = $params['id'];
@@ -154,7 +163,9 @@ class Server2Server {
 
 		if ($token && $id && !empty($share)) {
 
-			$owner = $share['owner'] . '@' . $share['remote'];
+			$remote = $this->cleanupRemote($share['remote']);
+
+			$owner = $share['owner'] . '@' . $remote;
 			$mountpoint = $share['mountpoint'];
 			$user = $share['user'];
 
@@ -162,13 +173,19 @@ class Server2Server {
 			$query->execute(array($id, $token));
 
 			\OC::$server->getActivityManager()->publishActivity(
-					'files_sharing', \OCA\Files_Sharing\Activity::SUBJECT_REMOTE_SHARE_DECLINED, array($owner, $mountpoint), '', array(),
-					'', '', $user, \OCA\Files_Sharing\Activity::TYPE_REMOTE_SHARE, \OCA\Files_Sharing\Activity::PRIORITY_MEDIUM);
+				'files_sharing', \OCA\Files_Sharing\Activity::SUBJECT_REMOTE_SHARE_UNSHARED, array($owner, $mountpoint), '', array(),
+				'', '', $user, \OCA\Files_Sharing\Activity::TYPE_REMOTE_SHARE, \OCA\Files_Sharing\Activity::PRIORITY_MEDIUM);
 		}
 
 		return new \OC_OCS_Result();
 	}
 
+	private function cleanupRemote($remote) {
+		$remote = substr($remote, strpos($remote, '://') + 3);
+
+		return rtrim($remote, '/');
+	}
+
 	/**
 	 * get share
 	 *
diff --git a/apps/files_sharing/appinfo/routes.php b/apps/files_sharing/appinfo/routes.php
index 41bdf554fc..dd9509575b 100644
--- a/apps/files_sharing/appinfo/routes.php
+++ b/apps/files_sharing/appinfo/routes.php
@@ -1,5 +1,16 @@
 <?php
 
+namespace OCA\Files_Sharing\AppInfo;
+
+use OCA\Files_Sharing\Application;
+
+$application = new Application();
+$application->registerRoutes($this, [
+	'resources' => [
+		'ExternalShares' => ['url' => '/api/externalShares'],
+	]
+]);
+
 /** @var $this \OCP\Route\IRouter */
 $this->create('core_ajax_public_preview', '/publicpreview')->action(
 	function() {
@@ -16,31 +27,32 @@ $this->create('sharing_external_add', '/external')
 	->actionInclude('files_sharing/ajax/external.php');
 $this->create('sharing_external_test_remote', '/testremote')
 	->actionInclude('files_sharing/ajax/testremote.php');
+
 // OCS API
 
 //TODO: SET: mail notification, waiting for PR #4689 to be accepted
 
-OC_API::register('get',
+\OC_API::register('get',
 		'/apps/files_sharing/api/v1/shares',
 		array('\OCA\Files_Sharing\API\Local', 'getAllShares'),
 		'files_sharing');
 
-OC_API::register('post',
+\OC_API::register('post',
 		'/apps/files_sharing/api/v1/shares',
 		array('\OCA\Files_Sharing\API\Local', 'createShare'),
 		'files_sharing');
 
-OC_API::register('get',
+\OC_API::register('get',
 		'/apps/files_sharing/api/v1/shares/{id}',
 		array('\OCA\Files_Sharing\API\Local', 'getShare'),
 		'files_sharing');
 
-OC_API::register('put',
+\OC_API::register('put',
 		'/apps/files_sharing/api/v1/shares/{id}',
 		array('\OCA\Files_Sharing\API\Local', 'updateShare'),
 		'files_sharing');
 
-OC_API::register('delete',
+\OC_API::register('delete',
 		'/apps/files_sharing/api/v1/shares/{id}',
 		array('\OCA\Files_Sharing\API\Local', 'deleteShare'),
 		'files_sharing');
diff --git a/apps/files_sharing/application.php b/apps/files_sharing/application.php
index 089ed6afbd..9fe8785df0 100644
--- a/apps/files_sharing/application.php
+++ b/apps/files_sharing/application.php
@@ -11,6 +11,7 @@
 namespace OCA\Files_Sharing;
 
 use OC\AppFramework\Utility\SimpleContainer;
+use OCA\Files_Sharing\Controllers\ExternalSharesController;
 use OCA\Files_Sharing\Controllers\ShareController;
 use OCA\Files_Sharing\Middleware\SharingCheckMiddleware;
 use \OCP\AppFramework\App;
@@ -44,6 +45,14 @@ class Application extends App {
 				$c->query('ServerContainer')->getLogger()
 			);
 		});
+		$container->registerService('ExternalSharesController', function(SimpleContainer $c) {
+			return new ExternalSharesController(
+				$c->query('AppName'),
+				$c->query('Request'),
+				$c->query('IsIncomingShareEnabled'),
+				$c->query('ExternalManager')
+			);
+		});
 
 		/**
 		 * Core class wrappers
@@ -54,6 +63,18 @@ class Application extends App {
 		$container->registerService('URLGenerator', function(SimpleContainer $c) {
 			return $c->query('ServerContainer')->getUrlGenerator();
 		});
+		$container->registerService('IsIncomingShareEnabled', function(SimpleContainer $c) {
+			return Helper::isIncomingServer2serverShareEnabled();
+		});
+		$container->registerService('ExternalManager', function(SimpleContainer $c) {
+			return new \OCA\Files_Sharing\External\Manager(
+					\OC::$server->getDatabaseConnection(),
+					\OC\Files\Filesystem::getMountManager(),
+					\OC\Files\Filesystem::getLoader(),
+					\OC::$server->getUserSession(),
+					\OC::$server->getHTTPHelper()
+			);
+		});
 
 		/**
 		 * Middleware
diff --git a/apps/files_sharing/js/external.js b/apps/files_sharing/js/external.js
index 6ede2584cd..aeb4b2461f 100644
--- a/apps/files_sharing/js/external.js
+++ b/apps/files_sharing/js/external.js
@@ -8,16 +8,6 @@
  *
  */
 (function () {
-	var addExternalShare = function (remote, token, owner, name, password) {
-		return $.post(OC.generateUrl('apps/files_sharing/external'), {
-			remote: remote,
-			token: token,
-			owner: owner,
-			name: name,
-			password: password
-		});
-	};
-
 	/**
 	 * Shows "add external share" dialog.
 	 *
@@ -27,20 +17,12 @@
 	 * @param {String} token authentication token
 	 * @param {bool} passwordProtected true if the share is password protected
 	 */
-	OCA.Sharing.showAddExternalDialog = function (remote, token, owner, name, passwordProtected) {
+	OCA.Sharing.showAddExternalDialog = function (share, passwordProtected, callback) {
+		var remote = share.remote;
+		var owner = share.owner;
+		var name = share.name;
 		var remoteClean = (remote.substr(0, 8) === 'https://') ? remote.substr(8) : remote.substr(7);
-		var callback = function (add, password) {
-			password = password || '';
-			if (add) {
-				addExternalShare(remote, token, owner, name, password).then(function (result) {
-					if (result.status === 'error') {
-						OC.Notification.show(result.data.message);
-					} else {
-						FileList.reload();
-					}
-				});
-			}
-		};
+
 		if (!passwordProtected) {
 			OC.dialogs.confirm(
 				t(
@@ -49,7 +31,9 @@
 					{name: name, owner: owner, remote: remoteClean}
 				),
 				t('files_sharing','Remote share'),
-				callback,
+				function (result) {
+					callback(result, share);
+				},
 				true
 			).then(this._adjustDialog);
 		} else {
@@ -60,7 +44,9 @@
 					{name: name, owner: owner, remote: remoteClean}
 				),
 				t('files_sharing','Remote share'),
-				callback,
+				function (result) {
+					callback(result, share);
+				},
 				true,
 				t('files_sharing','Remote share password'),
 				true
@@ -82,17 +68,66 @@ $(document).ready(function () {
 	// FIXME: HACK: do not init when running unit tests, need a better way
 	if (!window.TESTING && OCA.Files) {// only run in the files app
 		var params = OC.Util.History.parseUrlQuery();
+
+		//manually add server-to-server share
 		if (params.remote && params.token && params.owner && params.name) {
+
+			var callbackAddShare = function(result, share) {
+				var password = share.password || '';
+				if (result) {
+					//$.post(OC.generateUrl('/apps/files_sharing/api/externalShares'), {id: share.id});
+					$.post(OC.generateUrl('apps/files_sharing/external'), {
+						remote: share.remote,
+						token: share.token,
+						owner: share.owner,
+						name: share.name,
+						password: password}, function(result) {
+						if (result.status === 'error') {
+							OC.Notification.show(result.data.message);
+						} else {
+							FileList.reload();
+						}
+					});
+				}
+			};
+
 			// clear hash, it is unlikely that it contain any extra parameters
 			location.hash = '';
 			params.passwordProtected = parseInt(params.protected, 10) === 1;
 			OCA.Sharing.showAddExternalDialog(
-				params.remote,
-				params.token,
-				params.owner,
-				params.name,
-				params.passwordProtected
+				params,
+				params.passwordProtected,
+				callbackAddShare
 			);
 		}
+
+		// check for new server-to-server shares which need to be approved
+		$.get(OC.generateUrl('/apps/files_sharing/api/externalShares'),
+		{},
+		function(shares) {
+			var index;
+			for (index = 0; index < shares.length; ++index) {
+				OCA.Sharing.showAddExternalDialog(
+						shares[index],
+						false,
+						function(result, share) {
+							if (result) {
+								// Accept
+								$.post(OC.generateUrl('/apps/files_sharing/api/externalShares'), {id: share.id});
+								FileList.reload();
+							} else {
+								// Delete
+								$.ajax({
+									url: OC.generateUrl('/apps/files_sharing/api/externalShares/'+share.id),
+									type: 'DELETE'
+								});
+							}
+						}
+				);
+			}
+
+		});
+
 	}
+
 });
diff --git a/apps/files_sharing/lib/activity.php b/apps/files_sharing/lib/activity.php
index 979df1c1da..868830d80c 100644
--- a/apps/files_sharing/lib/activity.php
+++ b/apps/files_sharing/lib/activity.php
@@ -98,7 +98,7 @@ class Activity implements \OCP\Activity\IExtension {
 				case self::SUBJECT_REMOTE_SHARE_DECLINED:
 					return $l->t('%1$s declined remote share %2$s', $params)->__toString();
 					case self::SUBJECT_REMOTE_SHARE_UNSHARED:
-					return $l->t('%1$s unshared %2$s', $params)->__toString();
+					return $l->t('%1$s unshared %2$s from you', $params)->__toString();
 			}
 		}
 	}
diff --git a/apps/files_sharing/lib/connector/publicauth.php b/apps/files_sharing/lib/connector/publicauth.php
index 4144dafa37..a630d091fd 100644
--- a/apps/files_sharing/lib/connector/publicauth.php
+++ b/apps/files_sharing/lib/connector/publicauth.php
@@ -69,6 +69,8 @@ class PublicAuth extends \Sabre\DAV\Auth\Backend\AbstractBasic {
 				} else {
 					return false;
 				}
+			} elseif ($linkItem['share_type'] == \OCP\Share::SHARE_TYPE_REMOTE) {
+				return true;
 			} else {
 				return false;
 			}
diff --git a/apps/files_sharing/lib/controllers/externalsharescontroller.php b/apps/files_sharing/lib/controllers/externalsharescontroller.php
new file mode 100644
index 0000000000..773ff8ce98
--- /dev/null
+++ b/apps/files_sharing/lib/controllers/externalsharescontroller.php
@@ -0,0 +1,86 @@
+<?php
+/**
+ * @author Lukas Reschke <lukas@owncloud.com>
+ * @copyright 2014 Lukas Reschke
+ *
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+namespace OCA\Files_Sharing\Controllers;
+
+use OC;
+use OCP;
+use OCP\AppFramework\Controller;
+use OCP\IRequest;
+use OCP\AppFramework\Http\JSONResponse;
+
+/**
+ * Class ExternalSharesController
+ *
+ * @package OCA\Files_Sharing\Controllers
+ */
+class ExternalSharesController extends Controller {
+
+	/** @var bool */
+	private $incomingShareEnabled;
+	/** @var \OCA\Files_Sharing\External\Manager */
+	private $externalManager;
+
+	/**
+	 * @param string $appName
+	 * @param IRequest $request
+	 * @param \OCA\Files_Sharing\External\Manager $externalManager
+	 */
+	public function __construct($appName,
+								IRequest $request,
+								$incomingShareEnabled,
+								\OCA\Files_Sharing\External\Manager $externalManager) {
+		parent::__construct($appName, $request);
+		$this->incomingShareEnabled = $incomingShareEnabled;
+		$this->externalManager = $externalManager;
+	}
+
+	/**
+	 * @NoAdminRequired
+	 *
+	 * @return JSONResponse
+	 */
+	public function index() {
+		$shares = [];
+		if ($this->incomingShareEnabled) {
+			$shares = $this->externalManager->getOpenShares();
+		}
+		return new JSONResponse($shares);
+	}
+
+	/**
+	 * @NoAdminRequired
+	 *
+	 * @param int $id
+	 * @return JSONResponse
+	 */
+	public function create($id) {
+		if ($this->incomingShareEnabled) {
+			$this->externalManager->acceptShare($id);
+		}
+
+		return new JSONResponse();
+	}
+
+	/**
+	 * @NoAdminRequired
+	 *
+	 * @param $id
+	 * @return JSONResponse
+	 */
+	public function destroy($id) {
+		if ($this->incomingShareEnabled) {
+			$this->externalManager->declineShare($id);
+		}
+
+		return new JSONResponse();
+	}
+
+}
diff --git a/apps/files_sharing/lib/external/manager.php b/apps/files_sharing/lib/external/manager.php
index b52e1a5044..665e47c0fe 100644
--- a/apps/files_sharing/lib/external/manager.php
+++ b/apps/files_sharing/lib/external/manager.php
@@ -33,6 +33,11 @@ class Manager {
 	 */
 	private $userSession;
 
+	/**
+	 * @var \OC\HTTPHelper
+	 */
+	private $httpHelper;
+
 	/**
 	 * @param \OCP\IDBConnection $connection
 	 * @param \OC\Files\Mount\Manager $mountManager
@@ -40,19 +45,30 @@ class Manager {
 	 * @param \OC\Files\Storage\StorageFactory $storageLoader
 	 */
 	public function __construct(\OCP\IDBConnection $connection, \OC\Files\Mount\Manager $mountManager,
-								\OC\Files\Storage\StorageFactory $storageLoader, \OC\User\Session $userSession) {
+								\OC\Files\Storage\StorageFactory $storageLoader, \OC\User\Session $userSession, \OC\HTTPHelper $httpHelper) {
 		$this->connection = $connection;
 		$this->mountManager = $mountManager;
 		$this->userSession = $userSession;
 		$this->storageLoader = $storageLoader;
+		$this->httpHelper = $httpHelper;
 	}
 
-	public function addShare($remote, $token, $password, $name, $owner) {
-		$user = $this->userSession->getUser();
-		if ($user) {
-			$mountPoint = Filesystem::normalizePath('/' . $name);
-			\OCA\Files_Sharing\Helper::addServer2ServerShare($remote, $token, $name, $mountPoint, $owner, $user->getUID(), $password, -1, true);
+	public function addShare($remote, $token, $password, $name, $owner, $accepted=false, $user = null, $remoteId = -1) {
+
+		$user = $user ? $user: $this->userSession->getUser()->getUID();
+		$accepted = $accepted ? 1 : 0;
 
+		$mountPoint = Filesystem::normalizePath('/' . $name);
+
+		$query = $this->connection->prepare('
+				INSERT INTO `*PREFIX*share_external`
+					(`remote`, `share_token`, `password`, `name`, `owner`, `user`, `mountpoint`, `mountpoint_hash`, `accepted`, `remote_id`)
+				VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
+			');
+		$hash = md5($mountPoint);
+		$query->execute(array($remote, $token, $password, $name, $owner, $user, $mountPoint, $hash, $accepted, $remoteId));
+
+		if ($accepted) {
 			$options = array(
 				'remote' => $remote,
 				'token' => $token,
@@ -87,12 +103,85 @@ class Manager {
 		}
 	}
 
+	/**
+	 * get share
+	 *
+	 * @param int $id share id
+	 * @return mixed share of false
+	 */
+	private function getShare($id) {
+		$getShare = $this->connection->prepare('
+			SELECT `remote`, `share_token`
+			FROM  `*PREFIX*share_external`
+			WHERE `id` = ? AND `user` = ?');
+		$result = $getShare->execute(array($id,  $this->userSession->getUser()->getUID()));
+
+		return $result ? $getShare->fetch() : false;
+	}
+
+	/**
+	 * accept server-to-server share
+	 *
+	 * @param int $id
+	 */
+	public function acceptShare($id) {
+
+		$share = $this->getShare($id);
+
+		if ($share) {
+			$acceptShare = $this->connection->prepare('
+				UPDATE `*PREFIX*share_external`
+				SET `accepted` = ?
+				WHERE `id` = ? AND `user` = ?');
+			$acceptShare->execute(array(1, $id,  $this->userSession->getUser()->getUID()));
+			$this->sendFeedbackToRemote($share['remote'], $share['share_token'], $id, 'accept');
+		}
+	}
+
+	/**
+	 * decline server-to-server share
+	 *
+	 * @param int $id
+	 */
+	public function declineShare($id) {
+
+		$share = $this->getShare($id);
+
+		if ($share) {
+			$removeShare = $this->connection->prepare('
+				DELETE FROM `*PREFIX*share_external` WHERE `id` = ? AND `user` = ?');
+			$removeShare->execute(array($id, $this->userSession->getUser()->getUID()));
+			$this->sendFeedbackToRemote($share['remote'], $share['share_token'], $id, 'decline');
+		}
+	}
+
+	/**
+	 * inform remote server whether server-to-server share was accepted/declined
+	 *
+	 * @param string $remote
+	 * @param string $token
+	 * @param int $id
+	 * @param string $feedback
+	 * @return boolean
+	 */
+	private function sendFeedbackToRemote($remote, $token, $id, $feedback) {
+
+		$url = $remote . \OCP\Share::BASE_PATH_TO_SHARE_API . '/' . $id . '/' . $feedback . '?format=' . \OCP\Share::RESPONSE_FORMAT;
+		$fields = array('token' => $token);
+
+		$result = $this->httpHelper->post($url, $fields);
+		$status = json_decode($result['result'], true);
+
+		return ($result['success'] && $status['ocs']['meta']['statuscode'] === 100);
+	}
+
 	public static function setup() {
 		$externalManager = new \OCA\Files_Sharing\External\Manager(
-			\OC::$server->getDatabaseConnection(),
-			\OC\Files\Filesystem::getMountManager(),
-			\OC\Files\Filesystem::getLoader(),
-			\OC::$server->getUserSession()
+				\OC::$server->getDatabaseConnection(),
+				\OC\Files\Filesystem::getMountManager(),
+				\OC\Files\Filesystem::getLoader(),
+				\OC::$server->getUserSession(),
+				\OC::$server->getHTTPHelper()
 		);
 		$externalManager->setupMounts();
 	}
@@ -151,6 +240,18 @@ class Manager {
 		$user = $this->userSession->getUser();
 		$mountPoint = $this->stripPath($mountPoint);
 		$hash = md5($mountPoint);
+
+		$getShare = $this->connection->prepare('
+			SELECT `remote`, `share_token`, `remote_id`
+			FROM  `*PREFIX*share_external`
+			WHERE `mountpoint_hash` = ? AND `user` = ?');
+		$result = $getShare->execute(array($hash, $user->getUID()));
+
+		if ($result) {
+			$share = $getShare->fetch();
+			$this->sendFeedbackToRemote($share['remote'], $share['share_token'], $share['remote_id'], 'decline');
+		}
+
 		$query = $this->connection->prepare('
 			DELETE FROM `*PREFIX*share_external`
 			WHERE `mountpoint_hash` = ?
@@ -158,4 +259,17 @@ class Manager {
 		');
 		return (bool)$query->execute(array($hash, $user->getUID()));
 	}
-}
+
+	/**
+	 * return a list of shares which are not yet accepted by the user
+	 *
+	 * @return array list of open server-to-server shares
+	 */
+	public function getOpenShares() {
+		$openShares = $this->connection->prepare('SELECT * FROM `*PREFIX*share_external` WHERE `accepted` = ? AND `user` = ?');
+		$result = $openShares->execute(array(0, $this->userSession->getUser()->getUID()));
+
+		return $result ? $openShares->fetchAll() : array();
+
+	}
+}
\ No newline at end of file
diff --git a/apps/files_sharing/lib/helper.php b/apps/files_sharing/lib/helper.php
index 71519bd1d4..001d0387fa 100644
--- a/apps/files_sharing/lib/helper.php
+++ b/apps/files_sharing/lib/helper.php
@@ -2,8 +2,6 @@
 
 namespace OCA\Files_Sharing;
 
-use OC_Config;
-
 class Helper {
 
 	public static function registerHooks() {
@@ -20,30 +18,6 @@ class Helper {
 		\OCP\Util::connectHook('OCP\Share', 'post_unshareFromSelf', '\OC\Files\Cache\Shared_Updater', 'postUnshareFromSelfHook');
 	}
 
-	/**
-	 * add server-to-server share to database
-	 *
-	 * @param string $remote
-	 * @param string $token
-	 * @param string $name
-	 * @param string $mountPoint
-	 * @param string $owner
-	 * @param string $user
-	 * @param string $password
-	 * @param int $remoteId
-	 * @param bool $accepted
-	 */
-	public static function addServer2ServerShare($remote, $token, $name, $mountPoint, $owner, $user, $password='', $remoteId=-1, $accepted = false) {
-		$accepted = $accepted ? 1 : 0;
-		$query = \OCP\DB::prepare('
-				INSERT INTO `*PREFIX*share_external`
-					(`remote`, `share_token`, `password`, `name`, `owner`, `user`, `mountpoint`, `mountpoint_hash`, `accepted`, `remote_id`)
-				VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
-			');
-			$hash = md5($mountPoint);
-			$query->execute(array($remote, $token, $password, $name, $owner, $user, $mountPoint, $hash, $accepted, $remoteId));
-	}
-
 	/**
 	 * Sets up the filesystem and user for public sharing
 	 * @param string $token string share token
@@ -89,7 +63,7 @@ class Helper {
 			exit();
 		}
 
-		if (isset($linkItem['share_with'])) {
+		if (isset($linkItem['share_with']) && (int)$linkItem['share_type'] === \OCP\Share::SHARE_TYPE_LINK) {
 			if (!self::authenticate($linkItem, $password)) {
 				\OC_Response::setStatus(403);
 				\OCP\JSON::error(array('success' => false));
diff --git a/apps/files_sharing/lib/share/file.php b/apps/files_sharing/lib/share/file.php
index a5b4e75bce..93e4af3c39 100644
--- a/apps/files_sharing/lib/share/file.php
+++ b/apps/files_sharing/lib/share/file.php
@@ -159,6 +159,20 @@ class OC_Share_Backend_File implements OCP\Share_Backend_File_Dependent {
 		return array();
 	}
 
+	/**
+	 * check if server2server share is enabled
+	 *
+	 * @param int $shareType
+	 * @return boolean
+	 */
+	public function isShareTypeAllowed($shareType) {
+		if ($shareType === \OCP\Share::SHARE_TYPE_REMOTE) {
+			return \OCA\Files_Sharing\Helper::isOutgoingServer2serverShareEnabled();
+		}
+
+		return true;
+	}
+
 	/**
 	 * resolve reshares to return the correct source item
 	 * @param array $source
diff --git a/apps/files_sharing/lib/updater.php b/apps/files_sharing/lib/updater.php
index a34140f5a3..9d8ae7cbb4 100644
--- a/apps/files_sharing/lib/updater.php
+++ b/apps/files_sharing/lib/updater.php
@@ -161,7 +161,10 @@ class Shared_Updater {
 	 */
 	static public function postUnshareHook($params) {
 
-		if ($params['itemType'] === 'file' || $params['itemType'] === 'folder') {
+		// only update etags for file/folders shared to local users/groups
+		if (($params['itemType'] === 'file' || $params['itemType'] === 'folder') &&
+				$params['shareType'] !== \OCP\Share::SHARE_TYPE_LINK &&
+				$params['shareType'] !== \OCP\Share::SHARE_TYPE_REMOTE) {
 
 			$deletedShares = isset($params['deletedShares']) ? $params['deletedShares'] : array();
 
@@ -212,7 +215,7 @@ class Shared_Updater {
 
 	/**
 	 * rename mount point from the children if the parent was renamed
-	 * 
+	 *
 	 * @param string $oldPath old path relative to data/user/files
 	 * @param string $newPath new path relative to data/user/files
 	 */
diff --git a/apps/files_sharing/tests/server2server.php b/apps/files_sharing/tests/server2server.php
index 7aec0c4951..0400d357b8 100644
--- a/apps/files_sharing/tests/server2server.php
+++ b/apps/files_sharing/tests/server2server.php
@@ -38,6 +38,16 @@ class Test_Files_Sharing_S2S_OCS_API extends TestCase {
 		self::loginHelper(self::TEST_FILES_SHARING_API_USER1);
 		\OCP\Share::registerBackend('test', 'Test_Share_Backend');
 
+		$config = $this->getMockBuilder('\OCP\IConfig')
+				->disableOriginalConstructor()->getMock();
+		$certificateManager = $this->getMock('\OCP\ICertificateManager');
+		$httpHelperMock = $this->getMockBuilder('\OC\HTTPHelper')
+				->setConstructorArgs(array($config, $certificateManager))
+				->getMock();
+		$httpHelperMock->expects($this->any())->method('post')->with($this->anything())->will($this->returnValue(true));
+
+		$this->registerHttpHelper($httpHelperMock);
+
 		$this->s2s = new \OCA\Files_Sharing\API\Server2Server();
 	}
 
@@ -45,9 +55,32 @@ class Test_Files_Sharing_S2S_OCS_API extends TestCase {
 		$query = \OCP\DB::prepare('DELETE FROM `*PREFIX*share_external`');
 		$query->execute();
 
+		$this->restoreHttpHelper();
+
 		parent::tearDown();
 	}
 
+	/**
+	 * Register an http helper mock for testing purposes.
+	 * @param $httpHelper http helper mock
+	 */
+	private function registerHttpHelper($httpHelper) {
+		$this->oldHttpHelper = \OC::$server->query('HTTPHelper');
+		\OC::$server->registerService('HTTPHelper', function ($c) use ($httpHelper) {
+			return $httpHelper;
+		});
+	}
+
+	/**
+	 * Restore the original http helper
+	 */
+	private function restoreHttpHelper() {
+		$oldHttpHelper = $this->oldHttpHelper;
+		\OC::$server->registerService('HTTPHelper', function ($c) use ($oldHttpHelper) {
+			return $oldHttpHelper;
+		});
+	}
+
 	/**
 	 * @medium
 	 */
@@ -58,7 +91,7 @@ class Test_Files_Sharing_S2S_OCS_API extends TestCase {
 		$_POST['name'] = 'name';
 		$_POST['owner'] = 'owner';
 		$_POST['shareWith'] = self::TEST_FILES_SHARING_API_USER2;
-		$_POST['remote_id'] = 1;
+		$_POST['remoteId'] = 1;
 
 		$result = $this->s2s->createShare(null);
 
@@ -81,10 +114,10 @@ class Test_Files_Sharing_S2S_OCS_API extends TestCase {
 	function testDeclineShare() {
 		$dummy = \OCP\DB::prepare('
 			INSERT INTO `*PREFIX*share`
-			(`share_type`, `uid_owner`, `item_type`, `item_source`, `item_target`, `file_source`, `file_target`, `permissions`, `stime`, `token`)
-			VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
+			(`share_type`, `uid_owner`, `item_type`, `item_source`, `item_target`, `file_source`, `file_target`, `permissions`, `stime`, `token`, `share_with`)
+			VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
 			');
-		$dummy->execute(array(\OCP\Share::SHARE_TYPE_REMOTE, self::TEST_FILES_SHARING_API_USER1, 'test', '1', '/1', '1', '/test.txt', '1', time(), 'token'));
+		$dummy->execute(array(\OCP\Share::SHARE_TYPE_REMOTE, self::TEST_FILES_SHARING_API_USER1, 'test', '1', '/1', '1', '/test.txt', '1', time(), 'token', 'foo@bar'));
 
 		$verify = \OCP\DB::prepare('SELECT * FROM `*PREFIX*share`');
 		$result = $verify->execute();
diff --git a/core/ajax/share.php b/core/ajax/share.php
index 9f758b4e44..2831d42a36 100644
--- a/core/ajax/share.php
+++ b/core/ajax/share.php
@@ -36,7 +36,7 @@ if (isset($_POST['action']) && isset($_POST['itemType']) && isset($_POST['itemSo
 						$shareWith = null;
 					}
  					$itemSourceName=(isset($_POST['itemSourceName'])) ? $_POST['itemSourceName']:'';
-					
+
 					$token = OCP\Share::shareItem(
 						$_POST['itemType'],
 						$_POST['itemSource'],
@@ -309,6 +309,21 @@ if (isset($_POST['action']) && isset($_POST['itemType']) && isset($_POST['itemSo
 						break;
 					}
 				}
+
+				// allow user to add unknown remote addresses for server-to-server share
+				$backend = \OCP\Share::getBackend($_GET['itemType']);
+				if ($backend->isShareTypeAllowed(\OCP\Share::SHARE_TYPE_REMOTE)) {
+					if (substr_count($_GET['search'], '@') === 1) {
+						$shareWith[] = array(
+							'label' => $_GET['search'],
+							'value' => array(
+								'shareType' => \OCP\Share::SHARE_TYPE_REMOTE,
+								'shareWith' => $_GET['search']
+							)
+						);
+					}
+				}
+
 				$sorter = new \OC\Share\SearchResultSorter($_GET['search'],
 														   'label',
 														   new \OC\Log());
diff --git a/core/js/share.js b/core/js/share.js
index b8717d94ed..00d1dab519 100644
--- a/core/js/share.js
+++ b/core/js/share.js
@@ -8,6 +8,7 @@ OC.Share={
 	SHARE_TYPE_GROUP:1,
 	SHARE_TYPE_LINK:3,
 	SHARE_TYPE_EMAIL:4,
+	SHARE_TYPE_REMOTE:6,
 
 	/**
 	 * Regular expression for splitting parts of remote share owners:
@@ -444,7 +445,11 @@ OC.Share={
 						if (share.collection) {
 							OC.Share.addShareWith(share.share_type, share.share_with, share.share_with_displayname, share.permissions, possiblePermissions, share.mail_send, share.collection);
 						} else {
-							OC.Share.addShareWith(share.share_type, share.share_with, share.share_with_displayname, share.permissions, possiblePermissions, share.mail_send, false);
+							if (share.share_type === OC.Share.SHARE_TYPE_REMOTE) {
+								OC.Share.addShareWith(share.share_type, share.share_with, share.share_with_displayname, share.permissions, OC.PERMISSION_READ | OC.PERMISSION_UPDATE | OC.PERMISSION_CREATE, share.mail_send, false);
+							} else {
+								OC.Share.addShareWith(share.share_type, share.share_with, share.share_with_displayname, share.permissions, possiblePermissions, share.mail_send, false);
+							}
 						}
 					}
 					if (share.expiration != null) {
@@ -455,7 +460,7 @@ OC.Share={
 			$('#shareWith').autocomplete({minLength: 2, delay: 750, source: function(search, response) {
 				var $loading = $('#dropdown .shareWithLoading');
 				$loading.removeClass('hidden');
-				$.get(OC.filePath('core', 'ajax', 'share.php'), { fetch: 'getShareWith', search: search.term.trim(), itemShares: OC.Share.itemShares }, function(result) {
+				$.get(OC.filePath('core', 'ajax', 'share.php'), { fetch: 'getShareWith', search: search.term.trim(), itemShares: OC.Share.itemShares, itemType: itemType }, function(result) {
 					$loading.addClass('hidden');
 					if (result.status == 'success' && result.data.length > 0) {
 						$( "#shareWith" ).autocomplete( "option", "autoFocus", true );
@@ -484,20 +489,23 @@ OC.Share={
 				// Default permissions are Edit (CRUD) and Share
 				// Check if these permissions are possible
 				var permissions = OC.PERMISSION_READ;
-				if (possiblePermissions & OC.PERMISSION_UPDATE) {
-					permissions = permissions | OC.PERMISSION_UPDATE;
-				}
-				if (possiblePermissions & OC.PERMISSION_CREATE) {
-					permissions = permissions | OC.PERMISSION_CREATE;
-				}
-				if (possiblePermissions & OC.PERMISSION_DELETE) {
-					permissions = permissions | OC.PERMISSION_DELETE;
-				}
-				if (oc_appconfig.core.resharingAllowed && (possiblePermissions & OC.PERMISSION_SHARE)) {
-					permissions = permissions | OC.PERMISSION_SHARE;
+				if (shareType === OC.Share.SHARE_TYPE_REMOTE) {
+					permissions = OC.PERMISSION_CREATE | OC.PERMISSION_UPDATE | OC.PERMISSION_READ;
+				} else {
+					if (possiblePermissions & OC.PERMISSION_UPDATE) {
+						permissions = permissions | OC.PERMISSION_UPDATE;
+					}
+					if (possiblePermissions & OC.PERMISSION_CREATE) {
+						permissions = permissions | OC.PERMISSION_CREATE;
+					}
+					if (possiblePermissions & OC.PERMISSION_DELETE) {
+						permissions = permissions | OC.PERMISSION_DELETE;
+					}
+					if (oc_appconfig.core.resharingAllowed && (possiblePermissions & OC.PERMISSION_SHARE)) {
+						permissions = permissions | OC.PERMISSION_SHARE;
+					}
 				}
 
-
 				var $input = $(this);
 				var $loading = $dropDown.find('.shareWithLoading');
 				$loading.removeClass('hidden');
@@ -507,7 +515,11 @@ OC.Share={
 				OC.Share.share(itemType, itemSource, shareType, shareWith, permissions, itemSourceName, expirationDate, function() {
 					$input.prop('disabled', false);
 					$loading.addClass('hidden');
-					OC.Share.addShareWith(shareType, shareWith, selected.item.label, permissions, possiblePermissions);
+					var posPermissions = possiblePermissions;
+					if (shareType === OC.Share.SHARE_TYPE_REMOTE) {
+						posPermissions = permissions;
+					}
+					OC.Share.addShareWith(shareType, shareWith, selected.item.label, permissions, posPermissions);
 					$('#shareWith').val('');
 					$('#dropdown').trigger(new $.Event('sharesChanged', {shares: OC.Share.currentShares}));
 					OC.Share.updateIcon(itemType, itemSource);
@@ -518,13 +530,18 @@ OC.Share={
 			// customize internal _renderItem function to display groups and users differently
 			.data("ui-autocomplete")._renderItem = function( ul, item ) {
 				var insert = $( "<a>" );
-				var text = (item.value.shareType == 1)? item.label + ' ('+t('core', 'group')+')' : item.label;
+				var text = item.label;
+				if (item.value.shareType === OC.Share.SHARE_TYPE_GROUP) {
+					text = text +  ' ('+t('core', 'group')+')';
+				} else if (item.value.shareType === OC.Share.SHARE_TYPE_REMOTE) {
+					text = text +  ' ('+t('core', 'remote')+')';
+				}
 				insert.text( text );
-				if(item.value.shareType == 1) {
+				if(item.value.shareType === OC.Share.SHARE_TYPE_GROUP) {
 					insert = insert.wrapInner('<strong></strong>');
 				}
 				return $( "<li>" )
-					.addClass((item.value.shareType == 1)?'group':'user')
+					.addClass((item.value.shareType === OC.Share.SHARE_TYPE_GROUP)?'group':'user')
 					.append( insert )
 					.appendTo( ul );
 			};
@@ -585,9 +602,12 @@ OC.Share={
 			share_with_displayname: shareWithDisplayName,
 			permissions: permissions
 		};
-		if (shareType === 1) {
+		if (shareType === OC.Share.SHARE_TYPE_GROUP) {
 			shareWithDisplayName = shareWithDisplayName + " (" + t('core', 'group') + ')';
 		}
+		if (shareType === OC.Share.SHARE_TYPE_REMOTE) {
+			shareWithDisplayName = shareWithDisplayName + " (" + t('core', 'remote') + ')';
+		}
 		if (!OC.Share.itemShares[shareType]) {
 			OC.Share.itemShares[shareType] = [];
 		}
@@ -627,7 +647,7 @@ OC.Share={
 			html += '<a href="#" class="unshare"><img class="svg" alt="'+t('core', 'Unshare')+'" title="'+t('core', 'Unshare')+'" src="'+OC.imagePath('core', 'actions/delete')+'"/></a>';
 			html += '<span class="username">' + escapeHTML(shareWithDisplayName) + '</span>';
 			var mailNotificationEnabled = $('input:hidden[name=mailNotificationEnabled]').val();
-			if (mailNotificationEnabled === 'yes') {
+			if (mailNotificationEnabled === 'yes' && shareType !== OC.Share.SHARE_TYPE_REMOTE) {
 				var checked = '';
 				if (mailSend === '1') {
 					checked = 'checked';
@@ -640,17 +660,19 @@ OC.Share={
 			if (possiblePermissions & OC.PERMISSION_CREATE || possiblePermissions & OC.PERMISSION_UPDATE || possiblePermissions & OC.PERMISSION_DELETE) {
 				html += '<input id="canEdit-'+escapeHTML(shareWith)+'" type="checkbox" name="edit" class="permissions" '+editChecked+' /><label for="canEdit-'+escapeHTML(shareWith)+'">'+t('core', 'can edit')+'</label>';
 			}
-			showCrudsButton = '<a href="#" class="showCruds"><img class="svg" alt="'+t('core', 'access control')+'" src="'+OC.imagePath('core', 'actions/triangle-s')+'"/></a>';
+			if (shareType !== OC.Share.SHARE_TYPE_REMOTE) {
+				showCrudsButton = '<a href="#" class="showCruds"><img class="svg" alt="'+t('core', 'access control')+'" src="'+OC.imagePath('core', 'actions/triangle-s')+'"/></a>';
+			}
 			html += '<div class="cruds" style="display:none;">';
-				if (possiblePermissions & OC.PERMISSION_CREATE) {
-					html += '<input id="canCreate-'+escapeHTML(shareWith)+'" type="checkbox" name="create" class="permissions" '+createChecked+' data-permissions="'+OC.PERMISSION_CREATE+'"/><label for="canCreate-'+escapeHTML(shareWith)+'">'+t('core', 'create')+'</label>';
-				}
-				if (possiblePermissions & OC.PERMISSION_UPDATE) {
-					html += '<input id="canUpdate-'+escapeHTML(shareWith)+'" type="checkbox" name="update" class="permissions" '+updateChecked+' data-permissions="'+OC.PERMISSION_UPDATE+'"/><label for="canUpdate-'+escapeHTML(shareWith)+'">'+t('core', 'change')+'</label>';
-				}
-				if (possiblePermissions & OC.PERMISSION_DELETE) {
-					html += '<input id="canDelete-'+escapeHTML(shareWith)+'" type="checkbox" name="delete" class="permissions" '+deleteChecked+' data-permissions="'+OC.PERMISSION_DELETE+'"/><label for="canDelete-'+escapeHTML(shareWith)+'">'+t('core', 'delete')+'</label>';
-				}
+			if (possiblePermissions & OC.PERMISSION_CREATE) {
+				html += '<input id="canCreate-' + escapeHTML(shareWith) + '" type="checkbox" name="create" class="permissions" ' + createChecked + ' data-permissions="' + OC.PERMISSION_CREATE + '"/><label for="canCreate-' + escapeHTML(shareWith) + '">' + t('core', 'create') + '</label>';
+			}
+			if (possiblePermissions & OC.PERMISSION_UPDATE) {
+				html += '<input id="canUpdate-' + escapeHTML(shareWith) + '" type="checkbox" name="update" class="permissions" ' + updateChecked + ' data-permissions="' + OC.PERMISSION_UPDATE + '"/><label for="canUpdate-' + escapeHTML(shareWith) + '">' + t('core', 'change') + '</label>';
+			}
+			if (possiblePermissions & OC.PERMISSION_DELETE) {
+				html += '<input id="canDelete-' + escapeHTML(shareWith) + '" type="checkbox" name="delete" class="permissions" ' + deleteChecked + ' data-permissions="' + OC.PERMISSION_DELETE + '"/><label for="canDelete-' + escapeHTML(shareWith) + '">' + t('core', 'delete') + '</label>';
+			}
 			html += '</div>';
 			html += '</li>';
 			html = $(html).appendTo('#shareWithList');
diff --git a/lib/private/httphelper.php b/lib/private/httphelper.php
index 846825dee8..1f3482b351 100644
--- a/lib/private/httphelper.php
+++ b/lib/private/httphelper.php
@@ -8,7 +8,8 @@
 
 namespace OC;
 
-use \OCP\IConfig;
+use OCP\IConfig;
+use OCP\ICertificateManager;
 
 class HTTPHelper {
 	const USER_AGENT = 'ownCloud Server Crawler';
@@ -16,11 +17,15 @@ class HTTPHelper {
 	/** @var \OCP\IConfig */
 	private $config;
 
+	/** @var \OC\Security\CertificateManager */
+	private $certificateManager;
+
 	/**
 	 * @param \OCP\IConfig $config
 	 */
-	public function __construct(IConfig $config) {
+	public function __construct(IConfig $config, ICertificateManager $certificateManager) {
 		$this->config = $config;
+		$this->certificateManager = $certificateManager;
 	}
 
 	/**
@@ -176,4 +181,50 @@ class HTTPHelper {
 		return $location;
 	}
 
+	/**
+	 * create string of parameters for post request
+	 *
+	 * @param array $parameters
+	 * @return string
+	 */
+	private function assemblePostParameters(array $parameters) {
+		$parameterString = '';
+		foreach ($parameters as $key => $value) {
+			$parameterString .= $key . '=' . urlencode($value) . '&';
+		}
+
+		return rtrim($parameterString, '&');
+	}
+
+	/**
+	 * send http post request
+	 *
+	 * @param string $url
+	 * @param array $fields data send by the request
+	 * @return bool
+	 */
+	public function post($url, array $fields) {
+
+		$fieldsString = $this->assemblePostParameters($fields);
+
+		$certBundle = $this->certificateManager->getCertificateBundle();
+
+		$ch = curl_init();
+
+		curl_setopt($ch, CURLOPT_URL, $url);
+		curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+		curl_setopt($ch, CURLOPT_POST, count($fields));
+		curl_setopt($ch, CURLOPT_POSTFIELDS, $fieldsString);
+		if (is_readable($certBundle)) {
+			curl_setopt($ch, CURLOPT_CAINFO, $certBundle);
+		}
+
+		$result = curl_exec($ch);
+		$success = $result ? true : false;
+
+		curl_close($ch);
+
+		return array('success' => $success, 'result' => $result);
+	}
+
 }
diff --git a/lib/private/security/certificatemanager.php b/lib/private/security/certificatemanager.php
index a2a4c8b83d..4a8ea17073 100644
--- a/lib/private/security/certificatemanager.php
+++ b/lib/private/security/certificatemanager.php
@@ -33,7 +33,7 @@ class CertificateManager implements ICertificateManager {
 	 * @return \OCP\ICertificate[]
 	 */
 	public function listCertificates() {
-		$path = $this->user->getHome() . '/files_external/uploads/';
+		$path = $this->getPathToCertificates() . 'uploads/';
 		if (!is_dir($path)) {
 			return array();
 		}
@@ -57,7 +57,7 @@ class CertificateManager implements ICertificateManager {
 	 * create the certificate bundle of all trusted certificated
 	 */
 	protected function createCertificateBundle() {
-		$path = $this->user->getHome() . '/files_external/';
+		$path = $this->getPathToCertificates();
 		$certs = $this->listCertificates();
 
 		$fh_certs = fopen($path . '/rootcerts.crt', 'w');
@@ -86,7 +86,7 @@ class CertificateManager implements ICertificateManager {
 			return false;
 		}
 
-		$dir = $this->user->getHome() . '/files_external/uploads/';
+		$dir = $this->getPathToCertificates() . 'uploads/';
 		if (!file_exists($dir)) {
 			//path might not exist (e.g. non-standard OC_User::getHome() value)
 			//in this case create full path using 3rd (recursive=true) parameter.
@@ -116,7 +116,7 @@ class CertificateManager implements ICertificateManager {
 		if (!Filesystem::isValidPath($name)) {
 			return false;
 		}
-		$path = $this->user->getHome() . '/files_external/uploads/';
+		$path = $this->getPathToCertificates() . 'uploads/';
 		if (file_exists($path . $name)) {
 			unlink($path . $name);
 			$this->createCertificateBundle();
@@ -130,6 +130,12 @@ class CertificateManager implements ICertificateManager {
 	 * @return string
 	 */
 	public function getCertificateBundle() {
-		return $this->user->getHome() . '/files_external/rootcerts.crt';
+		return $this->getPathToCertificates() . 'rootcerts.crt';
+	}
+
+	private function getPathToCertificates() {
+		$path = $this->user ? $this->user->getHome() . '/files_external/' : '/files_external/';
+
+		return $path;
 	}
 }
diff --git a/lib/private/server.php b/lib/private/server.php
index f4c20576eb..c98f77c647 100644
--- a/lib/private/server.php
+++ b/lib/private/server.php
@@ -249,7 +249,7 @@ class Server extends SimpleContainer implements IServerContainer {
 		});
 		$this->registerService('HTTPHelper', function (Server $c) {
 			$config = $c->getConfig();
-			return new HTTPHelper($config);
+			return new HTTPHelper($config, new \OC\Security\CertificateManager($c->getUserSession()->getUser()));
 		});
 		$this->registerService('EventLogger', function (Server $c) {
 			if (defined('DEBUG') and DEBUG) {
diff --git a/lib/private/share/constants.php b/lib/private/share/constants.php
index 798327cc15..6c9d943160 100644
--- a/lib/private/share/constants.php
+++ b/lib/private/share/constants.php
@@ -34,8 +34,12 @@ class Constants {
 	const FORMAT_STATUSES = -2;
 	const FORMAT_SOURCES = -3;  // ToDo Check if it is still in use otherwise remove it
 
+	const RESPONSE_FORMAT = 'json'; // default resonse format for ocs calls
+
 	const TOKEN_LENGTH = 15; // old (oc7) length is 32, keep token length in db at least that for compatibility
 
+	const BASE_PATH_TO_SHARE_API = '/ocs/v1.php/cloud/shares';
+
 	protected static $shareTypeUserAndGroups = -1;
 	protected static $shareTypeGroupUserUnique = 2;
 	protected static $backends = array();
diff --git a/lib/private/share/helper.php b/lib/private/share/helper.php
index 6bbb101db3..3d20ba2d27 100644
--- a/lib/private/share/helper.php
+++ b/lib/private/share/helper.php
@@ -38,7 +38,7 @@ class Helper extends \OC\Share\Constants {
 	public static function generateTarget($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $suggestedTarget = null, $groupParent = null) {
 		// FIXME: $uidOwner and $groupParent seems to be unused
 		$backend = \OC\Share\Share::getBackend($itemType);
-		if ($shareType == self::SHARE_TYPE_LINK) {
+		if ($shareType === self::SHARE_TYPE_LINK || $shareType === self::SHARE_TYPE_REMOTE) {
 			if (isset($suggestedTarget)) {
 				return $suggestedTarget;
 			}
diff --git a/lib/private/share/share.php b/lib/private/share/share.php
index abcd14f6ec..f61f65f35a 100644
--- a/lib/private/share/share.php
+++ b/lib/private/share/share.php
@@ -247,7 +247,7 @@ class Share extends \OC\Share\Constants {
 	 * @return mixed Return depends on format
 	 */
 	public static function getItemsSharedWith($itemType, $format = self::FORMAT_NONE,
-		$parameters = null, $limit = -1, $includeCollections = false) {
+											  $parameters = null, $limit = -1, $includeCollections = false) {
 		return self::getItems($itemType, null, self::$shareTypeUserAndGroups, \OC_User::getUser(), null, $format,
 			$parameters, $limit, $includeCollections);
 	}
@@ -263,7 +263,7 @@ class Share extends \OC\Share\Constants {
 	 * @return mixed Return depends on format
 	 */
 	public static function getItemsSharedWithUser($itemType, $user, $format = self::FORMAT_NONE,
-		$parameters = null, $limit = -1, $includeCollections = false) {
+												  $parameters = null, $limit = -1, $includeCollections = false) {
 		return self::getItems($itemType, null, self::$shareTypeUserAndGroups, $user, null, $format,
 			$parameters, $limit, $includeCollections);
 	}
@@ -278,7 +278,7 @@ class Share extends \OC\Share\Constants {
 	 * @return mixed Return depends on format
 	 */
 	public static function getItemSharedWith($itemType, $itemTarget, $format = self::FORMAT_NONE,
-		$parameters = null, $includeCollections = false) {
+											 $parameters = null, $includeCollections = false) {
 		return self::getItems($itemType, $itemTarget, self::$shareTypeUserAndGroups, \OC_User::getUser(), null, $format,
 			$parameters, 1, $includeCollections);
 	}
@@ -338,12 +338,12 @@ class Share extends \OC\Share\Constants {
 			$groups = \OC_Group::getUserGroups($user);
 
 			$query = \OC_DB::prepare(
-					'SELECT *
+				'SELECT *
 						FROM
 						`*PREFIX*share`
 						WHERE
 						`' . $column . '` = ? AND `item_type` = ? AND `share_with` in (?)'
-					);
+			);
 
 			$result = \OC_DB::executeAudited($query, array($itemSource, $itemType, implode(',', $groups)));
 
@@ -367,7 +367,7 @@ class Share extends \OC\Share\Constants {
 	 * @return array
 	 */
 	public static function getItemSharedWithBySource($itemType, $itemSource, $format = self::FORMAT_NONE,
-		$parameters = null, $includeCollections = false, $shareWith = null) {
+													 $parameters = null, $includeCollections = false, $shareWith = null) {
 		$shareWith = ($shareWith === null) ? \OC_User::getUser() : $shareWith;
 		return self::getItems($itemType, $itemSource, self::$shareTypeUserAndGroups, $shareWith, null, $format,
 			$parameters, 1, $includeCollections, true);
@@ -445,7 +445,7 @@ class Share extends \OC\Share\Constants {
 	 * @return mixed Return depends on format
 	 */
 	public static function getItemsShared($itemType, $format = self::FORMAT_NONE, $parameters = null,
-		$limit = -1, $includeCollections = false) {
+										  $limit = -1, $includeCollections = false) {
 		return self::getItems($itemType, null, null, null, \OC_User::getUser(), $format,
 			$parameters, $limit, $includeCollections);
 	}
@@ -460,7 +460,7 @@ class Share extends \OC\Share\Constants {
 	 * @return mixed Return depends on format
 	 */
 	public static function getItemShared($itemType, $itemSource, $format = self::FORMAT_NONE,
-	                                     $parameters = null, $includeCollections = false) {
+										 $parameters = null, $includeCollections = false) {
 		return self::getItems($itemType, $itemSource, null, null, \OC_User::getUser(), $format,
 			$parameters, -1, $includeCollections);
 	}
@@ -503,9 +503,19 @@ class Share extends \OC\Share\Constants {
 	 * @throws \Exception
 	 */
 	public static function shareItem($itemType, $itemSource, $shareType, $shareWith, $permissions, $itemSourceName = null, \DateTime $expirationDate = null) {
+
+		$backend = self::getBackend($itemType);
+		$l = \OC::$server->getL10N('lib');
+
+		if ($backend->isShareTypeAllowed($shareType) === false) {
+			$message = 'Sharing %s failed, because the backend does not allow shares from type %i';
+			$message_t = $l->t('Sharing %s failed, because the backend does not allow shares from type %i', array($itemSourceName, $shareType));
+			\OC_Log::write('OCP\Share', sprintf($message, $itemSourceName, $shareType), \OC_Log::ERROR);
+			throw new \Exception($message_t);
+		}
+
 		$uidOwner = \OC_User::getUser();
 		$shareWithinGroupOnly = self::shareWithGroupMembersOnly();
-		$l = \OC::$server->getL10N('lib');
 
 		if (is_null($itemSourceName)) {
 			$itemSourceName = $itemSource;
@@ -655,8 +665,8 @@ class Share extends \OC\Share\Constants {
 				}
 
 				if ($updateExistingShare === false &&
-						self::isDefaultExpireDateEnabled() &&
-						empty($expirationDate)) {
+					self::isDefaultExpireDateEnabled() &&
+					empty($expirationDate)) {
 					$expirationDate = Helper::calcExpireDate();
 				}
 
@@ -681,6 +691,25 @@ class Share extends \OC\Share\Constants {
 			$message_t = $l->t('Sharing %s failed, because sharing with links is not allowed', array($itemSourceName));
 			\OC_Log::write('OCP\Share', sprintf($message, $itemSourceName), \OC_Log::ERROR);
 			throw new \Exception($message_t);
+		} else if ($shareType === self::SHARE_TYPE_REMOTE) {
+			$token = \OC::$server->getSecureRandom()->getMediumStrengthGenerator()->generate(self::TOKEN_LENGTH, \OCP\Security\ISecureRandom::CHAR_LOWER . \OCP\Security\ISecureRandom::CHAR_UPPER .
+				\OCP\Security\ISecureRandom::CHAR_DIGITS);
+
+			$shareId = self::put($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions, null, $token, $itemSourceName);
+
+			$send = false;
+			if ($shareId) {
+				$send = self::sendRemoteShare($token, $shareWith, $itemSourceName, $shareId, $uidOwner);
+			}
+
+			if ($send === false) {
+				$currentUser = \OC::$server->getUserSession()->getUser()->getUID();
+				self::unshare($itemType, $itemSource, $shareType, $shareWith, $currentUser);
+				$message_t = $l->t('Sharing %s failed, could not find %s, maybe the server is currently unreachable.', array($itemSourceName, $shareWith));
+				throw new \Exception($message_t);
+			}
+
+			return $send;
 		} else {
 			// Future share types need to include their own conditions
 			$message = 'Share type %s is not valid for %s';
@@ -690,7 +719,9 @@ class Share extends \OC\Share\Constants {
 		}
 
 		// Put the item into the database
-		return self::put($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions, null, null, $itemSourceName, $expirationDate);
+		$result = self::put($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions, null, null, $itemSourceName, $expirationDate);
+
+		return $result ? true : false;
 	}
 
 	/**
@@ -716,9 +747,9 @@ class Share extends \OC\Share\Constants {
 			// delete the item with the expected share_type and owner
 			if ((int)$item['share_type'] === (int)$shareType && $item['uid_owner'] === $currentUser) {
 				$toDelete = $item;
-			// if there is more then one result we don't have to delete the children
-			// but update their parent. For group shares the new parent should always be
-			// the original group share and not the db entry with the unique name
+				// if there is more then one result we don't have to delete the children
+				// but update their parent. For group shares the new parent should always be
+				// the original group share and not the db entry with the unique name
 			} else if ((int)$item['share_type'] === self::$shareTypeGroupUserUnique) {
 				$newParent = $item['parent'];
 			} else {
@@ -794,7 +825,7 @@ class Share extends \OC\Share\Constants {
 		$itemUnshared = false;
 		foreach ($shares as $share) {
 			if ((int)$share['share_type'] === \OCP\Share::SHARE_TYPE_USER &&
-					$share['share_with'] === $uid) {
+				$share['share_with'] === $uid) {
 				$deletedShares = Helper::delete($share['id']);
 				$shareTmp = array(
 					'id' => $share['id'],
@@ -814,16 +845,16 @@ class Share extends \OC\Share\Constants {
 					$groupShare = $share;
 				}
 			} elseif ((int)$share['share_type'] === self::$shareTypeGroupUserUnique &&
-					$share['share_with'] === $uid) {
+				$share['share_with'] === $uid) {
 				$uniqueGroupShare = $share;
 			}
 		}
 
 		if (!$itemUnshared && isset($groupShare) && !isset($uniqueGroupShare)) {
 			$query = \OC_DB::prepare('INSERT INTO `*PREFIX*share`'
-					.' (`item_type`, `item_source`, `item_target`, `parent`, `share_type`,'
-					.' `share_with`, `uid_owner`, `permissions`, `stime`, `file_source`, `file_target`)'
-					.' VALUES (?,?,?,?,?,?,?,?,?,?,?)');
+				.' (`item_type`, `item_source`, `item_target`, `parent`, `share_type`,'
+				.' `share_with`, `uid_owner`, `permissions`, `stime`, `file_source`, `file_target`)'
+				.' VALUES (?,?,?,?,?,?,?,?,?,?,?)');
 			$query->execute(array($groupShare['item_type'], $groupShare['item_source'], $groupShare['item_target'],
 				$groupShare['id'], self::$shareTypeGroupUserUnique,
 				\OC_User::getUser(), $groupShare['uid_owner'], 0, $groupShare['stime'], $groupShare['file_source'],
@@ -834,7 +865,7 @@ class Share extends \OC\Share\Constants {
 				'itemTarget' => $groupShare['item_target'],
 				'itemType' => $groupShare['item_type'],
 				'shareType' => (int)$groupShare['share_type'],
-				);
+			);
 			if (isset($groupShare['file_target'])) {
 				$shareTmp['fileTarget'] = $groupShare['file_target'];
 			}
@@ -849,7 +880,7 @@ class Share extends \OC\Share\Constants {
 				'itemTarget' => $uniqueGroupShare['item_target'],
 				'itemType' => $uniqueGroupShare['item_type'],
 				'shareType' => (int)$uniqueGroupShare['share_type'],
-				);
+			);
 			if (isset($uniqueGroupShare['file_target'])) {
 				$shareTmp['fileTarget'] = $uniqueGroupShare['file_target'];
 			}
@@ -859,7 +890,7 @@ class Share extends \OC\Share\Constants {
 
 		if ($itemUnshared) {
 			\OC_Hook::emit('OCP\Share', 'post_unshareFromSelf',
-					array('unsharedItems' => $listOfUnsharedItems, 'itemType' => $itemType));
+				array('unsharedItems' => $listOfUnsharedItems, 'itemType' => $itemType));
 		}
 
 		return $itemUnshared;
@@ -877,7 +908,7 @@ class Share extends \OC\Share\Constants {
 		$status = $status ? 1 : 0;
 
 		$query = \OC_DB::prepare(
-				'UPDATE `*PREFIX*share`
+			'UPDATE `*PREFIX*share`
 					SET `mail_send` = ?
 					WHERE `item_type` = ? AND `item_source` = ? AND `share_type` = ? AND `share_with` = ?');
 
@@ -1124,6 +1155,10 @@ class Share extends \OC\Share\Constants {
 		$deletedShares[] = $hookParams;
 		$hookParams['deletedShares'] = $deletedShares;
 		\OC_Hook::emit('OCP\Share', 'post_unshare', $hookParams);
+		if ((int)$item['share_type'] === \OCP\Share::SHARE_TYPE_REMOTE && \OC::$server->getUserSession()->getUser()) {
+			$urlParts = explode('@', $item['share_with'], 2);
+			self::sendRemoteUnshare($urlParts[1], $item['id'], $item['token']);
+		}
 	}
 
 	/**
@@ -1202,14 +1237,14 @@ class Share extends \OC\Share\Constants {
 	}
 
 	/**
-	* Get the owners of items shared with a user.
-	*
-	* @param string $user The user the items are shared with.
-	* @param string $type The type of the items shared with the user.
-	* @param boolean $includeCollections Include collection item types (optional)
-	* @param boolean $includeOwner include owner in the list of users the item is shared with (optional)
-	* @return array
-	*/
+	 * Get the owners of items shared with a user.
+	 *
+	 * @param string $user The user the items are shared with.
+	 * @param string $type The type of the items shared with the user.
+	 * @param boolean $includeCollections Include collection item types (optional)
+	 * @param boolean $includeOwner include owner in the list of users the item is shared with (optional)
+	 * @return array
+	 */
 	public static function getSharedItemsOwners($user, $type, $includeCollections = false, $includeOwner = false) {
 		// First, we find out if $type is part of a collection (and if that collection is part of
 		// another one and so on).
@@ -1271,8 +1306,8 @@ class Share extends \OC\Share\Constants {
 	 *
 	 */
 	public static function getItems($itemType, $item = null, $shareType = null, $shareWith = null,
-		$uidOwner = null, $format = self::FORMAT_NONE, $parameters = null, $limit = -1,
-		$includeCollections = false, $itemShareWithBySource = false, $checkExpireDate  = true) {
+									$uidOwner = null, $format = self::FORMAT_NONE, $parameters = null, $limit = -1,
+									$includeCollections = false, $itemShareWithBySource = false, $checkExpireDate  = true) {
 		if (!self::isEnabled()) {
 			return array();
 		}
@@ -1481,8 +1516,8 @@ class Share extends \OC\Share\Constants {
 					$parentResult = $query->execute(array($row['parent']));
 					if (\OC_DB::isError($result)) {
 						\OC_Log::write('OCP\Share', 'Can\'t select parent: ' .
-								\OC_DB::getErrorMessage($result) . ', select=' . $select . ' where=' . $where,
-								\OC_Log::ERROR);
+							\OC_DB::getErrorMessage($result) . ', select=' . $select . ' where=' . $where,
+							\OC_Log::ERROR);
 					} else {
 						$parentRow = $parentResult->fetchRow();
 						$tmpPath = $parentRow['file_target'];
@@ -1521,7 +1556,7 @@ class Share extends \OC\Share\Constants {
 			}
 			// Add display names to result
 			if ( isset($row['share_with']) && $row['share_with'] != '' &&
-					isset($row['share_with']) && $row['share_type'] === self::SHARE_TYPE_USER) {
+				isset($row['share_with']) && $row['share_type'] === self::SHARE_TYPE_USER) {
 				$row['share_with_displayname'] = \OCP\User::getDisplayName($row['share_with']);
 			} else {
 				$row['share_with_displayname'] = $row['share_with'];
@@ -1668,7 +1703,7 @@ class Share extends \OC\Share\Constants {
 				// only group shares if they already point to the same target, otherwise the file where shared
 				// before grouping of shares was added. In this case we don't group them toi avoid confusions
 				if (( $fileSharing && $item['file_source'] === $r['file_source'] && $item['file_target'] === $r['file_target']) ||
-						(!$fileSharing && $item['item_source'] === $r['item_source'] && $item['item_target'] === $r['item_target'])) {
+					(!$fileSharing && $item['item_source'] === $r['item_source'] && $item['item_target'] === $r['item_target'])) {
 					// add the first item to the list of grouped shares
 					if (!isset($result[$key]['grouped'])) {
 						$result[$key]['grouped'][] = $result[$key];
@@ -1689,7 +1724,7 @@ class Share extends \OC\Share\Constants {
 		return $result;
 	}
 
-/**
+	/**
 	 * Put shared item into the database
 	 * @param string $itemType Item type
 	 * @param string $itemSource Item source
@@ -1702,10 +1737,10 @@ class Share extends \OC\Share\Constants {
 	 * @param string $itemSourceName name of the source item (optional)
 	 * @param \DateTime $expirationDate (optional)
 	 * @throws \Exception
-	 * @return boolean Returns true on success or false on failure
+	 * @return mixed id of the new share or false
 	 */
 	private static function put($itemType, $itemSource, $shareType, $shareWith, $uidOwner,
-		$permissions, $parentFolder = null, $token = null, $itemSourceName = null, \DateTime $expirationDate = null) {
+								$permissions, $parentFolder = null, $token = null, $itemSourceName = null, \DateTime $expirationDate = null) {
 
 		$queriesToExecute = array();
 		$suggestedItemTarget = null;
@@ -1730,7 +1765,7 @@ class Share extends \OC\Share\Constants {
 				unset($users[array_search(\OCP\User::getUser(), $users)]);
 			}
 			$groupItemTarget = Helper::generateTarget($itemType, $itemSource, $shareType, $shareWith['group'],
-					$uidOwner, $suggestedItemTarget);
+				$uidOwner, $suggestedItemTarget);
 			$groupFileTarget = $filePath;
 
 			// add group share to table and remember the id as parent
@@ -1753,7 +1788,7 @@ class Share extends \OC\Share\Constants {
 		} else {
 			$users = array($shareWith);
 			$itemTarget = Helper::generateTarget($itemType, $itemSource, $shareType, $shareWith, $uidOwner,
-					$suggestedItemTarget);
+				$suggestedItemTarget);
 		}
 
 		$run = true;
@@ -1829,7 +1864,7 @@ class Share extends \OC\Share\Constants {
 				// do we also need a file target
 				if (isset($fileSource)) {
 					$fileTarget = Helper::generateTarget('file', $filePath, self::SHARE_TYPE_USER, $user,
-							$uidOwner, $suggestedFileTarget, $parent);
+						$uidOwner, $suggestedFileTarget, $parent);
 				} else {
 					$fileTarget = null;
 				}
@@ -1840,25 +1875,26 @@ class Share extends \OC\Share\Constants {
 			}
 
 			$queriesToExecute[] = array(
-					'itemType'			=> $itemType,
-					'itemSource'		=> $itemSource,
-					'itemTarget'		=> $itemTarget,
-					'shareType'			=> $shareType,
-					'shareWith'			=> $user,
-					'uidOwner'			=> $uidOwner,
-					'permissions'		=> $permissions,
-					'shareTime'			=> time(),
-					'fileSource'		=> $fileSource,
-					'fileTarget'		=> $fileTarget,
-					'token'				=> $token,
-					'parent'			=> $parent,
-					'expiration'		=> $expirationDate,
-				);
+				'itemType'			=> $itemType,
+				'itemSource'		=> $itemSource,
+				'itemTarget'		=> $itemTarget,
+				'shareType'			=> $shareType,
+				'shareWith'			=> $user,
+				'uidOwner'			=> $uidOwner,
+				'permissions'		=> $permissions,
+				'shareTime'			=> time(),
+				'fileSource'		=> $fileSource,
+				'fileTarget'		=> $fileTarget,
+				'token'				=> $token,
+				'parent'			=> $parent,
+				'expiration'		=> $expirationDate,
+			);
 
 		}
 
+		$id = false;
 		if ($isGroupShare) {
-			self::insertShare($queriesToExecute['groupShare']);
+			$id = self::insertShare($queriesToExecute['groupShare']);
 			// Save this id, any extra rows for this group share will need to reference it
 			$parent = \OC_DB::insertid('*PREFIX*share');
 			unset($queriesToExecute['groupShare']);
@@ -1866,7 +1902,7 @@ class Share extends \OC\Share\Constants {
 
 		foreach ($queriesToExecute as $shareQuery) {
 			$shareQuery['parent'] = $parent;
-			self::insertShare($shareQuery);
+			$id = self::insertShare($shareQuery);
 		}
 
 		$postHookData = array(
@@ -1889,7 +1925,7 @@ class Share extends \OC\Share\Constants {
 		\OC_Hook::emit('OCP\Share', 'post_shared', $postHookData);
 
 
-		return true;
+		return $id ? $id : false;
 	}
 
 	private static function checkReshare($itemType, $itemSource, $shareType, $shareWith, $uidOwner, $permissions, $itemSourceName, $expirationDate) {
@@ -1983,6 +2019,11 @@ class Share extends \OC\Share\Constants {
 		return $result;
 	}
 
+	/**
+	 *
+	 * @param array $shareData
+	 * @return mixed false in case of a failure or the id of the new share
+	 */
 	private static function insertShare(array $shareData)
 	{
 		$query = \OC_DB::prepare('INSERT INTO `*PREFIX*share` ('
@@ -2002,7 +2043,30 @@ class Share extends \OC\Share\Constants {
 		$query->bindValue(11, $shareData['token']);
 		$query->bindValue(12, $shareData['parent']);
 		$query->bindValue(13, $shareData['expiration'], 'datetime');
-		$query->execute();
+		$result = $query->execute();
+
+		$id = false;
+		if ($result) {
+			$id =  \OC::$server->getDatabaseConnection()->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) {
+				$getId = \OC_DB::prepare('
+					SELECT `id`
+					FROM`*PREFIX*share`
+					WHERE `uid_owner` = ? AND `item_target` = ? AND `item_source` = ? AND `stime` = ?
+					');
+				$r = $getId->execute(array($shareData['uidOwner'], $shareData['itemTarget'], $shareData['itemSource'], $shareData['shareTime']));
+				if ($r) {
+					$row = $r->fetchRow();
+					$id = $row['id'];
+				}
+			}
+
+		}
+
+		return $id;
+
 	}
 	/**
 	 * Delete all shares with type SHARE_TYPE_LINK
@@ -2064,19 +2128,19 @@ class Share extends \OC\Share\Constants {
 			if (isset($uidOwner)) {
 				if ($fileDependent) {
 					$select = '`*PREFIX*share`.`id`, `item_type`, `item_source`, `*PREFIX*share`.`parent`,'
-							. ' `share_type`, `share_with`, `file_source`, `file_target`, `path`, `*PREFIX*share`.`permissions`, `stime`,'
-							. ' `expiration`, `token`, `storage`, `mail_send`, `uid_owner`';
+						. ' `share_type`, `share_with`, `file_source`, `file_target`, `path`, `*PREFIX*share`.`permissions`, `stime`,'
+						. ' `expiration`, `token`, `storage`, `mail_send`, `uid_owner`';
 				} else {
 					$select = '`id`, `item_type`, `item_source`, `parent`, `share_type`, `share_with`, `*PREFIX*share`.`permissions`,'
-							. ' `stime`, `file_source`, `expiration`, `token`, `mail_send`, `uid_owner`';
+						. ' `stime`, `file_source`, `expiration`, `token`, `mail_send`, `uid_owner`';
 				}
 			} else {
 				if ($fileDependent) {
 					if ($format == \OC_Share_Backend_File::FORMAT_GET_FOLDER_CONTENTS || $format == \OC_Share_Backend_File::FORMAT_FILE_APP_ROOT) {
 						$select = '`*PREFIX*share`.`id`, `item_type`, `item_source`, `*PREFIX*share`.`parent`, `uid_owner`, '
-								. '`share_type`, `share_with`, `file_source`, `path`, `file_target`, `stime`, '
-								. '`*PREFIX*share`.`permissions`, `expiration`, `storage`, `*PREFIX*filecache`.`parent` as `file_parent`, '
-								. '`name`, `mtime`, `mimetype`, `mimepart`, `size`, `unencrypted_size`, `encrypted`, `etag`, `mail_send`';
+							. '`share_type`, `share_with`, `file_source`, `path`, `file_target`, `stime`, '
+							. '`*PREFIX*share`.`permissions`, `expiration`, `storage`, `*PREFIX*filecache`.`parent` as `file_parent`, '
+							. '`name`, `mtime`, `mimetype`, `mimepart`, `size`, `unencrypted_size`, `encrypted`, `etag`, `mail_send`';
 					} else {
 						$select = '`*PREFIX*share`.`id`, `item_type`, `item_source`, `item_target`,
 							`*PREFIX*share`.`parent`, `share_type`, `share_with`, `uid_owner`,
@@ -2150,6 +2214,99 @@ class Share extends \OC\Share\Constants {
 		}
 	}
 
+	/**
+	 * remove protocol from URL
+	 *
+	 * @param string $url
+	 * @return string
+	 */
+	private static function removeProtocolFromUrl($url) {
+		if (strpos($url, 'https://') === 0) {
+			return substr($url, strlen('https://'));
+		} else if (strpos($url, 'http://') === 0) {
+			return substr($url, strlen('http://'));
+		}
+
+		return $url;
+	}
+
+	/**
+	 * try http post first with https and then with http as a fallback
+	 *
+	 * @param string $url
+	 * @param array $fields post parameters
+	 * @return bool
+	 */
+	private static function tryHttpPost($url, $fields) {
+		$protocol = 'https://';
+		$success = false;
+		$try = 0;
+		while ($success === false && $try < 2) {
+			$result = \OC::$server->getHTTPHelper()->post($protocol . $url, $fields);
+			$success = $result['success'];
+			$try++;
+			$protocol = 'http://';
+		}
+
+		return $result;
+	}
+
+	/**
+	 * send server-to-server share to remote server
+	 *
+	 * @param string $token
+	 * @param string $shareWith
+	 * @param string $name
+	 * @param int $remote_id
+	 * @param string $owner
+	 * @return bool
+	 */
+	private static function sendRemoteShare($token, $shareWith, $name, $remote_id, $owner) {
+
+		list($user, $remote) = explode('@', $shareWith, 2);
+
+		if ($user && $remote) {
+			$url = $remote . self::BASE_PATH_TO_SHARE_API . '?format=' . self::RESPONSE_FORMAT;
+
+			$local = \OC::$server->getURLGenerator()->getAbsoluteURL('');
+
+			$fields = array(
+				'shareWith' => $user,
+				'token' => $token,
+				'name' => $name,
+				'remoteId' => $remote_id,
+				'owner' => $owner,
+				'remote' => $local,
+			);
+
+			$url = self::removeProtocolFromUrl($url);
+			$result = self::tryHttpPost($url, $fields);
+			$status = json_decode($result['result'], true);
+
+			return ($result['success'] && $status['ocs']['meta']['statuscode'] === 100);
+
+		}
+
+		return false;
+	}
+
+	/**
+	 * send server-to-server unshare to remote server
+	 *
+	 * @param string remote url
+	 * @param int $id share id
+	 * @param string $token
+	 * @return bool
+	 */
+	private static function sendRemoteUnshare($remote, $id, $token) {
+		$url = $remote . self::BASE_PATH_TO_SHARE_API . '/' . $id . '/unshare?format=' . self::RESPONSE_FORMAT;
+		$fields = array('token' => $token, 'format' => 'json');
+		$result = self::tryHttpPost($url, $fields);
+		$status = json_decode($result['result'], true);
+
+		return ($result['success'] && $status['ocs']['meta']['statuscode'] === 100);
+	}
+
 	/**
 	 * check if user can only share with group members
 	 * @return bool
diff --git a/lib/public/share_backend.php b/lib/public/share_backend.php
index 6ab234aecf..1ae63d4c1d 100644
--- a/lib/public/share_backend.php
+++ b/lib/public/share_backend.php
@@ -65,4 +65,16 @@ interface Share_Backend {
 	 */
 	public function formatItems($items, $format, $parameters = null);
 
+	/**
+	 * Check if a given share type is allowd by the back-end
+	 *
+	 * @param int $shareType share type
+	 * @return boolean
+	 *
+	 * The back-end can enable/disable specific share types. Just return true if
+	 * the back-end doesn't provide any specific settings for it and want to allow
+	 * all share types defined by the share API
+	 */
+	public function isShareTypeAllowed($shareType);
+
 }
diff --git a/tests/lib/app/infoparser.php b/tests/lib/app/infoparser.php
index e291b616e8..762a3584cd 100644
--- a/tests/lib/app/infoparser.php
+++ b/tests/lib/app/infoparser.php
@@ -21,8 +21,9 @@ class InfoParser extends \PHPUnit_Framework_TestCase {
 	public function setUp() {
 		$config = $this->getMockBuilder('\OCP\IConfig')
 			->disableOriginalConstructor()->getMock();
+		$certificateManager = $this->getMock('\OCP\ICertificateManager');
 		$httpHelper = $this->getMockBuilder('\OC\HTTPHelper')
-			->setConstructorArgs(array($config))
+			->setConstructorArgs(array($config, $certificateManager))
 			->setMethods(array('getHeaders'))
 			->getMock();
 		$urlGenerator = $this->getMockBuilder('\OCP\IURLGenerator')
diff --git a/tests/lib/httphelper.php b/tests/lib/httphelper.php
index 1cc4232ab4..48d6543f1f 100644
--- a/tests/lib/httphelper.php
+++ b/tests/lib/httphelper.php
@@ -12,14 +12,17 @@ class TestHTTPHelper extends \Test\TestCase {
 	private $config;
 	/** @var \OC\HTTPHelper */
 	private $httpHelperMock;
+	/** @var \OC\Security\CertificateManager */
+	private $certificateManager;
 
 	protected function setUp() {
 		parent::setUp();
 
 		$this->config = $this->getMockBuilder('\OCP\IConfig')
 			->disableOriginalConstructor()->getMock();
+		$this->certificateManager = $this->getMock('\OCP\ICertificateManager');
 		$this->httpHelperMock = $this->getMockBuilder('\OC\HTTPHelper')
-			->setConstructorArgs(array($this->config))
+			->setConstructorArgs(array($this->config, $this->certificateManager))
 			->setMethods(array('getHeaders'))
 			->getMock();
 	}
@@ -87,4 +90,23 @@ class TestHTTPHelper extends \Test\TestCase {
 			$this->assertSame($expected, $this->httpHelperMock->isHTTPURL($url));
 	}
 
+
+	/**
+	 * @dataProvider postParameters
+	 */
+	public function testassemblePostParameters($parameterList, $expectedResult) {
+		$helper = \OC::$server->getHTTPHelper();
+		$result = \Test_Helper::invokePrivate($helper, 'assemblePostParameters', array($parameterList));
+		$this->assertSame($expectedResult, $result);
+	}
+
+	public function postParameters() {
+		return array(
+			array(array('k1' => 'v1'), 'k1=v1'),
+			array(array('k1' => 'v1', 'k2' => 'v2'), 'k1=v1&k2=v2'),
+			array(array(), ''),
+		);
+	}
+
+
 }
diff --git a/tests/lib/share/backend.php b/tests/lib/share/backend.php
index 0795826694..9c0d7fcb02 100644
--- a/tests/lib/share/backend.php
+++ b/tests/lib/share/backend.php
@@ -84,4 +84,8 @@ class Test_Share_Backend implements OCP\Share_Backend {
 		return $testItems;
 	}
 
+	public function isShareTypeAllowed($shareType) {
+		return true;
+	}
+
 }
diff --git a/tests/lib/share/share.php b/tests/lib/share/share.php
index 1f95502919..b8abfa29a8 100644
--- a/tests/lib/share/share.php
+++ b/tests/lib/share/share.php
@@ -848,6 +848,23 @@ class Test_Share extends \Test\TestCase {
 		);
 	}
 
+	/**
+	 * @dataProvider urls
+	 */
+	function testRemoveProtocolFromUrl($url, $expectedResult) {
+		$share = new \OC\Share\Share();
+		$result = \Test_Helper::invokePrivate($share, 'removeProtocolFromUrl', array($url));
+		$this->assertSame($expectedResult, $result);
+	}
+
+	function urls() {
+		return array(
+			array('http://owncloud.org', 'owncloud.org'),
+			array('https://owncloud.org', 'owncloud.org'),
+			array('owncloud.org', 'owncloud.org'),
+		);
+	}
+
 	/**
 	 * @dataProvider dataProviderTestGroupItems
 	 * @param type $ungrouped
diff --git a/tests/lib/updater.php b/tests/lib/updater.php
index 2dab2750dc..f847ffc91b 100644
--- a/tests/lib/updater.php
+++ b/tests/lib/updater.php
@@ -30,30 +30,30 @@ class UpdaterTest extends \Test\TestCase {
 		$updater = new Updater(\OC::$server->getHTTPHelper(), \OC::$server->getConfig());
 		$this->assertSame($result, $updater->isUpgradePossible($oldVersion, $newVersion));
 	}
-	
+
 	public function testBrokenXmlResponse(){
 		$invalidUpdater = $this->getUpdaterMock('OMG!');
 		$invalidResult = $invalidUpdater->check();
 		$this->assertEmpty($invalidResult);
 	}
-	
+
 	public function testEmptyResponse(){
 		$emptyUpdater = $this->getUpdaterMock('');
 		$emptyResult = $emptyUpdater->check();
 		$this->assertEmpty($emptyResult);
-		
+
 		// Error while fetching new contents e.g. too many redirects
 		$falseUpdater = $this->getUpdaterMock(false);
 		$falseResult = $falseUpdater->check();
 		$this->assertEmpty($falseResult);
 	}
-	
+
 	public function testValidEmptyXmlResponse(){
 		$updater = $this->getUpdaterMock(
 				'<?xml version="1.0"?><owncloud><version></version><versionstring></versionstring><url></url><web></web></owncloud>'
 		);
 		$result = array_map('strval', $updater->check());
-		
+
 		$this->assertArrayHasKey('version', $result);
 		$this->assertArrayHasKey('versionstring', $result);
 		$this->assertArrayHasKey('url', $result);
@@ -63,7 +63,7 @@ class UpdaterTest extends \Test\TestCase {
 		$this->assertEmpty($result['url']);
 		$this->assertEmpty($result['web']);
 	}
-	
+
 	public function testValidUpdateResponse(){
 		$newUpdater = $this->getUpdaterMock(
 				'<?xml version="1.0"?>
@@ -75,7 +75,7 @@ class UpdaterTest extends \Test\TestCase {
 </owncloud>'
 		);
 		$newResult = array_map('strval', $newUpdater->check());
-		
+
 		$this->assertArrayHasKey('version', $newResult);
 		$this->assertArrayHasKey('versionstring', $newResult);
 		$this->assertArrayHasKey('url', $newResult);
@@ -85,22 +85,22 @@ class UpdaterTest extends \Test\TestCase {
 		$this->assertEquals('http://download.owncloud.org/community/owncloud-7.0.3.zip', $newResult['url']);
 		$this->assertEquals('http://owncloud.org/', $newResult['web']);
 	}
-	
+
 	protected function getUpdaterMock($content){
 		// Invalidate cache
 		$mockedAppConfig = $this->getMockBuilder('\OC\AppConfig')
 				->disableOriginalConstructor()
 				->getMock()
 		;
-		
+
+		$certificateManager = $this->getMock('\OCP\ICertificateManager');
 		$mockedHTTPHelper = $this->getMockBuilder('\OC\HTTPHelper')
-				->setConstructorArgs(array(\OC::$server->getConfig()))
+				->setConstructorArgs(array(\OC::$server->getConfig(), $certificateManager))
 				->getMock()
 		;
-		
-		$mockedHTTPHelper->method('getUrlContent')
-				->willReturn($content)
-		;
+
+		$mockedHTTPHelper->expects($this->once())->method('getUrlContent')->will($this->returnValue($content));
+
 		return new Updater($mockedHTTPHelper, $mockedAppConfig);
 	}
 
-- 
GitLab