diff --git a/oeps/best-practices/oep-0009-bp-permissions.rst b/oeps/archived/oep-0009-bp-permissions.rst similarity index 87% rename from oeps/best-practices/oep-0009-bp-permissions.rst rename to oeps/archived/oep-0009-bp-permissions.rst index 22c76d7e9..be67afdf9 100644 --- a/oeps/best-practices/oep-0009-bp-permissions.rst +++ b/oeps/archived/oep-0009-bp-permissions.rst @@ -1,23 +1,27 @@ OEP-9: User Authorization (Permissions) ####################################### -+---------------+-------------------------------------------+ -| OEP | :doc:`OEP-9 ` | -+---------------+-------------------------------------------+ -| Title | User Authorization (Permissions) | -+---------------+-------------------------------------------+ -| Last Modified | 2016-10-13 | -+---------------+-------------------------------------------+ -| Author | Jeremy Bowman | -+---------------+-------------------------------------------+ -| Arbiter | Eddie Fagin | -+---------------+-------------------------------------------+ -| Status | Provisional | -+---------------+-------------------------------------------+ -| Type | Best Practice | -+---------------+-------------------------------------------+ -| Created | 2016-09-09 | -+---------------+-------------------------------------------+ ++---------------+-----------------------------------------------------------------------+ +| OEP | :doc:`OEP-9 ` | ++---------------+-----------------------------------------------------------------------+ +| Title | User Authorization (Permissions) | ++---------------+-----------------------------------------------------------------------+ +| Last Modified | 2023-10-02 | ++---------------+-----------------------------------------------------------------------+ +| Author | Jeremy Bowman | ++---------------+-----------------------------------------------------------------------+ +| Arbiter | Eddie Fagin | ++---------------+-----------------------------------------------------------------------+ +| Status | Replaced by :doc:`OEP-66 ` | ++---------------+-----------------------------------------------------------------------+ +| Type | Best Practice | ++---------------+-----------------------------------------------------------------------+ +| Created | 2016-09-09 | ++---------------+-----------------------------------------------------------------------+ + +.. warning:: + + This OEP has been replaced by :doc:`OEP-66 ` Abstract ******** @@ -298,3 +302,9 @@ still uses a copy of the original implementation. Change History ************** + +2023-10-02 +=========== + +* Status updated to "Replaced by :doc:`OEP-66 `" +* `PR #520 `_ diff --git a/oeps/best-practices/oep-0066-bp-authorization.rst b/oeps/best-practices/oep-0066-bp-authorization.rst new file mode 100644 index 000000000..48fac5753 --- /dev/null +++ b/oeps/best-practices/oep-0066-bp-authorization.rst @@ -0,0 +1,537 @@ +OEP-66: User Authorization +########################## + +.. list-table:: + :widths: 25 75 + + * - OEP + - :doc:`OEP-66 ` + * - Title + - User Authorization + * - Last Modified + - 2023-10-20 + * - Authors + - Hilary Sinkoff (hsinkoff@2u.com), Jeremy Bowman (jbowman@edx.org) + * - Arbiter + - Feanil Patel (feanil@axim.org) + * - Status + - Accepted + * - Type + - Best Practice + * - Created + - 2023-08-21 + * - `Review Period` + - 2023-09-27 - 2023-10-18 + * - Replaces + - :doc:`/archived/oep-0009-bp-permissions` + * - References + - + * :doc:`/architectural-decisions/oep-0004-arch-oauth-scopes` + * :doc:`oep-0042-bp-authentication` + +Summary +******* + +There are a variety of manners in which authorization is handled within the Open edX ecosystem. +The goal of OEP-66 is to provide best practices that should be used with each of the +systems/protocols and outline the systems/protocols that are currently in use. + +Motivation +********** + +Best Practices Motivation +------------------------- +To date, the implementation and verification of permissions have been somewhat +conflated in the Open edX codebase. When a user attempts an action which is not +permitted for all users, the code typically directly checks properties of the +user: are they a superuser, do they belong to a particular group or have a +particular role, etc. This has a few drawbacks: + +* This is often a violation of DRY ("Don't Repeat Yourself") which results in + the same basic permission check being copied in multiple code locations, + making it very difficult to consistently change its implementation (as may + happen when a new type of user is introduced, or the need for a special + exception becomes clear). +* Fine-grained permission checks have sometimes been avoided even when + appropriate due to the difficulty of copying the permission code around, + finding a common place to store it, or updating all the code that used a + coarser initial implementation. This has resulted in some users being + technically capable of performing actions which logically should not be + permitted. +* When a decision is made to change who is granted a particular permission, + it can be difficult to avoid accidentally changing other permissions with + a similar implementation. + +Systems/Protocols Overview Motivation +------------------------------------- +There are currently multiple systems/protocols that control authorization. +Determining which combination of systems/protocols are responsible for granting access +is a complex task made more complex by the lack of +unified documentation on the systems/protocols. This OEP aims to compile existing +knowledge and documentation into a central document that will give an overview of each +system/protocol. The aim is not to be the only source of information for each system/protocol, +but rather a starting point when learning about authorization within the Open edX codebase. + +Defined Terms +************* + +Authorization (Authz) +--------------------- + +Authorization is the granting of permission of a certain user to perform specific operations in an application. A user can also delegate an application to be authorized to perform operations on their behalf without being logged in or authenticated, which is the basis of OAuth. + +.. note:: + The definition of authorization found here is the same as that found in + :doc:`OEP 42 `. + Credit for this definition belongs to the authors of OEP-42; Robert Raposa, Nimisha Asthagiri, and Julia Eskew. + +Authentication (Authn) +---------------------- + +Authentication is the verification of the identity of a user, which typically initiates at a “login” application point. Authentication is required whenever we need to identify a client/caller/user/etc. + +.. note:: + + Authentication is out of scope of this OEP. + The definition is included here to clarify the difference between it and Authorization. + The definition comes from :doc:`OEP 42 `. + Credit for this definition belongs to the authors of OEP-42; Robert Raposa, Nimisha Asthagiri, and Julia Eskew. + +RBAC +---- +Role Based Access Control. A system in which roles are assigned to a user +in order to grant that user permission to perform specific operations. + +There are multiple RBAC implementations in use within the Open edX codebase, +including, but not limited to, `edx-rbac`_` and `student_courseaccessrole`_. +The implementations will be described in detail below. + +.. _student_courseaccessrole: https://github.com/openedx/edx-platform/blob/master/common/djangoapps/student/roles.py +.. _edx-rbac: https://github.com/openedx/edx-rbac/tree/master + +Explicit Role +------------- +A role that is specifically assigned to a user with +the intent of providing the user permission to perform specific operations. + +Implicit Role +------------- +A "role" that is understood to belong to a user based +on data that is not role assignment data. + +Implicit roles grant users permissions, but are not specifically assigned +to a user. + +System-wide Role +---------------- +A role that can be used across all Open edX Software. + +Super User +---------- +A service specific role that exists only for the specified service and +grants a high level of access to the service (for example access to Django Admin +or read-write access for all database models). + +Best Practices +************** + +Permission Checks +----------------- + +Most authorization checks in Python code should use the standard +`Django authorization API`_, including the optional support for object-level +permissions which isn't implemented in the default backends. Some examples +can help give context for the details: + +.. _Django authorization API: https://docs.djangoproject.com/en/3.2/topics/auth/default/#permissions-and-authorization + +`This code checks if a user has the permission stated.` + +.. code-block:: python + + if user.has_perm('my_app.change_modelname', model_instance): + # Code which depends on the user being allowed to edit that specific model instance + + if user.has_perm('other_app.add_othermodel'): + # Code which depends on the user being allowed to create new instances of OtherModel + +`This code requires the permission app.modelname in order to perform the my_view action.` + +.. code-block:: python + + from django.contrib.auth.decorators import permission_required + + @permission_required('app.modelname') + def my_view(request): + # ... + +.. note:: + A permission name should respect the following rules: + + * It should contain only lower-case ASCII letters, periods, and underscores. + * It should start with the name of a Django application followed by a period. + * It should follow an "action_modelname" pattern for the rest of the name + if appropriate (especially because several of these are used by the Django + admin interface if defined), or a short description of an action otherwise. + + `Example permission names:` + + * my_app.change_modelname + * other_app.add_othermodel + +Extending Permission Checks +=========================== + +While the +`Django authorization API`_ is quite flexible, many Django developers +have not really utilized it because the default authentication backend that +comes with Django lacks support for object-level permissions and requires the +addition of per-user database records for even the most trivial permission +checks. Fortunately, Django supports custom authentication backends, and +checks each one that's in use when making authorization checks. + +The backend +which we currently recommend for use in defining new permission checks is +`bridgekeeper`_. + +`bridgekeeper`_ is "heavily inspired by `django-rules`_". It allows the creation of new permissions by mapping +the permission name to a function which implements the permission check. It also allows permission checking by +QuerySet. + +Django apps which are +implemented in the repository for a service should generally define their +custom permissions in a ``rules.py`` module where they will be automatically +loaded, as described in the documentation. For example: + +.. _bridgekeeper: https://bridgekeeper.readthedocs.io/en/latest/index.html +.. _django-rules: https://github.com/dfunckt/django-rules + +`This code grants the my_app.view_report permission to users that return true from the new +is_report_owner function or the imported is_superuser function.` + +.. code-block:: python + + import bridgekeeper + from bridgekeeper.rules import blanket_rule + from .rules import is_superuser + + @blanket_rule + def is_report_owner(user, report): + return report.owner == user + + rules.add_perm('my_app.view_report', is_report_owner | is_superuser) + +This allows permissions to be named and implemented in one place, without +requiring any additional database configuration. Note that reusable Django +applications should not automatically register implementations of their +permissions, as the actual services using them may need to implement their +own rules for them. + +Note that although the optional second argument to ``User.has_perm()`` is +often a model instance, it can technically be any Python object which contains +information relevant to the permission being tested, including a QuerySet. This allows for even +greater flexibility in the kinds of authorization rules that can be +implemented. + +Django REST Framework +********************* + +When using Django REST Framework (DRF) to build a REST API, note that it has object +permissions and query filtering mechanisms which are designed to be compatible +with Django's authorization API. This means they also work well with the +``bridgekeeper`` authentication backend described above. + +You can +`set the permissions policy`_ to a class such as `DjangoObjectPermissions`_ +and DRF will automatically check the appropriate object permission whenever +performing an action on a single object. That particular class always denies +permission to anonymous users and assumes that there are no ``view_*`` +permissions relevant to viewing or listing objects; those points can be +changed if desired by creating a subclass, for example: + +.. _DjangoObjectPermissions: https://www.django-rest-framework.org/api-guide/permissions/#djangoobjectpermissions +.. _set the permissions policy: https://www.django-rest-framework.org/api-guide/permissions/#setting-the-permission-policy + +.. code-block:: python + + class DjangoObjectPermissionsIncludingView(permissions.DjangoObjectPermissions): + authenticated_users_only = False + perms_map = { + 'GET': ['%(app_label)s.view_%(model_name)s'], + 'OPTIONS': ['%(app_label)s.view_%(model_name)s'], + 'HEAD': ['%(app_label)s.view_%(model_name)s'], + 'POST': ['%(app_label)s.add_%(model_name)s'], + 'PUT': ['%(app_label)s.change_%(model_name)s'], + 'PATCH': ['%(app_label)s.change_%(model_name)s'], + 'DELETE': ['%(app_label)s.delete_%(model_name)s'], + } + +If additional information about the session is needed beyond the user's +identity in order to make a permission decision (for example, if an action +should only be allowed if the client has been granted a particular OAuth +scope, as outlined in :doc:`OEP 4 `), +then a custom `BasePermission`_ subclass can +be implemented which both consults the Django authorization API and makes the +necessary checks against the session or other properties of the request +object. + +In order to filter the querysets used to generate list responses to only +include objects appropriate for the users permissions, an appropriate filter +class should also be set. A generic implementation using the library +proposed above for mapping permissions to Q objects might look as follows: + +.. code-block:: python + + from qpermissions import perms + + class DjangoPermissionRulesFilter(BaseFilterBackend): + + perm_format = '%(app_label)s.view_%(model_name)s' + + def filter_queryset(self, request, queryset, view): + user = request.user + model_cls = queryset.model + kwargs = { + 'app_label': model_cls._meta.app_label, + 'model_name': get_model_name(model_cls) + } + permission = self.perm_format % kwargs + if permission not in perms: + return queryset + return queryset.filter(perms[permission](user)) + +Such a class would be used in a view's `filter_backends`_ attribute or +could be used by default for all view classes which don't override it. + +.. _BasePermission: https://www.django-rest-framework.org/api-guide/permissions/#custom-permissions +.. _filter_backends: https://www.django-rest-framework.org/api-guide/filtering/#setting-filter-backends + +Systems/Protocols Overview +************************** +The following systems/protocols are currently used in the Open edX ecosystem +to grant users different levels of access. Each system/protocol is used in different +ways. A user's authz level is determined based on a combination of these systems/protocols. +It is important to note that it is the interplay of these systems/protocols that +determines whether a user has permissions for a given operation, not necessarily a single +system. + +Basic information about each system/protocol is included in the diagram and data tables. +More in-depth information is included in the sections below the diagrams. + +Open edX Auth Overview Diagram +------------------------------ + +.. image:: oep-0066/Open_edX_Auth_Overview.png + :alt: A diagram that provides an overview of Auth in the Open edX codebase. The information in the diagram is also in the Open edX Auth Overview Table (linked to in this document). + +.. toctree:: + :maxdepth: 1 + :glob: + + oep-0066/Open_edX_Auth_Overview_Table.rst + +Open edX Authorization Explicit Roles Diagram +--------------------------------------------- + +.. image:: oep-0066/Open_edX_Authorization_Explicit_Roles.png + :alt: A diagram that shows the different systems/protocols that are used to control explicit roles in the Open edX codebase. The information in the diagram is also in the Open edX Authorization Explicit Roles Table (linked to in this document). + +.. toctree:: + :maxdepth: 1 + :glob: + + oep-0066/Open_edX_Authorization_Explicit_Roles_Table.rst + +Open edX Authorization Implicit Roles Diagram +--------------------------------------------- + +.. image:: oep-0066/Open_edX_Authorization_Implicit_Roles.png + :alt: A diagram that shows the implicit roles in the Open edX codebase. The information in the diagram is also in the Open edX Authorization Implicit Roles Table (linked to in this document). + +.. toctree:: + :maxdepth: 1 + :glob: + + oep-0066/Open_edX_Authorization_Implicit_Roles_Table.rst + +Django Admin (auth_permission) +------------------------------ + +Permissions are granted for the entire instance. + +There are two ways in which the Django auth_permissions can be used to grant access. + +* Users can be granted model permissions based on the database models. +* Users can be assigned to groups which can be granted model permissions based on the database models. + +Django Admin auth_permissions grants permissions to users or groups, but does not +control whether the user is able to login to a service (authn) or access a service through other permissions +(i.e. an implicit student role). +In this way, it can grant permissions to a user that they will not be able to use. + +auth_permission users and groups are assigned through the Django Admin Dashboard. Each +service can have its own Django Admin Dashboard. In the Open edX software, the LMS Django Admin Dashboard +will be used to control (most) user and group permissions. + +student_courseaccessrole +------------------------ + +Explicit roles are assigned to users, generally on a course level basis. + +The roles are hardcoded strings that can be granted in the LMS or CMS. +In addition to granting the roles in the UI, it is possible to assign +the roles through the LMS Django Admin Dashboard. + +Each role assignment will generate one row in the database table. The values +in the row will determine if the user is granted access for a single course, all +courses in the org, or all courses in the instance. + +* If the course_id is not nil, the role grants permissions on the course level. +* If the course_id is nil and the org_id is not nil, the role grants permissions on the organization level. +* If the course_id and org_id are both nil, the role grants permissions on the instance level. + +django_comment_client_role +-------------------------- + +Explicit roles are assigned to users on a course level basis. + +These roles require that the user already be enrolled in the course +(have an enrollment, audit or verified). + +Roles are assigned through the LMS in the same place in the UI as the student_courseaccessrole roles. +They can also be granted in the LMS Django Admin Dashboard. + +edx-rbac +-------- + +Permission is granted on a Feature. + +edx-rbac is a protocol that can be implemented by any feature, but each +feature that implements it would need to set up its own implementation. + +It allows for creating feature specific roles with feature specific permissions. +The feature specific roles can be accessed by other +features which can choose to use or ignore this data point. + +The feature specific roles are stored on the jwt token. This mixes authz into an +authn data point, but is an accepted way to implement feature specific roles and permissions. +It is advisable to be very careful regarding the jwt token header limits if adding a new feature specific +set of roles using this implementation path. + +content_libraries_contentlibrarypermission +------------------------------------------ + +Permission is granted on a Feature, in this case Content Library. + +Permission is assigned in the CMS exclusively for providiing explicit permission to +view or edit a library in the CMS. + +It grants access on a library by library basis and is used for v2 of content libraries +in the CMS. + +.. note:: + v1 libraries (deprecated) granted access to libraries on a course by course basis + and was controlled by student_courseaccessrole. + +Student/Learner +--------------- +student/learner is an implicit role. + +It is not currently controlled by a system/protocol +whose primary focus is authorization. + +System-wide Roles +----------------- +System-wide roles are configurable and can differ between different Open edX instances. This +means that different instances can have different system-wide roles. + +System-wide user-roles (user assignments to a specific system-wide role) are +stored in a central user service (currently LMS) and communicated via JWT Tokens. + +If a feature/service utilizes a system-wide role, the feature/service enforces the roles in its own codebase. + +Example System-wide Role: + +* Global Staff - propogated in JWTs as the "administrator" field + +Example AuthZ User Access Flows +------------------------------- +.. image:: oep-0066/Open_edX_Authorization_User_Flows.png + :alt: A diagram that attempts to show different ways in which users can be granted elevated access. + +Users can be granted elevated access via different means (system-wide roles, edx-rbac, student_courseaccessroles, etc). +This diagram illustrates some, but not all, ways a user can be granted elevated access. + +User 1 is assigned to User Group 1 and User Group 2. +Being in User Group 1 grants the user System-wide Role A and System-wide Role B, +which in turn each grant a specific permission set or sets for a service. +Being in User Group 2 grants access to System-wide Role C +which grants access to a service permisison set. + +User 2 is assigned to User Group 2. +Being in User Group 2 grants access to System-wide Role C +which grants access to a service permission set. +User 2 is also directly assigned System-wide Role D +which grants access to a different servie permission set. +User 2 is also assigned Service/Feature Role A +which grants access to a service permission set. + +User 3 is assigned to Service/Feature Role A and Service/Feature Role B. +Each role grants the user a specific service permission set. + + +As demonstrated by the above flows: + +* a user can belong to multiple user groups +* a user can be granted one or many service/feature roles +* a user can belong to one or many user groups and one or many service/feature roles +* a user group can assign a user one or many system-wide roles +* a user can be assigned a system-wide role directly +* system-wide roles and service/feature roles all assign users permission sets that apply only to a specific service +* a system-wide role can have one or many associated service permission sets within a service +* a service/feature role can have one or many associated service permission sets +* a service permission set can be associated with multiple system-wide roles and/or service/feature roles + +.. note:: + Not illustrated in the diagram or user flows is the fact that multiple services can use the same + system-wide roles to grant different permission sets. + The permission sets do not persist between services, but the system-wide roles are available globally. + +Historical Systems/Protocols +**************************** + +This is a listing of the systems/protocols that have been used historically, but have since been phased out. +This list should include a link to any ADRs or documents that reflect why these changes were made. + +* `rules`_ was previously the preferred method for extending permission checks. + * `ADR for adding django-rules `_ + * `ADR for switching to bridgekeeper `_ + +.. _rules: https://github.com/dfunckt/django-rules + +References +********** + +`Authorization Architecture Vision & Principles `_ + +`django Authentication System `_ + +`django-rules `_ + +`bridgekeeper `_ + +Change History +************** + +2023-10-23 +---------- + +* PR comment updates - add additional diagram, add information from `Authorization Architecture Vision & Principles`_ +* `Pull request #520 `_ + +2023-08-21 +---------- + +* Document created +* `Pull request #520 `_ + diff --git a/oeps/best-practices/oep-0066/Open_edX_Auth_Overview.png b/oeps/best-practices/oep-0066/Open_edX_Auth_Overview.png new file mode 100644 index 000000000..4df63c804 Binary files /dev/null and b/oeps/best-practices/oep-0066/Open_edX_Auth_Overview.png differ diff --git a/oeps/best-practices/oep-0066/Open_edX_Auth_Overview.xml b/oeps/best-practices/oep-0066/Open_edX_Auth_Overview.xml new file mode 100644 index 000000000..ca68a7f9e --- /dev/null +++ b/oeps/best-practices/oep-0066/Open_edX_Auth_Overview.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/oeps/best-practices/oep-0066/Open_edX_Auth_Overview_Table.rst b/oeps/best-practices/oep-0066/Open_edX_Auth_Overview_Table.rst new file mode 100644 index 000000000..48c61a16c --- /dev/null +++ b/oeps/best-practices/oep-0066/Open_edX_Auth_Overview_Table.rst @@ -0,0 +1,18 @@ +Open edX Auth Overview Table +---------------------------- +.. list-table:: + :widths: 50 50 + :header-rows: 1 + + * - Authentication (AuthN) + - Authorization (AuthZ) + * - Users should receive a JWT Token once authenticated. + - Access is determined using a combination of the explicit and implicit role gratning. Logic may check a combination of the systems (or just one) and may check them in any order. Logic may use && or || depending on the specific Authn and Authz needs. + * - Each Open edX instance may utilize different authentication options. + - Roles assigned with edx-rbac are stored on the JWT and retrieved as part of `JWT creation `_ + * - + - Scopes are stored on the JWT and retrieved as part of `JWT creation `_. In this context, scopes limit access to the token bearer and control which optional claims are included in the token. + * - + - Individual models have helper functions to determine access level (role) of the users. + + `Example `_ diff --git a/oeps/best-practices/oep-0066/Open_edX_Authorization.png b/oeps/best-practices/oep-0066/Open_edX_Authorization.png new file mode 100644 index 000000000..f9f1315a7 Binary files /dev/null and b/oeps/best-practices/oep-0066/Open_edX_Authorization.png differ diff --git a/oeps/best-practices/oep-0066/Open_edX_Authorization_Explicit_Roles.png b/oeps/best-practices/oep-0066/Open_edX_Authorization_Explicit_Roles.png new file mode 100644 index 000000000..c8f9160f8 Binary files /dev/null and b/oeps/best-practices/oep-0066/Open_edX_Authorization_Explicit_Roles.png differ diff --git a/oeps/best-practices/oep-0066/Open_edX_Authorization_Explicit_Roles.xml b/oeps/best-practices/oep-0066/Open_edX_Authorization_Explicit_Roles.xml new file mode 100644 index 000000000..c3b3fbc06 --- /dev/null +++ b/oeps/best-practices/oep-0066/Open_edX_Authorization_Explicit_Roles.xml @@ -0,0 +1,398 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/oeps/best-practices/oep-0066/Open_edX_Authorization_Explicit_Roles_Table.rst b/oeps/best-practices/oep-0066/Open_edX_Authorization_Explicit_Roles_Table.rst new file mode 100644 index 000000000..178b14c01 --- /dev/null +++ b/oeps/best-practices/oep-0066/Open_edX_Authorization_Explicit_Roles_Table.rst @@ -0,0 +1,168 @@ +Open edX Authorization Systems Explicit Roles Table +################################################### + +edX Platform - Course Roles +--------------------------- +.. list-table:: + :widths: 15 75 + + * - **System Users** + - + * Roles are assigned by instructors in the LMS and by CMS admins in the CMS. + * Roles are assigned to users (other than students) who need elevated access in the LMS or CMS, but roles may also apply to other systems. + * Roles can be assigned in the django admin dashboard. + * - **System Role Options** + - + * Example roles as named in db: instructor, staff, beta_tester, etc. + * Example roles as named in Instructor Dashboard/Course Teams: Admin, Staff, Beta Tester, etc. + * - **Example Use Cases** + - + * Course level access + * Course Level Access, granted across an org of the system + * Role/Permission set likely to be needed for many users + * Roles need to be assignable within the UI + * Roles need to be assignable by others with a specific role on the course + * - **System Details** + - + * LMS + * Instructor role can access and assign course roles + * Roles can be assigned in the membership tab on the instructor dashboard page + * Roles assigned in the LMS may exist in the CMS + * CMS + * Admin role can access and assign course roles + * Roles can be assigned on course team page + * Roles assigned in the CMS must also exist in the LMS + * Connected to the django admin dashboard through admin.py file. + * Roles assigned on a course by course basis, an org by org basis, or for the entire system. + * - **Data Model** + - + * student_courseaccessrole database table in the edx-platform LMS database with course_id, id, org, role, user_id, _sdc_deleted_at fields + + *Note: If the course_id column is an empty string the role is for the org, if the org and course_id are empty strings the role is for the entire system.* + +comment_client - Discussion Roles +--------------------------------- +.. list-table:: + :widths: 15 75 + + * - **System Users** + - + * Roles are assigned by instructors in the LMS. + * Roles can be assigned to any user who needs elevated access to Discussions. + * The role of administrator cannot be removed from the instructor. + * - **System Role Options** + - + * Example roles as named in the db: Administrator, Moderator, etc. + * Example roles as named in Instructor Dashboard: Discussion Admin, Discussion Moderator, etc. + * - **Example Use Cases** + - + * Discussion Service + * - **System Details** + - + * LMS + * Instructor role can access and assign discussion roles + * Roles can be assigned in the membership tab on the instructor dashboard page + * Roles assigned in the LMS only apply to the LMS Discussions + * Administrator role is given to the instructor by default and cannot be removed. Additional administrators can be added + * - **Data Model** + - + * All tables are in the edx-platform LMS database + * django_comment_client_role table with course_id, id, name fields + * django_comment_client_role_users table with id, role_id, user_id, _sdc_deleted_at fields + * django_comment_client_permission_roles table with id, role_id, permission_id fields + * django_comment_client_permission table with name field + +edx Platform - Django Admin Flow +-------------------------------- +.. list-table:: + :widths: 15 75 + + * - **System Users** + - + * Roles are assigned by superusers who have django admin access. + * Any user can be assigned a permission set or a group (that has a permission set) through this process. + * - **System Role Options** + - + * `Currently Existing Roles `_ + + *Note: Student is not an explicit role at this time. It is an implicit role based on the existence of an enrollment.* + * - **Example Use Cases** + - + * Higher level system access + * Specific or individualized access required + * Higher level of control needed for assigning the roles + * - **System Details** + - + * Set in the Django Admin Control Panel + * users for the instance with superiser role (highest access level) have access to this functionality + * poor UX, poor discoverability, overly complex and possibly more error prone + + *Note: Other services have their own Django Admin Panels that grant permissions.* + * - **Data Model** + - + * All tables are in the edx-platform LMS database + * auth_permission table with codename, content_type_id, id_name fields + * auth_group table with id, name fields + * auth_group_permissions table with group_id, permission, permission_id, _sdc_deteled_at fields + * auth_user table with id, email, username, and many other fields + * auth_user_groups table with group_id, id, user_id, _sdc_deleted_at fields + * auth_user_user_permissions table with id, permission_id, user_id fields + +edx-rbac +-------- +.. list-table:: + :widths: 15 75 + + * - **System Users** + - + * Each service determines who can assign roles. + * Each service determines which users roles can be assigned to. + * - **System Role Options** + - + * Each service that uses edX-rbac has its own list of explicit roles. + * - **Example Use Cases** + - + * Role needed only for a specific service + * Roles needed across contexts + * Ability to assign roles needed within the code + * Ability to manage role permissions within the code + * - **System Details** + - + * Each service that follows the edX-rbac spec determines the scope of the role + * Each service determines what other roles can explicitly grant access and where implicit access can come from (i.e. a system wide role may have implicit access) + * Roles can be assigned for a feature or the service + * The edX-rbac spec is designed to be usable by an instance, org, or service + * Role assignments typlically "stored" in the JWT cookie, but roles are stored in the db and therefore can be used from the db. + * - **Data Model** + - + * Each service that uses edX-rbac has its own db tables. + +content_libraries - v2 Library Roles +------------------------------------ +.. list-table:: + :widths: 15 75 + + * - **System Users** + - + * Roles are assigned by the library creator in the CMS. + * Roles can be assigned in the django admin dashboard. + * - **System Role Options** + - + * Roles: + * admin = Administer users and author content + * author = Author content + * read = Read-only + * - **Example Use Cases** + - + * v2 Content Library Service + * - **System Details** + - + * Set in the CMS + * Roles can be assigned through the CMS UI + * Roles can be assigned through the LMS django admin dashboard + * Roles are assigned per library. + * Roles can be assigned in the UI by an admin for the library or a user with the global_staff role. + * Connected to the django admin dashboard through admin.py file. + * - **Data Model** + - + * content_libraries_contentlibrarypermission table in the edx-platform LMS database with access_level, id, library_id, user_id, _sdc_deleted_at fields diff --git a/oeps/best-practices/oep-0066/Open_edX_Authorization_Implicit_Roles.png b/oeps/best-practices/oep-0066/Open_edX_Authorization_Implicit_Roles.png new file mode 100644 index 000000000..00076cc78 Binary files /dev/null and b/oeps/best-practices/oep-0066/Open_edX_Authorization_Implicit_Roles.png differ diff --git a/oeps/best-practices/oep-0066/Open_edX_Authorization_Implicit_Roles.xml b/oeps/best-practices/oep-0066/Open_edX_Authorization_Implicit_Roles.xml new file mode 100644 index 000000000..43564a9d9 --- /dev/null +++ b/oeps/best-practices/oep-0066/Open_edX_Authorization_Implicit_Roles.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/oeps/best-practices/oep-0066/Open_edX_Authorization_Implicit_Roles_Table.rst b/oeps/best-practices/oep-0066/Open_edX_Authorization_Implicit_Roles_Table.rst new file mode 100644 index 000000000..5369b839a --- /dev/null +++ b/oeps/best-practices/oep-0066/Open_edX_Authorization_Implicit_Roles_Table.rst @@ -0,0 +1,11 @@ +Open edX Authorization Systems Implicit Roles Table +--------------------------------------------------- +.. list-table:: + :widths: 100 + :header-rows: 1 + + * - Student / learner + * - Student/Learner is an implicit role with permissions assigned based on logic within the code. + * - Student/Learner is determined on a course basis. + * - Student/Learner is determined based on related data (enrollment, payment, etc). + * - Student/Learner can be audit or verified, each with different permissions. diff --git a/oeps/best-practices/oep-0066/Open_edX_Authorization_User_Flows.png b/oeps/best-practices/oep-0066/Open_edX_Authorization_User_Flows.png new file mode 100644 index 000000000..c82ca4dde Binary files /dev/null and b/oeps/best-practices/oep-0066/Open_edX_Authorization_User_Flows.png differ diff --git a/oeps/best-practices/oep-0066/Open_edX_Authorization_User_Flows.xml b/oeps/best-practices/oep-0066/Open_edX_Authorization_User_Flows.xml new file mode 100644 index 000000000..facb7cf65 --- /dev/null +++ b/oeps/best-practices/oep-0066/Open_edX_Authorization_User_Flows.xml @@ -0,0 +1,161 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/oeps/redirects.txt b/oeps/redirects.txt index 96771d3ff..63e532fa4 100644 --- a/oeps/redirects.txt +++ b/oeps/redirects.txt @@ -19,3 +19,4 @@ "best-practices/oep-0011/decisions/0005-django-templates.rst" "best-practices/oep-0067/decisions/frontend/0005-django-templates.rst" "best-practices/oep-0011/decisions/0006-codecov.rst" "best-practices/oep-0067/decisions/frontend/0006-codecov.rst" "best-practices/oep-0011-bp-FED-technology.rst" "archived/oep-0011-bp-FED-technology.rst" +"best-practices/oep-0009-bp-permissions.rst" "archived/oep-0009-bp-permissions.rst"