Issue Description
I have a complex role based design suitable for a SaaS using latest parse SDK/Server
Multiple organisation’s (parent role) which have sub roles (admin, editor, viewer), the sub roles should have permissions only to interact and operate within the context of the organisation. The code which I use to create these base roles is as follows but also maybe i am doing this wrong, lets add in Apple as an organisation, so Microsoft, Apple, admin, editor and viewer are all created in a for loop calling the below function (later I assign each of these roles to be sub roles, correct ?).
try {
const { roleName } = request.params
let role_name = slugify(roleName)
let roleExists: any = await new Parse.Query(Parse.Role).equalTo("name", roleName).first(masterKey)
if(!roleExists) {
let perms = new Parse.Role(role_name, new Parse.ACL());
let result = await perms.save(null, masterKey)
resolve(result)
}
resolve(true)
// reject(`role ${roleName} already exists`)
} catch (error) {
console.log(error)
reject(error)
}
So now I have “Microsoft” and “Apple” roles - these are the parent level role to which all other i.e admin, editor, viewer shall be sub roles. I have the logic in place to add sub roles to each Parent role:
try {
let child: any = await new Parse.Query(Parse.Role).equalTo("name", childRole).first(masterKey)
let parent: any = await new Parse.Query(Parse.Role).equalTo("name", parentRole).first(masterKey)
let query = new Parse.Query(Parse.Role);
query.equalTo("name", parentRole);
let role = <any>await query.first(masterKey)
role.relation("roles").add(child);
await role.save(null, masterKey);
let nestedRoles = await parent.getRoles().query().find(masterKey)
console.log("nestedRoles "+JSON.stringify(nestedRoles))
resolve(nestedRoles)
} catch (error) {
console.log(error)
reject(error)
}
So now our Role structure is like this:
Microsoft => admin => editor => viewer
Apple => admin => editor => viewer
So now I call each parent role, I query for its direct descendant sub roles and I add myself as a user for each of these roles
return new Promise( async (resolve, reject) => {
try {
const user = request.user
const { parentRoleName } = request.params
let parentRole: any = await new Parse.Query(Parse.Role).equalTo("name", parentRoleName).first(masterKey)
let nestedRoles = await parentRole.getRoles().query().find(masterKey)
if(nestedRoles.length) {
nestedRoles.forEach( async (role: any) => {
let childRole: any = await new Parse.Query(Parse.Role).equalTo("name", role.get('name') ).first(masterKey)
childRole.getUsers().add(user)
let saveit = await childRole.save(null, masterKey)
console.log(saveit)
});
resolve( JSON.parse(JSON.stringify(nestedRoles)))
} else {
reject(`${parentRoleName} has no sub/child roles under it.`)
}
} catch (error) {
console.log(error)
reject(error)
}
})
In the parse dashboard, I see all roles, each of the above on the same hierarcy so:
Apple
editor
viewer
admin
Microsoft
if I click on Apple/Microsoft then inside each of these, on the role relations I see as expected editor, viewer and admin.
however if i go back outside to the main 1st level list and click on admin, editor, viewer I see my user object
So if i add editor, viewer, admin to any user then have this feature across both Apple and Microsoft, I get the logic of adding users to roles, adding roles to other roles but how do you lock it down in such a way that each user is assigned to an organization and they have roles within just that organization.
right now my org acl is looking like:
role:admin {
w: true
r: true
}
role:super {
w: true
r: true
}
role:microsoft {
w: true
r: true
}
but i would have thought that because using nested Roles it would first be:
role:super {
w: true
r: true
role:microsoft {
w: true
r: true
role:admin {
w: true
r: true
}
}
}
Role based docs are really lacking, id be happy to try flesh this out because parse security out of the box is not so good, its vital that people understand Roles, ACL proper use of masterkey etc
I guess im curious have I implemented this the way you guys have imagined it should be used, if not how can i refactor to do it by best practice as well as achieve this kind of nested role hierarchy based on organizations and special roles within each organization