-
Notifications
You must be signed in to change notification settings - Fork 4k
/
Copy pathlambda.ts
165 lines (147 loc) · 5.73 KB
/
lambda.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
import {
HttpAuthorizer,
HttpAuthorizerType,
HttpRouteAuthorizerBindOptions,
HttpRouteAuthorizerConfig,
IHttpRouteAuthorizer,
AuthorizerPayloadVersion,
IHttpApi,
} from '../../../aws-apigatewayv2';
import { ServicePrincipal } from '../../../aws-iam';
import { IFunction } from '../../../aws-lambda';
import { Stack, Duration, Names } from '../../../core';
/**
* Specifies the type responses the lambda returns
*/
export enum HttpLambdaResponseType {
/** Returns simple boolean response */
SIMPLE,
/** Returns an IAM Policy */
IAM,
}
/**
* Properties to initialize HttpTokenAuthorizer.
*/
export interface HttpLambdaAuthorizerProps {
/**
* Friendly authorizer name
* @default - same value as `id` passed in the constructor.
*/
readonly authorizerName?: string;
/**
* The identity source for which authorization is requested.
*
* @default ['$request.header.Authorization']
*/
readonly identitySource?: string[];
/**
* How long APIGateway should cache the results. Max 1 hour.
* Disable caching by setting this to `Duration.seconds(0)`.
*
* @default Duration.minutes(5)
*/
readonly resultsCacheTtl?: Duration;
/**
* The payload format version
*
* @see https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-lambda-authorizer.html#http-api-lambda-authorizer.payload-format
*
* Note: if `responseType` is set to simple, then
* setting this property to version 1.0 is not allowed.
*
* @default - if `responseType` is not set or is set to IAM,
* then payload format version is set to 1.0. If `responseType`
* is set to simple, then payload format version is set to 2.0.
*/
readonly payloadFormatVersion?: AuthorizerPayloadVersion;
/**
* The type of response the lambda can return
*
* @see https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-lambda-authorizer.html#http-api-lambda-authorizer.payload-format-response
*
* Note: if `payloadFormatVersion` is set to version 1.0, then
* setting this property to simple is not allowed.
*
* @default - if `payloadFormatVersion` is not set or is set to 1.0,
* then response type is set to IAM. If `payloadFormatVersion`
* is set to 2.0, then response type is set to simple.
*/
readonly responseType?: HttpLambdaResponseType;
}
/**
* Authorize Http Api routes via a lambda function
*/
export class HttpLambdaAuthorizer implements IHttpRouteAuthorizer {
private authorizer?: HttpAuthorizer;
private httpApi?: IHttpApi;
/**
* Initialize a lambda authorizer to be bound with HTTP route.
* @param id The id of the underlying construct
* @param pool The lambda function handler to use for authorization
* @param props Properties to configure the authorizer
*/
constructor(
private readonly id: string,
private readonly handler: IFunction,
private readonly props: HttpLambdaAuthorizerProps = {}) {
if (props.payloadFormatVersion === AuthorizerPayloadVersion.VERSION_1_0 && props.responseType === HttpLambdaResponseType.SIMPLE) {
throw new Error('payload format version is set to 1.0 but response type is set to SIMPLE');
}
}
public bind(options: HttpRouteAuthorizerBindOptions): HttpRouteAuthorizerConfig {
if (this.httpApi && (this.httpApi.apiId !== options.route.httpApi.apiId)) {
throw new Error('Cannot attach the same authorizer to multiple Apis');
}
if (!this.authorizer) {
let enableSimpleResponses: boolean;
let payloadFormatVersion: AuthorizerPayloadVersion;
const payloadFormatVersionInner = this.props.payloadFormatVersion;
const responseType = this.props.responseType;
if (payloadFormatVersionInner === undefined) {
enableSimpleResponses = responseType === HttpLambdaResponseType.SIMPLE;
payloadFormatVersion = enableSimpleResponses ? AuthorizerPayloadVersion.VERSION_2_0 : AuthorizerPayloadVersion.VERSION_1_0;
} else if (responseType === undefined) {
enableSimpleResponses = payloadFormatVersionInner === AuthorizerPayloadVersion.VERSION_2_0;
payloadFormatVersion = payloadFormatVersionInner;
} else {
// No need to check here whether payload format version is 1.0
// and response type is simple since this is already handled
// by the constructor
enableSimpleResponses = responseType === HttpLambdaResponseType.SIMPLE;
payloadFormatVersion = payloadFormatVersionInner;
}
this.httpApi = options.route.httpApi;
this.authorizer = new HttpAuthorizer(options.scope, this.id, {
httpApi: options.route.httpApi,
identitySource: this.props.identitySource ?? [
'$request.header.Authorization',
],
type: HttpAuthorizerType.LAMBDA,
authorizerName: this.props.authorizerName ?? this.id,
enableSimpleResponses,
payloadFormatVersion,
authorizerUri: lambdaAuthorizerArn(this.handler),
resultsCacheTtl: this.props.resultsCacheTtl ?? Duration.minutes(5),
});
this.handler.addPermission(`${Names.nodeUniqueId(this.authorizer.node)}-Permission`, {
scope: options.scope,
principal: new ServicePrincipal('apigateway.amazonaws.com'),
sourceArn: Stack.of(options.route).formatArn({
service: 'execute-api',
resource: options.route.httpApi.apiId,
resourceName: `authorizers/${this.authorizer.authorizerId}`,
}),
});
}
return {
authorizerId: this.authorizer.authorizerId,
authorizationType: 'CUSTOM',
};
}
}
/**
* constructs the authorizerURIArn.
*/
function lambdaAuthorizerArn(handler: IFunction) {
return `arn:${Stack.of(handler).partition}:apigateway:${Stack.of(handler).region}:lambda:path/2015-03-31/functions/${handler.functionArn}/invocations`;
}