@@ -117,15 +117,25 @@ internals.Auth.prototype._setupRoute = function (options, path) {
117
117
118
118
options . mode = options . mode || 'required' ;
119
119
120
- if ( options . scope ) {
121
- if ( typeof options . scope === 'string' ) {
122
- options . scope = [ options . scope ] ;
123
- }
120
+ if ( options . entity !== undefined ||
121
+ options . scope !== undefined ) {
122
+
123
+ options . access = [ { entity : options . entity , scope : options . scope } ] ;
124
+ delete options . entity ;
125
+ delete options . scope ;
126
+ }
124
127
125
- for ( let i = 0 ; i < options . scope . length ; ++ i ) {
126
- if ( / { ( [ ^ } ] + ) } / . test ( options . scope [ i ] ) ) {
127
- options . hasScopeParameters = true ;
128
- break ;
128
+ if ( options . access ) {
129
+ for ( let i = 0 ; i < options . access . length ; ++ i ) {
130
+ const access = options . access [ i ] ;
131
+ if ( access . scope ) { // Avoid processing the defaults
132
+ access . hasScopeParameters = false ;
133
+ for ( let j = 0 ; j < access . scope . length ; ++ j ) {
134
+ if ( / { ( [ ^ } ] + ) } / . test ( access . scope [ j ] ) ) {
135
+ access . hasScopeParameters = true ;
136
+ break ;
137
+ }
138
+ }
129
139
}
130
140
}
131
141
}
@@ -135,14 +145,15 @@ internals.Auth.prototype._setupRoute = function (options, path) {
135
145
}
136
146
137
147
let hasAuthenticatePayload = false ;
138
- options . strategies . forEach ( ( name ) => {
139
-
148
+ for ( let i = 0 ; i < options . strategies . length ; ++ i ) {
149
+ const name = options . strategies [ i ] ;
140
150
const strategy = this . _strategies [ name ] ;
141
151
Hoek . assert ( strategy , 'Unknown authentication strategy' , name , 'in' , path ) ;
152
+
142
153
Hoek . assert ( strategy . methods . payload || options . payload !== 'required' , 'Payload validation can only be required when all strategies support it in' , path ) ;
143
154
hasAuthenticatePayload = hasAuthenticatePayload || strategy . methods . payload ;
144
155
Hoek . assert ( ! strategy . methods . options . payload || options . payload === undefined || options . payload === 'required' , 'Cannot set authentication payload to' , options . payload , 'when a strategy requires payload validation in' , path ) ;
145
- } ) ;
156
+ }
146
157
147
158
Hoek . assert ( ! options . payload || hasAuthenticatePayload , 'Payload authentication requires at least one strategy with payload support in' , path ) ;
148
159
@@ -363,60 +374,73 @@ internals.Authenticator = class {
363
374
request . auth . credentials = credentials ;
364
375
request . auth . artifacts = result . artifacts ;
365
376
366
- // Check scope
377
+ const authenticated = ( ) => {
367
378
368
- if ( config . scope ) {
369
- let scopes = config . scope ;
370
- if ( config . hasScopeParameters ) {
371
- scopes = [ ] ;
372
- const context = { params : request . params , query : request . query } ;
373
- for ( let i = 0 ; i < config . scope . length ; ++ i ) {
374
- scopes [ i ] = Hoek . reachTemplate ( context , config . scope [ i ] ) ;
375
- }
376
- }
379
+ request . _log ( [ 'auth' , name ] ) ;
380
+ request . auth . isAuthenticated = true ;
381
+ return next ( ) ;
382
+ } ;
377
383
378
- if ( ! credentials . scope ||
379
- ( typeof credentials . scope === 'string' ? scopes . indexOf ( credentials . scope ) === - 1 : ! Hoek . intersect ( scopes , credentials . scope ) . length ) ) {
384
+ // Check access rules
380
385
381
- request . _log ( [ 'auth' , 'scope' , 'error' , name ] , { got : credentials . scope , need : scopes } ) ;
382
- return next ( Boom . forbidden ( 'Insufficient scope, expected any of: ' + scopes ) ) ;
383
- }
386
+ if ( ! config . access ) {
387
+ return authenticated ( ) ;
384
388
}
385
389
386
- // Check entity
390
+ const requestEntity = ( credentials . user ? 'user' : 'app' ) ;
387
391
388
- const entity = config . entity || 'any' ;
392
+ const scopeErrors = [ ] ;
393
+ for ( let i = 0 ; i < config . access . length ; ++ i ) {
394
+ const access = config . access [ i ] ;
389
395
390
- // Entity: 'any'
396
+ // Check entity
391
397
392
- if ( entity === 'any' ) {
393
- request . _log ( [ 'auth' , name ] ) ;
394
- request . auth . isAuthenticated = true ;
395
- return next ( ) ;
396
- }
398
+ const entity = access . entity ;
399
+ if ( entity &&
400
+ entity !== 'any' &&
401
+ entity !== requestEntity ) {
402
+
403
+ continue ;
404
+ }
397
405
398
- // Entity: 'user'
406
+ // Check scope
399
407
400
- if ( entity === 'user' ) {
401
- if ( ! credentials . user ) {
402
- request . _log ( [ 'auth' , 'entity' , 'user' , 'error' , name ] ) ;
403
- return next ( Boom . forbidden ( 'Application credentials cannot be used on a user endpoint' ) ) ;
408
+ let scope = access . scope ;
409
+ if ( scope ) {
410
+ if ( access . hasScopeParameters ) {
411
+ scope = [ ] ;
412
+ const context = { params : request . params , query : request . query } ;
413
+ for ( let j = 0 ; j < access . scope . length ; ++ j ) {
414
+ scope [ j ] = Hoek . reachTemplate ( context , access . scope [ j ] ) ;
415
+ }
416
+ }
417
+
418
+ if ( ! credentials . scope ||
419
+ ( typeof credentials . scope === 'string' ? scope . indexOf ( credentials . scope ) === - 1 : ! Hoek . intersect ( scope , credentials . scope ) . length ) ) {
420
+
421
+ scopeErrors . push ( scope ) ;
422
+ continue ;
423
+ }
404
424
}
405
425
406
- request . _log ( [ 'auth' , name ] ) ;
407
- request . auth . isAuthenticated = true ;
408
- return next ( ) ;
426
+ return authenticated ( ) ;
409
427
}
410
428
411
- // Entity: 'app'
429
+ // Scope error
412
430
413
- if ( credentials . user ) {
414
- request . _log ( [ 'auth' , 'entity ' , 'app' , ' error', name ] ) ;
415
- return next ( Boom . forbidden ( 'User credentials cannot be used on an application endpoint ' ) ) ;
431
+ if ( scopeErrors . length ) {
432
+ request . _log ( [ 'auth' , 'scope ' , 'error' , name ] , { got : credentials . scope , need : scopeErrors } ) ;
433
+ return next ( Boom . forbidden ( 'Insufficient scope ' ) ) ;
416
434
}
417
435
418
- request . _log ( [ 'auth' , name ] ) ;
419
- request . auth . isAuthenticated = true ;
420
- return next ( ) ;
436
+ // Entity error
437
+
438
+ if ( requestEntity === 'user' ) {
439
+ request . _log ( [ 'auth' , 'entity' , 'user' , 'error' , name ] ) ;
440
+ return next ( Boom . forbidden ( 'Application credentials cannot be used on a user endpoint' ) ) ;
441
+ }
442
+
443
+ request . _log ( [ 'auth' , 'entity' , 'app' , 'error' , name ] ) ;
444
+ return next ( Boom . forbidden ( 'User credentials cannot be used on an application endpoint' ) ) ;
421
445
}
422
446
} ;
0 commit comments