@@ -11,8 +11,8 @@ const defaultSecurityHandler = (
1111
1212interface SecurityHandlerResult {
1313 success : boolean ;
14- status : number ;
15- error : string ;
14+ status ? : number ;
15+ error ? : string ;
1616}
1717export function security (
1818 context : OpenApiContext ,
@@ -26,13 +26,16 @@ export function security(
2626 return next ( ) ;
2727 }
2828
29- const securities = < OpenAPIV3 . SecuritySchemeObject > (
30- req . openapi . schema . security
31- ) ;
29+ // const securities: OpenAPIV3.SecurityRequirementObject[] =
30+ // req.openapi.schema.security;
31+
32+ // use the local security object or fallbac to api doc's security or undefined
33+ const securities : OpenAPIV3 . SecurityRequirementObject [ ] =
34+ req . openapi . schema . security || context . apiDoc . security ;
3235
3336 const path : string = req . openapi . openApiRoute ;
3437
35- if ( ! path || ! Array . isArray ( securities ) ) {
38+ if ( ! path || ! Array . isArray ( securities ) || securities . length === 0 ) {
3639 return next ( ) ;
3740 }
3841
@@ -54,14 +57,17 @@ export function security(
5457 // TODO handle AND'd and OR'd security
5558 // This assumes OR only! i.e. at least one security passed authentication
5659 let firstError : SecurityHandlerResult = null ;
60+ let success = false ;
5761 for ( var r of results ) {
58- if ( ! r . success ) {
59- firstError = r ;
62+ if ( r . success ) {
63+ success = true ;
6064 break ;
65+ } else if ( ! firstError ) {
66+ firstError = r ;
6167 }
6268 }
63- if ( firstError ) throw firstError ;
64- else next ( ) ;
69+ if ( success ) next ( ) ;
70+ else throw firstError ;
6571 } catch ( e ) {
6672 const message = ( e && e . error && e . error . message ) || 'unauthorized' ;
6773 const err = validationError ( e . status , path , message ) ;
@@ -80,7 +86,7 @@ class SecuritySchemes {
8086 this . securities = securities ;
8187 }
8288
83- executeHandlers ( req : OpenApiRequest ) : Promise < SecurityHandlerResult [ ] > {
89+ async executeHandlers ( req : OpenApiRequest ) : Promise < SecurityHandlerResult [ ] > {
8490 // use a fallback handler if security handlers is not specified
8591 // This means if security handlers is specified, the user must define
8692 // all security handlers
@@ -90,9 +96,15 @@ class SecuritySchemes {
9096
9197 const promises = this . securities . map ( async s => {
9298 try {
99+ if ( Util . isEmptyObject ( s ) ) {
100+ // anonumous security
101+ return { success : true } ;
102+ }
93103 const securityKey = Object . keys ( s ) [ 0 ] ;
94104 const scheme : any = this . securitySchemes [ securityKey ] ;
95- const handler = this . securityHandlers [ securityKey ] || fallbackHandler ;
105+ const handler =
106+ ( this . securityHandlers && this . securityHandlers [ securityKey ] ) ||
107+ fallbackHandler ;
96108 const scopesTmp = s [ securityKey ] ;
97109 const scopes = Array . isArray ( scopesTmp ) ? scopesTmp : [ ] ;
98110
@@ -109,7 +121,7 @@ class SecuritySchemes {
109121 throw { status : 500 , message } ;
110122 }
111123
112- new AuthValidator ( req , scheme ) . validate ( ) ;
124+ new AuthValidator ( req , scheme , scopes ) . validate ( ) ;
113125
114126 // expected handler results are:
115127 // - throw exception,
@@ -140,10 +152,12 @@ class AuthValidator {
140152 private req : OpenApiRequest ;
141153 private scheme ;
142154 private path : string ;
143- constructor ( req : OpenApiRequest , scheme ) {
155+ private scopes : string [ ] ;
156+ constructor ( req : OpenApiRequest , scheme , scopes : string [ ] = [ ] ) {
144157 this . req = req ;
145158 this . scheme = scheme ;
146159 this . path = req . openapi . openApiRoute ;
160+ this . scopes = scopes ;
147161 }
148162
149163 validate ( ) {
@@ -186,6 +200,8 @@ class AuthValidator {
186200 if ( type === 'basic' && ! authHeader . includes ( 'basic' ) ) {
187201 throw Error ( `Authorization header with scheme 'Basic' required.` ) ;
188202 }
203+
204+ this . dissallowScopes ( ) ;
189205 }
190206 }
191207
@@ -202,6 +218,28 @@ class AuthValidator {
202218 }
203219 }
204220 // TODO scheme in cookie
221+
222+ this . dissallowScopes ( ) ;
205223 }
206224 }
225+
226+ private dissallowScopes ( ) {
227+ if ( this . scopes . length > 0 ) {
228+ // https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.2.md#security-requirement-object
229+ throw {
230+ status : 500 ,
231+ message : "scopes array must be empty for security type 'http'" ,
232+ } ;
233+ }
234+ }
235+ }
236+
237+ class Util {
238+ static isEmptyObject ( o : Object ) {
239+ return (
240+ typeof o === 'object' &&
241+ Object . entries ( o ) . length === 0 &&
242+ o . constructor === Object
243+ ) ;
244+ }
207245}
0 commit comments