canvas-lms/spec/lib/lti/message_authenticator_spec.rb

148 lines
5.4 KiB
Ruby

#
# Copyright (C) 2016 - present Instructure, Inc.
#
# This file is part of Canvas.
#
# Canvas is free software: you can redistribute it and/or modify it under
# the terms of the GNU Affero General Public License as published by the Free
# Software Foundation, version 3 of the License.
#
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
# details.
#
# You should have received a copy of the GNU Affero General Public License along
# with this program. If not, see <http://www.gnu.org/licenses/>.
#
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
require_dependency "lti/message_authenticator"
module Lti
describe MessageAuthenticator do
let(:launch_url) {'http://test.com/test'}
let(:course) {Course.create!}
let!(:tool) do
course.context_external_tools.create!(
{
name: 'test tool',
domain:'test.com',
consumer_key: 'key',
shared_secret: 'secret'
}
)
end
let(:message) do
m = IMS::LTI::Models::Messages::ContentItemSelection.new(
{
lti_message_type: 'ContentItemSelection',
lti_version: 'LTI-1p0',
content_items: File.read(File.join(Rails.root, 'spec', 'fixtures', 'lti', 'content_items.json')),
data: Canvas::Security.create_jwt({content_item_id: "3"}),
lti_msg: '',
lti_log: '',
lti_errormsg: '',
lti_errorlog: ''
}
)
m.launch_url = launch_url
m.oauth_consumer_key = tool.consumer_key
m
end
subject{described_class.new(launch_url, message.signed_post_params(tool.shared_secret))}
it 'creates a message from the signed_params' do
expect(subject.message.oauth_consumer_key).to eq tool.consumer_key
end
describe "#valid?" do
it 'validates a message' do
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]
end
end
it 'rejects an invalid secret' do
validator = described_class.new(launch_url, message.signed_post_params('invalid'))
expect(validator.valid?).to be false
end
it 'rejects a used nonce' do
enable_cache do
signed_params = message.signed_post_params(tool.shared_secret)
validator1 = described_class.new(launch_url, signed_params)
validator2 = described_class.new(launch_url, signed_params)
expect(validator1.valid?).to be true
expect(validator2.valid?).to be false
end
end
it 'rejects a message older than the NONCE_EXPIRATION' do
enable_cache do
validator = nil
Timecop.freeze((described_class::NONCE_EXPIRATION + 1.minute).ago) do
validator = described_class.new(launch_url, message.signed_post_params(tool.shared_secret))
end
expect(validator.valid?).to be false
end
end
it "doesn't store the nonce if the signature is invalid" do
enable_cache do
validator = described_class.new(launch_url, message.signed_post_params('invalid'))
expect(validator.valid?).to be false
expect(Rails.cache.exist?(validator.send(:cache_key))).to be_falsey
end
end
end
end
end