Metadata-Version: 2.0
Name: django-auth-utils
Version: 0.1.1
Summary: Django authentication and authorization utilities
Home-page: https://github.com/pjdelport/django-auth-utils
Author: Pi Delport
Author-email: pjdelport@gmail.com
License: Public Domain
Description-Content-Type: UNKNOWN
Platform: UNKNOWN
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Web Environment
Classifier: Framework :: Django
Classifier: Intended Audience :: Developers
Classifier: License :: Public Domain
Classifier: Programming Language :: Python :: 2
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Internet :: WWW/HTTP
Classifier: Topic :: Security
Classifier: Topic :: Software Development :: Libraries
Classifier: Topic :: Utilities
Requires-Dist: attrs
Requires-Dist: Django

=================
django-auth-utils
=================

Django authentication and authorization utilities.

.. image:: https://img.shields.io/pypi/v/django-auth-utils.svg
    :target: https://pypi.python.org/pypi/django-auth-utils

.. image:: https://img.shields.io/badge/source-GitHub-lightgrey.svg
    :target: https://github.com/pjdelport/django-auth-utils

.. image:: https://img.shields.io/github/issues/pjdelport/django-auth-utils.svg
    :target: https://github.com/pjdelport/django-auth-utils/issues?q=is:open

.. image:: https://travis-ci.org/pjdelport/django-auth-utils.svg?branch=master
    :target: https://travis-ci.org/pjdelport/django-auth-utils

.. image:: https://codecov.io/github/pjdelport/django-auth-utils/coverage.svg?branch=master
    :target: https://codecov.io/github/pjdelport/django-auth-utils?branch=master

.. contents::

Installation
============

.. code:: shell

    pip install django-auth-utils

Supported and tested on:

* Python: 2.7, 3.4, 3.5, 3.6, PyPy, PyPy3
* Django: 1.8, 1.10, 1.11


Configuration
=============

In order to use the ``auth_utils`` template tag library, add ``auth_utils`` to your ``INSTALLED_APPS``.

Alternatively, since Django 1.9, you can add ``auth_utils.templatetags.auth_utils`` to your
DjangoTemplates_ OPTIONS.


.. _DjangoTemplates:
    https://docs.djangoproject.com/en/1.9/topics/templates/#django.template.backends.django.DjangoTemplates


Usage
=====


Permission-checking views
-------------------------

The ``ObjectPermissionRequiredMixin`` view combines Django's PermissionRequiredMixin_ and
SingleObjectMixin_ views, and performs the permission check against the object that was looked up.

.. _PermissionRequiredMixin:
    https://docs.djangoproject.com/en/1.9/topics/auth/default/#the-permissionrequiredmixin-mixin

.. _SingleObjectMixin:
    https://docs.djangoproject.com/en/1.9/ref/class-based-views/mixins-single-object/#singleobjectmixin

Use it like the base classes:

.. code:: python

    from auth_utils.views import ObjectPermissionRequiredMixin


    class ArticleDetail(ObjectPermissionRequiredMixin, generic.DetailView):
        model = Article
        permission_required = ['news.read_article']


    class ArticleUpdate(ObjectPermissionRequiredMixin, generic.UpdateView):
        model = Article
        permission_required = ['news.change_article']


Permission-checking in templates
--------------------------------

Load the template tag library:

.. code:: django

    {% load auth_utils %}

The ``perms`` filter allows checking object-level permissions with a convenient syntax:

.. code:: django

    {% if perm in user|perms:object %} ... {% endif %}

The ``object`` argument is optional. If omitted, the global permission is checked,
similar to Django's `perms object`_.

.. _perms object:
    https://docs.djangoproject.com/en/1.9/topics/auth/default/#permissions

Examples:

.. code:: html+django


    {% if 'news.read_article' in user|perms:article %}
        {{ article.text }}
    {% else %}
        You do not have permission to read this article.
    {% endif %}


    {% if 'news.change_article' in user|perms:article %}
        <a href="...">Edit article</a>
    {% endif %}

    {% if 'news.delete_article' in user|perms:article %}
        <a href="...">Delete article</a>
    {% endif %}

The library provides ``can_change`` and ``can_delete`` shorthands for checking Django's default
``app.change_model`` and ``app.delete_model`` model permissions:

.. code:: html+django

    {% if user|can_change:article %} <a href="...">Edit</a> {% endif %}
    {% if user|can_delete:article %} <a href="...">Delete</a> {% endif %}


``BaseAuthorizationBackend``
----------------------------

This base class provides all the boilerplate code necessary for a Django `authentication backend`_
to work, without performing any user authentication or permission authorization itself.

This is intended to make it easy to write `custom authorization`_ policies that only implement the backend
methods they're interested in:

.. _authentication backend:
    https://docs.djangoproject.com/en/1.9/topics/auth/customizing/#writing-an-authentication-backend

.. _custom authorization:
    https://docs.djangoproject.com/en/1.9/topics/auth/customizing/#handling-authorization-in-custom-backends

.. code:: python

    from auth_utils.backends import BaseAuthorizationBackend


    class ArticleEditPolicy(BaseAuthorizationBackend):
        """
        Allow authors to change and delete their own articles.
        """

        def get_user_permissions(self, user_obj, obj=None):
            is_author = isinstance(obj, Article) and article.author == user_obj
            if user_obj.is_active and is_author:
                return {'news.change_article', 'news.delete_article'}
            else:
                return set()


    class GuestAccessPolicy(BaseAuthorizationBackend):
        """
        Allow anonymous users to read non-premium articles.
        """

        def get_user_permissions(self, user_obj, obj=None):
            guest_readable = isinstance(obj, Article) and not article.is_premium
            if not user_obj.is_authenticated() and guest_readable:
                return {'news.read_article'}
            else:
                return set()

Once defined, these policies can be enabled in AUTHENTICATION_BACKENDS_:

.. code:: python

    AUTHENTICATION_BACKENDS = [
        'django.contrib.auth.backends.ModelBackend',

        # Custom authorization policies
        'news.auth.ArticleEditPolicy',
        'news.auth.GuestAccessPolicy',
    ]

.. _AUTHENTICATION_BACKENDS:
    https://docs.djangoproject.com/en/1.9/ref/settings/#std:setting-AUTHENTICATION_BACKENDS


Related work
============

Inspiration: `django-model-utils`_

`django-guardian`_ provides object-based permission checking utilities:

* View: An `alternative PermissionRequiredMixin`_, predating Django's one
* Template tag: `get_obj_perms`_, using somewhat clunkier assignment syntax


.. _django-model-utils: https://django-model-utils.readthedocs.org/

.. _django-guardian: http://django-guardian.readthedocs.org/
.. _alternative PermissionRequiredMixin:
    http://django-guardian.readthedocs.org/en/stable/api/guardian.mixins.html#permissionrequiredmixin
.. _get_obj_perms:
    http://django-guardian.readthedocs.org/en/stable/api/guardian.templatetags.guardian_tags.html#get-obj-perms


