Skip to content

Commit 34a43ca

Browse files
committed
Merge pull request #103 from edx/awais786/ECOM-3808-bearer-auth-tests
Awais786/ecom 3808 Implement Bearer Auth for acceptance tests.
2 parents 993d196 + 2c0d8dc commit 34a43ca

File tree

7 files changed

+53
-32
lines changed

7 files changed

+53
-32
lines changed

acceptance_tests/config.py

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -29,21 +29,12 @@ def str2bool(s):
2929
CREDENTIALS_API_URL = os.environ.get('CREDENTIALS_API_URL', CREDENTIALS_ROOT_URL + '/api/v1/')
3030
PROGRAM_ID = os.environ.get('PROGRAM_ID', 1)
3131

32-
JWT_SECRET_KEY = os.environ.get('JWT_SECRET_KEY')
33-
if JWT_SECRET_KEY is None:
34-
raise RuntimeError('A valid JWT_SECRET_KEY is required to run acceptance tests.')
35-
36-
USER_JWT_AUDIENCE = os.environ.get('USER_JWT_AUDIENCE')
37-
if USER_JWT_AUDIENCE is None:
38-
raise RuntimeError('A valid USER_JWT_AUDIENCE is required to run acceptance tests.')
39-
4032
# LMS CONFIGURATION
4133
try:
4234
LMS_ROOT_URL = os.environ.get('LMS_ROOT_URL').strip('/')
4335
except AttributeError:
4436
raise RuntimeError('You must provide a valid URL root for the LMS to run acceptance tests.')
4537

46-
OAUTH_URL = LMS_ROOT_URL + '/oauth2'
4738
LMS_USERNAME = os.environ.get('LMS_USERNAME')
4839
LMS_EMAIL = os.environ.get('LMS_EMAIL')
4940
LMS_PASSWORD = os.environ.get('LMS_PASSWORD')

acceptance_tests/mixins.py

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -35,19 +35,8 @@ def setUp(self):
3535

3636
@property
3737
def credential_api_client(self):
38-
now = datetime.datetime.utcnow()
39-
expires_in = 60
40-
payload = {
41-
"iss": config.OAUTH_URL,
42-
"aud": config.USER_JWT_AUDIENCE,
43-
"exp": now + datetime.timedelta(seconds=expires_in),
44-
"iat": now,
45-
"preferred_username": config.LMS_USERNAME,
46-
"administrator": True,
47-
}
4838
try:
49-
jwt_data = jwt.encode(payload, config.JWT_SECRET_KEY)
50-
api_client = EdxRestApiClient(config.CREDENTIALS_API_URL, jwt=jwt_data)
39+
api_client = EdxRestApiClient(config.CREDENTIALS_API_URL, oauth_access_token=config.ACCESS_TOKEN)
5140
except Exception: # pylint: disable=broad-except
5241
log.exception("Failed to initialize the API client with url '%s'.", config.CREDENTIALS_API_URL)
5342
return

credentials/apps/api/authentication.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44

55
import logging
66

7+
from django.conf import settings
78
from django.contrib.auth.models import Group
9+
from edx_rest_framework_extensions.authentication import BearerAuthentication as BaseBearerAuthentication
810
from rest_framework.exceptions import AuthenticationFailed
911
from rest_framework_jwt.authentication import JSONWebTokenAuthentication
1012

@@ -63,3 +65,16 @@ def authenticate_credentials(self, payload):
6365
user.groups.remove(admin_group)
6466

6567
return user
68+
69+
70+
class BearerAuthentication(BaseBearerAuthentication):
71+
"""
72+
Simple token based authentication.
73+
74+
This authentication class is useful for authenticating an OAuth2 access token against a remote
75+
authentication provider. Clients should authenticate by passing the token key in the "Authorization" HTTP header,
76+
prepended with the string `"Bearer "`.
77+
"""
78+
def get_user_info_url(self):
79+
""" Returns the URL, hosted by the OAuth2 provider, from which user information can be pulled. """
80+
return '{base}/user_info/'.format(base=settings.OAUTH2_PROVIDER_URL)

credentials/apps/api/tests/test_authentication.py

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@
1010
from rest_framework.exceptions import AuthenticationFailed
1111
from rest_framework.test import APIRequestFactory
1212

13-
from credentials.apps.api.authentication import JwtAuthentication, pipeline_set_user_roles
13+
from credentials.apps.api.authentication import (
14+
BearerAuthentication, JwtAuthentication, pipeline_set_user_roles
15+
)
1416
from credentials.apps.api.jwt_decode_handler import api_settings as drf_jwt_settings
1517
from credentials.apps.api.tests.mixins import JwtMixin
1618
from credentials.apps.core.constants import Role
@@ -146,3 +148,33 @@ def test_no_user(self):
146148
"""
147149
result = pipeline_set_user_roles({}, None)
148150
self.assertEqual(result, {})
151+
152+
153+
class BearerAuthenticationTests(TestCase):
154+
""" Tests for the BearerAuthentication class. """
155+
156+
def setUp(self):
157+
super(BearerAuthenticationTests, self).setUp()
158+
self.auth = BearerAuthentication()
159+
self.factory = APIRequestFactory()
160+
161+
def _create_request(self, token='12345', token_name='Bearer'):
162+
"""Create request with authorization header. """
163+
auth_header = '{} {}'.format(token_name, token)
164+
request = self.factory.get('/', HTTP_AUTHORIZATION=auth_header)
165+
return request
166+
167+
def test_authenticate_header(self):
168+
"""The method should return the string Bearer."""
169+
self.assertEqual(self.auth.authenticate_header(self._create_request()), 'Bearer')
170+
171+
def test_authenticate_invalid_token(self):
172+
"""If no token is supplied, or if the token contains spaces, the method should raise an exception."""
173+
174+
# Missing token
175+
request = self._create_request('')
176+
self.assertRaises(AuthenticationFailed, self.auth.authenticate, request)
177+
178+
# Token with spaces
179+
request = self._create_request('abc 123 456')
180+
self.assertRaises(AuthenticationFailed, self.auth.authenticate, request)

credentials/settings/base.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,7 @@
288288
REST_FRAMEWORK = {
289289
'DEFAULT_AUTHENTICATION_CLASSES': (
290290
'credentials.apps.api.authentication.JwtAuthentication',
291+
'credentials.apps.api.authentication.BearerAuthentication',
291292
'rest_framework.authentication.SessionAuthentication',
292293
),
293294
'DEFAULT_FILTER_BACKENDS': ('rest_framework.filters.DjangoFilterBackend',),

docs/testing.rst

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -123,14 +123,6 @@ Our acceptance tests rely on configuration which can be specified using environm
123123
- URL root for credentials service
124124
- Yes
125125
- N/A
126-
* - JWT_SECRET_KEY
127-
- It should match ``SOCIAL_AUTH_EDX_OIDC_SECRET`` in credentials
128-
- Yes
129-
- N/A
130-
* - USER_JWT_AUDIENCE
131-
- It should match ``CREDENTIALS_JWT_AUDIENCE`` in credentials.
132-
- Yes
133-
- N/A
134126

135127
Running Acceptance Tests
136128
************************
@@ -141,8 +133,8 @@ Run all acceptance tests by executing ``make accept``. To run a specific test, e
141133

142134
As discussed above, the acceptance tests rely on configuration which can be specified using environment variables. For example, when running the acceptance tests against local instances of Programs and the LMS, you might run::
143135

144-
$ CREDENTIALS_ROOT_URL="http://localhost:8150/" LMS_ROOT_URL="http://127.0.0.1:8000" LMS_USERNAME="<username>" LMS_EMAIL="<email address>" LMS_PASSWORD="<password>" JWT_SECRET_KEY="<secret-key>" ACCESS_TOKEN="<access token>" PROGRAM_ID=<program_id> make accept
136+
$ CREDENTIALS_ROOT_URL="http://localhost:8150/" LMS_ROOT_URL="http://127.0.0.1:8000" LMS_USERNAME="<username>" LMS_EMAIL="<email address>" LMS_PASSWORD="<password>" ACCESS_TOKEN="<access token>" PROGRAM_ID=<program_id> make accept
145137

146138
When running against a production-like staging environment, you might run::
147139

148-
$ CREDENTIALS_ROOT_URL="https://credentials.stage.edx.org" LMS_URL_ROOT="https://courses.stage.edx.org" LMS_USERNAME="<username>" LMS_EMAIL="<email address>" LMS_PASSWORD="<password>" JWT_SECRET_KEY="<secret-key>" ACCESS_TOKEN="<access token>" PROGRAM_ID=<program_id> make accept
140+
$ CREDENTIALS_ROOT_URL="https://credentials.stage.edx.org" LMS_URL_ROOT="https://courses.stage.edx.org" LMS_USERNAME="<username>" LMS_EMAIL="<email address>" LMS_PASSWORD="<password>" ACCESS_TOKEN="<access token>" PROGRAM_ID=<program_id> make accept

requirements/base.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ djangorestframework-jwt==1.7.2
1010
django-rest-swagger==0.3.4
1111
django-storages==1.1.8
1212
edx-auth-backends==0.2.3
13+
edx-drf-extensions==0.5.1
1314
edx-opaque-keys==0.3.1
1415
edx-rest-api-client==1.4.0
1516
# The package django-libsass requires libsass and the newest version of libsass '0.10.1'

0 commit comments

Comments
 (0)