question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Question about operating with fields that have access restrictions

See original GitHub issue

After some playing with it and cross-referencing with the docs for my current requirements, I’m still not quite sure if I’m doing it right. Would like to ask if there are other ways of doing things as I’m quite uncertain at this point.

Scenario:

  1. A user can have many roles.
  2. There are 2 roles concerned about an update operation, HR and the default role for employees. The default role applies to everyone so HR also inherits the default role along with its associated permissions.
  3. HR can edit more fields (e.g. Job Title, Employment Status) for an employee (can only edit basic profile).
  4. I use TS w/ ObjectionJS + GraphQL and there’s only one mutation operation for editing the employee entity/model.
  5. On the frontend side, there’s only one component for both create/edit forms so there’d be fields that are hidden/shown based on your role and permissions for certain fields.
  6. I’d like to pick fields based on the user’s permissions when doing an operation that involves writing to the database.

So when editing information about an employee, depending on your role, there’d be certain fields that shouldn’t go through the Objection model.

Say we have the Employee model as:

class Employee {
  id: string;
  firstname: string;
  lastname: string;
  workEmail: string;
  jobTitleId: string;
  employmentStatus: EmploymentStatus;  // where EmploymentStatus is an enum
}

If you have the default role, you

can('update', 'Employee', ['firstname', 'lastname']);
cannot('update', 'Employee', ['jobTitleId', 'employmentStatus', 'workEmail']);

If you have the HR role, you

can('update', 'Employee', ['jobTitleId', 'employmentStatus', 'workEmail']);
cannot('update', 'Employee', ['firstname', 'lastname']);

My questions/concerns are:

  1. I experimented with the permittedFieldsOf helper to pick fields from the graphql mutation input but I noticed that the order matters as the inverted/cannot rules can unset a field. Now since HR inherits the default, this is fine when the rules are defined in that order (apply rules for default role first then rules for HR role). But when you start adding more roles to a user that also have different field access restrictions, the order returned by the database can be unpredictable which then affects the order and can then affect the results of permittedFieldsOf. One way to fix this is to ensure the order of the roles by sorting it based on the “role hierarchy” of the app. But one potential issue of that is if there’s a role higher than HR that can update firstname and lastname. That would replace the inverted rules of HR. Then some time in the future, another role is added higher than that which cannot update firstname and lastname and now there’s an issue of which one to follow. Since there’s no and/or operators, we’ll have to rely on the order of the rules now instead of the roles.

But if our implementation of the rolePermissions is the same as the one below, then there’s no way to reorder the rules. image

So to get around this, we instead return an array of RawRule then sort it accordingly but that can get messy/hard to maintain.

Ultimately, what one would want here is to get the fields from the can rules for picking from an object. But since an inverted rule could unset a field if it comes afterward can rules, now we lose the ability to pick that field since it won’t be returned by the permittedFieldsOf as that relies on the order of the rules. There seems to be no built-in way of achieve this currently.

What’s the best way then to go about getting all fields from non-inverted rules for that action and subject? Accessing the rules from the ability object and extracting non-inverted rules then use permittedFieldsOf is one way I could think of to achieve that but is there a better way currently? I’m not sure if this is common scenario but if it is, then can we possibly consider adding an ignoreInvertedRules option (which accepts a boolean value, false by default) in the PermittedFieldOptions (4th parameter of permittedFieldsOf helper) that does that?

  1. Once you start having field access restrictions for certain subjects and actions, is it then expected for other rules with the same subject and action to follow suit since one would most likely be picking the fields during create/update/some-custom-action? Wildcards don’t work on lodash’s pick so this got me wondering if there’s a better way to manage the picking of permitted fields when there are field access restrictions.

  2. On which layer do you think should this checking/picking occur?

  • As a middleware, before/after validation
  • On the interface layer (controller for REST / resolver for GraphQL)
  • On the business logic layer (services/handlers, functions would then would somehow need to accept the ability and actor/user objects)
  • On the data access layer (saw the objection-authorize plugin and I guess that works too but the interface layer shouldn’t be directly performing any operations from the data access layer so the ability object gets passed first to the business logic layer then to the data access layer.)

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:6 (6 by maintainers)

github_iconTop GitHub Comments

1reaction
stalniycommented, May 12, 2020

added “Best practice” section to “Define rules” page - https://stalniy.github.io/casl/v4/en/guide/define-rules#best-practice

1reaction
stalniycommented, May 10, 2020

Nice to know it solves the issue 😃

I wrote about the complexity of inverted rules in the intro guide I guess. But yes, probably it will be good to add a tip as a statement “give permissions, don’t take them away”

Read more comments on GitHub >

github_iconTop Results From Across the Web

Acecss control question - access to one field only - ServiceNow
I want give write access to only one field on cmdb_ci table with a new role i created now. example --> Role name...
Read more >
Restrict data input by using validation rules - Microsoft Support
Access provides a number of ways to restrict input: Data types Every table field has a data type that restricts what users can...
Read more >
How I Solved It: Selectively Control Record Access from ...
Watch how Tom Bassett uses the power of point-and-click tools—Flow, Restriction Rules, and Experience Cloud—to selectively control record access ...
Read more >
Restrict User Access to Object by Field Value [duplicate]
This question already has an answer here:​​ Is there a way to restrict a user's access to a subset of objects by field...
Read more >
Interview Questions on Sharing and Security in Salesforce
No, we can create sharing rules for details objects because they don't have owner field. Q. What are properties of sharing object?
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found