Merge pull request #3692 from serverless/fix-cors-origin-config

Fix CORS origin config
This commit is contained in:
Eslam λ Hefnawy 2017-06-06 18:49:19 +07:00 committed by GitHub
commit 050f968fc7
8 changed files with 68 additions and 14 deletions

View File

@ -115,8 +115,7 @@ functions:
path: hello
method: get
cors:
origins:
- '*'
origin: '*'
headers:
- Content-Type
- X-Amz-Date

View File

@ -12,8 +12,14 @@ module.exports = {
const corsMethodLogicalId = this.provider.naming
.getMethodLogicalId(resourceName, 'options');
// TODO remove once "origins" config is deprecated
let origin = config.origin;
if (config.origins && config.origins.length) {
origin = config.origins.join(',');
}
const preflightHeaders = {
'Access-Control-Allow-Origin': `'${config.origins.join(',')}'`,
'Access-Control-Allow-Origin': `'${origin}'`,
'Access-Control-Allow-Headers': `'${config.headers.join(',')}'`,
'Access-Control-Allow-Methods': `'${config.methods.join(',')}'`,
'Access-Control-Allow-Credentials': `'${config.allowCredentials}'`,

View File

@ -54,13 +54,13 @@ describe('#compileCors()', () => {
it('should create preflight method for CORS enabled resource', () => {
awsCompileApigEvents.validated.corsPreflight = {
'users/update': {
origins: ['*'],
origin: 'http://example.com',
headers: ['*'],
methods: ['OPTIONS', 'PUT'],
allowCredentials: false,
},
'users/create': {
origins: ['*'],
origins: ['*', 'http://example.com'],
headers: ['*'],
methods: ['OPTIONS', 'POST'],
allowCredentials: true,
@ -72,19 +72,20 @@ describe('#compileCors()', () => {
allowCredentials: false,
},
'users/any': {
origins: ['*'],
origins: ['http://example.com'],
headers: ['*'],
methods: ['OPTIONS', 'ANY'],
allowCredentials: false,
},
};
return awsCompileApigEvents.compileCors().then(() => {
// users/create
expect(
awsCompileApigEvents.serverless.service.provider.compiledCloudFormationTemplate
.Resources.ApiGatewayMethodUsersCreateOptions
.Properties.Integration.IntegrationResponses[0]
.ResponseParameters['method.response.header.Access-Control-Allow-Origin']
).to.equal('\'*\'');
).to.equal('\'*,http://example.com\'');
expect(
awsCompileApigEvents.serverless.service.provider.compiledCloudFormationTemplate
@ -107,12 +108,13 @@ describe('#compileCors()', () => {
.ResponseParameters['method.response.header.Access-Control-Allow-Credentials']
).to.equal('\'true\'');
// users/update
expect(
awsCompileApigEvents.serverless.service.provider.compiledCloudFormationTemplate
.Resources.ApiGatewayMethodUsersUpdateOptions
.Properties.Integration.IntegrationResponses[0]
.ResponseParameters['method.response.header.Access-Control-Allow-Origin']
).to.equal('\'*\'');
).to.equal('\'http://example.com\'');
expect(
awsCompileApigEvents.serverless.service.provider.compiledCloudFormationTemplate
@ -128,6 +130,7 @@ describe('#compileCors()', () => {
.ResponseParameters['method.response.header.Access-Control-Allow-Credentials']
).to.equal('\'false\'');
// users/delete
expect(
awsCompileApigEvents.serverless.service.provider.compiledCloudFormationTemplate
.Resources.ApiGatewayMethodUsersDeleteOptions
@ -156,12 +159,13 @@ describe('#compileCors()', () => {
.ResponseParameters['method.response.header.Access-Control-Allow-Credentials']
).to.equal('\'false\'');
// users/any
expect(
awsCompileApigEvents.serverless.service.provider.compiledCloudFormationTemplate
.Resources.ApiGatewayMethodUsersAnyOptions
.Properties.Integration.IntegrationResponses[0]
.ResponseParameters['method.response.header.Access-Control-Allow-Origin']
).to.equal('\'*\'');
).to.equal('\'http://example.com\'');
expect(
awsCompileApigEvents.serverless.service.provider.compiledCloudFormationTemplate

View File

@ -592,7 +592,7 @@ describe('#compileMethods()', () => {
method: 'post',
integration: 'AWS',
cors: {
origins: ['*'],
origin: 'http://example.com',
},
response: {
statusCodes: {
@ -638,13 +638,12 @@ describe('#compileMethods()', () => {
},
];
return awsCompileApigEvents.compileMethods().then(() => {
// Check origin.
expect(
awsCompileApigEvents.serverless.service.provider.compiledCloudFormationTemplate
.Resources.ApiGatewayMethodUsersCreatePost.Properties
.Integration.IntegrationResponses[0]
.ResponseParameters['method.response.header.Access-Control-Allow-Origin']
).to.equal('\'*\'');
).to.equal('\'http://example.com\'');
// CORS not enabled!
expect(

View File

@ -102,8 +102,14 @@ module.exports = {
const integrationResponseHeaders = [];
if (http.cors) {
// TODO remove once "origins" config is deprecated
let origin = http.cors.origin;
if (http.cors.origins && http.cors.origins.length) {
origin = http.cors.origins.join(',');
}
_.merge(integrationResponseHeaders, {
'Access-Control-Allow-Origin': `'${http.cors.origins.join(',')}'`,
'Access-Control-Allow-Origin': `'${origin}'`,
});
}

View File

@ -12,8 +12,14 @@ module.exports = {
const methodResponseHeaders = [];
if (http.cors) {
// TODO remove once "origins" config is deprecated
let origin = http.cors.origin;
if (http.cors.origins && http.cors.origins.length) {
origin = http.cors.origins.join(',');
}
_.merge(methodResponseHeaders, {
'Access-Control-Allow-Origin': `'${http.cors.origins.join(',')}'`,
'Access-Control-Allow-Origin': `'${origin}'`,
});
}

View File

@ -58,6 +58,7 @@ module.exports = {
cors.headers = _.union(http.cors.headers, cors.headers);
cors.methods = _.union(http.cors.methods, cors.methods);
cors.origins = _.union(http.cors.origins, cors.origins);
cors.origin = http.cors.origin || '*';
cors.allowCredentials = cors.allowCredentials || http.cors.allowCredentials;
corsPreflight[http.path] = cors;
@ -274,6 +275,7 @@ module.exports = {
let cors = {
origins: ['*'],
origin: '*',
methods: ['OPTIONS'],
headers,
allowCredentials: false,
@ -284,6 +286,15 @@ module.exports = {
cors.methods = cors.methods || [];
cors.allowCredentials = Boolean(cors.allowCredentials);
if (cors.origins && cors.origin) {
const errorMessage = [
'You can only use "origin" or "origins",',
' but not both at the same time to configure CORS.',
' Please check the docs for more info.',
].join('');
throw new this.serverless.classes.Error(errorMessage);
}
if (cors.headers) {
if (!Array.isArray(cors.headers)) {
const errorMessage = [

View File

@ -415,6 +415,28 @@ describe('#validate()', () => {
expect(authorizer.identityValidationExpression).to.equal('foo');
});
it('should throw an error if "origin" and "origins" CORS config is used', () => {
awsCompileApigEvents.serverless.service.functions = {
first: {
events: [
{
http: {
method: 'POST',
path: '/foo/bar',
cors: {
origin: '*',
origins: ['*'],
},
},
},
],
},
};
expect(() => awsCompileApigEvents.validate())
.to.throw(Error, 'can only use');
});
it('should process cors defaults', () => {
awsCompileApigEvents.serverless.service.functions = {
first: {
@ -436,6 +458,7 @@ describe('#validate()', () => {
headers: ['Content-Type', 'X-Amz-Date', 'Authorization', 'X-Api-Key',
'X-Amz-Security-Token', 'X-Amz-User-Agent'],
methods: ['OPTIONS', 'POST'],
origin: '*',
origins: ['*'],
allowCredentials: false,
});