smart_app_launch_test_kit 0.4.5 → 0.5.0
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/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
|