Skip to content

Define Standard Format for Scope IDs in Casbin Policies #102

@BryanttV

Description

@BryanttV

Description

When using the REST API to assign roles to users through Casbin, there’s a problem related to case sensitivity in the scope field (in this specific case, for libraries)

Example request: /api/authz/v1/roles/users/

{
    "users": ["admin"],
    "role": "library_admin",
    "scope": "lib:openedx:csprob"
}

The actual library ID is lib:OpenedX:CSPROB, However, during validation in the serializer, the following check is performed:

if not scope.exists():
    raise serializers.ValidationError(f"Scope '{scope_value}' does not exist")

Since the exists() method internally performs a case-insensitive lookup:

def exists(self) -> bool:
    try:
        library_key = LibraryLocatorV2.from_string(self.library_id)
        ContentLibrary.objects.get_by_key(library_key=library_key)
        return True
    except ContentLibrary.DoesNotExist:
        return False
In [1]: lib_id = "lib:openedx:csprob"

In [2]: library_key = LibraryLocatorV2.from_string(lib_id)

In [3]: ContentLibrary.objects.get_by_key(library_key=library_key)
Out[3]: <ContentLibrary: ContentLibrary (lib:Openedx:CSPROB)>

the validation passes, even if the scope value casing doesn’t match the real ID in the system. As a result, the policy is stored with the incorrect scope ID in the casbin_rule table.

Later, when a GET request or permission check is made, the stored policy doesn’t match because of the case mismatch; the system expects the exact lib:OpenedX:CSPROB, but finds lib:openedx:csprob.

Impact

  • Policies are stored with incorrect scope identifiers.
  • Authorization lookups and role retrieval fail due to casing mismatches.
  • The issue could also affect other scope types (e.g., Course, Organization, etc.), not only Library.

Possible Approaches

  • Normalize all scope IDs before saving policies (e.g., resolve them to their canonical forms or convert them to lowercase).
  • Modify the exists() function to return not only a boolean value but also the correct canonical identifier. It’s important to note that the same approach should be applied to all exists() methods of each new scope type.

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions