diff --git a/apps/cloud_federation_api/lib/Controller/RequestHandlerController.php b/apps/cloud_federation_api/lib/Controller/RequestHandlerController.php index c31ff10e1d733..bdd617f3bb6f9 100644 --- a/apps/cloud_federation_api/lib/Controller/RequestHandlerController.php +++ b/apps/cloud_federation_api/lib/Controller/RequestHandlerController.php @@ -122,7 +122,6 @@ public function __construct($appName, * Example: curl -H "Content-Type: application/json" -X POST -d '{"shareWith":"admin1@serve1","name":"welcome server2.txt","description":"desc","providerId":"2","owner":"admin2@http://localhost/server2","ownerDisplayName":"admin2 display","shareType":"user","resourceType":"file","protocol":{"name":"webdav","options":{"sharedSecret":"secret","permissions":"webdav-property"}}}' http://localhost/server/index.php/ocm/shares */ public function addShare($shareWith, $name, $description, $providerId, $owner, $ownerDisplayName, $sharedBy, $sharedByDisplayName, $protocol, $shareType, $resourceType) { - // check if all required parameters are set if ($shareWith === null || $name === null || @@ -177,6 +176,8 @@ public function addShare($shareWith, $name, $description, $providerId, $owner, $ $ownerDisplayName = $ownerDisplayName === null ? $owner : $ownerDisplayName; $sharedByDisplayName = $sharedByDisplayName === null ? $sharedBy : $sharedByDisplayName; + $password = ''; + // sharedBy* parameter is optional, if nothing is set we assume that it is the same user as the owner if ($sharedBy === null) { $sharedBy = $owner; @@ -185,7 +186,7 @@ public function addShare($shareWith, $name, $description, $providerId, $owner, $ try { $provider = $this->cloudFederationProviderManager->getCloudFederationProvider($resourceType); - $share = $this->factory->getCloudFederationShare($shareWith, $name, $description, $providerId, $owner, $ownerDisplayName, $sharedBy, $sharedByDisplayName, '', $shareType, $resourceType); + $share = $this->factory->getCloudFederationShare($shareWith, $name, $description, $providerId, $owner, $ownerDisplayName, $sharedBy, $sharedByDisplayName, '', $shareType, $resourceType, $password); $share->setProtocol($protocol); $provider->shareReceived($share); } catch (ProviderDoesNotExistsException $e) { diff --git a/apps/dav/appinfo/v1/publicwebdav.php b/apps/dav/appinfo/v1/publicwebdav.php index f0e3cc6438dd4..8279aea0a5e5b 100644 --- a/apps/dav/appinfo/v1/publicwebdav.php +++ b/apps/dav/appinfo/v1/publicwebdav.php @@ -29,6 +29,8 @@ * */ +use OCP\GlobalScale\IConfig as IGlobalScaleConfig; + // load needed apps $RUNTIME_APPTYPES = ['filesystem', 'authentication', 'logging']; @@ -41,7 +43,8 @@ $authBackend = new OCA\DAV\Connector\PublicAuth( \OC::$server->getRequest(), \OC::$server->getShareManager(), - \OC::$server->getSession() + \OC::$server->getSession(), + \OC::$server->query(IGlobalScaleConfig::class) ); $authPlugin = new \Sabre\DAV\Auth\Plugin($authBackend); diff --git a/apps/dav/lib/Connector/PublicAuth.php b/apps/dav/lib/Connector/PublicAuth.php index d92fbc68df3b7..39a267fb72856 100644 --- a/apps/dav/lib/Connector/PublicAuth.php +++ b/apps/dav/lib/Connector/PublicAuth.php @@ -30,6 +30,8 @@ namespace OCA\DAV\Connector; +use OCP\GlobalScale\IConfig as IGlobalScaleConfig; +use OCP\IConfig; use OCP\IRequest; use OCP\ISession; use OCP\Share\Exceptions\ShareNotFound; @@ -56,17 +58,24 @@ class PublicAuth extends AbstractBasic { /** @var IRequest */ private $request; + /** @var IGlobalScaleConfig */ + private $gsConfig; + + /** * @param IRequest $request * @param IManager $shareManager * @param ISession $session + * @param IGlobalScaleConfig $gsConfig */ public function __construct(IRequest $request, IManager $shareManager, - ISession $session) { + ISession $session, + IGlobalScaleConfig $gsConfig) { $this->request = $request; $this->shareManager = $shareManager; $this->session = $session; + $this->gsConfig = $gsConfig; // setup realm $defaults = new \OCP\Defaults(); @@ -117,11 +126,21 @@ protected function validateUserPass($username, $password) { return false; } } else if ($share->getShareType() === IShare::TYPE_REMOTE) { + // there is no password in federation share ? return true; } else { return false; } } else { + + if ($share->getShareType() === IShare::TYPE_REMOTE || $share->getShareType() === IShare::TYPE_REMOTE_GROUP) { + if ($this->gsConfig->allowedOutgoingFederation('', $share->getToken(), $password)) { + return true; + } + + return false; + } + return true; } } diff --git a/apps/federatedfilesharing/lib/AppInfo/Application.php b/apps/federatedfilesharing/lib/AppInfo/Application.php index dc1b8541f07ee..641f2835c7fc2 100644 --- a/apps/federatedfilesharing/lib/AppInfo/Application.php +++ b/apps/federatedfilesharing/lib/AppInfo/Application.php @@ -37,7 +37,8 @@ use OCA\FederatedFileSharing\Notifier; use OCA\FederatedFileSharing\OCM\CloudFederationProviderFiles; use OCP\AppFramework\App; -use OCP\GlobalScale\IConfig; + +use OCP\GlobalScale\IConfig as IGlobalScaleConfig; class Application extends App { @@ -68,6 +69,7 @@ function() use ($container) { $server->getURLGenerator(), $server->getCloudFederationFactory(), $server->getCloudFederationProviderManager(), + $server->query(IGlobalScaleConfig::class), $server->getDatabaseConnection(), $server->getGroupManager() ); @@ -109,7 +111,7 @@ function() use ($container) { $federatedShareProvider = $this->getFederatedShareProvider(); $manager->registerNotifierService(Notifier::class); - + $eventDispatcher->addListener( 'OCA\Files::loadAdditionalScripts', function() use ($federatedShareProvider) { @@ -166,7 +168,7 @@ protected function initFederatedShareProvider() { \OC::$server->getConfig(), \OC::$server->getUserManager(), \OC::$server->getCloudIdManager(), - $c->query(IConfig::class), + $c->query(IGlobalScaleConfig::class), \OC::$server->getCloudFederationProviderManager() ); diff --git a/apps/federatedfilesharing/lib/Controller/MountPublicLinkController.php b/apps/federatedfilesharing/lib/Controller/MountPublicLinkController.php index c0c9ce9bc8c94..9a9c75bf34ca4 100644 --- a/apps/federatedfilesharing/lib/Controller/MountPublicLinkController.php +++ b/apps/federatedfilesharing/lib/Controller/MountPublicLinkController.php @@ -196,6 +196,10 @@ public function askForFederatedShare($token, $remote, $password = '', $owner = ' $cloudId = $this->cloudIdManager->getCloudId($this->userSession->getUser()->getUID(), $this->addressHandler->generateRemoteURL()); + if (!$this->federatedShareProvider->allowedIncomingFederation($cloudId->getRemote(), $token, $password)) { + return new JSONResponse(['message' => $this->l->t('Server to server sharing is only available internally')], Http::STATUS_BAD_REQUEST); + } + $httpClient = $this->clientService->newClient(); try { diff --git a/apps/federatedfilesharing/lib/Controller/RequestHandlerController.php b/apps/federatedfilesharing/lib/Controller/RequestHandlerController.php index e772d088f24b4..18b899afa774d 100644 --- a/apps/federatedfilesharing/lib/Controller/RequestHandlerController.php +++ b/apps/federatedfilesharing/lib/Controller/RequestHandlerController.php @@ -146,6 +146,7 @@ public function createShare() { $remoteId = isset($_POST['remoteId']) ? (int)$_POST['remoteId'] : null; $sharedByFederatedId = isset($_POST['sharedByFederatedId']) ? $_POST['sharedByFederatedId'] : null; $ownerFederatedId = isset($_POST['ownerFederatedId']) ? $_POST['ownerFederatedId'] : null; + $password = isset($_POST['password']) ? $_POST['password'] : ''; if ($ownerFederatedId === null) { $ownerFederatedId = $this->cloudIdManager->getCloudId($owner, $this->cleanupRemote($remote))->getId(); @@ -167,7 +168,8 @@ public function createShare() { $sharedBy, $token, 'user', - 'file' + 'file', + $password ); try { diff --git a/apps/federatedfilesharing/lib/FederatedShareProvider.php b/apps/federatedfilesharing/lib/FederatedShareProvider.php index cf5ee133ea629..e6957c43b5107 100644 --- a/apps/federatedfilesharing/lib/FederatedShareProvider.php +++ b/apps/federatedfilesharing/lib/FederatedShareProvider.php @@ -40,6 +40,7 @@ use OCP\Files\IRootFolder; use OCP\Files\Node; use OCP\Files\NotFoundException; +use OCP\GlobalScale\IConfig as IGlobalScaleConfig; use OCP\IConfig; use OCP\IDBConnection; use OCP\IL10N; @@ -92,7 +93,7 @@ class FederatedShareProvider implements IShareProvider { /** @var ICloudIdManager */ private $cloudIdManager; - /** @var \OCP\GlobalScale\IConfig */ + /** @var IGlobalScaleConfig */ private $gsConfig; /** @var ICloudFederationProviderManager */ @@ -114,22 +115,22 @@ class FederatedShareProvider implements IShareProvider { * @param IConfig $config * @param IUserManager $userManager * @param ICloudIdManager $cloudIdManager - * @param \OCP\GlobalScale\IConfig $globalScaleConfig + * @param IGlobalScaleConfig $globalScaleConfig * @param ICloudFederationProviderManager $cloudFederationProviderManager */ public function __construct( - IDBConnection $connection, - AddressHandler $addressHandler, - Notifications $notifications, - TokenHandler $tokenHandler, - IL10N $l10n, - ILogger $logger, - IRootFolder $rootFolder, - IConfig $config, - IUserManager $userManager, - ICloudIdManager $cloudIdManager, - \OCP\GlobalScale\IConfig $globalScaleConfig, - ICloudFederationProviderManager $cloudFederationProviderManager + IDBConnection $connection, + AddressHandler $addressHandler, + Notifications $notifications, + TokenHandler $tokenHandler, + IL10N $l10n, + ILogger $logger, + IRootFolder $rootFolder, + IConfig $config, + IUserManager $userManager, + ICloudIdManager $cloudIdManager, + IGlobalScaleConfig $globalScaleConfig, + ICloudFederationProviderManager $cloudFederationProviderManager ) { $this->dbConnection = $connection; $this->addressHandler = $addressHandler; @@ -193,8 +194,16 @@ public function create(IShare $share) { } - // don't allow federated shares if source and target server are the same $cloudId = $this->cloudIdManager->resolveCloudId($shareWith); + // check that cloudId is an allowed recipient + if (!$this->allowedOutgoingFederation($cloudId->getRemote())) { + $message = 'Not allowed to create a federated share outside of the internal GlobalScale.'; + $message_t = $this->l->t($message); + $this->logger->debug($message, ['app' => 'Federated File Sharing']); + throw new \Exception($message_t); + } + + // don't allow federated shares if source and target server are the same $currentServer = $this->addressHandler->generateRemoteURL(); $currentUser = $sharedBy; if ($this->addressHandler->compareAddresses($cloudId->getUser(), $cloudId->getRemote(), $currentUser, $currentServer)) { @@ -274,6 +283,14 @@ protected function createFederatedShare(IShare $share) { $sharedByFederatedId = $cloudId->getId(); } $ownerCloudId = $this->cloudIdManager->getCloudId($share->getShareOwner(), $this->addressHandler->generateRemoteURL()); + // if in GS and recipient is internal, generate password + list(, $remote) = $this->addressHandler->splitUserRemote($share->getSharedWith()); + $password = ''; + if ($this->gsConfig->remoteIsInternal($remote)) { + $password = $this->gsConfig->generateInternalKey($token); + } + $share->setPassword($password); + $send = $this->notifications->sendRemoteShare( $token, $share->getSharedWith(), @@ -283,7 +300,8 @@ protected function createFederatedShare(IShare $share) { $ownerCloudId->getId(), $share->getSharedBy(), $sharedByFederatedId, - $share->getShareType() + $share->getShareType(), + $share->getPassword() ); if ($send === false) { @@ -977,13 +995,16 @@ public function userDeletedFromGroup($uid, $gid) { /** * check if users from other Nextcloud instances are allowed to mount public links share by this instance * + * @param string $remote + * * @return bool */ public function isOutgoingServer2serverShareEnabled() { - if ($this->gsConfig->onlyInternalFederation()) { - return false; + if ($this->gsConfig->onlyInternalFederation(IGlobalScaleConfig::OUTGOING)) { + return true; } $result = $this->config->getAppValue('files_sharing', 'outgoing_server2server_share_enabled', 'yes'); + return ($result === 'yes'); } @@ -993,10 +1014,11 @@ public function isOutgoingServer2serverShareEnabled() { * @return bool */ public function isIncomingServer2serverShareEnabled() { - if ($this->gsConfig->onlyInternalFederation()) { - return false; + if ($this->gsConfig->onlyInternalFederation(IGlobalScaleConfig::INCOMING)) { + return true; } $result = $this->config->getAppValue('files_sharing', 'incoming_server2server_share_enabled', 'yes'); + return ($result === 'yes'); } @@ -1007,10 +1029,11 @@ public function isIncomingServer2serverShareEnabled() { * @return bool */ public function isOutgoingServer2serverGroupShareEnabled() { - if ($this->gsConfig->onlyInternalFederation()) { - return false; + if ($this->gsConfig->onlyInternalFederation(IGlobalScaleConfig::OUTGOING)) { + return true; } $result = $this->config->getAppValue('files_sharing', 'outgoing_server2server_group_share_enabled', 'no'); + return ($result === 'yes'); } @@ -1020,13 +1043,39 @@ public function isOutgoingServer2serverGroupShareEnabled() { * @return bool */ public function isIncomingServer2serverGroupShareEnabled() { - if ($this->gsConfig->onlyInternalFederation()) { - return false; + if ($this->gsConfig->onlyInternalFederation(IGlobalScaleConfig::INCOMING)) { + return true; } $result = $this->config->getAppValue('files_sharing', 'incoming_server2server_group_share_enabled', 'no'); + return ($result === 'yes'); } + + /** + * @param string $remote + * + * @return bool + * @since 19.0.0 + */ + public function allowedOutgoingFederation(string $remote) { + return $this->gsConfig->allowedOutgoingFederation($remote); + } + + + /** + * @param string $token + * @param string $key + * @param string $remote + * + * @return bool + * @since 19.0.0 + */ + public function allowedIncomingFederation(string $remote, string $token, string $key): bool { + return $this->gsConfig->allowedIncomingFederation($remote, $token, $key); + } + + /** * check if federated group sharing is supported, therefore the OCM API need to be enabled * @@ -1047,6 +1096,7 @@ public function isLookupServerQueriesEnabled() { return true; } $result = $this->config->getAppValue('files_sharing', 'lookupServerEnabled', 'no'); + return ($result === 'yes'); } @@ -1062,6 +1112,7 @@ public function isLookupServerUploadEnabled() { return false; } $result = $this->config->getAppValue('files_sharing', 'lookupServerUploadEnabled', 'yes'); + return ($result === 'yes'); } @@ -1130,4 +1181,5 @@ public function getAllShares(): iterable { } $cursor->closeCursor(); } + } diff --git a/apps/federatedfilesharing/lib/Notifications.php b/apps/federatedfilesharing/lib/Notifications.php index 5df2173263ca9..269de6576b75f 100644 --- a/apps/federatedfilesharing/lib/Notifications.php +++ b/apps/federatedfilesharing/lib/Notifications.php @@ -88,11 +88,13 @@ public function __construct( * @param string $sharedBy * @param string $sharedByFederatedId * @param int $shareType (can be a remote user or group share) + * @param string $password (used to confirm that share is internal to GS) + * * @return bool * @throws \OC\HintException * @throws \OC\ServerNotAvailableException */ - public function sendRemoteShare($token, $shareWith, $name, $remote_id, $owner, $ownerFederatedId, $sharedBy, $sharedByFederatedId, $shareType) { + public function sendRemoteShare($token, $shareWith, $name, $remote_id, $owner, $ownerFederatedId, $sharedBy, $sharedByFederatedId, $shareType, string $password = '') { list($user, $remote) = $this->addressHandler->splitUserRemote($shareWith); @@ -109,7 +111,8 @@ public function sendRemoteShare($token, $shareWith, $name, $remote_id, $owner, $ 'sharedBy' => $sharedBy, 'sharedByFederatedId' => $sharedByFederatedId, 'remote' => $local, - 'shareType' => $shareType + 'shareType' => $shareType, + 'password' => $password ); $result = $this->tryHttpPostToShareEndpoint($remote, '', $fields); @@ -394,7 +397,8 @@ protected function tryOCMEndPoint($remoteDomain, $fields, $action) { $fields['sharedBy'], $fields['token'], $fields['shareType'], - 'file' + 'file', + '' ); return $this->federationProviderManager->sendShare($share); case 'reshare': diff --git a/apps/federatedfilesharing/lib/Settings/Admin.php b/apps/federatedfilesharing/lib/Settings/Admin.php index 821421294e562..b7fbd23c3dd17 100644 --- a/apps/federatedfilesharing/lib/Settings/Admin.php +++ b/apps/federatedfilesharing/lib/Settings/Admin.php @@ -27,7 +27,7 @@ use OCA\FederatedFileSharing\FederatedShareProvider; use OCP\AppFramework\Http\TemplateResponse; -use OCP\GlobalScale\IConfig; +use OCP\GlobalScale\IConfig as IGlobalScaleConfig; use OCP\Settings\ISettings; class Admin implements ISettings { @@ -35,16 +35,16 @@ class Admin implements ISettings { /** @var FederatedShareProvider */ private $fedShareProvider; - /** @var IConfig */ + /** @var IGlobalScaleConfig */ private $gsConfig; /** * Admin constructor. * * @param FederatedShareProvider $fedShareProvider - * @param IConfig $globalScaleConfig + * @param IGlobalScaleConfig $globalScaleConfig */ - public function __construct(FederatedShareProvider $fedShareProvider, IConfig $globalScaleConfig) { + public function __construct(FederatedShareProvider $fedShareProvider, IGlobalScaleConfig $globalScaleConfig) { $this->fedShareProvider = $fedShareProvider; $this->gsConfig = $globalScaleConfig; } @@ -55,7 +55,8 @@ public function __construct(FederatedShareProvider $fedShareProvider, IConfig $g public function getForm() { $parameters = [ - 'internalOnly' => $this->gsConfig->onlyInternalFederation(), + 'incomingInternalOnly' => $this->gsConfig->onlyInternalFederation(IGlobalScaleConfig::INCOMING), + 'outgoingInternalOnly' => $this->gsConfig->onlyInternalFederation(IGlobalScaleConfig::OUTGOING), 'outgoingServer2serverShareEnabled' => $this->fedShareProvider->isOutgoingServer2serverShareEnabled(), 'incomingServer2serverShareEnabled' => $this->fedShareProvider->isIncomingServer2serverShareEnabled(), 'federatedGroupSharingSupported' => $this->fedShareProvider->isFederatedGroupSharingSupported(), diff --git a/apps/federatedfilesharing/lib/ocm/CloudFederationProviderFiles.php b/apps/federatedfilesharing/lib/ocm/CloudFederationProviderFiles.php index e2e2f26ad3a83..b4d2cbc2f6dfd 100644 --- a/apps/federatedfilesharing/lib/ocm/CloudFederationProviderFiles.php +++ b/apps/federatedfilesharing/lib/ocm/CloudFederationProviderFiles.php @@ -43,6 +43,7 @@ use OCP\Federation\ICloudFederationShare; use OCP\Federation\ICloudIdManager; use OCP\Files\NotFoundException; +use OCP\GlobalScale\IConfig as IGlobalScaleConfig; use OCP\IDBConnection; use OCP\IGroupManager; use OCP\ILogger; @@ -93,6 +94,9 @@ class CloudFederationProviderFiles implements ICloudFederationProvider { /** @var ICloudFederationProviderManager */ private $cloudFederationProviderManager; + /** @var IGlobalScaleConfig */ + private $gsConfig; + /** @var IDBConnection */ private $connection; @@ -114,6 +118,7 @@ class CloudFederationProviderFiles implements ICloudFederationProvider { * @param IURLGenerator $urlGenerator * @param ICloudFederationFactory $cloudFederationFactory * @param ICloudFederationProviderManager $cloudFederationProviderManager + * @param IGlobalScaleConfig $gsConfig * @param IDBConnection $connection * @param IGroupManager $groupManager */ @@ -129,6 +134,7 @@ public function __construct(IAppManager $appManager, IURLGenerator $urlGenerator, ICloudFederationFactory $cloudFederationFactory, ICloudFederationProviderManager $cloudFederationProviderManager, + IGlobalScaleConfig $gsConfig, IDBConnection $connection, IGroupManager $groupManager ) { @@ -144,6 +150,7 @@ public function __construct(IAppManager $appManager, $this->urlGenerator = $urlGenerator; $this->cloudFederationFactory = $cloudFederationFactory; $this->cloudFederationProviderManager = $cloudFederationProviderManager; + $this->gsConfig = $gsConfig; $this->connection = $connection; $this->groupManager = $groupManager; } @@ -187,6 +194,10 @@ public function shareReceived(ICloudFederationShare $share) { } $token = $share->getShareSecret(); + if (!$this->federatedShareProvider->allowedIncomingFederation($remote, $token, $share->getPassword())) { + throw new ProviderCouldNotAddShareException('Server only support internal federated cloud sharing', '', Http::STATUS_SERVICE_UNAVAILABLE); + } + $name = $share->getResourceName(); $owner = $share->getOwnerDisplayName(); $sharedBy = $share->getSharedByDisplayName(); @@ -239,6 +250,7 @@ public function shareReceived(ICloudFederationShare $share) { \OC::$server->query(\OCP\OCS\IDiscoveryService::class), \OC::$server->getCloudFederationProviderManager(), \OC::$server->getCloudFederationFactory(), + $this->gsConfig, \OC::$server->getGroupManager(), \OC::$server->getUserManager(), $shareWith diff --git a/apps/federatedfilesharing/templates/settings-admin.php b/apps/federatedfilesharing/templates/settings-admin.php index fbbeecd88bf05..f79daeedb2066 100644 --- a/apps/federatedfilesharing/templates/settings-admin.php +++ b/apps/federatedfilesharing/templates/settings-admin.php @@ -5,7 +5,7 @@ style('federatedfilesharing', 'settings-admin'); ?> - +
t('Adjust how people can share between servers.')); ?>
+/> @@ -24,6 +25,9 @@ t('Allow users on this server to send shares to other servers'));?>
+ + +
/>
@@ -31,7 +35,10 @@
t('Allow users on this server to receive shares from other servers'));?>
/> @@ -39,6 +46,8 @@ t('Allow users on this server to send shares to groups on other servers'));?>
+ +
/>
@@ -47,6 +56,7 @@
/>
@@ -54,6 +64,7 @@
t('Search global and public address book for users'));?>
/>
@@ -61,6 +72,7 @@
t('Allow users to publish their data to a global and public address book'));?>