Merge pull request #18651 from edx/robrap/ARCH-180-dot-upgrade-all-steps
ARCH-180: Upgrade DOT to 1.1.2
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
"""
|
||||
Custom authentication backends.
|
||||
"""
|
||||
from django.contrib.auth.backends import AllowAllUsersModelBackend as UserModelBackend
|
||||
from ratelimitbackend.backends import RateLimitMixin
|
||||
|
||||
|
||||
class EdxRateLimitedAllowAllUsersModelBackend(RateLimitMixin, UserModelBackend):
|
||||
"""
|
||||
Authentication backend needed to incorporate rate limiting of login attempts - but also
|
||||
enabling users with is_active of False in the Django auth_user model to still authenticate.
|
||||
This is necessary for mobile users using 3rd party auth who have not activated their accounts,
|
||||
Inactive users who use 1st party auth (username/password auth) will still fail login attempts,
|
||||
just at a higher layer, in the login_user view.
|
||||
|
||||
See: https://openedx.atlassian.net/browse/TNL-4516
|
||||
"""
|
||||
pass
|
||||
@@ -6,14 +6,12 @@ from __future__ import unicode_literals
|
||||
from datetime import datetime
|
||||
|
||||
from django.contrib.auth import authenticate, get_user_model
|
||||
from django.contrib.auth.backends import AllowAllUsersModelBackend as UserModelBackend
|
||||
from django.db.models.signals import pre_save
|
||||
from django.dispatch import receiver
|
||||
from oauth2_provider.models import AccessToken
|
||||
from oauth2_provider.oauth2_validators import OAuth2Validator
|
||||
from oauth2_provider.scopes import get_scopes_backend
|
||||
from pytz import utc
|
||||
from ratelimitbackend.backends import RateLimitMixin
|
||||
|
||||
from ..models import RestrictedApplication
|
||||
|
||||
@@ -27,19 +25,6 @@ def on_access_token_presave(sender, instance, *args, **kwargs): # pylint: disab
|
||||
instance.expires = datetime(1970, 1, 1, tzinfo=utc)
|
||||
|
||||
|
||||
class EdxRateLimitedAllowAllUsersModelBackend(RateLimitMixin, UserModelBackend):
|
||||
"""
|
||||
Authentication backend needed to incorporate rate limiting of login attempts - but also
|
||||
enabling users with is_active of False in the Django auth_user model to still authenticate.
|
||||
This is necessary for mobile users using 3rd party auth who have not activated their accounts,
|
||||
Inactive users who use 1st party auth (username/password auth) will still fail login attempts,
|
||||
just at a higher layer, in the login_user view.
|
||||
|
||||
See: https://openedx.atlassian.net/browse/TNL-4516
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class EdxOAuth2Validator(OAuth2Validator):
|
||||
"""
|
||||
Validator class that implements edX-specific custom behavior:
|
||||
|
||||
@@ -5,7 +5,7 @@ from __future__ import unicode_literals
|
||||
|
||||
from oauth2_provider.exceptions import OAuthToolkitError
|
||||
from oauth2_provider.http import HttpResponseUriRedirect
|
||||
from oauth2_provider.models import get_application_model
|
||||
from oauth2_provider.models import get_access_token_model, get_application_model
|
||||
from oauth2_provider.scopes import get_scopes_backend
|
||||
from oauth2_provider.settings import oauth2_settings
|
||||
from oauth2_provider.views import AuthorizationView
|
||||
@@ -69,11 +69,12 @@ class EdxOAuth2AuthorizationView(AuthorizationView):
|
||||
uri, headers, body, status = self.create_authorization_response(
|
||||
request=self.request, scopes=" ".join(scopes),
|
||||
credentials=credentials, allow=True)
|
||||
return HttpResponseUriRedirect(uri)
|
||||
return HttpResponseUriRedirect(uri, application.get_allowed_schemes())
|
||||
|
||||
# *** Changed the if statement that checked for require_approval to an assert.
|
||||
assert require_approval == 'auto_even_if_expired'
|
||||
tokens = request.user.accesstoken_set.filter(
|
||||
tokens = get_access_token_model().objects.filter(
|
||||
user=request.user,
|
||||
application=kwargs['application'],
|
||||
# *** Purposefully keeping this commented out code to highlight that
|
||||
# our version of the implementation does NOT filter by expiration date.
|
||||
@@ -86,7 +87,7 @@ class EdxOAuth2AuthorizationView(AuthorizationView):
|
||||
uri, headers, body, status = self.create_authorization_response(
|
||||
request=self.request, scopes=" ".join(scopes),
|
||||
credentials=credentials, allow=True)
|
||||
return HttpResponseUriRedirect(uri)
|
||||
return HttpResponseUriRedirect(uri, application.get_allowed_schemes())
|
||||
|
||||
# render an authorization prompt so the user can approve
|
||||
# the application's requested scopes
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.14 on 2018-07-23 14:58
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('oauth_dispatch', '0005_applicationaccess_type'),
|
||||
]
|
||||
|
||||
run_before = [
|
||||
('oauth2_provider', '0005_auto_20170514_1141'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='applicationaccess',
|
||||
name='application',
|
||||
field=models.OneToOneField(db_constraint=False, on_delete=django.db.models.deletion.CASCADE, related_name='access', to=settings.OAUTH2_PROVIDER_APPLICATION_MODEL),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='applicationorganization',
|
||||
name='application',
|
||||
field=models.ForeignKey(db_constraint=False, on_delete=django.db.models.deletion.CASCADE, related_name='organizations', to=settings.OAUTH2_PROVIDER_APPLICATION_MODEL),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='restrictedapplication',
|
||||
name='application',
|
||||
field=models.ForeignKey(db_constraint=False, on_delete=django.db.models.deletion.CASCADE, to=settings.OAUTH2_PROVIDER_APPLICATION_MODEL),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,33 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.14 on 2018-07-23 15:12
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('oauth_dispatch', '0006_drop_application_id_constraints'),
|
||||
('oauth2_provider', '0006_auto_20171214_2232'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='applicationaccess',
|
||||
name='application',
|
||||
field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='access', to=settings.OAUTH2_PROVIDER_APPLICATION_MODEL),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='applicationorganization',
|
||||
name='application',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='organizations', to=settings.OAUTH2_PROVIDER_APPLICATION_MODEL),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='restrictedapplication',
|
||||
name='application',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.OAUTH2_PROVIDER_APPLICATION_MODEL),
|
||||
),
|
||||
]
|
||||
@@ -684,36 +684,39 @@ class TestRevokeTokenView(AccessTokenLoginMixin, _DispatchingViewTestCase): # p
|
||||
'token': token,
|
||||
}
|
||||
|
||||
def _assert_refresh_token_invalidated(self):
|
||||
def assert_refresh_token_status_code(self, refresh_token, expected_status_code):
|
||||
"""
|
||||
Asserts that oauth assigned refresh_token is not valid
|
||||
Asserts the status code using oauth assigned refresh_token
|
||||
"""
|
||||
response = self.client.post(
|
||||
self.access_token_url,
|
||||
self.access_token_post_body_with_refresh_token(self.refresh_token)
|
||||
self.access_token_post_body_with_refresh_token(refresh_token)
|
||||
)
|
||||
self.assertEqual(response.status_code, 401)
|
||||
self.assertEqual(response.status_code, expected_status_code)
|
||||
|
||||
def verify_revoke_token(self, token):
|
||||
def revoke_token(self, token):
|
||||
"""
|
||||
Verifies access of token before and after revoking
|
||||
Revokes the passed access or refresh token
|
||||
"""
|
||||
self._assert_access_token_is_valid()
|
||||
|
||||
response = self.client.post(self.revoke_token_url, self.revoke_token_post_body(token))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
self._assert_access_token_invalidated()
|
||||
self._assert_refresh_token_invalidated()
|
||||
|
||||
def test_revoke_refresh_token_dot(self):
|
||||
"""
|
||||
Tests invalidation/revoke of user tokens against refresh token for django-oauth-toolkit
|
||||
Tests invalidation/revoke of refresh token for django-oauth-toolkit
|
||||
"""
|
||||
self.verify_revoke_token(self.refresh_token)
|
||||
self.assert_refresh_token_status_code(self.refresh_token, expected_status_code=200)
|
||||
|
||||
self.revoke_token(self.refresh_token)
|
||||
|
||||
self.assert_refresh_token_status_code(self.refresh_token, expected_status_code=401)
|
||||
|
||||
def test_revoke_access_token_dot(self):
|
||||
"""
|
||||
Tests invalidation/revoke of user access token for django-oauth-toolkit
|
||||
"""
|
||||
self.verify_revoke_token(self.access_token)
|
||||
self._assert_access_token_is_valid(self.access_token)
|
||||
|
||||
self.revoke_token(self.access_token)
|
||||
|
||||
self._assert_access_token_invalidated(self.access_token)
|
||||
|
||||
Reference in New Issue
Block a user