smart_app_launch_test_kit 0.4.5 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/config/presets/inferno_reference_server_preset.json +103 -0
- data/config/presets/inferno_reference_server_stu2_2_preset.json +89 -0
- data/config/presets/inferno_reference_server_stu2_preset.json +89 -0
- data/config/presets/smart_access_brands.json.erb +13 -0
- data/config/presets/smart_access_brands_example_1.json +37 -0
- data/config/presets/smart_access_brands_example_2.json +37 -0
- data/config/presets/smart_access_brands_example_3.json +37 -0
- data/config/presets/smart_access_brands_example_4.json +37 -0
- data/lib/smart_app_launch/cors_metadata_request_test.rb +40 -0
- data/lib/smart_app_launch/cors_openid_fhir_user_claim_test.rb +48 -0
- data/lib/smart_app_launch/cors_token_exchange_test.rb +35 -0
- data/lib/smart_app_launch/cors_well_known_endpoint_test.rb +40 -0
- data/lib/smart_app_launch/discovery_stu2_2_group.rb +12 -0
- data/lib/smart_app_launch/ehr_launch_group_stu2_2.rb +14 -0
- data/lib/smart_app_launch/metadata.rb +75 -0
- data/lib/smart_app_launch/openid_connect_group_stu2_2.rb +40 -0
- data/lib/smart_app_launch/smart_access_brands_examples/smart_access_brands_example.json.erb +198 -0
- data/lib/smart_app_launch/smart_access_brands_suite.rb +4 -1
- data/lib/smart_app_launch/smart_stu1_suite.rb +7 -6
- data/lib/smart_app_launch/smart_stu2_2_suite.rb +10 -10
- data/lib/smart_app_launch/smart_stu2_suite.rb +11 -10
- data/lib/smart_app_launch/standalone_launch_group_stu2_2.rb +14 -0
- data/lib/smart_app_launch/token_exchange_stu2_2_test.rb +30 -0
- data/lib/smart_app_launch/token_exchange_test.rb +10 -14
- data/lib/smart_app_launch/token_introspection_access_token_group_stu2_2.rb +2 -4
- data/lib/smart_app_launch/token_introspection_group.rb +1 -2
- data/lib/smart_app_launch/token_introspection_group_stu2_2.rb +0 -21
- data/lib/smart_app_launch/token_introspection_request_group.rb +47 -36
- data/lib/smart_app_launch/token_refresh_test.rb +13 -9
- data/lib/smart_app_launch/version.rb +2 -1
- data/lib/smart_app_launch_test_kit.rb +1 -0
- metadata +26 -8
@@ -11,42 +11,44 @@ module SMARTAppLaunch
|
|
11
11
|
id :smart_token_introspection_request_group
|
12
12
|
description %(
|
13
13
|
This group of tests executes the token introspection requests and ensures the correct HTTP response is returned
|
14
|
-
but does not validate the contents of the token introspection response.
|
14
|
+
but does not validate the contents of the token introspection response.
|
15
15
|
|
16
|
-
If Inferno cannot reasonably be configured to be authorized to access the token introspection endpoint, these tests
|
16
|
+
If Inferno cannot reasonably be configured to be authorized to access the token introspection endpoint, these tests
|
17
17
|
can be skipped. Instead, an out-of-band token introspection request must be completed and the response body
|
18
18
|
manually provided as input for the Validate Introspection Response test group.
|
19
19
|
)
|
20
20
|
|
21
21
|
input_instructions %(
|
22
|
-
If the Request New Access Token group was executed, the access token input will auto-populate with that token.
|
23
|
-
Otherwise an active access token needs to be obtained out-of-band and input.
|
24
|
-
|
25
|
-
Per [RFC-7662](https://datatracker.ietf.org/doc/html/rfc7662#section-2), "the definition of an active token is
|
26
|
-
currently dependent upon the authorization server, but this is commonly a token that has been issued by this
|
27
|
-
authorization server, is not expired, has not been revoked, and is valid for use at the protected resource making
|
22
|
+
If the Request New Access Token group was executed, the access token input will auto-populate with that token.
|
23
|
+
Otherwise an active access token needs to be obtained out-of-band and input.
|
24
|
+
|
25
|
+
Per [RFC-7662](https://datatracker.ietf.org/doc/html/rfc7662#section-2), "the definition of an active token is
|
26
|
+
currently dependent upon the authorization server, but this is commonly a token that has been issued by this
|
27
|
+
authorization server, is not expired, has not been revoked, and is valid for use at the protected resource making
|
28
28
|
the introspection call."
|
29
29
|
|
30
30
|
If the introspection endpoint is protected, testers must enter their own HTTP Authorization header for the introspection request. See
|
31
31
|
[RFC 7616 The 'Basic' HTTP Authentication Scheme](https://datatracker.ietf.org/doc/html/rfc7617) for the most common
|
32
|
-
approach that uses client credentials. Testers may also provide any additional parameters needed for their authorization
|
32
|
+
approach that uses client credentials. Testers may also provide any additional parameters needed for their authorization
|
33
33
|
server to complete the introspection request.
|
34
34
|
|
35
35
|
**Note:** For both the Authorization header and request parameters, user-input
|
36
36
|
values will be sent exactly as entered and therefore the tester must URI-encode any appropriate values.
|
37
37
|
)
|
38
38
|
|
39
|
-
input :well_known_introspection_url,
|
40
|
-
title: 'Token Introspection Endpoint URL',
|
39
|
+
input :well_known_introspection_url,
|
40
|
+
title: 'Token Introspection Endpoint URL',
|
41
41
|
description: 'The complete URL of the token introspection endpoint.'
|
42
42
|
|
43
43
|
input :custom_authorization_header,
|
44
|
-
title: 'HTTP
|
44
|
+
title: 'Custom HTTP Headers for Introspection Request',
|
45
45
|
type: 'textarea',
|
46
46
|
optional: true,
|
47
47
|
description: %(
|
48
|
-
|
49
|
-
|
48
|
+
Add custom headers for the introspection request by adding each header's name and value with a new line
|
49
|
+
between each header.
|
50
|
+
Ex:
|
51
|
+
<Header 1 Name>: <Value 1>
|
50
52
|
)
|
51
53
|
|
52
54
|
input :optional_introspection_request_params,
|
@@ -54,69 +56,78 @@ module SMARTAppLaunch
|
|
54
56
|
type: 'textarea',
|
55
57
|
optional: true,
|
56
58
|
description: %(
|
57
|
-
Any additional parameters to append to the request body, separated by &. Example: 'param1=abc¶m2=def'
|
59
|
+
Any additional parameters to append to the request body, separated by &. Example: 'param1=abc¶m2=def'
|
58
60
|
)
|
59
61
|
|
60
62
|
test do
|
61
63
|
title 'Token introspection endpoint returns a response when provided an active token'
|
62
64
|
description %(
|
63
65
|
This test will execute a token introspection request for an active token and ensure a 200 status and valid JSON
|
64
|
-
body are returned in the response.
|
66
|
+
body are returned in the response.
|
65
67
|
)
|
66
68
|
|
67
|
-
input :standalone_access_token,
|
69
|
+
input :standalone_access_token,
|
68
70
|
title: 'Access Token',
|
69
71
|
description: 'The access token to be introspected. MUST be active.'
|
70
72
|
|
71
|
-
|
72
73
|
output :active_token_introspection_response_body
|
73
74
|
|
74
75
|
run do
|
75
|
-
|
76
76
|
# If this is being chained from an earlier test, it might be blank if not present in the well-known endpoint
|
77
77
|
skip_if well_known_introspection_url.nil?, 'No introspection URL present in SMART well-known endpoint.'
|
78
78
|
|
79
|
-
headers = {'Accept' => 'application/json', 'Content-Type' => 'application/x-www-form-urlencoded'}
|
79
|
+
headers = { 'Accept' => 'application/json', 'Content-Type' => 'application/x-www-form-urlencoded' }
|
80
80
|
body = "token=#{standalone_access_token}"
|
81
81
|
|
82
82
|
if custom_authorization_header.present?
|
83
|
-
|
84
|
-
|
85
|
-
|
83
|
+
custom_headers = custom_authorization_header.split("\n")
|
84
|
+
custom_headers.each do |custom_header|
|
85
|
+
parsed_header = custom_header.split(':', 2)
|
86
|
+
assert parsed_header.length == 2,
|
87
|
+
'Incorrect custom HTTP header format input, expected: "<header name>: <header value>"'
|
88
|
+
headers[parsed_header[0]] = parsed_header[1].strip
|
89
|
+
end
|
86
90
|
end
|
87
91
|
|
88
|
-
if optional_introspection_request_params.present?
|
89
|
-
body += "&#{optional_introspection_request_params}"
|
90
|
-
end
|
92
|
+
body += "&#{optional_introspection_request_params}" if optional_introspection_request_params.present?
|
91
93
|
|
92
|
-
post(well_known_introspection_url, body
|
94
|
+
post(well_known_introspection_url, body:, headers:)
|
93
95
|
|
94
96
|
assert_response_status(200)
|
95
97
|
output active_token_introspection_response_body: request.response_body
|
96
98
|
end
|
97
|
-
|
98
99
|
end
|
99
100
|
|
100
|
-
test do
|
101
|
+
test do
|
101
102
|
title 'Token introspection endpoint returns a response when provided an invalid token'
|
102
103
|
description %(
|
103
104
|
This test will execute a token introspection request for an invalid token and ensure a 200 status and valid JSON
|
104
|
-
body are returned in response.
|
105
|
+
body are returned in response.
|
105
106
|
)
|
106
107
|
|
107
108
|
output :invalid_token_introspection_response_body
|
108
109
|
run do
|
109
|
-
|
110
110
|
# If this is being chained from an earlier test, it might be blank if not present in the well-known endpoint
|
111
111
|
skip_if well_known_introspection_url.nil?, 'No introspection URL present in SMART well-known endpoint.'
|
112
112
|
|
113
|
-
headers = {'Accept' => 'application/json', 'Content-Type' => 'application/x-www-form-urlencoded'}
|
114
|
-
body =
|
115
|
-
|
116
|
-
|
113
|
+
headers = { 'Accept' => 'application/json', 'Content-Type' => 'application/x-www-form-urlencoded' }
|
114
|
+
body = 'token=invalid_token_value'
|
115
|
+
|
116
|
+
if custom_authorization_header.present?
|
117
|
+
custom_headers = custom_authorization_header.split("\n")
|
118
|
+
custom_headers.each do |custom_header|
|
119
|
+
parsed_header = custom_header.split(':', 2)
|
120
|
+
assert parsed_header.length == 2,
|
121
|
+
'Incorrect custom HTTP header format input, expected: "<header name>: <header value>"'
|
122
|
+
headers[parsed_header[0]] = parsed_header[1].strip
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
post(well_known_introspection_url, body:, headers:)
|
127
|
+
|
117
128
|
assert_response_status(200)
|
118
129
|
output invalid_token_introspection_response_body: request.response_body
|
119
130
|
end
|
120
131
|
end
|
121
132
|
end
|
122
|
-
end
|
133
|
+
end
|
@@ -30,6 +30,10 @@ module SMARTAppLaunch
|
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
33
|
+
def make_auth_token_request(smart_token_url, oauth2_params, oauth2_headers)
|
34
|
+
post(smart_token_url, body: oauth2_params, name: :token_refresh, headers: oauth2_headers)
|
35
|
+
end
|
36
|
+
|
33
37
|
run do
|
34
38
|
skip_if refresh_token.blank?
|
35
39
|
|
@@ -43,7 +47,7 @@ module SMARTAppLaunch
|
|
43
47
|
|
44
48
|
add_credentials_to_request(oauth2_headers, oauth2_params)
|
45
49
|
|
46
|
-
|
50
|
+
make_auth_token_request(smart_token_url, oauth2_params, oauth2_headers)
|
47
51
|
|
48
52
|
assert_response_status(200)
|
49
53
|
assert_valid_json(request.response_body)
|
@@ -52,14 +56,14 @@ module SMARTAppLaunch
|
|
52
56
|
|
53
57
|
token_response_body = JSON.parse(request.response_body)
|
54
58
|
output smart_credentials: {
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
59
|
+
refresh_token: token_response_body['refresh_token'].presence || refresh_token,
|
60
|
+
access_token: token_response_body['access_token'],
|
61
|
+
expires_in: token_response_body['expires_in'],
|
62
|
+
client_id:,
|
63
|
+
client_secret:,
|
64
|
+
token_retrieval_time:,
|
65
|
+
token_url: smart_token_url
|
66
|
+
}.to_json
|
63
67
|
end
|
64
68
|
end
|
65
69
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: smart_app_launch_test_kit
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stephen MacVicar
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2025-02-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: inferno_core
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 0.
|
19
|
+
version: 0.6.2
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 0.
|
26
|
+
version: 0.6.2
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: json-jwt
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -58,14 +58,14 @@ dependencies:
|
|
58
58
|
requirements:
|
59
59
|
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: 0.
|
61
|
+
version: 0.3.0
|
62
62
|
type: :runtime
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version: 0.
|
68
|
+
version: 0.3.0
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: database_cleaner-sequel
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -145,6 +145,14 @@ extensions: []
|
|
145
145
|
extra_rdoc_files: []
|
146
146
|
files:
|
147
147
|
- LICENSE
|
148
|
+
- config/presets/inferno_reference_server_preset.json
|
149
|
+
- config/presets/inferno_reference_server_stu2_2_preset.json
|
150
|
+
- config/presets/inferno_reference_server_stu2_preset.json
|
151
|
+
- config/presets/smart_access_brands.json.erb
|
152
|
+
- config/presets/smart_access_brands_example_1.json
|
153
|
+
- config/presets/smart_access_brands_example_2.json
|
154
|
+
- config/presets/smart_access_brands_example_3.json
|
155
|
+
- config/presets/smart_access_brands_example_4.json
|
148
156
|
- lib/smart_app_launch/app_launch_test.rb
|
149
157
|
- lib/smart_app_launch/app_redirect_test.rb
|
150
158
|
- lib/smart_app_launch/app_redirect_test_stu2.rb
|
@@ -157,14 +165,21 @@ files:
|
|
157
165
|
- lib/smart_app_launch/backend_services_invalid_jwt_test.rb
|
158
166
|
- lib/smart_app_launch/client_assertion_builder.rb
|
159
167
|
- lib/smart_app_launch/code_received_test.rb
|
168
|
+
- lib/smart_app_launch/cors_metadata_request_test.rb
|
169
|
+
- lib/smart_app_launch/cors_openid_fhir_user_claim_test.rb
|
170
|
+
- lib/smart_app_launch/cors_token_exchange_test.rb
|
171
|
+
- lib/smart_app_launch/cors_well_known_endpoint_test.rb
|
160
172
|
- lib/smart_app_launch/discovery_stu1_group.rb
|
173
|
+
- lib/smart_app_launch/discovery_stu2_2_group.rb
|
161
174
|
- lib/smart_app_launch/discovery_stu2_group.rb
|
162
175
|
- lib/smart_app_launch/ehr_launch_group.rb
|
163
176
|
- lib/smart_app_launch/ehr_launch_group_stu2.rb
|
164
177
|
- lib/smart_app_launch/ehr_launch_group_stu2_2.rb
|
165
178
|
- lib/smart_app_launch/jwks.rb
|
166
179
|
- lib/smart_app_launch/launch_received_test.rb
|
180
|
+
- lib/smart_app_launch/metadata.rb
|
167
181
|
- lib/smart_app_launch/openid_connect_group.rb
|
182
|
+
- lib/smart_app_launch/openid_connect_group_stu2_2.rb
|
168
183
|
- lib/smart_app_launch/openid_decode_id_token_test.rb
|
169
184
|
- lib/smart_app_launch/openid_fhir_user_claim_test.rb
|
170
185
|
- lib/smart_app_launch/openid_required_configuration_fields_test.rb
|
@@ -174,6 +189,7 @@ files:
|
|
174
189
|
- lib/smart_app_launch/openid_token_payload_test.rb
|
175
190
|
- lib/smart_app_launch/post_auth.html
|
176
191
|
- lib/smart_app_launch/smart_access_brands_examples/r4_capability_statement.json
|
192
|
+
- lib/smart_app_launch/smart_access_brands_examples/smart_access_brands_example.json.erb
|
177
193
|
- lib/smart_app_launch/smart_access_brands_group.rb
|
178
194
|
- lib/smart_app_launch/smart_access_brands_retrieval_group.rb
|
179
195
|
- lib/smart_app_launch/smart_access_brands_retrieve_bundle_test.rb
|
@@ -190,6 +206,7 @@ files:
|
|
190
206
|
- lib/smart_app_launch/standalone_launch_group.rb
|
191
207
|
- lib/smart_app_launch/standalone_launch_group_stu2.rb
|
192
208
|
- lib/smart_app_launch/standalone_launch_group_stu2_2.rb
|
209
|
+
- lib/smart_app_launch/token_exchange_stu2_2_test.rb
|
193
210
|
- lib/smart_app_launch/token_exchange_stu2_test.rb
|
194
211
|
- lib/smart_app_launch/token_exchange_test.rb
|
195
212
|
- lib/smart_app_launch/token_introspection_access_token_group.rb
|
@@ -217,6 +234,7 @@ homepage: https://github.com/inferno-framework/smart-app-launch-test-kit
|
|
217
234
|
licenses:
|
218
235
|
- Apache-2.0
|
219
236
|
metadata:
|
237
|
+
inferno_test_kit: 'true'
|
220
238
|
homepage_uri: https://github.com/inferno-framework/smart-app-launch-test-kit
|
221
239
|
source_code_uri: https://github.com/inferno-framework/smart-app-launch-test-kit
|
222
240
|
post_install_message:
|
@@ -227,14 +245,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
227
245
|
requirements:
|
228
246
|
- - ">="
|
229
247
|
- !ruby/object:Gem::Version
|
230
|
-
version: 3.
|
248
|
+
version: 3.3.6
|
231
249
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
232
250
|
requirements:
|
233
251
|
- - ">="
|
234
252
|
- !ruby/object:Gem::Version
|
235
253
|
version: '0'
|
236
254
|
requirements: []
|
237
|
-
rubygems_version: 3.5.
|
255
|
+
rubygems_version: 3.5.22
|
238
256
|
signing_key:
|
239
257
|
specification_version: 4
|
240
258
|
summary: Inferno Tests for the SMART Application Launch Framework Implementation Guide
|