Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
edx-notes-api
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
edx
edx-notes-api
Commits
862d847c
Commit
862d847c
authored
Dec 02, 2014
by
Tim Babych
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
TNL-782 Check for valid ID Token
parent
3e5e4b7b
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
83 additions
and
28 deletions
+83
-28
AUTHORS
+1
-0
Makefile
+1
-0
notesapi/v1/permissions.py
+53
-1
notesapi/v1/tests/helpers.py
+14
-21
notesapi/v1/tests/test_views.py
+0
-0
notesapi/v1/views.py
+0
-4
notesserver/settings/common.py
+12
-1
notesserver/views.py
+1
-1
requirements/base.txt
+1
-0
No files found.
AUTHORS
View file @
862d847c
Oleg Marshev <oleg@edx.org>
Tim Babych <tim.babych@gmail.com>
Makefile
View file @
862d847c
PACKAGES
=
notesserver notesapi
.PHONY
:
requirements
validate
:
test.requirements test coverage
...
...
notesapi/v1/permissions.py
View file @
862d847c
import
jwt
import
logging
from
django.conf
import
settings
from
rest_framework.permissions
import
BasePermission
logger
=
logging
.
getLogger
(
__name__
)
class
TokenWrongIssuer
(
Exception
):
pass
class
HasAccessToken
(
BasePermission
):
"""
Allow requests having valid ID Token.
https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-31
Expected Token:
Header {
"alg": "HS256",
"typ": "JWT"
}
Claims {
"sub": "<USER_ID>",
"exp": <EXPIRATION TIMESTAMP>,
"iat": <ISSUED TIMESTAMP>,
"aud": "<CLIENT ID"
}
Should be signed with CLIENT_SECRET
"""
def
has_permission
(
self
,
request
,
view
):
return
True
if
getattr
(
settings
,
'DISABLE_TOKEN_CHECK'
,
False
):
return
True
token
=
request
.
META
.
get
(
'HTTP_X_ANNOTATOR_AUTH_TOKEN'
,
''
)
if
not
token
:
logger
.
debug
(
"No token found in headers"
)
return
False
try
:
data
=
jwt
.
decode
(
token
,
settings
.
CLIENT_SECRET
)
auth_user
=
data
[
'sub'
]
if
data
[
'aud'
]
!=
settings
.
CLIENT_ID
:
raise
TokenWrongIssuer
for
request_field
in
(
'GET'
,
'POST'
,
'DATA'
):
if
'user'
in
getattr
(
request
,
request_field
):
req_user
=
getattr
(
request
,
request_field
)[
'user'
]
if
req_user
==
auth_user
:
return
True
else
:
logger
.
debug
(
"Token user {auth_user} did not match {field} user {req_user}"
.
format
(
auth_user
=
auth_user
,
field
=
request_field
,
req_user
=
req_user
))
return
False
logger
.
info
(
"No user was present to compare in GET, POST or DATA"
)
except
jwt
.
ExpiredSignature
:
logger
.
debug
(
"Token was expired: {}"
.
format
(
token
))
except
jwt
.
DecodeError
:
logger
.
debug
(
"Could not decode token {}"
.
format
(
token
))
except
TokenWrongIssuer
:
logger
.
debug
(
"Token has wrong issuer {}"
.
format
(
token
))
return
False
\ No newline at end of file
notesapi/v1/tests/helpers.py
View file @
862d847c
class
MockConsumer
(
object
):
def
__init__
(
self
,
key
=
'mockconsumer'
):
self
.
key
=
key
self
.
secret
=
'top-secret'
self
.
ttl
=
86400
class
MockUser
(
object
):
def
__init__
(
self
,
id
=
'alice'
,
consumer
=
None
):
self
.
id
=
id
self
.
consumer
=
MockConsumer
(
consumer
if
consumer
is
not
None
else
'mockconsumer'
)
self
.
is_admin
=
False
class
MockAuthenticator
(
object
):
def
request_user
(
self
,
request
):
return
MockUser
()
def
mock_authorizer
(
*
args
,
**
kwargs
):
return
True
import
jwt
from
calendar
import
timegm
from
datetime
import
datetime
,
timedelta
from
django.conf
import
settings
def
get_id_token
(
user
):
now
=
datetime
.
utcnow
()
return
jwt
.
encode
({
'aud'
:
settings
.
CLIENT_ID
,
'sub'
:
user
,
'iat'
:
timegm
(
now
.
utctimetuple
()),
'exp'
:
timegm
((
now
+
timedelta
(
seconds
=
300
))
.
utctimetuple
()),
},
settings
.
CLIENT_SECRET
)
notesapi/v1/tests/test_views.py
View file @
862d847c
This diff is collapsed.
Click to expand it.
notesapi/v1/views.py
View file @
862d847c
...
...
@@ -2,7 +2,6 @@ from django.conf import settings
from
django.core.urlresolvers
import
reverse
from
rest_framework
import
status
from
rest_framework.permissions
import
AllowAny
from
rest_framework.response
import
Response
from
rest_framework.views
import
APIView
...
...
@@ -16,7 +15,6 @@ class AnnotationSearchView(APIView):
"""
Search annotations.
"""
permission_classes
=
(
AllowAny
,)
def
get
(
self
,
*
args
,
**
kwargs
):
# pylint: disable=unused-argument
"""
...
...
@@ -52,7 +50,6 @@ class AnnotationListView(APIView):
"""
List all annotations or create.
"""
permission_classes
=
(
AllowAny
,)
def
get
(
self
,
*
args
,
**
kwargs
):
# pylint: disable=unused-argument
"""
...
...
@@ -90,7 +87,6 @@ class AnnotationDetailView(APIView):
"""
Annotation detail view.
"""
permission_classes
=
(
AllowAny
,)
UPDATE_FILTER_FIELDS
=
(
'updated'
,
'created'
,
'user'
,
'consumer'
)
...
...
notesserver/settings/common.py
View file @
862d847c
...
...
@@ -4,12 +4,18 @@ import sys
DEBUG
=
False
TEMPLATE_DEBUG
=
False
DISABLE_TOKEN_CHECK
=
False
USE_TZ
=
True
TIME_ZONE
=
'UTC'
# This value needs to be overriden in production.
SECRET_KEY
=
'*^owi*4
%
!
%9
=#h@app!l^$jz8(c*q297^)4&4yn^#_m#fq=z#l'
# ID and Secret used for authenticating JWT Auth Tokens
# should match those configured for `edx-notes` Client in EdX's /admin/oauth2/client/
CLIENT_ID
=
'edx-notes-id'
CLIENT_SECRET
=
'edx-notes-secret'
ROOT_URLCONF
=
'notesserver.urls'
MIDDLEWARE_CLASSES
=
(
...
...
@@ -78,12 +84,17 @@ LOGGING = {
'level'
:
'DEBUG'
,
'propagate'
:
True
},
'notesapi.v1.permissions'
:
{
'handlers'
:
[
'console'
],
'level'
:
'DEBUG'
,
'propagate'
:
True
},
},
}
REST_FRAMEWORK
=
{
'DEFAULT_PERMISSION_CLASSES'
:
[
'
rest_framework.permissions.IsAuthenticated
'
'
notesapi.v1.permissions.HasAccessToken
'
]
}
...
...
notesserver/views.py
View file @
862d847c
...
...
@@ -16,11 +16,11 @@ def root(request): # pylint: disable=unused-argument
})
@permission_classes
([
AllowAny
])
class
StatusView
(
APIView
):
"""
Determine if server is alive.
"""
permission_classes
=
(
AllowAny
,)
def
get
(
self
,
*
args
,
**
kwargs
):
# pylint: disable=unused-argument
"""
...
...
requirements/base.txt
View file @
862d847c
...
...
@@ -5,3 +5,4 @@ django-rest-swagger==0.2.0
elasticsearch==1.2.0
annotator==0.12.0
django-cors-headers==0.13
PyJWT==0.3.0
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment