openedx_authz package#

Subpackages#

Submodules#

openedx_authz.admin module#

Admin configuration for openedx_authz.

class openedx_authz.admin.AuthzCourseAuthoringMigrationRunAdmin(model, admin_site)

Bases: ModelAdmin

Admin for AuthzCourseAuthoringMigrationRun to display additional metadata.

fields = ('scope_type', 'scope_key', 'migration_type', 'status', 'pretty_metadata', 'completed_at', 'created_at', 'updated_at')
list_display = ('id', 'scope_type', 'scope_key', 'migration_type', 'status', 'created_at', 'updated_at')
list_filter = ('scope_type', 'migration_type', 'status')
property media
pretty_metadata(obj)

Return formatted JSON for the metadata field.

readonly_fields = ('scope_type', 'scope_key', 'migration_type', 'status', 'pretty_metadata', 'completed_at', 'created_at', 'updated_at')
search_fields = ('scope_type', 'scope_key', 'migration_type', 'status')
class openedx_authz.admin.CasbinRuleAdmin(model, admin_site)

Bases: ModelAdmin

Admin for CasbinRule to display additional metadata.

form

alias of CasbinRuleForm

inlines = [<class 'openedx_authz.admin.ExtendedCasbinRuleInline'>]
list_display = ('id', 'ptype', 'v0', 'v1', 'v2', 'v3', 'v4', 'v5')
list_filter = ('ptype',)
property media
search_fields = ('ptype', 'v0', 'v1', 'v2', 'v3', 'v4', 'v5')
class openedx_authz.admin.CasbinRuleForm(*args, **kwargs)

Bases: ModelForm

Custom form for CasbinRule to make v3, v4, v5 fields optional.

class Meta

Bases: object

Meta class for CasbinRuleForm.

fields = '__all__'
model

alias of CasbinRule

base_fields = {'ptype': <django.forms.fields.CharField object>, 'v0': <django.forms.fields.CharField object>, 'v1': <django.forms.fields.CharField object>, 'v2': <django.forms.fields.CharField object>, 'v3': <django.forms.fields.CharField object>, 'v4': <django.forms.fields.CharField object>, 'v5': <django.forms.fields.CharField object>}
declared_fields = {}
property media

Return all media required to render the widgets on this form.

class openedx_authz.admin.ExtendedCasbinRuleInline(parent_model, admin_site)

Bases: StackedInline

Inline admin for ExtendedCasbinRule to display additional metadata.

can_delete = False
extra = 0
fields = ('casbin_rule_key', 'scope', 'subject', 'description', 'metadata', 'created_at', 'updated_at')
property media
model

alias of ExtendedCasbinRule

readonly_fields = ('casbin_rule_key', 'scope', 'subject', 'created_at', 'updated_at')
class openedx_authz.admin.RoleAssignmentAuditAdmin(model, admin_site)

Bases: ModelAdmin

Read-only admin for the role assignment audit log.

date_hierarchy = 'timestamp'
display_role(obj)

Role name without the namespace prefix.

display_scope(obj)

Scope key without the namespace prefix.

display_subject(obj)

Subject key without the namespace prefix.

has_add_permission(request)

Audit records are created by the system only.

has_change_permission(request, obj=None)

Audit records must not be modified after creation.

has_delete_permission(request, obj=None)

Audit records must not be deleted through the admin.

list_display = ('operation', 'display_subject', 'display_role', 'display_scope', 'actor_id', 'timestamp')
list_filter = ('operation', <class 'openedx_authz.admin.ScopeTypeFilter'>)
property media
readonly_fields = ('operation', 'subject', 'role', 'scope', 'actor_id', 'timestamp')
search_fields = ('subject', 'role', 'scope')
class openedx_authz.admin.ScopeTypeFilter(request, params, model, model_admin)

Bases: SimpleListFilter

Filter audit records by scope type (content library, course, etc.).

lookups(request, model_admin)

Return the available scope type choices.

Audit records are independent from live Casbin tables and scope objects: there are no FK references to filter on. The namespace prefix in the stored scope string (e.g. lib^, course-v1^) is the only available signal for categorizing records by scope type.

parameter_name = 'scope_type'
queryset(request, queryset)

Filter the queryset by scope namespace prefix.

title = 'scope type'
openedx_authz.admin.pretty_json(value) str

Return an indented JSON representation of a value.

openedx_authz.apps module#

openedx_authz Django application initialization.

class openedx_authz.apps.OpenedxAuthzConfig(app_name, app_module)

Bases: AppConfig

Configuration for the openedx_authz Django application.

default_auto_field = 'django.db.models.BigAutoField'
name = 'openedx_authz'
plugin_app = {'settings_config': {'cms.djangoapp': {'common': {'relative_path': 'settings.common'}, 'production': {'relative_path': 'settings.production'}, 'test': {'relative_path': 'settings.test'}}, 'lms.djangoapp': {'common': {'relative_path': 'settings.common'}, 'production': {'relative_path': 'settings.production'}, 'test': {'relative_path': 'settings.test'}}}, 'url_config': {'cms.djangoapp': {'namespace': 'openedx-authz', 'regex': '^api/', 'relative_path': 'urls'}, 'lms.djangoapp': {'namespace': 'openedx-authz', 'regex': '^api/', 'relative_path': 'urls'}}}
ready()

Import signal handlers when Django starts.

verbose_name = 'Open edX AuthZ'

openedx_authz.data module#

Top-level data classes for actions and permissions.

These are defined here (rather than in openedx_authz.api.data) to avoid a circular import between openedx_authz.api.data and openedx_authz.constants.permissions.

class openedx_authz.data.ActionData(external_key: str = '', namespaced_key: str = '')

Bases: AuthZData

An action represents an operation that can be performed in the authorization system.

NAMESPACE

‘act’ for actions.

Type:

ClassVar[str]

external_key

The action identifier (e.g., ‘content_libraries.view_library’).

Type:

str

namespaced_key

The action identifier with namespace (e.g., ‘act^content_libraries.view_library’).

Type:

str

Examples

>>> action = ActionData(external_key='content_libraries.delete_library')
>>> action.namespaced_key
'act^content_libraries.delete_library'
>>> action.name
'Content Libraries > Delete Library'
NAMESPACE: ClassVar[str] = 'act'
property name: str

The human-readable name of the action (e.g., ‘Content Libraries > Delete Library’).

class openedx_authz.data.AuthZData(external_key: str = '', namespaced_key: str = '')

Bases: AuthzBaseClass

Base class for all authz data classes.

external_key: str
namespaced_key: str
class openedx_authz.data.AuthzBaseClass

Bases: object

Base class for all authz classes.

NAMESPACE: ClassVar[str] = None
SEPARATOR: ClassVar[str] = '^'
class openedx_authz.data.PermissionData(action: ActionData = None, effect: Literal['allow', 'deny'] = 'allow')

Bases: object

A permission combines an action with an effect (allow or deny).

action

The action being permitted or denied (ActionData instance).

Type:

openedx_authz.data.ActionData

effect

The effect of the permission, either ‘allow’ or ‘deny’ (default: ‘allow’).

Type:

Literal[‘allow’, ‘deny’]

Examples

>>> read_action = ActionData(external_key='read')
>>> permission = PermissionData(action=read_action, effect='allow')
>>> str(permission)
'Read - allow'
action: ActionData
effect: Literal['allow', 'deny']
property identifier: str

Get the permission identifier.

openedx_authz.handlers module#

Signal handlers for the authorization framework.

These handlers ensure proper cleanup and consistency when models are deleted.

openedx_authz.handlers.create_audit_record_on_role_assignment_change(sender, role_assignment, **kwargs)

Create an audit record when a role assignment is created or deleted.

This handler listens for both creation and deletion of role assignments and logs the changes for auditing purposes.

Parameters:
  • sender – The signal class (ROLE_ASSIGNMENT_CREATED or ROLE_ASSIGNMENT_DELETED).

  • role_assignment – RoleAssignmentEventData carrying the operation, subject, role, scope, and actor.

  • **kwargs – Additional keyword arguments from the signal.

openedx_authz.handlers.delete_casbin_rule_on_extended_rule_deletion(sender, instance, **kwargs)

Delete the companion CasbinRule after its ExtendedCasbinRule disappears.

The handler keeps authorization data symmetric with three common flows:

  • Direct ExtendedCasbinRule deletes (API/UI) trigger removal of the linked CasbinRule.

  • Cascades from Scope or Subject deletions clear their ExtendedCasbinRule rows and, via this handler, the matching CasbinRule entries.

  • Cascades initiated from the CasbinRule side (enforcer cleanups) leave the query as a no-op because the row is already gone.

Running on post_delete ensures database cascades complete before the cleanup runs, so enforcer-driven deletions no longer raise false errors.

Parameters:
  • sender – The model class (ExtendedCasbinRule).

  • instance – The ExtendedCasbinRule instance being deleted.

  • **kwargs – Additional keyword arguments from the signal.

openedx_authz.handlers.get_effective_state(record: None, global_flag_enabled: bool) bool

Return whether the feature is effectively active for the override and global flag.

An enabled override forces on or off, otherwise the result follows the global flag.

Parameters:
  • record (WaffleOverrideRecord | None) – The waffle flag record to evaluate.

  • global_flag_enabled (bool) – The state of the global flag.

Returns:

True if the feature is active, False otherwise.

Return type:

bool

openedx_authz.handlers.get_excluded_course_ids_for_org_migration(org_id: str, override_choice: str) frozenset[str]

Collect course-level authoring flag overrides for an org that oppose the new org-level state.

When the org flag changes, we need to exclude course ids that have a course-level authoring flag override that opposes the new org-level state.

Parameters:
  • org_id (str) – Organization short name.

  • override_choice (str) – The override choice of the org waffle flag.

Returns:

course ids excluded from org migration

Return type:

frozenset[str]

openedx_authz.handlers.get_migration_type(current_record: None, previous_record: None, global_flag_enabled: bool) MigrationType | None

Determine the migration type by comparing the effective state before and after the transaction.

This accounts for the global flag state, meaning a transition could be triggered by removing a FORCE_OFF override when the global flag is ON.

Parameters:
  • current_record (WaffleOverrideRecord) – The state of the record in the current transaction.

  • previous_record (WaffleOverrideRecord | None) – The state of the record prior to the current transaction.

  • global_flag_enabled (bool) – The state of the global flag.

Returns:

If the flag is newly forced on. MigrationType.ROLLBACK: If the forced-on state is removed. None: If there is no effective change in the flag’s behavior.

Return type:

MigrationType.FORWARD

openedx_authz.handlers.handle_course_waffle_flag_change(sender, instance, **kwargs) None

Handle changes to course-level waffle flags.

When the authz.enable_course_authoring flag is changed for a course, trigger the appropriate migration run. Only trigger if automatic migration is enabled in the settings.

Parameters:
  • sender – The model class (WaffleFlagCourseOverrideModel)

  • instance – The flag override instance being saved

  • **kwargs – Additional keyword arguments from the signal

openedx_authz.handlers.handle_org_waffle_flag_change(sender, instance, **kwargs) None

Handle changes to organization-level waffle flags.

When the authz.enable_course_authoring flag is changed for an organization, trigger the appropriate migration run. Only trigger if automatic migration is enabled in the settings.

Parameters:
  • sender – The model class (WaffleFlagOrgOverrideModel)

  • instance – The flag override instance being saved

  • **kwargs – Additional keyword arguments from the signal

openedx_authz.handlers.trigger_course_authoring_migration(sender: type[None], instance: None, scope_key: str) None

Trigger a migration run in response to a waffle flag change.

Determines the migration direction from the flag state, guards against no-op saves, and delegates execution to run_course_authoring_migration which handles tracking and concurrent-run protection.

Parameters:
  • sender – The model class (WaffleOverrideRecord).

  • instance – The waffle flag instance that triggered the migration.

  • scope_key (str) – Course ID or organization name.

openedx_authz.handlers.unassign_roles_on_user_retirement(sender, user, **kwargs)

Unassign roles from a user when they are retired.

This handler is triggered when a user is retired in the LMS. It ensures that any roles assigned to the user are removed, maintaining the integrity of the authorization system.

Parameters:
  • sender – The model class (User).

  • user – The user instance being retired.

  • **kwargs – Additional keyword arguments from the signal.

openedx_authz.urls module#

Open edX AuthZ API URLs.

openedx_authz.utils module#

General utility functions for Open edX AuthZ.

openedx_authz.utils.get_user_by_username_or_email(username_or_email: str) User

Retrieve a user by their username or email address.

Parameters:

username_or_email (str) – The username or email address to search for.

Returns:

The User object if found and not retired.

Return type:

User

Raises:

User.DoesNotExist – If no user matches the provided username or email, or if the user has an associated retirement request.

Module contents#

Open edX AuthZ provides the architecture and foundations of the authorization framework.