Skip to content

Conversation

@mariajgrimaldi
Copy link
Member

@mariajgrimaldi mariajgrimaldi commented Oct 28, 2025

Description

This PR adds filtering for content libraries based on user permissions, using the bridgekeeper filtering functionality built on top of the new authorization framework (based on the Casbin engine). This is the more straightforward approach since it piggybacks on the current architecture.

How it works:

The implementation introduces a custom Bridgekeeper rule (HasPermissionInContentLibraryScope) that integrates the openedx-authz authorization system with Bridgekeeper's declarative permission system. This rule enables both individual object permission checks and efficient QuerySet filtering:

  1. Database-level filtering (query() method): Queries the authorization system to get all library scopes where the user has permission, then builds Django Q objects to filter libraries at the database level. The permission check prioritizes the new authorization framework but falls back to the content library model permissions (the existing has_explicit_read_permission_for_library rule) for backward compatibility. Although it follows a backward compatibility approach, a migration script will be provided to support the new authorization framework. See [DEPR]: Libraries' Roles and Permission System #37409

  2. Individual object checks (check() method): For checking permission on specific library instances, it extracts the scope from the object and verifies permission via openedx-authz. This method is not currently used in favor of [FC-0099] feat: add openedx-authz to library apis user_can_create_library and require_permission_for_library_key #37501

Supporting information

Related documentation:

Testing instructions

  1. Start with a clean installation and load the authorization policies:

    python manage.py {lms|cms} load_policies
  2. Create a new content library using a user account without admin access

  3. Create additional libraries using different user accounts (preferably with different organizations)

  4. Go to the libraries list page

  5. Verify that only the libraries you have permission to view are shown in the list

    • Libraries where you have explicit role assignments should appear
    • Libraries where you have no authorization should NOT appear

Deadline

Before end-of-week (hopefully)

@openedx-webhooks openedx-webhooks added the open-source-contribution PR author is not from Axim or 2U label Oct 28, 2025
@openedx-webhooks
Copy link

openedx-webhooks commented Oct 28, 2025

Thanks for the pull request, @mariajgrimaldi!

This repository is currently maintained by @openedx/wg-maintenance-edx-platform.

Once you've gone through the following steps feel free to tag them in a comment and let them know that your changes are ready for engineering review.

🔘 Get product approval

If you haven't already, check this list to see if your contribution needs to go through the product review process.

  • If it does, you'll need to submit a product proposal for your contribution, and have it reviewed by the Product Working Group.
    • This process (including the steps you'll need to take) is documented here.
  • If it doesn't, simply proceed with the next step.
🔘 Provide context

To help your reviewers and other members of the community understand the purpose and larger context of your changes, feel free to add as much of the following information to the PR description as you can:

  • Dependencies

    This PR must be merged before / after / at the same time as ...

  • Blockers

    This PR is waiting for OEP-1234 to be accepted.

  • Timeline information

    This PR must be merged by XX date because ...

  • Partner information

    This is for a course on edx.org.

  • Supporting documentation
  • Relevant Open edX discussion forum threads
🔘 Get a green build

If one or more checks are failing, continue working on your changes until this is no longer the case and your build turns green.


Where can I find more information?

If you'd like to get more details on all aspects of the review process for open source pull requests (OSPRs), check out the following resources:

When can I expect my changes to be merged?

Our goal is to get community contributions seen and reviewed as efficiently as possible.

However, the amount of time that it takes to review and merge a PR can vary significantly based on factors such as:

  • The size and impact of the changes that it introduces
  • The need for product review
  • Maintenance status of the parent repository

💡 As a result it may take up to several weeks or months to complete a review and merge your PR.

@openedx-webhooks openedx-webhooks added the core contributor PR author is a Core Contributor (who may or may not have write access to this repo). label Oct 28, 2025
@github-project-automation github-project-automation bot moved this to Needs Triage in Contributions Oct 28, 2025
@mariajgrimaldi mariajgrimaldi force-pushed the MJG/get-filtered-libs-authz branch from a4a124a to 0d1fa11 Compare October 28, 2025 15:52
@mariajgrimaldi mariajgrimaldi moved this to In Progress in RBAC AuthZ Board Oct 28, 2025
@mphilbrick211 mphilbrick211 added the FC Relates to an Axim Funded Contribution project label Oct 29, 2025
@mphilbrick211 mphilbrick211 moved this from Needs Triage to Waiting on Author in Contributions Oct 29, 2025
@mariajgrimaldi mariajgrimaldi changed the title feat: use filter based on scopes alongside permissions dict [FC-0099] feat: use filter based on scopes alongside permissions dict Oct 29, 2025
@mariajgrimaldi mariajgrimaldi force-pushed the MJG/get-filtered-libs-authz branch from 16bce41 to 4ccfba7 Compare November 3, 2025 12:26
@mariajgrimaldi
Copy link
Member Author

mariajgrimaldi commented Nov 3, 2025

While working on this, a few questions came up that we haven’t really answered yet - at least not in such detail:

Should we start using the .check() method that works with Django’s user.has_perm(), or keep building on top of it like we’re doing now in #37501?

Right now, check() is implemented in HasPermissionInContentLibraryScope, but we don’t actually use it. That leaves us with two options:

Option 1: Use .check() and tie into Django’s permissions
We could rely on calls like user.has_perm('content_libraries.view_library', library_obj) which as far as I understand, internally calls bridgekeeper .check methods. This would couple the solution to bridgekeeper.

Option 2: Keep the higher-level approach (what we do now)
We’d keep Bridgekeeper mainly for queryset filtering and handle single permission checks through openedx-authz. That keeps us more flexible and less dependent on Bridgekeeper internals.

What do you think fits better with the long-term direction of this?

In this PR, a similar question comes up, since bridgekeeper can already achieve something close to what we're doing. This brings up the broader question of how much we should move away from bridgekeeper for attribute checks (or even queryset filtering) or rely more on Casbin-based definitions. I like that bridgekeeper uses the user object already in memory, while Casbin matchers need another database call to get the same data (see openedx/openedx-authz#114). What I don’t like is that bridgekeeper hasn’t been updated in a while, so it might not be reliable long-term. Maybe the real question is whether we should keep using bridgekeeper at all - which shouldn't be answered here.

@bmtcril @rodmgwgu @MaferMazu

@mariajgrimaldi mariajgrimaldi changed the title [FC-0099] feat: use filter based on scopes alongside permissions dict [FC-0099] feat: use filter based on library scopes to view libraries Nov 3, 2025
@mariajgrimaldi mariajgrimaldi changed the title [FC-0099] feat: use filter based on library scopes to view libraries [FC-0099] feat: filter libraries based on user role-scopes association Nov 3, 2025
@mariajgrimaldi mariajgrimaldi changed the title [FC-0099] feat: filter libraries based on user role-scopes association [FC-0099] feat: filter libraries based on user-role scopes Nov 3, 2025
@mariajgrimaldi mariajgrimaldi marked this pull request as ready for review November 3, 2025 12:59
@mariajgrimaldi mariajgrimaldi moved this from In Progress to Ready for review in RBAC AuthZ Board Nov 3, 2025
@mariajgrimaldi mariajgrimaldi force-pushed the MJG/get-filtered-libs-authz branch from d586651 to d89f1dc Compare November 3, 2025 13:49
@rodmgwgu
Copy link
Contributor

rodmgwgu commented Nov 3, 2025

While working on this, a few questions came up that we haven’t really answered yet - at least not in such detail:

Should we start using the .check() method that works with Django’s user.has_perm(), or keep building on top of it like we’re doing now in #37501?

Right now, check() is implemented in HasPermissionInContentLibraryScope, but we don’t actually use it. That leaves us with two options:

Option 1: Use .check() and tie into Django’s permissions We could rely on calls like user.has_perm('content_libraries.view_library', library_obj) which as far as I understand, internally calls bridgekeeper .check methods. This would couple the solution to bridgekeeper.

Option 2: Keep the higher-level approach (what we do now) We’d keep Bridgekeeper mainly for queryset filtering and handle single permission checks through openedx-authz. That keeps us more flexible and less dependent on Bridgekeeper internals.

What do you think fits better with the long-term direction of this?

In this PR, a similar question comes up, since bridgekeeper can already achieve something close to what we're doing. This brings up the broader question of how much we should move away from bridgekeeper for attribute checks (or even queryset filtering) or rely more on Casbin-based definitions. I like that bridgekeeper uses the user object already in memory, while Casbin matchers need another database call to get the same data (see openedx/openedx-authz#114). What I don’t like is that bridgekeeper hasn’t been updated in a while, so it might not be reliable long-term. Maybe the real question is whether we should keep using bridgekeeper at all - which shouldn't be answered here.

@bmtcril @rodmgwgu @MaferMazu

Given the maintenance status of the Bridgekeeper project, I think we should plan on moving away from it, perhaps reimplementing the useful parts (like the query filtering) in the openedx-authz. But this will require further research and planning.

For now, an hybrid approach like Option 2 is ok I think.

@bmtcril
Copy link
Contributor

bmtcril commented Nov 3, 2025

While working on this, a few questions came up that we haven’t really answered yet - at least not in such detail:
Should we start using the .check() method that works with Django’s user.has_perm(), or keep building on top of it like we’re doing now in #37501?
Right now, check() is implemented in HasPermissionInContentLibraryScope, but we don’t actually use it. That leaves us with two options:
Option 1: Use .check() and tie into Django’s permissions We could rely on calls like user.has_perm('content_libraries.view_library', library_obj) which as far as I understand, internally calls bridgekeeper .check methods. This would couple the solution to bridgekeeper.
Option 2: Keep the higher-level approach (what we do now) We’d keep Bridgekeeper mainly for queryset filtering and handle single permission checks through openedx-authz. That keeps us more flexible and less dependent on Bridgekeeper internals.
What do you think fits better with the long-term direction of this?
In this PR, a similar question comes up, since bridgekeeper can already achieve something close to what we're doing. This brings up the broader question of how much we should move away from bridgekeeper for attribute checks (or even queryset filtering) or rely more on Casbin-based definitions. I like that bridgekeeper uses the user object already in memory, while Casbin matchers need another database call to get the same data (see openedx/openedx-authz#114). What I don’t like is that bridgekeeper hasn’t been updated in a while, so it might not be reliable long-term. Maybe the real question is whether we should keep using bridgekeeper at all - which shouldn't be answered here.
@bmtcril @rodmgwgu @MaferMazu

Given the maintenance status of the Bridgekeeper project, I think we should plan on moving away from it, perhaps reimplementing the useful parts (like the query filtering) in the openedx-authz. But this will require further research and planning.

For now, an hybrid approach like Option 2 is ok I think.

I agree on all points here, I think our goal should be to move away from Bridgekeeper as soon as we can. 👍

@mariajgrimaldi mariajgrimaldi force-pushed the MJG/get-filtered-libs-authz branch from 36f3d17 to 9547ed4 Compare November 4, 2025 11:04
# Otherwise the user must be part of the library's team
# Users can access libraries within their authorized scope (via Casbin/role-based permissions)
HasPermissionInContentLibraryScope(VIEW_LIBRARY) |
# Fallback to: the user must be part of the library's team (legacy permission system)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we still want this? I thought we were not going to be using the legacy permissions any more since there will be no UI to revoke them?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's what I think should happen, though I'm not sure it should be part of this PR. It would also mean removing user.has_perm from this PR #37501, so we need to clarify when to do that. From my view, we could handle it after the integration is complete to avoid inconsistent intermediate states. What do you think?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the states will diverge either way, but I'm ok with leaving this as long as we have an issue to remove it that has a list of places we need to update 👍

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mariajgrimaldi @bmtcril, in #37501 I was maintaining the old check for prevention. But in a DEPR WG meeting they mention the concept of expand contract pattern, that it is related. For Ulmo we are only expanding (adding the new functionality withouth removing the old one), and then we can remove it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I think as long as we're not actually using the old permissions that's fine and gives instances the opportunity to roll back if necessary. I just want to make sure we're not in a position where we are checking old permissions that cannot be changed.

@mariajgrimaldi mariajgrimaldi self-assigned this Nov 5, 2025
@MaferMazu MaferMazu linked an issue Nov 6, 2025 that may be closed by this pull request
20 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

core contributor PR author is a Core Contributor (who may or may not have write access to this repo). FC Relates to an Axim Funded Contribution project open-source-contribution PR author is not from Axim or 2U

Projects

Status: Waiting on Author
Status: Ready for review

Development

Successfully merging this pull request may close these issues.

Enforcement Updates

7 participants