Parse-server: ACL on object field level

Created on 13 Nov 2017  路  6Comments  路  Source: parse-community/parse-server

If I don't like to use Parse Cloud Code Solution, how can I implement ACL on field level?
Because I want to grant permission on some fields for some people can update, some people only view, and some people won't see some fields?

Can I do it with a best practice solution?

Thanks a lot!

stale

Most helpful comment

I implement this in a similar way to @trylovetom, within before* triggers. Example function for checking if user has a role:

export const getUserRoles = (user, options) => {
    // eslint-disable-next-line
    return new Parse.Query('_Role').equalTo('users', user).find(options)
    .then((roles) => {
        return Promise.resolve(roles.map((r) => r.get('name')))
    })
}

export const userHasRole = (user, roleName, options) => {

    if (!user) {
        console.warn('Warning: no user, assume master key and say user has role')
    }

    return getUserRoles(user, options)
    .then((roles) => {
        return Promise.resolve(roles.includes(roleName))
    })
}

export const reqHasRole = (req, roleName, options) => {
    if (req.master) {
        console.warn('Master key has role', roleName)
        return Promise.resolve(true);
    } else {
        return userHasRole(req.user, roleName, options)
    }
}

In trigger (or any cloud code function with a req object):

return auth.reqHasRole(req, parentOrgAdminRoleName)
            .then((userHasAdminRole) => {
                if (!userHasAdminRole) {
                    return Promise.reject('Only admins of parentOrganization can create subOrgs')
                } else {
                    return Promise.resolve()
                }
            })

All 6 comments

Is it crazy if I create each role for each field, and create a high-level role is a set of children role?
E.g. I have a schema such as:

schema_a: {
     field_1,
     field_2,
     field_3,
     field_4,
     field_5,
     field_6
}

I'll a list of roles:

role_field_1_r
role_field_2_w
role_field_2_r
role_field_3_w
role_field_3_r
role_field_4_w
role_field_4_r
role_field_5_w
role_field_5_r
role_field_6_w
role_field_6_r

Example I have 2 groups:

  • Group A with Read-Write permission on fields: field_1, field_2, field_3 so I will create a role with name: group_a_role with children role is:
role_field_1_r
role_field_2_w
role_field_2_r
role_field_3_w
role_field_3_r
  • Group B with Read permission on fields: field_1, field_2, field_3, so I will create a role with name: group_b_role with children role is:
role_field_2_r
role_field_3_r

Yes pretty crazy indeed

The easiest way to realize it, would be to code a proof of concept yourself :)

Write the fields level permission check module and put it in BeforeSave Triggers, BeforeDelete Triggers, BeforeFind Triggers.

I implement this in a similar way to @trylovetom, within before* triggers. Example function for checking if user has a role:

export const getUserRoles = (user, options) => {
    // eslint-disable-next-line
    return new Parse.Query('_Role').equalTo('users', user).find(options)
    .then((roles) => {
        return Promise.resolve(roles.map((r) => r.get('name')))
    })
}

export const userHasRole = (user, roleName, options) => {

    if (!user) {
        console.warn('Warning: no user, assume master key and say user has role')
    }

    return getUserRoles(user, options)
    .then((roles) => {
        return Promise.resolve(roles.includes(roleName))
    })
}

export const reqHasRole = (req, roleName, options) => {
    if (req.master) {
        console.warn('Master key has role', roleName)
        return Promise.resolve(true);
    } else {
        return userHasRole(req.user, roleName, options)
    }
}

In trigger (or any cloud code function with a req object):

return auth.reqHasRole(req, parentOrgAdminRoleName)
            .then((userHasAdminRole) => {
                if (!userHasAdminRole) {
                    return Promise.reject('Only admins of parentOrganization can create subOrgs')
                } else {
                    return Promise.resolve()
                }
            })

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

jaydeep82 picture jaydeep82  路  4Comments

jiawenzhang picture jiawenzhang  路  4Comments

kilabyte picture kilabyte  路  4Comments

sanergulec picture sanergulec  路  4Comments

lorki picture lorki  路  3Comments