diff --git a/.gitignore b/.gitignore index 221440c4af..b9448fcb49 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,4 @@ behat.yml /datas /www/assets /www/skins/build +/www/crossdomain.xml diff --git a/bin/console b/bin/console index 449afd50d7..ecf7aaa816 100755 --- a/bin/console +++ b/bin/console @@ -17,6 +17,7 @@ namespace KonsoleKommander; * @link www.phraseanet.com */ use Alchemy\Phrasea\Command\Plugin\ListPlugin; +use Alchemy\Phrasea\Command\Setup\CrossDomainGenerator; use Alchemy\Phrasea\Command\Setup\H264ConfigurationDumper; use Alchemy\Phrasea\Command\Setup\H264MappingGenerator; use Alchemy\Phrasea\Core\Version; @@ -104,6 +105,7 @@ $cli->command(new H264ConfigurationDumper()); $cli->command(new H264MappingGenerator()); $cli->command(new XSendFileConfigurationDumper()); $cli->command(new XSendFileMappingGenerator()); +$cli->command(new CrossDomainGenerator()); $cli->loadPlugins(); diff --git a/config/configuration.sample.yml b/config/configuration.sample.yml index 50208d031e..8ea3bb4151 100644 --- a/config/configuration.sample.yml +++ b/config/configuration.sample.yml @@ -159,3 +159,29 @@ api_cors: session: idle: 0 lifetime: 604800 # 1 week +crossdomain: + site-control: 'master-only' + allow-access-from: + - + domain: '*.example.com' + secure: 'false' + - + domain: 'www.example.com' + secure: 'true' + to-ports: '507,516-523' + allow-access-from-identity: + - + fingerprint-algorithm: 'sha-1' + fingerprint: '01:23:45:67:89:ab:cd:ef:01:23:45:67:89:ab:cd:ef:01:23:45:67' + - + fingerprint-algorithm: 'sha256' + fingerprint: '01:23:45:67:89:ab:cd:ef:01:23:45:67:89:ab:cd:ef:01:23:45:67' + allow-http-request-headers-from: + - + domain: '*.bar.com' + secure: 'true' + headers: 'SOAPAction, X-Foo*' + - + domain: 'foo.example.com' + secure: 'false' + headers: 'Authorization,X-Foo*' diff --git a/lib/Alchemy/Phrasea/Command/Setup/CrossDomainGenerator.php b/lib/Alchemy/Phrasea/Command/Setup/CrossDomainGenerator.php new file mode 100644 index 0000000000..6e54a4b1f2 --- /dev/null +++ b/lib/Alchemy/Phrasea/Command/Setup/CrossDomainGenerator.php @@ -0,0 +1,45 @@ +setDescription('Generate crossdomain.xml file according to configuration'); + } + + /** + * {@inheritdoc} + */ + protected function doExecute(InputInterface $input, OutputInterface $output) + { + $configuration = $this->container['phraseanet.configuration']['crossdomain']; + + $dumper = new CrossDomainDumper(); + + $xml = $dumper->dump($configuration); + + $output->writeln($xml); + + $this->container['filesystem']->dumpFile($this->container['root.path'].'/www/crossdomain.xml', $xml); + + return ; + } +} diff --git a/lib/Alchemy/Phrasea/Core/Version.php b/lib/Alchemy/Phrasea/Core/Version.php index fa18a8bb0c..209e36a2e8 100644 --- a/lib/Alchemy/Phrasea/Core/Version.php +++ b/lib/Alchemy/Phrasea/Core/Version.php @@ -18,7 +18,7 @@ namespace Alchemy\Phrasea\Core; */ class Version { - protected static $number = '3.8.6-alpha.1'; + protected static $number = '3.8.6-alpha.2'; protected static $name = 'Falcarius'; public static function getNumber() diff --git a/lib/Alchemy/Phrasea/Utilities/CrossDomainDumper.php b/lib/Alchemy/Phrasea/Utilities/CrossDomainDumper.php new file mode 100644 index 0000000000..f14bd5e2c3 --- /dev/null +++ b/lib/Alchemy/Phrasea/Utilities/CrossDomainDumper.php @@ -0,0 +1,107 @@ +'.PHP_EOL; + $xml .= ''.PHP_EOL; + $xml .= '' . PHP_EOL; + $xml .= $this->getSiteControl($configuration); + $xml .= $this->getAllowAccess($configuration); + $xml .= $this->getAllowIdentity($configuration); + $xml .= $this->getAllowHeader($configuration); + $xml .= ""; + + return $xml; + } + + private function getSiteControl(array $conf) + { + $xml = ''; + + if (isset($conf['site-control'])) { + $xml = "\t".''.PHP_EOL; + } + + return $xml; + } + + private function getAllowAccess(array $conf) + { + $xml = ''; + if (!isset($conf['allow-access-from'])) { + return $xml; + } + $allowAccess = $conf['allow-access-from']; + if (!is_array($allowAccess)) { + return $xml; + } + + foreach ($allowAccess as $access) { + // domain is mandatory + if (!isset($access['domain'])) { + continue; + } + + $domain = $access['domain']; + $secure = isset($access['secure']) ? $access['secure'] : false; + $ports = isset($access['to-ports']) ? $access['to-ports'] : false; + + $xml .= "\t".''.PHP_EOL; + } + + return $xml; + } + + private function getAllowIdentity(array $conf) + { + $xml = ''; + if (!isset($conf['allow-access-from-identity'])) { + return $xml; + } + $allowAccess = $conf['allow-access-from-identity']; + if (!is_array($allowAccess)) { + return $xml; + } + foreach ($allowAccess as $access) { + $algorithm = isset($access['fingerprint-algorithm']) ? $access['fingerprint-algorithm'] : false; + $fingerprint = isset($access['fingerprint']) ? $access['fingerprint'] : false; + + // both are mandatory + if (!$algorithm || !$fingerprint) { + continue; + } + + $xml .= "\t".''.PHP_EOL; + } + + return $xml; + } + + private function getAllowHeader(array $conf) + { + $xml = ''; + if (!isset($conf['allow-http-request-headers-from'])) { + return $xml; + } + $allowHeaders = $conf['allow-http-request-headers-from']; + if (!is_array($allowHeaders)) { + return $xml; + } + foreach ($allowHeaders as $access) { + // domain & headers are mandatory + if (!isset($access['domain']) && !isset($access['headers'])) { + continue; + } + $secure = isset($access['secure']) ? $access['secure'] : false; + + $xml .= "\t".''.PHP_EOL; + } + + return $xml; + } +} diff --git a/lib/classes/patch/386alpha2a.php b/lib/classes/patch/386alpha2a.php new file mode 100644 index 0000000000..30ef919ad8 --- /dev/null +++ b/lib/classes/patch/386alpha2a.php @@ -0,0 +1,65 @@ +release; + } + + /** + * {@inheritdoc} + */ + public function require_all_upgrades() + { + return false; + } + + /** + * {@inheritdoc} + */ + public function concern() + { + return $this->concern; + } + + /** + * {@inheritdoc} + */ + public function apply(base $appbox, Application $app) + { + $config = $app['phraseanet.configuration']->getConfig(); + + $config['crossdomain'] = array( + 'allow-access-from' => array( + array( + 'domain' => '*.cooliris.com', + 'secure' => 'false', + ) + ) + ); + $app['phraseanet.configuration']->setConfig($config); + + return true; + } +} diff --git a/lib/conf.d/configuration.yml b/lib/conf.d/configuration.yml index 688dff3587..d11f93caaf 100644 --- a/lib/conf.d/configuration.yml +++ b/lib/conf.d/configuration.yml @@ -163,3 +163,8 @@ session: idle: 0 # 1 week lifetime: 604800 +crossdomain: + allow-access-from: + - + domain: '*.cooliris.com' + secure: 'false' diff --git a/tests/Alchemy/Tests/Phrasea/Utilities/CrossDomainDumperTest.php b/tests/Alchemy/Tests/Phrasea/Utilities/CrossDomainDumperTest.php new file mode 100644 index 0000000000..eee53b2d13 --- /dev/null +++ b/tests/Alchemy/Tests/Phrasea/Utilities/CrossDomainDumperTest.php @@ -0,0 +1,87 @@ +assertEquals($dumper->dump($configuration), $expected); + } + + public function crossDomainProvider() + { + return array( + array( + array( + 'site-control' => 'master-only', + 'allow-access-from' => array( + array( + 'domain'=> '*.example.com', + 'secure'=> 'false' + ), + array( + 'domain'=> 'www.example.com', + 'secure'=>'true', + 'to-ports'=>'507,516-523' + ) + ), + 'allow-access-from-identity' => array( + array( + 'fingerprint-algorithm'=> 'sha-1', + 'fingerprint'=> '01:23:45:67:89:ab:cd:ef:01:23:45:67:89:ab:cd:ef:01:23:45:67' + ), + array( + 'fingerprint-algorithm'=> 'sha256', + 'fingerprint' => '01:23:45:67:89:ab:cd:ef:01:23:45:67:89:ab:cd:ef:01:23:45:67' + ) + ), + 'allow-http-request-headers-from' => array( + array( + 'domain'=> '*.bar.com', + 'secure'=> 'true', + 'headers'=> 'SOAPAction, X-Foo*' + ), + array( + 'domain'=> 'foo.example.com', + 'secure'=> 'false', + 'headers'=> 'Authorization,X-Foo*' + ) + ), + ), + ' + + + + + + + + + +' + ), + array( + array( + 'allow-access-from' => array( + array( + 'domain'=> '*.cooliris.com', + 'secure'=> 'false' + ) + ) + ), + ' + + + +' + ) + ); + } +} diff --git a/www/crossdomain.xml b/www/crossdomain.xml deleted file mode 100644 index 6d0caa5aed..0000000000 --- a/www/crossdomain.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - -