Skip to content

Commit d3d3b53

Browse files
Merge pull request #371 from lkhari/removeServerlessDependency
feat: moved authorizers out into code
2 parents c0b2fe7 + 993214e commit d3d3b53

File tree

4 files changed

+301
-4
lines changed

4 files changed

+301
-4
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
'use strict';
2+
3+
const BbPromise = require('bluebird');
4+
const _ = require('lodash');
5+
const awsArnRegExs = require('../../../utils/arnRegularExpressions');
6+
7+
module.exports = {
8+
compileAuthorizers() {
9+
this.validated.events.forEach((event) => {
10+
if (event.http.authorizer && event.http.authorizer.arn) {
11+
const authorizer = event.http.authorizer;
12+
const authorizerProperties = {
13+
AuthorizerResultTtlInSeconds: authorizer.resultTtlInSeconds,
14+
IdentitySource: authorizer.identitySource,
15+
Name: authorizer.name,
16+
RestApiId: this.provider.getApiGatewayRestApiId(),
17+
};
18+
19+
if (typeof authorizer.identityValidationExpression === 'string') {
20+
Object.assign(authorizerProperties, {
21+
IdentityValidationExpression:
22+
authorizer.identityValidationExpression,
23+
});
24+
}
25+
26+
const authorizerLogicalId = this.provider.naming.getAuthorizerLogicalId(
27+
authorizer.name,
28+
);
29+
30+
if (
31+
(authorizer.type || '').toUpperCase() === 'COGNITO_USER_POOLS'
32+
|| (typeof authorizer.arn === 'string'
33+
&& awsArnRegExs.cognitoIdpArnExpr.test(authorizer.arn))
34+
) {
35+
authorizerProperties.Type = 'COGNITO_USER_POOLS';
36+
authorizerProperties.ProviderARNs = [authorizer.arn];
37+
} else {
38+
authorizerProperties.AuthorizerUri = {
39+
'Fn::Join': [
40+
'',
41+
[
42+
'arn:',
43+
{ Ref: 'AWS::Partition' },
44+
':apigateway:',
45+
{ Ref: 'AWS::Region' },
46+
':lambda:path/2015-03-31/functions/',
47+
authorizer.arn,
48+
'/invocations',
49+
],
50+
],
51+
};
52+
authorizerProperties.Type = authorizer.type
53+
? authorizer.type.toUpperCase()
54+
: 'TOKEN';
55+
}
56+
57+
_.merge(
58+
this.serverless.service.provider.compiledCloudFormationTemplate
59+
.Resources,
60+
{
61+
[authorizerLogicalId]: {
62+
Type: 'AWS::ApiGateway::Authorizer',
63+
Properties: authorizerProperties,
64+
},
65+
},
66+
);
67+
}
68+
});
69+
return BbPromise.resolve();
70+
},
71+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
1+
'use strict';
2+
3+
const expect = require('chai').expect;
4+
const Serverless = require('serverless/lib/Serverless');
5+
const AwsProvider = require('serverless/lib/plugins/aws/provider/awsProvider');
6+
const ServerlessStepFunctions = require('./../../../index');
7+
8+
describe('#compileAuthorizers()', () => {
9+
let awsCompileApigEvents;
10+
11+
beforeEach(() => {
12+
const options = {
13+
stage: 'dev',
14+
region: 'us-east-1',
15+
};
16+
const serverless = new Serverless();
17+
serverless.setProvider('aws', new AwsProvider(serverless));
18+
serverless.service.service = 'first-service';
19+
serverless.service.provider.compiledCloudFormationTemplate = { Resources: {} };
20+
awsCompileApigEvents = new ServerlessStepFunctions(serverless, options);
21+
awsCompileApigEvents.apiGatewayRestApiLogicalId = 'ApiGatewayRestApi';
22+
awsCompileApigEvents.validated = {};
23+
});
24+
25+
it('should create an authorizer with minimal configuration', () => {
26+
awsCompileApigEvents.validated.events = [
27+
{
28+
http: {
29+
path: 'users/create',
30+
method: 'POST',
31+
authorizer: {
32+
name: 'authorizer',
33+
arn: { 'Fn::GetAtt': ['SomeLambdaFunction', 'Arn'] },
34+
resultTtlInSeconds: 300,
35+
identitySource: 'method.request.header.Authorization',
36+
},
37+
},
38+
},
39+
];
40+
41+
return awsCompileApigEvents.compileAuthorizers().then(() => {
42+
const resource = awsCompileApigEvents.serverless.service.provider
43+
.compiledCloudFormationTemplate.Resources.AuthorizerApiGatewayAuthorizer;
44+
45+
expect(resource.Type).to.equal('AWS::ApiGateway::Authorizer');
46+
expect(resource.Properties.AuthorizerResultTtlInSeconds).to.equal(300);
47+
expect(resource.Properties.AuthorizerUri).to.deep.equal({
48+
'Fn::Join': [
49+
'',
50+
[
51+
'arn:',
52+
{ Ref: 'AWS::Partition' },
53+
':apigateway:',
54+
{ Ref: 'AWS::Region' },
55+
':lambda:path/2015-03-31/functions/',
56+
{ 'Fn::GetAtt': ['SomeLambdaFunction', 'Arn'] },
57+
'/invocations',
58+
],
59+
],
60+
});
61+
expect(resource.Properties.IdentitySource).to.equal('method.request.header.Authorization');
62+
expect(resource.Properties.IdentityValidationExpression).to.equal(undefined);
63+
expect(resource.Properties.Name).to.equal('authorizer');
64+
expect(resource.Properties.RestApiId.Ref).to.equal('ApiGatewayRestApi');
65+
expect(resource.Properties.Type).to.equal('TOKEN');
66+
});
67+
});
68+
69+
it('should create an authorizer with provided configuration', () => {
70+
awsCompileApigEvents.validated.events = [
71+
{
72+
http: {
73+
path: 'users/create',
74+
method: 'POST',
75+
authorizer: {
76+
name: 'authorizer',
77+
arn: 'foo',
78+
resultTtlInSeconds: 500,
79+
identitySource: 'method.request.header.Custom',
80+
identityValidationExpression: 'regex',
81+
},
82+
},
83+
},
84+
];
85+
86+
return awsCompileApigEvents.compileAuthorizers().then(() => {
87+
const resource = awsCompileApigEvents.serverless.service.provider
88+
.compiledCloudFormationTemplate.Resources.AuthorizerApiGatewayAuthorizer;
89+
90+
expect(resource.Type).to.equal('AWS::ApiGateway::Authorizer');
91+
expect(resource.Properties.AuthorizerUri).to.deep.equal({
92+
'Fn::Join': [
93+
'',
94+
[
95+
'arn:',
96+
{ Ref: 'AWS::Partition' },
97+
':apigateway:',
98+
{ Ref: 'AWS::Region' },
99+
':lambda:path/2015-03-31/functions/',
100+
'foo',
101+
'/invocations',
102+
],
103+
],
104+
});
105+
expect(resource.Properties.AuthorizerResultTtlInSeconds).to.equal(500);
106+
expect(resource.Properties.IdentitySource).to.equal('method.request.header.Custom');
107+
expect(resource.Properties.IdentityValidationExpression).to.equal('regex');
108+
expect(resource.Properties.Name).to.equal('authorizer');
109+
expect(resource.Properties.RestApiId.Ref).to.equal('ApiGatewayRestApi');
110+
expect(resource.Properties.Type).to.equal('TOKEN');
111+
});
112+
});
113+
114+
it('should apply optional provided type value to Authorizer Type', () => {
115+
awsCompileApigEvents.validated.events = [
116+
{
117+
http: {
118+
path: 'users/create',
119+
method: 'POST',
120+
authorizer: {
121+
name: 'authorizer',
122+
arn: 'foo',
123+
resultTtlInSeconds: 500,
124+
identityValidationExpression: 'regex',
125+
type: 'request',
126+
},
127+
},
128+
},
129+
];
130+
131+
return awsCompileApigEvents.compileAuthorizers().then(() => {
132+
const resource = awsCompileApigEvents.serverless.service.provider
133+
.compiledCloudFormationTemplate.Resources.AuthorizerApiGatewayAuthorizer;
134+
135+
expect(resource.Type).to.equal('AWS::ApiGateway::Authorizer');
136+
expect(resource.Properties.Type).to.equal('REQUEST');
137+
});
138+
});
139+
140+
it('should apply TOKEN as authorizer Type when not given a type value', () => {
141+
awsCompileApigEvents.validated.events = [
142+
{
143+
http: {
144+
path: 'users/create',
145+
method: 'POST',
146+
authorizer: {
147+
name: 'authorizer',
148+
arn: 'foo',
149+
resultTtlInSeconds: 500,
150+
identityValidationExpression: 'regex',
151+
},
152+
},
153+
},
154+
];
155+
156+
return awsCompileApigEvents.compileAuthorizers().then(() => {
157+
const resource = awsCompileApigEvents.serverless.service.provider
158+
.compiledCloudFormationTemplate.Resources
159+
.AuthorizerApiGatewayAuthorizer;
160+
161+
expect(resource.Type).to.equal('AWS::ApiGateway::Authorizer');
162+
expect(resource.Properties.Type).to.equal('TOKEN');
163+
});
164+
});
165+
166+
it('should create a valid cognito user pool authorizer', () => {
167+
awsCompileApigEvents.validated.events = [
168+
{
169+
http: {
170+
path: 'users/create',
171+
method: 'POST',
172+
authorizer: {
173+
name: 'authorizer',
174+
arn: 'arn:aws:cognito-idp:us-east-1:xxx:userpool/us-east-1_ZZZ',
175+
},
176+
},
177+
},
178+
];
179+
180+
return awsCompileApigEvents.compileAuthorizers().then(() => {
181+
const resource = awsCompileApigEvents.serverless.service.provider
182+
.compiledCloudFormationTemplate.Resources
183+
.AuthorizerApiGatewayAuthorizer;
184+
185+
expect(resource.Properties.Name).to.equal('authorizer');
186+
187+
expect(resource.Properties.ProviderARNs[0]).to.equal(
188+
'arn:aws:cognito-idp:us-east-1:xxx:userpool/us-east-1_ZZZ',
189+
);
190+
191+
expect(resource.Properties.Type).to.equal('COGNITO_USER_POOLS');
192+
});
193+
});
194+
195+
it('should create a valid cognito user pool authorizer using Fn::GetAtt', () => {
196+
awsCompileApigEvents.validated.events = [
197+
{
198+
http: {
199+
path: 'users/create',
200+
method: 'POST',
201+
authorizer: {
202+
name: 'authorizer',
203+
type: 'COGNITO_USER_POOLS',
204+
arn: {
205+
'Fn::GetAtt': ['CognitoUserPool', 'Arn'],
206+
},
207+
},
208+
},
209+
},
210+
];
211+
212+
return awsCompileApigEvents.compileAuthorizers().then(() => {
213+
const resource = awsCompileApigEvents.serverless.service.provider
214+
.compiledCloudFormationTemplate.Resources
215+
.AuthorizerApiGatewayAuthorizer;
216+
217+
expect(resource.Properties.Name).to.equal('authorizer');
218+
219+
expect(resource.Properties.ProviderARNs[0]).to.deep.equal({
220+
'Fn::GetAtt': ['CognitoUserPool', 'Arn'],
221+
});
222+
223+
expect(resource.Properties.Type).to.equal('COGNITO_USER_POOLS');
224+
});
225+
});
226+
});

lib/index.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
'use strict';
22

33
const BbPromise = require('bluebird');
4-
const httpAuthorizers = require('serverless/lib/plugins/aws/package/compile/events/apiGateway/lib/authorizers');
54
const _ = require('lodash');
65
const chalk = require('chalk');
6+
const httpAuthorizers = require('./deploy/events/apiGateway/authorizers');
77
const compileStateMachines = require('./deploy/stepFunctions/compileStateMachines');
88
const compileActivities = require('./deploy/stepFunctions/compileActivities');
99
const compileIamRole = require('./deploy/stepFunctions/compileIamRole');

package.json

+3-3
Original file line numberDiff line numberDiff line change
@@ -40,15 +40,15 @@
4040
"mocha-param": "^2.0.0",
4141
"nyc": "^15.0.0",
4242
"semantic-release": "^15.14.0",
43-
"sinon": "^1.17.5"
43+
"sinon": "^1.17.5",
44+
"serverless": "^1.72.0"
4445
},
4546
"dependencies": {
4647
"@hapi/joi": "^15.0.2",
4748
"asl-validator": "^1.7.0",
4849
"bluebird": "^3.4.0",
4950
"chalk": "^1.1.1",
50-
"lodash": "^4.17.11",
51-
"serverless": "^1.72.0"
51+
"lodash": "^4.17.11"
5252
},
5353
"husky": {
5454
"hooks": {

0 commit comments

Comments
 (0)