diff --git a/apps/federatedfilesharing/lib/AppInfo/Application.php b/apps/federatedfilesharing/lib/AppInfo/Application.php index 9d8464e37d..346d3c4e29 100644 --- a/apps/federatedfilesharing/lib/AppInfo/Application.php +++ b/apps/federatedfilesharing/lib/AppInfo/Application.php @@ -30,6 +30,7 @@ use OCA\FederatedFileSharing\Controller\RequestHandlerController; use OCA\FederatedFileSharing\FederatedShareProvider; use OCA\FederatedFileSharing\Notifications; use OCP\AppFramework\App; +use OCP\GlobalScale\IConfig; class Application extends App { @@ -91,6 +92,7 @@ class Application extends App { * initialize federated share provider */ protected function initFederatedShareProvider() { + $c = $this->getContainer(); $addressHandler = new \OCA\FederatedFileSharing\AddressHandler( \OC::$server->getURLGenerator(), \OC::$server->getL10N('federatedfilesharing'), @@ -116,7 +118,8 @@ class Application extends App { \OC::$server->getLazyRootFolder(), \OC::$server->getConfig(), \OC::$server->getUserManager(), - \OC::$server->getCloudIdManager() + \OC::$server->getCloudIdManager(), + $c->query(IConfig::class) ); } diff --git a/apps/federatedfilesharing/lib/FederatedShareProvider.php b/apps/federatedfilesharing/lib/FederatedShareProvider.php index 34e02391e0..60a54c6ca3 100644 --- a/apps/federatedfilesharing/lib/FederatedShareProvider.php +++ b/apps/federatedfilesharing/lib/FederatedShareProvider.php @@ -85,6 +85,9 @@ class FederatedShareProvider implements IShareProvider { /** @var ICloudIdManager */ private $cloudIdManager; + /** @var \OCP\GlobalScale\IConfig */ + private $gsConfig; + /** * DefaultShareProvider constructor. * @@ -98,6 +101,7 @@ class FederatedShareProvider implements IShareProvider { * @param IConfig $config * @param IUserManager $userManager * @param ICloudIdManager $cloudIdManager + * @param \OCP\GlobalScale\IConfig $globalScaleConfig */ public function __construct( IDBConnection $connection, @@ -109,7 +113,8 @@ class FederatedShareProvider implements IShareProvider { IRootFolder $rootFolder, IConfig $config, IUserManager $userManager, - ICloudIdManager $cloudIdManager + ICloudIdManager $cloudIdManager, + \OCP\GlobalScale\IConfig $globalScaleConfig ) { $this->dbConnection = $connection; $this->addressHandler = $addressHandler; @@ -121,6 +126,7 @@ class FederatedShareProvider implements IShareProvider { $this->config = $config; $this->userManager = $userManager; $this->cloudIdManager = $cloudIdManager; + $this->gsConfig = $globalScaleConfig; } /** @@ -941,6 +947,9 @@ class FederatedShareProvider implements IShareProvider { * @return bool */ public function isOutgoingServer2serverShareEnabled() { + if ($this->gsConfig->onlyInternalFederation()) { + return false; + } $result = $this->config->getAppValue('files_sharing', 'outgoing_server2server_share_enabled', 'yes'); return ($result === 'yes'); } @@ -951,6 +960,9 @@ class FederatedShareProvider implements IShareProvider { * @return bool */ public function isIncomingServer2serverShareEnabled() { + if ($this->gsConfig->onlyInternalFederation()) { + return false; + } $result = $this->config->getAppValue('files_sharing', 'incoming_server2server_share_enabled', 'yes'); return ($result === 'yes'); } @@ -961,6 +973,10 @@ class FederatedShareProvider implements IShareProvider { * @return bool */ public function isLookupServerQueriesEnabled() { + // in a global scale setup we should always query the lookup server + if ($this->gsConfig->isGlobalScaleEnabled()) { + return true; + } $result = $this->config->getAppValue('files_sharing', 'lookupServerEnabled', 'no'); return ($result === 'yes'); } @@ -972,6 +988,10 @@ class FederatedShareProvider implements IShareProvider { * @return bool */ public function isLookupServerUploadEnabled() { + // in a global scale setup the admin is responsible to keep the lookup server up-to-date + if ($this->gsConfig->isGlobalScaleEnabled()) { + return false; + } $result = $this->config->getAppValue('files_sharing', 'lookupServerUploadEnabled', 'yes'); return ($result === 'yes'); } diff --git a/apps/federatedfilesharing/lib/Settings/Admin.php b/apps/federatedfilesharing/lib/Settings/Admin.php index baac4b1086..47470fd584 100644 --- a/apps/federatedfilesharing/lib/Settings/Admin.php +++ b/apps/federatedfilesharing/lib/Settings/Admin.php @@ -25,6 +25,7 @@ namespace OCA\FederatedFileSharing\Settings; use OCA\FederatedFileSharing\FederatedShareProvider; use OCP\AppFramework\Http\TemplateResponse; +use OCP\GlobalScale\IConfig; use OCP\Settings\ISettings; class Admin implements ISettings { @@ -32,15 +33,27 @@ class Admin implements ISettings { /** @var FederatedShareProvider */ private $fedShareProvider; - public function __construct(FederatedShareProvider $fedShareProvider) { + /** @var IConfig */ + private $gsConfig; + + /** + * Admin constructor. + * + * @param FederatedShareProvider $fedShareProvider + * @param IConfig $globalScaleConfig + */ + public function __construct(FederatedShareProvider $fedShareProvider, IConfig $globalScaleConfig) { $this->fedShareProvider = $fedShareProvider; + $this->gsConfig = $globalScaleConfig; } /** * @return TemplateResponse */ public function getForm() { + $parameters = [ + 'internalOnly' => $this->gsConfig->onlyInternalFederation(), 'outgoingServer2serverShareEnabled' => $this->fedShareProvider->isOutgoingServer2serverShareEnabled(), 'incomingServer2serverShareEnabled' => $this->fedShareProvider->isIncomingServer2serverShareEnabled(), 'lookupServerEnabled' => $this->fedShareProvider->isLookupServerQueriesEnabled(), diff --git a/apps/federatedfilesharing/settings-personal.php b/apps/federatedfilesharing/settings-personal.php index d70f4e491a..cd22cc1708 100644 --- a/apps/federatedfilesharing/settings-personal.php +++ b/apps/federatedfilesharing/settings-personal.php @@ -53,7 +53,7 @@ if(\OC::$server->getAppManager()->isEnabledForUser("theming")) { $textColor = "#000000"; } } catch (OCP\AppFramework\QueryException $e) { - + } } diff --git a/apps/federatedfilesharing/templates/settings-admin.php b/apps/federatedfilesharing/templates/settings-admin.php index ff5cb0084e..e106f1dc4e 100644 --- a/apps/federatedfilesharing/templates/settings-admin.php +++ b/apps/federatedfilesharing/templates/settings-admin.php @@ -4,6 +4,8 @@ script('federatedfilesharing', 'settings-admin'); ?> + +

t('Federated Cloud Sharing'));?>

+ + diff --git a/apps/federatedfilesharing/tests/FederatedShareProviderTest.php b/apps/federatedfilesharing/tests/FederatedShareProviderTest.php index e01e02c83b..3ecd8162ca 100644 --- a/apps/federatedfilesharing/tests/FederatedShareProviderTest.php +++ b/apps/federatedfilesharing/tests/FederatedShareProviderTest.php @@ -65,6 +65,8 @@ class FederatedShareProviderTest extends \Test\TestCase { protected $config; /** @var IUserManager | \PHPUnit_Framework_MockObject_MockObject */ protected $userManager; + /** @var \OCP\GlobalScale\IConfig|\PHPUnit_Framework_MockObject_MockObject */ + protected $gsConfig; /** @var IManager */ protected $shareManager; @@ -96,11 +98,11 @@ class FederatedShareProviderTest extends \Test\TestCase { $this->userManager = $this->getMockBuilder('OCP\IUserManager')->getMock(); //$this->addressHandler = new AddressHandler(\OC::$server->getURLGenerator(), $this->l); $this->addressHandler = $this->getMockBuilder('OCA\FederatedFileSharing\AddressHandler')->disableOriginalConstructor()->getMock(); + $this->cloudIdManager = new CloudIdManager(); + $this->gsConfig = $this->createMock(\OCP\GlobalScale\IConfig::class); $this->userManager->expects($this->any())->method('userExists')->willReturn(true); - $this->cloudIdManager = new CloudIdManager(); - $this->provider = new FederatedShareProvider( $this->connection, $this->addressHandler, @@ -111,7 +113,8 @@ class FederatedShareProviderTest extends \Test\TestCase { $this->rootFolder, $this->config, $this->userManager, - $this->cloudIdManager + $this->cloudIdManager, + $this->gsConfig ); $this->shareManager = \OC::$server->getShareManager(); @@ -409,7 +412,8 @@ class FederatedShareProviderTest extends \Test\TestCase { $this->rootFolder, $this->config, $this->userManager, - $this->cloudIdManager + $this->cloudIdManager, + $this->gsConfig ] )->setMethods(['sendPermissionUpdate'])->getMock(); @@ -674,13 +678,15 @@ class FederatedShareProviderTest extends \Test\TestCase { } /** - * @dataProvider dataTestFederatedSharingSettings + * @dataProvider dataTestIsOutgoingServer2serverShareEnabled * * @param string $isEnabled * @param bool $expected */ - public function testIsOutgoingServer2serverShareEnabled($isEnabled, $expected) { - $this->config->expects($this->once())->method('getAppValue') + public function testIsOutgoingServer2serverShareEnabled($internalOnly, $isEnabled, $expected) { + $this->gsConfig->expects($this->once())->method('onlyInternalFederation') + ->willReturn($internalOnly); + $this->config->expects($this->any())->method('getAppValue') ->with('files_sharing', 'outgoing_server2server_share_enabled', 'yes') ->willReturn($isEnabled); @@ -689,14 +695,25 @@ class FederatedShareProviderTest extends \Test\TestCase { ); } + public function dataTestIsOutgoingServer2serverShareEnabled() { + return [ + [false, 'yes', true], + [false, 'no', false], + [true, 'yes', false], + [true, 'no', false], + ]; + } + /** - * @dataProvider dataTestFederatedSharingSettings + * @dataProvider dataTestIsIncomingServer2serverShareEnabled * * @param string $isEnabled * @param bool $expected */ - public function testIsIncomingServer2serverShareEnabled($isEnabled, $expected) { - $this->config->expects($this->once())->method('getAppValue') + public function testIsIncomingServer2serverShareEnabled($onlyInternal, $isEnabled, $expected) { + $this->gsConfig->expects($this->once())->method('onlyInternalFederation') + ->willReturn($onlyInternal); + $this->config->expects($this->any())->method('getAppValue') ->with('files_sharing', 'incoming_server2server_share_enabled', 'yes') ->willReturn($isEnabled); @@ -705,14 +722,25 @@ class FederatedShareProviderTest extends \Test\TestCase { ); } + public function dataTestIsIncomingServer2serverShareEnabled() { + return [ + [false, 'yes', true], + [false, 'no', false], + [true, 'yes', false], + [true, 'no', false], + ]; + } + /** - * @dataProvider dataTestFederatedSharingSettings + * @dataProvider dataTestIsLookupServerQueriesEnabled * * @param string $isEnabled * @param bool $expected */ - public function testIsLookupServerQueriesEnabled($isEnabled, $expected) { - $this->config->expects($this->once())->method('getAppValue') + public function testIsLookupServerQueriesEnabled($gsEnabled, $isEnabled, $expected) { + $this->gsConfig->expects($this->once())->method('isGlobalScaleEnabled') + ->willReturn($gsEnabled); + $this->config->expects($this->any())->method('getAppValue') ->with('files_sharing', 'lookupServerEnabled', 'no') ->willReturn($isEnabled); @@ -721,14 +749,26 @@ class FederatedShareProviderTest extends \Test\TestCase { ); } + + public function dataTestIsLookupServerQueriesEnabled() { + return [ + [false, 'yes', true], + [false, 'no', false], + [true, 'yes', true], + [true, 'no', true], + ]; + } + /** - * @dataProvider dataTestFederatedSharingSettings + * @dataProvider dataTestIsLookupServerUploadEnabled * * @param string $isEnabled * @param bool $expected */ - public function testIsLookupServerUploadEnabled($isEnabled, $expected) { - $this->config->expects($this->once())->method('getAppValue') + public function testIsLookupServerUploadEnabled($gsEnabled, $isEnabled, $expected) { + $this->gsConfig->expects($this->once())->method('isGlobalScaleEnabled') + ->willReturn($gsEnabled); + $this->config->expects($this->any())->method('getAppValue') ->with('files_sharing', 'lookupServerUploadEnabled', 'yes') ->willReturn($isEnabled); @@ -737,10 +777,12 @@ class FederatedShareProviderTest extends \Test\TestCase { ); } - public function dataTestFederatedSharingSettings() { + public function dataTestIsLookupServerUploadEnabled() { return [ - ['yes', true], - ['no', false] + [false, 'yes', true], + [false, 'no', false], + [true, 'yes', false], + [true, 'no', false], ]; } diff --git a/apps/federatedfilesharing/tests/Settings/AdminTest.php b/apps/federatedfilesharing/tests/Settings/AdminTest.php index 9eae6317bf..ce47ffb238 100644 --- a/apps/federatedfilesharing/tests/Settings/AdminTest.php +++ b/apps/federatedfilesharing/tests/Settings/AdminTest.php @@ -25,6 +25,7 @@ namespace OCA\FederatedFileSharing\Tests\Settings; use OCA\FederatedFileSharing\Settings\Admin; use OCP\AppFramework\Http\TemplateResponse; +use OCP\GlobalScale\IConfig; use Test\TestCase; class AdminTest extends TestCase { @@ -32,12 +33,17 @@ class AdminTest extends TestCase { private $admin; /** @var \OCA\FederatedFileSharing\FederatedShareProvider */ private $federatedShareProvider; + /** @var IConfig|\PHPUnit_Framework_MockObject_MockObject */ + private $gsConfig; public function setUp() { parent::setUp(); - $this->federatedShareProvider = $this->getMockBuilder('\OCA\FederatedFileSharing\FederatedShareProvider')->disableOriginalConstructor()->getMock(); + $this->federatedShareProvider = $this->getMockBuilder('\OCA\FederatedFileSharing\FederatedShareProvider') + ->disableOriginalConstructor()->getMock(); + $this->gsConfig = $this->getMock(IConfig::class); $this->admin = new Admin( - $this->federatedShareProvider + $this->federatedShareProvider, + $this->gsConfig ); } @@ -73,8 +79,11 @@ class AdminTest extends TestCase { ->expects($this->once()) ->method('isLookupServerUploadEnabled') ->willReturn($state); + $this->gsConfig->expects($this->once())->method('onlyInternalFederation') + ->willReturn($state); $params = [ + 'internalOnly' => $state, 'outgoingServer2serverShareEnabled' => $state, 'incomingServer2serverShareEnabled' => $state, 'lookupServerEnabled' => $state, diff --git a/config/config.sample.php b/config/config.sample.php index b143693082..27499825c6 100644 --- a/config/config.sample.php +++ b/config/config.sample.php @@ -1242,13 +1242,13 @@ $CONFIG = array( * During setup, if requirements are met (see below), this setting is set to true * and MySQL can handle 4 byte characters instead of 3 byte characters. * - * If you want to convert an existing 3-byte setup into a 4-byte setup please + * If you want to convert an existing 3-byte setup into a 4-byte setup please * set the parameters in MySQL as mentioned below and run the migration command: * ./occ db:convert-mysql-charset * The config setting will be set automatically after a successful run. - * + * * Consult the documentation for more details. - * + * * MySQL requires a special setup for longer indexes (> 767 bytes) which are * needed: * @@ -1530,4 +1530,15 @@ $CONFIG = array( */ 'lookup_server' => 'https://lookup.nextcloud.com', +/** + * set to true if the server is used in a setup based on Nextcloud's Global Scale architecture + */ +'gs.enabled' => false, + +/** + * by default federation is only used internally in a Global Scale setup + * If you want to allow federation outside of your environment set it to 'global' + */ +'gs.federation' => 'internal', + ); diff --git a/lib/private/AppFramework/DependencyInjection/DIContainer.php b/lib/private/AppFramework/DependencyInjection/DIContainer.php index d24836228c..86d14a2f33 100644 --- a/lib/private/AppFramework/DependencyInjection/DIContainer.php +++ b/lib/private/AppFramework/DependencyInjection/DIContainer.php @@ -53,6 +53,7 @@ use OCP\AppFramework\IAppContainer; use OCP\AppFramework\QueryException; use OCP\Files\Folder; use OCP\Files\IAppData; +use OCP\GlobalScale\IConfig; use OCP\IL10N; use OCP\IRequest; use OCP\IServerContainer; @@ -159,6 +160,10 @@ class DIContainer extends SimpleContainer implements IAppContainer { return $this->getServer()->getEncryptionManager(); }); + $this->registerService(IConfig::class, function ($c) { + return $c->query(OC\GlobalScale\Config::class); + }); + $this->registerService(IValidator::class, function($c) { return $c->query(Validator::class); }); diff --git a/lib/private/GlobalScale/Config.php b/lib/private/GlobalScale/Config.php new file mode 100644 index 0000000000..3d718e5d04 --- /dev/null +++ b/lib/private/GlobalScale/Config.php @@ -0,0 +1,71 @@ + + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + + +namespace OC\GlobalScale; + + +use OCP\IConfig; + +class Config implements \OCP\GlobalScale\IConfig { + + /** @var IConfig */ + private $config; + + /** + * Config constructor. + * + * @param IConfig $config + */ + public function __construct(IConfig $config) { + $this->config = $config; + } + + /** + * check if global scale is enabled + * + * @since 12.0.1 + * @return bool + */ + public function isGlobalScaleEnabled() { + $enabled = $this->config->getSystemValue('gs.enabled', false); + return $enabled !== false; + } + + /** + * check if federation should only be used internally in a global scale setup + * + * @since 12.0.1 + * @return bool + */ + public function onlyInternalFederation() { + // if global scale is disabled federation works always globally + $gsEnabled = $this->isGlobalScaleEnabled(); + if ($gsEnabled === false) { + return false; + } + + $enabled = $this->config->getSystemValue('gs.federation', 'internal'); + + return $enabled === 'internal'; + } + +} diff --git a/lib/private/Share20/ProviderFactory.php b/lib/private/Share20/ProviderFactory.php index 609fd87cd1..ddd8177250 100644 --- a/lib/private/Share20/ProviderFactory.php +++ b/lib/private/Share20/ProviderFactory.php @@ -24,6 +24,7 @@ namespace OC\Share20; use OC\CapabilitiesManager; +use OC\GlobalScale\Config; use OCA\FederatedFileSharing\AddressHandler; use OCA\FederatedFileSharing\FederatedShareProvider; use OCA\FederatedFileSharing\Notifications; @@ -125,7 +126,8 @@ class ProviderFactory implements IProviderFactory { $this->serverContainer->getLazyRootFolder(), $this->serverContainer->getConfig(), $this->serverContainer->getUserManager(), - $this->serverContainer->getCloudIdManager() + $this->serverContainer->getCloudIdManager(), + $this->serverContainer->query(Config::class) ); } diff --git a/lib/public/GlobalScale/IConfig.php b/lib/public/GlobalScale/IConfig.php new file mode 100644 index 0000000000..92c19be3af --- /dev/null +++ b/lib/public/GlobalScale/IConfig.php @@ -0,0 +1,51 @@ + + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + + +namespace OCP\GlobalScale; + +/** + * Interface IConfig + * + * Configuration of the global scale architecture + * + * @package OCP\GlobalScale + * @since 12.0.1 + */ +interface IConfig { + + /** + * check if global scale is enabled + * + * @since 12.0.1 + * @return bool + */ + public function isGlobalScaleEnabled(); + + /** + * check if federation should only be used internally in a global scale setup + * + * @since 12.0.1 + * @return bool + */ + public function onlyInternalFederation(); + +} diff --git a/settings/personal.php b/settings/personal.php index 86ac4f753f..d2b4801e68 100644 --- a/settings/personal.php +++ b/settings/personal.php @@ -212,8 +212,14 @@ $tmpl->assign('certs', $certificateManager->listCertificates()); $tmpl->assign('showCertificates', $enableCertImport); $tmpl->assign('urlGenerator', $urlGenerator); -$lookupServerUploadEnabled = $config->getAppValue('files_sharing', 'lookupServerUploadEnabled', 'yes'); -$lookupServerUploadEnabled = $lookupServerUploadEnabled === 'yes'; +$federatedFileSharingEnabled = \OC::$server->getAppManager()->isEnabledForUser('federatedfilesharing'); +$lookupServerUploadEnabled = false; +if ($federatedFileSharingEnabled) { + $federatedFileSharing = new \OCA\FederatedFileSharing\AppInfo\Application(); + $shareProvider = $federatedFileSharing->getFederatedShareProvider(); + $lookupServerUploadEnabled = $shareProvider->isLookupServerUploadEnabled(); +} + $tmpl->assign('lookupServerUploadEnabled', $lookupServerUploadEnabled); // Get array of group ids for this user diff --git a/tests/lib/GlobalScale/ConfigTest.php b/tests/lib/GlobalScale/ConfigTest.php new file mode 100644 index 0000000000..ec1581625c --- /dev/null +++ b/tests/lib/GlobalScale/ConfigTest.php @@ -0,0 +1,95 @@ + + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * + */ + + +namespace Test\GlobalScale; + + +use OC\GlobalScale\Config; +use OCP\IConfig; +use Test\TestCase; + +class ConfigTest extends TestCase { + + /** @var IConfig|\PHPUnit_Framework_MockObject_MockObject */ + private $config; + + public function setUp() { + parent::setUp(); + + $this->config = $this->createMock(IConfig::class); + } + + /** + * @param array $mockMethods + * @return Config|\PHPUnit_Framework_MockObject_MockObject + */ + public function getInstance($mockMethods = []) { + + if (!empty($mockMethods)) { + return $this->getMockBuilder(Config::class) + ->setConstructorArgs([$this->config]) + ->setMethods($mockMethods) + ->getMock(); + } + + return new Config($this->config); + } + + public function testIsGlobalScaleEnabled() { + $gsConfig = $this->getInstance(); + $this->config->expects($this->once())->method('getSystemValue') + ->with('gs.enabled', false)->willReturn(true); + + $result = $gsConfig->isGlobalScaleEnabled(); + + $this->assertTrue($result); + } + + + /** + * @dataProvider dataTestOnlyInternalFederation + * + * @param bool $gsEnabled + * @param string $gsFederation + * @param bool $expected + */ + public function testOnlyInternalFederation($gsEnabled, $gsFederation, $expected) { + $gsConfig = $this->getInstance(['isGlobalScaleEnabled']); + + $gsConfig->expects($this->any())->method('isGlobalScaleEnabled')->willReturn($gsEnabled); + + $this->config->expects($this->any())->method('getSystemValue') + ->with('gs.federation', 'internal')->willReturn($gsFederation); + + $this->assertSame($expected, $gsConfig->onlyInternalFederation()); + } + + public function dataTestOnlyInternalFederation() { + return [ + [true, 'global', false], + [true, 'internal', true], + [false, 'global', false], + [false, 'internal', false] + ]; + } + +}