Skip to content

Commit

Permalink
feat: introduce mgmt-token scheme for authorization (#176)
Browse files Browse the repository at this point in the history
  • Loading branch information
Sergey Shelomentsev authored and sshelomentsev committed Feb 26, 2024
1 parent ab3caa5 commit c884027
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 8 deletions.
12 changes: 6 additions & 6 deletions mgmt-lambda/app.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { APIGatewayProxyEventV2WithRequestContext, APIGatewayEventRequestContextV2 } from 'aws-lambda'
import { SecretsManagerClient } from '@aws-sdk/client-secrets-manager'
import { getAuthSettings } from './auth'
import { getAuthSettings, retrieveAuthToken } from './auth'
import type { DeploymentSettings } from './model/DeploymentSettings'
import { handleNoAthentication, handleWrongConfiguration, handleNotFound } from './handlers/errorHandlers'
import { defaults } from './DefaultSettings'
Expand All @@ -14,8 +14,8 @@ export async function handler(event: APIGatewayProxyEventV2WithRequestContext<AP

try {
const authSettings = await getAuthSettings(secretManagerClient)
const authorization = event.headers['authorization']
if (authorization !== authSettings.token) {
const authToken = retrieveAuthToken(event)
if (authToken !== authSettings.token) {
return handleNoAthentication()
}
} catch (error) {
Expand All @@ -36,11 +36,11 @@ export async function handler(event: APIGatewayProxyEventV2WithRequestContext<AP

if (path.startsWith('/update') && method === 'POST') {
return handleUpdate(lambdaClient, cloudFrontClient, deploymentSettings)
} else if (path.startsWith('/status') && method === 'GET') {
}
if (path.startsWith('/status') && method === 'GET') {
return handleStatus(lambdaClient, deploymentSettings)
} else {
return handleNotFound()
}
return handleNotFound()
}

function loadDeploymentSettings(): DeploymentSettings {
Expand Down
19 changes: 19 additions & 0 deletions mgmt-lambda/auth.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import { APIGatewayProxyEventV2WithRequestContext, APIGatewayEventRequestContextV2 } from 'aws-lambda'
import type { AuthSettings } from './model/AuthSettings'
import { SecretsManagerClient, GetSecretValueCommand, GetSecretValueResponse } from '@aws-sdk/client-secrets-manager'

const MGMT_TOKEN_SCHEME = 'mgmt-token'
const EMPTY_TOKEN = ''

export async function getAuthSettings(secretManagerClient: SecretsManagerClient): Promise<AuthSettings> {
const secretName = process.env.SettingsSecretName
if (!secretName) {
Expand All @@ -25,3 +29,18 @@ export async function getAuthSettings(secretManagerClient: SecretsManagerClient)
throw new Error(`Unable to retrieve secret. ${error}`)
}
}

export function retrieveAuthToken(
event: APIGatewayProxyEventV2WithRequestContext<APIGatewayEventRequestContextV2>,
): string {
const authorization = event.headers['authorization']
if (!authorization) {
return EMPTY_TOKEN
}

const [type, token] = authorization.split(' ')
if (type == MGMT_TOKEN_SCHEME) {
return token || EMPTY_TOKEN
}
return EMPTY_TOKEN
}
2 changes: 1 addition & 1 deletion mgmt-lambda/test/app.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ function generateStatusRequest(
rawQueryString: '',
headers: {
'content-type': 'application/json',
authorization: token,
authorization: `mgmt-token ${token}`,
},
requestContext: requestContext,
isBase64Encoded: false,
Expand Down
85 changes: 84 additions & 1 deletion mgmt-lambda/test/auth.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import { mockClient } from 'aws-sdk-client-mock'
import { SecretsManagerClient, GetSecretValueCommand } from '@aws-sdk/client-secrets-manager'
import { getAuthSettings } from '../auth'
import {
APIGatewayProxyEventV2WithRequestContext,
APIGatewayEventRequestContextV2,
APIGatewayProxyEventHeaders,
} from 'aws-lambda'
import { getAuthSettings, retrieveAuthToken } from '../auth'
import 'aws-sdk-client-mock-jest'

const secretMock = mockClient(SecretsManagerClient)
Expand Down Expand Up @@ -78,3 +83,81 @@ describe('auth test', () => {
}
})
})

describe('test token retrieving', () => {
it('correct scheme', () => {
const event = generateRequestEvent({
authorization: 'mgmt-token token-value',
})

const token = retrieveAuthToken(event)
expect(token).toBe('token-value')
})

it('correct scheme without value', () => {
const event = generateRequestEvent({
authorization: 'mgmt-token',
})

const token = retrieveAuthToken(event)
expect(token).toBe('')
})

it('wrong scheme', () => {
const event = generateRequestEvent({
authorization: 'basic token-value',
})

const token = retrieveAuthToken(event)
expect(token).toBe('')
})

it('no scheme', () => {
const event = generateRequestEvent({
authorization: 'some-string',
})

const token = retrieveAuthToken(event)
expect(token).toBe('')
})

it('no header', () => {
const event = generateRequestEvent({})

const token = retrieveAuthToken(event)
expect(token).toBe('')
})
})

function generateRequestEvent(
headers: APIGatewayProxyEventHeaders,
): APIGatewayProxyEventV2WithRequestContext<APIGatewayEventRequestContextV2> {
const requestContext: APIGatewayEventRequestContextV2 = {
accountId: '1234567890',
apiId: 'v3',
domainName: 'aws-lambda.amazonaws.com',
domainPrefix: 'xyz123-qwerttuii-fsfds',
http: {
method: 'GET',
path: 'status',
protocol: 'https',
sourceIp: '192.168.1.2',
userAgent: 'backend-app',
},
requestId: 'a70a6921-959a-40ea-8e2e-f5343b08588a',
routeKey: '',
stage: '',
time: '2023-12-18T15:57:15+0000',
timeEpoch: 1702915035000,
}

return {
version: 'v2',
routeKey: '',
rawPath: '',
rawQueryString: '',
headers: headers,
requestContext: requestContext,
isBase64Encoded: false,
}
}

0 comments on commit c884027

Please sign in to comment.