Skip to content

Commit

Permalink
feat(cors): Dynamically determine allowed headers
Browse files Browse the repository at this point in the history
  • Loading branch information
elpete committed Aug 8, 2019
1 parent 1e33450 commit 25a98ba
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 13 deletions.
4 changes: 3 additions & 1 deletion ModuleConfig.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ component {
allowMethods = function( event ) {
return event.getHTTPMethod();
},
allowHeaders = [ "Content-Type", "X-Auth-Token", "Origin", "Authorization" ],
allowHeaders = function( event ) {
return event.getHTTPHeader( "Access-Control-Request-Headers", "" );
},
maxAge = 60 * 60 * 24, // 1 day
allowCredentials = true,
eventPattern = ".*"
Expand Down
14 changes: 9 additions & 5 deletions interceptors/CORS.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,18 @@ component {
log.debug( "Setting the 'Access-Control-Allow-Credentials' header to #toString( settings.allowCredentials )#." );
event.setHTTPHeader( name = "Access-Control-Allow-Credentials", value = toString( settings.allowCredentials ) );

var allowedHeaders = "";
if ( isSimpleValue( settings.allowHeaders ) ) {
allowedHeaders = settings.allowHeaders == "*" ?
var allowedHeaders = settings.allowHeaders;
if ( isClosure( allowedHeaders ) || isCustomFunction( allowedHeaders ) ) {
allowedHeaders = allowedHeaders( event );
}
if ( isSimpleValue( allowedHeaders ) ) {
// TODO: This is needed for legacy reasons. We can remove it in the next breaking change
allowedHeaders = allowedHeaders == "*" ?
event.getHTTPHeader( "Access-Control-Request-Headers", "" ) :
settings.allowHeaders;
allowedHeaders;
}
else {
allowedHeaders = arrayToList( settings.allowHeaders, ", " );
allowedHeaders = arrayToList( allowedHeaders, ", " );
}

log.debug( "Setting the 'Access-Control-Allow-Headers' header to #allowedHeaders#." );
Expand Down
66 changes: 59 additions & 7 deletions tests/specs/integration/CORSSpec.cfc
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ component extends="tests.resources.ModuleIntegrationSpec" appMapping="/app" {
aroundEach( function( spec ) {
var originalSettings = duplicate( getController().getConfigSettings().modules.cors.settings );
setup();
prepareMock( getRequestContext() )
.$( "getHTTPHeader" )
.$args( "Access-Control-Request-Headers", "" )
.$results( "Content-Type, X-Auth-Token, Origin, Authorization" );
spec.body();
getController().getConfigSettings().modules.cors.settings = originalSettings;
} );
Expand Down Expand Up @@ -214,6 +218,30 @@ component extends="tests.resources.ModuleIntegrationSpec" appMapping="/app" {
expect( responseHeaders[ "Access-Control-Allow-Headers" ] ).toBe( "Content-Type" );
} );

it( "can configure the allowed headers with a closure", function() {
getController().getConfigSettings().modules.cors.settings.allowHeaders = function( event ) {
return event.getHTTPHeader( "Access-Control-Request-Headers", "" );
};

prepareMock( getRequestContext() )
.$( "getHTTPMethod", "OPTIONS" )
.$( "getHTTPHeader" )
.$args( "Origin", "" )
.$results( "example.com" )
.$( "getHTTPHeader" )
.$args( "Origin", "*" )
.$results( "example.com" )
.$( "getHTTPHeader" )
.$args( "Access-Control-Request-Headers", "" )
.$results( "Content-Type" );
var event = execute( route = "/", renderResults = true );

var responseHeaders = getHeaders( event );

expect( responseHeaders ).toHaveKey( "Access-Control-Allow-Headers" );
expect( responseHeaders[ "Access-Control-Allow-Headers" ] ).toBe( "Content-Type" );
} );

it( "can configure if credentials are allowed", function() {
getController().getConfigSettings().modules.cors.settings.allowCredentials = false;

Expand Down Expand Up @@ -284,7 +312,10 @@ component extends="tests.resources.ModuleIntegrationSpec" appMapping="/app" {
.$results( "example.com" )
.$( "getHTTPHeader" )
.$args( "Origin", "*" )
.$results( "example.com" );
.$results( "example.com" )
.$( "getHTTPHeader" )
.$args( "Access-Control-Request-Headers", "" )
.$results( "Content-Type, X-Auth-Token, Origin, Authorization" );
var event = execute( event = "Main.index", renderResults = true );
var responseHeaders = getHeaders( event );
expect( responseHeaders ).notToHaveKey( "Access-Control-Allow-Origin" );
Expand All @@ -298,7 +329,10 @@ component extends="tests.resources.ModuleIntegrationSpec" appMapping="/app" {
.$results( "example.com" )
.$( "getHTTPHeader" )
.$args( "Origin", "*" )
.$results( "example.com" );
.$results( "example.com" )
.$( "getHTTPHeader" )
.$args( "Access-Control-Request-Headers", "" )
.$results( "Content-Type, X-Auth-Token, Origin, Authorization" );
var event = execute( event = "Main.doSomething", renderResults = true );
var responseHeaders = getHeaders( event );
expect( responseHeaders ).toHaveKey( "Access-Control-Allow-Origin" );
Expand All @@ -313,7 +347,10 @@ component extends="tests.resources.ModuleIntegrationSpec" appMapping="/app" {
.$results( "example.com" )
.$( "getHTTPHeader" )
.$args( "Origin", "*" )
.$results( "example.com" );
.$results( "example.com" )
.$( "getHTTPHeader" )
.$args( "Access-Control-Request-Headers", "" )
.$results( "Content-Type, X-Auth-Token, Origin, Authorization" );
var event = execute( event = "Main.doSomethingElse", renderResults = true );
var responseHeaders = getHeaders( event );
expect( responseHeaders ).notToHaveKey( "Access-Control-Allow-Origin" );
Expand All @@ -332,7 +369,10 @@ component extends="tests.resources.ModuleIntegrationSpec" appMapping="/app" {
.$results( "example.com" )
.$( "getHTTPHeader" )
.$args( "Origin", "*" )
.$results( "example.com" );
.$results( "example.com" )
.$( "getHTTPHeader" )
.$args( "Access-Control-Request-Headers", "" )
.$results( "Content-Type, X-Auth-Token, Origin, Authorization" );
var event = execute( event = "Main.index", renderResults = true );
var responseHeaders = getHeaders( event );
expect( responseHeaders ).notToHaveKey( "Access-Control-Allow-Origin" );
Expand All @@ -346,7 +386,10 @@ component extends="tests.resources.ModuleIntegrationSpec" appMapping="/app" {
.$results( "example.com" )
.$( "getHTTPHeader" )
.$args( "Origin", "*" )
.$results( "example.com" );
.$results( "example.com" )
.$( "getHTTPHeader" )
.$args( "Access-Control-Request-Headers", "" )
.$results( "Content-Type, X-Auth-Token, Origin, Authorization" );
var event = execute( event = "Main.doSomething", renderResults = true );
var responseHeaders = getHeaders( event );
expect( responseHeaders ).toHaveKey( "Access-Control-Allow-Origin" );
Expand All @@ -361,7 +404,10 @@ component extends="tests.resources.ModuleIntegrationSpec" appMapping="/app" {
.$results( "example.com" )
.$( "getHTTPHeader" )
.$args( "Origin", "*" )
.$results( "example.com" );
.$results( "example.com" )
.$( "getHTTPHeader" )
.$args( "Access-Control-Request-Headers", "" )
.$results( "Content-Type, X-Auth-Token, Origin, Authorization" );
var event = execute( event = "Main.doSomethingElse", renderResults = true );
var responseHeaders = getHeaders( event );
expect( responseHeaders ).toHaveKey( "Access-Control-Allow-Origin" );
Expand All @@ -378,7 +424,10 @@ component extends="tests.resources.ModuleIntegrationSpec" appMapping="/app" {
.$( "getHTTPHeader" )
.$args( "Origin", "*" )
.$results( "example.com" )
.$( "getEventCacheableKey", {} );
.$( "getEventCacheableKey", {} )
.$( "getHTTPHeader" )
.$args( "Access-Control-Request-Headers", "" )
.$results( "Content-Type, X-Auth-Token, Origin, Authorization" );
var eventOne = execute( event = "Main.cached", renderResults = true );
var responseHeadersOne = getHeaders( eventOne );
expect( responseHeadersOne ).toHaveKey( "Access-Control-Allow-Origin" );
Expand All @@ -392,6 +441,9 @@ component extends="tests.resources.ModuleIntegrationSpec" appMapping="/app" {
.$( "getHTTPHeader" )
.$args( "Origin", "*" )
.$results( "example.com" )
.$( "getHTTPHeader" )
.$args( "Access-Control-Request-Headers", "" )
.$results( "Content-Type, X-Auth-Token, Origin, Authorization" )
.$( "getEventCacheableKey", {
"provider": "template",
"cacheable": true,
Expand Down

0 comments on commit 25a98ba

Please sign in to comment.