Last active
December 8, 2015 22:47
-
-
Save pulkitsinghal/e0c64e647060c205a1e6 to your computer and use it in GitHub Desktop.
How to set user in loopback context for use by remote methods when an arbitrary app token is used by incoming requests?
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// it resides in `/server/boot/` directory | |
'use strict'; | |
var path = require('path'); | |
var fileName = path.basename(__filename, '.js'); // gives the filename without the .js extension | |
var log = require('debug')('boot:'+fileName); | |
module.exports = function(app) { | |
var Role = app.models.Role; | |
Role.registerResolver('customRoleResolver', function(role, context, cb) { | |
log('inside customRoleResolver'); | |
log('role', role); | |
log('context.modelName: ', context.modelName); | |
//log('context.accessToken: ', context.accessToken); | |
var appToken = context.remotingContext.req.header('X-APP-TOKEN'); | |
if (!appToken) { | |
appToken = context.remotingContext.req.query['appToken']; | |
log('context.remotingContext.req.query[appToken]: ', appToken); | |
} | |
else { | |
log('context.remotingContext.req.header(\'X-APP-TOKEN\'): ', appToken); | |
} | |
function reject() { | |
process.nextTick(function() { | |
cb(null, false); // `false` means DENY access; | |
}); | |
} | |
// TODO: test IF any MyModel has a match for given appToken | |
var MyModel = app.models.MyModel; | |
MyModel.findOne({where: {'integrations.thirdPartyAppName.token': appToken} }, | |
function(err, myModel){ | |
log('inside findOne callback', 'myModel:', myModel); | |
if (err) { | |
log('ERROR', err); | |
return reject(); | |
} | |
if (!myModel) { | |
log('ERROR', 'No MyModel associated with this appToken was found.'); | |
return reject(); | |
} | |
var loopback = require('loopback'); // NOTE: moving it to the global scope of this file leads to an undefined loopbackContext | |
var loopbackContext = loopback.getCurrentContext(); | |
if (loopbackContext) { | |
log('loopbackContext', loopbackContext); | |
loopbackContext.set('currentUser', myModel); // info for use by remote methods | |
cb(null, true); // `true` means ALLOW access; | |
} | |
else { | |
log('ERROR', 'Why is there no loopbackContext? `customRoleResolver` cannot work without it'); | |
return reject(); | |
} | |
// TODO: the remote method is still responsible for filtering the results by currentUser's id | |
}); | |
}); | |
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var path = require('path'); | |
var fileName = path.basename(__filename, '.js'); // gives the filename without the .js extension | |
var log = require('debug')('common:models:'+fileName); | |
module.exports = function(SomeModel) { | |
SomeModel.remoteMethod('myRemoteMethodName', { | |
accepts: [], | |
http: {path: '/myRemoteMethodName', verb: 'get'}, | |
returns: {type: 'object', root: true} | |
}); | |
SomeModel.myRemoteMethodName = function(cb) { | |
log('SomeModel.myRemoteMethodName'); | |
var currentUser = SomeModel.getCurrentUserModel(cb); // returns immediately if no currentUser | |
if (currentUser) { | |
var filters = { | |
where: { | |
and: [ | |
{ sellerModelId: currentUser.id}/*, | |
{ other: 'thingsYouCareAbout' }*/ | |
] | |
} | |
}; | |
log('SomeModel.myRemoteMethodName', 'filters:', filters); | |
// filter results by running Model.find(filters); | |
cb(null); | |
} | |
}; | |
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"name": "SomeModel", | |
... | |
"acls": [ | |
... | |
{ | |
"accessType": "EXECUTE", | |
"principalType": "ROLE", | |
"principalId": "$everyone", | |
"permission": "DENY", | |
"property": "myRemoteMethodName" | |
}, | |
{ | |
"accessType": "EXECUTE", | |
"principalType": "ROLE", | |
"principalId": "customRoleResolver", | |
"permission": "ALLOW", | |
"property": "myRemoteMethodName" | |
} | |
], | |
"mixins": { | |
"Utils": true | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// it resides in `/common/mixins/` directory | |
'use strict'; | |
/* jshint ignore:start */ | |
var loopback = require('loopback'); | |
var Promise = require('bluebird'); // jshint ignore:line | |
var path = require('path'); | |
var fileName = path.basename(__filename, '.js'); // gives the filename without the .js extension | |
//var log = require('./../lib/debug-extension')('common:models:'+fileName); | |
var log = require('debug')('common:models:'+fileName); | |
module.exports = function(Model, options) { | |
Model.getCurrentUserModel = function(cb) { | |
var ctx = loopback.getCurrentContext(); | |
var currentUser = ctx && ctx.get('currentUser'); | |
if (currentUser) { | |
log('inside ' + Model.definition.name + '.getCurrentUserModel() - currentUser: ', currentUser.username); | |
//return currentUser; | |
return Promise.promisifyAll( | |
currentUser, | |
{ | |
filter: function(name, func, target){ | |
return (name !== 'validate'); | |
} | |
} | |
); | |
} | |
else { | |
// TODO: when used with core invocations, the call stack can end up here | |
// this error only makes sense to point out failures in RESTful calls | |
// how can this sanity check be made any better? | |
cb('401 - unauthorized - how did we end up here? should we manage ACL access to remote methods ourselves?'); | |
} | |
}; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment