Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@ language: python
python:
- "2.7"

node_js: 6

cache:
directories:
- $HOME/edxapp_toxenv/
pip: true
npm: true

before_install:
- sudo rm -f /etc/boto.cfg
- travis_retry sudo apt-get update
Expand Down
1,676 changes: 1,670 additions & 6 deletions cms/static/js/i18n/ar/djangojs.js

Large diffs are not rendered by default.

2,092 changes: 2,050 additions & 42 deletions cms/static/js/i18n/es-419/djangojs.js

Large diffs are not rendered by default.

2,268 changes: 2,267 additions & 1 deletion cms/static/js/i18n/fake2/djangojs.js

Large diffs are not rendered by default.

2,064 changes: 2,062 additions & 2 deletions cms/static/js/i18n/fr-ca/djangojs.js

Large diffs are not rendered by default.

1,360 changes: 766 additions & 594 deletions cms/static/js/i18n/fr/djangojs.js

Large diffs are not rendered by default.

1,202 changes: 1,188 additions & 14 deletions cms/static/js/i18n/pt-br/djangojs.js

Large diffs are not rendered by default.

1,035 changes: 1,034 additions & 1 deletion cms/static/js/i18n/zh-cn/djangojs.js

Large diffs are not rendered by default.

22 changes: 20 additions & 2 deletions common/djangoapps/student/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,19 @@
from django.contrib.auth import load_backend
from django.contrib.auth.models import User
from django.db import IntegrityError, transaction
from django.db.models import Subquery
from django.utils import http
from django.utils.translation import ugettext as _
from oauth2_provider.models import AccessToken as dot_access_token
from oauth2_provider.models import RefreshToken as dot_refresh_token
from provider.constants import CONFIDENTIAL
from provider.oauth2.models import AccessToken as dop_access_token
from provider.oauth2.models import Client
from provider.oauth2.models import RefreshToken as dop_refresh_token
from pytz import UTC
from six import iteritems, text_type
import third_party_auth
from edx_oauth2_provider.models import TrustedClient
from course_modes.models import CourseMode
from lms.djangoapps.certificates.api import (
get_certificate_url,
Expand Down Expand Up @@ -376,8 +380,22 @@ def destroy_oauth_tokens(user):
"""
Destroys ALL OAuth access and refresh tokens for the given user.
"""
dop_access_token.objects.filter(user=user.id).delete()
dop_refresh_token.objects.filter(user=user.id).delete()
dop_access_query = dop_access_token.objects.filter(user=user.id)
dop_refresh_query = dop_refresh_token.objects.filter(user=user.id)

if not settings.FEATURES.get('KEEP_TRUSTED_CONFIDENTIAL_CLIENT_TOKENS', True):
# Appsembler: Avoid deleting the trusted confidential clients such as the Appsembler Management Console
trusted_clients = Client.objects.filter(
client_type=CONFIDENTIAL,
pk__in=Subquery(TrustedClient.objects.all().values('id')),
)

dop_access_query = dop_access_query.exclude(client__in=trusted_clients)
dop_refresh_query = dop_refresh_query.exclude(client__in=trusted_clients)

dop_access_query.delete()
dop_refresh_query.delete()

dot_access_token.objects.filter(user=user.id).delete()
dot_refresh_token.objects.filter(user=user.id).delete()

Expand Down
76 changes: 75 additions & 1 deletion common/djangoapps/student/tests/test_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,18 @@
from mock import patch
from testfixtures import LogCapture

from student.helpers import get_next_url_for_login_page
from student.helpers import destroy_oauth_tokens, get_next_url_for_login_page
from student.tests.factories import UserFactory
from edx_oauth2_provider.models import TrustedClient
from edx_oauth2_provider.tests.factories import (
TrustedClientFactory,
AccessTokenFactory,
ClientFactory,
RefreshTokenFactory,
)
from provider.constants import CONFIDENTIAL, PUBLIC
from provider.oauth2.models import AccessToken, RefreshToken

from openedx.core.djangoapps.site_configuration.tests.test_util import with_site_configuration_context

LOGGER_NAME = "student.helpers"
Expand Down Expand Up @@ -110,3 +121,66 @@ def validate_login():

with with_site_configuration_context(configuration=dict(THIRD_PARTY_AUTH_HINT=tpa_hint)):
validate_login()


@patch.dict(settings.FEATURES, {'KEEP_TRUSTED_CONFIDENTIAL_CLIENT_TOKENS': True})
class TestDestroyOAuthTokensHelper(TestCase):
def setUp(self):
super(TestDestroyOAuthTokensHelper, self).setUp()
self.user = UserFactory.create()
self.client = ClientFactory(logout_uri='https://amc.example.com/logout/', client_type=CONFIDENTIAL)
access_token = AccessTokenFactory.create(user=self.user, client=self.client)
RefreshTokenFactory.create(user=self.user, client=self.client, access_token=access_token)

def assert_destroy_behaviour(self, should_be_kept, message):
"""
Helper to test the `destroy_oauth_tokens` behaviour.
"""
assert AccessToken.objects.count() # Sanity check
assert RefreshToken.objects.count() # Sanity check
destroy_oauth_tokens(self.user)
assert should_be_kept == AccessToken.objects.count(), message
assert should_be_kept == RefreshToken.objects.count(), message

@patch.dict(settings.FEATURES, {'KEEP_TRUSTED_CONFIDENTIAL_CLIENT_TOKENS': False})
def test_confidential_trusted_client_feature_disabled(self):
"""
Tokens that have a confidential TrustedClient should be removed if the feature is disabled
"""
TrustedClientFactory.create(client=self.client)
self.assert_destroy_behaviour(
should_be_kept=False,
message='Tokens of a trusted confidential client should be deleted if the feature is disabled',
)

def test_confidential_trusted_client(self):
"""
Tokens that have a confidential TrustedClient shouldn't be removed.
"""
TrustedClientFactory.create(client=self.client)
self.assert_destroy_behaviour(
should_be_kept=True,
message='Tokens of a trusted confidential client should be kept',
)

def test_no_trusted_client(self):
"""
Only tokens that don't have a TrustedClient should be removed.
"""
assert not TrustedClient.objects.count() # 'Sanity check, there should not be a client'
self.assert_destroy_behaviour(
should_be_kept=False,
message='Tokens of an untrusted client should be deleted',
)

def test_public_trusted_client(self):
"""
Tokens for public clients are removed, even if they're trusted.
"""
self.client.client_type = PUBLIC
self.client.save()
TrustedClientFactory.create(client=self.client)
self.assert_destroy_behaviour(
should_be_kept=False,
message='Tokens of a public trusted client should be deleted',
)
Binary file modified conf/locale/ar/LC_MESSAGES/django.mo
Binary file not shown.
Loading