Skip to content

Commit

Permalink
Merge branch 'master' into bilalqamar95/node20-upgrade-1
Browse files Browse the repository at this point in the history
  • Loading branch information
BilalQamar95 authored Aug 26, 2024
2 parents 7608cf1 + 2498f3c commit 143a9e9
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 20 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ Unreleased
----------
* nothing unreleased

[4.23.10]
----------
* fix: 403 for provisioning-admins due to crum and middleware

[4.23.9]
----------
* feat: Add option to show soft deleted group memberships in django admin
Expand Down
2 changes: 1 addition & 1 deletion enterprise/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
Your project description goes here.
"""

__version__ = "4.23.9"
__version__ = "4.23.10"
40 changes: 25 additions & 15 deletions enterprise/api/v1/decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

from functools import wraps

import crum
from rest_framework.exceptions import PermissionDenied, ValidationError

from enterprise.logging import getEnterpriseLogger
Expand Down Expand Up @@ -51,31 +52,40 @@ def wrapper(request, *args, **kwargs):
return outer_wrapper


def has_any_permissions(*permissions, fn=None):
def has_any_permissions(*permissions, **decorator_kwargs):
"""
Decorator that allows access if the user has at least one of the specified permissions,
and optionally checks object-level permissions if a `fn` is provided to get the object.
:param permissions: Permissions added via django_rules add_perm
:param decorator_kwargs: Arguments for permission checks
:return: decorator
"""
def decorator(view_func):
@wraps(view_func)
def _wrapped_view(request, *args, **kwargs):
def decorator(view):
"""Verify permissions decorator."""
@wraps(view)
def wrapped_view(self, request, *args, **kwargs):
"""Wrap for the view function."""
user = request.user
pk = fn(request, **kwargs) if fn else kwargs.get('pk')
LOGGER.info(
f"[User_Permissions_Check] Checking permissions for user {user.username}, "
f"permission: {permissions}, "
f"pk: {pk}"
)
has_permission = any(user.has_perm(perm, pk) for perm in permissions)
fn = decorator_kwargs.get('fn', None)
if callable(fn):
obj = fn(request, *args, **kwargs)
else:
obj = fn

crum.set_current_request(request)

has_permission = [perm for perm in permissions
if request.user.has_perm(perm, obj)]
LOGGER.info(f"[User_Permissions_Check] User {user.username} has permission: {has_permission}")
if has_permission:
return view_func(request, *args, **kwargs)
if any(has_permission):
return view(self, request, *args, **kwargs)
LOGGER.error(
f"[User_Permissions_Check] Access denied for user {user.username} to {view_func.__name__}. "
f"[User_Permissions_Check] Access denied for user {user.username}."
f"Method: {request.method}, "
f"URL: {request.get_full_path()}"
)
raise PermissionDenied(
"Access denied: Only admins and provisioning admins are allowed to access this endpoint.")
return _wrapped_view
return wrapped_view
return decorator
11 changes: 7 additions & 4 deletions enterprise/api/v1/views/enterprise_customer.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

from urllib.parse import quote_plus, unquote

import crum
from django_filters.rest_framework import DjangoFilterBackend
from edx_rbac.decorators import permission_required
from rest_framework import filters, permissions
Expand Down Expand Up @@ -72,6 +73,7 @@ def get_queryset(self):
Allow PAs to access all enterprise customers by modifying filter_backends
"""
queryset = self.queryset
crum.set_current_request(self.request)
is_provisioning_admin = self.request.user.has_perm(ENTERPRISE_CUSTOMER_PROVISIONING_ADMIN_ACCESS_PERMISSION)
if is_provisioning_admin:
self.filter_backends = (
Expand Down Expand Up @@ -134,16 +136,17 @@ def support_tool(self, request, *arg, **kwargs):
serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data)

@method_decorator(has_any_permissions('enterprise.can_access_admin_dashboard',
ENTERPRISE_CUSTOMER_PROVISIONING_ADMIN_ACCESS_PERMISSION))
@has_any_permissions('enterprise.can_access_admin_dashboard',
ENTERPRISE_CUSTOMER_PROVISIONING_ADMIN_ACCESS_PERMISSION)
def create(self, request, *args, **kwargs):
"""
POST /enterprise/api/v1/enterprise-customer/
"""
return super().create(request, *args, **kwargs)

@method_decorator(has_any_permissions('enterprise.can_access_admin_dashboard',
ENTERPRISE_CUSTOMER_PROVISIONING_ADMIN_ACCESS_PERMISSION))
@has_any_permissions('enterprise.can_access_admin_dashboard',
ENTERPRISE_CUSTOMER_PROVISIONING_ADMIN_ACCESS_PERMISSION,
fn=lambda request, pk: pk)
def partial_update(self, request, *args, **kwargs):
return super().partial_update(request, *args, **kwargs)

Expand Down

0 comments on commit 143a9e9

Please sign in to comment.