Skip to content

Commit

Permalink
Merge pr 4665
Browse files Browse the repository at this point in the history
  • Loading branch information
cncolder committed Feb 27, 2018
2 parents f1f2988 + 5477eb2 commit 24e90b7
Show file tree
Hide file tree
Showing 34 changed files with 432 additions and 274 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ node_modules

# IDE stuff
**/.idea
**/.vs

# OS stuff
.DS_Store
Expand All @@ -55,4 +56,4 @@ jest

# DotNet
[Bb]in/
[Oo]bj/
[Oo]bj/
32 changes: 17 additions & 15 deletions lib/classes/Utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const isDockerContainer = require('is-docker');
const version = require('../../package.json').version;
const segment = require('../utils/segment');
const configUtils = require('../utils/config');
const awsArnRegExs = require('../plugins/aws/utils/arnRegularExpressions');

class Utils {
constructor(serverless) {
Expand Down Expand Up @@ -204,11 +205,11 @@ class Utils {
}

// For HTTP events, see what authorizer types are enabled
if (event.http && event.http.authorizer) {
if ((typeof event.http.authorizer === 'string'
&& event.http.authorizer.toUpperCase() === 'AWS_IAM')
|| (event.http.authorizer.type
&& event.http.authorizer.type.toUpperCase() === 'AWS_IAM')) {
if (_.has(event, 'http.authorizer')) {
if ((_.isString(event.http.authorizer)
&& _.toUpper(event.http.authorizer) === 'AWS_IAM')
|| (event.http.authorizer.type
&& _.toUpper(event.http.authorizer.type) === 'AWS_IAM')) {
hasIAMAuthorizer = true;
}
// There are three ways a user can specify a Custom authorizer:
Expand All @@ -217,18 +218,19 @@ class Utils {
// 2) By listing the name of a function in the same service for the name property
// in the authorizer object.
// 3) By listing a function's ARN in the arn property of the authorizer object.
if ((typeof event.http.authorizer === 'string'
&& event.http.authorizer.toUpperCase() !== 'AWS_IAM'
&& !event.http.authorizer.includes('arn:aws:cognito-idp'))
|| event.http.authorizer.name
|| (event.http.authorizer.arn
&& event.http.authorizer.arn.includes('arn:aws:lambda'))) {

if ((_.isString(event.http.authorizer)
&& _.toUpper(event.http.authorizer) !== 'AWS_IAM'
&& !awsArnRegExs.cognitoIdpArnExpr.test(event.http.authorizer))
|| event.http.authorizer.name
|| (event.http.authorizer.arn
&& awsArnRegExs.lambdaArnExpr.test(event.http.authorizer.arn))) {
hasCustomAuthorizer = true;
}
if ((typeof event.http.authorizer === 'string'
&& event.http.authorizer.includes('arn:aws:cognito-idp'))
|| (event.http.authorizer.arn
&& event.http.authorizer.arn.includes('arn:aws:cognito-idp'))) {
if ((_.isString(event.http.authorizer)
&& awsArnRegExs.cognitoIdpArnExpr.test(event.http.authorizer))
|| (event.http.authorizer.arn
&& awsArnRegExs.cognitoIdpArnExpr.test(event.http.authorizer.arn))) {
hasCognitoAuthorizer = true;
}
}
Expand Down
5 changes: 3 additions & 2 deletions lib/plugins/aws/deploy/lib/validateTemplate.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
'use strict';
const getS3EndpointForRegion = require('../../utils/getS3EndpointForRegion');

module.exports = {
validateTemplate() {
const bucketName = this.bucketName;
const artifactDirectoryName = this.serverless.service.package.artifactDirectoryName;
const compiledTemplateFileName = 'compiled-cloudformation-template.json';

const s3Endpoint = getS3EndpointForRegion(this.provider.getRegion());
this.serverless.cli.log('Validating template...');
const params = {
TemplateURL: `https://s3.amazonaws.com/${bucketName}/${artifactDirectoryName}/${compiledTemplateFileName}`,
TemplateURL: `https://${s3Endpoint}/${bucketName}/${artifactDirectoryName}/${compiledTemplateFileName}`,
};

return this.provider.request(
Expand Down
30 changes: 15 additions & 15 deletions lib/plugins/aws/deployFunction/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,19 +57,19 @@ class AwsDeployFunction {
'getFunction',
params
)
.then((result) => {
this.serverless.service.provider.remoteFunctionData = result;
return result;
})
.catch(() => {
const errorMessage = [
`The function "${this.options.function}" you want to update is not yet deployed.`,
' Please run "serverless deploy" to deploy your service.',
' After that you can redeploy your services functions with the',
' "serverless deploy function" command.',
].join('');
throw new this.serverless.classes.Error(errorMessage);
});
.then((result) => {
this.serverless.service.provider.remoteFunctionData = result;
return result;
})
.catch(() => {
const errorMessage = [
`The function "${this.options.function}" you want to update is not yet deployed.`,
' Please run "serverless deploy" to deploy your service.',
' After that you can redeploy your services functions with the',
' "serverless deploy function" command.',
].join('');
throw new this.serverless.classes.Error(errorMessage);
});
}

normalizeArnRole(role) {
Expand All @@ -84,8 +84,8 @@ class AwsDeployFunction {
const roleProperties = roleResource.Properties;
const compiledFullRoleName = `${roleProperties.Path || '/'}${roleProperties.RoleName}`;

return this.provider.getAccountId().then((accountId) =>
`arn:aws:iam::${accountId}:role${compiledFullRoleName}`
return this.provider.getAccountInfo().then((result) =>
`arn:${result.partition}:iam::${result.accountId}:role${compiledFullRoleName}`
);
}

Expand Down
20 changes: 10 additions & 10 deletions lib/plugins/aws/deployFunction/index.test.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
'use strict';

/* eslint-disable no-unused-expressions */
const chai = require('chai');
const sinon = require('sinon');
const path = require('path');
Expand Down Expand Up @@ -120,13 +120,13 @@ describe('AwsDeployFunction', () => {
});

describe('#normalizeArnRole', () => {
let getAccountIdStub;
let getAccountInfoStub;
let getRoleStub;

beforeEach(() => {
getAccountIdStub = sinon
.stub(awsDeployFunction.provider, 'getAccountId')
.resolves('123456789012');
getAccountInfoStub = sinon
.stub(awsDeployFunction.provider, 'getAccountInfo')
.resolves({ accountId: '123456789012', partition: 'aws' });
getRoleStub = sinon
.stub(awsDeployFunction.provider, 'request')
.resolves({ Arn: 'arn:aws:iam::123456789012:role/role_2' });
Expand All @@ -144,7 +144,7 @@ describe('AwsDeployFunction', () => {
});

afterEach(() => {
awsDeployFunction.provider.getAccountId.restore();
awsDeployFunction.provider.getAccountInfo.restore();
awsDeployFunction.provider.request.restore();
serverless.service.resources = undefined;
});
Expand All @@ -153,7 +153,7 @@ describe('AwsDeployFunction', () => {
const arn = 'arn:aws:iam::123456789012:role/role';

return awsDeployFunction.normalizeArnRole(arn).then((result) => {
expect(getAccountIdStub.calledOnce).to.be.equal(false);
expect(getAccountInfoStub).to.not.have.been.called;
expect(result).to.be.equal(arn);
});
});
Expand All @@ -162,7 +162,7 @@ describe('AwsDeployFunction', () => {
const roleName = 'MyCustomRole';

return awsDeployFunction.normalizeArnRole(roleName).then((result) => {
expect(getAccountIdStub.calledOnce).to.be.equal(true);
expect(getAccountInfoStub).to.have.been.called;
expect(result).to.be.equal('arn:aws:iam::123456789012:role/role_123');
});
});
Expand All @@ -177,7 +177,7 @@ describe('AwsDeployFunction', () => {

return awsDeployFunction.normalizeArnRole(roleObj).then((result) => {
expect(getRoleStub.calledOnce).to.be.equal(true);
expect(getAccountIdStub.calledOnce).to.be.equal(false);
expect(getAccountInfoStub).to.not.have.been.called;
expect(result).to.be.equal('arn:aws:iam::123456789012:role/role_2');
});
});
Expand Down Expand Up @@ -336,7 +336,7 @@ describe('AwsDeployFunction', () => {
awsDeployFunction.options = options;

return expect(awsDeployFunction.updateFunctionConfiguration()).to.be.fulfilled
.then(() => expect(updateFunctionConfigurationStub).to.not.be.called);
.then(() => expect(updateFunctionConfigurationStub).to.not.be.called);
});

it('should fail when using invalid characters in environment variable', () => {
Expand Down
9 changes: 6 additions & 3 deletions lib/plugins/aws/lib/updateStack.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

const _ = require('lodash');
const BbPromise = require('bluebird');
const getS3EndpointForRegion = require('../utils/getS3EndpointForRegion');

const NO_UPDATE_MESSAGE = 'No updates are to be performed.';

Expand All @@ -13,7 +14,8 @@ module.exports = {
const stackName = this.provider.naming.getStackName();
let stackTags = { STAGE: this.provider.getStage() };
const compiledTemplateFileName = 'compiled-cloudformation-template.json';
const templateUrl = `https://s3.amazonaws.com/${this.bucketName}/${this.serverless.service.package.artifactDirectoryName}/${compiledTemplateFileName}`;
const s3Endpoint = getS3EndpointForRegion(this.provider.getRegion());
const templateUrl = `https://${s3Endpoint}/${this.bucketName}/${this.serverless.service.package.artifactDirectoryName}/${compiledTemplateFileName}`;

// Merge additional stack tags
if (typeof this.serverless.service.provider.stackTags === 'object') {
Expand Down Expand Up @@ -44,7 +46,8 @@ module.exports = {

update() {
const compiledTemplateFileName = 'compiled-cloudformation-template.json';
const templateUrl = `https://s3.amazonaws.com/${this.bucketName}/${this.serverless.service.package.artifactDirectoryName}/${compiledTemplateFileName}`;
const s3Endpoint = getS3EndpointForRegion(this.provider.getRegion());
const templateUrl = `https://${s3Endpoint}/${this.bucketName}/${this.serverless.service.package.artifactDirectoryName}/${compiledTemplateFileName}`;

this.serverless.cli.log('Updating Stack...');
const stackName = this.provider.naming.getStackName();
Expand Down Expand Up @@ -72,7 +75,7 @@ module.exports = {

// Policy must have at least one statement, otherwise no updates would be possible at all
if (this.serverless.service.provider.stackPolicy &&
this.serverless.service.provider.stackPolicy.length) {
!_.isEmpty(this.serverless.service.provider.stackPolicy)) {
params.StackPolicyBody = JSON.stringify({
Statement: this.serverless.service.provider.stackPolicy,
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

const BbPromise = require('bluebird');
const _ = require('lodash');
const awsArnRegExs = require('../../../../../utils/arnRegularExpressions');

module.exports = {
compileAuthorizers() {
Expand All @@ -23,20 +24,25 @@ module.exports = {

const authorizerLogicalId = this.provider.naming.getAuthorizerLogicalId(authorizer.name);

if (typeof authorizer.arn === 'string' && authorizer.arn.match(/^arn:aws:cognito-idp/)) {
if (typeof authorizer.arn === 'string'
&& awsArnRegExs.cognitoIdpArnExpr.test(authorizer.arn)) {
authorizerProperties.Type = 'COGNITO_USER_POOLS';
authorizerProperties.ProviderARNs = [authorizer.arn];
} else {
authorizerProperties.AuthorizerUri =
{ 'Fn::Join': ['',
[
'arn:aws:apigateway:',
{ Ref: 'AWS::Region' },
':lambda:path/2015-03-31/functions/',
authorizer.arn,
'/invocations',
{
'Fn::Join': ['',
[
'arn:',
{ Ref: 'AWS::Partition' },
':apigateway:',
{ Ref: 'AWS::Region' },
':lambda:path/2015-03-31/functions/',
authorizer.arn,
'/invocations',
],
],
] };
};
authorizerProperties.Type = authorizer.type ? authorizer.type.toUpperCase() : 'TOKEN';
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,18 @@ describe('#compileAuthorizers()', () => {

expect(resource.Type).to.equal('AWS::ApiGateway::Authorizer');
expect(resource.Properties.AuthorizerResultTtlInSeconds).to.equal(300);
expect(resource.Properties.AuthorizerUri).to.deep.equal({ 'Fn::Join': ['',
[
'arn:aws:apigateway:',
{ Ref: 'AWS::Region' },
':lambda:path/2015-03-31/functions/',
{ 'Fn::GetAtt': ['SomeLambdaFunction', 'Arn'] },
'/invocations',
expect(resource.Properties.AuthorizerUri).to.deep.equal({
'Fn::Join': ['',
[
'arn:',
{ Ref: 'AWS::Partition' },
':apigateway:',
{ Ref: 'AWS::Region' },
':lambda:path/2015-03-31/functions/',
{ 'Fn::GetAtt': ['SomeLambdaFunction', 'Arn'] },
'/invocations',
],
],
],
});
expect(resource.Properties.IdentitySource).to.equal('method.request.header.Authorization');
expect(resource.Properties.IdentityValidationExpression).to.equal(undefined);
Expand Down Expand Up @@ -77,15 +80,18 @@ describe('#compileAuthorizers()', () => {
.compiledCloudFormationTemplate.Resources.AuthorizerApiGatewayAuthorizer;

expect(resource.Type).to.equal('AWS::ApiGateway::Authorizer');
expect(resource.Properties.AuthorizerUri).to.deep.equal({ 'Fn::Join': ['',
[
'arn:aws:apigateway:',
{ Ref: 'AWS::Region' },
':lambda:path/2015-03-31/functions/',
'foo',
'/invocations',
expect(resource.Properties.AuthorizerUri).to.deep.equal({
'Fn::Join': ['',
[
'arn:',
{ Ref: 'AWS::Partition' },
':apigateway:',
{ Ref: 'AWS::Region' },
':lambda:path/2015-03-31/functions/',
'foo',
'/invocations',
],
],
],
});
expect(resource.Properties.AuthorizerResultTtlInSeconds).to.equal(500);
expect(resource.Properties.IdentitySource).to.equal('method.request.header.Custom');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,9 @@ module.exports = {
[
'https://',
this.provider.getApiGatewayRestApiId(),
`.execute-api.${
this.provider.getRegion()
}.amazonaws.com/${
this.provider.getStage()
}`,
`.execute-api.${this.provider.getRegion()}.`,
{ Ref: 'AWS::URLSuffix' },
`/${this.provider.getStage()}`,
],
],
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,9 @@ describe('#compileDeployment()', () => {
[
'https://',
{ Ref: awsCompileApigEvents.apiGatewayRestApiLogicalId },
'.execute-api.us-east-1.amazonaws.com/dev',
'.execute-api.us-east-1.',
{ Ref: 'AWS::URLSuffix' },
'/dev',
],
],
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
'use strict';

const _ = require('lodash');
const awsArnRegExs = require('../../../../../../utils/arnRegularExpressions');

module.exports = {
getMethodAuthorization(http) {
Expand All @@ -18,7 +19,8 @@ module.exports = {

let authorizationType;
const authorizerArn = http.authorizer.arn;
if (typeof authorizerArn === 'string' && authorizerArn.match(/^arn:aws:cognito-idp/)) {
if (typeof authorizerArn === 'string'
&& awsArnRegExs.cognitoIdpArnExpr.test(authorizerArn)) {
authorizationType = 'COGNITO_USER_POOLS';
} else {
authorizationType = 'CUSTOM';
Expand Down
Loading

0 comments on commit 24e90b7

Please sign in to comment.