OAuth docs: minor fixes
This commit is contained in:
@@ -50,22 +50,22 @@ payload.
|
||||
3. Restricted Applications receive *unexpired* JWTs, signed with a *new key*
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* We will no longer return expired *JWTs as access tokens* to Restricted
|
||||
Applications. We will sign them with a *new key* that is not shared with
|
||||
unprotected microservices.
|
||||
We will no longer return expired *JWTs as access tokens* to Restricted
|
||||
Applications. We will sign them with a *new key* that is not shared with
|
||||
unprotected microservices.
|
||||
|
||||
* API endpoints that are exposed by other microservices and that
|
||||
support OAuth2 requests are vulnerable to exploitation until
|
||||
they are also updated to enforce scopes.
|
||||
|
||||
* We do not want a lock-step deployment across all of our microservices.
|
||||
We want to enable these changes without blocking on updating all
|
||||
microservices.
|
||||
* We do not want a lock-step deployment across all of our microservices.
|
||||
We want to enable these changes without blocking on updating all
|
||||
microservices.
|
||||
|
||||
* We do not want to issue unexpired *Bearer tokens* to Restricted
|
||||
Applications since they will be accepted by unprotected microservices.
|
||||
There's no way to retroactively inform existing microservices
|
||||
to reject scope-limiting *Bearer tokens*.
|
||||
* We do not want to issue unexpired *Bearer tokens* to Restricted
|
||||
Applications since they will be accepted by unprotected microservices.
|
||||
There's no way to retroactively inform existing microservices
|
||||
to reject scope-limiting *Bearer tokens*.
|
||||
|
||||
* On the other hand, existing unprotected microservices will reject
|
||||
*JWT tokens* signed with new keys that they do not know about. We will
|
||||
@@ -90,20 +90,22 @@ payload.
|
||||
JWT tokens for Restricted Applications, but ONLY if:
|
||||
|
||||
* the token_type in the request equals *"jwt"* and
|
||||
* a `feature toggle (switch)`_ named "oauth2.unexpired_restricted_applications" is enabled.
|
||||
* a `feature toggle (switch)`_ named "oauth2.unexpired_restricted_applications"
|
||||
is enabled.
|
||||
|
||||
.. _edx_rest_framework_extensions.settings: https://github.com/edx/edx-drf-extensions/blob/1db9f5e3e5130a1e0f43af2035489b3ed916d245/edx_rest_framework_extensions/settings.py#L73
|
||||
.. _edx-platform settings: https://github.com/edx/edx-platform/blob/master/lms/envs/docs/README.rst
|
||||
.. _example: https://github.com/edx/edx-drf-extensions/blob/1db9f5e3e5130a1e0f43af2035489b3ed916d245/test_settings.py#L51
|
||||
.. _JwtBuilder: https://github.com/edx/edx-platform/blob/d3d64970c36f36a96d684571ec5b48ed645618d8/openedx/core/lib/token_utils.py#L15
|
||||
.. _oauth_dispatch.views.AccessTokenView.dispatch: https://github.com/edx/edx-platform/blob/d21a09828072504bc97a2e05883c1241e3a35da9/openedx/core/djangoapps/oauth_dispatch/views.py#L100
|
||||
.. _oauth_dispatch.validators: https://github.com/edx/edx-platform/blob/master/openedx/core/djangoapps/oauth_dispatch/dot_overrides/validators.py
|
||||
|
||||
4. Associate Available Scopes with Applications
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* In order to allow open edX operators to a priori limit the
|
||||
types of access an Application can request, we will allow them
|
||||
to configure Application-specific "available scopes".
|
||||
In order to allow open edX operators to a priori limit the
|
||||
types of access an Application can request, we will allow them
|
||||
to configure Application-specific "available scopes".
|
||||
|
||||
* Introduce a new data model that associates available scopes with
|
||||
DOT Applications.
|
||||
@@ -120,61 +122,70 @@ payload.
|
||||
5. Associate Available Organizations with Applications
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* See 0007-include-organizations-in-tokens_ for decisions on this.
|
||||
See 0007-include-organizations-in-tokens_ for decisions on this.
|
||||
|
||||
6. Introduce a new Permission class to enforce scopes
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
* The new `custom Permission`_ class will extend DOT's TokenHasScope_
|
||||
Permission class.
|
||||
* New Permission class
|
||||
|
||||
* The TokenHasScope_ permission allows API endpoints to declare the
|
||||
scopes that they require in a *required_scopes* class variable.
|
||||
* The new `custom Permission`_ class will extend DOT's TokenHasScope_
|
||||
Permission class.
|
||||
|
||||
* The permission class will verify that the scopes in the provided JWT
|
||||
are a proper superset of the scopes required by the requested view.
|
||||
* The TokenHasScope_ permission allows API endpoints to declare the
|
||||
scopes that they require in a *required_scopes* class variable.
|
||||
|
||||
* For now, the permission class will skip this verification if the
|
||||
application is not a Restricted Application or if the token_type
|
||||
was not a JWT token.
|
||||
* Enforcement by the Permission class
|
||||
|
||||
* **Note:** This will be an issue when microservices want to verify
|
||||
scopes. Determining whether an access token is associated with a
|
||||
Restricted Application is an LMS-specific capability. Given this,
|
||||
we may need to include a field in the token that indicates whether
|
||||
it was issued to a Restricted Application.
|
||||
* The permission class will verify that the scopes in the provided JWT
|
||||
are a proper superset of the *required_scopes* field set by the requested
|
||||
view.
|
||||
|
||||
* If the scopes verify, the permission class will update the request
|
||||
object with any organization values found in the token in an attribute
|
||||
called *allowed_organizations*. The view can then limit its access
|
||||
and resources by the allowed organizations.
|
||||
* For now, the permission class will skip this verification if the
|
||||
application is not a Restricted Application or if the token_type
|
||||
was not a JWT token.
|
||||
|
||||
* In order to have higher confidence that we don't inadvertently miss
|
||||
protecting any API endpoints, add the new Permission class to the
|
||||
`REST_FRAMEWORK's DEFAULT_PERMISSION_CLASSES`_ setting.
|
||||
* **Note:** This will be an issue when microservices want to verify
|
||||
scopes. Determining whether an access token is associated with a
|
||||
Restricted Application is an LMS-specific capability. Given this,
|
||||
we may need to include a field in the token that indicates whether
|
||||
it was issued to a Restricted Application.
|
||||
|
||||
* If the scopes verify, the permission class will update the request
|
||||
object with any organization values found in the token in an attribute
|
||||
called *allowed_organizations*. The view can then limit its access
|
||||
and resources by the allowed organizations.
|
||||
|
||||
* Using the Permission class
|
||||
|
||||
* In order to have higher confidence that we don't inadvertently miss
|
||||
protecting any API endpoints, add the new Permission class to the
|
||||
`REST_FRAMEWORK's DEFAULT_PERMISSION_CLASSES`_ setting.
|
||||
|
||||
* **Note:** Many of our API endpoints currently override this default
|
||||
by setting the *permission_classes* field on their own View or ViewSet.
|
||||
by overriding the *permission_classes* field on their own View or ViewSet.
|
||||
So in addition to setting this default value, we will update all
|
||||
(15 or so) places that include JwtAuthentication_ in their
|
||||
*authentication_classes* field.
|
||||
|
||||
* In case of an unexpected failure with this approach in production,
|
||||
use a `feature toggle (switch)`_ named "oauth2.enforce_token_scopes".
|
||||
When the switch is disabled, the new Permission class fails verification
|
||||
of all Restricted Application requests.
|
||||
* **Note:** We currently have both `function-based Django views`_ and
|
||||
class-based `Django Rest Framework (DRF)`_ views in the platform.
|
||||
|
||||
* **Note:** We currently have both `function-based Django views`_ and
|
||||
class-based `Django Rest Framework (DRF)`_ views in the platform.
|
||||
* Authorization enforcement using Django Permission classes is
|
||||
supported only for DRF views. DRF does provide a `Python decorator`_
|
||||
to add DRF support to function-based views.
|
||||
|
||||
* Authorization enforcement using Django Permission classes is
|
||||
supported only for DRF views. DRF does provide a `Python decorator`_
|
||||
to add DRF support to function-based views.
|
||||
|
||||
* Only DRF enhanced views support JWT based authentication in our
|
||||
system. They do so via the DRF-based JwtAuthentication_ class.
|
||||
So we can **safely assume** that all JWT-supporting API endpoints
|
||||
can be protected via DRF's Permission class.
|
||||
* Only DRF enhanced views support JWT based authentication in our
|
||||
system. They do so via the DRF-based JwtAuthentication_ class.
|
||||
So we can **safely assume** that all JWT-supporting API endpoints
|
||||
can be protected via DRF's Permission class.
|
||||
|
||||
* Easy to disable
|
||||
|
||||
* In case of an unexpected failure with this approach in production, use a
|
||||
`feature toggle (switch)`_ named "oauth2.enforce_token_scopes". When the
|
||||
switch is disabled, the new Permission class fails verification of all
|
||||
Restricted Application requests.
|
||||
|
||||
.. _custom Permission: http://www.django-rest-framework.org/api-guide/permissions/#custom-permissions
|
||||
.. _TokenHasScope: https://github.com/evonove/django-oauth-toolkit/blob/50e4df7d97af90439d27a73c5923f2c06a4961f2/oauth2_provider/contrib/rest_framework/permissions.py#L13
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
7. Include Organization in Tokens
|
||||
---------------------------------
|
||||
7. Include Organizations in Tokens
|
||||
----------------------------------
|
||||
|
||||
Status
|
||||
------
|
||||
@@ -74,7 +74,7 @@ embedded in the scopes.
|
||||
|
||||
* Create a configurable Application-specific "available organizations"
|
||||
setting, which is akin to Application-specific "available scopes"
|
||||
(as described in 0006-enforce-scopes-in-LMS-APIs_.
|
||||
(as described in 0006-enforce-scopes-in-LMS-APIs_).
|
||||
|
||||
* Introduce a new data model that associates available organizations
|
||||
with DOT Applications.
|
||||
@@ -112,7 +112,7 @@ embedded in the scopes.
|
||||
When the interstitial authorization approval form is presented to the
|
||||
user for granting access to a DOT Application, if the Application is
|
||||
associated with an Organization, the Organization value(s) should be
|
||||
presented to the user. This will make it clear to the user that the
|
||||
presented to the user. This makes it clear to the user that the
|
||||
granted access is limited to the Organization's affiliations.
|
||||
|
||||
4. Embed Organization Limitation Types in Scopes
|
||||
@@ -164,7 +164,7 @@ single user (via Authorization Code).
|
||||
Consequences
|
||||
------------
|
||||
|
||||
* By associating Organizations with DOT Applications and not Restricted
|
||||
* By associating organizations with DOT Applications and not Restricted
|
||||
Applications, we can eventually eliminate Restricted Applications
|
||||
altogether.
|
||||
|
||||
Reference in New Issue
Block a user