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

Fix Respect can_read_model permission in DjangoModelPermissions #8009

Merged
merged 2 commits into from
Jan 13, 2023

Conversation

ManishShah120
Copy link
Contributor

Description

This PR implements the view permission in DjangoModelPemissions class. The old PR #6325 tried to fix it, but it contains a flaw i.e., even if an object has change, add, delete permission the detail page of any objects returns "detail": "Not found.". which is not expected. As any objects which has change permission should also allow GET requests as well.

FIXES: #6324

Ref:-

@atb00ker
Copy link

Hey @tomchristie interested in your opinion on this implementation! 😄

Copy link
Contributor

@nemesifier nemesifier left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we'll need to update the docs here as well: https://github.com/encode/django-rest-framework/blob/master/docs/api-guide/permissions.md#djangomodelpermissions.
That section now suggests adding view permissions, but I think we should say view permissions are supported and any user having either view or change permissions on a model will be able to view.


user = request.user
if request.method == 'GET':
if user.has_perms(perms) or user.has_perms(change_perm):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ManishShah120 please update this block as we did in openwisp/openwisp-users#251

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, On it 👍

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated the docs and simplified the code.

Copy link
Member

@tomchristie tomchristie left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code-wise this seems good yup. All very neat & cleanly done. 👍

Seems like a possible issue with the change in behaviour. I guess there are plenty of existing apps out there that haven't been using "view" permissions, that would break if upgraded to this?

@nemesifier
Copy link
Contributor

Code-wise this seems good yup. All very neat & cleanly done.

Seems like a possible issue with the change in behaviour. I guess there are plenty of existing apps out there that haven't been using "view" permissions, that would break if upgraded to this?

I stressed that we maintain backward compatibility since the view permission is a relatively new thing (although has been around for a couple of years now).

If old apps are not using view permissions, change permission will be used to determine if a user they can view.
This avoids the situation in which a user with change permission cannot view because of the missing view permission (which doesn't make any sense).

Examples:

User with change permission but not view permission: can view and change
User with no change permission nor view permission: cannot view nor change
User with view permission but no change permission: can view but cannot change

@tomchristie I hope this clarifies.

@nemesifier
Copy link
Contributor

@tomchristie ping 🖖

@nemesifier
Copy link
Contributor

BTW we are using this code in https://github.com/openwisp/openwisp-users/#djangomodelpermissions. Just to clarify that we are using this code and is not just some random untested code we're sending here 😊.

@hericlesbitencourt
Copy link

Why this hasn't it been approved and merged yet? This issue has been opened for so long.

@nemesifier
Copy link
Contributor

Why this hasn't it been approved and merged yet? This issue has been opened for so long.

@hericlesbitencourt I think if we get more people to test and use it the maintainers will be more confident in merging.
I think they are afraid of causing bugs and didn't have time to test.

@auvipy
Copy link
Member

auvipy commented Aug 21, 2021

Why this hasn't it been approved and merged yet? This issue has been opened for so long.

@hericlesbitencourt I think if we get more people to test and use it the maintainers will be more confident in merging.
I think they are afraid of causing bugs and didn't have time to test.

actually the main maintainer lost his motivation to work on this project

@kxbin
Copy link

kxbin commented Sep 3, 2021

I think this PR is very useful and it is very necessary to be merged.

@kxbin
Copy link

kxbin commented Sep 3, 2021

It is also recommended to add a DjangoModelPerssionsOrReadOnly, which remains compatible with the old version DjangoModelPerssions.

There will be no compatibility issues, because users of the old version can easily replace.

In this way, three permissions are exist in total:
DjangoModelPerssions
DjangoModelPerssionsOrReadOnly
DjangoModelPerssionsOrAnonReadOnly


user = request.user
if request.method == 'GET':
return user.has_perms(perms) or user.has_perms(change_perm)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see the motivation for this additional set of checks against view_* or change_* permissions.

Just seems inconsistent to me.

Copy link
Contributor

@nemesifier nemesifier Sep 15, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This maintains backward compatibility Tom. If the DB was not updated to grant the users of an application view permissions, the API endpoints will not allow read operations and will break because users have no view permissions assigned, only change permissions which was how django worked before, we can't be sure all databases have been updated to use view permissions properly.

If we only check view permissions, that's how we would introduce a backward incompatible change.

@hericlesbitencourt
Copy link

I think this PR is very useful and it is very necessary to be merged.

Thanks man, indeed is highly necessary. When I was learning for the first time I took days to understand why a simple "get" wouldn't work with DjangoModelPermissions, for me makes no sense.

'OPTIONS': [],
'HEAD': [],
'HEAD': ['%(app_label)s.view_%(model_name)s'],
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Presumably we'd also want to make the same change on DjangoObjectPermissions, right?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I honestly don't know, if you say this should be done we'll look into it, but we should clear any doubt regarding https://github.com/encode/django-rest-framework/pull/8009/files/dd4de8e420f3fe6e069cfb176a3e64218a10eda0#r709556976.

@tomchristie
Copy link
Member

So the biggest thing here is the impact of behaviour changes in the project at this stage in its lifetime.

Do we support view model permissions? Yup, we currently document what the existing behaviour is, and note that if you want them then you can do so by subclassing DjangoModelPermissions. That's a few lines of code for any project that does want this behaviour.

Should we switch to requiring them by default? Well... possibly. It'll be more in line with what some users will want by default, but it'll also absolutely 100% undoubtedly break other projects that upgrade.

Is the cost of breakage in exchange for switching the behaviour around a good trade-off? Maybe. Maybe not.

Personally I'm almost always pushing back on almost any behavioural changes in REST framework at this point, because the negative impact the changes cause to upgrading projects probably doesn't seem worth it.

Perhaps we ought to make an exception here, because "view" permissions have been around in Django for quite some time now (they didn't exist at the time we first introduced this permission class), but if I'm hesitant, it's because there's very good reasons to default to "leave things as they are" at this point.

@tomchristie
Copy link
Member

tomchristie commented Sep 3, 2021

Having said all that, I do still think that this particular case is potentially worthy of a behavioural change, so long as we document it loudly enough. It's just that it's really not an easy trade-off to choose at this point.

@IgnacioFDM
Copy link

This should definitely be merged imo. In fact it should have been this way from the moment this was added to Django. Having a mode to use Django permissions that actually ignores half of Django permissions is a major flaw.

Even though it is technically breaking, it is a safe change in the sense that, from a security standpoint, it's more restrictive than before (it won't give access to things that didn't have access before).

@nemesifier
Copy link
Contributor

nemesifier commented Sep 15, 2021

I don't understand how this solution can break anything really because it has been thought with backward compatibility in mind.
@tomchristie do you care about providing a real world example of how this change can break a system so that if there's something we can do now to avoid it we could try?

I think that whoever didn't implement anything custom with view permissions will get the same behavior as without this patch.
Those who did implement something to handle view permissions may have some redundancy but unless they implemented it differently (eg: their implementation could grant a user to change an object but not view it, but that doensn't make sense and shouldn't be endorsed) it should not hurt them.

@ahmedalrifai
Copy link

When this issue will be merged?

@jonathan-golorry
Copy link

If I understand correctly, this will be a problem specifically for people who are using DjangoModelPermissions with users who are supposed to have read-only permissions, but don't have view permissions because it defaults to viewable. The special cases, such as making the detail endpoint viewable without the view permission, aren't very intuitive, but are unlikely to cause problems.

I'm not sure why this patch is preferable to adding a new Django2ModelPermissions class that respects view permissions completely, without any backwards compatibility considerations or special cases. Anyone who needs backwards compatibility can continue to use DjangoModelPermissions and get the exact same behavior. Anyone who wants to switch can--without worrying about special cases.

@igonro
Copy link

igonro commented Mar 4, 2022

I think this should be added. I understand the concerns about backward compatibility, but I think backward compatibility is only desirable not mandatory. Could this break some projects that upgrade? Probably, but the good practice that all of us should use in our projects is: use fixed package versions, and only upgrade them once we have tested in a development environment ensuring that it won't break anything.

Anyways, it's 2022 and this feature was firstly proposed in 2018. Maybe it's time for make a decission:

  1. Add these changes
  2. Leave DjangoModelPermissions as it is, and create a new DjangoModelWithViewPermissions (or something like that)

I like the propose of @kxbin of having DjangoModelPermissions, DjangoModelPermissionsOrReadOnly and DjangoModelPermissionsOrAnonReadOnly for the 1st option.

For the 2nd option the name DjangoModelWithViewPermissions feels a bit strange, but I would prefer having a strange name and having this functionality by default. This would be very useful for new people that are starting to use DRF (as it is my case).

@nemesifier
Copy link
Contributor

I think this should be added. I understand the concerns about backward compatibility, but I think backward compatibility is only desirable not mandatory. Could this break some projects that upgrade? Probably, but the good practice that all of us should use in our projects is: use fixed package versions, and only upgrade them once we have tested in a development environment ensuring that it won't break anything.

Anyways, it's 2022 and this feature was firstly proposed in 2018. Maybe it's time for make a decission:

  1. Add these changes
  2. Leave DjangoModelPermissions as it is, and create a new DjangoModelWithViewPermissions (or something like that)

I like the propose of @kxbin of having DjangoModelPermissions, DjangoModelPermissionsOrReadOnly and DjangoModelPermissionsOrAnonReadOnly for the 1st option.

For the 2nd option the name DjangoModelWithViewPermissions feels a bit strange, but I would prefer having a strange name and having this functionality by default. This would be very useful for new people that are starting to use DRF (as it is my case).

Sounds good, the alternative could be the opposite, implement a backward incompatible DjangoModelPermissions class but provide DjangoModelPermissionsLegacy with the old behavior.

@stale
Copy link

stale bot commented Jul 30, 2022

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.

@stale stale bot added the stale label Jul 30, 2022
@igonro
Copy link

igonro commented Aug 4, 2022

👀

@stale
Copy link

stale bot commented Oct 14, 2022

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.

@stale stale bot added the stale label Oct 14, 2022
@stale stale bot closed this Oct 22, 2022
@auvipy auvipy reopened this Dec 15, 2022
@stale stale bot removed the stale label Dec 15, 2022
Copy link
Member

@auvipy auvipy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let us come back to this again. we have to think about the trade off carefully, Tom mentioned.

@auvipy
Copy link
Member

auvipy commented Jan 12, 2023

i would love to see the minor conflicts resolved in the doc

@ManishShah120
Copy link
Contributor Author

i would love to see the minor conflicts resolved in the doc

Sure, working on it.

@auvipy auvipy added this to the 3.15 milestone Jan 13, 2023
@auvipy
Copy link
Member

auvipy commented Jan 13, 2023

I am going to accept this. as it is mostly a django compatibilty issue and will be released in a major version. if we need additional fixes we can handle those in another PR

@auvipy auvipy merged commit 0618fa8 into encode:master Jan 13, 2023
zengqiu added a commit to zengqiu/django-rest-framework-ext that referenced this pull request Jan 8, 2024
kernicPanel added a commit to openfun/joanie that referenced this pull request Mar 18, 2024
DRF verson 3.15 Fix Respect can_read_model permission in DjangoModelPermissions.
encode/django-rest-framework#8009
kernicPanel added a commit to openfun/joanie that referenced this pull request Mar 18, 2024
DRF verson 3.15 Fix Respect can_read_model permission in DjangoModelPermissions.
encode/django-rest-framework#8009
kernicPanel added a commit to openfun/joanie that referenced this pull request Mar 18, 2024
DRF verson 3.15 Fix Respect can_read_model permission in DjangoModelPermissions.
encode/django-rest-framework#8009
kernicPanel added a commit to openfun/joanie that referenced this pull request Mar 18, 2024
DRF verson 3.15 Fix Respect can_read_model permission in DjangoModelPermissions.
encode/django-rest-framework#8009
kernicPanel added a commit to openfun/joanie that referenced this pull request Mar 18, 2024
DRF verson 3.15 Fix Respect can_read_model permission in DjangoModelPermissions.
encode/django-rest-framework#8009
kernicPanel added a commit to openfun/joanie that referenced this pull request Mar 18, 2024
DRF verson 3.15 Fix Respect can_read_model permission in DjangoModelPermissions.
encode/django-rest-framework#8009
kernicPanel added a commit to openfun/joanie that referenced this pull request Mar 25, 2024
As DRF encode/django-rest-framework#8009 has
been reverted in 3.15.1, the related hack is no longer needed.
kernicPanel added a commit to openfun/joanie that referenced this pull request Mar 25, 2024
As DRF encode/django-rest-framework#8009 has
been reverted in 3.15.1, the related hack is no longer needed.
kernicPanel added a commit to openfun/joanie that referenced this pull request Mar 26, 2024
As DRF encode/django-rest-framework#8009 has
been reverted in 3.15.1, the related hack is no longer needed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

DjangoModelPermissions does not respect Django can_read_model permissoin