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 +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
|