Skip to content

Commit

Permalink
feat: Introduce header to override authorizer response (#1328)
Browse files Browse the repository at this point in the history
  • Loading branch information
ericctsf committed Feb 3, 2022
1 parent e217fcb commit a5158a4
Show file tree
Hide file tree
Showing 7 changed files with 189 additions and 6 deletions.
15 changes: 10 additions & 5 deletions README.md
Expand Up @@ -364,10 +364,11 @@ only enabled with the `--ignoreJWTSignature` flag. Make sure to only set this fl

You are able to use some custom headers in your request to gain more control over the requestContext object.

| Header | Event key |
| ------------------------------- | ----------------------------------------------------------- |
| cognito-identity-id | event.requestContext.identity.cognitoIdentityId |
| cognito-authentication-provider | event.requestContext.identity.cognitoAuthenticationProvider |
| Header | Event key | Example |
| ------------------------------- | ----------------------------------------------------------- | --------------------------------------------------------------------------------- |
| cognito-identity-id | event.requestContext.identity.cognitoIdentityId | |
| cognito-authentication-provider | event.requestContext.identity.cognitoAuthenticationProvider | |
| sls-offline-authorizer-override | event.requestContext.authorizer | { "iam": {"cognitoUser": { "amr": ["unauthenticated"], "identityId": "abc123" }}} |

By doing this you are now able to change those values using a custom header. This can help you with easier authentication or retrieving the userId from a `cognitoAuthenticationProvider` value.

Expand Down Expand Up @@ -744,6 +745,10 @@ We try to follow [Airbnb's JavaScript Style Guide](https://github.com/airbnb/jav
| :------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------: |
| [lteacher](https://github.com/lteacher) | [martinmicunda](https://github.com/martinmicunda) | [nori3tsu](https://github.com/nori3tsu) | [ppasmanik](https://github.com/ppasmanik) | [ryanzyy](https://github.com/ryanzyy) |

| [<img alt="m0ppers" src="https://avatars3.githubusercontent.com/u/819421?v=4&s=117" width="117">](https://github.com/m0ppers) | [<img alt="footballencarta" src="https://avatars0.githubusercontent.com/u/1312258?v=4&s=117" width="117">](https://github.com/footballencarta) | [<img alt="bryanvaz" src="https://avatars0.githubusercontent.com/u/9157498?v=4&s=117" width="117">](https://github.com/bryanvaz) | [<img alt="njyjn" src="https://avatars.githubusercontent.com/u/10694375?v=4&s=117" width="117">](https://github.com/njyjn) |
| [<img alt="m0ppers" src="https://avatars3.githubusercontent.com/u/819421?v=4&s=117" width="117">](https://github.com/m0ppers) | [<img alt="footballencarta" src="https://avatars0.githubusercontent.com/u/1312258?v=4&s=117" width="117">](https://github.com/footballencarta) | [<img alt="bryanvaz" src="https://avatars0.githubusercontent.com/u/9157498?v=4&s=117" width="117">](https://github.com/bryanvaz) | [<img alt="njyjn" src="https://avatars.githubusercontent.com/u/10694375?v=4&s=117" width="117">](https://github.com/njyjn) | |
| :---------------------------------------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------: | ------------------------------------- |
| [m0ppers](https://github.com/m0ppers) | [footballencarta](https://github.com/footballencarta) | [bryanvaz](https://github.com/bryanvaz) | [njyjn](https://github.com/njyjn) | [kdybicz](https://github.com/kdybicz) |

| [<img alt="ericctsf" src="https://avatars.githubusercontent.com/u/42775388?s=400&v=4" width="117">](https://github.com/ericctsf) | | | | |
| :------------------------------------------------------------------------------------------------------------------------------: | :-: | :-: | :-: | :-: |
| [ericctsf](https://github.com/erictsf) | | | | |
3 changes: 2 additions & 1 deletion package.json
Expand Up @@ -156,7 +156,8 @@
"Dima Krutolianov (https://github.com/dimadk24)",
"Bryan Vaz (https://github.com/bryanvaz)",
"Justin Ng (https://github.com/njyjn)",
"Fernando Alvarez (https://github.com/jefer590)"
"Fernando Alvarez (https://github.com/jefer590)",
"Eric Carter (https://github.com/ericctsf)"
],
"husky": {
"hooks": {
Expand Down
16 changes: 16 additions & 0 deletions src/events/http/lambda-events/LambdaProxyIntegrationEvent.js
Expand Up @@ -85,6 +85,22 @@ export default class LambdaProxyIntegrationEvent {
// NOTE FIXME request.raw.req.rawHeaders can only be null for testing (hapi shot inject())
const headers = parseHeaders(rawHeaders || []) || {}

if (headers['sls-offline-authorizer-override']) {
try {
authAuthorizer = parse(headers['sls-offline-authorizer-override'])
} catch (error) {
if (this.log) {
this.log.error(
'Could not parse header sls-offline-authorizer-override, make sure it is correct JSON',
)
} else {
console.error(
'Serverless-offline: Could not parse header sls-offline-authorizer-override make sure it is correct JSON.',
)
}
}
}

if (body) {
if (typeof body !== 'string') {
// this.#request.payload is NOT the same as the rawPayload
Expand Down
16 changes: 16 additions & 0 deletions src/events/http/lambda-events/LambdaProxyIntegrationEventV2.js
Expand Up @@ -72,6 +72,22 @@ export default class LambdaProxyIntegrationEventV2 {
// NOTE FIXME request.raw.req.rawHeaders can only be null for testing (hapi shot inject())
const headers = parseHeaders(rawHeaders || []) || {}

if (headers['sls-offline-authorizer-override']) {
try {
authAuthorizer = parse(headers['sls-offline-authorizer-override'])
} catch (error) {
if (this.log) {
this.log.error(
'Could not parse header sls-offline-authorizer-override, make sure it is correct JSON',
)
} else {
console.error(
'Serverless-offline: Could not parse header sls-offline-authorizer-override make sure it is correct JSON.',
)
}
}
}

if (body) {
if (typeof body !== 'string') {
// this.#request.payload is NOT the same as the rawPayload
Expand Down
8 changes: 8 additions & 0 deletions tests/integration/override-authorizer/handler.js
@@ -0,0 +1,8 @@
'use strict'

exports.echo_authorizer = async function get(context) {
return {
body: JSON.stringify(context.requestContext.authorizer),
statusCode: 200,
}
}
104 changes: 104 additions & 0 deletions tests/integration/override-authorizer/override-authorizer.test.js
@@ -0,0 +1,104 @@
import { resolve } from 'path'
import fetch from 'node-fetch'
import { joinUrl, setup, teardown } from '../_testHelpers/index.js'

jest.setTimeout(30000)

const envAuthorizer = {
iam: {
cognitoUser: {
amr: ['unauthenticated'],
identityId: 'env_identity_id',
},
},
}

const headerAuthorizer = {
iam: {
cognitoUser: {
amr: ['unauthenticated'],
identityId: 'header_identity_id',
},
},
}

describe('override authorizer tests', () => {
// init
beforeAll(async () => {
process.env.AUTHORIZER = JSON.stringify(envAuthorizer)
await setup({
servicePath: resolve(__dirname),
})
})

// cleanup
afterAll(async () => {
process.env.AUTHORIZER = undefined
await teardown()
})

//
;[
{
description: 'HTTP API Falls back on env variable',
req: {
path: '/gateway_v2_http_api',
headers: {},
},
res: {
status: 200,
body: envAuthorizer,
},
},
{
description: 'REST API Falls back on env variable',
req: {
path: '/dev/gateway_v1_rest_api',
headers: {},
},
res: {
status: 200,
body: envAuthorizer,
},
},
{
description: 'HTTP API uses override header',
req: {
path: '/gateway_v2_http_api',
headers: {
'sls-offline-authorizer-override': JSON.stringify(headerAuthorizer),
},
},
res: {
status: 200,
body: headerAuthorizer,
},
},
{
description: 'HTTP API uses override header',
req: {
path: '/dev/gateway_v1_rest_api',
headers: {
'sls-offline-authorizer-override': JSON.stringify(headerAuthorizer),
},
},
res: {
status: 200,
body: headerAuthorizer,
},
},
].forEach(({ description, req, res }) => {
test(description, async () => {
const url = joinUrl(TEST_BASE_URL, req.path)
const options = {
headers: req.headers,
}

const response = await fetch(url, options)
expect(response.status).toEqual(res.status)

const json = await response.json()
expect(json).toEqual(res.body)
})
})
})
33 changes: 33 additions & 0 deletions tests/integration/override-authorizer/serverless.yml
@@ -0,0 +1,33 @@
service: jwt-authorizer

plugins:
- ../../../

custom:
serverless-offline:
noAuth: true

provider:
memorySize: 128
name: aws
region: us-east-1 # default
runtime: nodejs12.x
stage: dev
versionFunctions: false
httpApi:
payload: '2.0'

functions:
user:
events:
- http:
authorizer:
type: 'AWS_IAM'
method: get
path: gateway_v1_rest_api
- httpApi:
authorizer:
type: AWS_IAM
method: get
path: gateway_v2_http_api
handler: handler.echo_authorizer

0 comments on commit a5158a4

Please sign in to comment.