Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature Request] Field-level policy: provide a way to "override" model-level rules #809

Closed
ymc9 opened this issue Nov 7, 2023 · 4 comments
Milestone

Comments

@ymc9
Copy link
Member

ymc9 commented Nov 7, 2023

Today, for having access to a field, both model-level and field-level (if any) policies need to be satisfied. This can be very inconvenient for scenarios where a user can only update one field but nothing else.

Concrete example:

  • Admin users can update all fields of "User" model
  • Regular users can only update "password" field of their own

To allow the second rule, we have to let regular users pass model-level "update" policies, however, then we have to add "@deny" rule on all fields except for "password".

The proposed solution, as discussed with @jasonmacdonald , is to introduce a third parameter to "@Allow" attribute to let it "override" model-level policies:

password String @allow('update', auth() == this, true)

Discord thread: https://discord.com/channels/1035538056146595961/1171196847797325854

@ymc9 ymc9 added this to the v1.3.0 milestone Nov 7, 2023
@ymc9
Copy link
Member Author

ymc9 commented Nov 7, 2023

Hi @jasonmacdonald , you also mentioned another case:

Another use-case is the profile relation. If you want to update your Profile, you must update it through a direct profile query if not admin, because any query which "passes through" the user model as nested updates are immediately revoked by the User policy, even if the only field you are trying to update is allowed at the field level.

Could you show the Prisma query that you want to make work? I just want to make sure it's also covered in the implementation. Thanks!

@jasonmacdonald
Copy link
Contributor

jasonmacdonald commented Nov 7, 2023

Hi @jasonmacdonald , you also mentioned another case:

Another use-case is the profile relation. If you want to update your Profile, you must update it through a direct profile query if not admin, because any query which "passes through" the user model as nested updates are immediately revoked by the User policy, even if the only field you are trying to update is allowed at the field level.

Could you show the Prisma query that you want to make work? I just want to make sure it's also covered in the implementation. Thanks!

Really, it's the same as the first, only on a relation rather than a property.

Example:

model User {
     id  String   @id @unique @default(uuid()) @db.Uuid
    ...
    password  String @allow('update', auth() == this, true)
    profileId  String   @unique 
    profile  Profile  @relation(fields: [profileId], references: [id]) @allow('update', auth() == this, true)
    
    @@allow('create,update,delete', auth().role == 'ADMIN')
    @@allow('read', true)
}

In this scenario, you could not update the password or anything in the Profile, even though you may have permission to update your own profile since the model level @@allow blocks both unless you are admin.

If, however, both @allow calls allow overriding for a user's own data, it's still possible to update the Profile model and the password, while blocking any other changes.

{
   data: {
      password: '12345'
      profile: {
         update: {
           data: { 
               phonenumber: '555-555-5555'
           }
         }
      }
   },
   where: {
        id: 'MyId'
   }
}

I would assume the ability to resolve the first scenario would likely work for the second, so it might just be a matter of ensuring it works.

@ymc9
Copy link
Member Author

ymc9 commented Nov 8, 2023

Got it. Thanks for providing the details.

I'm actually thinking, if only "profile" is updated, it probably shouldn't trigger User's "update" check at all (both model-level and field-level), since it's not really touching User. I need to think a bit more about this ...

@jasonmacdonald
Copy link
Contributor

Got it. Thanks for providing the details.

I'm actually thinking, if only "profile" is updated, it probably shouldn't trigger User's "update" check at all (both model-level and field-level), since it's not really touching User. I need to think a bit more about this ...

Yes, when no User fields are changed, just skipping the User model checks makes sense, provided the Profile policies are still run against its nested changes - I assume that would be the case.

@ymc9 ymc9 modified the milestones: v1.3.0, v1.4.0 Nov 15, 2023
@ymc9 ymc9 modified the milestones: v1.4.0, v1.5.0, v2.0.0 Dec 1, 2023
@ymc9 ymc9 modified the milestones: v2.0.0, v1.5.0 Dec 9, 2023
@ymc9 ymc9 closed this as completed Dec 15, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants