Skip to content

Commit da8970b

Browse files
authored
Merge pull request #14 from erezrokah/feature/add_authentication_support
Feature: add support for adding authorization
2 parents 8148756 + 89f5c50 commit da8970b

File tree

9 files changed

+696
-13
lines changed

9 files changed

+696
-13
lines changed

.vscode/settings.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"editor.formatOnSave": true
3+
}

README.md

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,33 @@
22
[![Build Status](https://travis-ci.org/horike37/serverless-apigateway-service-proxy.svg?branch=master)](https://travis-ci.org/horike37/serverless-apigateway-service-proxy) [![npm version](https://badge.fury.io/js/serverless-apigateway-service-proxy.svg)](https://badge.fury.io/js/serverless-apigateway-service-proxy) [![Coverage Status](https://coveralls.io/repos/github/horike37/serverless-apigateway-service-proxy/badge.svg?branch=master)](https://coveralls.io/github/horike37/serverless-apigateway-service-proxy?branch=master) [![MIT License](http://img.shields.io/badge/license-MIT-blue.svg?style=flat)](LICENSE)
33

44
# Serverless APIGateway Service Proxy(BETA)
5+
56
This Serverless Framewrok plugin supports the AWS service proxy integration feature of API Gateway. You can directly connect API Gateway to AWS services without Lambda.
67

78
## Install
9+
810
Run `servelress plugin install` in your Serverless project.
911

10-
```
11-
$ serverless plugin install -n serverless-apigateway-service-proxy
12+
```bash
13+
serverless plugin install -n serverless-apigateway-service-proxy
1214
```
1315

1416
## Supported AWS services
17+
1518
Here is a services list which this plugin supports for now. But will expand to other services in the feature.
1619
Please pull request if you are intersted in it.
1720

1821
- Kinesis Streams
1922
- SQS
2023

2124
## How to use
25+
2226
Define settings of the AWS services you want to integrate under `custom > apiGatewayServiceProxies` and run `serverless deploy`.
2327

2428
### Kinesis
29+
2530
Sample syntax for Kinesis proxy in serverless.yml.
31+
2632
```yaml
2733
custom:
2834
apiGatewayServiceProxies:
@@ -41,34 +47,38 @@ resources:
4147
```
4248
4349
Sample request after deploying.
44-
```
50+
51+
```bash
4552
curl -XPOST https://xxxxxxx.execute-api.us-east-1.amazonaws.com/dev/kinesis -d '{"Data": "some data","PartitionKey": "some key"}' -H 'Content-Type:application/json'
4653
```
4754
4855
### SQS
4956
5057
Sample syntax for SQS proxy in serverless.yml.
58+
5159
```yaml
5260
custom:
5361
apiGatewayServiceProxies:
5462
- sqs:
5563
path: /sqs
5664
method: post
57-
queueName: {"Fn::GetAtt":[ "SQSQueue", "QueueName" ]}
65+
queueName: { 'Fn::GetAtt': ['SQSQueue', 'QueueName'] }
5866
cors: true
5967

6068
resources:
6169
Resources:
6270
SQSQueue:
63-
Type: "AWS::SQS::Queue"
71+
Type: 'AWS::SQS::Queue'
6472
```
6573
6674
Sample request after deploying.
67-
```
75+
76+
```bash
6877
curl -XPOST https://xxxxxx.execute-api.us-east-1.amazonaws.com/dev/sqs -d '{"message": "testtest"}' -H 'Content-Type:application/json'
6978
```
7079
7180
## Common API Gateway features
81+
7282
### Enabling CORS
7383
7484
To set CORS configurations for your HTTP endpoints, simply modify your event configurations as follows:
@@ -142,8 +152,40 @@ custom:
142152
allowCredentials: false
143153
cacheControl: 'max-age=600, s-maxage=600, proxy-revalidate' # Caches on browser and proxy for 10 minutes and doesnt allow proxy to serve out of date content
144154
```
155+
156+
### Adding Authorization
157+
158+
You can pass in any supported authorization type:
159+
160+
```yml
161+
custom:
162+
apiGatewayServiceProxies:
163+
- sqs:
164+
path: /sqs
165+
method: post
166+
queueName: { 'Fn::GetAtt': ['SQSQueue', 'QueueName'] }
167+
cors: true
168+
169+
# optional - defaults to 'NONE'
170+
authorizationType: 'AWS_IAM' # can be one of ['NONE', 'AWS_IAM', 'CUSTOM', 'COGNITO_USER_POOLS']
171+
172+
# when using 'CUSTOM' authorization type, one should specify authorizerId
173+
# authorizerId: { Ref: 'AuthorizerLogicalId' }
174+
# when using 'COGNITO_USER_POOLS' authorization type, one can specify a list of authorization scopes
175+
# authorizationScopes: ['scope1','scope2']
176+
177+
resources:
178+
Resources:
179+
SQSQueue:
180+
Type: 'AWS::SQS::Queue'
181+
```
182+
183+
Source: [AWS::ApiGateway::Method docs](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigateway-method.html#cfn-apigateway-method-authorizationtype)
184+
145185
## Specific features
186+
146187
### Kinesis
188+
147189
#### Customizing request body mapping templates
148190
149191
If you'd like to add content types or customize the default templates, you can do so by including your custom [API Gateway request mapping template](https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-mapping-template-reference.html) in `serverless.yml` like so:
@@ -170,4 +212,5 @@ custom:
170212
- MyStreamArn:
171213
Fn::GetAtt: [MyStream, Arn]
172214
```
215+
173216
Source: [How to connect SNS to Kinesis for cross-account delivery via API Gateway](https://theburningmonk.com/2019/07/how-to-connect-sns-to-kinesis-for-cross-account-delivery-via-api-gateway/)

lib/apiGateway/validate.js

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ module.exports = {
1414
const http = serviceProxy[serviceName]
1515
http.path = await this.getProxyPath(serviceProxy[serviceName], serviceName)
1616
http.method = await this.getProxyMethod(serviceProxy[serviceName], serviceName)
17+
http.auth = await this.getAuth(serviceProxy[serviceName], serviceName)
1718

1819
if (serviceProxy[serviceName].cors) {
1920
http.cors = await this.getCors(serviceProxy[serviceName])
@@ -59,7 +60,7 @@ module.exports = {
5960
},
6061

6162
async getProxyPath(proxy, serviceName) {
62-
if (proxy.path && typeof proxy.path === 'string') {
63+
if (proxy.path && _.isString(proxy.path)) {
6364
return proxy.path.replace(/^\//, '').replace(/\/$/, '')
6465
}
6566

@@ -71,7 +72,7 @@ module.exports = {
7172
},
7273

7374
async getProxyMethod(proxy, serviceName) {
74-
if (proxy.method && typeof proxy.method === 'string') {
75+
if (proxy.method && _.isString(proxy.method)) {
7576
const method = proxy.method.toLowerCase()
7677

7778
const allowedMethods = ['get', 'post', 'put', 'patch', 'options', 'head', 'delete', 'any']
@@ -154,5 +155,60 @@ module.exports = {
154155
}
155156

156157
return cors
158+
},
159+
160+
async getAuth(proxy, serviceName) {
161+
const auth = {
162+
authorizationType: 'NONE'
163+
}
164+
165+
if (!_.isUndefined(proxy.authorizationType)) {
166+
if (_.isString(proxy.authorizationType)) {
167+
const allowedTypes = ['NONE', 'AWS_IAM', 'CUSTOM', 'COGNITO_USER_POOLS']
168+
if (allowedTypes.indexOf(proxy.authorizationType) === NOT_FOUND) {
169+
const errorMessage = [
170+
`Invalid APIG authorization type "${proxy.authorizationType}" in AWS service proxy.`,
171+
` AWS supported types are: ${allowedTypes.join(', ')}.`
172+
].join('')
173+
return BbPromise.reject(new this.serverless.classes.Error(errorMessage))
174+
}
175+
176+
auth.authorizationType = proxy.authorizationType
177+
} else {
178+
return BbPromise.reject(
179+
new this.serverless.classes.Error(
180+
`Invalid "authorizationType" property in ${serviceName} proxy`
181+
)
182+
)
183+
}
184+
}
185+
186+
if (!_.isUndefined(proxy.authorizerId)) {
187+
if (auth.authorizationType !== 'CUSTOM') {
188+
const errorMessage = `Expecting 'CUSTOM' authorization type when 'authorizerId' is set in service ${serviceName}`
189+
return BbPromise.reject(new this.serverless.classes.Error(errorMessage))
190+
}
191+
192+
auth.authorizerId = proxy.authorizerId
193+
}
194+
195+
if (!_.isUndefined(proxy.authorizationScopes)) {
196+
if (_.isArray(proxy.authorizationScopes)) {
197+
if (auth.authorizationType !== 'COGNITO_USER_POOLS') {
198+
const errorMessage = `Expecting 'COGNITO_USER_POOLS' authorization type when 'authorizationScopes' is set in service ${serviceName}`
199+
return BbPromise.reject(new this.serverless.classes.Error(errorMessage))
200+
}
201+
202+
auth.authorizationScopes = proxy.authorizationScopes
203+
} else {
204+
return BbPromise.reject(
205+
new this.serverless.classes.Error(
206+
`Invalid "authorizationScopes" property in ${serviceName} proxy`
207+
)
208+
)
209+
}
210+
}
211+
212+
return auth
157213
}
158214
}

0 commit comments

Comments
 (0)