feat: Add permissions to subscriptions to only exposed user's

This commit is contained in:
Christophe 2019-12-13 17:20:54 +01:00
parent 6bddcea475
commit 75baf561a8
6 changed files with 144 additions and 11 deletions

View File

@ -5,10 +5,54 @@ stages:
- test - test
- release - release
variables:
SIB_PROJECT_NAME: "sib_test"
SIB_PROJECT_DIR: "/builds/$SIB_PROJECT_NAME"
DJANGO_SETTINGS_MODULE: "$SIB_PROJECT_NAME.settings"
SIB_PACKAGE_CONTENT: >
{
"ldppackages": {
"djangoldp_project": "djangoldp_project",
"djangoldp_circle": "djangoldp_circle",
"djangoldp_notification": "djangoldp_notification",
"djangoldp_account": "djangoldp_account",
"djangoldp_skill": "djangoldp_skill",
"djangoldp_joboffer": "djangoldp_joboffer",
"djangoldp_conversation": "djangoldp_conversation",
"djangoldp_profile": "djangoldp_profile",
"oidc_provider": "git+https://github.com/jblemee/django-oidc-provider.git@develop"
},
"server": {
"site_url": "http://localhost:8000",
"allowed_hosts": [
],
"db_host": "localhost",
"db_name": "database",
"db_user": "me",
"db_pass": "changeit",
"smtp_host": "locahost",
"smtp_user": "user",
"smtp_pass": "changeit",
"admin_email": "admin@example.org",
"admin_name": "admin",
"admin_pass": "admin"
}
}
test: test:
stage: test stage: test
before_script:
- export PATH="$PATH:/root/.local/bin" PYTHONPATH="$SIB_PROJECT_DIR"
- pip install git+https://git.happy-dev.fr/startinblox/devops/sib.git
- cd /builds && DJANGO_SETTINGS_MODULE="" sib startproject $SIB_PROJECT_NAME
- echo $SIB_PACKAGE_CONTENT > $SIB_PROJECT_DIR/packages.yml
- cd $SIB_PROJECT_DIR
- sib install $SIB_PROJECT_NAME
- cd $CI_PROJECT_DIR
- pip install -e .[dev]
script: script:
- echo 'Make your tests here !' - pytest
except: except:
- master - master
tags: tags:

View File

@ -1,25 +1,20 @@
import logging import logging
from threading import Thread
import requests import requests
from django.conf import settings from django.conf import settings
from django.contrib.admin.models import LogEntry
from django.contrib.sessions.models import Session
from django.core.mail import send_mail from django.core.mail import send_mail
from django.db import models from django.db import models
from django.db.models.signals import post_save from django.db.models.signals import post_save
from django.dispatch import receiver from django.dispatch import receiver
from oidc_provider.models import Token from django.template import loader
from django.urls import NoReverseMatch from django.urls import NoReverseMatch
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from djangoldp.fields import LDPUrlField from djangoldp.fields import LDPUrlField
from djangoldp.models import Model from djangoldp.models import Model
from threading import Thread
from django.template import loader
from djangoldp_notification.middlewares import MODEL_MODIFICATION_USER_FIELD from djangoldp_notification.middlewares import MODEL_MODIFICATION_USER_FIELD
from .permissions import InboxPermissions from djangoldp_notification.permissions import InboxPermissions, SubscriptionsPermissions
class Notification(Model): class Notification(Model):
@ -50,6 +45,11 @@ class Subscription(Model):
def __str__(self): def __str__(self):
return '{}'.format(self.object) return '{}'.format(self.object)
class Meta(Model.Meta):
anonymous_perms = []
authenticated_perms = ["add", "view", "delete"]
permission_classes = [SubscriptionsPermissions]
# --- SUBSCRIPTION SYSTEM --- # --- SUBSCRIPTION SYSTEM ---
@receiver(post_save, dispatch_uid="callback_notif") @receiver(post_save, dispatch_uid="callback_notif")
def send_notification(sender, instance, created, **kwargs): def send_notification(sender, instance, created, **kwargs):

View File

@ -1,4 +1,6 @@
from django.contrib.auth import get_user_model
from djangoldp.permissions import LDPPermissions from djangoldp.permissions import LDPPermissions
from rest_framework.reverse import reverse
class InboxPermissions(LDPPermissions): class InboxPermissions(LDPPermissions):
@ -35,4 +37,26 @@ class InboxPermissions(LDPPermissions):
if not perm.split('.')[1].split('_')[0] in self.user_permissions(request.user, model, obj): if not perm.split('.')[1].split('_')[0] in self.user_permissions(request.user, model, obj):
return False return False
return True return True
class SubscriptionsPermissions(LDPPermissions):
def has_permission(self, request, view):
if request.user.is_anonymous and not request.method == "OPTIONS":
return False
if request.method in ["GET", "PATCH", "DELETE", "PUT"]:
return True
return super().has_permission(request, view)
def has_object_permission(self, request, view, obj):
if request.user.is_anonymous and not request.method == "OPTIONS":
return False
reverse_path_key = "{}-notification-list".format(get_user_model()._meta.object_name.lower())
user_inbox = reverse(reverse_path_key, kwargs={"slug": request.user.slug}, request=request)
if obj.inbox == user_inbox:
return True
return False

View File

@ -0,0 +1,15 @@
from importlib import import_module
from os import environ
from pytest import fail
settings_module = environ.get("DJANGO_SETTINGS_MODULE")
if settings_module is None or len(settings_module) == 0:
fail("DJANGO_SETTINGS_MODULE needs to be defined and point to your SIB app installation settings")
try:
import_module(settings_module)
except ImportError:
initial_module = [token for token in settings_module.split(".") if len(token) > 0][0]
fail("Unable to import {}. Try to configure PYTHONPATH to point the "
"directory containing the {} module".format(settings_module, initial_module))

View File

@ -0,0 +1,47 @@
from collections import OrderedDict
from djangoldp.factories import UserFactory
from test_plus import APITestCase
from djangoldp_notification.models import Subscription
class TestSubscription(APITestCase):
user1 = None
user2 = None
circle_user1_url = "http://localhost:8000/circles/1"
circle_user2_url = "http://localhost:8000/circles/2"
def setUp(self):
self.user1 = UserFactory(username="karl_marx", password="password")
Subscription.objects.create(object=self.circle_user1_url, inbox="http://testserver/users/karl_marx/inbox/")
self.user2 = UserFactory(username="piotr_kropotkine", password="password")
Subscription.objects.create(object=self.circle_user2_url,
inbox="http://testserver/users/piotr_kropotkine/inbox/")
def test_not_logged_fails(self):
response = self.get("/subscriptions/")
self.assert_http_403_forbidden(response)
self.assertEqual(response.data.get("detail"), "Authentication credentials were not provided.")
def test_logged_in_succeeds(self):
with self.login(self.user1):
result = self.get("/subscriptions/").data.get("ldp:contains")
expected = [OrderedDict({
"@id": "http://localhost:8000/subscriptions/1/",
"object": self.circle_user1_url,
"inbox": "http://testserver/users/karl_marx/inbox/",
"permissions": [{'mode': {'@type': 'view'}}, {'mode': {'@type': 'delete'}}]
})]
self.assertSequenceEqual(result, expected)
with self.login(self.user2):
result = self.get("/subscriptions/").data.get("ldp:contains")
expected = [OrderedDict({
"@id": "http://localhost:8000/subscriptions/2/",
"object": self.circle_user2_url,
"inbox": "http://testserver/users/piotr_kropotkine/inbox/",
"permissions": [{'mode': {'@type': 'view'}}, {'mode': {'@type': 'delete'}}]
})]
self.assertSequenceEqual(result, expected)

View File

@ -15,7 +15,10 @@ install_requires =
[options.extras_require] [options.extras_require]
include_package_data = True include_package_data = True
dev = dev =
factory_boy>=2.11.0 factory_boy>=2.12.0
pytest==5.1.1
pytest-django==3.7.0
django-test-plus==1.4.0
[semantic_release] [semantic_release]
version_source = tag version_source = tag