parse-community / parse-community/parse-server

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

Open
#8,116 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

type:question
Dominant language
JavaScript
Stars
21.4k
Forks
4.8k
Avg merge
7h 45m
Merged PRs (30d)
11

Description

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

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reading the Parse.Role relation calls shown: role.relation("roles"), getRoles(), and getUsers(), alongside the ACL examples. Compare the documented nested-role semantics with the expected organization-scoped behavior. Done means the role hierarchy and ACL limitations are explained clearly, with a precise recommended model or documentation change.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, mongodb, node.js
Domain
authorization, backend, documentation
Issue type
Documentation
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.