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-taggit = "*"
|
||||||
django-braces = "*"
|
django-braces = "*"
|
||||||
django-compressor = "*"
|
django-compressor = "*"
|
||||||
django-tastypie = ">=0.13.0,<0.14"
|
django-tastypie = "*"
|
||||||
mock = "*"
|
mock = "*"
|
||||||
factory-boy = "<2.0,>=1.3"
|
factory-boy = "<2.0,>=1.3"
|
||||||
gunicorn = "*"
|
gunicorn = "*"
|
||||||
|
|||||||
7
Pipfile.lock
generated
7
Pipfile.lock
generated
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"_meta": {
|
"_meta": {
|
||||||
"hash": {
|
"hash": {
|
||||||
"sha256": "c632e45ac592ec9c159c042db8c52e221ae133ade94cd11fcfb124a5fd5b9dd0"
|
"sha256": "68c12441be13a252f7fdd1b5532c7befdfa56fc8307ab75a2b197a1946a54bf2"
|
||||||
},
|
},
|
||||||
"pipfile-spec": 6,
|
"pipfile-spec": 6,
|
||||||
"requires": {},
|
"requires": {},
|
||||||
@@ -69,11 +69,10 @@
|
|||||||
},
|
},
|
||||||
"django-tastypie": {
|
"django-tastypie": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
"sha256:bd4eb8a9da6c2dd70c946edc460776a64f40fae01132520a26133361bd43bf3f",
|
"sha256:1fbf61ec7467eec70bd1abcb14e3b1dc67e47cc3642ad16ed8a3709f4140678b"
|
||||||
"sha256:e404b9ac24ab400015047f5503fae1732d9e944a7152693fe902c0a905f250cc"
|
|
||||||
],
|
],
|
||||||
"index": "pypi",
|
"index": "pypi",
|
||||||
"version": "==0.13.3"
|
"version": "==0.14.1"
|
||||||
},
|
},
|
||||||
"factory-boy": {
|
"factory-boy": {
|
||||||
"hashes": [
|
"hashes": [
|
||||||
|
|||||||
89
core/api.py
89
core/api.py
@@ -10,36 +10,101 @@ from .models import Pin, Image
|
|||||||
from users.models import User
|
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):
|
class PinryAuthorization(DjangoAuthorization):
|
||||||
"""
|
"""
|
||||||
Pinry-specific Authorization backend with object-level permission checking.
|
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__)
|
klass = self.base_checks(bundle.request, bundle.obj.__class__)
|
||||||
|
|
||||||
if klass is False:
|
if klass is False:
|
||||||
raise Unauthorized("You are not allowed to access that resource.")
|
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)
|
def read_list(self, object_list, bundle):
|
||||||
|
# This assumes a ``QuerySet`` from ``ModelResource``.
|
||||||
if not bundle.request.user.has_perm(permission, bundle.obj):
|
return object_list
|
||||||
raise Unauthorized("You are not allowed to access that resource.")
|
|
||||||
|
|
||||||
|
def read_detail(self, object_list, bundle):
|
||||||
|
"""
|
||||||
|
User can always read detail of any Pin object.
|
||||||
|
"""
|
||||||
return True
|
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):
|
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:
|
def update_list(self, object_list, bundle):
|
||||||
raise Unauthorized("You are not allowed to access that resource.")
|
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
|
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):
|
class UserResource(ModelResource):
|
||||||
gravatar = fields.CharField(readonly=True)
|
gravatar = fields.CharField(readonly=True)
|
||||||
@@ -101,7 +166,7 @@ class ImageResource(ModelResource):
|
|||||||
include_resource_uri = False
|
include_resource_uri = False
|
||||||
resource_name = 'image'
|
resource_name = 'image'
|
||||||
queryset = Image.objects.all()
|
queryset = Image.objects.all()
|
||||||
authorization = DjangoAuthorization()
|
authorization = ImageAuthorization()
|
||||||
|
|
||||||
|
|
||||||
class PinResource(ModelResource):
|
class PinResource(ModelResource):
|
||||||
|
|||||||
@@ -33,11 +33,3 @@ class CombinedAuthBackend(object):
|
|||||||
return User.objects.get(pk=user_id)
|
return User.objects.get(pk=user_id)
|
||||||
except User.DoesNotExist:
|
except User.DoesNotExist:
|
||||||
return None
|
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):
|
def test_authenticate_unknown_user(self):
|
||||||
self.assertIsNone(self.backend.authenticate(username='wrong-username', password='wrong-password'))
|
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):
|
class CreateUserTest(TestCase):
|
||||||
def test_create_post(self):
|
def test_create_post(self):
|
||||||
|
|||||||
Reference in New Issue
Block a user