ims-lti 2.1.2 → 2.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2bdd06e5c60fc13eb134e231cf0e0ee7738eb9a8
4
- data.tar.gz: 56c1d472a02e4d5359b9e03977a0d9f604a3a09f
3
+ metadata.gz: 64af3f1aebf17f2f5cc0029cabbead8ecc7a0370
4
+ data.tar.gz: 33ba505d3df21a88f8a10e9bc810ba9b4f4605fc
5
5
  SHA512:
6
- metadata.gz: 264a0293b2ccad3c5047d081ba08d6f2967a3e26c621855a1add4cafd113f3627d95cb75d95b491cc47293a35ded64ef9d82aa6ac61e393dde2e69189398fb91
7
- data.tar.gz: 47cfe33a68b1a8ee738ab6d80bc8e8e8d4b75d8fc47c25da6e42fef69b9ca55f04a5b343b82687d161434943670f6149f75da13ec6fb5be30c2485f965bc6819
6
+ metadata.gz: 194581f7c78f74ba27eb759eb0a39bc23c4c913a085737be6e5839b5d26fe74989c146bbd8e803cc1eb22d7419dbedf5ef0070480e9066068799de32821c0b6a
7
+ data.tar.gz: b0973c1dbfb50d420d7a93416d30f1d78370735dfbf0dde8be16684042911f4987e1b00fdc3a75d6de01dd0095d7815656a5f15e80338ec7b5226698bef0f42e
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
 
@@ -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
@@ -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
@@ -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
@@ -40,7 +40,7 @@ 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
@@ -81,20 +81,34 @@ module IMS::LTI::Models::Messages
81
81
  OAUTH_KEYS = :oauth_callback, :oauth_consumer_key, :oauth_nonce, :oauth_signature, :oauth_signature_method,
82
82
  :oauth_timestamp, :oauth_token, :oauth_verifier, :oauth_version
83
83
 
84
- attr_accessor :launch_url, *OAUTH_KEYS
84
+ attr_accessor :launch_url, :jwt, *OAUTH_KEYS
85
85
  attr_reader :unknown_params, :custom_params, :ext_params
86
86
 
87
87
  add_required_params :lti_message_type, :lti_version
88
88
 
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)
89
+ def self.generate(launch_params)
90
+ params = launch_params.key?('jwt') ? parse_jwt(jwt: launch_params['jwt']) : launch_params
91
+ klass = self.descendants.select {|d| d::MESSAGE_TYPE == params['lti_message_type']}.first
92
+ message = klass ? klass.new(params) : Message.new(params)
93
+ message.jwt = launch_params['jwt'] if launch_params.key?('jwt')
94
+ message
92
95
  end
93
96
 
94
- def initialize(attrs = {})
97
+ def self.parse_jwt(jwt:)
98
+ decoded_jwt = JSON::JWT.decode(jwt, :skip_verification)
99
+ params = decoded_jwt['org.imsglobal.lti.message'] || {}
100
+ custom = params.delete(:custom)
101
+ custom.each {|k,v| params["custom_#{k}"] = v }
102
+ params['consumer_key'] = decoded_jwt[:sub]
103
+ ext = params.delete(:ext)
104
+ ext.each {|k,v| params["ext_#{k}"] = v }
105
+ params
106
+ end
107
+
108
+ def initialize(attrs = {}, custom_params = {}, ext_params = {})
95
109
 
96
- @custom_params = {}
97
- @ext_params = {}
110
+ @custom_params = custom_params
111
+ @ext_params = ext_params
98
112
  @unknown_params = {}
99
113
 
100
114
  attrs.each do |k, v|
@@ -114,20 +128,28 @@ module IMS::LTI::Models::Messages
114
128
  end
115
129
 
116
130
  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 }
131
+ params.each {|k, v| k.to_s.start_with?('custom_') ? @custom_params[k.to_s] = v : @custom_params["custom_#{k.to_s}"] = v}
118
132
  end
119
133
 
120
134
  def get_custom_params
121
- @custom_params.inject({}) { |hash, (k, v)| hash[k.gsub(/\Acustom_/, '')] = v; hash }
135
+ @custom_params.inject({}) {|hash, (k, v)| hash[k.gsub(/\Acustom_/, '')] = v; hash}
136
+ end
137
+
138
+ def get_ext_params
139
+ @ext_params.inject({}) {|hash, (k, v)| hash[k.gsub(/\Aext_/, '')] = v; hash}
122
140
  end
123
141
 
124
142
  def post_params
125
143
  unknown_params.merge(@custom_params).merge(@ext_params).merge(parameters)
126
144
  end
127
145
 
146
+ def jwt_params(private_key:, originating_domain:, algorithm: :HS256)
147
+ { 'jwt' => to_jwt(private_key: private_key, originating_domain: originating_domain, algorithm: algorithm) }
148
+ end
149
+
128
150
  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 )
151
+ message_params = { oauth_consumer_key: oauth_consumer_key }.merge(post_params)
152
+ @message_authenticator = IMS::LTI::Services::MessageAuthenticator.new(launch_url, message_params, secret)
131
153
  @message_authenticator.signed_params
132
154
  end
133
155
 
@@ -165,6 +187,27 @@ module IMS::LTI::Models::Messages
165
187
  end
166
188
  end
167
189
 
190
+ def to_jwt(private_key:, originating_domain:, algorithm: :HS256)
191
+ now = Time.now
192
+ exp = now + 60 * 5
193
+ ims = unknown_params.merge(parameters)
194
+ ims[:custom] = get_custom_params
195
+ ims[:ext] = get_ext_params
196
+ claim = {
197
+ iss: originating_domain,
198
+ sub: consumer_key,
199
+ aud: launch_url,
200
+ iat: now,
201
+ exp: exp,
202
+ jti: SecureRandom.uuid,
203
+ "org.imsglobal.lti.message" => ims
204
+ }
205
+ jwt = JSON::JWT.new(claim).sign(private_key, algorithm)
206
+ jwt.to_s
207
+ end
208
+
209
+ alias_attribute :consumer_key, :oauth_consumer_key
210
+
168
211
  private
169
212
 
170
213
  def collect_attributes(attributes)
@@ -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
 
@@ -35,5 +36,10 @@ module IMS::LTI::Models
35
36
  def reregistration_capable?
36
37
  @capability_offered.include?(Messages::ToolProxyReregistrationRequest::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
@@ -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
@@ -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
@@ -52,6 +52,19 @@ module IMS::LTI::Services
52
52
 
53
53
 
54
54
  private
55
+
56
+ def valid_jwt?
57
+ begin
58
+ jwt = JSON::JWT.decode(message.jwt, @secret)
59
+ aud1 = Addressable::URI.parse(jwt['aud'])
60
+ aud2 = Addressable::URI.parse(launch_url)
61
+ [aud1, aud2].each{ |aud| aud.fragment = '' }
62
+ aud1.normalize == aud2.normalize
63
+ rescue JSON::JWS::VerificationFailed
64
+ false
65
+ end
66
+ end
67
+
55
68
  def parse_params(params)
56
69
  params.inject([{}, {}]) do |array, (k, v)|
57
70
  attr = k.to_s.sub('oauth_', '').to_sym
@@ -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
@@ -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
metadata CHANGED
@@ -1,29 +1,49 @@
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.1.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: 2017-06-28 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
18
  - !ruby/object:Gem::Version
19
- version: '0.2'
19
+ version: '2.5'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
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
+ - - "~>"
25
28
  - !ruby/object:Gem::Version
26
- version: '0.2'
29
+ version: '2.5'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 2.5.1
33
+ - !ruby/object:Gem::Dependency
34
+ name: builder
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '3.2'
40
+ type: :runtime
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '3.2'
27
47
  - !ruby/object:Gem::Dependency
28
48
  name: faraday
29
49
  requirement: !ruby/object:Gem::Requirement
@@ -53,47 +73,47 @@ dependencies:
53
73
  - !ruby/object:Gem::Version
54
74
  version: '0.8'
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.2'
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.2'
83
103
  - !ruby/object:Gem::Dependency
84
- name: rspec
104
+ name: byebug
85
105
  requirement: !ruby/object:Gem::Requirement
86
106
  requirements:
87
107
  - - "~>"
88
108
  - !ruby/object:Gem::Version
89
- version: '3.2'
109
+ version: '8.2'
90
110
  type: :development
91
111
  prerelease: false
92
112
  version_requirements: !ruby/object:Gem::Requirement
93
113
  requirements:
94
114
  - - "~>"
95
115
  - !ruby/object:Gem::Version
96
- version: '3.2'
116
+ version: '8.2'
97
117
  - !ruby/object:Gem::Dependency
98
118
  name: guard
99
119
  requirement: !ruby/object:Gem::Requirement
@@ -151,19 +171,47 @@ dependencies:
151
171
  - !ruby/object:Gem::Version
152
172
  version: '0.10'
153
173
  - !ruby/object:Gem::Dependency
154
- name: byebug
174
+ name: rake
155
175
  requirement: !ruby/object:Gem::Requirement
156
176
  requirements:
157
177
  - - "~>"
158
178
  - !ruby/object:Gem::Version
159
- version: '8.2'
179
+ version: '10.4'
160
180
  type: :development
161
181
  prerelease: false
162
182
  version_requirements: !ruby/object:Gem::Requirement
163
183
  requirements:
164
184
  - - "~>"
165
185
  - !ruby/object:Gem::Version
166
- version: '8.2'
186
+ version: '10.4'
187
+ - !ruby/object:Gem::Dependency
188
+ name: rspec
189
+ requirement: !ruby/object:Gem::Requirement
190
+ requirements:
191
+ - - "~>"
192
+ - !ruby/object:Gem::Version
193
+ version: '3.2'
194
+ type: :development
195
+ prerelease: false
196
+ version_requirements: !ruby/object:Gem::Requirement
197
+ requirements:
198
+ - - "~>"
199
+ - !ruby/object:Gem::Version
200
+ version: '3.2'
201
+ - !ruby/object:Gem::Dependency
202
+ name: timecop
203
+ requirement: !ruby/object:Gem::Requirement
204
+ requirements:
205
+ - - "~>"
206
+ - !ruby/object:Gem::Version
207
+ version: '0.8'
208
+ type: :development
209
+ prerelease: false
210
+ version_requirements: !ruby/object:Gem::Requirement
211
+ requirements:
212
+ - - "~>"
213
+ - !ruby/object:Gem::Version
214
+ version: '0.8'
167
215
  description:
168
216
  email: opensource@instructure.com
169
217
  executables: []
@@ -189,6 +237,7 @@ files:
189
237
  - lib/ims/lti/converters.rb
190
238
  - lib/ims/lti/converters/time_json_converter.rb
191
239
  - lib/ims/lti/errors.rb
240
+ - lib/ims/lti/errors/authentication_failed_error.rb
192
241
  - lib/ims/lti/errors/invalid_lti_config_error.rb
193
242
  - lib/ims/lti/errors/invalid_tool_consumer_profile.rb
194
243
  - lib/ims/lti/errors/tool_proxy_registration_error.rb
@@ -259,8 +308,11 @@ files:
259
308
  - lib/ims/lti/serializers/membership_service/page_serializer.rb
260
309
  - lib/ims/lti/serializers/membership_service/person_serializer.rb
261
310
  - lib/ims/lti/services.rb
311
+ - lib/ims/lti/services/authentication_service.rb
262
312
  - lib/ims/lti/services/message_authenticator.rb
313
+ - lib/ims/lti/services/oauth2_client.rb
263
314
  - lib/ims/lti/services/tool_config.rb
315
+ - lib/ims/lti/services/tool_consumer_profile_service.rb
264
316
  - lib/ims/lti/services/tool_proxy_registration_service.rb
265
317
  - lib/ims/lti/services/tool_proxy_validator.rb
266
318
  - lib/ims/lti/version.rb
@@ -284,7 +336,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
284
336
  version: '0'
285
337
  requirements: []
286
338
  rubyforge_project:
287
- rubygems_version: 2.6.8
339
+ rubygems_version: 2.6.11
288
340
  signing_key:
289
341
  specification_version: 4
290
342
  summary: Ruby library for creating IMS LTI tool providers and consumers