OAuth docs: minor fixes

This commit is contained in:
Nimisha Asthagiri
2018-02-04 18:26:26 -05:00
parent df4221e531
commit b99d0a3495
2 changed files with 67 additions and 56 deletions

View File

@@ -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

View File

@@ -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.