From 3de969820726a5c127ce078c88553a51c1fb0ded Mon Sep 17 00:00:00 2001 From: seokhochoi Date: Mon, 26 Aug 2024 00:48:43 +0900 Subject: [PATCH 1/5] fix: add cookie support for HTTP bearer authentication - Updated validateHttp() to handle bearer tokens in both authorization header and cookies. - Adapted logic to ensure flexibility for projects using HTTP-only cookies instead of headers for authentication. --- src/middlewares/openapi.security.ts | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/middlewares/openapi.security.ts b/src/middlewares/openapi.security.ts index 8f43af14..ec1fae72 100644 --- a/src/middlewares/openapi.security.ts +++ b/src/middlewares/openapi.security.ts @@ -232,14 +232,21 @@ class AuthValidator { const authHeader = req.headers['authorization'] && req.headers['authorization'].toLowerCase(); + const authCookie = req.cookies[scheme.name] || req.signedCookies?.[scheme.name]; - if (!authHeader) { - throw Error(`Authorization header required`); + if (!authHeader && !authCookie) { + throw Error(`Authorization header or cookie required`); } const type = scheme.scheme && scheme.scheme.toLowerCase(); - if (type === 'bearer' && !authHeader.includes('bearer')) { - throw Error(`Authorization header with scheme 'Bearer' required`); + if (type === 'bearer') { + if (authHeader && !authHeader.includes('bearer')) { + throw Error(`Authorization header with scheme 'Bearer' required`); + } + + if (!authHeader && authCookie === undefined) { + throw Error(`Bearer token required in authorization header or cookie`); + } } if (type === 'basic' && !authHeader.includes('basic')) { From 2df184d13c30cbbb793b5943fd0c4756d7b116ce Mon Sep 17 00:00:00 2001 From: seokhochoi Date: Fri, 18 Oct 2024 18:56:45 +0900 Subject: [PATCH 2/5] fix: Refine HTTP authentication validation based on code review feedback - Maintain existing error for missing Authorization header - Add specific error for cookie authentication when specified in security scheme - Consider both Authorization header and cookie for bearer token validation --- src/middlewares/openapi.security.ts | 52 +++++++++++++++++------------ 1 file changed, 31 insertions(+), 21 deletions(-) diff --git a/src/middlewares/openapi.security.ts b/src/middlewares/openapi.security.ts index ec1fae72..6609df8c 100644 --- a/src/middlewares/openapi.security.ts +++ b/src/middlewares/openapi.security.ts @@ -24,21 +24,31 @@ interface SecurityHandlerResult { error?: string; } -function extractErrorsFromResults(results: (SecurityHandlerResult | SecurityHandlerResult[])[]) { - return results.map(result => { - if (Array.isArray(result)) { - return result.map(it => it).filter(it => !it.success); - } - return [result].filter(it => !it.success); - }).flatMap(it => [...it]); +function extractErrorsFromResults( + results: (SecurityHandlerResult | SecurityHandlerResult[])[], +) { + return results + .map((result) => { + if (Array.isArray(result)) { + return result.map((it) => it).filter((it) => !it.success); + } + return [result].filter((it) => !it.success); + }) + .flatMap((it) => [...it]); } function didAllSecurityRequirementsPass(results: SecurityHandlerResult[]) { - return results.every(it => it.success); + return results.every((it) => it.success); } -function didOneSchemaPassValidation(results: (SecurityHandlerResult | SecurityHandlerResult[])[]) { - return results.some(result => Array.isArray(result) ? didAllSecurityRequirementsPass(result) : result.success); +function didOneSchemaPassValidation( + results: (SecurityHandlerResult | SecurityHandlerResult[])[], +) { + return results.some((result) => + Array.isArray(result) + ? didAllSecurityRequirementsPass(result) + : result.success, + ); } export function security( @@ -86,8 +96,8 @@ export function security( if (success) { next(); } else { - const errors = extractErrorsFromResults(results) - throw errors[0] + const errors = extractErrorsFromResults(results); + throw errors[0]; } } catch (e) { const message = e?.error?.message || 'unauthorized'; @@ -232,20 +242,20 @@ class AuthValidator { const authHeader = req.headers['authorization'] && req.headers['authorization'].toLowerCase(); - const authCookie = req.cookies[scheme.name] || req.signedCookies?.[scheme.name]; - - if (!authHeader && !authCookie) { - throw Error(`Authorization header or cookie required`); - } + const authCookie = + req.cookies[scheme.name] || req.signedCookies?.[scheme.name]; const type = scheme.scheme && scheme.scheme.toLowerCase(); if (type === 'bearer') { if (authHeader && !authHeader.includes('bearer')) { - throw Error(`Authorization header with scheme 'Bearer' required`); + throw Error(`Authorization header with scheme 'Bearer' required`); } - - if (!authHeader && authCookie === undefined) { - throw Error(`Bearer token required in authorization header or cookie`); + if (!authHeader && !authCookie) { + if (scheme.in === 'cookie') { + throw Error(`Cookie authentication required`); + } else { + throw Error(`Authorization header required`); + } } } From 3ae1b9ad52fd1d3eb1edfd6c9a89de96a3bb1462 Mon Sep 17 00:00:00 2001 From: seokhochoi Date: Fri, 18 Oct 2024 19:25:17 +0900 Subject: [PATCH 3/5] fix: Revert unintended code style changes made during previous commit --- src/middlewares/openapi.security.ts | 36 ++++++++++------------------- 1 file changed, 12 insertions(+), 24 deletions(-) diff --git a/src/middlewares/openapi.security.ts b/src/middlewares/openapi.security.ts index 6609df8c..97db70df 100644 --- a/src/middlewares/openapi.security.ts +++ b/src/middlewares/openapi.security.ts @@ -24,32 +24,20 @@ interface SecurityHandlerResult { error?: string; } -function extractErrorsFromResults( - results: (SecurityHandlerResult | SecurityHandlerResult[])[], -) { - return results - .map((result) => { - if (Array.isArray(result)) { - return result.map((it) => it).filter((it) => !it.success); - } - return [result].filter((it) => !it.success); - }) - .flatMap((it) => [...it]); -} +function extractErrorsFromResults(results: (SecurityHandlerResult | SecurityHandlerResult[])[]) { + return results.map(result => { + if (Array.isArray(result)) { + return result.map(it => it).filter(it => !it.success); + } + return [result].filter(it => !it.success); + }).flatMap(it => [...it]); function didAllSecurityRequirementsPass(results: SecurityHandlerResult[]) { - return results.every((it) => it.success); + return results.every(it => it.success); } -function didOneSchemaPassValidation( - results: (SecurityHandlerResult | SecurityHandlerResult[])[], -) { - return results.some((result) => - Array.isArray(result) - ? didAllSecurityRequirementsPass(result) - : result.success, - ); -} +function didOneSchemaPassValidation(results: (SecurityHandlerResult | SecurityHandlerResult[])[]) { + return results.some(result => Array.isArray(result) ? didAllSecurityRequirementsPass(result) : result.success); export function security( apiDoc: OpenAPIV3.Document, @@ -96,8 +84,8 @@ export function security( if (success) { next(); } else { - const errors = extractErrorsFromResults(results); - throw errors[0]; + const errors = extractErrorsFromResults(results) + throw errors[0] } } catch (e) { const message = e?.error?.message || 'unauthorized'; From 6437aa0410d08e1f7a9b413243cdf35d7f284c18 Mon Sep 17 00:00:00 2001 From: seokhochoi Date: Fri, 18 Oct 2024 19:29:44 +0900 Subject: [PATCH 4/5] fix: Revert unintended code style changes made during previous commit --- src/middlewares/openapi.security.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/middlewares/openapi.security.ts b/src/middlewares/openapi.security.ts index 97db70df..f6d56855 100644 --- a/src/middlewares/openapi.security.ts +++ b/src/middlewares/openapi.security.ts @@ -31,6 +31,7 @@ function extractErrorsFromResults(results: (SecurityHandlerResult | SecurityHand } return [result].filter(it => !it.success); }).flatMap(it => [...it]); +} function didAllSecurityRequirementsPass(results: SecurityHandlerResult[]) { return results.every(it => it.success); @@ -38,6 +39,7 @@ function didAllSecurityRequirementsPass(results: SecurityHandlerResult[]) { function didOneSchemaPassValidation(results: (SecurityHandlerResult | SecurityHandlerResult[])[]) { return results.some(result => Array.isArray(result) ? didAllSecurityRequirementsPass(result) : result.success); +} export function security( apiDoc: OpenAPIV3.Document, @@ -84,8 +86,8 @@ export function security( if (success) { next(); } else { - const errors = extractErrorsFromResults(results) - throw errors[0] + const errors = extractErrorsFromResults(results); + throw errors[0]; } } catch (e) { const message = e?.error?.message || 'unauthorized'; @@ -281,4 +283,4 @@ class Util { o.constructor === Object ); } -} +} \ No newline at end of file From 122d64cf224896f702b07852f9fde6edd8ef2b2a Mon Sep 17 00:00:00 2001 From: seokhochoi Date: Sat, 26 Oct 2024 15:59:39 +0900 Subject: [PATCH 5/5] fix: fix: update validateHttp to handle missing auth headers properly - Restructure Basic auth validation to check header existence first - Maintain original error messages for non-cookie authentication - Add proper cookie authentication check when specified - Fix undefined.includes() error in Basic auth validation --- src/middlewares/openapi.security.ts | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/middlewares/openapi.security.ts b/src/middlewares/openapi.security.ts index f6d56855..9abb5412 100644 --- a/src/middlewares/openapi.security.ts +++ b/src/middlewares/openapi.security.ts @@ -234,12 +234,13 @@ class AuthValidator { req.headers['authorization'].toLowerCase(); const authCookie = req.cookies[scheme.name] || req.signedCookies?.[scheme.name]; - + const type = scheme.scheme && scheme.scheme.toLowerCase(); if (type === 'bearer') { if (authHeader && !authHeader.includes('bearer')) { throw Error(`Authorization header with scheme 'Bearer' required`); } + if (!authHeader && !authCookie) { if (scheme.in === 'cookie') { throw Error(`Cookie authentication required`); @@ -248,9 +249,14 @@ class AuthValidator { } } } - - if (type === 'basic' && !authHeader.includes('basic')) { - throw Error(`Authorization header with scheme 'Basic' required`); + + if (type === 'basic') { + if (!authHeader) { + throw Error(`Authorization header required`); + } + if (!authHeader.includes('basic')) { + throw Error(`Authorization header with scheme 'Basic' required`); + } } } }