serverless-offline 11.3.0 → 11.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"dedicatedTo": "Blue, a great migrating bird.",
|
|
3
3
|
"name": "serverless-offline",
|
|
4
|
-
"version": "11.
|
|
4
|
+
"version": "11.5.0",
|
|
5
5
|
"description": "Emulate AWS λ and API Gateway locally when developing your Serverless project",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"exports": {
|
|
@@ -82,7 +82,7 @@
|
|
|
82
82
|
]
|
|
83
83
|
},
|
|
84
84
|
"dependencies": {
|
|
85
|
-
"@aws-sdk/client-lambda": "^3.
|
|
85
|
+
"@aws-sdk/client-lambda": "^3.210.0",
|
|
86
86
|
"@hapi/boom": "^10.0.0",
|
|
87
87
|
"@hapi/h2o2": "^10.0.0",
|
|
88
88
|
"@hapi/hapi": "^21.0.0",
|
|
@@ -93,13 +93,13 @@
|
|
|
93
93
|
"fs-extra": "^10.1.0",
|
|
94
94
|
"is-wsl": "^2.2.0",
|
|
95
95
|
"java-invoke-local": "0.0.6",
|
|
96
|
-
"jose": "^4.
|
|
96
|
+
"jose": "^4.11.0",
|
|
97
97
|
"js-string-escape": "^1.0.1",
|
|
98
98
|
"jsonpath-plus": "^7.2.0",
|
|
99
99
|
"jsonschema": "^1.4.1",
|
|
100
100
|
"jszip": "^3.10.1",
|
|
101
101
|
"luxon": "^3.1.0",
|
|
102
|
-
"node-fetch": "^3.
|
|
102
|
+
"node-fetch": "^3.3.0",
|
|
103
103
|
"node-schedule": "^2.1.0",
|
|
104
104
|
"object.hasown": "^1.1.2",
|
|
105
105
|
"p-memoize": "^7.1.1",
|
|
@@ -116,7 +116,7 @@
|
|
|
116
116
|
"eslint-plugin-import": "^2.25.4",
|
|
117
117
|
"eslint-plugin-prettier": "^4.2.1",
|
|
118
118
|
"git-list-updated": "^1.2.1",
|
|
119
|
-
"husky": "^8.0.
|
|
119
|
+
"husky": "^8.0.2",
|
|
120
120
|
"lint-staged": "^13.0.3",
|
|
121
121
|
"mocha": "^10.1.0",
|
|
122
122
|
"nyc": "^15.1.0",
|
|
@@ -18,6 +18,7 @@ export const supportedNodejs = new Set([
|
|
|
18
18
|
'nodejs12.x',
|
|
19
19
|
'nodejs14.x',
|
|
20
20
|
'nodejs16.x',
|
|
21
|
+
'nodejs18.x',
|
|
21
22
|
])
|
|
22
23
|
|
|
23
24
|
// PROVIDED
|
|
@@ -49,5 +50,6 @@ export const supportedRuntimes = new Set([
|
|
|
49
50
|
export const unsupportedDockerRuntimes = new Set([
|
|
50
51
|
'nodejs14.x',
|
|
51
52
|
'nodejs16.x',
|
|
53
|
+
'nodejs18.x',
|
|
52
54
|
'python3.9',
|
|
53
55
|
])
|
|
@@ -11,239 +11,287 @@ import {
|
|
|
11
11
|
parseQueryStringParameters,
|
|
12
12
|
} from '../../utils/index.js'
|
|
13
13
|
|
|
14
|
+
const IDENTITY_SOURCE_TYPE_HEADER = 'header'
|
|
15
|
+
const IDENTITY_SOURCE_TYPE_QUERYSTRING = 'querystring'
|
|
16
|
+
|
|
14
17
|
export default function createAuthScheme(authorizerOptions, provider, lambda) {
|
|
15
18
|
const authFunName = authorizerOptions.name
|
|
16
|
-
let
|
|
19
|
+
let identitySourceField = 'authorization'
|
|
20
|
+
let identitySourceType = IDENTITY_SOURCE_TYPE_HEADER
|
|
17
21
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
)
|
|
26
|
-
|
|
27
|
-
if (!identitySourceMatch || identitySourceMatch.length !== 3) {
|
|
28
|
-
throw new Error(
|
|
29
|
-
`Serverless Offline only supports retrieving tokens from headers (λ: ${authFunName})`,
|
|
30
|
-
)
|
|
31
|
-
}
|
|
22
|
+
const finalizeAuthScheme = () => {
|
|
23
|
+
return () => ({
|
|
24
|
+
async authenticate(request, h) {
|
|
25
|
+
log.notice()
|
|
26
|
+
log.notice(
|
|
27
|
+
`Running Authorization function for ${request.method} ${request.path} (λ: ${authFunName})`,
|
|
28
|
+
)
|
|
32
29
|
|
|
33
|
-
|
|
34
|
-
|
|
30
|
+
const { rawHeaders, url } = request.raw.req
|
|
31
|
+
|
|
32
|
+
// Get path params
|
|
33
|
+
// aws doesn't auto decode path params - hapi does
|
|
34
|
+
const pathParams = { ...request.params }
|
|
35
35
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
const accountId = 'random-account-id'
|
|
51
|
-
const apiId = 'random-api-id'
|
|
52
|
-
const requestId = 'random-request-id'
|
|
53
|
-
|
|
54
|
-
const httpMethod = request.method.toUpperCase()
|
|
55
|
-
const resourcePath = request.route.path.replace(
|
|
56
|
-
new RegExp(`^/${provider.stage}`),
|
|
57
|
-
'',
|
|
58
|
-
)
|
|
59
|
-
|
|
60
|
-
let event = {
|
|
61
|
-
enhancedAuthContext: {},
|
|
62
|
-
headers: parseHeaders(rawHeaders),
|
|
63
|
-
requestContext: {
|
|
64
|
-
accountId,
|
|
65
|
-
apiId,
|
|
66
|
-
domainName: `${apiId}.execute-api.us-east-1.amazonaws.com`,
|
|
67
|
-
domainPrefix: apiId,
|
|
68
|
-
requestId,
|
|
69
|
-
stage: provider.stage,
|
|
70
|
-
},
|
|
71
|
-
version: authorizerOptions.payloadVersion,
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
const protocol = `${request.server.info.protocol.toUpperCase()}/${
|
|
75
|
-
request.raw.req.httpVersion
|
|
76
|
-
}`
|
|
77
|
-
const currentDate = new Date()
|
|
78
|
-
const resourceId = `${httpMethod} ${resourcePath}`
|
|
79
|
-
const methodArn = `arn:aws:execute-api:${provider.region}:${accountId}:${apiId}/${provider.stage}/${httpMethod}${resourcePath}`
|
|
80
|
-
|
|
81
|
-
const authorization = request.raw.req.headers[identityHeader]
|
|
82
|
-
|
|
83
|
-
const identityValidationExpression = new RegExp(
|
|
84
|
-
authorizerOptions.identityValidationExpression,
|
|
85
|
-
)
|
|
86
|
-
const matchedAuthorization =
|
|
87
|
-
identityValidationExpression.test(authorization)
|
|
88
|
-
const finalAuthorization = matchedAuthorization ? authorization : ''
|
|
89
|
-
|
|
90
|
-
log.debug(`Retrieved ${identityHeader} header "${finalAuthorization}"`)
|
|
91
|
-
|
|
92
|
-
if (authorizerOptions.payloadVersion === '1.0') {
|
|
93
|
-
event = {
|
|
94
|
-
...event,
|
|
95
|
-
authorizationToken: finalAuthorization,
|
|
96
|
-
httpMethod: request.method.toUpperCase(),
|
|
97
|
-
identitySource: finalAuthorization,
|
|
98
|
-
methodArn,
|
|
99
|
-
multiValueHeaders: parseMultiValueHeaders(rawHeaders),
|
|
100
|
-
multiValueQueryStringParameters:
|
|
101
|
-
parseMultiValueQueryStringParameters(url),
|
|
102
|
-
path: request.path,
|
|
103
|
-
pathParameters: nullIfEmpty(pathParams),
|
|
104
|
-
queryStringParameters: parseQueryStringParameters(url),
|
|
36
|
+
const accountId = 'random-account-id'
|
|
37
|
+
const apiId = 'random-api-id'
|
|
38
|
+
const requestId = 'random-request-id'
|
|
39
|
+
|
|
40
|
+
const httpMethod = request.method.toUpperCase()
|
|
41
|
+
const resourcePath = request.route.path.replace(
|
|
42
|
+
new RegExp(`^/${provider.stage}`),
|
|
43
|
+
'',
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
let event = {
|
|
47
|
+
enhancedAuthContext: {},
|
|
48
|
+
headers: parseHeaders(rawHeaders),
|
|
105
49
|
requestContext: {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
requestTimeEpoch: currentDate.getTime(),
|
|
112
|
-
resourceId,
|
|
113
|
-
resourcePath,
|
|
50
|
+
accountId,
|
|
51
|
+
apiId,
|
|
52
|
+
domainName: `${apiId}.execute-api.us-east-1.amazonaws.com`,
|
|
53
|
+
domainPrefix: apiId,
|
|
54
|
+
requestId,
|
|
114
55
|
stage: provider.stage,
|
|
115
56
|
},
|
|
116
|
-
|
|
57
|
+
version: authorizerOptions.payloadVersion,
|
|
117
58
|
}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
59
|
+
|
|
60
|
+
const protocol = `${request.server.info.protocol.toUpperCase()}/${
|
|
61
|
+
request.raw.req.httpVersion
|
|
62
|
+
}`
|
|
63
|
+
const currentDate = new Date()
|
|
64
|
+
const resourceId = `${httpMethod} ${resourcePath}`
|
|
65
|
+
const methodArn = `arn:aws:execute-api:${provider.region}:${accountId}:${apiId}/${provider.stage}/${httpMethod}${resourcePath}`
|
|
66
|
+
|
|
67
|
+
let authorization
|
|
68
|
+
if (identitySourceType === IDENTITY_SOURCE_TYPE_HEADER) {
|
|
69
|
+
const headers = request.raw.req.headers ?? {}
|
|
70
|
+
authorization = headers[identitySourceField]
|
|
71
|
+
} else if (identitySourceType === IDENTITY_SOURCE_TYPE_QUERYSTRING) {
|
|
72
|
+
const queryStringParameters = parseQueryStringParameters(url) ?? {}
|
|
73
|
+
authorization = queryStringParameters[identitySourceField]
|
|
74
|
+
} else {
|
|
75
|
+
throw new Error(
|
|
76
|
+
`No Authorization source has been specified. This should never happen. (λ: ${authFunName})`,
|
|
77
|
+
)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (authorization === undefined) {
|
|
81
|
+
throw new Error(
|
|
82
|
+
`Identity Source is null for ${identitySourceType} ${identitySourceField} (λ: ${authFunName})`,
|
|
83
|
+
)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const identityValidationExpression = new RegExp(
|
|
87
|
+
authorizerOptions.identityValidationExpression,
|
|
88
|
+
)
|
|
89
|
+
const matchedAuthorization =
|
|
90
|
+
identityValidationExpression.test(authorization)
|
|
91
|
+
const finalAuthorization = matchedAuthorization ? authorization : ''
|
|
92
|
+
|
|
93
|
+
log.debug(
|
|
94
|
+
`Retrieved ${identitySourceField} ${identitySourceType} "${finalAuthorization}"`,
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
if (authorizerOptions.payloadVersion === '1.0') {
|
|
98
|
+
event = {
|
|
99
|
+
...event,
|
|
100
|
+
authorizationToken: finalAuthorization,
|
|
101
|
+
httpMethod: request.method.toUpperCase(),
|
|
102
|
+
identitySource: finalAuthorization,
|
|
103
|
+
methodArn,
|
|
104
|
+
multiValueHeaders: parseMultiValueHeaders(rawHeaders),
|
|
105
|
+
multiValueQueryStringParameters:
|
|
106
|
+
parseMultiValueQueryStringParameters(url),
|
|
107
|
+
path: request.path,
|
|
108
|
+
pathParameters: nullIfEmpty(pathParams),
|
|
109
|
+
queryStringParameters: parseQueryStringParameters(url),
|
|
110
|
+
requestContext: {
|
|
111
|
+
extendedRequestId: requestId,
|
|
112
|
+
httpMethod,
|
|
113
|
+
path: request.path,
|
|
130
114
|
protocol,
|
|
115
|
+
requestTime: currentDate.toString(),
|
|
116
|
+
requestTimeEpoch: currentDate.getTime(),
|
|
117
|
+
resourceId,
|
|
118
|
+
resourcePath,
|
|
119
|
+
stage: provider.stage,
|
|
131
120
|
},
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
timeEpoch: currentDate.getTime(),
|
|
135
|
-
},
|
|
136
|
-
routeArn: methodArn,
|
|
137
|
-
routeKey: resourceId,
|
|
121
|
+
resource: resourcePath,
|
|
122
|
+
}
|
|
138
123
|
}
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
124
|
+
|
|
125
|
+
if (authorizerOptions.payloadVersion === '2.0') {
|
|
126
|
+
event = {
|
|
127
|
+
...event,
|
|
128
|
+
identitySource: [finalAuthorization],
|
|
129
|
+
rawPath: request.path,
|
|
130
|
+
rawQueryString: getRawQueryParams(url),
|
|
131
|
+
requestContext: {
|
|
132
|
+
http: {
|
|
133
|
+
method: httpMethod,
|
|
134
|
+
path: resourcePath,
|
|
135
|
+
protocol,
|
|
136
|
+
},
|
|
137
|
+
routeKey: resourceId,
|
|
138
|
+
time: currentDate.toString(),
|
|
139
|
+
timeEpoch: currentDate.getTime(),
|
|
140
|
+
},
|
|
141
|
+
routeArn: methodArn,
|
|
142
|
+
routeKey: resourceId,
|
|
143
|
+
}
|
|
147
144
|
}
|
|
148
|
-
|
|
149
|
-
//
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
145
|
+
|
|
146
|
+
// methodArn is the ARN of the function we are running we are authorizing access to (or not)
|
|
147
|
+
// Account ID and API ID are not simulated
|
|
148
|
+
if (authorizerOptions.type === 'request') {
|
|
149
|
+
event = {
|
|
150
|
+
...event,
|
|
151
|
+
type: 'REQUEST',
|
|
152
|
+
}
|
|
153
|
+
} else {
|
|
154
|
+
// This is safe since type: 'TOKEN' cannot have payload format 2.0
|
|
155
|
+
event = {
|
|
156
|
+
...event,
|
|
157
|
+
type: 'TOKEN',
|
|
158
|
+
}
|
|
153
159
|
}
|
|
154
|
-
}
|
|
155
160
|
|
|
156
|
-
|
|
157
|
-
|
|
161
|
+
const lambdaFunction = lambda.get(authFunName)
|
|
162
|
+
lambdaFunction.setEvent(event)
|
|
163
|
+
|
|
164
|
+
try {
|
|
165
|
+
const result = await lambdaFunction.runHandler()
|
|
166
|
+
|
|
167
|
+
if (authorizerOptions.enableSimpleResponses) {
|
|
168
|
+
if (result.isAuthorized) {
|
|
169
|
+
const authorizer = {
|
|
170
|
+
integrationLatency: '42',
|
|
171
|
+
...result.context,
|
|
172
|
+
}
|
|
173
|
+
return h.authenticated({
|
|
174
|
+
credentials: {
|
|
175
|
+
authorizer,
|
|
176
|
+
context: result.context || {},
|
|
177
|
+
},
|
|
178
|
+
})
|
|
179
|
+
}
|
|
180
|
+
return Boom.forbidden(
|
|
181
|
+
'User is not authorized to access this resource',
|
|
182
|
+
)
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
if (result === 'Unauthorized')
|
|
186
|
+
return Boom.unauthorized('Unauthorized')
|
|
158
187
|
|
|
159
|
-
|
|
160
|
-
|
|
188
|
+
// Validate that the policy document has the principalId set
|
|
189
|
+
if (!result.principalId) {
|
|
190
|
+
log.notice(
|
|
191
|
+
`Authorization response did not include a principalId: (λ: ${authFunName})`,
|
|
192
|
+
)
|
|
161
193
|
|
|
162
|
-
|
|
163
|
-
if (result.isAuthorized) {
|
|
164
|
-
const authorizer = {
|
|
165
|
-
integrationLatency: '42',
|
|
166
|
-
...result.context,
|
|
167
|
-
}
|
|
168
|
-
return h.authenticated({
|
|
169
|
-
credentials: {
|
|
170
|
-
authorizer,
|
|
171
|
-
context: result.context || {},
|
|
172
|
-
},
|
|
173
|
-
})
|
|
194
|
+
return Boom.forbidden('No principalId set on the Response')
|
|
174
195
|
}
|
|
175
|
-
return Boom.forbidden(
|
|
176
|
-
'User is not authorized to access this resource',
|
|
177
|
-
)
|
|
178
|
-
}
|
|
179
196
|
|
|
180
|
-
|
|
197
|
+
if (
|
|
198
|
+
!authCanExecuteResource(
|
|
199
|
+
result.policyDocument,
|
|
200
|
+
event.methodArn || event.routeArn,
|
|
201
|
+
)
|
|
202
|
+
) {
|
|
203
|
+
log.notice(
|
|
204
|
+
`Authorization response didn't authorize user to access resource: (λ: ${authFunName})`,
|
|
205
|
+
)
|
|
206
|
+
|
|
207
|
+
return Boom.forbidden(
|
|
208
|
+
'User is not authorized to access this resource',
|
|
209
|
+
)
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// validate the resulting context, ensuring that all
|
|
213
|
+
// values are either string, number, or boolean types
|
|
214
|
+
if (result.context) {
|
|
215
|
+
const validationResult = authValidateContext(
|
|
216
|
+
result.context,
|
|
217
|
+
authFunName,
|
|
218
|
+
)
|
|
219
|
+
|
|
220
|
+
if (validationResult instanceof Error) {
|
|
221
|
+
return validationResult
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
result.context = validationResult
|
|
225
|
+
}
|
|
181
226
|
|
|
182
|
-
// Validate that the policy document has the principalId set
|
|
183
|
-
if (!result.principalId) {
|
|
184
227
|
log.notice(
|
|
185
|
-
`Authorization
|
|
228
|
+
`Authorization function returned a successful response: (λ: ${authFunName})`,
|
|
186
229
|
)
|
|
187
230
|
|
|
188
|
-
|
|
189
|
-
|
|
231
|
+
const authorizer = {
|
|
232
|
+
integrationLatency: '42',
|
|
233
|
+
principalId: result.principalId,
|
|
234
|
+
...result.context,
|
|
235
|
+
}
|
|
190
236
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
237
|
+
// Set the credentials for the rest of the pipeline
|
|
238
|
+
return h.authenticated({
|
|
239
|
+
credentials: {
|
|
240
|
+
authorizer,
|
|
241
|
+
context: result.context,
|
|
242
|
+
principalId: result.principalId,
|
|
243
|
+
usageIdentifierKey: result.usageIdentifierKey,
|
|
244
|
+
},
|
|
245
|
+
})
|
|
246
|
+
} catch {
|
|
197
247
|
log.notice(
|
|
198
|
-
`Authorization
|
|
248
|
+
`Authorization function returned an error response: (λ: ${authFunName})`,
|
|
199
249
|
)
|
|
200
250
|
|
|
201
|
-
return Boom.
|
|
202
|
-
'User is not authorized to access this resource',
|
|
203
|
-
)
|
|
251
|
+
return Boom.unauthorized('Unauthorized')
|
|
204
252
|
}
|
|
253
|
+
},
|
|
254
|
+
})
|
|
255
|
+
}
|
|
205
256
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
if (result.context) {
|
|
209
|
-
const validationResult = authValidateContext(
|
|
210
|
-
result.context,
|
|
211
|
-
authFunName,
|
|
212
|
-
)
|
|
213
|
-
|
|
214
|
-
if (validationResult instanceof Error) {
|
|
215
|
-
return validationResult
|
|
216
|
-
}
|
|
257
|
+
const checkForIdentitySourceMatch = (exp, expectedLength) => {
|
|
258
|
+
const identitySourceMatch = exp.exec(authorizerOptions.identitySource)
|
|
217
259
|
|
|
218
|
-
|
|
219
|
-
|
|
260
|
+
if (!identitySourceMatch || identitySourceMatch.length !== expectedLength) {
|
|
261
|
+
return undefined
|
|
262
|
+
}
|
|
263
|
+
return identitySourceMatch[expectedLength - 1]
|
|
264
|
+
}
|
|
220
265
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
266
|
+
if (
|
|
267
|
+
authorizerOptions.type !== 'request' ||
|
|
268
|
+
authorizerOptions.identitySource
|
|
269
|
+
) {
|
|
270
|
+
const headerRegExp = /^(method.|\$)request.header.((?:\w+-?)+\w+)$/
|
|
271
|
+
const queryStringRegExp =
|
|
272
|
+
/^(method.|\$)request.querystring.((?:\w+-?)+\w+)$/
|
|
273
|
+
|
|
274
|
+
const identityHeaderResult = checkForIdentitySourceMatch(headerRegExp, 3)
|
|
275
|
+
if (identityHeaderResult !== undefined) {
|
|
276
|
+
identitySourceField = identityHeaderResult.toLowerCase()
|
|
277
|
+
identitySourceType = IDENTITY_SOURCE_TYPE_HEADER
|
|
278
|
+
return finalizeAuthScheme()
|
|
279
|
+
}
|
|
224
280
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
281
|
+
const identityQueryStringResult = checkForIdentitySourceMatch(
|
|
282
|
+
queryStringRegExp,
|
|
283
|
+
3,
|
|
284
|
+
)
|
|
285
|
+
if (identityQueryStringResult !== undefined) {
|
|
286
|
+
identitySourceField = identityQueryStringResult
|
|
287
|
+
identitySourceType = IDENTITY_SOURCE_TYPE_QUERYSTRING
|
|
288
|
+
return finalizeAuthScheme()
|
|
289
|
+
}
|
|
230
290
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
context: result.context,
|
|
236
|
-
principalId: result.principalId,
|
|
237
|
-
usageIdentifierKey: result.usageIdentifierKey,
|
|
238
|
-
},
|
|
239
|
-
})
|
|
240
|
-
} catch {
|
|
241
|
-
log.notice(
|
|
242
|
-
`Authorization function returned an error response: (λ: ${authFunName})`,
|
|
243
|
-
)
|
|
291
|
+
throw new Error(
|
|
292
|
+
`Serverless Offline only supports retrieving tokens from headers and querystring parameters (λ: ${authFunName})`,
|
|
293
|
+
)
|
|
294
|
+
}
|
|
244
295
|
|
|
245
|
-
|
|
246
|
-
}
|
|
247
|
-
},
|
|
248
|
-
})
|
|
296
|
+
return finalizeAuthScheme()
|
|
249
297
|
}
|