An enhanced permission system which support object permission in Django

Overview

django-permission

Build status Coverage Requirements Status Inspection Version License Format Supported python versions Status
Author
Alisue <[email protected]>
Supported python versions
Python 2.7, 3.3, 3.4, 3.5, 3.6
Supported django versions
Django 1.8 - 1.11b

An enhanced permission library which enables a logic-based permission system to handle complex permissions in Django.

Documentation

http://django-permission.readthedocs.org/en/latest/

Installation

Use pip like:

$ pip install django-permission

Usage

The following might help you to understand as well.

Configuration

  1. Add permission to the INSTALLED_APPS in your settings module

    INSTALLED_APPS = (
        # ...
        'permission',
    )
  2. Add our extra authorization/authentication backend

    AUTHENTICATION_BACKENDS = (
        'django.contrib.auth.backends.ModelBackend', # default
        'permission.backends.PermissionBackend',
    )
  3. Follow the instructions below to apply logical permissions to django models

Autodiscovery

Like django's admin package, django-permission automatically discovers the perms.py in your application directory by running ``permission.autodiscover()``. Additionally, if the perms.py module has a PERMISSION_LOGICS variable, django-permission automatically run the following functions to apply the permission logics.

for model, permission_logic_instance in PERMISSION_LOGICS:
    if isinstance(model, str):
        model = get_model(*model.split(".", 1))
    add_permission_logic(model, permission_logic_instance)

Note

Autodiscover feature is automatically called if you are using django higher than 1.7 so no need to follow the tutorial below. To disable, use PERMISSION_AUTODISCOVER_ENABLE setting.

Quick tutorial

  1. Add import permission; permission.autodiscover() to your urls.py like:

    from django.conf.urls import patterns, include, url
    from django.contrib import admin
    
    admin.autodiscover()
    # add this line
    import permission; permission.autodiscover()
    
    urlpatterns = patterns('',
        url(r'^admin/', include(admin.site.urls)),
        # ...
    )
  2. Write perms.py in your application directory like:

    from permission.logics import AuthorPermissionLogic
    from permission.logics import CollaboratorsPermissionLogic
    
    PERMISSION_LOGICS = (
        ('your_app.Article', AuthorPermissionLogic()),
        ('your_app.Article', CollaboratorsPermissionLogic()),
    )

You can specify a different module or variable name, with PERMISSION_AUTODISCOVER_MODULE_NAME or PERMISSION_AUTODISCOVER_VARIABLE_NAME respectively.

Apply permission logic

Let's assume you wrote an article model which has an author attribute to store the creator of the article, and you want to give that author full control permissions (e.g. add, change and delete permissions).

What you need to do is just applying permission.logics.AuthorPermissionLogic to the Article model like

from django.db import models
from django.contrib.auth.models import User


class Article(models.Model):
    title = models.CharField('title', max_length=120)
    body = models.TextField('body')
    author = models.ForeignKey(User)

    # this is just required for easy explanation
    class Meta:
        app_label='permission'

# apply AuthorPermissionLogic
from permission import add_permission_logic
from permission.logics import AuthorPermissionLogic
add_permission_logic(Article, AuthorPermissionLogic())

Note

From django-permission version 0.8.0, you can specify related object with field__name attribute like django queryset lookup. See the working example below:

from django.db import models
from django.contrib.auth.models import User


class Article(models.Model):
    title = models.CharField('title', max_length=120)
    body = models.TextField('body')
    project = models.ForeignKey('permission.Project')

    # this is just required for easy explanation
    class Meta:
        app_label='permission'

class Project(models.Model):
    title = models.CharField('title', max_length=120)
    body = models.TextField('body')
    author = models.ForeignKey(User)

    # this is just required for easy explanation
    class Meta:
        app_label='permission'

# apply AuthorPermissionLogic to Article
from permission import add_permission_logic
from permission.logics import AuthorPermissionLogic
add_permission_logic(Article, AuthorPermissionLogic(
    field_name='project__author',
))

That's it. Now the following codes will work as expected:

user1 = User.objects.create_user(
    username='john',
    email='[email protected]',
    password='password',
)
user2 = User.objects.create_user(
    username='alice',
    email='[email protected]',
    password='password',
)

art1 = Article.objects.create(
    title="Article 1",
    body="foobar hogehoge",
    author=user1
)
art2 = Article.objects.create(
    title="Article 2",
    body="foobar hogehoge",
    author=user2
)

# You have to apply 'permission.add_article' to users manually because it
# is not an object permission.
from permission.utils.permissions import perm_to_permission
user1.user_permissions.add(perm_to_permission('permission.add_article'))

assert user1.has_perm('permission.add_article') == True
assert user1.has_perm('permission.change_article') == False
assert user1.has_perm('permission.change_article', art1) == True
assert user1.has_perm('permission.change_article', art2) == False

assert user2.has_perm('permission.add_article') == False
assert user2.has_perm('permission.delete_article') == False
assert user2.has_perm('permission.delete_article', art1) == False
assert user2.has_perm('permission.delete_article', art2) == True

#
# You may also be interested in django signals to apply 'add' permissions to the
# newly created users.
# https://docs.djangoproject.com/en/dev/ref/signals/#django.db.models.signals.post_save
#
from django.db.models.signals.post_save
from django.dispatch import receiver
from permission.utils.permissions import perm_to_permission

@receiver(post_save, sender=User)
def apply_permissions_to_new_user(sender, instance, created, **kwargs):
    if not created:
        return
    #
    # permissions you want to apply to the newly created user
    # YOU SHOULD NOT APPLY PERMISSIONS EXCEPT PERMISSIONS FOR 'ADD'
    # in this way, the applied permissions are not object permission so
    # if you apply 'permission.change_article' then the user can change
    # any article object.
    #
    permissions = [
        'permission.add_article',
    ]
    for permission in permissions:
        # apply permission
        # perm_to_permission is a utility to convert string permission
        # to permission instance.
        instance.user_permissions.add(perm_to_permission(permission))

See http://django-permission.readthedocs.org/en/latest/_modules/permission/logics/author.html#AuthorPermissionLogic to learn how this logic works.

Now, assume you add collaborators attribute to store collaborators of the article and you want to give them a change permission.

What you need to do is quite simple. Apply permission.logics.CollaboratorsPermissionLogic to the Article model as follows

from django.db import models
from django.contrib.auth.models import User


class Article(models.Model):
    title = models.CharField('title', max_length=120)
    body = models.TextField('body')
    author = models.ForeignKey(User)
    collaborators = models.ManyToManyField(User)

    # this is just required for easy explanation
    class Meta:
        app_label='permission'

# apply AuthorPermissionLogic and CollaboratorsPermissionLogic
from permission import add_permission_logic
from permission.logics import AuthorPermissionLogic
from permission.logics import CollaboratorsPermissionLogic
add_permission_logic(Article, AuthorPermissionLogic())
add_permission_logic(Article, CollaboratorsPermissionLogic(
    field_name='collaborators',
    any_permission=False,
    change_permission=True,
    delete_permission=False,
))

Note

From django-permission version 0.8.0, you can specify related object with field_name attribute like django queryset lookup. See the working example below:

from django.db import models
from django.contrib.auth.models import User


class Article(models.Model):
    title = models.CharField('title', max_length=120)
    body = models.TextField('body')
    project = models.ForeignKey('permission.Project')

    # this is just required for easy explanation
    class Meta:
        app_label='permission'

class Project(models.Model):
    title = models.CharField('title', max_length=120)
    body = models.TextField('body')
    collaborators = models.ManyToManyField(User)

    # this is just required for easy explanation
    class Meta:
        app_label='permission'

# apply AuthorPermissionLogic to Article
from permission import add_permission_logic
from permission.logics import CollaboratorsPermissionLogic
add_permission_logic(Article, CollaboratorsPermissionLogic(
    field_name='project__collaborators',
))

That's it. Now the following codes will work as expected:

user1 = User.objects.create_user(
    username='john',
    email='[email protected]',
    password='password',
)
user2 = User.objects.create_user(
    username='alice',
    email='[email protected]',
    password='password',
)

art1 = Article.objects.create(
    title="Article 1",
    body="foobar hogehoge",
    author=user1
)
art1.collaborators.add(user2)

assert user1.has_perm('permission.change_article') == False
assert user1.has_perm('permission.change_article', art1) == True
assert user1.has_perm('permission.delete_article', art1) == True

assert user2.has_perm('permission.change_article') == False
assert user2.has_perm('permission.change_article', art1) == True
assert user2.has_perm('permission.delete_article', art1) == False

See http://django-permission.readthedocs.org/en/latest/_modules/permission/logics/collaborators.html#CollaboratorsPermissionLogic to learn how this logic works.

There are StaffPermissionLogic and GroupInPermissionLogic for is_staff or group based permission logic as well.

Customize permission logic

Your own permission logic class must be a subclass of permission.logics.PermissionLogic and must override has_perm(user_obj, perm, obj=None) method which return boolean value.

Class, method, or function decorator

Like Django's permission_required but it can be used for object permissions and as a class, method, or function decorator. Also, you don't need to specify a object to this decorator for object permission. This decorator automatically determined the object from request (so you cannnot use this decorator for non view class/method/function but you anyway use user.has_perm in that case).

>>> from permission.decorators import permission_required
>>> # As class decorator
>>> @permission_required('auth.change_user')
>>> class UpdateAuthUserView(UpdateView):
...     pass
>>> # As method decorator
>>> class UpdateAuthUserView(UpdateView):
...     @permission_required('auth.change_user')
...     def dispatch(self, request, *args, **kwargs):
...         pass
>>> # As function decorator
>>> @permission_required('auth.change_user')
>>> def update_auth_user(request, *args, **kwargs):
...     pass

Override the builtin if template tag

django-permission overrides the builtin if tag, adding two operators to handle permissions in templates. You can write a permission test by using has keyword, and a target object with of as below.

{% if user has 'blogs.add_article' %}
    <p>This user have 'blogs.add_article' permissionp>
{% elif user has 'blog.change_article' of object %}
    <p>This user have 'blogs.change_article' permission of {{object}}p>
{% endif %}

{# If you set 'PERMISSION_REPLACE_BUILTIN_IF = False' in settings #}
{% permission user has 'blogs.add_article' %}
    <p>This user have 'blogs.add_article' permissionp>
{% elpermission user has 'blog.change_article' of object %}
    <p>This user have 'blogs.change_article' permission of {{object}}p>
{% endpermission %}

Note

From Django 1.9, users require to add 'permission.templatetags.permissionif' to 'builtins' option manually. See - https://docs.djangoproject.com/en/1.9/releases/1.9/#django-template-base-add-to-builtins-is-removed - https://docs.djangoproject.com/en/1.9/topics/templates/#module-django.template.backends.django Or following example:

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'OPTIONS': {
            'builtins': ['permission.templatetags.permissionif'],
        },
    },
]

License

The MIT License (MIT)

Copyright (c) 2015 Alisue, hashnote.net

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Comments
  • Two roles with admin in project

    Two roles with admin in project

    Good Nights, this is a question, not a issue.

    I need to do two types of users, and default admin and author user. An aditional permission for two users, Admin can publish news, author can't. Author only can created news, and only edit and delect his own news.

    A friend say me that for the second restrictions i need per object permissions, but i don't know how do all of this.

    Can you help me?

    question 
    opened by SalahAdDin 30
  • Warning Django 1.9

    Warning Django 1.9

    Please, update your app, now we have this warning:

    /home/tulipan/Proyectos/TiempoTurco/lib/python3.4/importlib/_bootstrap.py:321: RemovedInDjango19Warning: django.utils.importlib will be removed in Django 1.9.
      return f(*args, **kwds)
    
    /home/tulipan/Proyectos/IspanyolHaber/lib/python3.4/importlib/_bootstrap.py:321: RemovedInDjango19Warning: The utilities in django.db.models.loading are deprecated in favor of the new application loading system.
      return f(*args, **kwds)
    
    bug 
    opened by SalahAdDin 17
  • Custom permission logics documentation

    Custom permission logics documentation

    I am really struggling to understand how I am meant to use custom permission logics, I am pretty sure I am 99% of the way there, and that they're what I want, but the documentation is so sparse it's really putting me off, but yours appears to be the only library that seems to cater for this requirement.

    My current error is django.contrib.auth.models.DoesNotExist simply because the row doesn't exist in the auth_permission table.

    Now, I have no desire to maintain database records to describe my permissions – but I'd be happy to create these if necessary, but what I don't understand is what or where should be doing that, or more importantly, what binds permissions to logics, how does it know which logic class to run based on the permission being checked, and if it's multiple or all of them, what happens if one logic says yes and another says no? Unanimous voting? ¯_(ツ)_/¯

    question 
    opened by stevelacey 16
  • Ready to Use ?

    Ready to Use ?

    Is this software ready to use? You've mentioned that:

    This is under development. The codes below may not works in the future

    But I wonder if I can use the "current" version for my new started project ??

    question 
    opened by vahidR 16
  • Question - Permissions do not seem to be taking effect

    Question - Permissions do not seem to be taking effect

    Hello,

    Have posted the same question on stackoverflow in case that is a more appropriate place to post it.

    Have prepared a simple test app (almost identical to the example used in the docs) to try to figure out how it works. I have read the documentation and tried to use the example app provided on this link.

    The issue is when the author of an article is not able to edit/ delete the article.

    The user in question has been granted all permissions in the admin section.

    Key code listed below - any help much appreciated

    test_app/models.py

    class Article(models.Model):
        created_by = models.ForeignKey(User)
        created = models.DateField(auto_now_add=True)
        modified = models.DateField(auto_now=True)
        title = models.CharField(max_length=100)
        content = models.TextField()
    
        class Meta:
            app_label = 'test_app'
    
    from permission import add_permission_logic
    from permission.logics import AuthorPermissionLogic
    
    add_permission_logic(Article, AuthorPermissionLogic(
        field_name='created_by',
        any_permission = False,
        change_permission = True,
        delete_permission = True,
    ))
    

    test_app/views.py

    @permission_required('change_article')
    def change_article(request, *args, **kwargs):
        pk = kwargs.pop('pk')
        template = 'test_app/edit.html'
        article = models.Article.objects.get(id=pk)
    
        if request.method == 'POST':
            form = forms.Article_form(request.POST, instance=article)
    
            if form.is_valid():
                article = form.save(commit=False)
    
                article.created_by = request.user
                article.title = form.cleaned_data['title']
                article.content = form.cleaned_data['content']
    
                article.save()
    
                return HttpResponseRedirect('/test/')
    
            else:
    
                raise Http404
    
        else:
            form = forms.Article_form(instance=article)
    
            return render(request, template_name=template, context={'form':form})
    

    test_app/perms.py

    PERMISSION_LOGICS = (
        ('test_app.Article', AuthorPermissionLogic()),
    )
    
    question 
    opened by djbettega 11
  • restrict access instead of allowing it

    restrict access instead of allowing it

    Hi

    I want to use django-permission for a project I am working on, but I'm not sure how to achieve what I want. I used the normal django permissions stuff until now, but now I need to restrict access to some objects. I still want to use the django permissions for defining which user is generally allowed to read/add/change/delete objects. But I also want to add a check, that checks if a object is marked as private and if yes, the user has to be in a specific group.

    Now the problem is, that as soon as a user has the read permission for all objects of that model, my custom permission code is not called. But I want my custom permission code to be executed explicitly when a user has the global permission for that model to ensure that the user also has the permission for this specific object Is there any way to do this?

    question 
    opened by phillipthelen 9
  • ImportError if django 1.9 AppConfig is used for installed apps

    ImportError if django 1.9 AppConfig is used for installed apps

    if I add permission.autodiscover() to my urls.py, the following exception is thrown, if the Django 1.9 AppConfig ist used for my apps. If the .apps.ProjectAppConfig is removed, the exception does not occur.

    INSTALLED_APPS = [
        ...
        'project_app.apps.ProjectAppConfig',  # Not working
        # 'project_app',  # Working
    ]
    
    Traceback (most recent call last):
      File "/project/env/lib/python3.4/site-packages/django/utils/autoreload.py", line 226, in wrapper
        fn(*args, **kwargs)
      File "/project/env/lib/python3.4/site-packages/django/core/management/commands/runserver.py", line 116, in inner_run
        self.check(display_num_errors=True)
      File "/project/env/lib/python3.4/site-packages/django/core/management/base.py", line 426, in check
        include_deployment_checks=include_deployment_checks,
      File "/project/env/lib/python3.4/site-packages/django/core/checks/registry.py", line 75, in run_checks
        new_errors = check(app_configs=app_configs)
      File "/project/env/lib/python3.4/site-packages/django/core/checks/urls.py", line 10, in check_url_config
        return check_resolver(resolver)
      File "/project/env/lib/python3.4/site-packages/django/core/checks/urls.py", line 19, in check_resolver
        for pattern in resolver.url_patterns:
      File "/project/env/lib/python3.4/site-packages/django/utils/functional.py", line 33, in __get__
        res = instance.__dict__[self.name] = self.func(instance)
      File "/project/env/lib/python3.4/site-packages/django/core/urlresolvers.py", line 417, in url_patterns
        patterns = getattr(self.urlconf_module, "urlpatterns", self.urlconf_module)
      File "/project/env/lib/python3.4/site-packages/django/utils/functional.py", line 33, in __get__
        res = instance.__dict__[self.name] = self.func(instance)
      File "/project/env/lib/python3.4/site-packages/django/core/urlresolvers.py", line 410, in urlconf_module
        return import_module(self.urlconf_name)
      File "/project/env/lib/python3.4/importlib/__init__.py", line 109, in import_module
        return _bootstrap._gcd_import(name[level:], package, level)
      File "<frozen importlib._bootstrap>", line 2254, in _gcd_import
      File "<frozen importlib._bootstrap>", line 2237, in _find_and_load
      File "<frozen importlib._bootstrap>", line 2226, in _find_and_load_unlocked
      File "<frozen importlib._bootstrap>", line 1200, in _load_unlocked
      File "<frozen importlib._bootstrap>", line 1129, in _exec
      File "<frozen importlib._bootstrap>", line 1471, in exec_module
      File "<frozen importlib._bootstrap>", line 321, in _call_with_frames_removed
      File "/project/src/project/urls.py", line 21, in <module>
        permission.autodiscover()
      File "/project/env/lib/python3.4/site-packages/permission/utils/autodiscover.py", line 19, in autodiscover
        mod = import_module(app)
      File "/project/env/lib/python3.4/importlib/__init__.py", line 109, in import_module
        return _bootstrap._gcd_import(name[level:], package, level)
      File "<frozen importlib._bootstrap>", line 2254, in _gcd_import
      File "<frozen importlib._bootstrap>", line 2237, in _find_and_load
      File "<frozen importlib._bootstrap>", line 2221, in _find_and_load_unlocked
    ImportError: No module named 'project.apps.ProjectConfig'; 'project.apps' is not a package
    

    This hack fixes the error for now:

    #/project/env/lib/python3.4/site-packages/permission/utils/autodiscover.py:18
        for app in settings.INSTALLED_APPS:
            if '.apps.' in app:
                app = app.split('.')[0]
            mod = import_module(app)
    
    bug 
    opened by JanMalte 8
  • Fix import of `six` module

    Fix import of `six` module

    Django 3.0 doesn't have django.utils.six anymore, there was already a fix for that, but it wasn't being used in the file src/permission/utils/permissions.py. I'm just making this file use the same way to import the six module.

    opened by LuRsT 5
  • Django 1.9 compatibility - AppRegistryNotReady

    Django 1.9 compatibility - AppRegistryNotReady

    After upgrading to django 1.9 and running python manage.py check, I get the following error:

    Traceback (most recent call last):
      File "./manage.py", line 22, in <module>
        execute_from_command_line(sys.argv)
      File "/path/to/virtualenv/lib/python2.7/site-packages/django/core/management/__init__.py", line 350, in execute_from_command_line
        utility.execute()
      File "/path/to/virtualenv/lib/python2.7/site-packages/django/core/management/__init__.py", line 324, in execute
        django.setup()
      File "/path/to/virtualenv/lib/python2.7/site-packages/django/__init__.py", line 18, in setup
        apps.populate(settings.INSTALLED_APPS)
      File "/path/to/virtualenv/lib/python2.7/site-packages/django/apps/registry.py", line 85, in populate
        app_config = AppConfig.create(entry)
      File "/path/to/virtualenv/lib/python2.7/site-packages/django/apps/config.py", line 90, in create
        module = import_module(entry)
      File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/importlib/__init__.py", line 37, in import_module
        __import__(name)
      File "/path/to/virtualenv/lib/python2.7/site-packages/permission/__init__.py", line 9, in <module>
        from permission.utils.logics import add_permission_logic
      File "/path/to/virtualenv/lib/python2.7/site-packages/permission/utils/logics.py", line 6, in <module>
        from permission.logics import PermissionLogic
      File "/path/to/virtualenv/lib/python2.7/site-packages/permission/logics/__init__.py", line 7, in <module>
        from permission.logics.author import AuthorPermissionLogic
      File "/path/to/virtualenv/lib/python2.7/site-packages/permission/logics/author.py", line 6, in <module>
        from permission.conf import settings
      File "/path/to/virtualenv/lib/python2.7/site-packages/permission/conf.py", line 10, in <module>
        from permission.handlers import LogicalPermissionHandler
      File "/path/to/virtualenv/lib/python2.7/site-packages/permission/handlers.py", line 5, in <module>
        from permission.utils.permissions import get_app_perms
      File "/path/to/virtualenv/lib/python2.7/site-packages/permission/utils/permissions.py", line 9, in <module>
        from django.contrib.auth.models import Permission
      File "/path/to/virtualenv/lib/python2.7/site-packages/django/contrib/auth/models.py", line 4, in <module>
        from django.contrib.auth.base_user import AbstractBaseUser, BaseUserManager
      File "/path/to/virtualenv/lib/python2.7/site-packages/django/contrib/auth/base_user.py", line 49, in <module>
        class AbstractBaseUser(models.Model):
      File "/path/to/virtualenv/lib/python2.7/site-packages/django/db/models/base.py", line 94, in __new__
        app_config = apps.get_containing_app_config(module)
      File "/path/to/virtualenv/lib/python2.7/site-packages/django/apps/registry.py", line 239, in get_containing_app_config
        self.check_apps_ready()
      File "/path/to/virtualenv/lib/python2.7/site-packages/django/apps/registry.py", line 124, in check_apps_ready
        raise AppRegistryNotReady("Apps aren't loaded yet.")
    django.core.exceptions.AppRegistryNotReady: Apps aren't loaded yet.
    
    opened by theskumar 4
  • "manage.py dumpdata" fails when permission app is active

    $ ./manage.py dumpdata Error: Can't resolve dependencies for permission.Role in serialized app list.

    However, excluding permission app works fine. $ ./manage.py dumpdata -e permission [result as expected]

    bug wontfix 
    opened by Shanto 4
  • TypeError get_object() takes 1 positional argument but 2 were given

    TypeError get_object() takes 1 positional argument but 2 were given

    Hello again,

    I am trying to use django-permission in conjunction with another app called django-viewflow. When I try the following code on it's own it works as expected, however, when I apply the django-permission decorator it throws the error.

    views.py

    from permission.decorators import permission_required
    
    @permission_required('test_app_cbv.change_cbvarticle')
    class ArticleCreate(StartFlowMixin, generic.UpdateView):
    
        model = models.CBVArticle
        form_class = forms.Article_form
        template_name = 'test_app_cbv/edit.html'
    
        def form_valid(self, form):
            obj = form.save(commit=False)
            obj.created_by_id = self.request.user.id
            obj.save()
            return super(ArticleCreate, self).form_valid(form)
    
        def get_object(self):
            return self.activation.process.article
    
        def activation_done(self, form):
            article = form.save()
            self.activation.process.article = article
            super(ArticleCreate, self).activation_done(form)
    
        def dispatch(self, request, **kwargs):
            return super(ArticleCreate, self).dispatch(request, **kwargs)
    

    The error details are as follows

    get_object() takes 1 positional argument but 2 were given

    /home/daniel/Django1.11.4/python3.5.2/lib/python3.5/site-packages/permission/decorators/classbase.py in get_object_from_classbased_instance

    1. obj = instance.get_object(queryset)

    Variable | Value -- | -- BaseCreateView | <class 'django.views.generic.edit.BaseCreateView'> args | () instance | <test_app_cbv.views.ArticleCreate object at 0x7f8c985fa7b8> kwargs | {'flow_class': <test_app_cbv.flow.CBVArticleFlow object at 0x7f8c98a11e10>, 'flow_task': <viewflow.flow.nodes.Start object at 0x7f8c98a11710>} queryset | <QuerySet [<CBVArticle: CBVArticle object>]> request | <WSGIRequest: GET '/test_cbv/process/start/'>

    I have a pretty basic understanding of python - so I am pretty sure that the error is due to something I have not understood. Any suggestions would be great. Thanks in advance!

    opened by djbettega 3
  • The documentation is difficult to follow

    The documentation is difficult to follow

    class Article(models.Model):
        title = models.CharField('title', max_length=120)
        body = models.TextField('body')
        project = models.ForeignKey('permission.Project')
    
        # this is just required for easy explanation
        class Meta:
            app_label='permission'
    
    class Project(models.Model):
        title = models.CharField('title', max_length=120)
        body = models.TextField('body')
        author = models.ForeignKey(User)
    
        # this is just required for easy explanation
        class Meta:
            app_label='permission'
    
    # apply AuthorPermissionLogic to Article
    from permission import add_permission_logic
    from permission.logics import AuthorPermissionLogic
    add_permission_logic(Article, AuthorPermissionLogic(
        field_name='project__author',
    ))
    

    I am really not sure what is the permission mentioned in the code block.

    1. Is it the package of the permission we just installed?
    2. Is it an app that host the Article and Project?

    It is really difficult to follow when applying to my own code on which permission should I replace and which permission should I keep.

    opened by weasteam 0
  • Stay at model level

    Stay at model level

    Hello, I love this package, it's awesome thank you. Is there a way to use the permission_required decorator on a ListView (or any CBV with a get_queryset method) on a Model level and thus checking the has_perm only once.

    Right now I'm using the django.contrib.auth.mixins.PermissionRequiredMixin, but I love the permission_required decorator.

    Basically I would love to do something like

    from permission.decorators import permission_required
    
    @permission_required('blog.view_post',stay_at_model_level=True)
    class PostList(ListView):
        model = Post
    

    Instead of doing :

    from django.contrib.auth.mixins import PermissionRequiredMixin
    
    class PostList(PermissionRequiredMixin, ListView):
        model = Post
        permission_required = 'blog.view_post'
    
    enhancement 
    opened by LucasBerbesson 1
  • Custom permission logic with @permission_required() decorator and {% if ... %} tag config issue

    Custom permission logic with @permission_required() decorator and {% if ... %} tag config issue

    Hello! I've read the docs, read #26 and #28 examples, tried to find out where I've mistaken using Kawaz sources, but still can't understand where I've made a mistake.

    I'm using Djnago 1.11 with Python 3.6.1 and django-permission 1.4.0 (also tried under django 1.10.7, python 3.6.0) I have 'console_test' project with 'console' app inside it. It has 1 model called Deal, so my models.py looks like this:

    #models.py
    from django.db import models
    
    # Create your models here.
    from django.contrib.auth.models import User
    
    class Deal(models.Model):
        title = models.CharField(max_length=200)
        desc = models.CharField(max_length=200, blank=True)
        user = models.ForeignKey(User)
    

    In settings.py of the project I've: 1)Added permission to INSTALLED_APPS:

    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'console',
        'permission',
    ]
    

    2)Added 'builtins': ['permission.templatetags.permissionif'], for using {% if user has ... %} in TEMPLATES:

    TEMPLATES = [
        {
            'BACKEND': 'django.template.backends.django.DjangoTemplates',
            'DIRS': [os.path.join(BASE_DIR, 'templates')]
            ,
            'APP_DIRS': True,
            'OPTIONS': {
                'context_processors': [
                    'django.template.context_processors.debug',
                    'django.template.context_processors.request',
                    'django.contrib.auth.context_processors.auth',
                    'django.contrib.messages.context_processors.messages',
                ],
                'builtins': ['permission.templatetags.permissionif'],
    
            },
        },
    ]
    

    3)Added to the bottom of the settings.py AUTHENTICATION_BACKENDS:

    AUTHENTICATION_BACKENDS = (
        'django.contrib.auth.backends.ModelBackend', # default
        'permission.backends.PermissionBackend',
    )
    

    4)Then in project's urls.py (not app's) I've added Autodiscover

    #urls.py
    from django.conf.urls import url, include
    from django.contrib import admin
    from django.contrib.auth import views as auth_views
    
    import permission; permission.autodiscover()
    
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^console/', include('console.urls', namespace="console")),
        url(r'^accounts/login/$', auth_views.login, {'template_name': 'login.html'}, name='login'),
        url(r'^accounts/logout/$', auth_views.logout_then_login, name='logout'),
    ]
    

    5)Then I've created perms.py file inside 'console' app dir (Is it right? Not in 'console_test' project root?) with AuthorPermissionLogic, StaffPermissionLogic and CustomPermissionLogic (for test purposes it always returns True):

    #perms.py
    from permission.logics import AuthorPermissionLogic, StaffPermissionLogic, PermissionLogic
    
    class CustomPermissionLogic(PermissionLogic):
        def has_perm(self, user_obj, perm, obj=None):
            return True
    
    PERMISSION_LOGICS = (
        ('console.Deal', AuthorPermissionLogic()),
        ('console.Deal', StaffPermissionLogic()),
        ('console.Deal', CustomPermissionLogic()),
    )
    

    In views I have 4 views (Index, Result, Detail and Change).

    #views.py
    from django.shortcuts import render
    
    from django.shortcuts import get_object_or_404
    from django.http import HttpResponse,HttpResponseRedirect
    from django.core.urlresolvers import reverse
    
    from .models import Deal
    from django.views import generic
    from permission.decorators import permission_required
    
    class IndexView(generic.ListView):
        template_name = 'index.html'
        context_object_name = 'model_list'
    
        def get_queryset(self):
            return Deal.objects.all()
    
    def change(request, model_id):
        model = get_object_or_404(Deal, pk=model_id)
        try:
            model.title = request.POST['title']
            model.desc = request.POST['desc']
            model.save()
            return HttpResponseRedirect(reverse('console:results', args=(model.id,)))
        except:
            return HttpResponse("Error changing model")
    
    def detail(request, *args, **kwargs):
        model = get_object_or_404(Deal, pk=kwargs['model_id'])
        return render(request, 'detail.html', {'model': model})
    
    def results(request, *args, **kwargs):
        model = get_object_or_404(Deal, pk=kwargs['model_id'])
        return render(request, 'results.html', {'model': model})
    

    console app's urls.py are simple

    #urls.py
    from django.conf.urls import url
    from . import views
    urlpatterns = [
        url(r'^$', views.IndexView.as_view(), name='index'),
        url(r'^(?P<model_id>[0-9]+)/detail/$', views.detail, name='detail'),
        url(r'^(?P<model_id>[0-9]+)/results/$', views.results, name='results'),
        url(r'^(?P<model_id>[0-9]+)/change/$', views.change, name='change'),
    ]
    

    I've tried a lot to make this module working for me but unfortunately unsuccessfully.

    If I try to use, for example, 'deal.read' for permission name with @permission_required decorator I'm always getting error "Permission matching query does not exist.

    If I try to use for example, 'read' for permission name @permission_required decorator I've always being redirected to login screen (no matter what CustomPermissionLogic has_perm function returns). Could you tell me where I've made a mistake?

    So views under this decorator are unreachable for users. Super-user can reach these views (as I understand no permission checking is made for him) but {% if user has ... %} template tags inside view template also doesn't work.

    So I have some questions:

    1. If I want to use @permission_required decorator to limit access to some views (for ex. With list of models and Detail page), how can I do that? What permission name I must use to limit access with that built-in Logic?

    If I want to use AuthorPermissionLogic, StaffPermissionLogic, GroupInPermissionLogic what permission name must be? Must I use 'app_name.permission_name' or 'model_name.permission_name' or 'app_name.model_name.permission_name' or just 'permission_name'? Is it connected somehow with Logic?

    Example

    @permission_required('staff? or console.staff? or deal.staff?') How to combine them (for ex. Author and Custom), with a list (['staff','author']?

    1. The same situation, if I want to use {% if user has ... %} template tags?

    2. I've created CustomPermissionLogic and want to create permissions for viewing, deleting, and modifying Deal model objects. How can I bind by permissions to be processed by CustomPermissionLogic. I've tried to check whether has_perm function is used during permission-checking process but it seems that it is unreachable, return True or return False or raise Exception inside it has no effect at alaa. I can't understand how to bind permissions to model or to CustomPermissionLogic. How does django-permission module bind them?

    Example:

    I want Deal model to have permissions: read, modify and delete CustomPermissionLogic has has_perm function, that can process that permissions and return True or False. CustomPermissionLogic binded to Deal model via perms.py file inside console app dir ('console.Deal', CustomPermissionLogic()), How to bind my "new permissions" to Deal or to CustomPermissionLogic to use them with @permission_required() or {% if user has ... %}

    question 
    opened by tabakov 1
  • Add configuration to return False if `of obj` is specifed but `obj` is None.

    Add configuration to return False if `of obj` is specifed but `obj` is None.

    Currently when obj context is not exists in the template, something like {% if user has 'app_label.change_model' of obj %} return non object permission.

    It is a correct behavior but usually non object permission should return True based on basic django concept (https://code.djangoproject.com/wiki/RowLevelPermissions) thus the following code will render links for chaning/deleting the object even if the accessed user does not have such permissions for the object.

    {# assume if obj is None or context does not have obj #}
    {% if user has 'foo.change_bar' of obj %}
    <a href="{% url 'foo_bar_change' pk=obj.pk %}">Change</a>
    {% endif %}
    {% if user has 'foo.delete_bar' of obj %}
    <a href="{% url 'foo_bar_delete' pk=obj.pk %}">Delete</a>
    {% endif %}
    

    It is quite annoying thus add PERMISSION_RETURN_FALSE_IF_NONE_IN_TEMPLATE or whatever configuration and check obj value at https://github.com/lambdalisue/django-permission/blob/master/src/permission/templatetags/permissionif.py#L38 and return False if of obj keyword is specified but obj is None.

    enhancement 
    opened by lambdalisue 0
  • Create full sample project

    Create full sample project

    Hello, if you could create a sample project would be great. The documentation seems a bit confusing to me, working example code can be more explicit and easier to understand

    Thanks.

    enhancement question 
    opened by luzfcb 3
Owner
Alisue
Vim, Python, Rust, Deno
Alisue
JSON Web Token Authentication support for Django REST Framework

REST framework JWT Auth Notice This project is currently unmaintained. Check #484 for more details and suggested alternatives. JSON Web Token Authenti

José Padilla 3.2k Dec 31, 2022
JSON Web Token Authentication support for Django REST Framework

REST framework JWT Auth JSON Web Token Authentication support for Django REST Framework Overview This package provides JSON Web Token Authentication s

Styria Digital Development 178 Jan 2, 2023
python-social-auth and oauth2 support for django-rest-framework

Django REST Framework Social OAuth2 This module provides OAuth2 social authentication support for applications in Django REST Framework. The aim of th

null 1k Dec 22, 2022
python-social-auth and oauth2 support for django-rest-framework

Django REST Framework Social OAuth2 This module provides OAuth2 social authentication support for applications in Django REST Framework. The aim of th

null 1k Dec 22, 2022
REST implementation of Django authentication system.

djoser REST implementation of Django authentication system. djoser library provides a set of Django Rest Framework views to handle basic actions such

Sunscrapers 2.2k Jan 1, 2023
Login System Using Django

Login System Django

Nandini Chhajed 6 Dec 12, 2021
Extending the Django authentication system with a phone verification step.

Extending the Django authentication system with a phone verification step.

Miguel Grinberg 50 Dec 4, 2022
Django Auth Protection This package logout users from the system by changing the password in Simple JWT REST API.

Django Auth Protection Django Auth Protection This package logout users from the system by changing the password in REST API. Why Django Auth Protecti

Iman Karimi 5 Oct 26, 2022
Per object permissions for Django

django-guardian django-guardian is an implementation of per object permissions [1] on top of Django's authorization backend Documentation Online docum

null 3.3k Jan 1, 2023
Django-registration (redux) provides user registration functionality for Django websites.

Description: Django-registration provides user registration functionality for Django websites. maintainers: Macropin, DiCato, and joshblum contributor

Andrew Cutler 920 Jan 8, 2023
Complete Two-Factor Authentication for Django providing the easiest integration into most Django projects.

Django Two-Factor Authentication Complete Two-Factor Authentication for Django. Built on top of the one-time password framework django-otp and Django'

Bouke Haarsma 1.3k Jan 4, 2023
Django Admin Two-Factor Authentication, allows you to login django admin with google authenticator.

Django Admin Two-Factor Authentication Django Admin Two-Factor Authentication, allows you to login django admin with google authenticator. Why Django

Iman Karimi 9 Dec 7, 2022
Django-react-firebase-auth - A web app showcasing OAuth2.0 + OpenID Connect using Firebase, Django-Rest-Framework and React

Demo app to show Django Rest Framework working with Firebase for authentication

Teshank Raut 6 Oct 13, 2022
OAuthlib support for Python-Requests!

Requests-OAuthlib This project provides first-class OAuth library support for Requests. The OAuth 1 workflow OAuth 1 can seem overly complicated and i

null 1.6k Dec 28, 2022
An open source Flask extension that provides JWT support (with batteries included)!

Flask-JWT-Extended Features Flask-JWT-Extended not only adds support for using JSON Web Tokens (JWT) to Flask for protecting views, but also many help

Landon Gilbert-Bland 1.4k Jan 4, 2023
FastAPI extension that provides JWT Auth support (secure, easy to use, and lightweight)

FastAPI JWT Auth Documentation: https://indominusbyte.github.io/fastapi-jwt-auth Source Code: https://github.com/IndominusByte/fastapi-jwt-auth Featur

Nyoman Pradipta Dewantara 468 Jan 1, 2023
Easy and secure implementation of Azure AD for your FastAPI APIs 🔒 Single- and multi-tenant support.

Easy and secure implementation of Azure AD for your FastAPI APIs ?? Single- and multi-tenant support.

Intility 220 Jan 5, 2023
A host-guest based app in which host can CREATE the room. and guest can join room with room code and vote for song to skip. User is authenticated using Spotify API

A host-guest based app in which host can CREATE the room. and guest can join room with room code and vote for song to skip. User is authenticated using Spotify API

Aman Raj 5 May 10, 2022
Simple two factor authemtication system, made by me.

Simple two factor authemtication system, made by me. Honestly, i don't even know How 2FAs work I just used my knowledge and did whatever i could. Send

Refined 5 Jan 4, 2022