@@ -23,7 +23,7 @@ import {
2323 TraceIDs ,
2424 ResponseFunc
2525} from "./responses"
26- import { extractNHSNumber , NHSNumberValidationError } from "./extractNHSNumber"
26+ import { extractNHSNumber , NHSNumberValidationError , validateNHSNumber } from "./extractNHSNumber"
2727import { deepCopy , hasTimedOut , jobWithTimeout } from "./utils"
2828import { buildStatusUpdateData , shouldGetStatusUpdates } from "./statusUpdate"
2929import { extractOdsCodes , isolateOperationOutcome } from "./fhirUtils"
@@ -38,6 +38,8 @@ const servicesCache: ServicesCache = {}
3838const LAMBDA_TIMEOUT_MS = 10_000
3939const SPINE_TIMEOUT_MS = 9_000
4040const SERVICE_SEARCH_TIMEOUT_MS = 5_000
41+ export const DELEGATED_ACCESS_HDR = "delegatedaccess"
42+ export const DELEGATED_ACCESS_SUB_HDR = "x-nhsd-subject-nhs-number"
4143
4244type EventHeaders = Record < string , string | undefined >
4345
@@ -75,19 +77,16 @@ async function eventHandler(
7577 successResponse : ResponseFunc ,
7678 includeStatusUpdateData : boolean = false
7779) : Promise < LambdaResult > {
78- const xRequestId = headers [ "x-request-id" ]
79- const requestId = headers [ "apigw-request-id" ]
80- const spineClient = params . spineClient
81-
8280 const traceIDs : TraceIDs = {
8381 "nhsd-correlation-id" : headers [ "nhsd-correlation-id" ] ,
84- "x-request-id" : xRequestId ,
82+ "x-request-id" : headers [ "x-request-id" ] ,
8583 "nhsd-request-id" : headers [ "nhsd-request-id" ] ,
8684 "x-correlation-id" : headers [ "x-correlation-id" ] ,
87- "apigw-request-id" : requestId
85+ "apigw-request-id" : headers [ "apigw-request-id" ]
8886 }
8987 logger . appendKeys ( traceIDs )
9088
89+ const spineClient = params . spineClient
9190 const applicationName = headers [ "nhsd-application-name" ] ?? "unknown"
9291
9392 try {
@@ -96,10 +95,8 @@ async function eventHandler(
9695 return SPINE_CERT_NOT_CONFIGURED_RESPONSE
9796 }
9897
99- const nhsNumber = extractNHSNumber ( headers [ "nhsd-nhslogin-user" ] )
100- logger . info ( `nhsNumber: ${ nhsNumber } ` , { nhsNumber} )
101- headers [ "nhsNumber" ] = nhsNumber
102- if ( await params . pfpConfig . isTC008 ( nhsNumber ) ) {
98+ headers = adaptHeadersToSpine ( headers )
99+ if ( await params . pfpConfig . isTC008 ( headers [ "nhsNumber" ] ! ) ) {
103100 logger . info ( "Test NHS number corresponding to TC008 has been received. Returning a 500 response" )
104101 return TC008_ERROR_RESPONSE
105102 }
@@ -111,7 +108,7 @@ async function eventHandler(
111108 return TIMEOUT_RESPONSE
112109 }
113110 const searchsetBundle : Bundle = response . data
114- searchsetBundle . id = xRequestId
111+ searchsetBundle . id = traceIDs [ "x-request-id" ] || "unknown"
115112
116113 const operationOutcomes = isolateOperationOutcome ( searchsetBundle )
117114 operationOutcomes . forEach ( ( operationOutcome ) => {
@@ -124,7 +121,8 @@ async function eventHandler(
124121 + "They have these relevant ODS codes, and the PfP request was made via this apigee application." ,
125122 {
126123 ODSCodes,
127- nhsNumber,
124+ actorNhsNumber : headers [ "nhsd-nhslogin-user" ] ,
125+ subjectNhsNumber : headers [ "nhsNumber" ] ,
128126 applicationName
129127 }
130128 )
@@ -141,10 +139,15 @@ async function eventHandler(
141139 timeout : SERVICE_SEARCH_TIMEOUT_MS ,
142140 message : `The request to the distance selling service timed out after ${ SERVICE_SEARCH_TIMEOUT_MS } ms.`
143141 } )
144- return await successResponse ( logger , nhsNumber , searchsetBundle , traceIDs , params . pfpConfig , statusUpdateData )
142+ return await successResponse (
143+ logger , headers [ "nhsNumber" ] ! , searchsetBundle , traceIDs , params . pfpConfig , statusUpdateData
144+ )
145145 }
146146
147- return await successResponse ( logger , nhsNumber , distanceSellingBundle , traceIDs , params . pfpConfig , statusUpdateData )
147+ return await successResponse (
148+ logger , headers [ "nhsNumber" ] ! , distanceSellingBundle , traceIDs ,
149+ params . pfpConfig , statusUpdateData
150+ )
148151 } catch ( error ) {
149152 if ( error instanceof NHSNumberValidationError ) {
150153 return INVALID_NHS_NUMBER_RESPONSE
@@ -154,6 +157,28 @@ async function eventHandler(
154157 }
155158}
156159
160+ export function adaptHeadersToSpine ( headers : EventHeaders ) : EventHeaders {
161+ // AEA-3344 introduces delegated access using different headers
162+ logger . debug ( "Testing if delegated access enabled" , { headers} )
163+ if ( ! headers [ DELEGATED_ACCESS_HDR ] || headers [ DELEGATED_ACCESS_HDR ] . toLowerCase ( ) !== "true" ) {
164+ logger . info ( "Subject access request detected" )
165+ headers [ "nhsNumber" ] = extractNHSNumber ( headers [ "nhsd-nhslogin-user" ] )
166+ } else {
167+ logger . info ( "Delegated access request detected" )
168+ let subjectNHSNumber = headers [ DELEGATED_ACCESS_SUB_HDR ]
169+ if ( ! subjectNHSNumber ) {
170+ throw new NHSNumberValidationError ( `${ DELEGATED_ACCESS_SUB_HDR } header not present for delegated access` )
171+ }
172+ if ( subjectNHSNumber . indexOf ( ":" ) > - 1 ) {
173+ logger . warn ( `${ DELEGATED_ACCESS_SUB_HDR } is not expected to be prefixed by proofing level, but is, removing it` )
174+ subjectNHSNumber = subjectNHSNumber . split ( ":" ) [ 1 ]
175+ }
176+ headers [ "nhsNumber" ] = validateNHSNumber ( subjectNHSNumber )
177+ }
178+ logger . info ( `after setting subject nhsNumber` , { headers} )
179+ return headers
180+ }
181+
157182type HandlerConfig < T > = {
158183 handlerFunction : ( event : T , config : HandlerParams ) => Promise < LambdaResult >
159184 middleware : Array < middy . MiddlewareObj >
0 commit comments