diff --git a/composer.json b/composer.json
index 8bc14b6..c6f09c8 100644
--- a/composer.json
+++ b/composer.json
@@ -17,6 +17,7 @@
     "symfony/serializer": "2.6.0-beta1",
     "symfony/validator": "2.6.0-beta1",
     "symfony/yaml": "2.6.0-beta1",
+    "asm89/stack-cors": "0.2.*",
     "twig/twig": "1.16.*",
     "doctrine/common": "dev-master#a45d110f71c323e29f41eb0696fa230e3fa1b1b5",
     "doctrine/annotations": "1.2.*",
diff --git a/composer.lock b/composer.lock
index 868008a..9aa89af 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,9 +4,52 @@
         "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
         "This file is @generated automatically"
     ],
-    "hash": "34a4f5a56891e51217c305b97e8cc675",
+    "hash": "d1fe9717d884cf48c6a32a702656ee62",
     "packages": [
         {
+            "name": "asm89/stack-cors",
+            "version": "0.2.1",
+            "source": {
+                "type": "git",
+                "url": "https://github.com/asm89/stack-cors.git",
+                "reference": "2d77e77251a434e4527315313a672f5801b29fa2"
+            },
+            "dist": {
+                "type": "zip",
+                "url": "https://api.github.com/repos/asm89/stack-cors/zipball/2d77e77251a434e4527315313a672f5801b29fa2",
+                "reference": "2d77e77251a434e4527315313a672f5801b29fa2",
+                "shasum": ""
+            },
+            "require": {
+                "php": ">=5.3.2",
+                "symfony/http-foundation": "~2.1",
+                "symfony/http-kernel": "~2.1"
+            },
+            "type": "library",
+            "autoload": {
+                "psr-0": {
+                    "Asm89\\Stack": "src/"
+                }
+            },
+            "notification-url": "https://packagist.org/downloads/",
+            "license": [
+                "MIT"
+            ],
+            "authors": [
+                {
+                    "name": "Alexander",
+                    "email": "iam.asm89@gmail.com"
+                }
+            ],
+            "description": "Cross-origin resource sharing library and stack middleware",
+            "homepage": "https://github.com/asm89/stack-cors",
+            "keywords": [
+                "cors",
+                "stack"
+            ],
+            "time": "2014-07-28 07:22:35"
+        },
+        {
             "name": "doctrine/annotations",
             "version": "v1.2.1",
             "source": {
diff --git a/core/core.services.yml b/core/core.services.yml
index b0fdda0..689c3a2 100644
--- a/core/core.services.yml
+++ b/core/core.services.yml
@@ -1,5 +1,6 @@
 parameters:
   twig.config: {}
+  cors.config: {}
   factory.keyvalue:
     default: keyvalue.database
   factory.keyvalue.expirable:
@@ -420,6 +421,11 @@ services:
     arguments: ['@kernel']
     tags:
       - { name: http_middleware, priority: 100 }
+  http_middleware.cors:
+    class: Asm89\Stack\Cors
+    arguments: ['%cors.config%']
+    tags:
+      - { name: http_middleware }
   language_manager:
     class: Drupal\Core\Language\LanguageManager
     arguments: ['@language.default']
diff --git a/core/lib/Drupal/Core/CoreServiceProvider.php b/core/lib/Drupal/Core/CoreServiceProvider.php
index 249944f..5c36a80 100644
--- a/core/lib/Drupal/Core/CoreServiceProvider.php
+++ b/core/lib/Drupal/Core/CoreServiceProvider.php
@@ -10,6 +10,7 @@
 use Drupal\Core\Cache\CacheContextsPass;
 use Drupal\Core\Cache\ListCacheBinsPass;
 use Drupal\Core\DependencyInjection\Compiler\BackendCompilerPass;
+use Drupal\Core\DependencyInjection\Compiler\CorsCompilerPass;
 use Drupal\Core\DependencyInjection\Compiler\StackedKernelPass;
 use Drupal\Core\DependencyInjection\Compiler\RegisterStreamWrappersPass;
 use Drupal\Core\DependencyInjection\ServiceProviderInterface;
@@ -51,6 +52,8 @@ public function register(ContainerBuilder $container) {
 
     $container->addCompilerPass(new BackendCompilerPass());
 
+    $container->addCompilerPass(new CorsCompilerPass());
+
     $container->addCompilerPass(new StackedKernelPass());
 
     $container->addCompilerPass(new MainContentRenderersPass());
diff --git a/core/lib/Drupal/Core/DependencyInjection/Compiler/CorsCompilerPass.php b/core/lib/Drupal/Core/DependencyInjection/Compiler/CorsCompilerPass.php
new file mode 100644
index 0000000..3c66ad6
--- /dev/null
+++ b/core/lib/Drupal/Core/DependencyInjection/Compiler/CorsCompilerPass.php
@@ -0,0 +1,36 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\DependencyInjection\Compiler\CorsCompilerPass.
+ */
+
+namespace Drupal\Core\DependencyInjection\Compiler;
+
+use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+
+/**
+ * Provides a compiler pass which disables the CORS middleware in case disabled.
+ *
+ * @see services.yml
+ */
+class CorsCompilerPass implements CompilerPassInterface {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function process(ContainerBuilder $container) {
+    $enabled = FALSE;
+
+    if ($cors_config = $container->getParameter('cors.config')) {
+      $enabled = !empty($cors_config['enabled']);
+    }
+
+    // Remove the CORS middleware completly in case it was not enabled.
+    if (!$enabled) {
+      $container->removeDefinition('http_middleware.cors');
+    }
+  }
+
+}
diff --git a/core/modules/system/src/Tests/HttpKernel/CorsIntegrationTest.php b/core/modules/system/src/Tests/HttpKernel/CorsIntegrationTest.php
new file mode 100755
index 0000000..2b500a7
--- /dev/null
+++ b/core/modules/system/src/Tests/HttpKernel/CorsIntegrationTest.php
@@ -0,0 +1,56 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\system\Tests\HttpKernel\CorsIntegrationTest.
+ */
+
+namespace Drupal\system\Tests\HttpKernel;
+
+use Drupal\simpletest\WebTestBase;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Response;
+
+/**
+ * Tests CORS provided by Drupal.
+ *
+ * @see sites/default/default.services.yml
+ * @see \Asm89\Stack\Cors
+ * @see \Asm89\Stack\CorsService
+ *
+ * @group Http
+ */
+class CorsIntegrationTest extends WebTestBase {
+
+  public function testCrossSiteRequest() {
+    // Test default parameters.
+    $cors_config = $this->container->getParameter('cors.config');
+    $this->assertIdentical(FALSE, $cors_config['enabled']);
+    $this->assertIdentical([], $cors_config['allowedHeaders']);
+    $this->assertIdentical([], $cors_config['allowedMethods']);
+    $this->assertIdentical(['*'], $cors_config['allowedOrigins']);
+
+    $this->assertIdentical(FALSE, $cors_config['exposedHeaders']);
+    $this->assertIdentical(FALSE, $cors_config['maxAge']);
+    $this->assertIdentical(FALSE, $cors_config['supportsCredentials']);
+
+    // Configure the CORS stack to allow a specific set of origins, but don't
+    // specify an origin header.
+    $request = Request::create('/');
+    $request->headers->set('Origin', '');
+    $cors_config['enabled'] = TRUE;
+    $cors_config['allowedOrigins'] = array('http://example.com');
+    $this->setContainerParameter('cors.config', $cors_config);
+    $this->rebuildContainer();
+
+    $response = $this->container->get('http_kernel')->handle($request);
+    $this->assertEqual(Response::HTTP_FORBIDDEN, $response->getStatusCode());
+    $this->assertEqual('Not allowed.', $response->getContent());
+
+    // Specify a valid origin.
+    $request->headers->set('Origin', 'http://example.com');
+    $response = $this->container->get('http_kernel')->handle($request);
+    $this->assertEqual(Response::HTTP_OK, $response->getStatusCode());
+  }
+
+}
diff --git a/core/vendor/asm89/stack-cors/.travis.yml b/core/vendor/asm89/stack-cors/.travis.yml
new file mode 100644
index 0000000..ddb1058
--- /dev/null
+++ b/core/vendor/asm89/stack-cors/.travis.yml
@@ -0,0 +1,10 @@
+language: php
+
+php:
+  - 5.3
+  - 5.4
+  - 5.5
+
+before_script: composer install --dev
+
+script: phpunit
diff --git a/core/vendor/asm89/stack-cors/README.md b/core/vendor/asm89/stack-cors/README.md
new file mode 100644
index 0000000..dea18a8
--- /dev/null
+++ b/core/vendor/asm89/stack-cors/README.md
@@ -0,0 +1,59 @@
+# Stack/Cors
+
+Library and middleware enabling cross-origin resource sharing for your
+http-{foundation,kernel} using application. It attempts to implement the
+[W3C Candidate Recommendation] for cross-origin resource sharing.
+
+[W3C Candidate Recommendation]: http://www.w3.org/TR/cors/
+
+Master [![Build Status](https://secure.travis-ci.org/asm89/stack-cors.png?branch=master)](http://travis-ci.org/asm89/stack-cors)
+Develop [![Build Status](https://secure.travis-ci.org/asm89/stack-cors.png?branch=develop)](http://travis-ci.org/asm89/stack-cors)
+
+## Installation
+
+Require `asm89/stack-cors` using composer.
+
+## Usage
+
+Stack middleware:
+
+```php
+<?php
+
+use Asm89\Stack\Cors;
+
+$app = new Cors($app, array(
+    // you can use array('*') to allow any headers
+    'allowedHeaders'      => array('x-allowed-header', 'x-other-allowed-header'),
+    // you can use array('*') to allow any methods
+    'allowedMethods'      => array('DELETE', 'GET', 'POST', 'PUT'),
+    // you can use array('*') to allow requests from any origin
+    'allowedOrigins'      => array('localhost'),
+    'exposedHeaders'      => false,
+    'maxAge'              => false,
+    'supportsCredentials' => false,
+));
+```
+
+Or use the library:
+
+```php
+<?php
+
+use Asm89\Stack\CorsService;
+
+$cors = new CorsService(array(
+    'allowedHeaders'      => array('x-allowed-header', 'x-other-allowed-header'),
+    'allowedMethods'      => array('DELETE', 'GET', 'POST', 'PUT'),
+    'allowedOrigins'      => array('localhost'),
+    'exposedHeaders'      => false,
+    'maxAge'              => false,
+    'supportsCredentials' => false,
+));
+
+$cors->addActualRequestHeaders(Response $response, $origin);
+$cors->handlePreflightRequest(Request $request);
+$cors->isActualRequestAllowed(Request $request);
+$cors->isCorsRequest(Request $request);
+$cors->isPreflightRequest(Request $request);
+```
diff --git a/core/vendor/asm89/stack-cors/composer.json b/core/vendor/asm89/stack-cors/composer.json
new file mode 100644
index 0000000..f8be507
--- /dev/null
+++ b/core/vendor/asm89/stack-cors/composer.json
@@ -0,0 +1,22 @@
+{
+    "name": "asm89/stack-cors",
+    "description": "Cross-origin resource sharing library and stack middleware",
+    "keywords": ["stack", "cors"],
+    "homepage": "https://github.com/asm89/stack-cors",
+    "type": "library",
+    "license": "MIT",
+    "authors": [
+        {
+            "name": "Alexander",
+            "email": "iam.asm89@gmail.com"
+        }
+    ],
+    "require": {
+        "php": ">=5.3.2",
+        "symfony/http-foundation": "~2.1",
+        "symfony/http-kernel": "~2.1"
+    },
+    "autoload": {
+        "psr-0": { "Asm89\\Stack": "src/" }
+    }
+}
diff --git a/core/vendor/asm89/stack-cors/phpunit.xml.dist b/core/vendor/asm89/stack-cors/phpunit.xml.dist
new file mode 100644
index 0000000..1959e53
--- /dev/null
+++ b/core/vendor/asm89/stack-cors/phpunit.xml.dist
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<phpunit backupGlobals="false"
+         backupStaticAttributes="false"
+         colors="true"
+         convertErrorsToExceptions="true"
+         convertNoticesToExceptions="true"
+         convertWarningsToExceptions="true"
+         processIsolation="false"
+         stopOnFailure="false"
+         syntaxCheck="false"
+         bootstrap="test/bootstrap.php"
+>
+  <testsuites>
+    <testsuite name="Stack Cors Test Suite">
+      <directory>./test/Asm89/</directory>
+    </testsuite>
+  </testsuites>
+
+  <filter>
+    <whitelist>
+      <directory suffix=".php">./src/</directory>
+    </whitelist>
+  </filter>
+
+</phpunit>
diff --git a/core/vendor/asm89/stack-cors/src/Asm89/Stack/Cors.php b/core/vendor/asm89/stack-cors/src/Asm89/Stack/Cors.php
new file mode 100755
index 0000000..a5e81ce
--- /dev/null
+++ b/core/vendor/asm89/stack-cors/src/Asm89/Stack/Cors.php
@@ -0,0 +1,55 @@
+<?php
+
+namespace Asm89\Stack;
+
+use Symfony\Component\HttpKernel\HttpKernelInterface;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Response;
+
+class Cors implements HttpKernelInterface
+{
+    /**
+     * @var \Symfony\Component\HttpKernel\HttpKernelInterface
+     */
+    private $app;
+
+    /**
+     * @var \Asm89\Stack\CorsService
+     */
+    private $cors;
+
+    private $defaultOptions = array(
+        'allowedHeaders'      => array(),
+        'allowedMethods'      => array(),
+        'allowedOrigins'      => array(),
+        'exposedHeaders'      => false,
+        'maxAge'              => false,
+        'supportsCredentials' => false,
+    );
+
+    public function __construct(HttpKernelInterface $app, array $options = array())
+    {
+        $this->app  = $app;
+        $this->cors = new CorsService(array_merge($this->defaultOptions, $options));
+
+    }
+
+    public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, $catch = true)
+    {
+        if ( ! $this->cors->isCorsRequest($request)) {
+            return $this->app->handle($request, $type, $catch);
+        }
+
+        if ($this->cors->isPreflightRequest($request)) {
+            return $this->cors->handlePreflightRequest($request);
+        }
+
+        if ( ! $this->cors->isActualRequestAllowed($request)) {
+            return new Response('Not allowed.', 403);
+        }
+
+        $response = $this->app->handle($request, $type, $catch);
+
+        return $this->cors->addActualRequestHeaders($response, $request);
+    }
+}
diff --git a/core/vendor/asm89/stack-cors/src/Asm89/Stack/CorsService.php b/core/vendor/asm89/stack-cors/src/Asm89/Stack/CorsService.php
new file mode 100755
index 0000000..339256b
--- /dev/null
+++ b/core/vendor/asm89/stack-cors/src/Asm89/Stack/CorsService.php
@@ -0,0 +1,178 @@
+<?php
+
+namespace Asm89\Stack;
+
+use Symfony\Component\HttpKernel\HttpKernelInterface;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Response;
+
+class CorsService
+{
+    private $options;
+
+    public function __construct(array $options = array())
+    {
+        $this->options = $this->normalizeOptions($options);
+    }
+
+    private function normalizeOptions(array $options = array())
+    {
+
+        $options += array(
+            'allowedOrigins' => array(),
+            'supportsCredentials' => false,
+            'allowedHeaders' => array(),
+            'exposedHeaders' => array(),
+            'allowedMethods' => array(),
+            'maxAge' => 0,
+        );
+
+        // normalize array('*') to true
+        if (in_array('*', $options['allowedOrigins'])) {
+          $options['allowedOrigins'] = true;
+        }
+        if (in_array('*', $options['allowedHeaders'])) {
+          $options['allowedHeaders'] = true;
+        } else {
+          $options['allowedHeaders'] = array_map('strtolower', $options['allowedHeaders']);
+        }
+
+        if (in_array('*', $options['allowedMethods'])) {
+          $options['allowedMethods'] = true;
+        } else {
+          $options['allowedMethods'] = array_map('strtoupper', $options['allowedMethods']);
+        }
+
+        return $options;
+    }
+
+    public function isActualRequestAllowed(Request $request)
+    {
+        return $this->checkOrigin($request);
+    }
+
+    public function isCorsRequest(Request $request)
+    {
+        return $request->headers->has('Origin');
+    }
+
+    public function isPreflightRequest(Request $request)
+    {
+        return $this->isCorsRequest($request)
+            &&$request->getMethod() === 'OPTIONS'
+            && $request->headers->has('Access-Control-Request-Method');
+    }
+
+    public function addActualRequestHeaders(Response $response, Request $request)
+    {
+        if ( ! $this->checkOrigin($request)) {
+            return $response;
+        }
+
+        $response->headers->set('Access-Control-Allow-Origin', $request->headers->get('Origin'));
+
+        if ( ! $response->headers->has('Vary')) {
+            $response->headers->set('Vary', 'Origin');
+        } else {
+            $response->headers->set('Vary', $response->headers->get('Vary') . ', Origin');
+        }
+
+        if ($this->options['supportsCredentials']) {
+            $response->headers->set('Access-Control-Allow-Credentials', 'true');
+        }
+
+        if ($this->options['exposedHeaders']) {
+            $response->headers->set('Access-Control-Expose-Headers', implode(', ', $this->options['exposedHeaders']));
+        }
+
+        return $response;
+    }
+
+    public function handlePreflightRequest(Request $request)
+    {
+        if (true !== $check = $this->checkPreflightRequestConditions($request)) {
+            return $check;
+        }
+
+        return $this->buildPreflightCheckResponse($request);
+    }
+
+    private function buildPreflightCheckResponse(Request $request)
+    {
+        $response = new Response();
+
+        if ($this->options['supportsCredentials']) {
+            $response->headers->set('Access-Control-Allow-Credentials', 'true');
+        }
+
+        $response->headers->set('Access-Control-Allow-Origin', $request->headers->get('Origin'));
+
+        if ($this->options['maxAge']) {
+            $response->headers->set('Access-Control-Max-Age', $this->options['maxAge']);
+        }
+
+        $allowMethods = $this->options['allowedMethods'] === true
+            ? strtoupper($request->headers->get('Access-Control-Request-Method'))
+            : implode(', ', $this->options['allowedMethods']);
+        $response->headers->set('Access-Control-Allow-Methods', $allowMethods);
+
+        $allowHeaders = $this->options['allowedHeaders'] === true
+            ? strtoupper($request->headers->get('Access-Control-Request-Headers'))
+            : implode(', ', $this->options['allowedHeaders']);
+        $response->headers->set('Access-Control-Allow-Headers', $allowHeaders);
+
+        return $response;
+    }
+
+    private function checkPreflightRequestConditions(Request $request)
+    {
+        if ( ! $this->checkOrigin($request)) {
+            return $this->createBadRequestResponse(403, 'Origin not allowed');
+        }
+
+        if ( ! $this->checkMethod($request)) {
+            return $this->createBadRequestResponse(405, 'Method not allowed');
+        }
+
+        $requestHeaders = array();
+        // if allowedHeaders has been set to true ('*' allow all flag) just skip this check
+        if ($this->options['allowedHeaders'] !== true && $request->headers->has('Access-Control-Request-Headers')) {
+            $headers        = strtolower($request->headers->get('Access-Control-Request-Headers'));
+            $requestHeaders = explode(',', $headers);
+
+            foreach ($requestHeaders as $header) {
+                if ( ! in_array(trim($header), $this->options['allowedHeaders'])) {
+                    return $this->createBadRequestResponse(403, 'Header not allowed');
+                }
+            }
+        }
+
+        return true;
+    }
+
+    private function createBadRequestResponse($code, $reason = '')
+    {
+        return new Response($reason, $code);
+    }
+
+    private function checkOrigin(Request $request) {
+        if ($this->options['allowedOrigins'] === true) {
+            // allow all '*' flag
+            return true;
+        }
+        $origin = $request->headers->get('Origin');
+
+        return in_array($origin, $this->options['allowedOrigins']);
+    }
+
+    private function checkMethod(Request $request) {
+        if ($this->options['allowedMethods'] === true) {
+            // allow all '*' flag
+            return true;
+        }
+
+        $requestMethod = strtoupper($request->headers->get('Access-Control-Request-Method'));
+        return in_array($requestMethod, $this->options['allowedMethods']);
+    }
+
+}
diff --git a/core/vendor/asm89/stack-cors/test/Asm89/Stack/CorsTest.php b/core/vendor/asm89/stack-cors/test/Asm89/Stack/CorsTest.php
new file mode 100755
index 0000000..1493c46
--- /dev/null
+++ b/core/vendor/asm89/stack-cors/test/Asm89/Stack/CorsTest.php
@@ -0,0 +1,395 @@
+<?php
+
+namespace Asm89\Stack;
+
+use PHPUnit_Framework_TestCase;
+use Symfony\Component\HttpKernel\HttpKernelInterface;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Response;
+
+class CorsTest extends PHPUnit_Framework_TestCase
+{
+    /**
+     * @test
+     */
+    public function it_does_not_modify_on_a_request_without_origin()
+    {
+        $app                = $this->createStackedApp();
+        $unmodifiedResponse = new Response();
+
+        $response = $app->handle(new Request());
+
+        $this->assertEquals($unmodifiedResponse->headers, $response->headers);
+    }
+
+    /**
+     * @test
+     */
+    public function it_returns_403_on_valid_actual_request_with_origin_not_allowed()
+    {
+        $app      = $this->createStackedApp(array('allowedOrigins' => array('notlocalhost')));
+        $request  = $this->createValidActualRequest();
+
+        $response = $app->handle($request);
+
+        $this->assertEquals(403, $response->getStatusCode());
+    }
+
+    /**
+     * @test
+     */
+    public function it_returns_allow_origin_header_on_valid_actual_request()
+    {
+        $app      = $this->createStackedApp();
+        $request  = $this->createValidActualRequest();
+
+        $response = $app->handle($request);
+
+        $this->assertTrue($response->headers->has('Access-Control-Allow-Origin'));
+        $this->assertEquals('localhost', $response->headers->get('Access-Control-Allow-Origin'));
+    }
+
+    /**
+     * @test
+     */
+    public function it_returns_allow_origin_header_on_allow_all_origin_request()
+    {
+        $app      = $this->createStackedApp(array('allowedOrigins' => array('*')));
+        $request  = new Request();
+        $request->headers->set('Origin', 'http://localhost');
+
+        $response = $app->handle($request);
+
+        $this->assertEquals(200, $response->getStatusCode());
+        $this->assertTrue($response->headers->has('Access-Control-Allow-Origin'));
+        $this->assertEquals('http://localhost', $response->headers->get('Access-Control-Allow-Origin'));
+    }
+
+    /**
+     * @test
+     */
+    public function it_returns_allow_headers_header_on_allow_all_headers_request()
+    {
+        $app     = $this->createStackedApp(array('allowedHeaders' => array('*')));
+        $request = $this->createValidPreflightRequest();
+        $request->headers->set('Access-Control-Request-Headers', 'Foo, BAR');
+
+        $response = $app->handle($request);
+
+        $this->assertEquals(200, $response->getStatusCode());
+        $this->assertEquals('FOO, BAR', $response->headers->get('Access-Control-Allow-Headers'));
+    }
+
+    /**
+     * @test
+     */
+    public function it_does_not_return_allow_origin_header_on_valid_actual_request_with_origin_not_allowed()
+    {
+        $app      = $this->createStackedApp(array('allowedOrigins' => array('notlocalhost')));
+        $request  = $this->createValidActualRequest();
+
+        $response = $app->handle($request);
+
+        $this->assertFalse($response->headers->has('Access-Control-Allow-Origin'));
+    }
+
+    /**
+     * @test
+     */
+    public function it_sets_allow_credentials_header_when_flag_is_set_on_valid_actual_request()
+    {
+        $app     = $this->createStackedApp(array('supportsCredentials' => true));
+        $request = $this->createValidActualRequest();
+
+        $response = $app->handle($request);
+
+        $this->assertTrue($response->headers->has('Access-Control-Allow-Credentials'));
+        $this->assertEquals('true', $response->headers->get('Access-Control-Allow-Credentials'));
+    }
+
+    /**
+     * @test
+     */
+    public function it_does_not_set_allow_credentials_header_when_flag_is_not_set_on_valid_actual_request()
+    {
+        $app     = $this->createStackedApp();
+        $request = $this->createValidActualRequest();
+
+        $response = $app->handle($request);
+
+        $this->assertFalse($response->headers->has('Access-Control-Allow-Credentials'));
+    }
+
+    /**
+     * @test
+     */
+    public function it_sets_exposed_headers_when_configured_on_actual_request()
+    {
+        $app     = $this->createStackedApp(array('exposedHeaders' => array('x-exposed-header', 'x-another-exposed-header')));
+        $request = $this->createValidActualRequest();
+
+        $response = $app->handle($request);
+
+        $this->assertTrue($response->headers->has('Access-Control-Expose-Headers'));
+        $this->assertEquals('x-exposed-header, x-another-exposed-header', $response->headers->get('Access-Control-Expose-Headers'));
+    }
+
+    /**
+     * @test
+     * @see http://www.w3.org/TR/cors/index.html#resource-implementation
+     */
+    public function it_adds_a_vary_header()
+    {
+        $app      = $this->createStackedApp();
+        $request  = $this->createValidActualRequest();
+
+        $response = $app->handle($request);
+
+        $this->assertTrue($response->headers->has('Vary'));
+        $this->assertEquals('Origin', $response->headers->get('Vary'));
+    }
+
+    /**
+     * @test
+     * @see http://www.w3.org/TR/cors/index.html#resource-implementation
+     */
+    public function it_appends_an_existing_vary_header()
+    {
+        $app      = $this->createStackedApp(array(), array('Vary' => 'Content-Type'));
+        $request  = $this->createValidActualRequest();
+
+        $response = $app->handle($request);
+
+        $this->assertTrue($response->headers->has('Vary'));
+        $this->assertEquals('Content-Type, Origin', $response->headers->get('Vary'));
+    }
+
+    /**
+     * @test
+     */
+    public function it_returns_access_control_headers_on_cors_request()
+    {
+        $app      = $this->createStackedApp();
+        $request  = new Request();
+        $request->headers->set('Origin', 'localhost');
+
+        $response = $app->handle($request);
+
+        $this->assertTrue($response->headers->has('Access-Control-Allow-Origin'));
+        $this->assertEquals('localhost', $response->headers->get('Access-Control-Allow-Origin'));
+    }
+
+    /**
+     * @test
+     */
+    public function it_returns_access_control_headers_on_valid_preflight_request()
+    {
+        $app     = $this->createStackedApp();
+        $request = $this->createValidPreflightRequest();
+
+        $response = $app->handle($request);
+
+        $this->assertTrue($response->headers->has('Access-Control-Allow-Origin'));
+        $this->assertEquals('localhost', $response->headers->get('Access-Control-Allow-Origin'));
+    }
+
+    /**
+     * @test
+     */
+    public function it_returns_403_on_valid_preflight_request_with_origin_not_allowed()
+    {
+        $app     = $this->createStackedApp(array('allowedOrigins' => array('notlocalhost')));
+        $request = $this->createValidPreflightRequest();
+
+        $response = $app->handle($request);
+
+        $this->assertEquals(403, $response->getStatusCode());
+    }
+
+    /**
+     * @test
+     */
+    public function it_does_not_modify_request_with_origin_not_allowed()
+    {
+        $passedOptions = array(
+          'allowedOrigins' => array('notlocalhost'),
+        );
+
+        $service  = new CorsService($passedOptions);
+        $request  = $this->createValidActualRequest();
+        $response = new Response();
+        $service->addActualRequestHeaders($response, $request);
+
+        $this->assertEquals($response, new Response());
+    }
+
+    /**
+     * @test
+     */
+    public function it_returns_405_on_valid_preflight_request_with_method_not_allowed()
+    {
+        $app     = $this->createStackedApp(array('allowedMethods' => array('put')));
+        $request = $this->createValidPreflightRequest();
+
+        $response = $app->handle($request);
+
+        $this->assertEquals(405, $response->getStatusCode());
+    }
+
+    /**
+     * @test
+     */
+    public function it_allow_methods_on_valid_preflight_request()
+    {
+        $app     = $this->createStackedApp(array('allowedMethods' => array('get', 'put')));
+        $request = $this->createValidPreflightRequest();
+
+        $response = $app->handle($request);
+
+        $this->assertTrue($response->headers->has('Access-Control-Allow-Methods'));
+        // it will uppercase the methods
+        $this->assertEquals('GET, PUT', $response->headers->get('Access-Control-Allow-Methods'));
+    }
+
+    /**
+     * @test
+     */
+    public function it_returns_valid_preflight_request_with_allow_methods_all()
+    {
+        $app     = $this->createStackedApp(array('allowedMethods' => array('*')));
+        $request = $this->createValidPreflightRequest();
+
+        $response = $app->handle($request);
+
+        $this->assertTrue($response->headers->has('Access-Control-Allow-Methods'));
+        // it will return the Access-Control-Request-Method pass in the request
+        $this->assertEquals('GET', $response->headers->get('Access-Control-Allow-Methods'));
+    }
+
+    /**
+     * @test
+     */
+    public function it_returns_403_on_valid_preflight_request_with_one_of_the_requested_headers_not_allowed()
+    {
+        $app     = $this->createStackedApp();
+        $request = $this->createValidPreflightRequest();
+        $request->headers->set('Access-Control-Request-Headers', 'x-not-allowed-header');
+
+        $response = $app->handle($request);
+
+        $this->assertEquals(403, $response->getStatusCode());
+    }
+
+    /**
+     * @test
+     */
+    public function it_returns_ok_on_valid_preflight_request_with_requested_headers_allowed()
+    {
+        $app            = $this->createStackedApp();
+        $requestHeaders = 'X-Allowed-Header, x-other-allowed-header';
+        $request        = $this->createValidPreflightRequest();
+        $request->headers->set('Access-Control-Request-Headers', $requestHeaders);
+
+        $response = $app->handle($request);
+
+        $this->assertEquals(200, $response->getStatusCode());
+
+        $this->assertTrue($response->headers->has('Access-Control-Allow-Headers'));
+        // the response will have the "allowedHeaders" value passed to Cors rather than the request one
+        $this->assertEquals('x-allowed-header, x-other-allowed-header', $response->headers->get('Access-Control-Allow-Headers'));
+    }
+
+    /**
+     * @test
+     */
+    public function it_sets_allow_credentials_header_when_flag_is_set_on_valid_preflight_request()
+    {
+        $app     = $this->createStackedApp(array('supportsCredentials' => true));
+        $request = $this->createValidPreflightRequest();
+
+        $response = $app->handle($request);
+
+        $this->assertTrue($response->headers->has('Access-Control-Allow-Credentials'));
+        $this->assertEquals('true', $response->headers->get('Access-Control-Allow-Credentials'));
+    }
+
+    /**
+     * @test
+     */
+    public function it_does_not_set_allow_credentials_header_when_flag_is_not_set_on_valid_preflight_request()
+    {
+        $app     = $this->createStackedApp();
+        $request = $this->createValidPreflightRequest();
+
+        $response = $app->handle($request);
+
+        $this->assertFalse($response->headers->has('Access-Control-Allow-Credentials'));
+    }
+
+    /**
+     * @test
+     */
+    public function it_sets_max_age_when_set()
+    {
+        $app     = $this->createStackedApp(array('maxAge' => 42));
+        $request = $this->createValidPreflightRequest();
+
+        $response = $app->handle($request);
+
+        $this->assertTrue($response->headers->has('Access-Control-Max-Age'));
+        $this->assertEquals(42, $response->headers->get('Access-Control-Max-Age'));
+    }
+
+    private function createValidActualRequest()
+    {
+        $request  = new Request();
+        $request->headers->set('Origin', 'localhost');
+
+        return $request;
+    }
+
+    private function createValidPreflightRequest()
+    {
+        $request  = new Request();
+        $request->headers->set('Origin', 'localhost');
+        $request->headers->set('Access-Control-Request-Method', 'get');
+        $request->setMethod('OPTIONS');
+
+        return $request;
+    }
+
+    private function createStackedApp(array $options = array(), array $responseHeaders = array())
+    {
+        $passedOptions = array_merge(array(
+                'allowedHeaders'      => array('x-allowed-header', 'x-other-allowed-header'),
+                'allowedMethods'      => array('delete', 'get', 'post', 'put'),
+                'allowedOrigins'      => array('localhost'),
+                'exposedHeaders'      => false,
+                'maxAge'              => false,
+                'supportsCredentials' => false,
+            ),
+            $options
+        );
+
+        return new Cors(new MockApp($responseHeaders), $passedOptions);
+    }
+}
+
+class MockApp implements HttpKernelInterface
+{
+    private $responseHeaders;
+
+    public function __construct(array $responseHeaders)
+    {
+        $this->responseHeaders = $responseHeaders;
+    }
+
+    public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, $catch = true)
+    {
+        $response = new Response();
+
+        $response->headers->add($this->responseHeaders);
+
+        return $response;
+    }
+}
diff --git a/core/vendor/asm89/stack-cors/test/bootstrap.php b/core/vendor/asm89/stack-cors/test/bootstrap.php
new file mode 100644
index 0000000..deb617f
--- /dev/null
+++ b/core/vendor/asm89/stack-cors/test/bootstrap.php
@@ -0,0 +1,10 @@
+<?php
+
+if (file_exists($file = __DIR__.'/../vendor/autoload.php')) {
+    $loader = require_once $file;
+    $loader->add('Asm89\Stack', __DIR__);
+    $loader->add('Asm89\Stack', __DIR__ . '/../src');
+} else {
+    throw new RuntimeException('Install dependencies to run test suite.');
+}
+
diff --git a/core/vendor/composer/autoload_namespaces.php b/core/vendor/composer/autoload_namespaces.php
index 18472d7..7e74b46 100644
--- a/core/vendor/composer/autoload_namespaces.php
+++ b/core/vendor/composer/autoload_namespaces.php
@@ -35,4 +35,5 @@
     'Doctrine\\Common\\Cache\\' => array($vendorDir . '/doctrine/cache/lib'),
     'Doctrine\\Common\\Annotations\\' => array($vendorDir . '/doctrine/annotations/lib'),
     'Doctrine\\Common\\' => array($vendorDir . '/doctrine/common/lib'),
+    'Asm89\\Stack' => array($vendorDir . '/asm89/stack-cors/src'),
 );
diff --git a/core/vendor/composer/installed.json b/core/vendor/composer/installed.json
index 03eef68..b086b19 100644
--- a/core/vendor/composer/installed.json
+++ b/core/vendor/composer/installed.json
@@ -2601,5 +2601,50 @@
                 "homepage": "https://github.com/mtdowling"
             }
         ]
+    },
+    {
+        "name": "asm89/stack-cors",
+        "version": "0.2.1",
+        "version_normalized": "0.2.1.0",
+        "source": {
+            "type": "git",
+            "url": "https://github.com/asm89/stack-cors.git",
+            "reference": "2d77e77251a434e4527315313a672f5801b29fa2"
+        },
+        "dist": {
+            "type": "zip",
+            "url": "https://api.github.com/repos/asm89/stack-cors/zipball/2d77e77251a434e4527315313a672f5801b29fa2",
+            "reference": "2d77e77251a434e4527315313a672f5801b29fa2",
+            "shasum": ""
+        },
+        "require": {
+            "php": ">=5.3.2",
+            "symfony/http-foundation": "~2.1",
+            "symfony/http-kernel": "~2.1"
+        },
+        "time": "2014-07-28 07:22:35",
+        "type": "library",
+        "installation-source": "dist",
+        "autoload": {
+            "psr-0": {
+                "Asm89\\Stack": "src/"
+            }
+        },
+        "notification-url": "https://packagist.org/downloads/",
+        "license": [
+            "MIT"
+        ],
+        "authors": [
+            {
+                "name": "Alexander",
+                "email": "iam.asm89@gmail.com"
+            }
+        ],
+        "description": "Cross-origin resource sharing library and stack middleware",
+        "homepage": "https://github.com/asm89/stack-cors",
+        "keywords": [
+            "cors",
+            "stack"
+        ]
     }
 ]
diff --git a/sites/default/default.services.yml b/sites/default/default.services.yml
index a5307ec..d13c99c 100644
--- a/sites/default/default.services.yml
+++ b/sites/default/default.services.yml
@@ -51,3 +51,20 @@ parameters:
     # Default key/value expirable storage service to use.
     # @default keyvalue.database.expirable
     # default: keyvalue.database.expirable
+
+  # Configure Cross-Site HTTP requests (CORS).
+  # Read https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS
+  # for more information about the topic in general.
+  # Note: By default the configuration is disabled.
+  cors.config:
+    enabled: false
+    # Specify allowed headers, like 'x-allowed-header'.
+    allowedHeaders: []
+    # Specify allowed request methods, specify '*' to allow all possible ones.
+    allowedMethods: []
+    # Configure requests allowed from specific origins.
+    allowedOrigins: ['*']
+    exposedHeaders: false
+    maxAge: false
+    supportsCredentials: false
+
