From 0fdc9c44cb8a22b53321769d5b8222623722ec7e Mon Sep 17 00:00:00 2001 From: "Benjamin D. Plessinger" Date: Thu, 16 Jan 2020 09:19:43 -0500 Subject: [PATCH] Allow CORS requests when configured --- .../Version851To870/ConfigFilesMigration.php | 6 +- classes/Rest/XdmodApplicationFactory.php | 56 +++++++++++++++++-- configuration/portal_settings.ini | 5 ++ templates/portal_settings.template | 5 ++ 4 files changed, 65 insertions(+), 7 deletions(-) diff --git a/classes/OpenXdmod/Migration/Version851To870/ConfigFilesMigration.php b/classes/OpenXdmod/Migration/Version851To870/ConfigFilesMigration.php index 8adcedff2c..798adef7ed 100644 --- a/classes/OpenXdmod/Migration/Version851To870/ConfigFilesMigration.php +++ b/classes/OpenXdmod/Migration/Version851To870/ConfigFilesMigration.php @@ -16,6 +16,10 @@ class ConfigFilesMigration extends AbstractConfigFilesMigration public function execute() { $this->assertPortalSettingsIsWritable(); - $this->writePortalSettingsFile(); + $this->writePortalSettingsFile( + array( + 'cors_domains' => '' + ) + ); } } diff --git a/classes/Rest/XdmodApplicationFactory.php b/classes/Rest/XdmodApplicationFactory.php index 91f372b4e0..ac4ddc3611 100644 --- a/classes/Rest/XdmodApplicationFactory.php +++ b/classes/Rest/XdmodApplicationFactory.php @@ -118,6 +118,25 @@ public static function getInstance() // SETUP: an after middleware that detects the query debug mode and, if true, retrieves // and returns the collected sql queries / params. $app->after(function (Request $request, Response $response, Application $app) { + $origin = $request->headers->get('Origin'); + if ($origin !== null) { + try { + $corsDomains = \xd_utilities\getConfiguration('cors', 'domains'); + if (!empty($corsDomains)){ + $allowedCorsDomains = explode(',', $corsDomains); + if (in_array($origin, $allowedCorsDomains)) { + // If these headers change similar updates will need to be made to the `error` section below + $response->headers->set('Access-Control-Allow-Origin', $origin); + $response->headers->set('Access-Control-Allow-Headers', 'x-requested-with, content-type'); + $response->headers->set('Access-Control-Allow-Credentials', 'true'); + $response->headers->set('Vary', 'Origin'); + } + } + } catch (Exception $e) { + // this catches if the section or config item does not exist + // in that case we just carry on + } + } if (PDODB::debugging()) { $debugInfo = PDODB::debugInfo(); @@ -170,12 +189,37 @@ public static function getInstance() // SETUP: error handler $app->error(function (\Exception $e, $code) use ($app) { - $exceptionOutput = \handle_uncaught_exception($e); - return new Response( - $exceptionOutput['content'], - $exceptionOutput['httpCode'], - $exceptionOutput['headers'] - ); + if($code == 405 && strtoupper($_SERVER['REQUEST_METHOD']) === 'OPTIONS' && array_key_exists('HTTP_ORIGIN', $_SERVER)){ + try { + $corsDomains = \xd_utilities\getConfiguration('cors', 'domains'); + } catch (\Exception $cors) { + $corsDomains = null; + } + if (!empty($corsDomains)){ + $allowedCorsDomains = explode(',', $corsDomains); + $origin = $_SERVER['HTTP_ORIGIN']; + if (in_array($origin, $allowedCorsDomains)) { + // if these headers change we will need to update the `after` above + return new Response( + '', + 204, /* in `$app->error` this value is ignored use header `X-Status-Code` to force a different status code */ + [ + 'X-Status-Code' => 204, + 'Vary' => 'Origin', + 'Access-Control-Allow-Origin' => $origin, + 'Access-Control-Allow-Headers' => 'x-requested-with, content-type', + 'Access-Control-Allow-Credentials' => 'true' + ] + ); + } + } + } + $exceptionOutput = \handle_uncaught_exception($e); + return new Response( + $exceptionOutput['content'], + $exceptionOutput['httpCode'], + $exceptionOutput['headers'] + ); }); // Set the application instance as the global instance and return it. diff --git a/configuration/portal_settings.ini b/configuration/portal_settings.ini index 94b6fb5e0d..010a546f54 100644 --- a/configuration/portal_settings.ini +++ b/configuration/portal_settings.ini @@ -76,6 +76,11 @@ version = "v1" ; * Apereo CAS basic_auth = "on" +[cors] +; this allows for specified domains (comma separated list) to +; respond with cors headers allowing third party integration +domains = "" + [mailer] sender_name = "Open XDMoD Mailer" sender_email = "" diff --git a/templates/portal_settings.template b/templates/portal_settings.template index ff0550af25..705386fa10 100644 --- a/templates/portal_settings.template +++ b/templates/portal_settings.template @@ -76,6 +76,11 @@ version = "[:rest_version:]" ; * Apereo CAS basic_auth = "[:rest_basic_auth:]" +[cors] +; this allows for specified domains (comma separated list) to +; respond with cors headers allowing third party integration +domains = "[:cors_domains:]" + [mailer] sender_name = "[:mailer_sender_name:]" sender_email = "[:mailer_sender_email:]"