@@ -2,6 +2,7 @@ import { IncomingMessage, OutgoingMessage } from 'node:http';
22import { CAT , CommonAccessToken } from '..' ;
33import {
44 InvalidAudienceError ,
5+ InvalidCatIfError ,
56 InvalidIssuerError ,
67 InvalidReuseDetected ,
78 KeyNotFoundError ,
@@ -15,9 +16,10 @@ import {
1516 CloudFrontRequest ,
1617 CloudFrontResponse
1718} from 'aws-lambda' ;
18- import { CommonAccessTokenDict } from '../cat' ;
19+ import { CommonAccessTokenDict , CommonAccessTokenFactory } from '../cat' ;
1920import { ICTIStore } from '../stores/interface' ;
2021import { ITokenLogger } from '../loggers/interface' ;
22+ import { CatIfDictValue } from '../catif' ;
2123
2224interface HttpValidatorKey {
2325 kid : string ;
@@ -257,8 +259,19 @@ export class HttpValidator {
257259 }
258260 return { status : code , claims : cat ?. claims , count } ;
259261 } else {
262+ // CAT valid but not acceptable
263+ let responseCode = 401 ;
264+ if ( result . error instanceof TokenExpiredError ) {
265+ responseCode =
266+ ( cat ?. claims . catif &&
267+ ( await this . handleCatIf ( {
268+ cat,
269+ response
270+ } ) ) ) ||
271+ 401 ;
272+ }
260273 return {
261- status : 401 ,
274+ status : responseCode ,
262275 message : result . error . message ,
263276 claims : cat ?. claims
264277 } ;
@@ -274,8 +287,9 @@ export class HttpValidator {
274287 err instanceof InvalidReuseDetected ||
275288 err instanceof MethodNotAllowedError
276289 ) {
290+ const responseCode = 401 ;
277291 return {
278- status : 401 ,
292+ status : responseCode ,
279293 message : ( err as Error ) . message ,
280294 claims : cat ?. claims
281295 } ;
@@ -322,6 +336,54 @@ export class HttpValidator {
322336 }
323337 }
324338
339+ private async handleCatIf ( {
340+ cat,
341+ response
342+ } : {
343+ cat : CommonAccessToken ;
344+ response ?: OutgoingMessage ;
345+ } ) : Promise < number > {
346+ if ( ! response ) {
347+ throw new Error ( 'Missing response object in HTTP validator' ) ;
348+ }
349+ let returnCode = 401 ;
350+ const catif : CatIfDictValue = cat . claims . catif as CatIfDictValue ;
351+ if ( catif ) {
352+ for ( const claim in catif ) {
353+ if ( cat . claims [ claim ] !== undefined ) {
354+ const [ code , value , keyid ] = catif [ claim ] ;
355+ returnCode = code ;
356+ for ( const header in value ) {
357+ if ( ! Array . isArray ( value [ header ] ) ) {
358+ response . setHeader ( header , value [ header ] as string ) ;
359+ } else {
360+ const newCatDict = value [ header ] [ 1 ] as CommonAccessTokenDict ;
361+ if ( ! newCatDict [ 'iss' ] ) {
362+ newCatDict [ 'iss' ] = this . opts . issuer ;
363+ }
364+ if ( ! newCatDict [ 'iat' ] ) {
365+ newCatDict [ 'iat' ] = Math . floor ( Date . now ( ) / 1000 ) ;
366+ }
367+ const newCat = CommonAccessTokenFactory . fromDict ( newCatDict ) ;
368+ if ( ! keyid ) {
369+ throw new InvalidCatIfError ( 'Missing key id in catif claim' ) ;
370+ }
371+ await newCat . mac (
372+ { kid : keyid , k : this . keys [ keyid ] } ,
373+ this . opts . alg || 'HS256' ,
374+ { addCwtTag : true }
375+ ) ;
376+ const newToken = newCat . raw ?. toString ( 'base64' ) ;
377+ const newUrl = new URL ( value [ header ] [ 0 ] + newToken ) ;
378+ response . setHeader ( header , newUrl . toString ( ) ) ;
379+ }
380+ }
381+ }
382+ }
383+ }
384+ return returnCode ;
385+ }
386+
325387 private async handleReplay ( {
326388 cat,
327389 count
@@ -358,6 +420,7 @@ export class HttpValidator {
358420 if ( ! cat . keyId ) {
359421 throw new Error ( 'Key ID not found' ) ;
360422 }
423+ let responseCode = 200 ;
361424 if (
362425 cat &&
363426 cat ?. shouldRenew &&
@@ -402,9 +465,10 @@ export class HttpValidator {
402465 redirectUrl . searchParams . delete ( this . tokenUriParam ) ;
403466 redirectUrl . searchParams . set ( this . tokenUriParam , renewedToken ) ;
404467 response . setHeader ( 'Location' , redirectUrl . toString ( ) ) ;
468+ responseCode = 302 ;
405469 }
406470 }
407471 }
408- return { status : 200 } ;
472+ return { status : responseCode } ;
409473 }
410474}
0 commit comments