From 1e10b336002b23255b2fcfb85dde4f963f99be58 Mon Sep 17 00:00:00 2001 From: Richard Herbert <1644678+richardherbert@users.noreply.github.com> Date: Tue, 3 May 2022 16:00:05 +0100 Subject: [PATCH] fix: Support for Multiple Allowed Origins * Added tests for multiple allowed origins * Added support for multiple allowed origins Allowed origins can be provided as a list. If the current origin is found in that list then it is returned as the allowed origin. * Added a failure expectation Expectation added to the "can configure for multiple allowed origins" test. --- interceptors/CORS.cfc | 16 ++++-------- tests/resources/app/config/Coldbox.cfc | 8 ++++++ tests/specs/integration/CORSSpec.cfc | 36 ++++++++++++++++++++++++++ 3 files changed, 49 insertions(+), 11 deletions(-) diff --git a/interceptors/CORS.cfc b/interceptors/CORS.cfc index 2b33c16..12a6f1b 100644 --- a/interceptors/CORS.cfc +++ b/interceptors/CORS.cfc @@ -37,13 +37,7 @@ component { return; } - var allowedOrigins = settings.allowOrigins; - if ( isClosure( allowedOrigins ) || isCustomFunction( allowedOrigins ) ) { - allowedOrigins = allowedOrigins( event ); - } - if ( ! isSimpleValue( allowedOrigins ) ) { - allowedOrigins = arrayToList( allowedOrigins, ", " ); - } + var allowedOrigin = event.getHTTPHeader( "Origin", "" ); if ( isCachedEvent( event ) ) { if ( event.getHTTPMethod() != "OPTIONS" ) { @@ -53,8 +47,8 @@ component { var templateCache = getController().getCache( "template" ); var cachedEvent = templateCache.get( event.getEventCacheableEntry().cacheKey ); - log.debug( "Setting the 'Access-Control-Allow-Origin' header to #allowedOrigins# for the cached event." ); - cachedEvent.responseHeaders[ "Access-Control-Allow-Origin" ] = allowedOrigins; + log.debug( "Setting the 'Access-Control-Allow-Origin' header to #allowedOrigin# for the cached event." ); + cachedEvent.responseHeaders[ "Access-Control-Allow-Origin" ] = allowedOrigin; log.debug( "Setting the 'Access-Control-Allow-Credentials' header to #toString( settings.allowCredentials )# for the cached event." ); cachedEvent.responseHeaders[ "Access-Control-Allow-Credentials" ] = toString( settings.allowCredentials ); @@ -68,8 +62,8 @@ component { templateCache.clear( cacheKey ); } - log.debug( "Setting the 'Access-Control-Allow-Origin' header to #allowedOrigins#." ); - event.setHTTPHeader( name = "Access-Control-Allow-Origin", value = allowedOrigins ); + log.debug( "Setting the 'Access-Control-Allow-Origin' header to #allowedOrigin#." ); + event.setHTTPHeader( name = "Access-Control-Allow-Origin", value = allowedOrigin ); log.debug( "Setting the 'Access-Control-Allow-Credentials' header to #toString( settings.allowCredentials )#." ); event.setHTTPHeader( name = "Access-Control-Allow-Credentials", value = toString( settings.allowCredentials ) ); diff --git a/tests/resources/app/config/Coldbox.cfc b/tests/resources/app/config/Coldbox.cfc index eef33ac..66b7409 100644 --- a/tests/resources/app/config/Coldbox.cfc +++ b/tests/resources/app/config/Coldbox.cfc @@ -109,6 +109,14 @@ }; break; + case "multiple_origin_string": + moduleSettings = { + "cors" = { + "allowOrigins" = "example.net,example.com" + } + }; + break; + case "allow_methods_array": moduleSettings = { "cors" = { diff --git a/tests/specs/integration/CORSSpec.cfc b/tests/specs/integration/CORSSpec.cfc index ac8ae1c..1a5304d 100644 --- a/tests/specs/integration/CORSSpec.cfc +++ b/tests/specs/integration/CORSSpec.cfc @@ -120,6 +120,42 @@ component extends="tests.resources.ModuleIntegrationSpec" appMapping="/app" { expect( responseHeadersTwo ).notToHaveKey( "Access-Control-Allow-Origin" ); } ); + it( "can configure for multiple allowed origins", function() { + hyper.get( "/", { + "fwreinit": "true", + // testcase configures the module as needed for the test + "testcase": "multiple_origin_string" + } ); + + var resOne = hyper.setMethod( "OPTIONS" ) + .withHeaders( { + "Origin": "example.com", + "Access-Control-Request-Method": "GET", + "Access-Control-Request-Headers": "Content-Type, X-Auth-Token, Origin, Authorization" + } ) + .setUrl( "/" ) + .send(); + + var responseHeadersOne = resOne.getHeaders(); + + expect( responseHeadersOne ).toHaveKey( "Access-Control-Allow-Origin" ); + expect( responseHeadersOne[ "Access-Control-Allow-Origin" ] ).toBe( "example.com" ); + + var resTwo = hyper.setMethod( "OPTIONS" ) + .withHeaders( { + "Origin": "exampleTwo.com", + "Access-Control-Request-Method": "GET", + "Access-Control-Request-Headers": "Content-Type, X-Auth-Token, Origin, Authorization" + } ) + .setUrl( "/" ) + .send(); + + var responseHeadersTwo = resTwo.getHeaders(); + + expect( resTwo.getStatusCode() ).toBe( 403 ); + expect( responseHeadersTwo ).notToHaveKey( "Access-Control-Allow-Origin" ); + } ); + it( "can accept a function for the allowed origins", function() { hyper.get( "/?fwreinit=true" );