mirror of
https://github.com/pinry/pinry.git
synced 2025-11-13 16:45:41 +01:00
Fix: Fix permission check for tastypie / update to 0.14.1
This commit is contained in:
2
Pipfile
2
Pipfile
@@ -14,7 +14,7 @@ requests = "*"
|
||||
django-taggit = "*"
|
||||
django-braces = "*"
|
||||
django-compressor = "*"
|
||||
django-tastypie = ">=0.13.0,<0.14"
|
||||
django-tastypie = "*"
|
||||
mock = "*"
|
||||
factory-boy = "<2.0,>=1.3"
|
||||
gunicorn = "*"
|
||||
|
||||
7
Pipfile.lock
generated
7
Pipfile.lock
generated
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"_meta": {
|
||||
"hash": {
|
||||
"sha256": "c632e45ac592ec9c159c042db8c52e221ae133ade94cd11fcfb124a5fd5b9dd0"
|
||||
"sha256": "68c12441be13a252f7fdd1b5532c7befdfa56fc8307ab75a2b197a1946a54bf2"
|
||||
},
|
||||
"pipfile-spec": 6,
|
||||
"requires": {},
|
||||
@@ -69,11 +69,10 @@
|
||||
},
|
||||
"django-tastypie": {
|
||||
"hashes": [
|
||||
"sha256:bd4eb8a9da6c2dd70c946edc460776a64f40fae01132520a26133361bd43bf3f",
|
||||
"sha256:e404b9ac24ab400015047f5503fae1732d9e944a7152693fe902c0a905f250cc"
|
||||
"sha256:1fbf61ec7467eec70bd1abcb14e3b1dc67e47cc3642ad16ed8a3709f4140678b"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.13.3"
|
||||
"version": "==0.14.1"
|
||||
},
|
||||
"factory-boy": {
|
||||
"hashes": [
|
||||
|
||||
89
core/api.py
89
core/api.py
@@ -10,36 +10,101 @@ from .models import Pin, Image
|
||||
from users.models import User
|
||||
|
||||
|
||||
def _is_pin_owner(obj_or_list, user):
|
||||
assert obj_or_list is not None
|
||||
if not isinstance(obj_or_list, (tuple, list)):
|
||||
obj_or_list = (obj_or_list,)
|
||||
results = tuple(
|
||||
obj.submitter == user
|
||||
for obj in obj_or_list
|
||||
if isinstance(obj, Pin)
|
||||
)
|
||||
if len(results) <= 0:
|
||||
raise ValueError(
|
||||
"You should never check permission on %s with this function."
|
||||
% obj_or_list
|
||||
)
|
||||
return all(results)
|
||||
|
||||
|
||||
def _is_authenticated_and_owner(object_list, bundle):
|
||||
if bundle.request.user.is_anonymous():
|
||||
return object_list.none()
|
||||
return object_list.filter(submitter=bundle.request.user)
|
||||
|
||||
|
||||
class PinryAuthorization(DjangoAuthorization):
|
||||
"""
|
||||
Pinry-specific Authorization backend with object-level permission checking.
|
||||
"""
|
||||
def update_detail(self, object_list, bundle):
|
||||
def _is_obj_owner(self, object_list, bundle):
|
||||
klass = self.base_checks(bundle.request, bundle.obj.__class__)
|
||||
|
||||
if klass is False:
|
||||
raise Unauthorized("You are not allowed to access that resource.")
|
||||
return _is_pin_owner(bundle.obj, bundle.request.user)
|
||||
|
||||
permission = '%s.change_%s' % (klass._meta.app_label, klass._meta.model_name)
|
||||
|
||||
if not bundle.request.user.has_perm(permission, bundle.obj):
|
||||
raise Unauthorized("You are not allowed to access that resource.")
|
||||
def read_list(self, object_list, bundle):
|
||||
# This assumes a ``QuerySet`` from ``ModelResource``.
|
||||
return object_list
|
||||
|
||||
def read_detail(self, object_list, bundle):
|
||||
"""
|
||||
User can always read detail of any Pin object.
|
||||
"""
|
||||
return True
|
||||
|
||||
def create_detail(self, object_list, bundle):
|
||||
return self._is_obj_owner(object_list, bundle)
|
||||
|
||||
def update_detail(self, object_list, bundle):
|
||||
return self._is_obj_owner(object_list, bundle)
|
||||
|
||||
def delete_detail(self, object_list, bundle):
|
||||
klass = self.base_checks(bundle.request, bundle.obj.__class__)
|
||||
return self._is_obj_owner(object_list, bundle)
|
||||
|
||||
if klass is False:
|
||||
raise Unauthorized("You are not allowed to access that resource.")
|
||||
def update_list(self, object_list, bundle):
|
||||
return _is_authenticated_and_owner(object_list, bundle)
|
||||
|
||||
permission = '%s.delete_%s' % (klass._meta.app_label, klass._meta.model_name)
|
||||
def delete_list(self, object_list, bundle):
|
||||
return _is_authenticated_and_owner(object_list, bundle)
|
||||
|
||||
if not bundle.request.user.has_perm(permission, bundle.obj):
|
||||
raise Unauthorized("You are not allowed to access that resource.")
|
||||
|
||||
class ImageAuthorization(DjangoAuthorization):
|
||||
"""
|
||||
Pinry-specific Authorization backend with object-level permission checking.
|
||||
"""
|
||||
def __init__(self):
|
||||
DjangoAuthorization.__init__(self)
|
||||
|
||||
def read_list(self, object_list, bundle):
|
||||
return object_list
|
||||
|
||||
def read_detail(self, object_list, bundle):
|
||||
"""
|
||||
User can always read detail of any Pin object.
|
||||
"""
|
||||
return True
|
||||
|
||||
def create_detail(self, object_list, bundle):
|
||||
return bundle.request.user.is_authenticated()
|
||||
|
||||
def update_detail(self, object_list, bundle):
|
||||
return bundle.request.user.is_authenticated()
|
||||
|
||||
def delete_detail(self, object_list, bundle):
|
||||
return bundle.request.user.is_authenticated()
|
||||
|
||||
def update_list(self, object_list, bundle):
|
||||
if not bundle.request.user.is_authenticated():
|
||||
return object_list.none()
|
||||
return object_list
|
||||
|
||||
def delete_list(self, object_list, bundle):
|
||||
if not bundle.request.user.is_authenticated():
|
||||
return object_list.none()
|
||||
return object_list
|
||||
|
||||
|
||||
class UserResource(ModelResource):
|
||||
gravatar = fields.CharField(readonly=True)
|
||||
@@ -101,7 +166,7 @@ class ImageResource(ModelResource):
|
||||
include_resource_uri = False
|
||||
resource_name = 'image'
|
||||
queryset = Image.objects.all()
|
||||
authorization = DjangoAuthorization()
|
||||
authorization = ImageAuthorization()
|
||||
|
||||
|
||||
class PinResource(ModelResource):
|
||||
|
||||
@@ -33,11 +33,3 @@ class CombinedAuthBackend(object):
|
||||
return User.objects.get(pk=user_id)
|
||||
except User.DoesNotExist:
|
||||
return None
|
||||
|
||||
def has_perm(self, user, perm, obj=None):
|
||||
"""
|
||||
A very simplistic authorization mechanism for now. Basically a pin owner can do anything with the pin.
|
||||
"""
|
||||
if obj and isinstance(obj, Pin):
|
||||
return obj.submitter == user
|
||||
return False
|
||||
|
||||
@@ -34,21 +34,6 @@ class CombinedAuthBackendTest(TestCase):
|
||||
def test_authenticate_unknown_user(self):
|
||||
self.assertIsNone(self.backend.authenticate(username='wrong-username', password='wrong-password'))
|
||||
|
||||
@mock.patch('requests.get', mock_requests_get)
|
||||
def test_has_perm_on_pin(self):
|
||||
image = Image.objects.create_for_url('http://testserver/mocked/screenshot.png')
|
||||
user = User.objects.get(username=self.username)
|
||||
pin = Pin.objects.create(submitter=user, image=image)
|
||||
self.assertTrue(self.backend.has_perm(user, 'add_pin', pin))
|
||||
|
||||
@mock.patch('requests.get', mock_requests_get)
|
||||
def test_has_perm_on_pin_unauthorized(self):
|
||||
image = Image.objects.create_for_url('http://testserver/mocked/screenshot.png')
|
||||
user = User.objects.get(username=self.username)
|
||||
other_user = User.objects.create_user('test', 'test@example.com', 'test')
|
||||
pin = Pin.objects.create(submitter=user, image=image)
|
||||
self.assertFalse(self.backend.has_perm(other_user, 'add_pin', pin))
|
||||
|
||||
|
||||
class CreateUserTest(TestCase):
|
||||
def test_create_post(self):
|
||||
|
||||
Reference in New Issue
Block a user