CORS settings in webui (#11912)

* Change CORS implementation
allows for upstream integration of Laravel 7

* migrate config

* skip implementing patterns for now

* Expose settings to the webui

* Make db settings apply
This commit is contained in:
Tony Murray 2020-07-08 07:36:51 -05:00 committed by GitHub
parent 726a762944
commit 560fd71ef6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 318 additions and 194 deletions

View File

@ -16,6 +16,7 @@ class Kernel extends HttpKernel
*/
protected $middleware = [
\App\Http\Middleware\TrustProxies::class,
\App\Http\Middleware\HandleCors::class,
\App\Http\Middleware\CheckForMaintenanceMode::class,
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
\App\Http\Middleware\TrimStrings::class,
@ -54,7 +55,6 @@ class Kernel extends HttpKernel
'api' => [
\Illuminate\Routing\Middleware\SubstituteBindings::class,
'authenticate:token',
\Spatie\Cors\Cors::class,
],
];

View File

@ -0,0 +1,61 @@
<?php
/**
* HandleCors.php
*
* Check and load cors settings from db config at runtime
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @package LibreNMS
* @link http://librenms.org
* @copyright 2020 Tony Murray
* @author Tony Murray <murraytony@gmail.com>
*/
namespace App\Http\Middleware;
use Asm89\Stack\CorsService;
use Illuminate\Contracts\Container\Container;
class HandleCors extends \Fruitcake\Cors\HandleCors
{
private $map = [
'allowmethods' => 'allowed_methods',
'origin' => 'allowed_origins',
'allowheaders' => 'allowed_headers',
'exposeheaders' => 'exposed_headers',
'maxage' => 'max_age',
'allowcredentials' => 'supports_credentials',
];
public function __construct(Container $container)
{
// load legacy config settings before booting the CorsService
if (\LibreNMS\Config::get('api.cors.enabled')) {
$laravel_config = $container['config']->get('cors');
$legacy = \LibreNMS\Config::get('api.cors');
$laravel_config['paths'][] = 'api/*';
foreach ($this->map as $config_key => $option_key) {
$laravel_config[$option_key] = $legacy[$config_key] ?? $laravel_config[$option_key];
}
$container['config']->set('cors', $laravel_config);
}
$cors = $container->make(CorsService::class);
parent::__construct($cors, $container);
}
}

View File

@ -1,77 +0,0 @@
<?php
/**
* CorsApiProfile.php
*
* -Description-
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* @package LibreNMS
* @link http://librenms.org
* @copyright 2019 Tony Murray
* @author Tony Murray <murraytony@gmail.com>
*/
namespace App\Http\Profile;
use Illuminate\Support\Arr;
use LibreNMS\Config;
use Spatie\Cors\CorsProfile\DefaultProfile;
class CorsApiProfile extends DefaultProfile
{
public function addCorsHeaders($response)
{
return Config::get('api.cors.enabled') ?
parent::addCorsHeaders($response) :
$response;
}
public function addPreflightHeaders($response)
{
return Config::get('api.cors.enabled') ?
parent::addPreflightHeaders($response) :
$response;
}
public function allowHeaders(): array
{
return Arr::wrap(Config::get('api.cors.allowheaders', []));
}
public function allowMethods(): array
{
return Arr::wrap(Config::get('api.cors.allowmethods', []));
}
public function maxAge(): int
{
return (int)Config::get('api.cors.maxage', 86400);
}
public function allowOrigins(): array
{
return Arr::wrap(Config::get('api.cors.origin', []));
}
public function exposeHeaders(): array
{
return Arr::wrap(Config::get('api.cors.exposeheaders', []));
}
public function allowCredentials(): bool
{
return (bool)Config::get('api.cors.allowcredentials');
}
}

View File

@ -39,6 +39,7 @@
"ezyang/htmlpurifier": "^4.8",
"fico7489/laravel-pivot": "^3.0",
"fideloper/proxy": "^4.0",
"fruitcake/laravel-cors": "^2.0",
"influxdb/influxdb-php": "^1.14",
"laravel/framework": "^6.18",
"laravel/tinker": "^2.0",
@ -49,7 +50,6 @@
"php-amqplib/php-amqplib": "^2.0",
"phpmailer/phpmailer": "~6.0",
"rmccue/requests": "^1.7",
"spatie/laravel-cors": "^1.6",
"symfony/yaml": "^4.0",
"tecnickcom/tcpdf": "~6.2.0",
"tightenco/ziggy": "^0.8.0",

190
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "e72ee8f57b19bfafb68f1ea62ecad1b2",
"content-hash": "af8c6b05826511d29e36dd2d38338192",
"packages": [
{
"name": "amenadiel/jpgraph",
@ -61,6 +61,58 @@
],
"time": "2018-10-14T21:43:30+00:00"
},
{
"name": "asm89/stack-cors",
"version": "v2.0.1",
"source": {
"type": "git",
"url": "https://github.com/asm89/stack-cors.git",
"reference": "23f469e81c65e2fb7fc7bce371fbdc363fe32adf"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/asm89/stack-cors/zipball/23f469e81c65e2fb7fc7bce371fbdc363fe32adf",
"reference": "23f469e81c65e2fb7fc7bce371fbdc363fe32adf",
"shasum": ""
},
"require": {
"php": "^7.0",
"symfony/http-foundation": "~2.7|~3.0|~4.0|~5.0",
"symfony/http-kernel": "~2.7|~3.0|~4.0|~5.0"
},
"require-dev": {
"phpunit/phpunit": "^6|^7|^8|^9",
"squizlabs/php_codesniffer": "^3.5"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.0-dev"
}
},
"autoload": {
"psr-4": {
"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": "2020-05-31T07:17:05+00:00"
},
{
"name": "clue/socket-raw",
"version": "v1.4.1",
@ -1031,6 +1083,82 @@
],
"time": "2020-06-23T01:36:47+00:00"
},
{
"name": "fruitcake/laravel-cors",
"version": "v2.0.1",
"source": {
"type": "git",
"url": "https://github.com/fruitcake/laravel-cors.git",
"reference": "dbfc311b25d4873c3c2382b26860be3567492bd6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/fruitcake/laravel-cors/zipball/dbfc311b25d4873c3c2382b26860be3567492bd6",
"reference": "dbfc311b25d4873c3c2382b26860be3567492bd6",
"shasum": ""
},
"require": {
"asm89/stack-cors": "^2.0.1",
"illuminate/contracts": "^5.6|^6.0|^7.0|^8.0",
"illuminate/support": "^5.6|^6.0|^7.0|^8.0",
"php": ">=7.1",
"symfony/http-foundation": "^4.0|^5.0",
"symfony/http-kernel": "^4.0|^5.0"
},
"require-dev": {
"laravel/framework": "^5.5|^6.0|^7.0|^8.0",
"orchestra/dusk-updater": "^1.2",
"orchestra/testbench": "^3.5|^4.0|^5.0|^6.0",
"orchestra/testbench-dusk": "^5.1",
"phpro/grumphp": "^0.16|^0.17",
"phpunit/phpunit": "^6.0|^7.0|^8.0",
"squizlabs/php_codesniffer": "^3.5"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.0-dev"
},
"laravel": {
"providers": [
"Fruitcake\\Cors\\CorsServiceProvider"
]
}
},
"autoload": {
"psr-4": {
"Fruitcake\\Cors\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fruitcake",
"homepage": "https://fruitcake.nl"
},
{
"name": "Barry vd. Heuvel",
"email": "barryvdh@gmail.com"
}
],
"description": "Adds CORS (Cross-Origin Resource Sharing) headers support in your Laravel application",
"keywords": [
"api",
"cors",
"crossdomain",
"laravel"
],
"funding": [
{
"url": "https://github.com/barryvdh",
"type": "github"
}
],
"time": "2020-05-31T07:30:16+00:00"
},
{
"name": "guzzlehttp/guzzle",
"version": "6.5.5",
@ -2986,66 +3114,6 @@
],
"time": "2016-10-13T00:11:37+00:00"
},
{
"name": "spatie/laravel-cors",
"version": "1.6.0",
"source": {
"type": "git",
"url": "https://github.com/spatie/laravel-cors.git",
"reference": "d74099d57821d5a72ae21416c0be0dcd58779355"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/spatie/laravel-cors/zipball/d74099d57821d5a72ae21416c0be0dcd58779355",
"reference": "d74099d57821d5a72ae21416c0be0dcd58779355",
"shasum": ""
},
"require": {
"illuminate/support": "5.5.*|5.6.*|5.7.*|5.8.*|^6.0",
"php": "^7.2"
},
"require-dev": {
"orchestra/testbench": "3.5.*|3.6.*|3.7.*|3.8.*|^4.0",
"phpunit/phpunit": "^8.0"
},
"type": "library",
"extra": {
"laravel": {
"providers": [
"Spatie\\Cors\\CorsServiceProvider"
]
}
},
"autoload": {
"psr-4": {
"Spatie\\Cors\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Freek Van der Herten",
"email": "freek@spatie.be",
"homepage": "https://spatie.be",
"role": "Developer"
}
],
"description": "Send CORS headers in a Laravel or Lumen application",
"homepage": "https://github.com/spatie/laravel-cors",
"keywords": [
"ajax",
"api",
"cors",
"laravel-cors",
"request",
"spatie"
],
"abandoned": "laravel/framework",
"time": "2019-09-04T06:55:15+00:00"
},
{
"name": "swiftmailer/swiftmailer",
"version": "v6.2.3",

View File

@ -3,59 +3,58 @@
return [
/*
* A cors profile determines which origins, methods, headers are allowed for
* a given requests. The `DefaultProfile` reads its configuration from this
* config file.
*
* You can easily create your own cors profile.
* More info: https://github.com/spatie/laravel-cors/#creating-your-own-cors-profile
*/
'cors_profile' => App\Http\Profile\CorsApiProfile::class,
|--------------------------------------------------------------------------
| Laravel CORS Options
|--------------------------------------------------------------------------
|
| The allowed_methods and allowed_headers options are case-insensitive.
|
| You don't need to provide both allowed_origins and allowed_origins_patterns.
| If one of the strings passed matches, it is considered a valid origin.
|
| If array('*') is provided to allowed_methods, allowed_origins or allowed_headers
| all methods / origins / headers are allowed.
|
*/
/*
* This configuration is used by `DefaultProfile`.
* You can enable CORS for 1 or multiple paths.
* Example: ['api/*']
*/
'default_profile' => [
'paths' => [],
'allow_credentials' => false,
/*
* Matches the request method. `[*]` allows all methods.
*/
'allowed_methods' => ['*'],
'allow_origins' => [
'*',
],
/*
* Matches the request origin. `[*]` allows all origins. Wildcards can be used, eg `*.mydomain.com`
*/
'allowed_origins' => [],
'allow_methods' => [
'POST',
'GET',
'OPTIONS',
'PUT',
'PATCH',
'DELETE',
],
/*
* Patterns that can be used with `preg_match` to match the origin.
*/
'allowed_origins_patterns' => [],
'allow_headers' => [
'Content-Type',
'X-Auth-Token',
'Origin',
'Authorization',
],
/*
* Sets the Access-Control-Allow-Headers response header. `[*]` allows all headers.
*/
'allowed_headers' => ['*'],
'expose_headers' => [
'Cache-Control',
'Content-Language',
'Content-Type',
'Expires',
'Last-Modified',
'Pragma',
],
/*
* Sets the Access-Control-Expose-Headers response header with these headers.
*/
'exposed_headers' => [],
'forbidden_response' => [
'message' => 'Forbidden (cors).',
'status' => 403,
],
/*
* Sets the Access-Control-Max-Age response header when > 0.
*/
'max_age' => 0,
/*
* Preflight request will respond with value for the max age header.
*/
'max_age' => 60 * 60 * 24,
],
/*
* Sets the Access-Control-Allow-Credentials header.
*/
'supports_credentials' => false,
];

View File

@ -3,11 +3,12 @@
"/css/app.css": "/css/app.css?id=ffec4165a9c98d892a32",
"/js/manifest.js": "/js/manifest.js?id=3c768977c2574a34506e",
"/js/vendor.js": "/js/vendor.js?id=c0e0ebbfd027a8baefb4",
"/js/lang/de.js": "/js/lang/de.js?id=2c4ad02fa89b684d4f57",
"/js/lang/en.js": "/js/lang/en.js?id=8aeb65879e99c385460f",
"/js/lang/fr.js": "/js/lang/fr.js?id=3b61631feb2cb579f713",
"/js/lang/it.js": "/js/lang/it.js?id=514765c5399ffaa111b9",
"/js/lang/ru.js": "/js/lang/ru.js?id=f6b7c078755312a0907c",
"/js/lang/uk.js": "/js/lang/uk.js?id=c19a5dcee4724579cb41",
"/js/lang/zh-TW.js": "/js/lang/zh-TW.js?id=6cec27c0472c6d721d30"
"/js/lang/de.js": "/js/lang/de.js?id=73ed23dde31af205f171",
"/js/lang/en.js": "/js/lang/en.js?id=e2297f39a1eabc180200",
"/js/lang/fr.js": "/js/lang/fr.js?id=91daac2f7383c820457b",
"/js/lang/it.js": "/js/lang/it.js?id=c202a58a7f5bca08801b",
"/js/lang/ru.js": "/js/lang/ru.js?id=aaab82593592e9368a08",
"/js/lang/uk.js": "/js/lang/uk.js?id=9b0b074259847e7aaff3",
"/js/lang/zh-CN.js": "/js/lang/zh-CN.js?id=f6d951b7d6b1f25810fc",
"/js/lang/zh-TW.js": "/js/lang/zh-TW.js?id=21cdd68dc06a428e7260"
}

View File

@ -273,8 +273,18 @@
"Accept",
"X-Auth-Token"
],
"group": "api",
"section": "cors",
"order": 4,
"type": "array"
},
"api.cors.allowcredentials": {
"default": false,
"group": "api",
"section": "cors",
"order": 7,
"type": "boolean"
},
"api.cors.allowmethods": {
"default": [
"POST",
@ -283,14 +293,37 @@
"DELETE",
"PATCH"
],
"group": "api",
"section": "cors",
"order": 2,
"type": "array"
},
"api.cors.enabled": {
"default": false,
"group": "api",
"section": "cors",
"order": 1,
"type": "boolean"
},
"api.cors.exposeheaders": {
"default": [
"Cache-Control",
"Content-Language",
"Content-Type",
"Expires",
"Last-Modified",
"Pragma"
],
"group": "api",
"section": "cors",
"order": 5,
"type": "array"
},
"api.cors.maxage": {
"default": 86400,
"group": "api",
"section": "cors",
"order": 6,
"type": "integer",
"units": "seconds",
"validate": {
@ -298,8 +331,11 @@
}
},
"api.cors.origin": {
"default": "*",
"type": "text"
"default": ["*"],
"group": "api",
"section": "cors",
"order": 3,
"type": "array"
},
"api_demo": {
"default": false,

View File

@ -5,6 +5,7 @@ return [
'readonly' => 'Set in config.php, remove from config.php to enable.',
'groups' => [
'alerting' => 'Alerting',
'api' => 'API',
'auth' => 'Authentication',
'authorization' => 'Authorization',
'external' => 'External',
@ -22,6 +23,9 @@ return [
'email' => 'Email Options',
'rules' => 'Alert Rule Default Settings',
],
'api' => [
'cors' => 'CORS',
],
'auth' => [
'general' => 'General Authentication Settings',
'ad' => 'Active Directory Settings',
@ -193,6 +197,38 @@ return [
'description' => 'Allow the given networks graph access',
'help' => 'Allow the given networks unauthenticated graph access (does not apply when unauthenticated graphs is enabled)'
],
'api' => [
'cors' => [
'allowheaders' => [
'description' => 'Allow Headers',
'help' => 'Sets the Access-Control-Allow-Headers response header',
],
'allowcredentials' => [
'description' => 'Allow Credentials',
'help' => 'Sets the Access-Control-Allow-Credentials header',
],
'allowmethods' => [
'description' => 'Allowed Methods',
'help' => 'Matches the request method.',
],
'enabled' => [
'description' => 'Enable CORS support for the API',
'help' => 'Allows you to load api resources from a web client',
],
'exposeheaders' => [
'description' => 'Expose Headers',
'help' => 'Sets the Access-Control-Expose-Headers response header',
],
'maxage' => [
'description' => 'Max Age',
'help' => 'Sets the Access-Control-Max-Age response header',
],
'origin' => [
'description' => 'Allow Request Origins',
'help' => 'Matches the request origin. Wildcards can be used, eg. *.mydomain.com',
],
],
],
'api_demo' => [
'description' => 'This is the demo'
],