bairwell/middleware-cors

A PSR-7 middleware layer for providing CORS (Cross Origin Request Security) headers and security provisions. Instead of just allowing invalid CORs requests to come through, this middleware actively blocks them after validating.

v0.3.7 2016-06-02 17:38 UTC

This package is auto-updated.

Last update: 2024-10-29 04:31:05 UTC


README

Latest Stable Version License SensioLabsInsight Coverage Status Build Status Total Downloads

This is a PHP 7 Composer compatible library for providing a PSR-7 compatible middleware layer for handling "CORS" (Cross Origin Request Security/Cross-Origin Http Request/HTTP access control) headers and security.

What does this library provides over other CORs libraries?

  • PHP-7 type declarations.
  • Works as a piece of PSR-7 middleware making it compatible with many frameworks (such as Slim 3 and Symfony)
  • Massively flexibility over configuration settings (most can be strings, arrays or callbacks).
  • Follows the CORs flowchart and actively rejects invalid requests.
  • Only sends the appropriate headers when necessary.
  • On CORs "OPTIONS" request, ensure a blank page 204 "No Content" page is returned instead of returning unwanted content bodies.
  • Supports PSR-3 based loggers for debugging purposes.
  • Ignores non-CORs "OPTIONS" requests (for example, on REST services). A CORs request is indicated by the presence of the Origin: header on the inbound request.
  • Fully unit tested.
  • Licensed under the MIT License allowing you to practically do whatever you want.
  • Uses namespaces and is 100% object orientated.
  • Blocks invalid settings.
  • Minimal third party requirements (just the definition files "psr/http-message" and "psr/log" as interface definitions, and PHPUnit, PHPCodeSniffer, and Monolog for development/testing).

Installation

Install the latest version with Composer via:

$ composer require bairwell/middleware-cors

or by modifying your composer.json file:

{
  "require": {
    "bairwell/middleware-cors": "@stable"
  }
}

or from the Github repository (which is needed to be able to fork and contribute):

$ git clone git://github.com:bairwell/middleware-cors.git

Usage

You can utilise this CORs library as simply as:

$slim = new \Slim\App(); // use Slim3 as it supports PSR7 middleware

// add CORs
$slim->add(new MiddlewareCors());

// add routes
$slim->run(); // get Slim running

but that won't really add much (as it allows all hosts origin and methods by default).

You can make it slightly more complex by:

$slim = new \Slim\App(); // use Slim3 as it supports PSR7 middleware

$config = [
    'origin' => '*.example.com' // allow all hosts ending example.com
];

// add CORs
$slim->add(new MiddlewareCors($config));

// add routes
$slim->run(); // get Slim running

or

$slim = new \Slim\App(); // use Slim3 as it supports PSR7 middleware

$config = [
    'origin' => ['*.example.com', '*.example.com.test', 'example.com', 'dev.*'],
    'allowCredentials' => true
];

$slim->add(new MiddlewareCors($config)); // add CORs

// add routes
$slim->run(); // get Slim running

which will allow all Origins ending .example.com or *.example.com.test, the exact example.com origin or any host starting with dev. It'll also allow credentials to be allowed.

For a more complicated integration which relies on the Slim router to feed back which methods are actually allowed per route, see tests/MiddlewareCors/FunctionalTests/SlimTest.php

Suggested settings

// read the allowed methods for a route
$corsAllowedMethods = function (ServerRequestInterface $request) use ($container) : array {
    // if this closure is called, make sure it has the route available in the container.
    /* @var RouterInterface $router */
    $router = $container->get('router');

    $routeInfo = $router->dispatch($request);
    $methods = [];
    // was the method called allowed?
    if ($routeInfo[0] === Dispatcher::METHOD_NOT_ALLOWED) {
        $methods = $routeInfo[1];
    } else {
        // if it was, see if we can get the routes and then the methods from it.
        // @var \Slim\Route $route
        $route = $request->getAttribute('route');
        
        // has the request get a route defined? is so use that
        if (null !== $route) {
            $methods = $route->getMethods();
        }
    }

    // if we have methods, let's list them removing the OPTIONs one.
    if (0 === count($methods)) {
        // find the OPTIONs method
        $key = array_search('OPTIONS', $methods,true);
        // and remove it if set.
        if (false !== $key) {
            unset($methods[$key]);
            $methods = array_values($methods);
        }
    }

    return $methods;
};

$cors = new MiddlewareCors([
    'origin' => ['*.example.com','example.com','*.example.com.test','192.168.*','10.*'],
    'exposeHeaders' => '',
    'maxAge' => 120,
    'allowCredentials' => true,
    'allowMethods' => $corsAllowedMethods,
    'allowHeaders' => ['Accept', 'Accept-Language', 'Authorization', 'Content-Type','DNT','Keep-Alive','User-Agent','X-Requested-With','If-Modified-Since','Cache-Control','Origin'],
]);

$slim->add($cors);

Standards

The following PHP FIG standards should be followed:

Standards Checking

PHP Code Sniffer highlights potential coding standards issues.

vendor/bin/phpcs

PHP CS will use the configuration in phpcs.xml.dist by default.

To see which sniffs are running add "-s"

Unit Tests

PHPUnit is installed for unit testing (tests are in tests)

To run unit tests: vendor/bin/phpunit

For a list of the tests that have ran: vendor/bin/phpunit --tap

To restrict the tests run: vendor/bin/phpunit --filter 'MiddlewareCors\\Exceptions\\BadOrigin'

or just

vendor/bin/phpunit --filter 'ExceptionTest'

for all tests which have "Exception" in them and: vendor/bin/phpunit --filter '(ExceptionTest::testEverything|ExceptionTest::testStub)'

to test the two testEverything and testStub methods in the ExceptionTest class (for example).

Licence/License

Licenced under the MIT license. See LICENSE.md for full information.

Bairwell/MiddlewareCors is Copyright (c) Bairwell Ltd/Richard Bairwell 2016.

Supporting development

You can help support development of this library via a variety of methods: