Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 45 additions & 25 deletions common/djangoapps/student/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,11 @@
from django.core.exceptions import PermissionDenied
from opaque_keys.edx.locator import LibraryLocator
from openedx_authz import api as authz_api
from openedx_authz.constants.permissions import COURSES_CREATE_COURSE, COURSES_MANAGE_ADVANCED_SETTINGS
from openedx_authz.constants.permissions import (
COURSES_CREATE_COURSE,
COURSES_MANAGE_ADVANCED_SETTINGS,
COURSES_VIEW_ADVANCED_SETTINGS,
)

from common.djangoapps.student.roles import (
CourseBetaTesterRole,
Expand Down Expand Up @@ -187,40 +191,56 @@ def check_course_advanced_settings_access(user, course_key, access_type='read'):
Uses openedx-authz when AUTHZ_COURSE_AUTHORING_FLAG is enabled,
otherwise falls back to legacy permission checks.

If the DISABLE_ADVANCED_SETTINGS feature flag is on, then authz will not be used for the
permission check.
When DISABLE_ADVANCED_SETTINGS is enabled, only the 'feature_restricted' access type
bypasses authz (staff/superuser only); 'read' and 'write' still go through authz normally.

Args:
user: Django user object
course_key: CourseKey for the course
access_type: Type of access to check. Options:
- 'read': Check studio read access (default)
- 'write': Check studio write access
- 'feature_restricted': Check access based on the DISABLE_ADVANCED_SETTINGS feature

- 'read': granted to users with MANAGE or VIEW permission (auditors get read-only);
in legacy mode delegates to has_studio_read_access
- 'write': requires MANAGE permission; in legacy mode delegates to has_studio_write_access
- 'feature_restricted': requires MANAGE permission (or staff/superuser when
DISABLE_ADVANCED_SETTINGS is set); in legacy mode delegates to
has_studio_advanced_settings_access
Returns:
bool: True if user has permission, False otherwise
Raises:
ValueError: If access_type is not one of 'read', 'write', or 'feature_restricted'.
"""
if core_toggles.AUTHZ_COURSE_AUTHORING_FLAG.is_enabled(course_key):
# For feature_restricted access type, check DISABLE_ADVANCED_SETTINGS feature
if (
access_type == 'feature_restricted'
and settings.FEATURES.get('DISABLE_ADVANCED_SETTINGS', False)
):
# When feature is disabled, only staff/superuser can access (bypass authz)
return user.is_staff or user.is_superuser
# Otherwise check authz permission
return authz_api.is_user_allowed(user.username, COURSES_MANAGE_ADVANCED_SETTINGS.identifier, str(course_key))

# Legacy permission checks
if access_type == 'read':
return has_studio_read_access(user, course_key)
if access_type == 'feature_restricted':
return has_studio_advanced_settings_access(user)
if access_type == 'write':
if access_type not in ('read', 'write', 'feature_restricted'):
raise ValueError(f"Invalid access_type: {access_type!r}")

if not core_toggles.AUTHZ_COURSE_AUTHORING_FLAG.is_enabled(course_key):
if access_type == 'read':
return has_studio_read_access(user, course_key)
if access_type == 'feature_restricted':
return has_studio_advanced_settings_access(user)
return has_studio_write_access(user, course_key)

raise ValueError(f"Invalid access_type: {access_type}")
# Feature flag override: when DISABLE_ADVANCED_SETTINGS is enabled,
# only staff/superuser can access regardless of authz permissions
if access_type == 'feature_restricted' and settings.FEATURES.get('DISABLE_ADVANCED_SETTINGS', False):
return user.is_staff or user.is_superuser

# MANAGE satisfies all access types. Check it first for all three cases.
if authz_api.is_user_allowed(
user.username,
COURSES_MANAGE_ADVANCED_SETTINGS.identifier,
str(course_key),
):
return True

# Only 'read' falls back to VIEW (auditor access); 'write' and 'feature_restricted' require MANAGE.
if access_type == 'read':
return authz_api.is_user_allowed(
user.username,
COURSES_VIEW_ADVANCED_SETTINGS.identifier,
str(course_key),
)

return False


def is_content_creator(user, org):
Expand Down
Loading