Last active
February 13, 2018 18:43
-
-
Save pulkitsinghal/1152cad3b66a640a0d52e007ee8aa373 to your computer and use it in GitHub Desktop.
Raw source for the steps in add-multi-tenancy.md
This file contains 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
module.exports = function(app){ | |
var RoleMapping = app.models.RoleMapping; | |
var UserModel = app.models.UserModel; | |
var Role = app.models.Role; | |
RoleMapping.belongsTo(UserModel); | |
UserModel.hasMany(RoleMapping, {foreignKey: 'principalId'}); | |
UserModel.hasMany(Role, {as:'roles', through: RoleMapping, foreignKey: 'principalId'}); | |
Role.hasMany(UserModel, {through: RoleMapping, foreignKey: 'roleId'}); | |
}; |
This file contains 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
'use strict'; | |
module.exports = function (app, cb) { | |
var Role = app.models.Role; | |
var Promise = require('bluebird'); // jshint ignore:line | |
Promise.resolve() | |
.then(function () { | |
return Role.findOrCreate( | |
{where: {name: 'orgAdmin'}}, // either find | |
{ // or create | |
name: 'orgAdmin', | |
description: 'Org Admins' + '\n' + | |
'- should be able to read-update-delete their organization' + '\n' + | |
'- should be able to create-read-update-delete any users within their organization' + '\n' + | |
'- should be able to add new users to their organization' | |
} | |
); | |
}) | |
.spread(function (created, found) { | |
return Role.findOrCreate( | |
{where: {name: 'orgUser'}}, // either find | |
{ // or create | |
name: 'orgUser', | |
description: 'Org Users' + '\n' + | |
'- should be able to create-read-update-delete any models within their organization, other than OrgModel' | |
} | |
); | |
}) | |
.spread(function (created, found) { | |
return cb(); | |
}) | |
.catch(function (error) { | |
return cb(error); | |
}); | |
}; |
This file contains 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
'use strict'; | |
module.exports = function (app) { | |
var Role = app.models.Role; | |
var roles = [ | |
'orgAdmin', | |
'orgUser' | |
]; | |
var _ = require('underscore'); | |
_.each(roles, function (eachRole) { | |
var log = require('debug')('loopback:security:role-resolver:'+eachRole); | |
Role.registerResolver(eachRole, function (role, context, cb) { | |
function reject(reason, err) { | |
log('DENY' | |
+ '\n' + '\t' + context.remotingContext.req.method + ' ' + context.remotingContext.req.originalUrl | |
+ '\n' + '\t' + 'Reason: ' +reason); | |
if (err) { | |
return cb(err); | |
} | |
cb(null, false); | |
} | |
if (context.modelName !== 'OrgModel') { | |
return reject('target model is not OrgModel'); // return error if target model is not OrgModel | |
} | |
var currentOrg = context.modelId; | |
if (!currentOrg) { | |
return reject('an exact OrgModel isn\'t specified'); // return error if an exact OrgModel isn't specified | |
} | |
var currentUserId = context.accessToken.userId; | |
if (!currentUserId) { | |
return reject('do not allow unauthenticated users to proceed'); // do not allow unauthenticated users to proceed | |
} | |
else { | |
app.models.UserModel.findById(currentUserId, { | |
include: { | |
relation: 'roles', | |
scope: { | |
fields: ['name'] // only include the role name and id | |
} | |
} | |
}) | |
.then(function (userModelInstance) { | |
if(!userModelInstance.orgModelId){ | |
return reject('user does not belong to any organization'); // reject users who do not belong to any organization | |
} | |
if (!_.isEqual(userModelInstance.orgModelId.toString(), currentOrg.toString())) { | |
return reject('user does not belong to the given organization'); // reject users who do not belong to the given organization | |
} | |
var isValidUser = _.findWhere(userModelInstance.roles(), {name: eachRole}); | |
if(!isValidUser) { | |
return reject('user does not have this role '+eachRole+' assigned'); // reject users who haven't been assigned the given role | |
} | |
else { | |
log('ALLOW an authenticated user who belongs to this organization and has this role assigned'); | |
return cb(null, true); | |
} | |
}) | |
.catch(function (error) { | |
cb(error); | |
}); | |
} | |
}); | |
}); | |
}; |
This file contains 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
module.exports = function (OrgModel) { | |
// Hiding methods and REST endpoints | |
// https://loopback.io/doc/en/lb3/Exposing-models-over-REST.html#hiding-methods-and-rest-endpoints | |
// Clients should not be able to create organizations | |
OrgModel.disableRemoteMethodByName("create"); // disables POST /OrgModels | |
OrgModel.disableRemoteMethodByName("upsert"); // disables PATCH /OrgModels | |
OrgModel.disableRemoteMethodByName("replaceOrCreate"); // disables PUT /OrgModels | |
OrgModel.disableRemoteMethodByName("replaceById"); // disables PUT /OrgModels/{id} | |
OrgModel.disableRemoteMethodByName("upsertWithWhere"); // disables POST /OrgModels/upsertWithWhere | |
// Clients should not be able to discover organizations | |
OrgModel.disableRemoteMethodByName("count"); // disables HEAD /OrgModels/count | |
OrgModel.disableRemoteMethodByName("find"); // disables GET /OrgModels | |
OrgModel.disableRemoteMethodByName("findOne"); // disables GET /OrgModels/findOne | |
OrgModel.disableRemoteMethodByName("findById"); // disables GET /OrgModels/{id} | |
OrgModel.disableRemoteMethodByName("exists"); // disables HEAD /OrgModels/{id} | |
// Certain organization operations should take place on server-side only | |
// and aren't meant to be exposed to the client-side | |
//OrgModel.disableRemoteMethodByName("update"); // disables POST /OrgModels/update | |
//OrgModel.disableRemoteMethodByName("prototype.updateAttributes"); // disables PATCH /OrgModels/{id} | |
//OrgModel.disableRemoteMethodByName("deleteById"); // disables DELETE /OrgModels/{id} | |
// An organization does not need login related functionality | |
OrgModel.disableRemoteMethodByName('login'); | |
OrgModel.disableRemoteMethodByName('logout'); | |
OrgModel.disableRemoteMethodByName('confirm'); | |
OrgModel.disableRemoteMethodByName("resetPassword"); // disables POST /OrgModels/reset | |
OrgModel.disableRemoteMethodByName("setPassword"); // disables POST /OrgModels/reset-password | |
OrgModel.disableRemoteMethodByName("prototype.verify"); // disable POST /OrgModels/{id}/verify | |
OrgModel.disableRemoteMethodByName("changePassword"); // disable POST /OrgModels/change-password | |
// Don't expose what you don't need to | |
OrgModel.disableRemoteMethodByName("createChangeStream"); // disable GET and POST /OrgModels/change-stream | |
// An organization does not need accessToken related functionality | |
OrgModel.disableRemoteMethodByName('prototype.__count__accessTokens'); | |
OrgModel.disableRemoteMethodByName('prototype.__create__accessTokens'); | |
OrgModel.disableRemoteMethodByName('prototype.__delete__accessTokens'); | |
OrgModel.disableRemoteMethodByName('prototype.__destroyById__accessTokens'); | |
OrgModel.disableRemoteMethodByName('prototype.__findById__accessTokens'); | |
OrgModel.disableRemoteMethodByName('prototype.__get__accessTokens'); | |
OrgModel.disableRemoteMethodByName('prototype.__updateById__accessTokens'); | |
OrgModel.on('dataSourceAttached', function () { | |
delete OrgModel.validations.password; // An organization does not require a password | |
}); | |
OrgModel.on('attached', function () { | |
var app = OrgModel.app; | |
/** | |
* Any OrgModel related validations should be placed here | |
*/ | |
OrgModel.validatesUniquenessOf('email'); | |
}); | |
}; |
This file contains 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": "OrgModel", | |
"base": "User", | |
"idInjection": true, | |
"options": { | |
"validateUpsert": true | |
}, | |
"properties": { | |
"name": { | |
"type": "string", | |
"required": true, | |
"default": "none" | |
}, | |
"email": { | |
"type": "string" | |
} | |
}, | |
"validations": [], | |
"relations": { | |
}, | |
"acls": [ | |
], | |
"methods": {} | |
} |
This file contains 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": "OrgModel", | |
"base": "User", | |
"idInjection": true, | |
"options": { | |
"validateUpsert": true | |
}, | |
"properties": { | |
"name": { | |
"type": "string", | |
"required": true, | |
"default": "none" | |
}, | |
"email": { | |
"type": "string" | |
} | |
}, | |
"validations": [], | |
"relations": { | |
"users": { | |
"type": "hasMany", | |
"model": "UserModel", | |
"foreignKey": "orgModelId" | |
} | |
}, | |
"acls": [ | |
], | |
"methods": {} | |
} |
This file contains 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": "OrgModel", | |
"base": "User", | |
"idInjection": true, | |
"options": { | |
"validateUpsert": true | |
}, | |
"properties": { | |
"name": { | |
"type": "string", | |
"required": true, | |
"default": "none" | |
}, | |
"email": { | |
"type": "string" | |
} | |
}, | |
"validations": [], | |
"relations": { | |
"users": { | |
"type": "hasMany", | |
"model": "UserModel", | |
"foreignKey": "orgModelId" | |
} | |
}, | |
"acls": [ | |
{ | |
"description": "DENY any and all requests which we do not explicitly ALLOW", | |
"accessType": "*", | |
"principalType": "ROLE", | |
"principalId": "$everyone", | |
"permission": "DENY" | |
}, | |
{ | |
"description": "Admins can CRUD users within their own org", | |
"accessType": "EXECUTE", | |
"principalType": "ROLE", | |
"principalId": "orgAdmin", | |
"permission": "ALLOW", | |
"property": [ | |
"__count__users", | |
"__create__users", | |
"__delete__users", | |
"__destroyById__users", | |
"__findById__users", | |
"__get__users", | |
"__updateById__users" | |
] | |
} | |
], | |
"methods": {} | |
} |
This file contains 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": "OrgModel", | |
"base": "User", | |
"idInjection": true, | |
"options": { | |
"validateUpsert": true | |
}, | |
"mixins": { | |
}, | |
"properties": { | |
"name": { | |
"type": "string", | |
"required": true, | |
"default": "none" | |
}, | |
"email": { | |
"type": "string" | |
} | |
}, | |
"validations": [], | |
"relations": { | |
"users": { | |
"type": "hasMany", | |
"model": "UserModel", | |
"foreignKey": "orgModelId" | |
}, | |
"stuffModels": { | |
"type": "hasMany", | |
"model": "StuffModel", | |
"foreignKey": "orgModelId" | |
} | |
}, | |
"acls": [ | |
{ | |
"description": "DENY any and all requests which we do not explicitly ALLOW", | |
"accessType": "*", | |
"principalType": "ROLE", | |
"principalId": "$everyone", | |
"permission": "DENY" | |
}, | |
{ | |
"description": "Admins can CRUD users within their own org", | |
"accessType": "EXECUTE", | |
"principalType": "ROLE", | |
"principalId": "orgAdmin", | |
"permission": "ALLOW", | |
"property": [ | |
"__count__users", | |
"__create__users", | |
"__delete__users", | |
"__destroyById__users", | |
"__findById__users", | |
"__get__users", | |
"__updateById__users" | |
] | |
}, | |
{ | |
"description": "Users can CRUD stuff within their own org", | |
"accessType": "EXECUTE", | |
"principalType": "ROLE", | |
"principalId": "orgUser", | |
"permission": "ALLOW", | |
"property": [ | |
"__count__stuffModels", | |
"__create__stuffModels", | |
"__delete__stuffModels", | |
"__destroyById__stuffModels", | |
"__findById__stuffModels", | |
"__get__stuffModels", | |
"__updateById__stuffModels" | |
] | |
} | |
], | |
"methods": {} | |
} |
This file contains 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
module.exports = function(StuffModel) { | |
}; |
This file contains 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": "StuffModel", | |
"base": "PersistedModel", | |
"idInjection": true, | |
"options": { | |
"validateUpsert": true | |
}, | |
"mixins": { | |
}, | |
"properties": { | |
"name": { | |
"type": "string", | |
"required": true | |
} | |
}, | |
"validations": [], | |
"relations": { | |
"org": { | |
"type": "belongsTo", | |
"model": "OrgModel", | |
"foreignKey": "orgModelId", | |
"scope": { | |
"fields": { | |
"id": true, | |
"name": true, | |
"uniqueName": true | |
} | |
} | |
} | |
}, | |
"acls": [ | |
{ | |
"description": "DENY any and all requests which we do not explicitly ALLOW", | |
"accessType": "*", | |
"principalType": "ROLE", | |
"principalId": "$everyone", | |
"permission": "DENY" | |
} | |
], | |
"methods": {} | |
} |
This file contains 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); | |
var Promise = require('bluebird'); | |
var Joi = Promise.promisifyAll(require('joi')); | |
var validate = Promise.promisify(require('joi').validate); | |
var _ = require('underscore'); | |
module.exports = function (UserModel) { | |
// Hiding methods and REST endpoints | |
// https://loopback.io/doc/en/lb3/Exposing-models-over-REST.html#hiding-methods-and-rest-endpoints | |
// Clients should not be able to create users (BUT signups are a different story) | |
UserModel.disableRemoteMethodByName("create"); // disables POST /UserModels | |
UserModel.disableRemoteMethodByName("upsert"); // disables PATCH /UserModels | |
UserModel.disableRemoteMethodByName("replaceOrCreate"); // disables PUT /UserModels | |
UserModel.disableRemoteMethodByName("replaceById"); // disables PUT /UserModels/{id} | |
UserModel.disableRemoteMethodByName("upsertWithWhere"); // disables POST /UserModels/upsertWithWhere | |
UserModel.on('attached', function () { | |
var app = UserModel.app; | |
var Role = app.models.Role; | |
var RoleMapping = app.models.RoleMapping; | |
UserModel.remoteMethod('signup', { | |
accepts: [ | |
{ arg: 'data', type: 'object', required: true, http: { source: 'body' } }, | |
{ arg: 'options', type: 'object', http: 'optionsFromRequest' } | |
], | |
http: { path: '/signup', verb: 'post' }, | |
returns: { type: 'string', root: true } | |
}); | |
UserModel.signup = function (data, options, cb) { | |
log('initiating sign-up', data); | |
var OrgModel = UserModel.app.models.OrgModel; | |
var validObjectSchema = Joi.object().keys({ | |
'orgName': Joi.string().required(), | |
'email': Joi.string().email().required(), | |
'password': Joi.string().min(8).max(15).required() | |
}); | |
var orgData = { | |
name: data.orgName, | |
email: data.email | |
}; | |
delete data.username; | |
var orgCreated = {}; | |
var userCreated = {}; | |
validate(data, validObjectSchema) | |
.then(function () { | |
return OrgModel.create(orgData); | |
}) | |
.then(function (orgInstance) { | |
delete data.orgName; | |
data.username = data.email; | |
orgCreated = orgInstance; //creating object reference instead of copying, so that can be accessed in catch block | |
return orgInstance.users.create(data, options); | |
}) | |
.then(function (userInstance) { | |
userCreated = userInstance; | |
cb(null, userCreated); | |
}) | |
.catch(function (error) { | |
log('Error creating organization, rolling back ...', JSON.stringify(error, null, 2)); | |
if (!_.isEmpty(orgCreated)) { | |
OrgModel.deleteById(orgCreated.id) | |
.then(function () { | |
if (!_.isEmpty(userCreated)) { | |
return UserModel.deleteById(userCreated.id); | |
} | |
else { | |
return Promise.resolve(); | |
} | |
}) | |
.then(function () { | |
if (error && error.details && error.details.codes && error.details.codes.email && error.details.codes.email[0] === 'uniqueness') { | |
cb({ 'property': 'email', 'message': 'This email address already exists.' }); | |
} | |
else { | |
cb('Internal Server Error. Please try again.'); | |
} | |
}) | |
.catch(function (anotherError) { | |
log('signup error', anotherError); | |
cb('Internal Server Error. Please try again.'); | |
}); | |
} | |
else { | |
cb(error); | |
} | |
}); | |
}; | |
}); | |
}; |
This file contains 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": "UserModel", | |
"base": "User", | |
"idInjection": true, | |
"options": { | |
"validateUpsert": true | |
}, | |
"mixins": { | |
}, | |
"properties": { | |
}, | |
"validations": [], | |
"relations": { | |
"org": { | |
"type": "belongsTo", | |
"model": "OrgModel", | |
"foreignKey": "orgModelId" | |
} | |
}, | |
"acls": [ | |
{ | |
"description": "DENY any and all requests which we do not explicitly ALLOW", | |
"accessType": "*", | |
"principalType": "ROLE", | |
"principalId": "$everyone", | |
"permission": "DENY" | |
}, | |
{ | |
"description": "Anyone can signup", | |
"accessType": "EXECUTE", | |
"principalType": "ROLE", | |
"principalId": "$everyone", | |
"permission": "ALLOW", | |
"property": "signup" | |
} | |
], | |
"methods": {} | |
} |
This file contains 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); | |
var Promise = require('bluebird'); | |
var Joi = Promise.promisifyAll(require('joi')); | |
var validate = Promise.promisify(require('joi').validate); | |
var _ = require('underscore'); | |
module.exports = function (UserModel) { | |
// Hiding methods and REST endpoints | |
// https://loopback.io/doc/en/lb3/Exposing-models-over-REST.html#hiding-methods-and-rest-endpoints | |
// Clients should not be able to create users (BUT signups are a different story) | |
UserModel.disableRemoteMethodByName("create"); // disables POST /UserModels | |
UserModel.disableRemoteMethodByName("upsert"); // disables PATCH /UserModels | |
UserModel.disableRemoteMethodByName("replaceOrCreate"); // disables PUT /UserModels | |
UserModel.disableRemoteMethodByName("replaceById"); // disables PUT /UserModels/{id} | |
UserModel.disableRemoteMethodByName("upsertWithWhere"); // disables POST /UserModels/upsertWithWhere | |
UserModel.on('attached', function () { | |
var app = UserModel.app; | |
var Role = app.models.Role; | |
var RoleMapping = app.models.RoleMapping; | |
/** | |
* Overrides the `create` method | |
* - must restrict access so its only called from server-side and not client-side | |
*/ | |
var overriddenCreate = UserModel.create; | |
UserModel.create = function(data, options, callback) { | |
log('OVERRIDING UserModel create method'); | |
console.assert(data.orgModelId); // sanity check | |
// if its a direct api call via `POST /OrgModels/:id/users` then loopback will add this value | |
// if its a server side api by developers then they must add this value | |
// handle both callbacks and promise based invocations | |
var loopbackUtils = require('loopback/lib/utils'); | |
originalCallback = callback || loopbackUtils.createPromiseCallback(); | |
// nest callbacks to attach desired functionality, post-create | |
callback = function(error, userInstance) { | |
if (error) { | |
originalCallback(error); | |
} | |
else { | |
// Is `selfEditingOrgUser` a better role name than `orgUser:self` ??? | |
// if the code was not split across two "boot" files then | |
// there wouldn't be need to register a role resolver under the name `orgUser:self` | |
// because having all the code under one file registered with role-resolver named `orgUser` | |
// would let us handle permissions to OrgModel and UserModel in one place under one named role | |
var rolesToAssign = ['orgUser', 'orgUser:self']; | |
UserModel.assignRoles(rolesToAssign, userInstance, options) | |
.then(function(){ | |
originalCallback(null, userInstance); | |
}) | |
.catch(function(error){ | |
originalCallback(error); | |
}); | |
} | |
}; | |
// call original `create` method | |
var self = this; | |
var argsForCreate = arguments; | |
overriddenCreate.apply(self, argsForCreate); | |
}; // END of UserModel.create | |
UserModel.remoteMethod('signup', { | |
accepts: [ | |
{ arg: 'data', type: 'object', required: true, http: { source: 'body' } }, | |
{ arg: 'options', type: 'object', http: 'optionsFromRequest' } | |
], | |
http: { path: '/signup', verb: 'post' }, | |
returns: { type: 'string', root: true } | |
}); | |
UserModel.signup = function (data, options, cb) { | |
log('initiating sign-up', data); | |
var OrgModel = UserModel.app.models.OrgModel; | |
var validObjectSchema = Joi.object().keys({ | |
'orgName': Joi.string().required(), | |
'email': Joi.string().email().required(), | |
'password': Joi.string().min(8).max(15).required() | |
}); | |
var orgData = { | |
name: data.orgName, | |
email: data.email | |
}; | |
delete data.username; | |
var orgCreated = {}; | |
var userCreated = {}; | |
validate(data, validObjectSchema) | |
.then(function () { | |
return OrgModel.create(orgData); | |
}) | |
.then(function (orgInstance) { | |
delete data.orgName; | |
data.username = data.email; | |
orgCreated = orgInstance; //creating object reference instead of copying, so that can be accessed in catch block | |
return orgInstance.users.create(data, options); | |
}) | |
.then(function (userInstance) { | |
userCreated = userInstance; | |
var rolesToAssign = ['orgAdmin']; // for users who "self-signup", one additional role MUST be that of `orgAdmin` | |
return UserModel.assignRoles(rolesToAssign, userInstance, options); | |
}) | |
.then(function () { | |
cb(null, userCreated); | |
}) | |
.catch(function (error) { | |
log('Error creating organization, rolling back ...', JSON.stringify(error, null, 2)); | |
if (!_.isEmpty(orgCreated)) { | |
OrgModel.deleteById(orgCreated.id) | |
.then(function () { | |
if (!_.isEmpty(userCreated)) { | |
return UserModel.deleteById(userCreated.id); | |
} | |
else { | |
return Promise.resolve(); | |
} | |
}) | |
.then(function () { | |
if (error && error.details && error.details.codes && error.details.codes.email && error.details.codes.email[0] === 'uniqueness') { | |
cb({ 'property': 'email', 'message': 'This email address already exists.' }); | |
} | |
else { | |
cb('Internal Server Error. Please try again.'); | |
} | |
}) | |
.catch(function (anotherError) { | |
log('signup error', anotherError); | |
cb('Internal Server Error. Please try again.'); | |
}); | |
} | |
else { | |
cb(error); | |
} | |
}); | |
}; | |
UserModel.assignRoles = function (rolesToAssign, userInstance, options) { | |
var Role = UserModel.app.models.Role; | |
var RoleMapping = UserModel.app.models.RoleMapping; | |
var orConditions = []; | |
rolesToAssign.forEach(function (eachRole) { | |
orConditions.push({ name: eachRole }); | |
}); | |
return Role.find({ | |
where: { | |
or: orConditions | |
} | |
}) | |
.then(function (roles) { | |
return Promise.map(roles, function (eachRole) { | |
log('Assigning role ' + eachRole.name); | |
return RoleMapping.create({ roleId: eachRole.id, principalId: userInstance.id }); | |
}); | |
}) | |
.then(function (result) { | |
log('Finished assigning roles to user'); | |
return Promise.resolve(result); | |
}) | |
.catch(function (error) { | |
log('Error assigning roles', error); | |
return Promise.reject(error); | |
}); | |
}; | |
}); | |
}; |
This file contains 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": "UserModel", | |
"base": "User", | |
"idInjection": true, | |
"options": { | |
"validateUpsert": true | |
}, | |
"mixins": { | |
"TimeStamp": { | |
"createdAt" : "created", | |
"updatedAt" : "modified", | |
"required" : true | |
}, | |
"Context": {}, | |
"ResetPassword": {} | |
}, | |
"properties": { | |
}, | |
"validations": [], | |
"relations": { | |
"org": { | |
"type": "belongsTo", | |
"model": "OrgModel", | |
"foreignKey": "orgModelId" | |
} | |
}, | |
"acls": [ | |
{ | |
"description": "DENY any and all requests which we do not explicitly ALLOW", | |
"accessType": "*", | |
"principalType": "ROLE", | |
"principalId": "$everyone", | |
"permission": "DENY" | |
}, | |
{ | |
"description": "Anyone can signup", | |
"accessType": "EXECUTE", | |
"principalType": "ROLE", | |
"principalId": "$everyone", | |
"permission": "ALLOW", | |
"property": "signup" | |
}, | |
{ | |
"description": "Users can access their own profile", | |
"accessType": "EXECUTE", | |
"principalType": "ROLE", | |
"principalId": "$owner", | |
"permission": "ALLOW", | |
"property": "profile" | |
} | |
], | |
"methods": {} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment