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
7c070f29
Commit
7c070f29
authored
Dec 18, 2013
by
Oleg Marshev
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add better messaging, turn off SSL verification when sending grade back.
parent
e24ddaa3
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
40 additions
and
33 deletions
+40
-33
common/lib/xmodule/xmodule/lti_module.py
+12
-13
common/lib/xmodule/xmodule/tests/test_lti_unit.py
+8
-6
lms/djangoapps/courseware/features/lti_setup.py
+2
-3
lms/djangoapps/courseware/mock_lti_server/mock_lti_server.py
+12
-8
lms/djangoapps/courseware/mock_lti_server/server_start.py
+3
-3
lms/djangoapps/courseware/mock_lti_server/test_mock_lti_server.py
+3
-0
No files found.
common/lib/xmodule/xmodule/lti_module.py
View file @
7c070f29
...
...
@@ -486,23 +486,26 @@ oauth_consumer_key="", oauth_signature="frVp4JuvT1mVXlxktiAUjQ7%2F1cw%3D"'}
try
:
imsx_messageIdentifier
,
sourcedId
,
score
,
action
=
self
.
parse_grade_xml_body
(
request
.
body
)
except
Exception
:
log
.
debug
(
"[LTI]: Request body XML parsing error."
)
failure_values
[
'imsx_description'
]
=
'Request body XML parsing error.'
except
Exception
as
e
:
error_message
=
"Request body XML parsing error: "
+
escape
(
e
.
message
)
log
.
debug
(
"[LTI]: "
+
error_message
)
failure_values
[
'imsx_description'
]
=
error_message
return
Response
(
response_xml_template
.
format
(
**
failure_values
),
content_type
=
"application/xml"
)
# Verify OAuth signing.
try
:
self
.
verify_oauth_body_sign
(
request
)
except
(
ValueError
,
LTIError
):
except
(
ValueError
,
LTIError
)
as
e
:
failure_values
[
'imsx_messageIdentifier'
]
=
escape
(
imsx_messageIdentifier
)
failure_values
[
'imsx_description'
]
=
'OAuth verification error.'
error_message
=
"OAuth verification error: "
+
escape
(
e
.
message
)
failure_values
[
'imsx_description'
]
=
error_message
log
.
debug
(
"[LTI]: "
+
error_message
)
return
Response
(
response_xml_template
.
format
(
**
failure_values
),
content_type
=
"application/xml"
)
real_user
=
self
.
system
.
get_real_user
(
urllib
.
unquote
(
sourcedId
.
split
(
':'
)[
-
1
]))
if
not
real_user
:
# that means we can't save to database, as we do not have real user id.
failure_values
[
'imsx_messageIdentifier'
]
=
escape
(
imsx_messageIdentifier
)
failure_values
[
'imsx_description'
]
=
'User not found.'
failure_values
[
'imsx_description'
]
=
"User not found."
return
Response
(
response_xml_template
.
format
(
**
failure_values
),
content_type
=
"application/xml"
)
if
action
==
'replaceResultRequest'
:
...
...
@@ -554,8 +557,7 @@ oauth_consumer_key="", oauth_signature="frVp4JuvT1mVXlxktiAUjQ7%2F1cw%3D"'}
# Raise exception if score is not float or not in range 0.0-1.0 regarding spec.
score
=
float
(
score
)
if
not
0
<=
score
<=
1
:
log
.
debug
(
"[LTI]: Score not in range."
)
raise
LTIError
raise
LTIError
(
'score value outside the permitted range of 0-1.'
)
return
imsx_messageIdentifier
,
sourcedId
,
score
,
action
...
...
@@ -576,7 +578,6 @@ oauth_consumer_key="", oauth_signature="frVp4JuvT1mVXlxktiAUjQ7%2F1cw%3D"'}
"""
client_key
,
client_secret
=
self
.
get_client_key_secret
()
headers
=
{
'Authorization'
:
unicode
(
request
.
headers
.
get
(
'Authorization'
)),
'Content-Type'
:
'application/x-www-form-urlencoded'
,
...
...
@@ -597,11 +598,9 @@ oauth_consumer_key="", oauth_signature="frVp4JuvT1mVXlxktiAUjQ7%2F1cw%3D"'}
signature
=
oauth_signature
)
if
oauth_body_hash
!=
oauth_headers
.
get
(
'oauth_body_hash'
):
log
.
debug
(
"[LTI]: OAuth body hash verification is failed."
)
raise
LTIError
raise
LTIError
(
"OAuth body hash verification is failed."
)
if
not
signature
.
verify_hmac_sha1
(
mock_request
,
client_secret
):
log
.
debug
(
"[LTI]: OAuth signature verification is failed."
)
raise
LTIError
raise
LTIError
(
"OAuth signature verification is failed."
)
def
get_client_key_secret
(
self
):
"""
...
...
common/lib/xmodule/xmodule/tests/test_lti_unit.py
View file @
7c070f29
...
...
@@ -99,7 +99,8 @@ class LTIModuleTest(LogicTest):
'action'
:
action
}
def
test_authorization_header_not_present
(
self
):
@patch
(
'xmodule.lti_module.LTIModule.get_client_key_secret'
,
return_value
=
(
'test_client_key'
,
u'test_client_secret'
))
def
test_authorization_header_not_present
(
self
,
get_key_secret
):
"""
Request has no Authorization header.
...
...
@@ -112,14 +113,15 @@ class LTIModuleTest(LogicTest):
expected_response
=
{
'action'
:
None
,
'code_major'
:
'failure'
,
'description'
:
'OAuth verification error
.
'
,
'description'
:
'OAuth verification error
: Malformed authorization header
'
,
'messageIdentifier'
:
self
.
DEFAULTS
[
'messageIdentifier'
],
}
self
.
assertEqual
(
response
.
status_code
,
200
)
self
.
assertDictEqual
(
expected_response
,
real_response
)
def
test_authorization_header_empty
(
self
):
@patch
(
'xmodule.lti_module.LTIModule.get_client_key_secret'
,
return_value
=
(
'test_client_key'
,
u'test_client_secret'
))
def
test_authorization_header_empty
(
self
,
get_key_secret
):
"""
Request Authorization header has no value.
...
...
@@ -133,7 +135,7 @@ class LTIModuleTest(LogicTest):
expected_response
=
{
'action'
:
None
,
'code_major'
:
'failure'
,
'description'
:
'OAuth verification error
.
'
,
'description'
:
'OAuth verification error
: Malformed authorization header
'
,
'messageIdentifier'
:
self
.
DEFAULTS
[
'messageIdentifier'
],
}
self
.
assertEqual
(
response
.
status_code
,
200
)
...
...
@@ -171,7 +173,7 @@ class LTIModuleTest(LogicTest):
expected_response
=
{
'action'
:
None
,
'code_major'
:
'failure'
,
'description'
:
'Request body XML parsing error.'
,
'description'
:
'Request body XML parsing error
: score value outside the permitted range of 0-1
.'
,
'messageIdentifier'
:
'unknown'
,
}
self
.
assertEqual
(
response
.
status_code
,
200
)
...
...
@@ -189,7 +191,7 @@ class LTIModuleTest(LogicTest):
expected_response
=
{
'action'
:
None
,
'code_major'
:
'failure'
,
'description'
:
'Request body XML parsing error
.
'
,
'description'
:
'Request body XML parsing error
: invalid literal for float(): 0,5
'
,
'messageIdentifier'
:
'unknown'
,
}
self
.
assertEqual
(
response
.
status_code
,
200
)
...
...
lms/djangoapps/courseware/features/lti_setup.py
View file @
7c070f29
...
...
@@ -36,9 +36,8 @@ def setup_mock_lti_server():
'lti_endpoint'
:
'correct_lti_endpoint'
}
# Flag for acceptance tests used for creating right callback_url and sending
# graded result. Used in MockLTIRequestHandler.
server
.
test_mode
=
True
# For testing on localhost make callback url using referer host.
server
.
real_callback_url_on
=
False
# Store the server instance in lettuce's world
# so that other steps can access it
...
...
lms/djangoapps/courseware/mock_lti_server/mock_lti_server.py
View file @
7c070f29
...
...
@@ -61,7 +61,7 @@ class MockLTIRequestHandler(BaseHTTPRequestHandler):
'''
if
'grade'
in
self
.
path
and
self
.
_send_graded_result
()
.
status_code
==
200
:
status_message
=
'LTI consumer (edX) responded with XML content:<br>'
+
self
.
server
.
grade_data
[
'TC answer'
]
self
.
server
.
grade_data
[
'callback_url'
]
=
None
self
.
server
.
grade_data
=
None
self
.
_send_response
(
status_message
,
200
)
# Respond to request with correct lti endpoint:
elif
self
.
_is_correct_lti_request
():
...
...
@@ -152,12 +152,14 @@ class MockLTIRequestHandler(BaseHTTPRequestHandler):
</imsx_POXEnvelopeRequest>
"""
)
data
=
payload
.
format
(
**
values
)
# get relative part, because host name is different in a) manual tests b) acceptance tests c) demos
if
getattr
(
self
.
server
,
'test_mode'
,
None
):
if
getattr
(
self
.
server
,
'use_real_callback_url'
,
None
):
# Use exact URL that was sent from TC when using this Stub LTI server
# as TP in real standalone environment.
url
=
self
.
server
.
grade_data
[
'callback_url'
]
else
:
# Use relative URL when using TP locally for manual testing or jenkins.
relative_url
=
urlparse
.
urlparse
(
self
.
server
.
grade_data
[
'callback_url'
])
.
path
url
=
self
.
server
.
referer_host
+
relative_url
else
:
url
=
self
.
server
.
grade_data
[
'callback_url'
]
headers
=
{
'Content-Type'
:
'application/xml'
,
'X-Requested-With'
:
'XMLHttpRequest'
}
headers
[
'Authorization'
]
=
self
.
oauth_sign
(
url
,
data
)
...
...
@@ -167,11 +169,12 @@ class MockLTIRequestHandler(BaseHTTPRequestHandler):
if
getattr
(
self
.
server
,
'run_inside_unittest_flag'
,
None
):
response
=
mock
.
Mock
(
status_code
=
200
,
url
=
url
,
data
=
data
,
headers
=
headers
)
return
response
# Send request ignoring verification of SSL certificate
response
=
requests
.
post
(
url
,
data
=
data
,
headers
=
headers
headers
=
headers
,
verify
=
False
)
self
.
server
.
grade_data
[
'TC answer'
]
=
response
.
content
return
response
...
...
@@ -182,6 +185,7 @@ class MockLTIRequestHandler(BaseHTTPRequestHandler):
'''
self
.
_send_head
(
status_code
)
if
getattr
(
self
.
server
,
'grade_data'
,
False
):
# lti can be graded
url
=
"//{}:{}"
.
format
(
self
.
server
.
server_host
,
self
.
server
.
server_port
)
response_str
=
textwrap
.
dedent
(
"""
<html>
<head>
...
...
@@ -198,7 +202,7 @@ class MockLTIRequestHandler(BaseHTTPRequestHandler):
</form>
</body>
</html>
"""
)
.
format
(
message
,
url
=
"http://
%
s:
%
s"
%
self
.
server
.
server_address
)
"""
)
.
format
(
message
,
url
=
url
)
else
:
# lti can't be graded
response_str
=
textwrap
.
dedent
(
"""
<html>
...
...
lms/djangoapps/courseware/mock_lti_server/server_start.py
View file @
7c070f29
...
...
@@ -19,10 +19,10 @@ server.oauth_settings = {
'lti_endpoint'
:
'correct_lti_endpoint'
}
server
.
server_host
=
server_host
server
.
server_port
=
server_port
# If in test mode mock lti server will make callback url using referer host.
# Used in MockLTIRequestHandler when sending graded result.
server
.
test_mode
=
True
# For testing on localhost make callback url using referer host.
server
.
use_real_callback_url
=
False
try
:
server
.
serve_forever
()
...
...
lms/djangoapps/courseware/mock_lti_server/test_mock_lti_server.py
View file @
7c070f29
...
...
@@ -36,6 +36,9 @@ class MockLTIServerTest(unittest.TestCase):
#flag for creating right callback_url
self
.
server
.
test_mode
=
True
self
.
server
.
server_host
=
server_host
self
.
server
.
server_port
=
server_port
# Start the server in a separate daemon thread
server_thread
=
threading
.
Thread
(
target
=
self
.
server
.
serve_forever
)
server_thread
.
daemon
=
True
...
...
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