Skip to content

permissions must return a boolean to allow &/| operator comparison #6286

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

Merged
merged 3 commits into from
Nov 5, 2018

Conversation

markddavidoff
Copy link
Contributor

@markddavidoff markddavidoff commented Oct 28, 2018

x and y actually returns object y when both are true. This meansSomePermission & IsAuthenticated will fail with TypeError: unsupported operand type(s) for &: 'instance' and 'bool' as IsAuthenticated now returns a CallableBool which does not overload __ror__ (at least in Django==1.11.16)

An alternative approach is explicitly calling bool() in AND and OR, which would allow has_permission to return truthy non boolean objects, but i feel permissions should be more explicit than that. If this approach makes sense I can add tests.

Note: Before submitting this pull request, please review our contributing guidelines.

Description

Please describe your pull request. If it fixes a bug or resolves a feature request, be sure to link to that issue. When linking to an issue, please use refs #... in the description of the pull request.

`x and y` actually returns object y when both are true. the means P & IsAuthenticated will fail with TypeError: unsupported operand type(s) for &: 'instance' and 'bool' as IsAuthenticated now returns a CallableBool which does not overload __ror__
@markddavidoff markddavidoff changed the title permissions must return a boolean permissions must return a boolean to allow &/| operator comparison Oct 28, 2018
@xordoquy
Copy link
Collaborator

Hi,

This is too abstract without a test case to demonstrate the issue.
It seems to me that your issue may happen if a permission doesn't inherit BasePermission in which case they can not be composed.

@xordoquy xordoquy closed this Oct 28, 2018
@markddavidoff
Copy link
Contributor Author

markddavidoff commented Oct 29, 2018

@xordoquy I explained the case in the description but here is an explicit test case:

from django.contrib.auth.models import User
from django.test.client import RequestFactory
from mock import MagicMock
from rest_framework.permissions import AllowAny, IsAuthenticated

user = User.objects.create_user(username='tester', email='test@test.com', password='top_secret')
rf = RequestFactory()
request = rf.get('/')
request.user = MagicMock()

ret = AllowAny().has_permission(request, None) & IsAuthenticated().has_permission(request, None)

The last line raises:
TypeError: unsupported operand type(s) for &: 'bool' and 'instance'

The reason this occurs is explained in my original description.

@xordoquy xordoquy reopened this Oct 29, 2018
@carltongibson carltongibson added this to the 3.9.1 Release milestone Oct 29, 2018
@markddavidoff
Copy link
Contributor Author

Updated test cases to reflect the change in django. Is there a way to use a real django user object instead of FakeUser? I believe that wouldve caught this case.

@xordoquy
Copy link
Collaborator

@markddavidoff if fact, you don't want a user if you want the test to fail.
I first ran your test with:

request.user = user

and it wouldn't fail until I correct that part with:

request.user = None

in which case it would now fail.
I'm not sure what's that story about CallableBool is.

@markddavidoff
Copy link
Contributor Author

@xordoquy what version of django are you using when you run the test. CallableBool is in Django versions: Django 1.10.0-Django 2.1.2.

I don't understand your last comment at all. The issue is with is_authenticated returning an object not a bool. Steps for you to repro this:

  • Install Django 1.11.16
  • change FakeUser in test_permissions to return CallableBool as I have or user a real User object.
  • run the tests or the snippet I provided above.

@markddavidoff
Copy link
Contributor Author

markddavidoff commented Oct 29, 2018

@xordoquy I have added this pr: #6287 to show you the issue, with just the test change. look at the output to the django 1.11 output

@markddavidoff
Copy link
Contributor Author

@xordoquy
Copy link
Collaborator

OK, I get it.
CallableBool is only available for Django 1.11 as it's on the path of the is_authenticated migration from a function to a property.
The Django 2.0 release notes state:

Using User.is_authenticated() and User.is_anonymous() as methods rather than properties is no longer supported.

This being said, you demonstrated an issue when there's no user to a request (whatever reason there might be). So I'll be willing to fix it though not spending too much time on the CallableBool as the next minor will drop support for Django 1.11 anyway.

@markddavidoff
Copy link
Contributor Author

markddavidoff commented Oct 29, 2018 via email

@xordoquy
Copy link
Collaborator

Sure thing, but you'll need to find a workaround for the test to pass for Django 2.0+
I'll check tonight how that can be solved.

@markddavidoff
Copy link
Contributor Author

Fixed test

@markddavidoff
Copy link
Contributor Author

@xordoquy updated test

@xordoquy
Copy link
Collaborator

xordoquy commented Nov 5, 2018

Thanks for the PR, nice work.

@xordoquy xordoquy merged commit bf9533a into encode:master Nov 5, 2018
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.

3 participants
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy