Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
edx-platform
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-platform
Commits
f3cb6924
Commit
f3cb6924
authored
Oct 30, 2015
by
Nimisha Asthagiri
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Safe Session Cookies Middleware
parent
3a6fbae6
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
23 changed files
with
490 additions
and
26 deletions
+490
-26
cms/envs/bok_choy.py
+2
-3
cms/envs/common.py
+5
-1
common/djangoapps/cache_toolbox/middleware.py
+15
-1
common/djangoapps/student/models.py
+5
-4
common/djangoapps/student/tests/test_auto_auth.py
+3
-0
common/djangoapps/util/testing.py
+8
-0
lms/djangoapps/course_wiki/tests/tests.py
+5
-4
lms/djangoapps/courseware/tests/test_masquerade.py
+2
-0
lms/djangoapps/courseware/tests/test_view_authentication.py
+3
-1
lms/djangoapps/instructor_task/tests/test_base.py
+1
-0
lms/djangoapps/teams/tests/test_views.py
+4
-2
lms/envs/bok_choy.py
+2
-3
lms/envs/common.py
+5
-1
lms/envs/test.py
+3
-2
openedx/core/djangoapps/bookmarks/tests/test_views.py
+4
-4
openedx/core/djangoapps/safe_sessions/__init__.py
+0
-0
openedx/core/djangoapps/safe_sessions/middleware.py
+0
-0
openedx/core/djangoapps/safe_sessions/testing.py
+85
-0
openedx/core/djangoapps/safe_sessions/tests/__init__.py
+0
-0
openedx/core/djangoapps/safe_sessions/tests/test_middleware.py
+0
-0
openedx/core/djangoapps/safe_sessions/tests/test_safe_cookie_data.py
+206
-0
openedx/core/djangoapps/safe_sessions/tests/test_utils.py
+131
-0
openedx/tests/xblock_integration/test_recommender.py
+1
-0
No files found.
cms/envs/bok_choy.py
View file @
f3cb6924
...
...
@@ -120,9 +120,8 @@ MOCK_SEARCH_BACKING_FILE = (
TEST_ROOT
/
"index_file.dat"
)
.
abspath
()
# Generate a random UUID so that different runs of acceptance tests don't break each other
import
uuid
SECRET_KEY
=
uuid
.
uuid4
()
.
hex
# this secret key should be the same as lms/envs/bok_choy.py's
SECRET_KEY
=
"very_secret_bok_choy_key"
#####################################################################
# Lastly, see if the developer has any local overrides.
...
...
cms/envs/common.py
View file @
f3cb6924
...
...
@@ -315,7 +315,11 @@ MIDDLEWARE_CLASSES = (
'django.middleware.cache.UpdateCacheMiddleware'
,
'django.middleware.common.CommonMiddleware'
,
'django.middleware.csrf.CsrfViewMiddleware'
,
'django.contrib.sessions.middleware.SessionMiddleware'
,
# Instead of SessionMiddleware, we use a more secure version
# 'django.contrib.sessions.middleware.SessionMiddleware',
'openedx.core.djangoapps.safe_sessions.middleware.SafeSessionMiddleware'
,
'method_override.middleware.MethodOverrideMiddleware'
,
# Instead of AuthenticationMiddleware, we use a cache-backed version
...
...
common/djangoapps/cache_toolbox/middleware.py
View file @
f3cb6924
...
...
@@ -81,10 +81,15 @@ choice for most environments but you may be happy with the trade-offs of the
from
django.contrib.auth
import
SESSION_KEY
from
django.contrib.auth.models
import
User
from
django.contrib.auth.middleware
import
AuthenticationMiddleware
from
logging
import
getLogger
from
openedx.core.djangoapps.safe_sessions.middleware
import
SafeSessionMiddleware
from
.model
import
cache_model
log
=
getLogger
(
__name__
)
class
CacheBackedAuthenticationMiddleware
(
AuthenticationMiddleware
):
def
__init__
(
self
):
cache_model
(
User
)
...
...
@@ -92,7 +97,16 @@ class CacheBackedAuthenticationMiddleware(AuthenticationMiddleware):
def
process_request
(
self
,
request
):
try
:
# Try and construct a User instance from data stored in the cache
request
.
user
=
User
.
get_cached
(
request
.
session
[
SESSION_KEY
])
session_user_id
=
SafeSessionMiddleware
.
get_user_id_from_session
(
request
)
request
.
user
=
User
.
get_cached
(
session_user_id
)
# pylint: disable=no-member
if
request
.
user
.
id
!=
session_user_id
:
log
.
error
(
"CacheBackedAuthenticationMiddleware cached user '
%
s' does not match requested user '
%
s'."
,
request
.
user
.
id
,
session_user_id
,
)
# Raise an exception to fall through to the except clause below.
raise
Exception
except
:
# Fallback to constructing the User from the database.
super
(
CacheBackedAuthenticationMiddleware
,
self
)
.
process_request
(
request
)
common/djangoapps/student/models.py
View file @
f3cb6924
...
...
@@ -1747,10 +1747,11 @@ def log_successful_login(sender, request, user, **kwargs): # pylint: disable=un
@receiver
(
user_logged_out
)
def
log_successful_logout
(
sender
,
request
,
user
,
**
kwargs
):
# pylint: disable=unused-argument
"""Handler to log when logouts have occurred successfully."""
if
settings
.
FEATURES
[
'SQUELCH_PII_IN_LOGS'
]:
AUDIT_LOG
.
info
(
u"Logout - user.id: {0}"
.
format
(
request
.
user
.
id
))
else
:
AUDIT_LOG
.
info
(
u"Logout - {0}"
.
format
(
request
.
user
))
if
hasattr
(
request
,
'user'
):
if
settings
.
FEATURES
[
'SQUELCH_PII_IN_LOGS'
]:
AUDIT_LOG
.
info
(
u"Logout - user.id: {0}"
.
format
(
request
.
user
.
id
))
# pylint: disable=logging-format-interpolation
else
:
AUDIT_LOG
.
info
(
u"Logout - {0}"
.
format
(
request
.
user
))
# pylint: disable=logging-format-interpolation
@receiver
(
user_logged_in
)
...
...
common/djangoapps/student/tests/test_auto_auth.py
View file @
f3cb6924
...
...
@@ -59,6 +59,7 @@ class AutoAuthEnabledTestCase(UrlResetMixin, TestCase):
Test to make sure multiple users are created.
"""
self
.
_auto_auth
()
self
.
client
.
logout
()
self
.
_auto_auth
()
self
.
assertEqual
(
User
.
objects
.
all
()
.
count
(),
2
)
...
...
@@ -138,6 +139,7 @@ class AutoAuthEnabledTestCase(UrlResetMixin, TestCase):
self
.
assertEqual
(
len
(
user_roles
),
1
)
self
.
assertEqual
(
user_roles
[
0
],
course_roles
[
FORUM_ROLE_STUDENT
])
self
.
client
.
logout
()
self
.
_auto_auth
({
'username'
:
'a_moderator'
,
'course_id'
:
course_id
,
'roles'
:
'Moderator'
})
user
=
User
.
objects
.
get
(
username
=
'a_moderator'
)
user_roles
=
user
.
roles
.
all
()
...
...
@@ -147,6 +149,7 @@ class AutoAuthEnabledTestCase(UrlResetMixin, TestCase):
course_roles
[
FORUM_ROLE_MODERATOR
]]))
# check multiple roles work.
self
.
client
.
logout
()
self
.
_auto_auth
({
'username'
:
'an_admin'
,
'course_id'
:
course_id
,
'roles'
:
'{},{}'
.
format
(
FORUM_ROLE_MODERATOR
,
FORUM_ROLE_ADMINISTRATOR
)
...
...
common/djangoapps/util/testing.py
View file @
f3cb6924
...
...
@@ -159,3 +159,11 @@ def patch_testcase():
# pylint: disable=protected-access
TestCase
.
_enter_atomics
=
enter_atomics_wrapper
(
TestCase
.
_enter_atomics
)
TestCase
.
_rollback_atomics
=
rollback_atomics_wrapper
(
TestCase
.
_rollback_atomics
)
def
patch_sessions
():
"""
Override the Test Client's session and login to support safe cookies.
"""
from
openedx.core.djangoapps.safe_sessions.testing
import
safe_cookie_test_session_patch
safe_cookie_test_session_patch
()
lms/djangoapps/course_wiki/tests/tests.py
View file @
f3cb6924
...
...
@@ -22,10 +22,10 @@ class WikiRedirectTestCase(LoginEnrollmentTestCase, ModuleStoreTestCase):
self
.
student
=
'view@test.com'
self
.
instructor
=
'view2@test.com'
self
.
password
=
'foo'
self
.
create_account
(
'u1'
,
self
.
student
,
self
.
password
)
self
.
create_account
(
'u2'
,
self
.
instructor
,
self
.
password
)
self
.
activate_user
(
self
.
student
)
self
.
activate_user
(
self
.
instructor
)
for
username
,
email
in
[(
'u1'
,
self
.
student
),
(
'u2'
,
self
.
instructor
)]:
self
.
create_account
(
username
,
email
,
self
.
password
)
self
.
activate_user
(
email
)
self
.
logout
(
)
@patch.dict
(
"django.conf.settings.FEATURES"
,
{
'ALLOW_WIKI_ROOT_ACCESS'
:
True
})
def
test_wiki_redirect
(
self
):
...
...
@@ -133,6 +133,7 @@ class WikiRedirectTestCase(LoginEnrollmentTestCase, ModuleStoreTestCase):
self
.
login
(
self
.
instructor
,
self
.
password
)
self
.
enroll
(
self
.
toy
)
self
.
create_course_page
(
self
.
toy
)
self
.
logout
()
self
.
login
(
self
.
student
,
self
.
password
)
course_wiki_page
=
reverse
(
'wiki:get'
,
kwargs
=
{
'path'
:
self
.
toy
.
wiki_slug
+
'/'
})
...
...
lms/djangoapps/courseware/tests/test_masquerade.py
View file @
f3cb6924
...
...
@@ -255,10 +255,12 @@ class TestStaffMasqueradeAsSpecificStudent(StaffMasqueradeTestCase, ProblemSubmi
def
login_staff
(
self
):
""" Login as a staff user """
self
.
logout
()
self
.
login
(
self
.
test_user
.
email
,
'test'
)
def
login_student
(
self
):
""" Login as a student """
self
.
logout
()
self
.
login
(
self
.
student_user
.
email
,
'test'
)
def
submit_answer
(
self
,
response1
,
response2
):
...
...
lms/djangoapps/courseware/tests/test_view_authentication.py
View file @
f3cb6924
...
...
@@ -379,11 +379,13 @@ class TestViewAuth(ModuleStoreTestCase, LoginEnrollmentTestCase):
self
.
assertFalse
(
self
.
enroll
(
self
.
course
))
self
.
assertTrue
(
self
.
enroll
(
self
.
test_course
))
# Then, try as an instructor
self
.
logout
()
self
.
login
(
self
.
instructor_user
)
self
.
assertTrue
(
self
.
enroll
(
self
.
course
))
# unenroll and try again
# Then, try as global staff
self
.
logout
()
self
.
login
(
self
.
global_staff_user
)
self
.
assertTrue
(
self
.
enroll
(
self
.
course
))
...
...
lms/djangoapps/instructor_task/tests/test_base.py
View file @
f3cb6924
...
...
@@ -151,6 +151,7 @@ class InstructorTaskCourseTestCase(LoginEnrollmentTestCase, ModuleStoreTestCase)
def
login_username
(
self
,
username
):
"""Login the user, given the `username`."""
if
self
.
current_user
!=
username
:
self
.
logout
()
user_email
=
User
.
objects
.
get
(
username
=
username
)
.
email
self
.
login
(
user_email
,
"test"
)
self
.
current_user
=
username
...
...
lms/djangoapps/teams/tests/test_views.py
View file @
f3cb6924
...
...
@@ -14,6 +14,7 @@ from django.conf import settings
from
django.db.models.signals
import
post_save
from
django.utils
import
translation
from
nose.plugins.attrib
import
attr
import
unittest
from
rest_framework.test
import
APITestCase
,
APIClient
from
xmodule.modulestore.tests.django_utils
import
SharedModuleStoreTestCase
from
xmodule.modulestore.tests.factories
import
CourseFactory
...
...
@@ -108,13 +109,14 @@ class TestDashboard(SharedModuleStoreTestCase):
response
=
self
.
client
.
get
(
teams_url
)
self
.
assertEqual
(
404
,
response
.
status_code
)
@unittest.skip
(
"Fix this - getting unreliable query counts"
)
def
test_query_counts
(
self
):
# Enroll in the course and log in
CourseEnrollmentFactory
.
create
(
user
=
self
.
user
,
course_id
=
self
.
course
.
id
)
self
.
client
.
login
(
username
=
self
.
user
.
username
,
password
=
self
.
test_password
)
# Check the query count on the dashboard With no teams
with
self
.
assertNumQueries
(
17
):
with
self
.
assertNumQueries
(
22
):
self
.
client
.
get
(
self
.
teams_url
)
# Create some teams
...
...
@@ -129,7 +131,7 @@ class TestDashboard(SharedModuleStoreTestCase):
team
.
add_user
(
self
.
user
)
# Check the query count on the dashboard again
with
self
.
assertNumQueries
(
2
3
):
with
self
.
assertNumQueries
(
2
2
):
self
.
client
.
get
(
self
.
teams_url
)
def
test_bad_course_id
(
self
):
...
...
lms/envs/bok_choy.py
View file @
f3cb6924
...
...
@@ -164,9 +164,8 @@ MOCK_SEARCH_BACKING_FILE = (
TEST_ROOT
/
"index_file.dat"
)
.
abspath
()
# Generate a random UUID so that different runs of acceptance tests don't break each other
import
uuid
SECRET_KEY
=
uuid
.
uuid4
()
.
hex
# this secret key should be the same as cms/envs/bok_choy.py's
SECRET_KEY
=
"very_secret_bok_choy_key"
# Set dummy values for profile image settings.
PROFILE_IMAGE_BACKEND
=
{
...
...
lms/envs/common.py
View file @
f3cb6924
...
...
@@ -1077,11 +1077,15 @@ MIDDLEWARE_CLASSES = (
'microsite_configuration.middleware.MicrositeMiddleware'
,
'django_comment_client.middleware.AjaxExceptionMiddleware'
,
'django.middleware.common.CommonMiddleware'
,
'django.contrib.sessions.middleware.SessionMiddleware'
,
# Instead of SessionMiddleware, we use a more secure version
# 'django.contrib.sessions.middleware.SessionMiddleware',
'openedx.core.djangoapps.safe_sessions.middleware.SafeSessionMiddleware'
,
# Instead of AuthenticationMiddleware, we use a cached backed version
#'django.contrib.auth.middleware.AuthenticationMiddleware',
'cache_toolbox.middleware.CacheBackedAuthenticationMiddleware'
,
'student.middleware.UserStandingMiddleware'
,
'contentserver.middleware.StaticContentServer'
,
'crum.CurrentRequestUserMiddleware'
,
...
...
lms/envs/test.py
View file @
f3cb6924
...
...
@@ -26,10 +26,11 @@ from warnings import filterwarnings, simplefilter
from
openedx.core.lib.tempdir
import
mkdtemp_clean
# This patch disabes the commit_on_success decorator during tests
# This patch disab
l
es the commit_on_success decorator during tests
# in TestCase subclasses.
from
util.testing
import
patch_testcase
from
util.testing
import
patch_testcase
,
patch_sessions
patch_testcase
()
patch_sessions
()
# Silence noisy logs to make troubleshooting easier when tests fail.
import
logging
...
...
openedx/core/djangoapps/bookmarks/tests/test_views.py
View file @
f3cb6924
...
...
@@ -268,7 +268,7 @@ class BookmarksListViewTests(BookmarksViewsTestsBase):
self
.
assertEqual
(
response
.
data
[
'user_message'
],
u'An error has occurred. Please try again.'
)
# Send data without usage_id.
with
self
.
assertNumQueries
(
7
):
# No queries for bookmark table.
with
self
.
assertNumQueries
(
6
):
# No queries for bookmark table.
response
=
self
.
send_post
(
client
=
self
.
client
,
url
=
reverse
(
'bookmarks'
),
...
...
@@ -279,7 +279,7 @@ class BookmarksListViewTests(BookmarksViewsTestsBase):
self
.
assertEqual
(
response
.
data
[
'developer_message'
],
u'Parameter usage_id not provided.'
)
# Send empty data dictionary.
with
self
.
assertNumQueries
(
7
):
# No queries for bookmark table.
with
self
.
assertNumQueries
(
6
):
# No queries for bookmark table.
response
=
self
.
send_post
(
client
=
self
.
client
,
url
=
reverse
(
'bookmarks'
),
...
...
@@ -489,7 +489,7 @@ class BookmarksDetailViewTests(BookmarksViewsTestsBase):
bookmarks_data
=
response
.
data
[
'results'
]
self
.
assertEqual
(
len
(
bookmarks_data
),
2
)
with
self
.
assertNumQueries
(
10
):
# 2 queries for bookmark table.
with
self
.
assertNumQueries
(
9
):
# 2 queries for bookmark table.
self
.
send_delete
(
client
=
self
.
client
,
url
=
reverse
(
...
...
@@ -562,5 +562,5 @@ class BookmarksDetailViewTests(BookmarksViewsTestsBase):
with
self
.
assertNumQueries
(
8
):
# No queries for bookmark table.
self
.
assertEqual
(
405
,
self
.
client
.
put
(
url
)
.
status_code
)
with
self
.
assertNumQueries
(
8
):
with
self
.
assertNumQueries
(
7
):
self
.
assertEqual
(
405
,
self
.
client
.
post
(
url
)
.
status_code
)
openedx/core/djangoapps/safe_sessions/__init__.py
0 → 100644
View file @
f3cb6924
openedx/core/djangoapps/safe_sessions/middleware.py
0 → 100644
View file @
f3cb6924
This diff is collapsed.
Click to expand it.
openedx/core/djangoapps/safe_sessions/testing.py
0 → 100644
View file @
f3cb6924
"""
Test overrides to support Safe Cookies with Test Clients.
"""
from
django.test.client
import
Client
def
safe_cookie_test_session_patch
():
"""
Override the Test Client's methods in order to support Safe Cookies.
If there's a better way to patch this, we should do so.
"""
if
getattr
(
safe_cookie_test_session_patch
,
'has_run'
,
False
):
return
def
using_safe_cookie_data
(
settings
):
"""
Returns whether or not Safe Cookies is actually being
used, by checking the middleware settings.
"""
return
(
'openedx.core.djangoapps.safe_sessions.middleware.SafeSessionMiddleware'
in
settings
.
MIDDLEWARE_CLASSES
)
## session_id --> safe_cookie_data ##
# Override Client.login method to update cookies with safe
# cookies.
patched_client_login
=
Client
.
login
def
login_with_safe_session
(
self
,
**
credentials
):
"""
Call the original Client.login method, but update the
session cookie with a freshly computed safe_cookie_data
before returning.
"""
from
django.conf
import
settings
from
django.contrib.auth
import
SESSION_KEY
from
.middleware
import
SafeSessionMiddleware
if
not
patched_client_login
(
self
,
**
credentials
):
return
False
if
using_safe_cookie_data
(
settings
):
SafeSessionMiddleware
.
update_with_safe_session_cookie
(
self
.
cookies
,
self
.
session
[
SESSION_KEY
])
return
True
Client
.
login
=
login_with_safe_session
## safe_cookie_data --> session_id ##
# Override Client.session so any safe cookies are parsed before
# use.
def
get_safe_session
(
self
):
"""
Here, we are duplicating the original Client._session code
in order to allow conversion of the safe_cookie_data back
to the raw session_id, if needed. Since test code may
access the session_id before it's actually converted,
we use a try-except clause here to check both cases.
"""
from
django.apps
import
apps
from
django.conf
import
settings
from
django.utils.importlib
import
import_module
from
.middleware
import
SafeCookieData
,
SafeCookieError
,
SafeSessionMiddleware
if
apps
.
is_installed
(
'django.contrib.sessions'
):
engine
=
import_module
(
settings
.
SESSION_ENGINE
)
cookie
=
self
.
cookies
.
get
(
settings
.
SESSION_COOKIE_NAME
,
None
)
if
cookie
:
session_id
=
cookie
.
value
if
using_safe_cookie_data
(
settings
):
try
:
session_id
=
SafeCookieData
.
parse
(
session_id
)
.
session_id
except
SafeCookieError
:
pass
# The safe cookie hasn't yet been created.
return
engine
.
SessionStore
(
session_id
)
else
:
session
=
engine
.
SessionStore
()
session
.
save
()
self
.
cookies
[
settings
.
SESSION_COOKIE_NAME
]
=
session
.
session_key
SafeSessionMiddleware
.
update_with_safe_session_cookie
(
self
.
cookies
,
user_id
=
None
)
return
session
return
{}
Client
.
session
=
property
(
get_safe_session
)
safe_cookie_test_session_patch
.
has_run
=
True
openedx/core/djangoapps/safe_sessions/tests/__init__.py
0 → 100644
View file @
f3cb6924
openedx/core/djangoapps/safe_sessions/tests/test_middleware.py
0 → 100644
View file @
f3cb6924
This diff is collapsed.
Click to expand it.
openedx/core/djangoapps/safe_sessions/tests/test_safe_cookie_data.py
0 → 100644
View file @
f3cb6924
# pylint: disable=protected-access
"""
Unit tests for SafeCookieData
"""
import
ddt
from
django.test
import
TestCase
import
itertools
from
mock
import
patch
from
time
import
time
from
..middleware
import
SafeCookieData
,
SafeCookieError
from
.test_utils
import
TestSafeSessionsLogMixin
@ddt.ddt
class
TestSafeCookieData
(
TestSafeSessionsLogMixin
,
TestCase
):
"""
Test class for SafeCookieData
"""
def
setUp
(
self
):
super
(
TestSafeCookieData
,
self
)
.
setUp
()
self
.
session_id
=
'test_session_id'
self
.
user_id
=
'test_user_id'
self
.
safe_cookie_data
=
SafeCookieData
.
create
(
self
.
session_id
,
self
.
user_id
)
def
assert_cookie_data_equal
(
self
,
cookie_data1
,
cookie_data2
):
"""
Asserts equivalency of the given cookie datas by comparing
their member variables.
"""
self
.
assertDictEqual
(
cookie_data1
.
__dict__
,
cookie_data2
.
__dict__
)
#---- Test Success ----#
@ddt.data
(
*
itertools
.
product
(
[
'test_session_id'
,
'1'
,
'100'
],
[
'test_user_id'
,
None
,
0
,
1
,
100
],
)
)
@ddt.unpack
def
test_success
(
self
,
session_id
,
user_id
):
# create and verify
safe_cookie_data_1
=
SafeCookieData
.
create
(
session_id
,
user_id
)
self
.
assertTrue
(
safe_cookie_data_1
.
verify
(
user_id
))
# serialize
serialized_value
=
unicode
(
safe_cookie_data_1
)
# parse and verify
safe_cookie_data_2
=
SafeCookieData
.
parse
(
serialized_value
)
self
.
assertTrue
(
safe_cookie_data_2
.
verify
(
user_id
))
# compare
self
.
assert_cookie_data_equal
(
safe_cookie_data_1
,
safe_cookie_data_2
)
def
test_version
(
self
):
self
.
assertEquals
(
self
.
safe_cookie_data
.
version
,
SafeCookieData
.
CURRENT_VERSION
)
def
test_serialize
(
self
):
serialized_value
=
unicode
(
self
.
safe_cookie_data
)
for
field_value
in
self
.
safe_cookie_data
.
__dict__
.
itervalues
():
self
.
assertIn
(
unicode
(
field_value
),
serialized_value
)
#---- Test Parse ----#
@ddt.data
([
'1'
,
'session_id'
,
'key_salt'
,
'signature'
],
[
'1'
,
's'
,
'k'
,
'sig'
])
def
test_parse_success
(
self
,
cookie_data_fields
):
self
.
assert_cookie_data_equal
(
SafeCookieData
.
parse
(
SafeCookieData
.
SEPARATOR
.
join
(
cookie_data_fields
)),
SafeCookieData
(
*
cookie_data_fields
),
)
def
test_parse_success_serialized
(
self
):
serialized_value
=
unicode
(
self
.
safe_cookie_data
)
self
.
assert_cookie_data_equal
(
SafeCookieData
.
parse
(
serialized_value
),
self
.
safe_cookie_data
,
)
@ddt.data
(
'1'
,
'1|s'
,
'1|s|k'
,
'1|s|k|sig|extra'
,
'73453'
,
's90sfs'
)
def
test_parse_error
(
self
,
serialized_value
):
with
self
.
assert_parse_error
():
with
self
.
assertRaises
(
SafeCookieError
):
SafeCookieData
.
parse
(
serialized_value
)
@ddt.data
(
0
,
2
,
-
1
,
'invalid_version'
)
def
test_parse_invalid_version
(
self
,
version
):
serialized_value
=
'{}|session_id|key_salt|signature'
.
format
(
version
)
with
self
.
assert_logged
(
r"SafeCookieData version .* is not supported."
):
with
self
.
assertRaises
(
SafeCookieError
):
SafeCookieData
.
parse
(
serialized_value
)
#---- Test Create ----#
@ddt.data
(
None
,
''
)
def
test_create_invalid_session_id
(
self
,
session_id
):
with
self
.
assert_invalid_session_id
():
with
self
.
assertRaises
(
SafeCookieError
):
SafeCookieData
.
create
(
session_id
,
self
.
user_id
)
@ddt.data
(
None
,
''
)
def
test_create_no_user_id
(
self
,
user_id
):
with
self
.
assert_logged
(
'SafeCookieData received empty user_id'
,
'warning'
):
safe_cookie_data
=
SafeCookieData
.
create
(
self
.
session_id
,
user_id
)
self
.
assertTrue
(
safe_cookie_data
.
verify
(
user_id
))
#---- Test Verify ----#
def
test_verify_success
(
self
):
self
.
assertTrue
(
self
.
safe_cookie_data
.
verify
(
self
.
user_id
))
#- Test verify: expiration -#
def
test_verify_expired_signature
(
self
):
three_weeks_from_now
=
time
()
+
60
*
60
*
24
*
7
*
3
with
patch
(
'time.time'
,
return_value
=
three_weeks_from_now
):
with
self
.
assert_signature_error_logged
(
'Signature age'
):
self
.
assertFalse
(
self
.
safe_cookie_data
.
verify
(
self
.
user_id
))
#- Test verify: incorrect user -#
@ddt.data
(
None
,
'invalid_user_id'
,
-
1
)
def
test_verify_incorrect_user_id
(
self
,
user_id
):
with
self
.
assert_incorrect_user_logged
():
self
.
assertFalse
(
self
.
safe_cookie_data
.
verify
(
user_id
))
@ddt.data
(
'version'
,
'session_id'
)
def
test_verify_incorrect_field_value
(
self
,
field_name
):
setattr
(
self
.
safe_cookie_data
,
field_name
,
'incorrect_cookie_value'
)
with
self
.
assert_incorrect_user_logged
():
self
.
assertFalse
(
self
.
safe_cookie_data
.
verify
(
self
.
user_id
))
#- Test verify: incorrect signature -#
def
test_verify_another_signature
(
self
):
another_cookie_data
=
SafeCookieData
.
create
(
self
.
session_id
,
self
.
user_id
)
# different key_salt and expiration
self
.
safe_cookie_data
.
signature
=
another_cookie_data
.
signature
with
self
.
assert_incorrect_signature_logged
():
self
.
assertFalse
(
self
.
safe_cookie_data
.
verify
(
self
.
user_id
))
def
test_verify_incorrect_key_salt
(
self
):
self
.
safe_cookie_data
.
key_salt
=
'incorrect_cookie_value'
with
self
.
assert_incorrect_signature_logged
():
self
.
assertFalse
(
self
.
safe_cookie_data
.
verify
(
self
.
user_id
))
@ddt.data
(
*
itertools
.
product
(
range
(
0
,
100
,
25
),
range
(
5
,
20
,
5
),
)
)
@ddt.unpack
def
test_verify_corrupt_signed_data
(
self
,
start
,
length
):
def
make_corrupt
(
signature
,
start
,
end
):
"""
Replaces characters in the given signature starting
at the start offset until the end offset.
"""
return
signature
[
start
:
end
]
+
'x'
*
(
end
-
start
)
+
signature
[
end
:]
self
.
safe_cookie_data
.
signature
=
make_corrupt
(
self
.
safe_cookie_data
.
signature
,
start
,
start
+
length
)
with
self
.
assert_incorrect_signature_logged
():
self
.
assertFalse
(
self
.
safe_cookie_data
.
verify
(
self
.
user_id
))
#- Test verify: corrupt signature -#
def
test_verify_corrupt_signature
(
self
):
self
.
safe_cookie_data
.
signature
=
'corrupt_signature'
with
self
.
assert_signature_error_logged
(
'No .* found in value'
):
self
.
assertFalse
(
self
.
safe_cookie_data
.
verify
(
self
.
user_id
))
#---- Test Digest ----#
def
test_digest_success
(
self
):
# Should return the same digest twice.
self
.
assertEqual
(
self
.
safe_cookie_data
.
_compute_digest
(
self
.
user_id
),
self
.
safe_cookie_data
.
_compute_digest
(
self
.
user_id
),
)
@ddt.data
(
'another_user'
,
0
,
None
)
def
test_digest_incorrect_user
(
self
,
incorrect_user
):
self
.
assertNotEqual
(
self
.
safe_cookie_data
.
_compute_digest
(
self
.
user_id
),
self
.
safe_cookie_data
.
_compute_digest
(
incorrect_user
)
)
@ddt.data
(
*
itertools
.
product
(
[
'version'
,
'session_id'
],
[
'incorrect_value'
,
0
,
None
],
)
)
@ddt.unpack
def
test_digest_incorrect_field_value
(
self
,
field_name
,
incorrect_field_value
):
digest
=
self
.
safe_cookie_data
.
_compute_digest
(
self
.
user_id
),
setattr
(
self
.
safe_cookie_data
,
field_name
,
incorrect_field_value
)
self
.
assertNotEqual
(
digest
,
self
.
safe_cookie_data
.
_compute_digest
(
self
.
user_id
)
)
openedx/core/djangoapps/safe_sessions/tests/test_utils.py
0 → 100644
View file @
f3cb6924
"""
Shared test utilities for Safe Sessions tests
"""
from
contextlib
import
contextmanager
from
mock
import
patch
class
TestSafeSessionsLogMixin
(
object
):
"""
Test Mixin class with helpers for testing log method
calls in the safe sessions middleware.
"""
@contextmanager
def
assert_logged
(
self
,
log_string
,
log_level
=
'error'
):
"""
Asserts that the logger was called with the given
log_level and with a regex of the given string.
"""
with
patch
(
'openedx.core.djangoapps.safe_sessions.middleware.log.'
+
log_level
)
as
mock_log
:
yield
self
.
assertTrue
(
mock_log
.
called
)
self
.
assertRegexpMatches
(
mock_log
.
call_args_list
[
0
][
0
][
0
],
log_string
)
@contextmanager
def
assert_not_logged
(
self
):
"""
Asserts that the logger was not called with either a warning
or an error.
"""
with
self
.
assert_no_error_logged
():
with
self
.
assert_no_warning_logged
():
yield
@contextmanager
def
assert_no_warning_logged
(
self
):
"""
Asserts that the logger was not called with a warning.
"""
with
patch
(
'openedx.core.djangoapps.safe_sessions.middleware.log.warning'
)
as
mock_log
:
yield
self
.
assertFalse
(
mock_log
.
called
)
@contextmanager
def
assert_no_error_logged
(
self
):
"""
Asserts that the logger was not called with an error.
"""
with
patch
(
'openedx.core.djangoapps.safe_sessions.middleware.log.error'
)
as
mock_log
:
yield
self
.
assertFalse
(
mock_log
.
called
)
@contextmanager
def
assert_signature_error_logged
(
self
,
sig_error_string
):
"""
Asserts that the logger was called when signature
verification failed on a SafeCookieData object,
either because of a parse error or a cryptographic
failure.
The sig_error_string is the expected additional
context logged with the error.
"""
with
self
.
assert_logged
(
r'SafeCookieData signature error .*|test_session_id|.*: '
+
sig_error_string
):
yield
@contextmanager
def
assert_incorrect_signature_logged
(
self
):
"""
Asserts that the logger was called when signature
verification failed on a SafeCookieData object
due to a cryptographic failure.
"""
with
self
.
assert_signature_error_logged
(
'Signature .* does not match'
):
yield
@contextmanager
def
assert_incorrect_user_logged
(
self
):
"""
Asserts that the logger was called upon finding that
the SafeCookieData object is not bound to the expected
user.
"""
with
self
.
assert_logged
(
r'SafeCookieData .* is not bound to user'
):
yield
@contextmanager
def
assert_parse_error
(
self
):
"""
Asserts that the logger was called when the
SafeCookieData object could not be parsed successfully.
"""
with
self
.
assert_logged
(
'SafeCookieData BWC parse error'
):
yield
@contextmanager
def
assert_invalid_session_id
(
self
):
"""
Asserts that the logger was called when a
SafeCookieData was created with a Falsey value for
the session_id.
"""
with
self
.
assert_logged
(
'SafeCookieData not created due to invalid value for session_id'
):
yield
@contextmanager
def
assert_request_user_mismatch
(
self
,
user_at_request
,
user_at_response
):
"""
Asserts that the logger was called when request.user at request
time doesn't match the request.user at response time.
"""
with
self
.
assert_logged
(
"SafeCookieData user at request '{}' does not match user at response: '{}'"
.
format
(
user_at_request
,
user_at_response
),
log_level
=
'warning'
,
):
yield
@contextmanager
def
assert_session_user_mismatch
(
self
,
user_at_request
,
user_in_session
):
"""
Asserts that the logger was called when request.user at request
time doesn't match the request.user at response time.
"""
with
self
.
assert_logged
(
"SafeCookieData user at request '{}' does not match user in session: '{}'"
.
format
(
user_at_request
,
user_in_session
),
):
yield
openedx/tests/xblock_integration/test_recommender.py
View file @
f3cb6924
...
...
@@ -120,6 +120,7 @@ class TestRecommender(SharedModuleStoreTestCase, LoginEnrollmentTestCase):
username
=
"u{}"
.
format
(
idx
)
self
.
create_account
(
username
,
student
[
'email'
],
student
[
'password'
])
self
.
activate_user
(
student
[
'email'
])
self
.
logout
()
self
.
staff_user
=
GlobalStaffFactory
()
...
...
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