Skip to main content

Cedar policy-based authorization for Django

Project description

django-cedar

Cedar policy-based authorization for Django.

Cedar is an open-source policy language for expressive, analyzable permissions. django-cedar lets you express who can do what in Cedar policy files instead of scattering permission logic through your views, and enforces those policies with class-based-view mixins.

Requirements

  • Python 3.12+
  • Django 5.2+

Your user model must subclass django.contrib.auth.models.AbstractUser. The Cedar principal type is always User, regardless of the model's class name.

Installation

pip install django-cedar

Add the app (optional, but recommended — it enables startup-time configuration checks via Django's system check framework):

INSTALLED_APPS = [
    # ...
    "django_cedar",
]

Quickstart

1. Write a policy file (policies.cedar next to manage.py):

// Staff can do anything
permit(principal, action, resource)
when { principal.is_staff };

// Anyone signed in can view widgets
permit(principal is User, action == Action::"ViewWidget", resource);

2. Point Django at it:

CEDAR_POLICY_PATH = "policies.cedar"  # relative paths resolve against BASE_DIR

3. Enforce it in your views:

from django_cedar.views import AuthorizedDetailView

from .models import Widget


class WidgetDetailView(AuthorizedDetailView):
    model = Widget
    action_names = {"GET": "ViewWidget"}

Every request is authorized in dispatch(). The Cedar request is built as:

  • principalUser::"<pk>" for authenticated users, Anonymous::"guest" otherwise. User entities carry id, is_staff and is_superuser attributes, and the user's Django groups become parent entities (Group::"<name>"), so principal in Group::"editors" works out of the box.
  • actionAction::"<name>" from the view's action_names mapping (HTTP method → action name). HEAD requests are authorized using the view's "GET" action mapping; a "HEAD" key in action_names is not consulted.
  • resource — the object returned by the view's get_resource() hook, as <ModelClass>::"<pk>"; System::"global" when there is no resource.

Denied requests raise django.core.exceptions.PermissionDenied (HTTP 403).

Views and mixins

Class Resource used for the check
AuthorizedDetailView / AuthorizedUpdateView / AuthorizedDeleteView self.get_object()
AuthorizedListView / AuthorizedCreateView / AuthorizedTemplateView / AuthorizedFormView System::"global" (override get_resource())

Compose the behavior yourself with CedarAuthorizationMixin plus:

  • ResourceIsCurrentObjectMixin — authorize against self.get_object().
  • CurrentUserScopedMixin — authorize against the current user and filter the queryset to user=<request.user>.
  • AsyncLoginRequiredMixin — a LoginRequiredMixin that works on async views. CedarAuthorizationMixin itself supports async views too.

Custom scoping is one method:

class ProjectScopedView(CedarAuthorizationMixin, ListView):
    action_names = {"GET": "ListTasks"}

    def get_resource(self, request):
        return Project.objects.get(pk=self.kwargs["project_pk"])

Exposing model attributes to policies

Models opt in to exposing attributes with authz_fields(), and pull related entities into the request with authz_related_entities():

class Task(models.Model):
    project = models.ForeignKey(Project, on_delete=models.CASCADE)
    status = models.CharField(max_length=20)

    def authz_fields(self):
        return {"status": self.status, "project": str(self.project_id)}

    def authz_related_entities(self):
        return [self.project]
permit(principal, action == Action::"CloseTask", resource is Task)
when { resource.status == "open" };

Settings

Setting Required Description
CEDAR_POLICY_PATH yes Path to the Cedar policy file. Relative paths resolve against BASE_DIR.
CEDAR_PRINCIPAL_ATTRIBUTE_PROVIDERS no List of dotted paths to classes with get_attributes(user) -> dict (extra principal attributes) and optionally get_entities(user) -> iterable[Entity] (extra entities).
CEDAR_CONTEXT_PROVIDERS no List of dotted paths to classes with get_context(user, action, resource) -> dict. Results are deep-merged into the Cedar request context in list order; a per-call context= argument merges last and wins.

Example context provider:

class FeatureFlagContext:
    def get_context(self, user, action, resource):
        return {"allow": {"self_signup": settings.ALLOW_SELF_SIGNUP}}

Using the engine directly

from django_cedar import create_authz

authz = create_authz()  # loads policies + providers from settings (cached)
authz.authorize(request.user, "ExportReport", report)  # raises PermissionDenied on deny

System checks

With django_cedar in INSTALLED_APPS, manage.py check (and every server start) verifies that CEDAR_POLICY_PATH is set and the file exists (django_cedar.E001/E002), that it parses as Cedar (E003), that the provider settings are lists or tuples (E006), and that all configured providers import and have the right methods (E004/E005).

License

Apache-2.0

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

django_cedar-0.1.0.tar.gz (13.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

django_cedar-0.1.0-py3-none-any.whl (15.7 kB view details)

Uploaded Python 3

File details

Details for the file django_cedar-0.1.0.tar.gz.

File metadata

  • Download URL: django_cedar-0.1.0.tar.gz
  • Upload date:
  • Size: 13.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for django_cedar-0.1.0.tar.gz
Algorithm Hash digest
SHA256 67092340c6ce7a9dbaa16d14c0d2489412401c21715f33cc6a53bc4dba1a41b1
MD5 102926910f14a0964501f301faabb221
BLAKE2b-256 3dd29c54206f48c4fa4fc601072f9a111a3f89d88a9546034a85b6addcdb88ca

See more details on using hashes here.

Provenance

The following attestation bundles were made for django_cedar-0.1.0.tar.gz:

Publisher: publish.yml on hyperscale-consulting/django-cedar

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file django_cedar-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: django_cedar-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 15.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.13

File hashes

Hashes for django_cedar-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 2bb928f4de0dd1c7fde78948b64f092bf1ea377895d8220b8e5e0982a16cb0c3
MD5 e80dc20034c6d84189d5aba7c47882e7
BLAKE2b-256 b42419920e9351c66366fd64a06e058fca17176f9dfe880de4749bcd5c840056

See more details on using hashes here.

Provenance

The following attestation bundles were made for django_cedar-0.1.0-py3-none-any.whl:

Publisher: publish.yml on hyperscale-consulting/django-cedar

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page