Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
D
django-rest-framework
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
django-rest-framework
Commits
37f7b76f
Commit
37f7b76f
authored
Jan 05, 2016
by
Tom Christie
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #3785 from sheppard/authtoken-import
don't import authtoken model until needed
parents
dceb6867
4f407141
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
50 additions
and
22 deletions
+50
-22
rest_framework/authentication.py
+11
-4
rest_framework/authtoken/models.py
+0
-8
tests/test_authentication.py
+39
-10
No files found.
rest_framework/authentication.py
View file @
37f7b76f
...
...
@@ -10,7 +10,6 @@ from django.middleware.csrf import CsrfViewMiddleware
from
django.utils.translation
import
ugettext_lazy
as
_
from
rest_framework
import
HTTP_HEADER_ENCODING
,
exceptions
from
rest_framework.authtoken.models
import
Token
def
get_authorization_header
(
request
):
...
...
@@ -149,7 +148,14 @@ class TokenAuthentication(BaseAuthentication):
Authorization: Token 401f7ac837da42b97f613d789819ff93537bee6a
"""
model
=
Token
model
=
None
def
get_model
(
self
):
if
self
.
model
is
not
None
:
return
self
.
model
from
rest_framework.authtoken.models
import
Token
return
Token
"""
A custom token model may be used, but must have the following properties.
...
...
@@ -179,9 +185,10 @@ class TokenAuthentication(BaseAuthentication):
return
self
.
authenticate_credentials
(
token
)
def
authenticate_credentials
(
self
,
key
):
model
=
self
.
get_model
()
try
:
token
=
self
.
model
.
objects
.
select_related
(
'user'
)
.
get
(
key
=
key
)
except
self
.
model
.
DoesNotExist
:
token
=
model
.
objects
.
select_related
(
'user'
)
.
get
(
key
=
key
)
except
model
.
DoesNotExist
:
raise
exceptions
.
AuthenticationFailed
(
_
(
'Invalid token.'
))
if
not
token
.
user
.
is_active
:
...
...
rest_framework/authtoken/models.py
View file @
37f7b76f
...
...
@@ -21,14 +21,6 @@ class Token(models.Model):
user
=
models
.
OneToOneField
(
AUTH_USER_MODEL
,
related_name
=
'auth_token'
)
created
=
models
.
DateTimeField
(
auto_now_add
=
True
)
class
Meta
:
# Work around for a bug in Django:
# https://code.djangoproject.com/ticket/19422
#
# Also see corresponding ticket:
# https://github.com/tomchristie/django-rest-framework/issues/705
abstract
=
'rest_framework.authtoken'
not
in
settings
.
INSTALLED_APPS
def
save
(
self
,
*
args
,
**
kwargs
):
if
not
self
.
key
:
self
.
key
=
self
.
generate_key
()
...
...
tests/test_authentication.py
View file @
37f7b76f
...
...
@@ -6,6 +6,7 @@ import base64
from
django.conf.urls
import
include
,
url
from
django.contrib.auth.models
import
User
from
django.db
import
models
from
django.http
import
HttpResponse
from
django.test
import
TestCase
from
django.utils
import
six
...
...
@@ -25,6 +26,15 @@ from rest_framework.views import APIView
factory
=
APIRequestFactory
()
class
CustomToken
(
models
.
Model
):
key
=
models
.
CharField
(
max_length
=
40
,
primary_key
=
True
)
user
=
models
.
OneToOneField
(
User
)
class
CustomTokenAuthentication
(
TokenAuthentication
):
model
=
CustomToken
class
MockView
(
APIView
):
permission_classes
=
(
permissions
.
IsAuthenticated
,)
...
...
@@ -42,6 +52,7 @@ urlpatterns = [
url
(
r'^session/$'
,
MockView
.
as_view
(
authentication_classes
=
[
SessionAuthentication
])),
url
(
r'^basic/$'
,
MockView
.
as_view
(
authentication_classes
=
[
BasicAuthentication
])),
url
(
r'^token/$'
,
MockView
.
as_view
(
authentication_classes
=
[
TokenAuthentication
])),
url
(
r'^customtoken/$'
,
MockView
.
as_view
(
authentication_classes
=
[
CustomTokenAuthentication
])),
url
(
r'^auth-token/$'
,
'rest_framework.authtoken.views.obtain_auth_token'
),
url
(
r'^auth/'
,
include
(
'rest_framework.urls'
,
namespace
=
'rest_framework'
)),
]
...
...
@@ -142,9 +153,11 @@ class SessionAuthTests(TestCase):
self
.
assertEqual
(
response
.
status_code
,
status
.
HTTP_403_FORBIDDEN
)
class
TokenAuthTests
(
TestCase
):
class
BaseTokenAuthTests
(
object
):
"""Token authentication"""
urls
=
'tests.test_authentication'
model
=
None
path
=
None
def
setUp
(
self
):
self
.
csrf_client
=
APIClient
(
enforce_csrf_checks
=
True
)
...
...
@@ -154,24 +167,30 @@ class TokenAuthTests(TestCase):
self
.
user
=
User
.
objects
.
create_user
(
self
.
username
,
self
.
email
,
self
.
password
)
self
.
key
=
'abcd1234'
self
.
token
=
Token
.
objects
.
create
(
key
=
self
.
key
,
user
=
self
.
user
)
self
.
token
=
self
.
model
.
objects
.
create
(
key
=
self
.
key
,
user
=
self
.
user
)
def
test_post_form_passing_token_auth
(
self
):
"""Ensure POSTing json over token auth with correct credentials passes and does not require CSRF"""
auth
=
'Token '
+
self
.
key
response
=
self
.
csrf_client
.
post
(
'/token/'
,
{
'example'
:
'example'
},
HTTP_AUTHORIZATION
=
auth
)
response
=
self
.
csrf_client
.
post
(
self
.
path
,
{
'example'
:
'example'
},
HTTP_AUTHORIZATION
=
auth
)
self
.
assertEqual
(
response
.
status_code
,
status
.
HTTP_200_OK
)
def
test_fail_post_form_passing_nonexistent_token_auth
(
self
):
# use a nonexistent token key
auth
=
'Token wxyz6789'
response
=
self
.
csrf_client
.
post
(
self
.
path
,
{
'example'
:
'example'
},
HTTP_AUTHORIZATION
=
auth
)
self
.
assertEqual
(
response
.
status_code
,
status
.
HTTP_401_UNAUTHORIZED
)
def
test_fail_post_form_passing_invalid_token_auth
(
self
):
# add an 'invalid' unicode character
auth
=
'Token '
+
self
.
key
+
"¸"
response
=
self
.
csrf_client
.
post
(
'/token/'
,
{
'example'
:
'example'
},
HTTP_AUTHORIZATION
=
auth
)
response
=
self
.
csrf_client
.
post
(
self
.
path
,
{
'example'
:
'example'
},
HTTP_AUTHORIZATION
=
auth
)
self
.
assertEqual
(
response
.
status_code
,
status
.
HTTP_401_UNAUTHORIZED
)
def
test_post_json_passing_token_auth
(
self
):
"""Ensure POSTing form over token auth with correct credentials passes and does not require CSRF"""
auth
=
"Token "
+
self
.
key
response
=
self
.
csrf_client
.
post
(
'/token/'
,
{
'example'
:
'example'
},
format
=
'json'
,
HTTP_AUTHORIZATION
=
auth
)
response
=
self
.
csrf_client
.
post
(
self
.
path
,
{
'example'
:
'example'
},
format
=
'json'
,
HTTP_AUTHORIZATION
=
auth
)
self
.
assertEqual
(
response
.
status_code
,
status
.
HTTP_200_OK
)
def
test_post_json_makes_one_db_query
(
self
):
...
...
@@ -179,29 +198,34 @@ class TokenAuthTests(TestCase):
auth
=
"Token "
+
self
.
key
def
func_to_test
():
return
self
.
csrf_client
.
post
(
'/token/'
,
{
'example'
:
'example'
},
format
=
'json'
,
HTTP_AUTHORIZATION
=
auth
)
return
self
.
csrf_client
.
post
(
self
.
path
,
{
'example'
:
'example'
},
format
=
'json'
,
HTTP_AUTHORIZATION
=
auth
)
self
.
assertNumQueries
(
1
,
func_to_test
)
def
test_post_form_failing_token_auth
(
self
):
"""Ensure POSTing form over token auth without correct credentials fails"""
response
=
self
.
csrf_client
.
post
(
'/token/'
,
{
'example'
:
'example'
})
response
=
self
.
csrf_client
.
post
(
self
.
path
,
{
'example'
:
'example'
})
self
.
assertEqual
(
response
.
status_code
,
status
.
HTTP_401_UNAUTHORIZED
)
def
test_post_json_failing_token_auth
(
self
):
"""Ensure POSTing json over token auth without correct credentials fails"""
response
=
self
.
csrf_client
.
post
(
'/token/'
,
{
'example'
:
'example'
},
format
=
'json'
)
response
=
self
.
csrf_client
.
post
(
self
.
path
,
{
'example'
:
'example'
},
format
=
'json'
)
self
.
assertEqual
(
response
.
status_code
,
status
.
HTTP_401_UNAUTHORIZED
)
class
TokenAuthTests
(
BaseTokenAuthTests
,
TestCase
):
model
=
Token
path
=
'/token/'
def
test_token_has_auto_assigned_key_if_none_provided
(
self
):
"""Ensure creating a token with no key will auto-assign a key"""
self
.
token
.
delete
()
token
=
Token
.
objects
.
create
(
user
=
self
.
user
)
token
=
self
.
model
.
objects
.
create
(
user
=
self
.
user
)
self
.
assertTrue
(
bool
(
token
.
key
))
def
test_generate_key_returns_string
(
self
):
"""Ensure generate_key returns a string"""
token
=
Token
()
token
=
self
.
model
()
key
=
token
.
generate_key
()
self
.
assertTrue
(
isinstance
(
key
,
six
.
string_types
))
...
...
@@ -236,6 +260,11 @@ class TokenAuthTests(TestCase):
self
.
assertEqual
(
response
.
data
[
'token'
],
self
.
key
)
class
CustomTokenAuthTests
(
BaseTokenAuthTests
,
TestCase
):
model
=
CustomToken
path
=
'/customtoken/'
class
IncorrectCredentialsTests
(
TestCase
):
def
test_incorrect_credentials
(
self
):
"""
...
...
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