use the new ims lti message authenticator
the new gem created an lti message authenticator that fixes a bug around content-item-selection message signature validation. fixes PLAT-1639 test plan: the test tool content item edit should still work the o365 content-item edit should work with it Change-Id: I5ebe868b31518861d32bf1b02244c21cceb55eb6 Reviewed-on: https://gerrit.instructure.com/84481 Reviewed-by: Andrew Butterfield <abutterfield@instructure.com> Tested-by: Jenkins QA-Review: August Thornton <august@instructure.com> Product-Review: Nathan Mills <nathanm@instructure.com>
This commit is contained in:
parent
1af7eb10ec
commit
1ff9e81d6d
|
@ -54,7 +54,7 @@ gem 'i18n', '0.7.0'
|
|||
gem 'i18nema', '0.0.8'
|
||||
gem 'i18nliner', '0.0.12'
|
||||
gem 'icalendar', '1.5.4', require: false
|
||||
gem 'ims-lti', '2.0.0.beta.41', require: 'ims'
|
||||
gem 'ims-lti', '2.1.0.beta.3', require: 'ims'
|
||||
gem 'json', '1.8.2'
|
||||
gem 'oj', '2.14.1'
|
||||
gem 'jwt', '1.2.1', require: false
|
||||
|
|
|
@ -17,39 +17,47 @@
|
|||
#
|
||||
module Lti
|
||||
class MessageAuthenticator
|
||||
attr_reader :message
|
||||
|
||||
CACHE_KEY_PREFIX = 'lti_nonce_'
|
||||
NONCE_EXPIRATION = 10.minutes
|
||||
|
||||
def initialize(launch_url, params)
|
||||
@message = IMS::LTI::Models::Messages::Message.generate(params)
|
||||
@version = @message.lti_version
|
||||
@message.launch_url = launch_url
|
||||
@params = params.with_indifferent_access
|
||||
@launch_url = launch_url
|
||||
@version = @params[:lti_version]
|
||||
@nonce = @params[:oauth_nonce]
|
||||
@oauth_consumer_key = @params[:oauth_consumer_key]
|
||||
end
|
||||
|
||||
def valid?
|
||||
@valid ||= begin
|
||||
valid = message.valid_signature?(shared_secret)
|
||||
valid &&= message.oauth_timestamp.to_i > NONCE_EXPIRATION.ago.to_i
|
||||
valid = lti_message_authenticator.valid_signature?
|
||||
valid &&= @params[:oauth_timestamp].to_i > NONCE_EXPIRATION.ago.to_i
|
||||
valid &&= !Rails.cache.exist?(cache_key)
|
||||
Rails.cache.write(cache_key, message.oauth_consumer_key, expires_in: NONCE_EXPIRATION) if valid
|
||||
Rails.cache.write(cache_key, 'OK', expires_in: NONCE_EXPIRATION) if valid
|
||||
valid
|
||||
end
|
||||
end
|
||||
|
||||
def message
|
||||
lti_message_authenticator.message
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def lti_message_authenticator
|
||||
@lti_message_authenticator ||= IMS::LTI::Services::MessageAuthenticator.new(@launch_url, @params, shared_secret)
|
||||
end
|
||||
|
||||
def shared_secret
|
||||
@shared_secret ||=
|
||||
if @version.strip == 'LTI-1p0'
|
||||
tool = ContextExternalTool.where(consumer_key: message.oauth_consumer_key).first
|
||||
tool = ContextExternalTool.where(consumer_key: @params[:oauth_consumer_key]).first
|
||||
tool && tool.shared_secret
|
||||
end
|
||||
end
|
||||
|
||||
def cache_key
|
||||
CACHE_KEY_PREFIX+@message.oauth_nonce
|
||||
"#{CACHE_KEY_PREFIX}_#{@oauth_consumer_key}_#{@nonce}"
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -22,7 +22,7 @@ module Lti
|
|||
|
||||
let(:launch_url) {'http://test.com/test'}
|
||||
let(:course) {Course.create!}
|
||||
let(:tool) do
|
||||
let!(:tool) do
|
||||
course.context_external_tools.create!(
|
||||
{
|
||||
name: 'test tool',
|
||||
|
@ -61,6 +61,44 @@ module Lti
|
|||
expect(subject.valid?).to be true
|
||||
end
|
||||
|
||||
context 'content-item unique json serialization' do
|
||||
let(:launch_url) {"http://test.com/test"}
|
||||
let(:secret) {'secret'}
|
||||
let(:signed_params) {
|
||||
{
|
||||
:oauth_callback=>"about:blank",
|
||||
:oauth_consumer_key=>"key",
|
||||
:oauth_nonce=>"89fc77055d2a051de296fc5d99987a20",
|
||||
:oauth_signature_method=>"HMAC-SHA1",
|
||||
:oauth_timestamp=>"1467842103",
|
||||
:oauth_version=>"1.0",
|
||||
:oauth_signature=>"TL8PLA/V43D21+JkGg8i9Cj+Dqg=",
|
||||
"lti_message_type"=>"ContentItemSelection",
|
||||
"lti_version"=>"LTI-1p0",
|
||||
"content_items"=>"{\"@graph\":[{\"windowTarget\":\"\",\"text\":\"Arch Linux\",\"title\":\"Its your "+
|
||||
"computer\",\"url\":\"http://lti-tool-provider-example.dev/messages/blti\""+
|
||||
",\"thumbnail\":{\"height\":128,\"width\":128,\"@id\""+
|
||||
":\"http://www.runeaudio.com/assets/img/banner-archlinux.png\"}"+
|
||||
",\"placementAdvice\":{\"displayHeight\":600,\"displayWidth\":800"+
|
||||
",\"presentationDocumentTarget\":\"iframe\"},\"mediaType\""+
|
||||
":\"application/vnd.ims.lti.v1.ltilink\",\"@type\":\"LtiLinkItem\",\"@id\""+
|
||||
":\"http://lti-tool-provider-example.dev/messages/blti\"}],\"@context\""+
|
||||
":\"http://purl.imsglobal.org/ctx/lti/v1/ContentItem\"}",
|
||||
"lti_msg"=>"",
|
||||
"lti_log"=>"",
|
||||
"lti_errormsg"=>"",
|
||||
"lti_errorlog"=>""
|
||||
}
|
||||
}
|
||||
|
||||
it "validates the message" do
|
||||
message_authenticator = MessageAuthenticator.new(launch_url, signed_params)
|
||||
Timecop.freeze(Time.at(signed_params[:oauth_timestamp].to_i)) do
|
||||
expect(message_authenticator.valid?).to eq true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it "returns the same value if called multiple times" do
|
||||
enable_cache do
|
||||
expect(2.times.map { |_| subject.valid? }).to eq [true, true]
|
||||
|
|
Loading…
Reference in New Issue