Skip to main content

Permissions System

This guide explains the technical implementation of Deepdesk's permissions system, which extends Django's built-in authentication and content types framework.

Prerequisites

This guide assumes familiarity with:

Architecture Overview

Deepdesk's permissions system is built on top of Django's permission framework with custom extensions to support role-based access control across the platform.

Single Source of Truth

All permissions configuration is maintained in core.permissions. This module contains the complete configuration of permissions per group, ensuring consistency across the system.

Groups Over Users

Permissions are assigned to groups rather than individual users. This approach:

  • Simplifies management at scale
  • Ensures consistent permission sets for users with the same role
  • Makes it easier to audit and modify access control
warning

Not recommended: Assigning individual permissions directly to users. Always use group-based permissions instead.

System Groups

Deepdesk has four system groups that are automatically set up during provisioning:

Agent
Studio Editor
Assistants Editor
Manager

These groups correspond to the Deepdesk roles available in the system.

Permission Configuration

Each group has a list of permission types and content types, for example:

  • view_assistant - Permission to view assistants
  • change_assistant - Permission to modify assistants

Permissions are scoped to specific apps (Django apps, roughly equivalent to domains in DDD terminology).

A group can use the * wildcard to grant all permissions for all models under a specific domain.

Provisioning

The core.permissions module provides the provision_groups_and_permissions() function that resets the permissions configuration for all groups according to the defined configuration.

When Provisioning Occurs

Provisioning is triggered:

  • During deployment: The provision script calls provision_groups_and_permissions()
  • In unit tests: Test factories automatically provision groups and permissions
  • Manual provisioning: Can be triggered via the admin interface when needed

This ensures that all accounts across all environments have the latest permissions configuration.

Permissions in API Views

Most Django REST Framework (DRF) class-based views use custom permission classes to enforce access control.

HasSessionOrTokenPermission

The custom permission class core.api.permissions.HasSessionOrTokenPermission determines whether to serve or refuse a user action based on:

  1. OAuth2 Token Scope (TokenHasResourceScope from django-oauth2)
    • Provides permission based on OAuth token scope
    • Independent of the Django permissions system

OR

  1. Django Permission Classes:
    • IsAuthenticated - Used when the view does not have a queryset or get_queryset implementation
    • FullDjangoModelPermissions - Used when the view has a queryset; enforces permissions based on content types as configured per group

FullDjangoModelPermissions

This is a custom permissions class implemented by Deepdesk because vanilla DRF does not enforce view-based access control by default.

info

For more details, see the broken access control discussion.

Refer to the tests for HasSessionOrTokenPermission for examples and test data setup patterns.

Test Data Factories

To facilitate testing of access control, Deepdesk provides Factory Boy classes that automatically set up:

  • A user belonging to a specific group
  • That group having all appropriate permissions per the configuration

Available factories:

AgentUserFactory
StudioEditorUserFactory
ManagerUserFactory
AssistantEditorUserFactory

Testing Best Practices

  • Use the factories: Always use these factories when testing access control
  • Be consistent: If you find tests that should use these factories but don't, refactor them to use the factories
  • Don't bypass: Avoid creating users or permissions manually in tests when factories are available

Code References

note

All code references in this guide are based on the codebase structure at the time of writing. Refer to the actual codebase for the most current implementation.

See Also