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 @@
-
-
-
-
-