Module: Lti2Commons::MessageSupport

Defined in:
lib/lti2_commons/message_support.rb

Overview

Module to support LTI 1 and 2 secure messaging. This messaging is documented in the LTI 2 Security Document

LTI 2 defines two types of LTI secure messaging:

1. LTI Messages
  This is the model used exclusively in LTI 1.
  It is also used in LTI 2 for user-submitted actions such as LtiLaunch and ToolDeployment.

  It works the following way:
    1. LTI parameters are signed by OAuth.
    2. The message is marshalled into an HTML Form with the params
       specified in form fields.
    3. The form is sent to the browser with a redirect.
    4. An attached Javascript script 'auto-submits' the form.

  This structure appears to the Tool Provider as a user submission with all user browser context
  intact.

2. LTI Services
  This is a standard REST web service with OAuth message security added.
  In LTI 2.0 Services are only defined for Tool Provider --> Tool Consumer services;
  such as, GetToolConsumerProfile, RegisterToolProxy, and LTI 2 Outcomes.
  LTI 2.x will add Tool Consumer --> Tool Provider services using the same machinery.

Instance Method Summary collapse

Instance Method Details

#create_lti_message_body(launch_url, parameters, wire_log = nil, title = nil) ⇒ String

Convenience method signs and then invokes create_lti_message_from_signed_request

Returns:

  • (String)

    Post body ready for use



38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/lti2_commons/message_support.rb', line 38

def create_lti_message_body(launch_url, parameters, wire_log=nil, title=nil)
  result = create_message_header(launch_url)
  result += create_message_body parameters
  result += create_message_footer
  
  if wire_log
    wire_log.timestamp
    wire_log.raw_log((title.nil?) ? "LtiMessage" : "LtiMessage: #{title}")
    wire_log.raw_log "LaunchUrl: #{launch_url}"
    wire_log.raw_log result.strip
    wire_log.newline
    wire_log.flush
  end
  result
end

#create_lti_message_body_from_signed_request(signed_request, is_include_oauth_params = true) ⇒ String

Creates an LTI Message (POST body) ready for redirecting to the launch_url. Note that the is_include_oauth_params option specifies that ‘oauth_’ params are included in the body. This option should be false when sender is putting them in the HTTP Authorization header (now recommended).

Parameters:

  • params (Hash)

    Full set of params for message (including OAuth provided params)

Returns:

  • (String)

    Post body ready for use



61
62
63
64
65
66
# File 'lib/lti2_commons/message_support.rb', line 61

def create_lti_message_body_from_signed_request(signed_request, is_include_oauth_params=true)
  result = create_message_header(signed_request.uri)
  result += create_message_body signed_request.parameters, is_include_oauth_params
  result += create_message_footer
  result
end

#invoke_service(request, wire_log = nil, title = nil) ⇒ Object

Invokes an LTI Service. This is fully-compliant REST request suitable for LTI server-to-server services.

Parameters:

  • request (Request)

    Signed Request encapsulates everything needed for service.



72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
# File 'lib/lti2_commons/message_support.rb', line 72

def invoke_service(request, wire_log=nil, title=nil)
  uri = request.uri.to_s
  method = request.method.downcase
  headers = {}
  headers['Authorization'] = request.oauth_header
  headers['ACCEPT'] = request.accept if request.accept.present?
  if ['post','put'].include? method
    headers['Content-Type'] = request.content_type if request.content_type
    headers['Content-Length'] = request.body.length.to_s if request.body
  end

  parameters = request.parameters
  # need filtered params here
    
  output_parameters = {}
  (write_wirelog_header wire_log, title, request.method, uri, headers, request.parameters, request.body, output_parameters) if wire_log
  
  full_uri = uri
  full_uri += '?' unless uri.include? "?"
  full_uri += '&' unless full_uri =~ /[?&]$/
  output_parameters.each_pair do |key, value|
    full_uri << '&' unless key == output_parameters.keys.first
    full_uri << "#{URI.encode(key.to_s)}=#{URI.encode(output_parameters[key])}"
  end

  case request.method.downcase
  when "get"
    response = HTTParty.get full_uri, :headers => headers
  when "post"
    response = HTTParty.post full_uri, :body => request.body, :headers => headers
  when "put"
    response = HTTParty.put full_uri, :body => request.body, :headers => headers
  when "delete"
    response = HTTParty.delete full_uri, :headers => headers
  end
  wire_log.log_response response, title if wire_log
  response
end

#invoke_unsigned_service(uri, method, params = {}, headers = {}, data = nil, wire_log = nil, title = nil) ⇒ Object



111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'lib/lti2_commons/message_support.rb', line 111

def invoke_unsigned_service uri, method, params={}, headers={}, data=nil, wire_log=nil, title=nil
  full_uri = uri
  full_uri += '?' unless uri.include? "?"
  full_uri += '&' unless full_uri =~ /[?&]$/
  params.each_pair do |key, value|
    full_uri << '&' unless key == params.keys.first
    full_uri << "#{URI.encode(key.to_s)}=#{URI.encode(params[key])}"
  end

  (write_wirelog_header wire_log, title, method, uri, headers, params, data, {}) if wire_log
  
  case method
  when "get"
    response = HTTParty.get full_uri, :headers => headers, :timeout => 120
  when "post"
    response = HTTParty.post full_uri, :body => data, :headers => headers, :timeout => 120
  when "put"
    response = HTTParty.put full_uri, :body => data, :headers => headers, :timeout => 120
  when "delete"
    response = HTTParty.delete full_uri, :headers => headers, :timeout => 120
  end     
  wire_log.log_response response, title if wire_log
  response
end