-
Notifications
You must be signed in to change notification settings - Fork 16
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add API endpoint for retrieving CSRF token.
- Loading branch information
Douglas Hall
committed
Oct 9, 2018
1 parent
58f4297
commit 360b7d0
Showing
16 changed files
with
201 additions
and
68 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
""" | ||
URL definitions for the CSRF API endpoints. | ||
""" | ||
|
||
from django.conf.urls import include, url | ||
|
||
urlpatterns = [ | ||
url(r'^v1/', include('csrf.api.v1.urls'), name='csrf_api_v1'), | ||
] |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
""" | ||
URL definitions for version 1 of the CSRF API. | ||
""" | ||
|
||
from django.conf.urls import url | ||
|
||
from .views import CsrfTokenView | ||
|
||
urlpatterns = [ | ||
url(r'^token$', CsrfTokenView.as_view(), name='csrf_token'), | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
""" | ||
API for CSRF application. | ||
""" | ||
|
||
from django.middleware.csrf import get_token | ||
from rest_framework.permissions import IsAuthenticated | ||
from rest_framework.response import Response | ||
from rest_framework.views import APIView | ||
|
||
from edx_rest_framework_extensions.authentication import JwtAuthentication | ||
|
||
|
||
class CsrfTokenView(APIView): | ||
""" | ||
**Use Case** | ||
Allows frontend apps to obtain a CSRF token from the Django | ||
service in order to make POST, PUT, and DELETE requests to | ||
API endpoints hosted on the service. | ||
**Behavior** | ||
GET /csrf/api/v1/token | ||
>>> { | ||
>>> "csrfToken": "abcdefg1234567" | ||
>>> } | ||
""" | ||
|
||
authentication_classes = (JwtAuthentication,) | ||
permission_classes = (IsAuthenticated,) | ||
|
||
def get(self, request): | ||
""" | ||
GET /csrf/api/v1/token | ||
""" | ||
return Response({'csrfToken': get_token(request)}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
""" | ||
App for creating and distributing CSRF tokens to frontend applications. | ||
""" | ||
|
||
from django.apps import AppConfig | ||
|
||
|
||
class CsrfAppConfig(AppConfig): | ||
"""Configuration for the csrf application.""" | ||
|
||
name = 'csrf' | ||
verbose_name = 'CSRF' |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
""" Tests for the CSRF API """ | ||
|
||
from django.urls import reverse | ||
from rest_framework import status | ||
from rest_framework.test import APITestCase | ||
|
||
from edx_rest_framework_extensions.auth.jwt.tests.utils import generate_jwt | ||
from edx_rest_framework_extensions.tests.factories import UserFactory | ||
|
||
|
||
class CsrfTokenTests(APITestCase): | ||
""" Tests for the CSRF token endpoint. """ | ||
|
||
def test_get_token(self): | ||
""" | ||
Ensure we can get a CSRF token. | ||
""" | ||
url = reverse('csrf_token') | ||
user = UserFactory() | ||
jwt = generate_jwt(user) | ||
self.client.credentials(HTTP_AUTHORIZATION='JWT {}'.format(jwt)) | ||
response = self.client.get(url, format='json') | ||
self.assertEqual(response.status_code, status.HTTP_200_OK) | ||
self.assertIn('csrfToken', response.data) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
""" | ||
URLs for the CSRF application. | ||
""" | ||
|
||
from django.conf.urls import include, url | ||
|
||
urlpatterns = [ | ||
url(r'^csrf/api/', include('csrf.api.urls'), name='csrf_api'), | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,3 @@ | ||
""" edx Django REST Framework extensions. """ | ||
|
||
__version__ = '1.10.0' # pragma: no cover | ||
__version__ = '1.11.0' # pragma: no cover |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
""" Utility functions for tests. """ | ||
from time import time | ||
|
||
import jwt | ||
from django.conf import settings | ||
|
||
|
||
def generate_jwt(user, scopes=None, filters=None, is_restricted=None): | ||
""" | ||
Generate a valid JWT for authenticated requests. | ||
""" | ||
access_token = generate_latest_version_payload( | ||
user, | ||
scopes=scopes, | ||
filters=filters, | ||
is_restricted=is_restricted | ||
) | ||
return generate_jwt_token(access_token) | ||
|
||
|
||
def generate_jwt_token(payload, signing_key=None): | ||
""" | ||
Generate a valid JWT token for authenticated requests. | ||
""" | ||
signing_key = signing_key or settings.JWT_AUTH['JWT_ISSUERS'][0]['SECRET_KEY'] | ||
return jwt.encode(payload, signing_key).decode('utf-8') | ||
|
||
|
||
def generate_latest_version_payload(user, scopes=None, filters=None, version=None, | ||
is_restricted=None): | ||
""" | ||
Generate a valid JWT payload given a user and optionally scopes and filters. | ||
""" | ||
payload = generate_unversioned_payload(user) | ||
payload.update({ | ||
# fix this version and add newly introduced fields as the version updates. | ||
'version': '1.1.0', | ||
'filters': [], | ||
'is_restricted': False, | ||
}) | ||
if scopes is not None: | ||
payload['scopes'] = scopes | ||
if version is not None: | ||
payload['version'] = version | ||
if filters is not None: | ||
payload['filters'] = filters | ||
if is_restricted is not None: | ||
payload['is_restricted'] = is_restricted | ||
return payload | ||
|
||
|
||
def generate_unversioned_payload(user): | ||
""" | ||
Generate an unversioned valid JWT payload given a user. | ||
""" | ||
jwt_issuer_data = settings.JWT_AUTH['JWT_ISSUERS'][0] | ||
now = int(time()) | ||
ttl = 600 | ||
payload = { | ||
'iss': jwt_issuer_data['ISSUER'], | ||
'aud': jwt_issuer_data['AUDIENCE'], | ||
'username': user.username, | ||
'email': user.email, | ||
'iat': now, | ||
'exp': now + ttl, | ||
'scopes': [], | ||
} | ||
return payload |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters