Skip to content

Parse Roles nested hierarchy either not working, not possible or misleading docs #8116

Open
@REPTILEHAUS

Description

@REPTILEHAUS

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

Steps to reproduce

code provided above

Actual Outcome

as mentioned above

Expected Outcome

as mentioned above

Server

  • Parse Server version: latest
  • Operating system: linux
  • Local or remote host (AWS, Azure, Google Cloud, Heroku, Digital Ocean, etc): local and remove on aws

Database

  • System (MongoDB or Postgres): mongo
  • Database version: 4
  • Local or remote host (MongoDB Atlas, mLab, AWS, Azure, Google Cloud, etc): MongoDB Atlas

Client

  • SDK (iOS, Android, JavaScript, PHP, Unity, etc): JavaScript
  • SDK version: latest

Logs

none to provide

Metadata

Metadata

Assignees

No one assigned

    Labels

    type:questionSupport or code-level question

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions