ims-lti 2.1.2 → 2.3.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 2bdd06e5c60fc13eb134e231cf0e0ee7738eb9a8
4
- data.tar.gz: 56c1d472a02e4d5359b9e03977a0d9f604a3a09f
2
+ SHA256:
3
+ metadata.gz: 2471bb32ba4e415a4134bca8b7fd89e395e6d2fcea9cf694ae3a094599bed683
4
+ data.tar.gz: 9978a2ca0c9f89cd4fdd03217cb0f13bde37098f45c319e2d813c3fad6102b31
5
5
  SHA512:
6
- metadata.gz: 264a0293b2ccad3c5047d081ba08d6f2967a3e26c621855a1add4cafd113f3627d95cb75d95b491cc47293a35ded64ef9d82aa6ac61e393dde2e69189398fb91
7
- data.tar.gz: 47cfe33a68b1a8ee738ab6d80bc8e8e8d4b75d8fc47c25da6e42fef69b9ca55f04a5b343b82687d161434943670f6149f75da13ec6fb5be30c2485f965bc6819
6
+ metadata.gz: b96119ce642dde977d998fb405576b21ca755311b841b49d9a985f556bf0fdfbbab60798027060f641463edd1329505a4a53ad916f75a9ce344d9c4723d1ab20
7
+ data.tar.gz: 5e4fd658b0658adcdbcca33feacf429f04e8a0f354eb6db1d031cfa4b0655f9a8478131919f215d833d872478462677bfcd04ed6ee298a00ed85bcb921f3313c
data/README.md CHANGED
@@ -37,7 +37,7 @@ return false unless authenticator.valid_signature?
37
37
  # check if `params['oauth_nonce']` has already been used
38
38
 
39
39
  #check if the message is too old
40
- return false if DateTime.strptime(request.request_parameters['oauth_timestamp'],'%s') > 5.minutes.ago
40
+ return false if DateTime.strptime(request.request_parameters['oauth_timestamp'],'%s') < 5.minutes.ago
41
41
 
42
42
  ```
43
43
 
@@ -0,0 +1,11 @@
1
+ module IMS::LTI::Errors
2
+ class AuthenticationFailedError < StandardError
3
+
4
+ attr_reader :response
5
+
6
+ def initialize(response: nil)
7
+ @response = response
8
+ end
9
+
10
+ end
11
+ end
@@ -3,5 +3,6 @@ module IMS::LTI
3
3
  require_relative 'errors/invalid_lti_config_error'
4
4
  require_relative 'errors/tool_proxy_registration_error'
5
5
  require_relative 'errors/invalid_tool_consumer_profile'
6
+ require_relative 'errors/authentication_failed_error'
6
7
  end
7
8
  end
@@ -1,3 +1,5 @@
1
+ require 'uri'
2
+
1
3
  module IMS::LTI::Models
2
4
  class LTIModel
3
5
  LTI_VERSION_2P0 = 'LTI-2p0'.freeze
@@ -90,8 +92,13 @@ module IMS::LTI::Models
90
92
  end
91
93
 
92
94
  def from_json(json)
93
- # JSON.parse(json.to_json) is a quick and dirty way to clone the json object passed in
94
- data = json.is_a?(String) ? JSON.parse(json) : JSON.parse(json.to_json)
95
+ json = json.to_json unless json.is_a?(String)
96
+ begin
97
+ data = JSON.parse(json)
98
+ rescue
99
+ data = JSON.parse(URI::DEFAULT_PARSER.unescape(json))
100
+ end
101
+
95
102
  if data.is_a? Array
96
103
  data.map { |hash| self.class.from_json(hash.to_json) }
97
104
  else
@@ -1,6 +1,6 @@
1
1
  module IMS::LTI::Models::MembershipService
2
2
  class LISPerson < Person
3
- attr_reader :email, :result_sourced_id, :sourced_id, :user_id
3
+ attr_reader :email, :result_sourced_id, :sourced_id, :user_id, :sis_id
4
4
 
5
5
  def initialize(opts={})
6
6
  super(opts)
@@ -8,6 +8,7 @@ module IMS::LTI::Models::MembershipService
8
8
  @result_sourced_id = opts[:result_sourced_id]
9
9
  @sourced_id = opts[:sourced_id]
10
10
  @user_id = opts[:user_id]
11
+ @sis_id = opts[:sis_id]
11
12
  end
12
13
  end
13
14
  end
@@ -3,7 +3,8 @@ module IMS::LTI::Models::Messages
3
3
 
4
4
  add_required_params :resource_link_id
5
5
  add_recommended_params :context_id, :launch_presentation_return_url, :tool_consumer_instance_guid
6
- add_optional_params :context_type, :role_scope_mentor, :user_image
6
+ add_optional_params :context_type, :role_scope_mentor, :user_image,
7
+ :lis_outcome_service_url, :lis_person_sourced_id, :lis_result_sourcedid
7
8
  add_deprecated_params :context_title, :context_label, :resource_link_title, :resource_link_description,
8
9
  :lis_person_name_given, :lis_person_name_family, :lis_person_name_full,
9
10
  :lis_person_contact_email_primary, :user_image, :lis_person_sourcedid,
@@ -40,13 +40,26 @@ module IMS::LTI::Models::Messages
40
40
  def inherited(klass)
41
41
  @descendants ||= Set.new
42
42
  @descendants << klass
43
- superclass.inherited(klass) unless(self == Message)
43
+ superclass.inherited(klass) unless (self == Message)
44
44
  end
45
45
 
46
46
  def descendants
47
47
  @descendants || Set.new
48
48
  end
49
49
 
50
+ # For signature generation -- see usage in signed_post_params
51
+ def convert_param_values_to_crlf_endings(hash)
52
+ hash.transform_values do |val|
53
+ if val.is_a?(String)
54
+ # Convert to all newlines first, for consistency, just in case there
55
+ # is some weird mix of newlines & carriage returns in input
56
+ val.encode(universal_newline: true).encode(crlf_newline: true)
57
+ else
58
+ val
59
+ end
60
+ end
61
+ end
62
+
50
63
  private
51
64
 
52
65
  def add_params(instance_variable, param, *params)
@@ -81,20 +94,34 @@ module IMS::LTI::Models::Messages
81
94
  OAUTH_KEYS = :oauth_callback, :oauth_consumer_key, :oauth_nonce, :oauth_signature, :oauth_signature_method,
82
95
  :oauth_timestamp, :oauth_token, :oauth_verifier, :oauth_version
83
96
 
84
- attr_accessor :launch_url, *OAUTH_KEYS
97
+ attr_accessor :launch_url, :jwt, *OAUTH_KEYS
85
98
  attr_reader :unknown_params, :custom_params, :ext_params
86
99
 
87
100
  add_required_params :lti_message_type, :lti_version
88
101
 
89
- def self.generate(params)
90
- klass = self.descendants.select{|d| d::MESSAGE_TYPE == params['lti_message_type']}.first
91
- klass ? klass.new(params) : Message.new(params)
102
+ def self.generate(launch_params)
103
+ params = launch_params.key?('jwt') ? parse_jwt(jwt: launch_params['jwt']) : launch_params
104
+ klass = self.descendants.select {|d| d::MESSAGE_TYPE == params['lti_message_type']}.first
105
+ message = klass ? klass.new(params) : Message.new(params)
106
+ message.jwt = launch_params['jwt'] if launch_params.key?('jwt')
107
+ message
92
108
  end
93
109
 
94
- def initialize(attrs = {})
110
+ def self.parse_jwt(jwt:)
111
+ decoded_jwt = JSON::JWT.decode(jwt, :skip_verification)
112
+ params = decoded_jwt['org.imsglobal.lti.message'] || {}
113
+ custom = params.delete(:custom)
114
+ custom.each {|k,v| params["custom_#{k}"] = v }
115
+ params['consumer_key'] = decoded_jwt[:sub]
116
+ ext = params.delete(:ext)
117
+ ext.each {|k,v| params["ext_#{k}"] = v }
118
+ params
119
+ end
120
+
121
+ def initialize(attrs = {}, custom_params = {}, ext_params = {})
95
122
 
96
- @custom_params = {}
97
- @ext_params = {}
123
+ @custom_params = custom_params
124
+ @ext_params = ext_params
98
125
  @unknown_params = {}
99
126
 
100
127
  attrs.each do |k, v|
@@ -114,20 +141,32 @@ module IMS::LTI::Models::Messages
114
141
  end
115
142
 
116
143
  def add_custom_params(params)
117
- params.each { |k, v| k.to_s.start_with?('custom_') ? @custom_params[k.to_s] = v : @custom_params["custom_#{k.to_s}"] = v }
144
+ params.each {|k, v| k.to_s.start_with?('custom_') ? @custom_params[k.to_s] = v : @custom_params["custom_#{k.to_s}"] = v}
118
145
  end
119
146
 
120
147
  def get_custom_params
121
- @custom_params.inject({}) { |hash, (k, v)| hash[k.gsub(/\Acustom_/, '')] = v; hash }
148
+ @custom_params.inject({}) {|hash, (k, v)| hash[k.gsub(/\Acustom_/, '')] = v; hash}
149
+ end
150
+
151
+ def get_ext_params
152
+ @ext_params.inject({}) {|hash, (k, v)| hash[k.gsub(/\Aext_/, '')] = v; hash}
122
153
  end
123
154
 
124
155
  def post_params
125
156
  unknown_params.merge(@custom_params).merge(@ext_params).merge(parameters)
126
157
  end
127
158
 
159
+ def jwt_params(private_key:, originating_domain:, algorithm: :HS256)
160
+ { 'jwt' => to_jwt(private_key: private_key, originating_domain: originating_domain, algorithm: algorithm) }
161
+ end
162
+
128
163
  def signed_post_params(secret)
129
- message_params = { oauth_consumer_key: oauth_consumer_key}.merge(post_params)
130
- @message_authenticator = IMS::LTI::Services::MessageAuthenticator.new(launch_url, message_params, secret )
164
+ # The params will be used in an HTML form, and browsers will always use
165
+ # newlines+carriage return line endings for submitted form data. The
166
+ # signature needs to match, and signature generation does not add carriage
167
+ # returns, so we ensure CRLF endings here.
168
+ message_params = self.class.convert_param_values_to_crlf_endings(oauth_params.merge(post_params))
169
+ @message_authenticator = IMS::LTI::Services::MessageAuthenticator.new(launch_url, message_params, secret)
131
170
  @message_authenticator.signed_params
132
171
  end
133
172
 
@@ -165,6 +204,27 @@ module IMS::LTI::Models::Messages
165
204
  end
166
205
  end
167
206
 
207
+ def to_jwt(private_key:, originating_domain:, algorithm: :HS256)
208
+ now = Time.now
209
+ exp = now + 60 * 5
210
+ ims = unknown_params.merge(parameters)
211
+ ims[:custom] = get_custom_params
212
+ ims[:ext] = get_ext_params
213
+ claim = {
214
+ iss: originating_domain,
215
+ sub: consumer_key,
216
+ aud: launch_url,
217
+ iat: now,
218
+ exp: exp,
219
+ jti: SecureRandom.uuid,
220
+ "org.imsglobal.lti.message" => ims
221
+ }
222
+ jwt = JSON::JWT.new(claim).sign(private_key, algorithm)
223
+ jwt.to_s
224
+ end
225
+
226
+ alias_attribute :consumer_key, :oauth_consumer_key
227
+
168
228
  private
169
229
 
170
230
  def collect_attributes(attributes)
@@ -176,4 +236,4 @@ module IMS::LTI::Models::Messages
176
236
  end
177
237
 
178
238
  end
179
- end
239
+ end
@@ -1,7 +1,8 @@
1
1
  module IMS::LTI::Models::Messages
2
2
  class RegistrationRequest < RequestMessage
3
3
 
4
- add_required_params :reg_key, :reg_password, :tc_profile_url, :launch_presentation_return_url
4
+ add_required_params :reg_key, :reg_password, :tc_profile_url, :launch_presentation_return_url, :tool_proxy_guid,
5
+ :tool_proxy_url
5
6
 
6
7
 
7
8
  MESSAGE_TYPE = 'ToolProxyRegistrationRequest'
@@ -16,4 +17,4 @@ module IMS::LTI::Models::Messages
16
17
  end
17
18
 
18
19
  end
19
- end
20
+ end
@@ -1,10 +1,10 @@
1
1
  module IMS::LTI::Models::Messages
2
- class ToolProxyReregistrationRequest < RequestMessage
2
+ class ToolProxyUpdateRequest < RequestMessage
3
3
 
4
4
  add_required_params :tc_profile_url, :launch_presentation_return_url
5
5
 
6
6
 
7
- MESSAGE_TYPE = 'ToolProxyReregistrationRequest'
7
+ MESSAGE_TYPE = 'ToolProxyUpdateRequest'
8
8
 
9
9
  def initialize(attrs = {})
10
10
  super(attrs)
@@ -6,6 +6,6 @@ module IMS::LTI::Models
6
6
  require_relative 'messages/basic_lti_launch_request'
7
7
  require_relative 'messages/content_item_selection_request'
8
8
  require_relative 'messages/content_item_selection'
9
- require_relative 'messages/tool_proxy_reregistration_request'
9
+ require_relative 'messages/tool_proxy_update_request'
10
10
  end
11
11
  end
@@ -11,6 +11,7 @@ module IMS::LTI::Models
11
11
  add_attribute :id, json_key:'@id'
12
12
  add_attribute :type, json_key:'@type'
13
13
  add_attribute :context, json_key:'@context'
14
+ add_attribute :security_profile, relation: 'IMS::LTI::Models::SecurityProfile'
14
15
  add_attribute :product_instance, relation:'IMS::LTI::Models::ProductInstance'
15
16
  add_attribute :service_offered, relation: 'IMS::LTI::Models::RestService'
16
17
 
@@ -33,7 +34,12 @@ module IMS::LTI::Models
33
34
  end
34
35
 
35
36
  def reregistration_capable?
36
- @capability_offered.include?(Messages::ToolProxyReregistrationRequest::MESSAGE_TYPE)
37
+ @capability_offered.include?(Messages::ToolProxyUpdateRequest::MESSAGE_TYPE)
37
38
  end
39
+
40
+ def security_profile_by_name(security_profile_name:)
41
+ security_profiles.find { |sp| sp.security_profile_name == security_profile_name}
42
+ end
43
+
38
44
  end
39
45
  end
@@ -7,5 +7,6 @@ module IMS::LTI::Serializers::MembershipService
7
7
  set_attribute :result_sourced_id, key: :resultSourcedId
8
8
  set_attribute :sourced_id, key: :sourcedId
9
9
  set_attribute :user_id, key: :userId
10
+ set_attribute :sis_id, key: :sisId, optional: true
10
11
  end
11
12
  end
@@ -0,0 +1,67 @@
1
+ module IMS::LTI::Services
2
+ class AuthenticationService
3
+
4
+ attr_accessor :connection, :iss, :aud, :sub, :secret, :grant_type,
5
+ :additional_claims, :additional_params
6
+ attr_writer :secret
7
+
8
+ def initialize(iss:, aud:, sub:, secret:)
9
+ @iss = iss
10
+ @aud = aud
11
+ @sub = sub
12
+ @secret = secret
13
+ @additional_claims = {}
14
+ @additional_params = {}
15
+ @grant_type = 'urn:ietf:params:oauth:grant-type:jwt-bearer'
16
+ end
17
+
18
+ def connection
19
+ @connection ||= Faraday.new
20
+ end
21
+
22
+ def access_token
23
+ access_token_request['access_token']
24
+ end
25
+
26
+ def expiration
27
+ expires_in = access_token_request['expires_in'].to_i
28
+ @_response_time + expires_in
29
+ end
30
+
31
+ def expired?
32
+ expiration < Time.now
33
+ end
34
+
35
+ def invalidate!
36
+ @_access_token_request = nil
37
+ @_response_time = nil
38
+ end
39
+
40
+ private
41
+
42
+ def access_token_request
43
+ @_access_token_request ||= begin
44
+ assertion = JSON::JWT.new(
45
+ iss: iss,
46
+ sub: sub,
47
+ aud: aud.to_s,
48
+ iat: Time.now.to_i,
49
+ exp: 1.minute.from_now,
50
+ jti: SecureRandom.uuid
51
+ )
52
+ assertion.merge!(@additional_claims)
53
+ assertion = assertion.sign(@secret, :HS256).to_s
54
+ body = {
55
+ grant_type: grant_type,
56
+ assertion: assertion
57
+ }
58
+ body.merge!(@additional_params)
59
+ response = connection.post(aud, body)
60
+ raise IMS::LTI::Errors::AuthenticationFailedError.new(response: response) unless response.success?
61
+ @_response_time = Time.now
62
+ response.body
63
+ end
64
+ end
65
+
66
+ end
67
+ end
@@ -14,7 +14,7 @@ module IMS::LTI::Services
14
14
 
15
15
 
16
16
  def valid_signature?
17
- simple_oauth_header.valid?(signature: signature)
17
+ message.jwt ? valid_jwt? : simple_oauth_header.valid?(signature: signature)
18
18
  end
19
19
 
20
20
  def message
@@ -33,8 +33,7 @@ module IMS::LTI::Services
33
33
  @options.merge(
34
34
  {
35
35
  consumer_key: consumer_key,
36
- consumer_secret: @secret,
37
- callback: 'about:blank'
36
+ consumer_secret: @secret
38
37
  }
39
38
  )
40
39
  )
@@ -47,11 +46,24 @@ module IMS::LTI::Services
47
46
  end
48
47
 
49
48
  def signed_params
50
- simple_oauth_header.signed_attributes.merge(params)
49
+ simple_oauth_header.signed_attributes.merge(@parsed_params)
51
50
  end
52
51
 
53
52
 
54
53
  private
54
+
55
+ def valid_jwt?
56
+ begin
57
+ jwt = JSON::JWT.decode(message.jwt, @secret)
58
+ aud1 = Addressable::URI.parse(jwt['aud'])
59
+ aud2 = Addressable::URI.parse(launch_url)
60
+ [aud1, aud2].each{ |aud| aud.fragment = '' }
61
+ aud1.normalize == aud2.normalize
62
+ rescue JSON::JWS::VerificationFailed
63
+ false
64
+ end
65
+ end
66
+
55
67
  def parse_params(params)
56
68
  params.inject([{}, {}]) do |array, (k, v)|
57
69
  attr = k.to_s.sub('oauth_', '').to_sym
@@ -65,4 +77,4 @@ module IMS::LTI::Services
65
77
  end
66
78
 
67
79
  end
68
- end
80
+ end
@@ -0,0 +1,18 @@
1
+ module IMS::LTI::Services
2
+
3
+ class OAuth2Client
4
+ attr_accessor :token, :base_url
5
+ attr_writer :connection
6
+
7
+ def initialize(token:, base_url: nil)
8
+ @base_url = base_url
9
+ @token = token
10
+ end
11
+
12
+ def connection
13
+ @connection ||= Faraday.new base_url do |conn|
14
+ conn.authorization :Bearer, token
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,16 @@
1
+ module IMS::LTI::Services
2
+ class ToolConsumerProfileService
3
+
4
+ attr_accessor :tcp
5
+
6
+ def initialize(tool_consumer_profile)
7
+ @tcp = tool_consumer_profile
8
+ end
9
+
10
+ def supports_capabilities?(capability, *capabilities)
11
+ capabilities.unshift(capability)
12
+ (capabilities - tcp.capabilities_offered).empty?
13
+ end
14
+
15
+ end
16
+ end
@@ -76,7 +76,7 @@ module IMS::LTI::Services
76
76
  end
77
77
 
78
78
  def reregistration?
79
- @registration_request.is_a?(IMS::LTI::Models::Messages::ToolProxyReregistrationRequest)
79
+ @registration_request.is_a?(IMS::LTI::Models::Messages::ToolProxyUpdateRequest)
80
80
  end
81
81
 
82
82
 
@@ -85,25 +85,42 @@ module IMS::LTI::Services
85
85
  ret_val
86
86
  end
87
87
 
88
+ def invalid_security_profiles
89
+ security_profiles = tool_proxy.tool_profile.security_profiles
90
+ array = security_profiles.each_with_object([]) do |sp, array|
91
+ tcp_sp = tool_consumer_profile.security_profile_by_name(security_profile_name: sp.security_profile_name)
92
+ if tcp_sp
93
+ supported_algorithms = sp.digest_algorithms & tcp_sp.digest_algorithms
94
+ unsupported_algorithms = sp.digest_algorithms - supported_algorithms
95
+ unless unsupported_algorithms.empty?
96
+ array << { name: sp.security_profile_name, algorithms: unsupported_algorithms }
97
+ end
98
+ else
99
+ array << { name: sp.security_profile_name }
100
+ end
101
+ end
102
+ array
103
+ end
104
+
88
105
  def errors
89
106
  ret_val = {}
90
107
  ret_val[:invalid_security_contract] = invalid_security_contract unless invalid_security_contract.empty?
91
108
  ret_val[:invalid_capabilities] = invalid_capabilities unless invalid_capabilities.empty?
92
109
  ret_val[:invalid_message_handlers] = invalid_message_handlers unless invalid_message_handlers.empty?
93
110
  ret_val[:invalid_services] = invalid_services unless invalid_services.empty?
94
-
111
+ ret_val[:invalid_security_profiles] = invalid_security_profiles unless invalid_security_profiles.empty?
95
112
  ret_val
96
113
  end
97
114
 
98
115
  def valid?
99
- invalid_capabilities.empty? && invalid_security_contract.empty? && invalid_services.empty? && invalid_message_handlers.empty?
116
+ errors.keys.empty?
100
117
  end
101
118
 
102
119
  private
103
120
 
104
121
  def normalize_strings(string, *strings)
105
122
  strings.push(string)
106
- normalized = strings.map { |s| s.upcase.strip }
123
+ normalized = strings.map {|s| s.upcase.strip}
107
124
  normalized
108
125
  end
109
126
 
@@ -112,7 +129,7 @@ module IMS::LTI::Services
112
129
  invalid_capabilities = mh.enabled_capabilities - capabilities_offered
113
130
  invalid_parameters = validate_parameters(mh.parameters)
114
131
  if !invalid_parameters.empty? || !invalid_capabilities.empty?
115
- hash = {message_type: mh.message_type, }
132
+ hash = { message_type: mh.message_type, }
116
133
  hash[:invalid_capabilities] = invalid_capabilities unless invalid_capabilities.empty?
117
134
  hash[:invalid_parameters] = invalid_parameters unless invalid_parameters.empty?
118
135
  array << hash
@@ -124,7 +141,7 @@ module IMS::LTI::Services
124
141
  def validate_parameters(parameters)
125
142
  parameters.each_with_object([]) do |p, array|
126
143
  if !p.fixed? && !capabilities_offered.include?(p.variable)
127
- array << {name: p.name, variable: p.variable}
144
+ array << { name: p.name, variable: p.variable }
128
145
  end
129
146
  end
130
147
  end
@@ -142,7 +159,7 @@ module IMS::LTI::Services
142
159
  invalid_mhs = validate_message_handlers(rh.messages)
143
160
  if !invalid_mhs.empty? || !invalid_message_types.empty?
144
161
  hash = {
145
- code: rh.resource_type.code,
162
+ code: rh.resource_type.code,
146
163
  }
147
164
  hash[:messages] = invalid_mhs unless invalid_mhs.empty?
148
165
  hash[:invalid_message_types] = invalid_message_types unless invalid_message_types.empty?
@@ -161,6 +178,5 @@ module IMS::LTI::Services
161
178
  hash
162
179
  end
163
180
 
164
-
165
181
  end
166
182
  end
@@ -1,8 +1,11 @@
1
1
  module IMS::LTI
2
2
  module Services
3
+ require_relative 'services/oauth2_client'
3
4
  require_relative 'services/tool_proxy_registration_service'
4
5
  require_relative 'services/tool_config'
5
6
  require_relative 'services/tool_proxy_validator'
6
7
  require_relative 'services/message_authenticator'
8
+ require_relative 'services/tool_consumer_profile_service'
9
+ require_relative 'services/authentication_service'
7
10
  end
8
- end
11
+ end
@@ -1,5 +1,5 @@
1
1
  module IMS
2
2
  module LTI
3
- VERSION = "2.0.0.beta.27"
3
+ VERSION = "2.3.3"
4
4
  end
5
5
  end
data/lib/ims/lti.rb CHANGED
@@ -1,17 +1,19 @@
1
- require 'json'
2
- require 'securerandom'
3
- require 'simple_oauth'
1
+ require 'addressable/uri'
2
+ require 'builder'
4
3
  require 'faraday'
5
4
  require 'faraday_middleware'
6
- require 'builder'
5
+ require 'json'
6
+ require 'json/jwt'
7
7
  require 'rexml/document'
8
+ require 'securerandom'
9
+ require 'simple_oauth'
8
10
 
9
11
  module IMS
10
12
  module LTI
11
- require_relative 'lti/models'
12
13
  require_relative 'lti/converters'
13
- require_relative 'lti/services'
14
14
  require_relative 'lti/errors'
15
+ require_relative 'lti/models'
15
16
  require_relative 'lti/serializers'
17
+ require_relative 'lti/services'
16
18
  end
17
19
  end
metadata CHANGED
@@ -1,99 +1,133 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ims-lti
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.2
4
+ version: 2.3.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Instructure
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-03-27 00:00:00.000000000 Z
11
+ date: 2023-01-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: simple_oauth
14
+ name: addressable
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - '='
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.5'
20
+ - - ">="
18
21
  - !ruby/object:Gem::Version
19
- version: '0.2'
22
+ version: 2.5.1
20
23
  type: :runtime
21
24
  prerelease: false
22
25
  version_requirements: !ruby/object:Gem::Requirement
23
26
  requirements:
24
- - - '='
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '2.5'
30
+ - - ">="
25
31
  - !ruby/object:Gem::Version
26
- version: '0.2'
32
+ version: 2.5.1
27
33
  - !ruby/object:Gem::Dependency
28
- name: faraday
34
+ name: builder
29
35
  requirement: !ruby/object:Gem::Requirement
30
36
  requirements:
31
37
  - - "~>"
32
38
  - !ruby/object:Gem::Version
33
- version: '0.8'
39
+ version: '3.2'
34
40
  type: :runtime
35
41
  prerelease: false
36
42
  version_requirements: !ruby/object:Gem::Requirement
37
43
  requirements:
38
44
  - - "~>"
39
45
  - !ruby/object:Gem::Version
40
- version: '0.8'
46
+ version: '3.2'
47
+ - !ruby/object:Gem::Dependency
48
+ name: faraday
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "<"
52
+ - !ruby/object:Gem::Version
53
+ version: '2.0'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "<"
59
+ - !ruby/object:Gem::Version
60
+ version: '2.0'
41
61
  - !ruby/object:Gem::Dependency
42
62
  name: faraday_middleware
43
63
  requirement: !ruby/object:Gem::Requirement
44
64
  requirements:
45
- - - "~>"
65
+ - - "<"
46
66
  - !ruby/object:Gem::Version
47
- version: '0.8'
67
+ version: '2.0'
48
68
  type: :runtime
49
69
  prerelease: false
50
70
  version_requirements: !ruby/object:Gem::Requirement
51
71
  requirements:
52
- - - "~>"
72
+ - - "<"
53
73
  - !ruby/object:Gem::Version
54
- version: '0.8'
74
+ version: '2.0'
55
75
  - !ruby/object:Gem::Dependency
56
- name: builder
76
+ name: json-jwt
57
77
  requirement: !ruby/object:Gem::Requirement
58
78
  requirements:
59
79
  - - "~>"
60
80
  - !ruby/object:Gem::Version
61
- version: '3.2'
81
+ version: '1.7'
62
82
  type: :runtime
63
83
  prerelease: false
64
84
  version_requirements: !ruby/object:Gem::Requirement
65
85
  requirements:
66
86
  - - "~>"
67
87
  - !ruby/object:Gem::Version
68
- version: '3.2'
88
+ version: '1.7'
69
89
  - !ruby/object:Gem::Dependency
70
- name: rake
90
+ name: simple_oauth
71
91
  requirement: !ruby/object:Gem::Requirement
72
92
  requirements:
73
93
  - - "~>"
74
94
  - !ruby/object:Gem::Version
75
- version: '10.4'
76
- type: :development
95
+ version: 0.3.1
96
+ type: :runtime
77
97
  prerelease: false
78
98
  version_requirements: !ruby/object:Gem::Requirement
79
99
  requirements:
80
100
  - - "~>"
81
101
  - !ruby/object:Gem::Version
82
- version: '10.4'
102
+ version: 0.3.1
83
103
  - !ruby/object:Gem::Dependency
84
- name: rspec
104
+ name: rexml
105
+ requirement: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ type: :runtime
111
+ prerelease: false
112
+ version_requirements: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ version: '0'
117
+ - !ruby/object:Gem::Dependency
118
+ name: byebug
85
119
  requirement: !ruby/object:Gem::Requirement
86
120
  requirements:
87
121
  - - "~>"
88
122
  - !ruby/object:Gem::Version
89
- version: '3.2'
123
+ version: '9.0'
90
124
  type: :development
91
125
  prerelease: false
92
126
  version_requirements: !ruby/object:Gem::Requirement
93
127
  requirements:
94
128
  - - "~>"
95
129
  - !ruby/object:Gem::Version
96
- version: '3.2'
130
+ version: '9.0'
97
131
  - !ruby/object:Gem::Dependency
98
132
  name: guard
99
133
  requirement: !ruby/object:Gem::Requirement
@@ -128,14 +162,14 @@ dependencies:
128
162
  requirements:
129
163
  - - "~>"
130
164
  - !ruby/object:Gem::Version
131
- version: '2.10'
165
+ version: '3.0'
132
166
  type: :development
133
167
  prerelease: false
134
168
  version_requirements: !ruby/object:Gem::Requirement
135
169
  requirements:
136
170
  - - "~>"
137
171
  - !ruby/object:Gem::Version
138
- version: '2.10'
172
+ version: '3.0'
139
173
  - !ruby/object:Gem::Dependency
140
174
  name: pry
141
175
  requirement: !ruby/object:Gem::Requirement
@@ -151,19 +185,47 @@ dependencies:
151
185
  - !ruby/object:Gem::Version
152
186
  version: '0.10'
153
187
  - !ruby/object:Gem::Dependency
154
- name: byebug
188
+ name: rake
155
189
  requirement: !ruby/object:Gem::Requirement
156
190
  requirements:
157
191
  - - "~>"
158
192
  - !ruby/object:Gem::Version
159
- version: '8.2'
193
+ version: '12.0'
160
194
  type: :development
161
195
  prerelease: false
162
196
  version_requirements: !ruby/object:Gem::Requirement
163
197
  requirements:
164
198
  - - "~>"
165
199
  - !ruby/object:Gem::Version
166
- version: '8.2'
200
+ version: '12.0'
201
+ - !ruby/object:Gem::Dependency
202
+ name: rspec
203
+ requirement: !ruby/object:Gem::Requirement
204
+ requirements:
205
+ - - "~>"
206
+ - !ruby/object:Gem::Version
207
+ version: '3.2'
208
+ type: :development
209
+ prerelease: false
210
+ version_requirements: !ruby/object:Gem::Requirement
211
+ requirements:
212
+ - - "~>"
213
+ - !ruby/object:Gem::Version
214
+ version: '3.2'
215
+ - !ruby/object:Gem::Dependency
216
+ name: timecop
217
+ requirement: !ruby/object:Gem::Requirement
218
+ requirements:
219
+ - - "~>"
220
+ - !ruby/object:Gem::Version
221
+ version: '0.8'
222
+ type: :development
223
+ prerelease: false
224
+ version_requirements: !ruby/object:Gem::Requirement
225
+ requirements:
226
+ - - "~>"
227
+ - !ruby/object:Gem::Version
228
+ version: '0.8'
167
229
  description:
168
230
  email: opensource@instructure.com
169
231
  executables: []
@@ -189,6 +251,7 @@ files:
189
251
  - lib/ims/lti/converters.rb
190
252
  - lib/ims/lti/converters/time_json_converter.rb
191
253
  - lib/ims/lti/errors.rb
254
+ - lib/ims/lti/errors/authentication_failed_error.rb
192
255
  - lib/ims/lti/errors/invalid_lti_config_error.rb
193
256
  - lib/ims/lti/errors/invalid_tool_consumer_profile.rb
194
257
  - lib/ims/lti/errors/tool_proxy_registration_error.rb
@@ -226,7 +289,7 @@ files:
226
289
  - lib/ims/lti/models/messages/message.rb
227
290
  - lib/ims/lti/models/messages/registration_request.rb
228
291
  - lib/ims/lti/models/messages/request_message.rb
229
- - lib/ims/lti/models/messages/tool_proxy_reregistration_request.rb
292
+ - lib/ims/lti/models/messages/tool_proxy_update_request.rb
230
293
  - lib/ims/lti/models/parameter.rb
231
294
  - lib/ims/lti/models/product_family.rb
232
295
  - lib/ims/lti/models/product_info.rb
@@ -259,8 +322,11 @@ files:
259
322
  - lib/ims/lti/serializers/membership_service/page_serializer.rb
260
323
  - lib/ims/lti/serializers/membership_service/person_serializer.rb
261
324
  - lib/ims/lti/services.rb
325
+ - lib/ims/lti/services/authentication_service.rb
262
326
  - lib/ims/lti/services/message_authenticator.rb
327
+ - lib/ims/lti/services/oauth2_client.rb
263
328
  - lib/ims/lti/services/tool_config.rb
329
+ - lib/ims/lti/services/tool_consumer_profile_service.rb
264
330
  - lib/ims/lti/services/tool_proxy_registration_service.rb
265
331
  - lib/ims/lti/services/tool_proxy_validator.rb
266
332
  - lib/ims/lti/version.rb
@@ -283,8 +349,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
283
349
  - !ruby/object:Gem::Version
284
350
  version: '0'
285
351
  requirements: []
286
- rubyforge_project:
287
- rubygems_version: 2.6.8
352
+ rubygems_version: 3.2.22
288
353
  signing_key:
289
354
  specification_version: 4
290
355
  summary: Ruby library for creating IMS LTI tool providers and consumers