ims-lti 2.1.2 → 2.1.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/lib/ims/lti.rb +8 -6
- data/lib/ims/lti/errors.rb +1 -0
- data/lib/ims/lti/errors/authentication_failed_error.rb +11 -0
- data/lib/ims/lti/models/messages/message.rb +55 -12
- data/lib/ims/lti/models/tool_consumer_profile.rb +6 -0
- data/lib/ims/lti/services.rb +4 -1
- data/lib/ims/lti/services/authentication_service.rb +67 -0
- data/lib/ims/lti/services/message_authenticator.rb +14 -1
- data/lib/ims/lti/services/oauth2_client.rb +18 -0
- data/lib/ims/lti/services/tool_consumer_profile_service.rb +16 -0
- data/lib/ims/lti/services/tool_proxy_validator.rb +23 -7
- metadata +75 -23
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 64af3f1aebf17f2f5cc0029cabbead8ecc7a0370
|
4
|
+
data.tar.gz: 33ba505d3df21a88f8a10e9bc810ba9b4f4605fc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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')
|
40
|
+
return false if DateTime.strptime(request.request_parameters['oauth_timestamp'],'%s') < 5.minutes.ago
|
41
41
|
|
42
42
|
```
|
43
43
|
|
data/lib/ims/lti.rb
CHANGED
@@ -1,17 +1,19 @@
|
|
1
|
-
require '
|
2
|
-
require '
|
3
|
-
require 'simple_oauth'
|
1
|
+
require 'addressable/uri'
|
2
|
+
require 'builder'
|
4
3
|
require 'faraday'
|
5
4
|
require 'faraday_middleware'
|
6
|
-
require '
|
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
|
data/lib/ims/lti/errors.rb
CHANGED
@@ -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(
|
90
|
-
|
91
|
-
klass
|
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
|
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 {
|
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({}) {
|
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
|
data/lib/ims/lti/services.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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 {
|
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
|
-
|
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.
|
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-
|
11
|
+
date: 2017-06-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: addressable
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
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: '
|
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:
|
76
|
+
name: json-jwt
|
57
77
|
requirement: !ruby/object:Gem::Requirement
|
58
78
|
requirements:
|
59
79
|
- - "~>"
|
60
80
|
- !ruby/object:Gem::Version
|
61
|
-
version: '
|
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: '
|
88
|
+
version: '1.7'
|
69
89
|
- !ruby/object:Gem::Dependency
|
70
|
-
name:
|
90
|
+
name: simple_oauth
|
71
91
|
requirement: !ruby/object:Gem::Requirement
|
72
92
|
requirements:
|
73
|
-
- -
|
93
|
+
- - '='
|
74
94
|
- !ruby/object:Gem::Version
|
75
|
-
version: '
|
76
|
-
type: :
|
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: '
|
102
|
+
version: '0.2'
|
83
103
|
- !ruby/object:Gem::Dependency
|
84
|
-
name:
|
104
|
+
name: byebug
|
85
105
|
requirement: !ruby/object:Gem::Requirement
|
86
106
|
requirements:
|
87
107
|
- - "~>"
|
88
108
|
- !ruby/object:Gem::Version
|
89
|
-
version: '
|
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: '
|
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:
|
174
|
+
name: rake
|
155
175
|
requirement: !ruby/object:Gem::Requirement
|
156
176
|
requirements:
|
157
177
|
- - "~>"
|
158
178
|
- !ruby/object:Gem::Version
|
159
|
-
version: '
|
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: '
|
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.
|
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
|