diff --git a/docs/providers/aws/events/apigateway.md b/docs/providers/aws/events/apigateway.md index 3ee601d32..ff6646b56 100644 --- a/docs/providers/aws/events/apigateway.md +++ b/docs/providers/aws/events/apigateway.md @@ -206,6 +206,26 @@ functions: arn: arn:aws:cognito-idp:us-east-1:xxx:userpool/us-east-1_ZZZ ``` +By default the `sub` claim will be exposed in `events.cognitoPoolClaims`, you can add extra claims like so: + +```yml +functions: + create: + handler: posts.create + events: + - http: + path: posts/create + method: post + integration: lambda + authorizer: + arn: arn:aws:cognito-idp:us-east-1:xxx:userpool/us-east-1_ZZZ + claims: + - email + - nickname +``` + +You must use `integration: lambda` to have any claims exposed. + ### Catching Exceptions In Your Lambda Function In case an exception is thrown in your lambda function AWS will send an error message with `Process exited before completing request`. This will be caught by the regular expression for the 500 HTTP status and the 500 status will be returned. diff --git a/lib/plugins/aws/deploy/compile/events/apiGateway/lib/authorizers.js b/lib/plugins/aws/deploy/compile/events/apiGateway/lib/authorizers.js index c7247e857..96d0cf06e 100644 --- a/lib/plugins/aws/deploy/compile/events/apiGateway/lib/authorizers.js +++ b/lib/plugins/aws/deploy/compile/events/apiGateway/lib/authorizers.js @@ -28,15 +28,15 @@ module.exports = { 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:aws:apigateway:', + { Ref: 'AWS::Region' }, + ':lambda:path/2015-03-31/functions/', + authorizer.arn, + '/invocations', + ], + ] }; authorizerProperties.Type = 'TOKEN'; } diff --git a/lib/plugins/aws/deploy/compile/events/apiGateway/lib/method/index.js b/lib/plugins/aws/deploy/compile/events/apiGateway/lib/method/index.js index 9353e14ac..aa5cbe4bd 100644 --- a/lib/plugins/aws/deploy/compile/events/apiGateway/lib/method/index.js +++ b/lib/plugins/aws/deploy/compile/events/apiGateway/lib/method/index.js @@ -28,7 +28,6 @@ module.exports = { template.Properties.ApiKeyRequired = true; } - const methodLogicalId = this.provider.naming .getMethodLogicalId(resourceName, event.http.method); const lambdaLogicalId = this.provider.naming @@ -43,6 +42,19 @@ module.exports = { this.getMethodResponses(event.http) ); + let extraCognitoPoolClaims; + if (event.http.authorizer) { + const claims = event.http.authorizer.claims || []; + extraCognitoPoolClaims = _.map(claims, claim => + `"${claim}": "$context.authorizer.claims.${claim}",` + ); + } + const requestTemplates = template.Properties.Integration.RequestTemplates; + _.forEach(requestTemplates, (value, key) => { + requestTemplates[key] = + value.replace('extraCognitoPoolClaims', extraCognitoPoolClaims || ''); + }); + this.apiGatewayMethodLogicalIds.push(methodLogicalId); _.merge(this.serverless.service.provider.compiledCloudFormationTemplate.Resources, { diff --git a/lib/plugins/aws/deploy/compile/events/apiGateway/lib/method/index.test.js b/lib/plugins/aws/deploy/compile/events/apiGateway/lib/method/index.test.js index e98ba077e..95e063087 100644 --- a/lib/plugins/aws/deploy/compile/events/apiGateway/lib/method/index.test.js +++ b/lib/plugins/aws/deploy/compile/events/apiGateway/lib/method/index.test.js @@ -192,6 +192,63 @@ describe('#compileMethods()', () => { awsCompileApigEvents.serverless.service.provider.compiledCloudFormationTemplate .Resources.ApiGatewayMethodUsersCreatePost.Properties.AuthorizerId.Ref ).to.equal('AuthorizerApiGatewayAuthorizer'); + + expect( + awsCompileApigEvents.serverless.service.provider.compiledCloudFormationTemplate + .Resources.ApiGatewayMethodUsersCreatePost.Properties + .Integration.RequestTemplates['application/json'] + ).to.not.match(/undefined/); + }); + }); + + it('should set claims for a cognito user pool', () => { + awsCompileApigEvents.validated.events = [ + { + functionName: 'First', + http: { + authorizer: { + name: 'authorizer', + arn: 'arn:aws:cognito-idp:us-east-1:xxx:userpool/us-east-1_ZZZ', + claims: ['email'], + }, + integration: 'AWS', + path: 'users/create', + method: 'post', + }, + }, + ]; + + return awsCompileApigEvents.compileMethods().then(() => { + expect( + awsCompileApigEvents.serverless.service.provider.compiledCloudFormationTemplate + .Resources.ApiGatewayMethodUsersCreatePost.Properties + .Integration.RequestTemplates['application/json'] + ).to.match(/email/); + }); + }); + + it('should replace the extra claims in the template if there are none', () => { + awsCompileApigEvents.validated.events = [ + { + functionName: 'First', + http: { + authorizer: { + name: 'authorizer', + arn: 'arn:aws:cognito-idp:us-east-1:xxx:userpool/us-east-1_ZZZ', + }, + integration: 'AWS', + path: 'users/create', + method: 'post', + }, + }, + ]; + + return awsCompileApigEvents.compileMethods().then(() => { + expect( + awsCompileApigEvents.serverless.service.provider.compiledCloudFormationTemplate + .Resources.ApiGatewayMethodUsersCreatePost.Properties + .Integration.RequestTemplates['application/json'] + ).to.not.match(/extraCognitoPoolClaims/); }); }); diff --git a/lib/plugins/aws/deploy/compile/events/apiGateway/lib/method/integration.js b/lib/plugins/aws/deploy/compile/events/apiGateway/lib/method/integration.js index 90a15b602..da6deff7b 100644 --- a/lib/plugins/aws/deploy/compile/events/apiGateway/lib/method/integration.js +++ b/lib/plugins/aws/deploy/compile/events/apiGateway/lib/method/integration.js @@ -120,6 +120,11 @@ module.exports = { "principalId": "$context.authorizer.principalId", "stage": "$context.stage", + "cognitoPoolClaims" : { + extraCognitoPoolClaims + "sub": "$context.authorizer.claims.sub" + }, + #set( $map = $input.params().header ) "headers": $loop, @@ -172,6 +177,11 @@ module.exports = { "principalId": "$context.authorizer.principalId", "stage": "$context.stage", + "cognitoPoolClaims" : { + extraCognitoPoolClaims + "sub": "$context.authorizer.claims.sub" + }, + #set( $map = $input.params().header ) "headers": $loop, diff --git a/lib/plugins/aws/deploy/compile/events/apiGateway/lib/validate.js b/lib/plugins/aws/deploy/compile/events/apiGateway/lib/validate.js index 033bdce14..66d2e4738 100644 --- a/lib/plugins/aws/deploy/compile/events/apiGateway/lib/validate.js +++ b/lib/plugins/aws/deploy/compile/events/apiGateway/lib/validate.js @@ -188,6 +188,7 @@ module.exports = { let identitySource; let resultTtlInSeconds; let identityValidationExpression; + let claims; if (typeof authorizer === 'string') { if (authorizer.indexOf(':') === -1) { @@ -210,6 +211,7 @@ module.exports = { resultTtlInSeconds = Number.parseInt(authorizer.resultTtlInSeconds, 10); resultTtlInSeconds = Number.isNaN(resultTtlInSeconds) ? 300 : resultTtlInSeconds; + claims = authorizer.claims || []; identitySource = authorizer.identitySource; identityValidationExpression = authorizer.identityValidationExpression; @@ -233,6 +235,7 @@ module.exports = { resultTtlInSeconds, identitySource, identityValidationExpression, + claims, }; },