@@ -4,7 +4,7 @@ const debug = require('debug')('loopback:componenet:access');
4
4
const createPromiseCallback = require ( 'loopback-datasource-juggler/lib/utils' ) . createPromiseCallback ;
5
5
const _defaults = require ( 'lodash' ) . defaults ;
6
6
const _get = require ( 'lodash' ) . get ;
7
- const Promise = require ( " bluebird" ) ;
7
+ const Promise = require ( ' bluebird' ) ;
8
8
9
9
module . exports = class AccessUtils {
10
10
constructor ( app , options ) {
@@ -57,18 +57,27 @@ module.exports = class AccessUtils {
57
57
const currentUser = this . getCurrentUser ( ) ;
58
58
59
59
if ( currentUser ) {
60
- // Do noinvoice if options.skipAccess has been set.
60
+ // Do not filter if options.skipAccess has been set.
61
61
if ( ctx . options . skipAccess ) {
62
62
debug ( 'skipAccess: true - skipping access filters' ) ;
63
63
return next ( ) ;
64
64
}
65
65
66
- // Do noinvoice if the request is being made against a single model instance.
66
+ // Do not filter if the request is being made against a single model instance.
67
67
if ( _get ( ctx . query , 'where.id' ) ) {
68
68
debug ( 'looking up by Id - skipping access filters' ) ;
69
69
return next ( ) ;
70
70
}
71
71
72
+ // Do not apply filters if no group access acls were applied.
73
+ const loopbackContext = this . app . loopback . getCurrentContext ( ) ;
74
+ const groupAccessApplied = loopbackContext && loopbackContext . get ( 'groupAccessApplied' ) || false ;
75
+
76
+ if ( ! groupAccessApplied ) {
77
+ debug ( 'acls not appled - skipping access filters' ) ;
78
+ return next ( ) ;
79
+ }
80
+
72
81
debug ( '%s observe access: query=%s, options=%o, hookState=%o' ,
73
82
Model . modelName , JSON . stringify ( ctx . query , null , 4 ) , ctx . options , ctx . hookState ) ;
74
83
@@ -259,19 +268,19 @@ module.exports = class AccessUtils {
259
268
const Role = this . app . models [ this . options . roleModel ] ;
260
269
261
270
Role . registerResolver ( accessGroup , ( role , context , cb ) => {
262
- const currentUserId = context . accessToken . userId ;
271
+ const currentUser = this . getCurrentUser ( ) ;
263
272
const roleName = this . extractRoleName ( role ) ;
264
273
const GroupAccess = this . app . models [ this . options . groupAccessModel ] ;
265
274
const scope = { } ;
266
275
267
276
// Do not allow anonymous users.
268
- if ( ! currentUserId ) {
277
+ if ( ! currentUser ) {
269
278
debug ( 'access denied for anonymous user' ) ;
270
279
return process . nextTick ( ( ) => cb ( null , false ) ) ;
271
280
}
272
281
273
282
debug ( `Role resolver for ${ role } : evaluate ${ context . model . definition . name } with id: ${ context . modelId } ` +
274
- ` for currentUserId : ${ currentUserId } ` ) ;
283
+ ` for currentUser.getId() : ${ currentUser . getId ( ) } ` ) ;
275
284
276
285
return Promise . join ( this . getCurrentGroupId ( context ) , this . getTargetGroupId ( context ) ,
277
286
( currentGroupId , targetGroupId ) => {
@@ -284,7 +293,10 @@ module.exports = class AccessUtils {
284
293
scope . currentGroupId = currentGroupId ;
285
294
scope . targetGroupId = targetGroupId ;
286
295
const actions = [ ] ;
287
- const conditions = { userId : currentUserId , role : roleName } ;
296
+ const conditions = {
297
+ userId : currentUser . getId ( ) ,
298
+ role : roleName
299
+ } ;
288
300
289
301
conditions [ this . options . foreignKey ] = currentGroupId ;
290
302
actions . push ( GroupAccess . count ( conditions ) ) ;
@@ -298,24 +310,35 @@ module.exports = class AccessUtils {
298
310
return actions ;
299
311
} )
300
312
. spread ( ( currentGroupCount , targetGroupCount ) => {
313
+ let res = false ;
314
+
301
315
if ( currentGroupCount === false ) {
302
316
// No group context was determined, so allow passthrough access.
303
- return cb ( null , true ) ;
317
+ res = true ;
304
318
}
305
- const cMember = currentGroupCount > 0 ;
319
+ else {
320
+ // Determine grant based on the current/target group context.
321
+ res = currentGroupCount > 0 ;
322
+
323
+ debug ( `user ${ currentUser . getId ( ) } ${ res ? 'is a' : 'is not a' } ` +
324
+ `${ roleName } of group ${ scope . currentGroupId } ` ) ;
306
325
307
- debug ( `user ${ currentUserId } ${ cMember ? 'is a' : 'is not a' } ${ roleName } of group ${ scope . currentGroupId } ` ) ;
326
+ // If it's an attempt to save into a new group, also ensure the user has access to the target group.
327
+ if ( scope . targetGroupId && scope . targetGroupId !== scope . currentGroupId ) {
328
+ const tMember = targetGroupCount > 0 ;
308
329
309
- // If it's an attempt to save the item into a new group, also ensure the user has access to the target group.
310
- if ( scope . targetGroupId && scope . targetGroupId !== scope . currentGroupId ) {
311
- const tMember = targetGroupCount > 0 ;
330
+ debug ( `user ${ currentUser . getId ( ) } ${ tMember ? 'is a' : 'is not a' } ` +
331
+ `${ roleName } of group ${ scope . targetGroupId } ` ) ;
332
+ res = res && tMember ;
333
+ }
334
+ }
312
335
313
- debug ( `user ${ currentUserId } ${ tMember ? 'is a' : 'is not a' } ${ roleName } of group ${ scope . targetGroupId } ` ) ;
314
- return cb ( null , cMember && tMember ) ;
336
+ // Note the fact that we are allowing access due to passing an ACL.
337
+ if ( res ) {
338
+ this . app . loopback . getCurrentContext ( ) . set ( 'groupAccessApplied' , true ) ;
315
339
}
316
340
317
- // Otherwise, base access on the current group membership only.
318
- return cb ( null , cMember ) ;
341
+ return cb ( null , res ) ;
319
342
} )
320
343
. catch ( cb ) ;
321
344
} ) ;
0 commit comments