From 062e170b55b9066b6d9e805ced64d8c1fb8d7415 Mon Sep 17 00:00:00 2001 From: pearl-truss Date: Thu, 1 Feb 2024 11:38:06 -0500 Subject: [PATCH] move ip address check to thirdPartyAuthn function --- services/app-api/src/authn/thirdPartyAuthn.ts | 15 ++++++- services/app-api/src/handlers/apollo_gql.ts | 4 +- .../handlers/third_party_API_authorizer.ts | 44 +++---------------- 3 files changed, 21 insertions(+), 42 deletions(-) diff --git a/services/app-api/src/authn/thirdPartyAuthn.ts b/services/app-api/src/authn/thirdPartyAuthn.ts index 577779bbca..b06f2a577f 100644 --- a/services/app-api/src/authn/thirdPartyAuthn.ts +++ b/services/app-api/src/authn/thirdPartyAuthn.ts @@ -5,7 +5,8 @@ import { initTracer, recordException } from '../../../uploads/src/lib/otel' export async function userFromThirdPartyAuthorizer( store: Store, - userId: string + userId: string, + ipAddress: string ) { // // setup otel tracing const otelCollectorURL = process.env.REACT_APP_OTEL_COLLECTOR_URL @@ -17,8 +18,18 @@ export async function userFromThirdPartyAuthorizer( const serviceName = 'third-party-authorizer' initTracer(serviceName, otelCollectorURL) - + const allowedIpAddresses = process.env.ALLOWED_IP_ADDRESSES + if (allowedIpAddresses === undefined || allowedIpAddresses === '') { + throw new Error( + 'Configuration Error: ALLOWD_IP_ADDRESSES is required to run app-api.' + ) + } try { + const ipAddressIsValid = allowedIpAddresses.includes(ipAddress) + if (!ipAddressIsValid) { + const errMsg = new Error('bad ip address') + return err(errMsg) + } // Lookup user from postgres const auroraUser = await lookupUserAurora(store, userId) if (auroraUser instanceof Error) { diff --git a/services/app-api/src/handlers/apollo_gql.ts b/services/app-api/src/handlers/apollo_gql.ts index 71311b4628..b40a763e3f 100644 --- a/services/app-api/src/handlers/apollo_gql.ts +++ b/services/app-api/src/handlers/apollo_gql.ts @@ -62,6 +62,7 @@ function contextForRequestForFetcher(userFetcher: userFromAuthProvider): ({ const requestSpan = anyContext[requestSpanKey] const authProvider = event.requestContext.identity.cognitoAuthenticationProvider + const ipAddress = context.requestContext.identity.sourceIp // This handler is shared with the third_party_API_authorizer // when called from the 3rd party authorizer the cognito auth provider // is not valid for instead the authorizer returns a user ID @@ -94,7 +95,8 @@ function contextForRequestForFetcher(userFetcher: userFromAuthProvider): ({ } else if (fromThirdPartyAuthorizer && userId) { userResult = await userFromThirdPartyAuthorizer( store, - userId + userId, + ipAddress ) } diff --git a/services/app-api/src/handlers/third_party_API_authorizer.ts b/services/app-api/src/handlers/third_party_API_authorizer.ts index 15ca9d0085..451ed57c7e 100644 --- a/services/app-api/src/handlers/third_party_API_authorizer.ts +++ b/services/app-api/src/handlers/third_party_API_authorizer.ts @@ -8,7 +8,6 @@ import { newJWTLib } from '../jwt' const stageName = process.env.stage const jwtSecret = process.env.JWT_SECRET -const allowedIpAddresses = process.env.ALLOWED_IP_ADDRESSES if (stageName === undefined) { throw new Error('Configuration Error: stage is required') @@ -20,12 +19,6 @@ if (jwtSecret === undefined || jwtSecret === '') { ) } -if (allowedIpAddresses === undefined || allowedIpAddresses === '') { - throw new Error( - 'Configuration Error: ALLOWD_IP_ADDRESSES is required to run app-api.' - ) -} - const jwtLib = newJWTLib({ issuer: `mcreview-${stageName}`, signingKey: Buffer.from(jwtSecret, 'hex'), @@ -37,38 +30,12 @@ export const main: APIGatewayTokenAuthorizerHandler = async ( ): Promise => { const authToken = event.authorizationToken.replace('Bearer ', '') try { - const parsedEvent = JSON.parse(JSON.stringify(event)) - console.info( - parsedEvent?.multiValueHeaders?.Host[0], - 'Multivalue header host' - ) - const host = parsedEvent?.multiValueHeaders?.Host[0] - console.info(parsedEvent, '============ PARSED EVENT =============') - console.info({ - message: `${parsedEvent?.headers}`, - operation: 'parsed event', - status: 'LOGGED', - }) - if (host === undefined) { - // TODO: remove this log - // eslint-disable-next-line - console.log(parsedEvent) - console.error('Invalid host on header') - - return generatePolicy(undefined, event, false) - } - // host is formatted as ipAddress:port - // the following will remove the :port to leave just the ip address - const ipAddress = host.slice(0, host.indexOf(':')) - const ipAddressIsValid = allowedIpAddresses.includes(ipAddress) - console.info(ipAddress, 'IP Address') - console.info(allowedIpAddresses, 'Allowed IP Address') // authentication step for validating JWT token const userId = jwtLib.userIDFromToken(authToken) if (userId instanceof Error) { console.error('Invalid auth token') - return generatePolicy(undefined, event, ipAddressIsValid) + return generatePolicy(undefined, event) } console.info({ @@ -77,20 +44,19 @@ export const main: APIGatewayTokenAuthorizerHandler = async ( status: 'SUCCESS', }) - return generatePolicy(userId, event, ipAddressIsValid) + return generatePolicy(userId, event) } catch (err) { console.error( 'unexpected exception attempting to validate authorization', err ) - return generatePolicy(undefined, event, false) + return generatePolicy(undefined, event) } } const generatePolicy = function ( userId: string | undefined, - event: APIGatewayTokenAuthorizerEvent, - ipAddressIsValid: boolean + event: APIGatewayTokenAuthorizerEvent ): APIGatewayAuthorizerResult { // If the JWT is verified as valid, and the request comes from an allowed IP address // send an Allow policy @@ -100,7 +66,7 @@ const generatePolicy = function ( Statement: [ { Action: 'execute-api:Invoke', - Effect: userId && ipAddressIsValid ? 'Allow' : 'Deny', + Effect: userId ? 'Allow' : 'Deny', Resource: event['methodArn'], }, ],